4 -- Assorted tests using SQL-language functions
6 -- All objects made in this test are in temp_func_test schema
7 CREATE USER regress_unpriv_user;
8 CREATE SCHEMA temp_func_test;
9 GRANT ALL ON SCHEMA temp_func_test TO public;
10 SET search_path TO temp_func_test, public;
12 -- Make sanity checks on the pg_proc entries created by CREATE FUNCTION
15 -- ARGUMENT and RETURN TYPES
17 CREATE FUNCTION functest_A_1(text, date) RETURNS bool LANGUAGE 'sql'
18 AS 'SELECT $1 = ''abcd'' AND $2 > ''2001-01-01''';
19 CREATE FUNCTION functest_A_2(text[]) RETURNS int LANGUAGE 'sql'
20 AS 'SELECT $1[1]::int';
21 CREATE FUNCTION functest_A_3() RETURNS bool LANGUAGE 'sql'
23 SELECT proname, prorettype::regtype, proargtypes::regtype[] FROM pg_proc
24 WHERE oid in ('functest_A_1'::regproc,
25 'functest_A_2'::regproc,
26 'functest_A_3'::regproc) ORDER BY proname;
27 proname | prorettype | proargtypes
28 --------------+------------+-------------------
29 functest_a_1 | boolean | [0:1]={text,date}
30 functest_a_2 | integer | [0:0]={text[]}
31 functest_a_3 | boolean | {}
34 SELECT functest_A_1('abcd', '2020-01-01');
40 SELECT functest_A_2(ARRAY['1', '2', '3']);
46 SELECT functest_A_3();
53 -- IMMUTABLE | STABLE | VOLATILE
55 CREATE FUNCTION functest_B_1(int) RETURNS bool LANGUAGE 'sql'
57 CREATE FUNCTION functest_B_2(int) RETURNS bool LANGUAGE 'sql'
58 IMMUTABLE AS 'SELECT $1 > 0';
59 CREATE FUNCTION functest_B_3(int) RETURNS bool LANGUAGE 'sql'
60 STABLE AS 'SELECT $1 = 0';
61 CREATE FUNCTION functest_B_4(int) RETURNS bool LANGUAGE 'sql'
62 VOLATILE AS 'SELECT $1 < 0';
63 SELECT proname, provolatile FROM pg_proc
64 WHERE oid in ('functest_B_1'::regproc,
65 'functest_B_2'::regproc,
66 'functest_B_3'::regproc,
67 'functest_B_4'::regproc) ORDER BY proname;
69 --------------+-------------
76 ALTER FUNCTION functest_B_2(int) VOLATILE;
77 ALTER FUNCTION functest_B_3(int) COST 100; -- unrelated change, no effect
78 SELECT proname, provolatile FROM pg_proc
79 WHERE oid in ('functest_B_1'::regproc,
80 'functest_B_2'::regproc,
81 'functest_B_3'::regproc,
82 'functest_B_4'::regproc) ORDER BY proname;
84 --------------+-------------
92 -- SECURITY DEFINER | INVOKER
94 CREATE FUNCTION functest_C_1(int) RETURNS bool LANGUAGE 'sql'
96 CREATE FUNCTION functest_C_2(int) RETURNS bool LANGUAGE 'sql'
97 SECURITY DEFINER AS 'SELECT $1 = 0';
98 CREATE FUNCTION functest_C_3(int) RETURNS bool LANGUAGE 'sql'
99 SECURITY INVOKER AS 'SELECT $1 < 0';
100 SELECT proname, prosecdef FROM pg_proc
101 WHERE oid in ('functest_C_1'::regproc,
102 'functest_C_2'::regproc,
103 'functest_C_3'::regproc) ORDER BY proname;
105 --------------+-----------
111 ALTER FUNCTION functest_C_1(int) IMMUTABLE; -- unrelated change, no effect
112 ALTER FUNCTION functest_C_2(int) SECURITY INVOKER;
113 ALTER FUNCTION functest_C_3(int) SECURITY DEFINER;
114 SELECT proname, prosecdef FROM pg_proc
115 WHERE oid in ('functest_C_1'::regproc,
116 'functest_C_2'::regproc,
117 'functest_C_3'::regproc) ORDER BY proname;
119 --------------+-----------
128 CREATE FUNCTION functest_E_1(int) RETURNS bool LANGUAGE 'sql'
129 AS 'SELECT $1 > 100';
130 CREATE FUNCTION functest_E_2(int) RETURNS bool LANGUAGE 'sql'
131 LEAKPROOF AS 'SELECT $1 > 100';
132 SELECT proname, proleakproof FROM pg_proc
133 WHERE oid in ('functest_E_1'::regproc,
134 'functest_E_2'::regproc) ORDER BY proname;
135 proname | proleakproof
136 --------------+--------------
141 ALTER FUNCTION functest_E_1(int) LEAKPROOF;
142 ALTER FUNCTION functest_E_2(int) STABLE; -- unrelated change, no effect
143 SELECT proname, proleakproof FROM pg_proc
144 WHERE oid in ('functest_E_1'::regproc,
145 'functest_E_2'::regproc) ORDER BY proname;
146 proname | proleakproof
147 --------------+--------------
152 ALTER FUNCTION functest_E_2(int) NOT LEAKPROOF; -- remove leakproof attribute
153 SELECT proname, proleakproof FROM pg_proc
154 WHERE oid in ('functest_E_1'::regproc,
155 'functest_E_2'::regproc) ORDER BY proname;
156 proname | proleakproof
157 --------------+--------------
162 -- it takes superuser privilege to turn on leakproof, but not to turn off
163 ALTER FUNCTION functest_E_1(int) OWNER TO regress_unpriv_user;
164 ALTER FUNCTION functest_E_2(int) OWNER TO regress_unpriv_user;
165 SET SESSION AUTHORIZATION regress_unpriv_user;
166 SET search_path TO temp_func_test, public;
167 ALTER FUNCTION functest_E_1(int) NOT LEAKPROOF;
168 ALTER FUNCTION functest_E_2(int) LEAKPROOF;
169 ERROR: only superuser can define a leakproof function
170 CREATE FUNCTION functest_E_3(int) RETURNS bool LANGUAGE 'sql'
171 LEAKPROOF AS 'SELECT $1 < 200'; -- fail
172 ERROR: only superuser can define a leakproof function
173 RESET SESSION AUTHORIZATION;
175 -- CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
177 CREATE FUNCTION functest_F_1(int) RETURNS bool LANGUAGE 'sql'
179 CREATE FUNCTION functest_F_2(int) RETURNS bool LANGUAGE 'sql'
180 CALLED ON NULL INPUT AS 'SELECT $1 = 50';
181 CREATE FUNCTION functest_F_3(int) RETURNS bool LANGUAGE 'sql'
182 RETURNS NULL ON NULL INPUT AS 'SELECT $1 < 50';
183 CREATE FUNCTION functest_F_4(int) RETURNS bool LANGUAGE 'sql'
184 STRICT AS 'SELECT $1 = 50';
185 SELECT proname, proisstrict FROM pg_proc
186 WHERE oid in ('functest_F_1'::regproc,
187 'functest_F_2'::regproc,
188 'functest_F_3'::regproc,
189 'functest_F_4'::regproc) ORDER BY proname;
190 proname | proisstrict
191 --------------+-------------
198 ALTER FUNCTION functest_F_1(int) IMMUTABLE; -- unrelated change, no effect
199 ALTER FUNCTION functest_F_2(int) STRICT;
200 ALTER FUNCTION functest_F_3(int) CALLED ON NULL INPUT;
201 SELECT proname, proisstrict FROM pg_proc
202 WHERE oid in ('functest_F_1'::regproc,
203 'functest_F_2'::regproc,
204 'functest_F_3'::regproc,
205 'functest_F_4'::regproc) ORDER BY proname;
206 proname | proisstrict
207 --------------+-------------
214 -- pg_get_functiondef tests
215 SELECT pg_get_functiondef('functest_A_1'::regproc);
217 --------------------------------------------------------------------
218 CREATE OR REPLACE FUNCTION temp_func_test.functest_a_1(text, date)+
221 AS $function$SELECT $1 = 'abcd' AND $2 > '2001-01-01'$function$ +
225 SELECT pg_get_functiondef('functest_B_3'::regproc);
227 -----------------------------------------------------------------
228 CREATE OR REPLACE FUNCTION temp_func_test.functest_b_3(integer)+
232 AS $function$SELECT $1 = 0$function$ +
236 SELECT pg_get_functiondef('functest_C_3'::regproc);
238 -----------------------------------------------------------------
239 CREATE OR REPLACE FUNCTION temp_func_test.functest_c_3(integer)+
243 AS $function$SELECT $1 < 0$function$ +
247 SELECT pg_get_functiondef('functest_F_2'::regproc);
249 -----------------------------------------------------------------
250 CREATE OR REPLACE FUNCTION temp_func_test.functest_f_2(integer)+
254 AS $function$SELECT $1 = 50$function$ +
261 CREATE FUNCTION functest_S_1(a text, b date) RETURNS boolean
263 RETURN a = 'abcd' AND b > '2001-01-01';
264 CREATE FUNCTION functest_S_2(a text[]) RETURNS int
266 CREATE FUNCTION functest_S_3() RETURNS boolean
268 CREATE FUNCTION functest_S_3a() RETURNS boolean
272 CREATE FUNCTION functest_S_10(a text, b date) RETURNS boolean
275 SELECT a = 'abcd' AND b > '2001-01-01';
277 CREATE FUNCTION functest_S_13() RETURNS boolean
282 -- error: duplicate function body
283 CREATE FUNCTION functest_S_xxx(x int) RETURNS int
285 AS $$ SELECT x * 2 $$
287 ERROR: duplicate function body specified
288 -- polymorphic arguments not allowed in this form
289 CREATE FUNCTION functest_S_xx(x anyarray) RETURNS anyelement
292 ERROR: SQL function with unquoted function body cannot have polymorphic arguments
293 -- check reporting of parse-analysis errors
294 CREATE FUNCTION functest_S_xx(x date) RETURNS boolean
297 ERROR: operator does not exist: date > integer
298 LINE 3: RETURN x > 1;
300 HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
302 CREATE FUNCTION functest_S_15(x int) RETURNS boolean
305 select case when x % 2 = 0 then true else false end;
307 SELECT functest_S_1('abcd', '2020-01-01');
313 SELECT functest_S_2(ARRAY['1', '2', '3']);
319 SELECT functest_S_3();
325 SELECT functest_S_10('abcd', '2020-01-01');
331 SELECT functest_S_13();
337 SELECT pg_get_functiondef('functest_S_1'::regproc);
339 ------------------------------------------------------------------------
340 CREATE OR REPLACE FUNCTION temp_func_test.functest_s_1(a text, b date)+
343 RETURN ((a = 'abcd'::text) AND (b > '01-01-2001'::date)) +
347 SELECT pg_get_functiondef('functest_S_2'::regproc);
349 ------------------------------------------------------------------
350 CREATE OR REPLACE FUNCTION temp_func_test.functest_s_2(a text[])+
353 RETURN ((a)[1])::integer +
357 SELECT pg_get_functiondef('functest_S_3'::regproc);
359 ----------------------------------------------------------
360 CREATE OR REPLACE FUNCTION temp_func_test.functest_s_3()+
367 SELECT pg_get_functiondef('functest_S_3a'::regproc);
369 -----------------------------------------------------------
370 CREATE OR REPLACE FUNCTION temp_func_test.functest_s_3a()+
379 SELECT pg_get_functiondef('functest_S_10'::regproc);
381 -------------------------------------------------------------------------
382 CREATE OR REPLACE FUNCTION temp_func_test.functest_s_10(a text, b date)+
386 SELECT ((a = 'abcd'::text) AND (b > '01-01-2001'::date)); +
391 SELECT pg_get_functiondef('functest_S_13'::regproc);
393 -----------------------------------------------------------
394 CREATE OR REPLACE FUNCTION temp_func_test.functest_s_13()+
399 SELECT false AS bool; +
404 SELECT pg_get_functiondef('functest_S_15'::regproc);
406 --------------------------------------------------------------------
407 CREATE OR REPLACE FUNCTION temp_func_test.functest_s_15(x integer)+
413 WHEN ((x % 2) = 0) THEN true +
421 CREATE TABLE functest3 (a int);
422 INSERT INTO functest3 VALUES (1), (2);
423 CREATE VIEW functestv3 AS SELECT * FROM functest3;
424 CREATE FUNCTION functest_S_14() RETURNS bigint
425 RETURN (SELECT count(*) FROM functestv3);
426 SELECT functest_S_14();
432 DROP TABLE functest3 CASCADE;
433 NOTICE: drop cascades to 2 other objects
434 DETAIL: drop cascades to view functestv3
435 drop cascades to function functest_s_14()
436 -- information_schema tests
437 CREATE FUNCTION functest_IS_1(a int, b int default 1, c text default 'foo')
441 CREATE FUNCTION functest_IS_2(out a int, b int default 1)
445 CREATE FUNCTION functest_IS_3(a int default 1, out b int)
449 SELECT routine_name, ordinal_position, parameter_name, parameter_default
450 FROM information_schema.parameters JOIN information_schema.routines USING (specific_schema, specific_name)
451 WHERE routine_schema = 'temp_func_test' AND routine_name ~ '^functest_is_'
453 routine_name | ordinal_position | parameter_name | parameter_default
454 ---------------+------------------+----------------+-------------------
455 functest_is_1 | 1 | a |
456 functest_is_1 | 2 | b | 1
457 functest_is_1 | 3 | c | 'foo'::text
458 functest_is_2 | 1 | a |
459 functest_is_2 | 2 | b | 1
460 functest_is_3 | 1 | a | 1
461 functest_is_3 | 2 | b |
464 DROP FUNCTION functest_IS_1(int, int, text), functest_IS_2(int), functest_IS_3(int);
465 -- routine usage views
466 CREATE FUNCTION functest_IS_4a() RETURNS int LANGUAGE SQL AS 'SELECT 1';
467 CREATE FUNCTION functest_IS_4b(x int DEFAULT functest_IS_4a()) RETURNS int LANGUAGE SQL AS 'SELECT x';
468 CREATE SEQUENCE functest1;
469 CREATE FUNCTION functest_IS_5(x int DEFAULT nextval('functest1'))
473 CREATE FUNCTION functest_IS_6()
476 RETURN nextval('functest1');
477 CREATE TABLE functest2 (a int, b int);
478 CREATE FUNCTION functest_IS_7()
481 RETURN (SELECT count(a) FROM functest2);
482 SELECT r0.routine_name, r1.routine_name
483 FROM information_schema.routine_routine_usage rru
484 JOIN information_schema.routines r0 ON r0.specific_name = rru.specific_name
485 JOIN information_schema.routines r1 ON r1.specific_name = rru.routine_name
486 WHERE r0.routine_schema = 'temp_func_test' AND
487 r1.routine_schema = 'temp_func_test'
489 routine_name | routine_name
490 ----------------+----------------
491 functest_is_4b | functest_is_4a
494 SELECT routine_name, sequence_name FROM information_schema.routine_sequence_usage
495 WHERE routine_schema = 'temp_func_test'
497 routine_name | sequence_name
498 ---------------+---------------
499 functest_is_5 | functest1
500 functest_is_6 | functest1
503 SELECT routine_name, table_name, column_name FROM information_schema.routine_column_usage
504 WHERE routine_schema = 'temp_func_test'
506 routine_name | table_name | column_name
507 ---------------+------------+-------------
508 functest_is_7 | functest2 | a
511 SELECT routine_name, table_name FROM information_schema.routine_table_usage
512 WHERE routine_schema = 'temp_func_test'
514 routine_name | table_name
515 ---------------+------------
516 functest_is_7 | functest2
519 DROP FUNCTION functest_IS_4a CASCADE;
520 NOTICE: drop cascades to function functest_is_4b(integer)
521 DROP SEQUENCE functest1 CASCADE;
522 NOTICE: drop cascades to 2 other objects
523 DETAIL: drop cascades to function functest_is_5(integer)
524 drop cascades to function functest_is_6()
525 DROP TABLE functest2 CASCADE;
526 NOTICE: drop cascades to function functest_is_7()
528 CREATE FUNCTION functest_B_2(bigint) RETURNS bool LANGUAGE 'sql'
529 IMMUTABLE AS 'SELECT $1 > 0';
530 DROP FUNCTION functest_b_1;
531 DROP FUNCTION functest_b_1; -- error, not found
532 ERROR: could not find a function named "functest_b_1"
533 DROP FUNCTION functest_b_2; -- error, ambiguous
534 ERROR: function name "functest_b_2" is not unique
535 HINT: Specify the argument list to select the function unambiguously.
536 -- CREATE OR REPLACE tests
537 CREATE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL AS 'SELECT $1';
538 CREATE OR REPLACE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL WINDOW AS 'SELECT $1';
539 ERROR: cannot change routine kind
540 DETAIL: "functest1" is a function.
541 CREATE OR REPLACE PROCEDURE functest1(a int) LANGUAGE SQL AS 'SELECT $1';
542 ERROR: cannot change routine kind
543 DETAIL: "functest1" is a function.
544 DROP FUNCTION functest1(a int);
545 -- inlining of set-returning functions
546 CREATE TABLE functest3 (a int);
547 INSERT INTO functest3 VALUES (1), (2), (3);
548 CREATE FUNCTION functest_sri1() RETURNS SETOF int
552 SELECT * FROM functest3;
554 SELECT * FROM functest_sri1();
562 EXPLAIN (verbose, costs off) SELECT * FROM functest_sri1();
564 --------------------------------------
565 Seq Scan on temp_func_test.functest3
569 CREATE FUNCTION functest_sri2() RETURNS SETOF int
573 SELECT * FROM functest3;
575 SELECT * FROM functest_sri2();
583 EXPLAIN (verbose, costs off) SELECT * FROM functest_sri2();
585 --------------------------------------
586 Seq Scan on temp_func_test.functest3
590 DROP TABLE functest3 CASCADE;
591 NOTICE: drop cascades to function functest_sri2()
592 -- Check behavior of VOID-returning SQL functions
593 CREATE FUNCTION voidtest1(a int) RETURNS VOID LANGUAGE SQL AS
595 SELECT voidtest1(42);
601 CREATE FUNCTION voidtest2(a int, b int) RETURNS VOID LANGUAGE SQL AS
602 $$ SELECT voidtest1(a + b) $$;
603 SELECT voidtest2(11,22);
609 -- currently, we can inline voidtest2 but not voidtest1
610 EXPLAIN (verbose, costs off) SELECT voidtest2(11,22);
612 -------------------------
614 Output: voidtest1(33)
617 CREATE TEMP TABLE sometable(f1 int);
618 CREATE FUNCTION voidtest3(a int) RETURNS VOID LANGUAGE SQL AS
619 $$ INSERT INTO sometable VALUES(a + 1) $$;
620 SELECT voidtest3(17);
626 CREATE FUNCTION voidtest4(a int) RETURNS VOID LANGUAGE SQL AS
627 $$ INSERT INTO sometable VALUES(a - 1) RETURNING f1 $$;
628 SELECT voidtest4(39);
641 CREATE FUNCTION voidtest5(a int) RETURNS SETOF VOID LANGUAGE SQL AS
642 $$ SELECT generate_series(1, a) $$ STABLE;
643 SELECT * FROM voidtest5(3);
649 DROP SCHEMA temp_func_test CASCADE;
650 NOTICE: drop cascades to 29 other objects
651 DETAIL: drop cascades to function functest_a_1(text,date)
652 drop cascades to function functest_a_2(text[])
653 drop cascades to function functest_a_3()
654 drop cascades to function functest_b_2(integer)
655 drop cascades to function functest_b_3(integer)
656 drop cascades to function functest_b_4(integer)
657 drop cascades to function functest_c_1(integer)
658 drop cascades to function functest_c_2(integer)
659 drop cascades to function functest_c_3(integer)
660 drop cascades to function functest_e_1(integer)
661 drop cascades to function functest_e_2(integer)
662 drop cascades to function functest_f_1(integer)
663 drop cascades to function functest_f_2(integer)
664 drop cascades to function functest_f_3(integer)
665 drop cascades to function functest_f_4(integer)
666 drop cascades to function functest_s_1(text,date)
667 drop cascades to function functest_s_2(text[])
668 drop cascades to function functest_s_3()
669 drop cascades to function functest_s_3a()
670 drop cascades to function functest_s_10(text,date)
671 drop cascades to function functest_s_13()
672 drop cascades to function functest_s_15(integer)
673 drop cascades to function functest_b_2(bigint)
674 drop cascades to function functest_sri1()
675 drop cascades to function voidtest1(integer)
676 drop cascades to function voidtest2(integer,integer)
677 drop cascades to function voidtest3(integer)
678 drop cascades to function voidtest4(integer)
679 drop cascades to function voidtest5(integer)
680 DROP USER regress_unpriv_user;