1 -- test error handling, i forgot to restore Warn_restart in
2 -- the trigger handler once. the errors and subsequent core dump were
4 /* Flat out Python syntax error
6 CREATE FUNCTION python_syntax_error() RETURNS text
10 ERROR: could not compile PL/Python function "python_syntax_error"
11 DETAIL: SyntaxError: invalid syntax (<string>, line 2)
12 /* With check_function_bodies = false the function should get defined
13 * and the error reported when called
15 SET check_function_bodies = false;
16 CREATE FUNCTION python_syntax_error() RETURNS text
20 SELECT python_syntax_error();
21 ERROR: could not compile PL/Python function "python_syntax_error"
22 DETAIL: SyntaxError: invalid syntax (<string>, line 2)
23 /* Run the function twice to check if the hashtable entry gets cleaned up */
24 SELECT python_syntax_error();
25 ERROR: could not compile PL/Python function "python_syntax_error"
26 DETAIL: SyntaxError: invalid syntax (<string>, line 2)
27 RESET check_function_bodies;
28 /* Flat out syntax error
30 CREATE FUNCTION sql_syntax_error() RETURNS text
32 'plpy.execute("syntax error")'
34 SELECT sql_syntax_error();
35 ERROR: spiexceptions.SyntaxError: syntax error at or near "syntax"
39 CONTEXT: Traceback (most recent call last):
40 PL/Python function "sql_syntax_error", line 1, in <module>
41 plpy.execute("syntax error")
42 PL/Python function "sql_syntax_error"
43 /* check the handling of uncaught python exceptions
45 CREATE FUNCTION exception_index_invalid(text) RETURNS text
49 SELECT exception_index_invalid('test');
50 ERROR: IndexError: list index out of range
51 CONTEXT: Traceback (most recent call last):
52 PL/Python function "exception_index_invalid", line 1, in <module>
54 PL/Python function "exception_index_invalid"
55 /* check handling of nested exceptions
57 CREATE FUNCTION exception_index_invalid_nested() RETURNS text
59 'rv = plpy.execute("SELECT test5(''foo'')")
62 SELECT exception_index_invalid_nested();
63 ERROR: spiexceptions.UndefinedFunction: function test5(unknown) does not exist
64 LINE 1: SELECT test5('foo')
66 HINT: No function matches the given name and argument types. You might need to add explicit type casts.
67 QUERY: SELECT test5('foo')
68 CONTEXT: Traceback (most recent call last):
69 PL/Python function "exception_index_invalid_nested", line 1, in <module>
70 rv = plpy.execute("SELECT test5('foo')")
71 PL/Python function "exception_index_invalid_nested"
74 CREATE FUNCTION invalid_type_uncaught(a text) RETURNS text
77 q = "SELECT fname FROM users WHERE lname = $1"
78 SD["plan"] = plpy.prepare(q, [ "test" ])
79 rv = plpy.execute(SD["plan"], [ a ])
85 SELECT invalid_type_uncaught('rick');
86 ERROR: spiexceptions.UndefinedObject: type "test" does not exist
87 CONTEXT: Traceback (most recent call last):
88 PL/Python function "invalid_type_uncaught", line 3, in <module>
89 SD["plan"] = plpy.prepare(q, [ "test" ])
90 PL/Python function "invalid_type_uncaught"
91 /* for what it's worth catch the exception generated by
92 * the typo, and return None
94 CREATE FUNCTION invalid_type_caught(a text) RETURNS text
97 q = "SELECT fname FROM users WHERE lname = $1"
99 SD["plan"] = plpy.prepare(q, [ "test" ])
100 except plpy.SPIError as ex:
103 rv = plpy.execute(SD["plan"], [ a ])
105 return rv[0]["fname"]
109 SELECT invalid_type_caught('rick');
110 NOTICE: type "test" does not exist
112 ---------------------
116 /* for what it's worth catch the exception generated by
117 * the typo, and reraise it as a plain error
119 CREATE FUNCTION invalid_type_reraised(a text) RETURNS text
121 'if "plan" not in SD:
122 q = "SELECT fname FROM users WHERE lname = $1"
124 SD["plan"] = plpy.prepare(q, [ "test" ])
125 except plpy.SPIError as ex:
127 rv = plpy.execute(SD["plan"], [ a ])
129 return rv[0]["fname"]
133 SELECT invalid_type_reraised('rick');
134 ERROR: plpy.Error: type "test" does not exist
135 CONTEXT: Traceback (most recent call last):
136 PL/Python function "invalid_type_reraised", line 6, in <module>
138 PL/Python function "invalid_type_reraised"
139 /* no typo no messing about
141 CREATE FUNCTION valid_type(a text) RETURNS text
143 'if "plan" not in SD:
144 SD["plan"] = plpy.prepare("SELECT fname FROM users WHERE lname = $1", [ "text" ])
145 rv = plpy.execute(SD["plan"], [ a ])
147 return rv[0]["fname"]
151 SELECT valid_type('rick');
157 /* error in nested functions to get a traceback
159 CREATE FUNCTION nested_error() RETURNS text
174 SELECT nested_error();
175 ERROR: plpy.Error: boom
176 CONTEXT: Traceback (most recent call last):
177 PL/Python function "nested_error", line 10, in <module>
179 PL/Python function "nested_error", line 8, in fun3
181 PL/Python function "nested_error", line 5, in fun2
183 PL/Python function "nested_error", line 2, in fun1
185 PL/Python function "nested_error"
186 /* raising plpy.Error is just like calling plpy.error
188 CREATE FUNCTION nested_error_raise() RETURNS text
191 raise plpy.Error("boom")
203 SELECT nested_error_raise();
204 ERROR: plpy.Error: boom
205 CONTEXT: Traceback (most recent call last):
206 PL/Python function "nested_error_raise", line 10, in <module>
208 PL/Python function "nested_error_raise", line 8, in fun3
210 PL/Python function "nested_error_raise", line 5, in fun2
212 PL/Python function "nested_error_raise", line 2, in fun1
213 raise plpy.Error("boom")
214 PL/Python function "nested_error_raise"
215 /* using plpy.warning should not produce a traceback
217 CREATE FUNCTION nested_warning() RETURNS text
229 return "you''ve been warned"
232 SELECT nested_warning();
239 /* AttributeError at toplevel used to give segfaults with the traceback
241 CREATE FUNCTION toplevel_attribute_error() RETURNS void AS
244 $$ LANGUAGE plpythonu;
245 SELECT toplevel_attribute_error();
246 ERROR: AttributeError: 'module' object has no attribute 'nonexistent'
247 CONTEXT: Traceback (most recent call last):
248 PL/Python function "toplevel_attribute_error", line 2, in <module>
250 PL/Python function "toplevel_attribute_error"
251 /* Calling PL/Python functions from SQL and vice versa should not lose context.
253 CREATE OR REPLACE FUNCTION python_traceback() RETURNS void AS $$
261 plpy.execute("select sql_error()")
264 $$ LANGUAGE plpythonu;
265 CREATE OR REPLACE FUNCTION sql_error() RETURNS void AS $$
270 CREATE OR REPLACE FUNCTION python_from_sql_error() RETURNS void AS $$
272 select python_traceback();
275 CREATE OR REPLACE FUNCTION sql_from_python_error() RETURNS void AS $$
276 plpy.execute("select sql_error()")
277 $$ LANGUAGE plpythonu;
278 SELECT python_traceback();
279 ERROR: spiexceptions.DivisionByZero: division by zero
280 CONTEXT: Traceback (most recent call last):
281 PL/Python function "python_traceback", line 11, in <module>
283 PL/Python function "python_traceback", line 3, in first
285 PL/Python function "python_traceback", line 6, in second
287 PL/Python function "python_traceback", line 9, in third
288 plpy.execute("select sql_error()")
289 PL/Python function "python_traceback"
291 ERROR: division by zero
292 CONTEXT: SQL statement "select 1/0"
293 PL/pgSQL function sql_error() line 3 at SQL statement
294 SELECT python_from_sql_error();
295 ERROR: spiexceptions.DivisionByZero: division by zero
296 CONTEXT: Traceback (most recent call last):
297 PL/Python function "python_traceback", line 11, in <module>
299 PL/Python function "python_traceback", line 3, in first
301 PL/Python function "python_traceback", line 6, in second
303 PL/Python function "python_traceback", line 9, in third
304 plpy.execute("select sql_error()")
305 PL/Python function "python_traceback"
306 SQL statement "select python_traceback()"
307 PL/pgSQL function python_from_sql_error() line 3 at SQL statement
308 SELECT sql_from_python_error();
309 ERROR: spiexceptions.DivisionByZero: division by zero
310 CONTEXT: Traceback (most recent call last):
311 PL/Python function "sql_from_python_error", line 2, in <module>
312 plpy.execute("select sql_error()")
313 PL/Python function "sql_from_python_error"
314 /* check catching specific types of exceptions
316 CREATE TABLE specific (
317 i integer PRIMARY KEY
319 CREATE FUNCTION specific_exception(i integer) RETURNS void AS
321 from plpy import spiexceptions
323 plpy.execute("insert into specific values (%s)" % (i or "NULL"));
324 except spiexceptions.NotNullViolation as e:
325 plpy.notice("Violated the NOT NULL constraint, sqlstate %s" % e.sqlstate)
326 except spiexceptions.UniqueViolation as e:
327 plpy.notice("Violated the UNIQUE constraint, sqlstate %s" % e.sqlstate)
328 $$ LANGUAGE plpythonu;
329 SELECT specific_exception(2);
335 SELECT specific_exception(NULL);
336 NOTICE: Violated the NOT NULL constraint, sqlstate 23502
342 SELECT specific_exception(2);
343 NOTICE: Violated the UNIQUE constraint, sqlstate 23505
349 /* SPI errors in PL/Python functions should preserve the SQLSTATE value
351 CREATE FUNCTION python_unique_violation() RETURNS void AS $$
352 plpy.execute("insert into specific values (1)")
353 plpy.execute("insert into specific values (1)")
354 $$ LANGUAGE plpythonu;
355 CREATE FUNCTION catch_python_unique_violation() RETURNS text AS $$
358 perform python_unique_violation();
359 exception when unique_violation then
362 return 'not reached';
365 SELECT catch_python_unique_violation();
366 catch_python_unique_violation
367 -------------------------------
371 /* manually starting subtransactions - a bad idea
373 CREATE FUNCTION manual_subxact() RETURNS void AS $$
374 plpy.execute("savepoint save")
375 plpy.execute("create table foo(x integer)")
376 plpy.execute("rollback to save")
377 $$ LANGUAGE plpythonu;
378 SELECT manual_subxact();
379 ERROR: plpy.SPIError: SPI_execute failed: SPI_ERROR_TRANSACTION
380 CONTEXT: Traceback (most recent call last):
381 PL/Python function "manual_subxact", line 2, in <module>
382 plpy.execute("savepoint save")
383 PL/Python function "manual_subxact"
384 /* same for prepared plans
386 CREATE FUNCTION manual_subxact_prepared() RETURNS void AS $$
387 save = plpy.prepare("savepoint save")
388 rollback = plpy.prepare("rollback to save")
390 plpy.execute("create table foo(x integer)")
391 plpy.execute(rollback)
392 $$ LANGUAGE plpythonu;
393 SELECT manual_subxact_prepared();
394 ERROR: plpy.SPIError: SPI_execute_plan failed: SPI_ERROR_TRANSACTION
395 CONTEXT: Traceback (most recent call last):
396 PL/Python function "manual_subxact_prepared", line 4, in <module>
398 PL/Python function "manual_subxact_prepared"
399 /* raising plpy.spiexception.* from python code should preserve sqlstate
401 CREATE FUNCTION plpy_raise_spiexception() RETURNS void AS $$
402 raise plpy.spiexceptions.DivisionByZero()
403 $$ LANGUAGE plpythonu;
406 SELECT plpy_raise_spiexception();
407 EXCEPTION WHEN division_by_zero THEN
411 /* setting a custom sqlstate should be handled
413 CREATE FUNCTION plpy_raise_spiexception_override() RETURNS void AS $$
414 exc = plpy.spiexceptions.DivisionByZero()
415 exc.sqlstate = 'SILLY'
417 $$ LANGUAGE plpythonu;
420 SELECT plpy_raise_spiexception_override();
421 EXCEPTION WHEN SQLSTATE 'SILLY' THEN
425 /* test the context stack trace for nested execution levels
427 CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
428 plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
430 $$ LANGUAGE plpythonu;
431 CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
432 plpy.execute("SELECT notice_innerfunc()")
434 $$ LANGUAGE plpythonu;
435 \set SHOW_CONTEXT always
436 SELECT notice_outerfunc();
438 CONTEXT: PL/Python anonymous code block
439 SQL statement "DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$"
440 PL/Python function "notice_innerfunc"
441 SQL statement "SELECT notice_innerfunc()"
442 PL/Python function "notice_outerfunc"