1-- 2-- CREATE FUNCTION 3-- 4-- Assorted tests using SQL-language functions 5-- 6 7-- All objects made in this test are in temp_func_test schema 8 9CREATE USER regress_unpriv_user; 10 11CREATE SCHEMA temp_func_test; 12GRANT ALL ON SCHEMA temp_func_test TO public; 13 14SET search_path TO temp_func_test, public; 15 16-- 17-- Make sanity checks on the pg_proc entries created by CREATE FUNCTION 18-- 19 20-- 21-- ARGUMENT and RETURN TYPES 22-- 23CREATE FUNCTION functest_A_1(text, date) RETURNS bool LANGUAGE 'sql' 24 AS 'SELECT $1 = ''abcd'' AND $2 > ''2001-01-01'''; 25CREATE FUNCTION functest_A_2(text[]) RETURNS int LANGUAGE 'sql' 26 AS 'SELECT $1[0]::int'; 27CREATE FUNCTION functest_A_3() RETURNS bool LANGUAGE 'sql' 28 AS 'SELECT false'; 29SELECT proname, prorettype::regtype, proargtypes::regtype[] FROM pg_proc 30 WHERE oid in ('functest_A_1'::regproc, 31 'functest_A_2'::regproc, 32 'functest_A_3'::regproc) ORDER BY proname; 33 34-- 35-- IMMUTABLE | STABLE | VOLATILE 36-- 37CREATE FUNCTION functest_B_1(int) RETURNS bool LANGUAGE 'sql' 38 AS 'SELECT $1 > 0'; 39CREATE FUNCTION functest_B_2(int) RETURNS bool LANGUAGE 'sql' 40 IMMUTABLE AS 'SELECT $1 > 0'; 41CREATE FUNCTION functest_B_3(int) RETURNS bool LANGUAGE 'sql' 42 STABLE AS 'SELECT $1 = 0'; 43CREATE FUNCTION functest_B_4(int) RETURNS bool LANGUAGE 'sql' 44 VOLATILE AS 'SELECT $1 < 0'; 45SELECT proname, provolatile FROM pg_proc 46 WHERE oid in ('functest_B_1'::regproc, 47 'functest_B_2'::regproc, 48 'functest_B_3'::regproc, 49 'functest_B_4'::regproc) ORDER BY proname; 50 51ALTER FUNCTION functest_B_2(int) VOLATILE; 52ALTER FUNCTION functest_B_3(int) COST 100; -- unrelated change, no effect 53SELECT proname, provolatile FROM pg_proc 54 WHERE oid in ('functest_B_1'::regproc, 55 'functest_B_2'::regproc, 56 'functest_B_3'::regproc, 57 'functest_B_4'::regproc) ORDER BY proname; 58 59-- 60-- SECURITY DEFINER | INVOKER 61-- 62CREATE FUNCTION functest_C_1(int) RETURNS bool LANGUAGE 'sql' 63 AS 'SELECT $1 > 0'; 64CREATE FUNCTION functest_C_2(int) RETURNS bool LANGUAGE 'sql' 65 SECURITY DEFINER AS 'SELECT $1 = 0'; 66CREATE FUNCTION functest_C_3(int) RETURNS bool LANGUAGE 'sql' 67 SECURITY INVOKER AS 'SELECT $1 < 0'; 68SELECT proname, prosecdef FROM pg_proc 69 WHERE oid in ('functest_C_1'::regproc, 70 'functest_C_2'::regproc, 71 'functest_C_3'::regproc) ORDER BY proname; 72 73ALTER FUNCTION functest_C_1(int) IMMUTABLE; -- unrelated change, no effect 74ALTER FUNCTION functest_C_2(int) SECURITY INVOKER; 75ALTER FUNCTION functest_C_3(int) SECURITY DEFINER; 76SELECT proname, prosecdef FROM pg_proc 77 WHERE oid in ('functest_C_1'::regproc, 78 'functest_C_2'::regproc, 79 'functest_C_3'::regproc) ORDER BY proname; 80 81-- 82-- LEAKPROOF 83-- 84CREATE FUNCTION functest_E_1(int) RETURNS bool LANGUAGE 'sql' 85 AS 'SELECT $1 > 100'; 86CREATE FUNCTION functest_E_2(int) RETURNS bool LANGUAGE 'sql' 87 LEAKPROOF AS 'SELECT $1 > 100'; 88SELECT proname, proleakproof FROM pg_proc 89 WHERE oid in ('functest_E_1'::regproc, 90 'functest_E_2'::regproc) ORDER BY proname; 91 92ALTER FUNCTION functest_E_1(int) LEAKPROOF; 93ALTER FUNCTION functest_E_2(int) STABLE; -- unrelated change, no effect 94SELECT proname, proleakproof FROM pg_proc 95 WHERE oid in ('functest_E_1'::regproc, 96 'functest_E_2'::regproc) ORDER BY proname; 97 98ALTER FUNCTION functest_E_2(int) NOT LEAKPROOF; -- remove leakproof attribute 99SELECT proname, proleakproof FROM pg_proc 100 WHERE oid in ('functest_E_1'::regproc, 101 'functest_E_2'::regproc) ORDER BY proname; 102 103-- it takes superuser privilege to turn on leakproof, but not to turn off 104ALTER FUNCTION functest_E_1(int) OWNER TO regress_unpriv_user; 105ALTER FUNCTION functest_E_2(int) OWNER TO regress_unpriv_user; 106 107SET SESSION AUTHORIZATION regress_unpriv_user; 108SET search_path TO temp_func_test, public; 109ALTER FUNCTION functest_E_1(int) NOT LEAKPROOF; 110ALTER FUNCTION functest_E_2(int) LEAKPROOF; 111 112CREATE FUNCTION functest_E_3(int) RETURNS bool LANGUAGE 'sql' 113 LEAKPROOF AS 'SELECT $1 < 200'; -- fail 114 115RESET SESSION AUTHORIZATION; 116 117-- 118-- CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT 119-- 120CREATE FUNCTION functest_F_1(int) RETURNS bool LANGUAGE 'sql' 121 AS 'SELECT $1 > 50'; 122CREATE FUNCTION functest_F_2(int) RETURNS bool LANGUAGE 'sql' 123 CALLED ON NULL INPUT AS 'SELECT $1 = 50'; 124CREATE FUNCTION functest_F_3(int) RETURNS bool LANGUAGE 'sql' 125 RETURNS NULL ON NULL INPUT AS 'SELECT $1 < 50'; 126CREATE FUNCTION functest_F_4(int) RETURNS bool LANGUAGE 'sql' 127 STRICT AS 'SELECT $1 = 50'; 128SELECT proname, proisstrict FROM pg_proc 129 WHERE oid in ('functest_F_1'::regproc, 130 'functest_F_2'::regproc, 131 'functest_F_3'::regproc, 132 'functest_F_4'::regproc) ORDER BY proname; 133 134ALTER FUNCTION functest_F_1(int) IMMUTABLE; -- unrelated change, no effect 135ALTER FUNCTION functest_F_2(int) STRICT; 136ALTER FUNCTION functest_F_3(int) CALLED ON NULL INPUT; 137SELECT proname, proisstrict FROM pg_proc 138 WHERE oid in ('functest_F_1'::regproc, 139 'functest_F_2'::regproc, 140 'functest_F_3'::regproc, 141 'functest_F_4'::regproc) ORDER BY proname; 142 143 144-- pg_get_functiondef tests 145 146SELECT pg_get_functiondef('functest_A_1'::regproc); 147SELECT pg_get_functiondef('functest_B_3'::regproc); 148SELECT pg_get_functiondef('functest_C_3'::regproc); 149SELECT pg_get_functiondef('functest_F_2'::regproc); 150 151 152-- information_schema tests 153 154CREATE FUNCTION functest_IS_1(a int, b int default 1, c text default 'foo') 155 RETURNS int 156 LANGUAGE SQL 157 AS 'SELECT $1 + $2'; 158 159CREATE FUNCTION functest_IS_2(out a int, b int default 1) 160 RETURNS int 161 LANGUAGE SQL 162 AS 'SELECT $1'; 163 164CREATE FUNCTION functest_IS_3(a int default 1, out b int) 165 RETURNS int 166 LANGUAGE SQL 167 AS 'SELECT $1'; 168 169SELECT routine_name, ordinal_position, parameter_name, parameter_default 170 FROM information_schema.parameters JOIN information_schema.routines USING (specific_schema, specific_name) 171 WHERE routine_schema = 'temp_func_test' AND routine_name ~ '^functest_is_' 172 ORDER BY 1, 2; 173 174DROP FUNCTION functest_IS_1(int, int, text), functest_IS_2(int), functest_IS_3(int); 175 176-- overload 177CREATE FUNCTION functest_B_2(bigint) RETURNS bool LANGUAGE 'sql' 178 IMMUTABLE AS 'SELECT $1 > 0'; 179 180DROP FUNCTION functest_b_1; 181DROP FUNCTION functest_b_1; -- error, not found 182DROP FUNCTION functest_b_2; -- error, ambiguous 183 184 185-- CREATE OR REPLACE tests 186 187CREATE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL AS 'SELECT $1'; 188CREATE OR REPLACE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL WINDOW AS 'SELECT $1'; 189CREATE OR REPLACE PROCEDURE functest1(a int) LANGUAGE SQL AS 'SELECT $1'; 190DROP FUNCTION functest1(a int); 191 192 193-- Check behavior of VOID-returning SQL functions 194 195CREATE FUNCTION voidtest1(a int) RETURNS VOID LANGUAGE SQL AS 196$$ SELECT a + 1 $$; 197SELECT voidtest1(42); 198 199CREATE FUNCTION voidtest2(a int, b int) RETURNS VOID LANGUAGE SQL AS 200$$ SELECT voidtest1(a + b) $$; 201SELECT voidtest2(11,22); 202 203-- currently, we can inline voidtest2 but not voidtest1 204EXPLAIN (verbose, costs off) SELECT voidtest2(11,22); 205 206CREATE TEMP TABLE sometable(f1 int); 207 208CREATE FUNCTION voidtest3(a int) RETURNS VOID LANGUAGE SQL AS 209$$ INSERT INTO sometable VALUES(a + 1) $$; 210SELECT voidtest3(17); 211 212CREATE FUNCTION voidtest4(a int) RETURNS VOID LANGUAGE SQL AS 213$$ INSERT INTO sometable VALUES(a - 1) RETURNING f1 $$; 214SELECT voidtest4(39); 215 216TABLE sometable; 217 218CREATE FUNCTION voidtest5(a int) RETURNS SETOF VOID LANGUAGE SQL AS 219$$ SELECT generate_series(1, a) $$ STABLE; 220SELECT * FROM voidtest5(3); 221 222-- Cleanup 223DROP SCHEMA temp_func_test CASCADE; 224DROP USER regress_unpriv_user; 225RESET search_path; 226