-- -- CREATE_OPERATOR -- CREATE OPERATOR ## ( leftarg = path, rightarg = path, function = path_inter, commutator = ## ); CREATE OPERATOR <% ( leftarg = point, rightarg = widget, procedure = pt_in_widget, commutator = >% , negator = >=% ); CREATE OPERATOR @#@ ( rightarg = int8, -- prefix procedure = factorial ); CREATE OPERATOR #%# ( leftarg = int8, -- fail, postfix is no longer supported procedure = factorial ); ERROR: operator right argument type must be specified DETAIL: Postfix operators are not supported. -- Test operator created above SELECT point '(1,2)' <% widget '(0,0,3)' AS t, point '(1,2)' <% widget '(0,0,1)' AS f; t | f ---+--- t | f (1 row) -- Test comments COMMENT ON OPERATOR ###### (NONE, int4) IS 'bad prefix'; ERROR: operator does not exist: ###### integer COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad postfix'; ERROR: postfix operators are not supported COMMENT ON OPERATOR ###### (int4, int8) IS 'bad infix'; ERROR: operator does not exist: integer ###### bigint -- Check that DROP on a nonexistent op behaves sanely, too DROP OPERATOR ###### (NONE, int4); ERROR: operator does not exist: ###### integer DROP OPERATOR ###### (int4, NONE); ERROR: postfix operators are not supported DROP OPERATOR ###### (int4, int8); ERROR: operator does not exist: integer ###### bigint -- => is disallowed as an operator name now CREATE OPERATOR => ( rightarg = int8, procedure = factorial ); ERROR: syntax error at or near "=>" LINE 1: CREATE OPERATOR => ( ^ -- lexing of <=, >=, <>, != has a number of edge cases -- (=> is tested elsewhere) -- this is legal because ! is not allowed in sql ops CREATE OPERATOR !=- ( rightarg = int8, procedure = factorial ); SELECT !=- 10; ?column? ---------- 3628800 (1 row) -- postfix operators don't work anymore SELECT 10 !=-; ERROR: syntax error at or near ";" LINE 1: SELECT 10 !=-; ^ -- make sure lexer returns != as <> even in edge cases SELECT 2 !=/**/ 1, 2 !=/**/ 2; ?column? | ?column? ----------+---------- t | f (1 row) SELECT 2 !=-- comment to be removed by psql 1; ?column? ---------- t (1 row) DO $$ -- use DO to protect -- from psql declare r boolean; begin execute $e$ select 2 !=-- comment 1 $e$ into r; raise info 'r = %', r; end; $$; INFO: r = t -- check that <= etc. followed by more operator characters are returned -- as the correct token with correct precedence SELECT true<>-1 BETWEEN 1 AND 1; -- BETWEEN has prec. above <> but below Op ?column? ---------- t (1 row) SELECT false<>/**/1 BETWEEN 1 AND 1; ?column? ---------- t (1 row) SELECT false<=-1 BETWEEN 1 AND 1; ?column? ---------- t (1 row) SELECT false>=-1 BETWEEN 1 AND 1; ?column? ---------- t (1 row) SELECT 2<=/**/3, 3>=/**/2, 2<>/**/3; ?column? | ?column? | ?column? ----------+----------+---------- t | t | t (1 row) SELECT 3<=/**/2, 2>=/**/3, 2<>/**/2; ?column? | ?column? | ?column? ----------+----------+---------- f | f | f (1 row) -- Should fail. CREATE OPERATOR requires USAGE on SCHEMA BEGIN TRANSACTION; CREATE ROLE regress_rol_op1; CREATE SCHEMA schema_op1; GRANT USAGE ON SCHEMA schema_op1 TO PUBLIC; REVOKE USAGE ON SCHEMA schema_op1 FROM regress_rol_op1; SET ROLE regress_rol_op1; CREATE OPERATOR schema_op1.#*# ( rightarg = int8, procedure = factorial ); ERROR: permission denied for schema schema_op1 ROLLBACK; -- Should fail. SETOF type functions not allowed as argument (testing leftarg) BEGIN TRANSACTION; CREATE OPERATOR #*# ( leftarg = SETOF int8, procedure = factorial ); ERROR: SETOF type not allowed for operator argument ROLLBACK; -- Should fail. SETOF type functions not allowed as argument (testing rightarg) BEGIN TRANSACTION; CREATE OPERATOR #*# ( rightarg = SETOF int8, procedure = factorial ); ERROR: SETOF type not allowed for operator argument ROLLBACK; -- Should work. Sample text-book case BEGIN TRANSACTION; CREATE OR REPLACE FUNCTION fn_op2(boolean, boolean) RETURNS boolean AS $$ SELECT NULL::BOOLEAN; $$ LANGUAGE sql IMMUTABLE; CREATE OPERATOR === ( LEFTARG = boolean, RIGHTARG = boolean, PROCEDURE = fn_op2, COMMUTATOR = ===, NEGATOR = !==, RESTRICT = contsel, JOIN = contjoinsel, SORT1, SORT2, LTCMP, GTCMP, HASHES, MERGES ); ROLLBACK; -- Should fail. Invalid attribute CREATE OPERATOR #@%# ( rightarg = int8, procedure = factorial, invalid_att = int8 ); WARNING: operator attribute "invalid_att" not recognized -- Should fail. At least rightarg should be mandatorily specified CREATE OPERATOR #@%# ( procedure = factorial ); ERROR: operator argument types must be specified -- Should fail. Procedure should be mandatorily specified CREATE OPERATOR #@%# ( rightarg = int8 ); ERROR: operator function must be specified -- Should fail. CREATE OPERATOR requires USAGE on TYPE BEGIN TRANSACTION; CREATE ROLE regress_rol_op3; CREATE TYPE type_op3 AS ENUM ('new', 'open', 'closed'); CREATE FUNCTION fn_op3(type_op3, int8) RETURNS int8 AS $$ SELECT NULL::int8; $$ LANGUAGE sql IMMUTABLE; REVOKE USAGE ON TYPE type_op3 FROM regress_rol_op3; REVOKE USAGE ON TYPE type_op3 FROM PUBLIC; -- Need to do this so that regress_rol_op3 is not allowed USAGE via PUBLIC SET ROLE regress_rol_op3; CREATE OPERATOR #*# ( leftarg = type_op3, rightarg = int8, procedure = fn_op3 ); ERROR: permission denied for type type_op3 ROLLBACK; -- Should fail. CREATE OPERATOR requires USAGE on TYPE (need to check separately for rightarg) BEGIN TRANSACTION; CREATE ROLE regress_rol_op4; CREATE TYPE type_op4 AS ENUM ('new', 'open', 'closed'); CREATE FUNCTION fn_op4(int8, type_op4) RETURNS int8 AS $$ SELECT NULL::int8; $$ LANGUAGE sql IMMUTABLE; REVOKE USAGE ON TYPE type_op4 FROM regress_rol_op4; REVOKE USAGE ON TYPE type_op4 FROM PUBLIC; -- Need to do this so that regress_rol_op3 is not allowed USAGE via PUBLIC SET ROLE regress_rol_op4; CREATE OPERATOR #*# ( leftarg = int8, rightarg = type_op4, procedure = fn_op4 ); ERROR: permission denied for type type_op4 ROLLBACK; -- Should fail. CREATE OPERATOR requires EXECUTE on function BEGIN TRANSACTION; CREATE ROLE regress_rol_op5; CREATE TYPE type_op5 AS ENUM ('new', 'open', 'closed'); CREATE FUNCTION fn_op5(int8, int8) RETURNS int8 AS $$ SELECT NULL::int8; $$ LANGUAGE sql IMMUTABLE; REVOKE EXECUTE ON FUNCTION fn_op5(int8, int8) FROM regress_rol_op5; REVOKE EXECUTE ON FUNCTION fn_op5(int8, int8) FROM PUBLIC;-- Need to do this so that regress_rol_op3 is not allowed EXECUTE via PUBLIC SET ROLE regress_rol_op5; CREATE OPERATOR #*# ( leftarg = int8, rightarg = int8, procedure = fn_op5 ); ERROR: permission denied for function fn_op5 ROLLBACK; -- Should fail. CREATE OPERATOR requires USAGE on return TYPE BEGIN TRANSACTION; CREATE ROLE regress_rol_op6; CREATE TYPE type_op6 AS ENUM ('new', 'open', 'closed'); CREATE FUNCTION fn_op6(int8, int8) RETURNS type_op6 AS $$ SELECT NULL::type_op6; $$ LANGUAGE sql IMMUTABLE; REVOKE USAGE ON TYPE type_op6 FROM regress_rol_op6; REVOKE USAGE ON TYPE type_op6 FROM PUBLIC; -- Need to do this so that regress_rol_op3 is not allowed USAGE via PUBLIC SET ROLE regress_rol_op6; CREATE OPERATOR #*# ( leftarg = int8, rightarg = int8, procedure = fn_op6 ); ERROR: permission denied for type type_op6 ROLLBACK; -- invalid: non-lowercase quoted identifiers CREATE OPERATOR === ( "Leftarg" = box, "Rightarg" = box, "Procedure" = area_equal_function, "Commutator" = ===, "Negator" = !==, "Restrict" = area_restriction_function, "Join" = area_join_function, "Hashes", "Merges" ); WARNING: operator attribute "Leftarg" not recognized WARNING: operator attribute "Rightarg" not recognized WARNING: operator attribute "Procedure" not recognized WARNING: operator attribute "Commutator" not recognized WARNING: operator attribute "Negator" not recognized WARNING: operator attribute "Restrict" not recognized WARNING: operator attribute "Join" not recognized WARNING: operator attribute "Hashes" not recognized WARNING: operator attribute "Merges" not recognized ERROR: operator function must be specified