@@ -36,7 +36,10 @@ ERROR: spiexceptions.SyntaxError: syntax error at or near "syntax"
3636LINE 1: syntax error
3737 ^
3838QUERY: syntax error
39- CONTEXT: PL/Python function "sql_syntax_error"
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"
4043/* check the handling of uncaught python exceptions
4144 */
4245CREATE FUNCTION exception_index_invalid(text) RETURNS text
@@ -45,7 +48,10 @@ CREATE FUNCTION exception_index_invalid(text) RETURNS text
4548 LANGUAGE plpythonu;
4649SELECT exception_index_invalid('test');
4750ERROR: IndexError: list index out of range
48- CONTEXT: PL/Python function "exception_index_invalid"
51+ CONTEXT: Traceback (most recent call last):
52+ PL/Python function "exception_index_invalid", line 1, in <module>
53+ return args[1]
54+ PL/Python function "exception_index_invalid"
4955/* check handling of nested exceptions
5056 */
5157CREATE FUNCTION exception_index_invalid_nested() RETURNS text
@@ -59,7 +65,10 @@ LINE 1: SELECT test5('foo')
5965 ^
6066HINT: No function matches the given name and argument types. You might need to add explicit type casts.
6167QUERY: SELECT test5('foo')
62- CONTEXT: PL/Python function "exception_index_invalid_nested"
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"
6372/* a typo
6473 */
6574CREATE FUNCTION invalid_type_uncaught(a text) RETURNS text
@@ -75,7 +84,10 @@ return None
7584 LANGUAGE plpythonu;
7685SELECT invalid_type_uncaught('rick');
7786ERROR: spiexceptions.UndefinedObject: type "test" does not exist
78- CONTEXT: PL/Python function "invalid_type_uncaught"
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"
7991/* for what it's worth catch the exception generated by
8092 * the typo, and return None
8193 */
@@ -121,7 +133,10 @@ return None
121133 LANGUAGE plpythonu;
122134SELECT invalid_type_reraised('rick');
123135ERROR: plpy.Error: type "test" does not exist
124- CONTEXT: PL/Python function "invalid_type_reraised"
136+ CONTEXT: Traceback (most recent call last):
137+ PL/Python function "invalid_type_reraised", line 6, in <module>
138+ plpy.error(str(ex))
139+ PL/Python function "invalid_type_reraised"
125140/* no typo no messing about
126141 */
127142CREATE FUNCTION valid_type(a text) RETURNS text
@@ -140,6 +155,164 @@ SELECT valid_type('rick');
140155
141156(1 row)
142157
158+ /* error in nested functions to get a traceback
159+ */
160+ CREATE FUNCTION nested_error() RETURNS text
161+ AS
162+ 'def fun1():
163+ plpy.error("boom")
164+
165+ def fun2():
166+ fun1()
167+
168+ def fun3():
169+ fun2()
170+
171+ fun3()
172+ return "not reached"
173+ '
174+ LANGUAGE plpythonu;
175+ SELECT nested_error();
176+ ERROR: plpy.Error: boom
177+ CONTEXT: Traceback (most recent call last):
178+ PL/Python function "nested_error", line 10, in <module>
179+ fun3()
180+ PL/Python function "nested_error", line 8, in fun3
181+ fun2()
182+ PL/Python function "nested_error", line 5, in fun2
183+ fun1()
184+ PL/Python function "nested_error", line 2, in fun1
185+ plpy.error("boom")
186+ PL/Python function "nested_error"
187+ /* raising plpy.Error is just like calling plpy.error
188+ */
189+ CREATE FUNCTION nested_error_raise() RETURNS text
190+ AS
191+ 'def fun1():
192+ raise plpy.Error("boom")
193+
194+ def fun2():
195+ fun1()
196+
197+ def fun3():
198+ fun2()
199+
200+ fun3()
201+ return "not reached"
202+ '
203+ LANGUAGE plpythonu;
204+ SELECT nested_error_raise();
205+ ERROR: plpy.Error: boom
206+ CONTEXT: Traceback (most recent call last):
207+ PL/Python function "nested_error_raise", line 10, in <module>
208+ fun3()
209+ PL/Python function "nested_error_raise", line 8, in fun3
210+ fun2()
211+ PL/Python function "nested_error_raise", line 5, in fun2
212+ fun1()
213+ PL/Python function "nested_error_raise", line 2, in fun1
214+ raise plpy.Error("boom")
215+ PL/Python function "nested_error_raise"
216+ /* using plpy.warning should not produce a traceback
217+ */
218+ CREATE FUNCTION nested_warning() RETURNS text
219+ AS
220+ 'def fun1():
221+ plpy.warning("boom")
222+
223+ def fun2():
224+ fun1()
225+
226+ def fun3():
227+ fun2()
228+
229+ fun3()
230+ return "you''ve been warned"
231+ '
232+ LANGUAGE plpythonu;
233+ SELECT nested_warning();
234+ WARNING: boom
235+ CONTEXT: PL/Python function "nested_warning"
236+ nested_warning
237+ --------------------
238+ you've been warned
239+ (1 row)
240+
241+ /* AttributeError at toplevel used to give segfaults with the traceback
242+ */
243+ CREATE FUNCTION toplevel_attribute_error() RETURNS void AS
244+ $$
245+ plpy.nonexistent
246+ $$ LANGUAGE plpythonu;
247+ SELECT toplevel_attribute_error();
248+ ERROR: AttributeError: 'module' object has no attribute 'nonexistent'
249+ CONTEXT: Traceback (most recent call last):
250+ PL/Python function "toplevel_attribute_error", line 2, in <module>
251+ plpy.nonexistent
252+ PL/Python function "toplevel_attribute_error"
253+ /* Calling PL/Python functions from SQL and vice versa should not lose context.
254+ */
255+ CREATE OR REPLACE FUNCTION python_traceback() RETURNS void AS $$
256+ def first():
257+ second()
258+
259+ def second():
260+ third()
261+
262+ def third():
263+ plpy.execute("select sql_error()")
264+
265+ first()
266+ $$ LANGUAGE plpythonu;
267+ CREATE OR REPLACE FUNCTION sql_error() RETURNS void AS $$
268+ begin
269+ select 1/0;
270+ end
271+ $$ LANGUAGE plpgsql;
272+ CREATE OR REPLACE FUNCTION python_from_sql_error() RETURNS void AS $$
273+ begin
274+ select python_traceback();
275+ end
276+ $$ LANGUAGE plpgsql;
277+ CREATE OR REPLACE FUNCTION sql_from_python_error() RETURNS void AS $$
278+ plpy.execute("select sql_error()")
279+ $$ LANGUAGE plpythonu;
280+ SELECT python_traceback();
281+ ERROR: spiexceptions.DivisionByZero: division by zero
282+ CONTEXT: Traceback (most recent call last):
283+ PL/Python function "python_traceback", line 11, in <module>
284+ first()
285+ PL/Python function "python_traceback", line 3, in first
286+ second()
287+ PL/Python function "python_traceback", line 6, in second
288+ third()
289+ PL/Python function "python_traceback", line 9, in third
290+ plpy.execute("select sql_error()")
291+ PL/Python function "python_traceback"
292+ SELECT sql_error();
293+ ERROR: division by zero
294+ CONTEXT: SQL statement "select 1/0"
295+ PL/pgSQL function "sql_error" line 3 at SQL statement
296+ SELECT python_from_sql_error();
297+ ERROR: spiexceptions.DivisionByZero: division by zero
298+ CONTEXT: Traceback (most recent call last):
299+ PL/Python function "python_traceback", line 11, in <module>
300+ first()
301+ PL/Python function "python_traceback", line 3, in first
302+ second()
303+ PL/Python function "python_traceback", line 6, in second
304+ third()
305+ PL/Python function "python_traceback", line 9, in third
306+ plpy.execute("select sql_error()")
307+ PL/Python function "python_traceback"
308+ SQL statement "select python_traceback()"
309+ PL/pgSQL function "python_from_sql_error" line 3 at SQL statement
310+ SELECT sql_from_python_error();
311+ ERROR: spiexceptions.DivisionByZero: division by zero
312+ CONTEXT: Traceback (most recent call last):
313+ PL/Python function "sql_from_python_error", line 2, in <module>
314+ plpy.execute("select sql_error()")
315+ PL/Python function "sql_from_python_error"
143316/* check catching specific types of exceptions
144317 */
145318CREATE TABLE specific (
@@ -187,7 +360,10 @@ plpy.execute("rollback to save")
187360$$ LANGUAGE plpythonu;
188361SELECT manual_subxact();
189362ERROR: plpy.SPIError: SPI_execute failed: SPI_ERROR_TRANSACTION
190- CONTEXT: PL/Python function "manual_subxact"
363+ CONTEXT: Traceback (most recent call last):
364+ PL/Python function "manual_subxact", line 2, in <module>
365+ plpy.execute("savepoint save")
366+ PL/Python function "manual_subxact"
191367/* same for prepared plans
192368 */
193369CREATE FUNCTION manual_subxact_prepared() RETURNS void AS $$
@@ -199,4 +375,7 @@ plpy.execute(rollback)
199375$$ LANGUAGE plpythonu;
200376SELECT manual_subxact_prepared();
201377ERROR: plpy.SPIError: SPI_execute_plan failed: SPI_ERROR_TRANSACTION
202- CONTEXT: PL/Python function "manual_subxact_prepared"
378+ CONTEXT: Traceback (most recent call last):
379+ PL/Python function "manual_subxact_prepared", line 4, in <module>
380+ plpy.execute(save)
381+ PL/Python function "manual_subxact_prepared"
0 commit comments