1 CREATE FUNCTION global_test_one() returns text
3 'if not SD.has_key("global_test"):
4 SD["global_test"] = "set by global_test_one"
5 if not GD.has_key("global_test"):
6 GD["global_test"] = "set by global_test_one"
7 return "SD: " + SD["global_test"] + ", GD: " + GD["global_test"]'
9 CREATE FUNCTION global_test_two() returns text
11 'if not SD.has_key("global_test"):
12 SD["global_test"] = "set by global_test_two"
13 if not GD.has_key("global_test"):
14 GD["global_test"] = "set by global_test_two"
15 return "SD: " + SD["global_test"] + ", GD: " + GD["global_test"]'
17 CREATE FUNCTION static_test() returns int4
19 'if SD.has_key("call"):
20 SD["call"] = SD["call"] + 1
26 -- import python modules
27 CREATE FUNCTION import_fail() returns text
32 plpy.notice("import socket failed -- %s" % str(ex))
33 return "failed as expected"
34 return "succeeded, that wasn''t supposed to happen"'
36 CREATE FUNCTION import_succeed() returns text
53 plpy.notice("import failed -- %s" % str(ex))
54 return "failed, that wasn''t supposed to happen"
55 return "succeeded, as expected"'
57 CREATE FUNCTION import_test_one(p text) RETURNS text
61 return digest.hexdigest()'
63 CREATE FUNCTION import_test_two(u users) RETURNS text
66 plain = u["fname"] + u["lname"]
67 digest = sha.new(plain);
68 return "sha hash of " + plain + " is " + digest.hexdigest()'
70 CREATE FUNCTION argument_test_one(u users, a1 text, a2 text) RETURNS text
76 out.append("%s: %s" % (key, u[key]))
77 words = a1 + " " + a2 + " => {" + ", ".join(out) + "}"
80 -- these triggers are dedicated to HPHC of RI who
81 -- decided that my kid's name was william not willem, and
82 -- vigorously resisted all efforts at correction. they have
83 -- since gone bankrupt...
84 CREATE FUNCTION users_insert() returns trigger
86 'if TD["new"]["fname"] == None or TD["new"]["lname"] == None:
88 if TD["new"]["username"] == None:
89 TD["new"]["username"] = TD["new"]["fname"][:1] + "_" + TD["new"]["lname"]
93 if TD["new"]["fname"] == "william":
94 TD["new"]["fname"] = TD["args"][0]
98 CREATE FUNCTION users_update() returns trigger
100 'if TD["event"] == "UPDATE":
101 if TD["old"]["fname"] != TD["new"]["fname"] and TD["old"]["fname"] == TD["args"][0]:
105 CREATE FUNCTION users_delete() RETURNS trigger
107 'if TD["old"]["fname"] == TD["args"][0]:
111 CREATE TRIGGER users_insert_trig BEFORE INSERT ON users FOR EACH ROW
112 EXECUTE PROCEDURE users_insert ('willem');
113 CREATE TRIGGER users_update_trig BEFORE UPDATE ON users FOR EACH ROW
114 EXECUTE PROCEDURE users_update ('willem');
115 CREATE TRIGGER users_delete_trig BEFORE DELETE ON users FOR EACH ROW
116 EXECUTE PROCEDURE users_delete ('willem');
118 CREATE TABLE trigger_test
120 CREATE FUNCTION trigger_data() returns trigger language plpythonu as $$
122 if TD.has_key('relid'):
123 TD['relid'] = "bogus:12345"
129 plpy.notice("TD[" + key + "] => " + str(val))
134 CREATE TRIGGER show_trigger_data_trig
135 BEFORE INSERT OR UPDATE OR DELETE ON trigger_test
136 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
137 insert into trigger_test values(1,'insert');
138 NOTICE: ("TD[args] => ['23', 'skidoo']",)
139 NOTICE: ('TD[event] => INSERT',)
140 NOTICE: ('TD[level] => ROW',)
141 NOTICE: ('TD[name] => show_trigger_data_trig',)
142 NOTICE: ("TD[new] => {'i': 1, 'v': 'insert'}",)
143 NOTICE: ('TD[old] => None',)
144 NOTICE: ('TD[relid] => bogus:12345',)
145 NOTICE: ('TD[table_name] => trigger_test',)
146 NOTICE: ('TD[table_schema] => public',)
147 NOTICE: ('TD[when] => BEFORE',)
148 update trigger_test set v = 'update' where i = 1;
149 NOTICE: ("TD[args] => ['23', 'skidoo']",)
150 NOTICE: ('TD[event] => UPDATE',)
151 NOTICE: ('TD[level] => ROW',)
152 NOTICE: ('TD[name] => show_trigger_data_trig',)
153 NOTICE: ("TD[new] => {'i': 1, 'v': 'update'}",)
154 NOTICE: ("TD[old] => {'i': 1, 'v': 'insert'}",)
155 NOTICE: ('TD[relid] => bogus:12345',)
156 NOTICE: ('TD[table_name] => trigger_test',)
157 NOTICE: ('TD[table_schema] => public',)
158 NOTICE: ('TD[when] => BEFORE',)
159 delete from trigger_test;
160 NOTICE: ("TD[args] => ['23', 'skidoo']",)
161 NOTICE: ('TD[event] => DELETE',)
162 NOTICE: ('TD[level] => ROW',)
163 NOTICE: ('TD[name] => show_trigger_data_trig',)
164 NOTICE: ('TD[new] => None',)
165 NOTICE: ("TD[old] => {'i': 1, 'v': 'update'}",)
166 NOTICE: ('TD[relid] => bogus:12345',)
167 NOTICE: ('TD[table_name] => trigger_test',)
168 NOTICE: ('TD[table_schema] => public',)
169 NOTICE: ('TD[when] => BEFORE',)
171 DROP TRIGGER show_trigger_data_trig on trigger_test;
173 DROP FUNCTION trigger_data();
176 CREATE FUNCTION nested_call_one(a text) RETURNS text
178 'q = "SELECT nested_call_two(''%s'')" % a
182 CREATE FUNCTION nested_call_two(a text) RETURNS text
184 'q = "SELECT nested_call_three(''%s'')" % a
188 CREATE FUNCTION nested_call_three(a text) RETURNS text
193 CREATE FUNCTION spi_prepared_plan_test_one(a text) RETURNS text
195 'if not SD.has_key("myplan"):
196 q = "SELECT count(*) FROM users WHERE lname = $1"
197 SD["myplan"] = plpy.prepare(q, [ "text" ])
199 rv = plpy.execute(SD["myplan"], [a])
200 return "there are " + str(rv[0]["count"]) + " " + str(a) + "s"
201 except Exception, ex:
206 CREATE FUNCTION spi_prepared_plan_test_nested(a text) RETURNS text
208 'if not SD.has_key("myplan"):
209 q = "SELECT spi_prepared_plan_test_one(''%s'') as count" % a
210 SD["myplan"] = plpy.prepare(q)
212 rv = plpy.execute(SD["myplan"])
214 return rv[0]["count"]
215 except Exception, ex:
220 /* really stupid function just to get the module loaded
222 CREATE FUNCTION stupid() RETURNS text AS 'return "zarkon"' LANGUAGE plpythonu;
225 CREATE FUNCTION invalid_type_uncaught(a text) RETURNS text
227 'if not SD.has_key("plan"):
228 q = "SELECT fname FROM users WHERE lname = $1"
229 SD["plan"] = plpy.prepare(q, [ "test" ])
230 rv = plpy.execute(SD["plan"], [ a ])
232 return rv[0]["fname"]
236 /* for what it's worth catch the exception generated by
237 * the typo, and return None
239 CREATE FUNCTION invalid_type_caught(a text) RETURNS text
241 'if not SD.has_key("plan"):
242 q = "SELECT fname FROM users WHERE lname = $1"
244 SD["plan"] = plpy.prepare(q, [ "test" ])
245 except plpy.SPIError, ex:
248 rv = plpy.execute(SD["plan"], [ a ])
250 return rv[0]["fname"]
254 /* for what it's worth catch the exception generated by
255 * the typo, and reraise it as a plain error
257 CREATE FUNCTION invalid_type_reraised(a text) RETURNS text
259 'if not SD.has_key("plan"):
260 q = "SELECT fname FROM users WHERE lname = $1"
262 SD["plan"] = plpy.prepare(q, [ "test" ])
263 except plpy.SPIError, ex:
265 rv = plpy.execute(SD["plan"], [ a ])
267 return rv[0]["fname"]
271 /* no typo no messing about
273 CREATE FUNCTION valid_type(a text) RETURNS text
275 'if not SD.has_key("plan"):
276 SD["plan"] = plpy.prepare("SELECT fname FROM users WHERE lname = $1", [ "text" ])
277 rv = plpy.execute(SD["plan"], [ a ])
279 return rv[0]["fname"]
283 /* Flat out syntax error
285 CREATE FUNCTION sql_syntax_error() RETURNS text
287 'plpy.execute("syntax error")'
289 /* check the handling of uncaught python exceptions
291 CREATE FUNCTION exception_index_invalid(text) RETURNS text
295 /* check handling of nested exceptions
297 CREATE FUNCTION exception_index_invalid_nested() RETURNS text
299 'rv = plpy.execute("SELECT test5(''foo'')")
302 CREATE FUNCTION join_sequences(s sequences) RETURNS text
304 'if not s["multipart"]:
306 q = "SELECT sequence FROM xsequences WHERE pid = ''%s''" % s["pid"]
310 seq = seq + r["sequence"]
315 -- Universal Newline Support
317 CREATE OR REPLACE FUNCTION newline_lf() RETURNS integer AS
318 E'x = 100\ny = 23\nreturn x + y\n'
320 CREATE OR REPLACE FUNCTION newline_cr() RETURNS integer AS
321 E'x = 100\ry = 23\rreturn x + y\r'
323 CREATE OR REPLACE FUNCTION newline_crlf() RETURNS integer AS
324 E'x = 100\r\ny = 23\r\nreturn x + y\r\n'
327 -- Unicode error handling
329 CREATE FUNCTION unicode_return_error() RETURNS text AS E'
331 ' LANGUAGE plpythonu;
332 CREATE FUNCTION unicode_trigger_error() RETURNS trigger AS E'
333 TD["new"]["testvalue"] = u"\\x80"
335 ' LANGUAGE plpythonu;
336 CREATE TRIGGER unicode_test_bi BEFORE INSERT ON unicode_test
337 FOR EACH ROW EXECUTE PROCEDURE unicode_trigger_error();
338 CREATE FUNCTION unicode_plan_error1() RETURNS text AS E'
339 plan = plpy.prepare("SELECT $1 AS testvalue", ["text"])
340 rv = plpy.execute(plan, [u"\\x80"], 1)
341 return rv[0]["testvalue"]
342 ' LANGUAGE plpythonu;
343 CREATE FUNCTION unicode_plan_error2() RETURNS text AS E'
344 plan = plpy.prepare("SELECT $1 AS testvalue1, $2 AS testvalue2", ["text", "text"])
345 rv = plpy.execute(plan, u"\\x80", 1)
346 return rv[0]["testvalue1"]
347 ' LANGUAGE plpythonu;
348 -- Tests for functions that return void
349 CREATE FUNCTION test_void_func1() RETURNS void AS $$
351 $$ LANGUAGE plpythonu;
352 -- illegal: can't return non-None value in void-returning func
353 CREATE FUNCTION test_void_func2() RETURNS void AS $$
355 $$ LANGUAGE plpythonu;
356 CREATE FUNCTION test_return_none() RETURNS int AS $$
358 $$ LANGUAGE plpythonu;
360 -- Test named parameters
362 CREATE FUNCTION test_param_names1(a0 integer, a1 text) RETURNS boolean AS $$
366 $$ LANGUAGE plpythonu;
367 CREATE FUNCTION test_param_names2(u users) RETURNS text AS $$
370 $$ LANGUAGE plpythonu;
371 -- use deliberately wrong parameter names
372 CREATE FUNCTION test_param_names3(a0 integer) RETURNS boolean AS $$
377 assert e.args[0].find("a1") > -1
379 $$ LANGUAGE plpythonu;
381 -- Test returning SETOF
383 CREATE FUNCTION test_setof_as_list(count integer, content text) RETURNS SETOF text AS $$
384 return [ content ]*count
385 $$ LANGUAGE plpythonu;
386 CREATE FUNCTION test_setof_as_tuple(count integer, content text) RETURNS SETOF text AS $$
388 for i in xrange(count):
391 $$ LANGUAGE plpythonu;
392 CREATE FUNCTION test_setof_as_iterator(count integer, content text) RETURNS SETOF text AS $$
394 def __init__ (self, icount, icontent):
395 self.icontent = icontent
404 return producer(count, content)
405 $$ LANGUAGE plpythonu;
407 -- Test returning tuples
409 CREATE FUNCTION test_table_record_as(typ text, first text, second integer, retnull boolean) RETURNS table_record AS $$
413 return { 'first': first, 'second': second, 'additionalfield': 'must not cause trouble' }
415 return ( first, second )
417 return [ first, second ]
419 class type_record: pass
420 type_record.first = first
421 type_record.second = second
423 $$ LANGUAGE plpythonu;
424 CREATE FUNCTION test_type_record_as(typ text, first text, second integer, retnull boolean) RETURNS type_record AS $$
428 return { 'first': first, 'second': second, 'additionalfield': 'must not cause trouble' }
430 return ( first, second )
432 return [ first, second ]
434 class type_record: pass
435 type_record.first = first
436 type_record.second = second
438 $$ LANGUAGE plpythonu;
439 CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
440 return first + '_in_to_out';
441 $$ LANGUAGE plpythonu;
442 -- this doesn't work yet :-(
443 CREATE FUNCTION test_in_out_params_multi(first in text,
444 second out text, third out text) AS $$
445 return first + '_record_in_to_out';
446 $$ LANGUAGE plpythonu;
447 CREATE FUNCTION test_inout_params(first inout text) AS $$
448 return first + '_inout';
449 $$ LANGUAGE plpythonu;