Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2bd78eb

Browse files
committed
Add traceback information to PL/Python errors
This mimics the traceback information the Python interpreter printswith exceptions.Jan Urbański
1 parentbf6848b commit2bd78eb

11 files changed

+786
-76
lines changed

‎src/pl/plpython/expected/plpython_do.out

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@ NOTICE: This is plpythonu.
33
CONTEXT: PL/Python anonymous code block
44
DO $$ nonsense $$ LANGUAGE plpythonu;
55
ERROR: NameError: global name 'nonsense' is not defined
6-
CONTEXT: PL/Python anonymous code block
6+
CONTEXT: Traceback (most recent call last):
7+
PL/Python anonymous code block, line 1, in <module>
8+
nonsense
9+
PL/Python anonymous code block

‎src/pl/plpython/expected/plpython_error.out

Lines changed: 186 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ ERROR: spiexceptions.SyntaxError: syntax error at or near "syntax"
3636
LINE 1: syntax error
3737
^
3838
QUERY: 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
*/
4245
CREATE FUNCTION exception_index_invalid(text) RETURNS text
@@ -45,7 +48,10 @@ CREATE FUNCTION exception_index_invalid(text) RETURNS text
4548
LANGUAGE plpythonu;
4649
SELECT exception_index_invalid('test');
4750
ERROR: 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
*/
5157
CREATE FUNCTION exception_index_invalid_nested() RETURNS text
@@ -59,7 +65,10 @@ LINE 1: SELECT test5('foo')
5965
^
6066
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
6167
QUERY: 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
*/
6574
CREATE FUNCTION invalid_type_uncaught(a text) RETURNS text
@@ -75,7 +84,10 @@ return None
7584
LANGUAGE plpythonu;
7685
SELECT invalid_type_uncaught('rick');
7786
ERROR: 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;
122134
SELECT invalid_type_reraised('rick');
123135
ERROR: 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
*/
127142
CREATE 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
*/
145318
CREATE TABLE specific (
@@ -187,7 +360,10 @@ plpy.execute("rollback to save")
187360
$$ LANGUAGE plpythonu;
188361
SELECT manual_subxact();
189362
ERROR: 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
*/
193369
CREATE FUNCTION manual_subxact_prepared() RETURNS void AS $$
@@ -199,4 +375,7 @@ plpy.execute(rollback)
199375
$$ LANGUAGE plpythonu;
200376
SELECT manual_subxact_prepared();
201377
ERROR: 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

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp