Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 27c405d

Browse files
committed
Enhanced error context support in PL/Python
Extract the "while creating return value" and "while modifying trigger row" parts of some error messages into another layer of error context. This will simplify the upcoming patch to improve data type support, but it can stand on its own.
1 parent 983d108 commit 27c405d

8 files changed

+71
-26
lines changed

src/pl/plpython/expected/plpython_record.out

+6-3
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,15 @@ $$ LANGUAGE plpythonu;
313313
SELECT * FROM test_type_record_error1();
314314
ERROR: key "second" not found in mapping
315315
HINT: To return null in a column, add the value None to the mapping with the key named after the column.
316-
CONTEXT: PL/Python function "test_type_record_error1"
316+
CONTEXT: while creating return value
317+
PL/Python function "test_type_record_error1"
317318
CREATE FUNCTION test_type_record_error2() RETURNS type_record AS $$
318319
return [ 'first' ]
319320
$$ LANGUAGE plpythonu;
320321
SELECT * FROM test_type_record_error2();
321322
ERROR: length of returned sequence did not match number of columns in row
322-
CONTEXT: PL/Python function "test_type_record_error2"
323+
CONTEXT: while creating return value
324+
PL/Python function "test_type_record_error2"
323325
CREATE FUNCTION test_type_record_error3() RETURNS type_record AS $$
324326
class type_record: pass
325327
type_record.first = 'first'
@@ -328,4 +330,5 @@ $$ LANGUAGE plpythonu;
328330
SELECT * FROM test_type_record_error3();
329331
ERROR: attribute "second" does not exist in Python object
330332
HINT: To return null in a column, let the returned object have an attribute named after column with value None.
331-
CONTEXT: PL/Python function "test_type_record_error3"
333+
CONTEXT: while creating return value
334+
PL/Python function "test_type_record_error3"

src/pl/plpython/expected/plpython_trigger.out

+8-4
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ BEFORE UPDATE ON trigger_test
353353
FOR EACH ROW EXECUTE PROCEDURE stupid4();
354354
UPDATE trigger_test SET v = 'null' WHERE i = 0;
355355
ERROR: TD["new"] deleted, cannot modify row
356-
CONTEXT: PL/Python function "stupid4"
356+
CONTEXT: while modifying trigger row
357+
PL/Python function "stupid4"
357358
DROP TRIGGER stupid_trigger4 ON trigger_test;
358359
-- TD not a dictionary
359360
CREATE FUNCTION stupid5() RETURNS trigger
@@ -366,7 +367,8 @@ BEFORE UPDATE ON trigger_test
366367
FOR EACH ROW EXECUTE PROCEDURE stupid5();
367368
UPDATE trigger_test SET v = 'null' WHERE i = 0;
368369
ERROR: TD["new"] is not a dictionary
369-
CONTEXT: PL/Python function "stupid5"
370+
CONTEXT: while modifying trigger row
371+
PL/Python function "stupid5"
370372
DROP TRIGGER stupid_trigger5 ON trigger_test;
371373
-- TD not having string keys
372374
CREATE FUNCTION stupid6() RETURNS trigger
@@ -379,7 +381,8 @@ BEFORE UPDATE ON trigger_test
379381
FOR EACH ROW EXECUTE PROCEDURE stupid6();
380382
UPDATE trigger_test SET v = 'null' WHERE i = 0;
381383
ERROR: TD["new"] dictionary key at ordinal position 0 is not a string
382-
CONTEXT: PL/Python function "stupid6"
384+
CONTEXT: while modifying trigger row
385+
PL/Python function "stupid6"
383386
DROP TRIGGER stupid_trigger6 ON trigger_test;
384387
-- TD keys not corresponding to row columns
385388
CREATE FUNCTION stupid7() RETURNS trigger
@@ -392,7 +395,8 @@ BEFORE UPDATE ON trigger_test
392395
FOR EACH ROW EXECUTE PROCEDURE stupid7();
393396
UPDATE trigger_test SET v = 'null' WHERE i = 0;
394397
ERROR: key "a" found in TD["new"] does not exist as a column in the triggering row
395-
CONTEXT: PL/Python function "stupid7"
398+
CONTEXT: while modifying trigger row
399+
PL/Python function "stupid7"
396400
DROP TRIGGER stupid_trigger7 ON trigger_test;
397401
-- calling a trigger function directly
398402
SELECT stupid7();

src/pl/plpython/expected/plpython_types.out

+6-3
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,8 @@ SELECT * FROM test_type_conversion_uint2(100::uint2, -50);
332332
INFO: (100, <type 'int'>)
333333
CONTEXT: PL/Python function "test_type_conversion_uint2"
334334
ERROR: value for domain uint2 violates check constraint "uint2_check"
335-
CONTEXT: PL/Python function "test_type_conversion_uint2"
335+
CONTEXT: while creating return value
336+
PL/Python function "test_type_conversion_uint2"
336337
SELECT * FROM test_type_conversion_uint2(null, 1);
337338
INFO: (None, <type 'NoneType'>)
338339
CONTEXT: PL/Python function "test_type_conversion_uint2"
@@ -360,11 +361,13 @@ SELECT * FROM test_type_conversion_bytea10('hello word', 'hello world');
360361
INFO: ('\\x68656c6c6f20776f7264', <type 'str'>)
361362
CONTEXT: PL/Python function "test_type_conversion_bytea10"
362363
ERROR: value for domain bytea10 violates check constraint "bytea10_check"
363-
CONTEXT: PL/Python function "test_type_conversion_bytea10"
364+
CONTEXT: while creating return value
365+
PL/Python function "test_type_conversion_bytea10"
364366
SELECT * FROM test_type_conversion_bytea10(null, 'hello word');
365367
ERROR: value for domain bytea10 violates check constraint "bytea10_check"
366368
SELECT * FROM test_type_conversion_bytea10('hello word', null);
367369
INFO: ('\\x68656c6c6f20776f7264', <type 'str'>)
368370
CONTEXT: PL/Python function "test_type_conversion_bytea10"
369371
ERROR: value for domain bytea10 violates check constraint "bytea10_check"
370-
CONTEXT: PL/Python function "test_type_conversion_bytea10"
372+
CONTEXT: while creating return value
373+
PL/Python function "test_type_conversion_bytea10"

src/pl/plpython/expected/plpython_unicode.out

+6-4
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ rv = plpy.execute(plan, u"\\x80", 1)
2424
return rv[0]["testvalue1"]
2525
' LANGUAGE plpythonu;
2626
SELECT unicode_return_error();
27-
ERROR: PL/Python: could not create string representation of Python object, while creating return value
27+
ERROR: PL/Python: could not create string representation of Python object
2828
DETAIL: <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
29-
CONTEXT: PL/Python function "unicode_return_error"
29+
CONTEXT: while creating return value
30+
PL/Python function "unicode_return_error"
3031
INSERT INTO unicode_test (testvalue) VALUES ('test');
31-
ERROR: PL/Python: could not compute string representation of Python object, while modifying trigger row
32+
ERROR: PL/Python: could not create string representation of Python object
3233
DETAIL: <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
33-
CONTEXT: PL/Python function "unicode_trigger_error"
34+
CONTEXT: while modifying trigger row
35+
PL/Python function "unicode_trigger_error"
3436
SELECT unicode_plan_error1();
3537
WARNING: PL/Python: <class 'plpy.Error'>: unrecognized error in PLy_spi_execute_plan
3638
CONTEXT: PL/Python function "unicode_plan_error1"

src/pl/plpython/expected/plpython_unicode_2.out

+6-4
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ rv = plpy.execute(plan, u"\\x80", 1)
2424
return rv[0]["testvalue1"]
2525
' LANGUAGE plpythonu;
2626
SELECT unicode_return_error();
27-
ERROR: PL/Python: could not create string representation of Python object, while creating return value
27+
ERROR: PL/Python: could not create string representation of Python object
2828
DETAIL: exceptions.UnicodeError: ASCII encoding error: ordinal not in range(128)
29-
CONTEXT: PL/Python function "unicode_return_error"
29+
CONTEXT: while creating return value
30+
PL/Python function "unicode_return_error"
3031
INSERT INTO unicode_test (testvalue) VALUES ('test');
31-
ERROR: PL/Python: could not compute string representation of Python object, while modifying trigger row
32+
ERROR: PL/Python: could not create string representation of Python object
3233
DETAIL: exceptions.UnicodeError: ASCII encoding error: ordinal not in range(128)
33-
CONTEXT: PL/Python function "unicode_trigger_error"
34+
CONTEXT: while modifying trigger row
35+
PL/Python function "unicode_trigger_error"
3436
SELECT unicode_plan_error1();
3537
WARNING: PL/Python: plpy.Error: unrecognized error in PLy_spi_execute_plan
3638
CONTEXT: PL/Python function "unicode_plan_error1"

src/pl/plpython/expected/plpython_unicode_3.out

+6-4
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ rv = plpy.execute(plan, u"\\x80", 1)
2424
return rv[0]["testvalue1"]
2525
' LANGUAGE plpythonu;
2626
SELECT unicode_return_error();
27-
ERROR: PL/Python: could not create string representation of Python object, while creating return value
27+
ERROR: PL/Python: could not create string representation of Python object
2828
DETAIL: exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
29-
CONTEXT: PL/Python function "unicode_return_error"
29+
CONTEXT: while creating return value
30+
PL/Python function "unicode_return_error"
3031
INSERT INTO unicode_test (testvalue) VALUES ('test');
31-
ERROR: PL/Python: could not compute string representation of Python object, while modifying trigger row
32+
ERROR: PL/Python: could not create string representation of Python object
3233
DETAIL: exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
33-
CONTEXT: PL/Python function "unicode_trigger_error"
34+
CONTEXT: while modifying trigger row
35+
PL/Python function "unicode_trigger_error"
3436
SELECT unicode_plan_error1();
3537
WARNING: PL/Python: plpy.Error: unrecognized error in PLy_spi_execute_plan
3638
CONTEXT: PL/Python function "unicode_plan_error1"

src/pl/plpython/expected/plpython_void.out

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ SELECT test_void_func1(), test_void_func1() IS NULL AS "is null";
2020

2121
SELECT test_void_func2(); -- should fail
2222
ERROR: PL/Python function with return type "void" did not return None
23-
CONTEXT: PL/Python function "test_void_func2"
23+
CONTEXT: while creating return value
24+
PL/Python function "test_void_func2"
2425
SELECT test_return_none(), test_return_none() IS NULL AS "is null";
2526
test_return_none | is null
2627
------------------+---------

src/pl/plpython/plpython.c

+31-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**********************************************************************
22
* plpython.c - python as a procedural language for PostgreSQL
33
*
4-
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.126 2009/08/25 08:14:42 petere Exp $
4+
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.127 2009/08/25 12:44:59 petere Exp $
55
*
66
*********************************************************************
77
*/
@@ -339,6 +339,20 @@ plpython_error_callback(void *arg)
339339
errcontext("PL/Python function \"%s\"", PLy_procedure_name(PLy_curr_procedure));
340340
}
341341

342+
static void
343+
plpython_trigger_error_callback(void *arg)
344+
{
345+
if (PLy_curr_procedure)
346+
errcontext("while modifying trigger row");
347+
}
348+
349+
static void
350+
plpython_return_error_callback(void *arg)
351+
{
352+
if (PLy_curr_procedure)
353+
errcontext("while creating return value");
354+
}
355+
342356
Datum
343357
plpython_call_handler(PG_FUNCTION_ARGS)
344358
{
@@ -506,6 +520,11 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
506520
Datum *volatile modvalues;
507521
char *volatile modnulls;
508522
TupleDesc tupdesc;
523+
ErrorContextCallback plerrcontext;
524+
525+
plerrcontext.callback = plpython_trigger_error_callback;
526+
plerrcontext.previous = error_context_stack;
527+
error_context_stack = &plerrcontext;
509528

510529
plntup = plkeys = platt = plval = plstr = NULL;
511530
modattrs = NULL;
@@ -563,7 +582,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
563582
{
564583
plstr = PyObject_Str(plval);
565584
if (!plstr)
566-
PLy_elog(ERROR, "could not compute string representation of Python object, while modifying trigger row");
585+
PLy_elog(ERROR, "could not create string representation of Python object");
567586
src = PyString_AsString(plstr);
568587

569588
modvalues[i] =
@@ -620,6 +639,8 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
620639
pfree(modvalues);
621640
pfree(modnulls);
622641

642+
error_context_stack = plerrcontext.previous;
643+
623644
return rtup;
624645
}
625646

@@ -811,6 +832,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
811832
PyObject *volatile plrv = NULL;
812833
PyObject *volatile plrv_so = NULL;
813834
char *plrv_sc;
835+
ErrorContextCallback plerrcontext;
814836

815837
PG_TRY();
816838
{
@@ -901,6 +923,10 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
901923
}
902924
}
903925

926+
plerrcontext.callback = plpython_return_error_callback;
927+
plerrcontext.previous = error_context_stack;
928+
error_context_stack = &plerrcontext;
929+
904930
/*
905931
* If the function is declared to return void, the Python return value
906932
* must be None. For void-returning functions, we also treat a None
@@ -959,7 +985,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
959985
fcinfo->isnull = false;
960986
plrv_so = PyObject_Str(plrv);
961987
if (!plrv_so)
962-
PLy_elog(ERROR, "could not create string representation of Python object, while creating return value");
988+
PLy_elog(ERROR, "could not create string representation of Python object");
963989
plrv_sc = PyString_AsString(plrv_so);
964990
rv = InputFunctionCall(&proc->result.out.d.typfunc,
965991
plrv_sc,
@@ -977,6 +1003,8 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
9771003
}
9781004
PG_END_TRY();
9791005

1006+
error_context_stack = plerrcontext.previous;
1007+
9801008
Py_XDECREF(plargs);
9811009
Py_DECREF(plrv);
9821010
Py_XDECREF(plrv_so);

0 commit comments

Comments
 (0)