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