diff --git a/src/pl/plpython/expected/plpython_record.out b/src/pl/plpython/expected/plpython_record.out index 9e4645d56c..c8c4f9d5a3 100644 --- a/src/pl/plpython/expected/plpython_record.out +++ b/src/pl/plpython/expected/plpython_record.out @@ -313,13 +313,15 @@ $$ LANGUAGE plpythonu; SELECT * FROM test_type_record_error1(); ERROR: key "second" not found in mapping HINT: To return null in a column, add the value None to the mapping with the key named after the column. -CONTEXT: PL/Python function "test_type_record_error1" +CONTEXT: while creating return value +PL/Python function "test_type_record_error1" CREATE FUNCTION test_type_record_error2() RETURNS type_record AS $$ return [ 'first' ] $$ LANGUAGE plpythonu; SELECT * FROM test_type_record_error2(); ERROR: length of returned sequence did not match number of columns in row -CONTEXT: PL/Python function "test_type_record_error2" +CONTEXT: while creating return value +PL/Python function "test_type_record_error2" CREATE FUNCTION test_type_record_error3() RETURNS type_record AS $$ class type_record: pass type_record.first = 'first' @@ -328,4 +330,5 @@ $$ LANGUAGE plpythonu; SELECT * FROM test_type_record_error3(); ERROR: attribute "second" does not exist in Python object HINT: To return null in a column, let the returned object have an attribute named after column with value None. -CONTEXT: PL/Python function "test_type_record_error3" +CONTEXT: while creating return value +PL/Python function "test_type_record_error3" diff --git a/src/pl/plpython/expected/plpython_trigger.out b/src/pl/plpython/expected/plpython_trigger.out index b60796dab5..6be1c9dd0c 100644 --- a/src/pl/plpython/expected/plpython_trigger.out +++ b/src/pl/plpython/expected/plpython_trigger.out @@ -353,7 +353,8 @@ BEFORE UPDATE ON trigger_test FOR EACH ROW EXECUTE PROCEDURE stupid4(); UPDATE trigger_test SET v = 'null' WHERE i = 0; ERROR: TD["new"] deleted, cannot modify row -CONTEXT: PL/Python function "stupid4" +CONTEXT: while modifying trigger row +PL/Python function "stupid4" DROP TRIGGER stupid_trigger4 ON trigger_test; -- TD not a dictionary CREATE FUNCTION stupid5() RETURNS trigger @@ -366,7 +367,8 @@ BEFORE UPDATE ON trigger_test FOR EACH ROW EXECUTE PROCEDURE stupid5(); UPDATE trigger_test SET v = 'null' WHERE i = 0; ERROR: TD["new"] is not a dictionary -CONTEXT: PL/Python function "stupid5" +CONTEXT: while modifying trigger row +PL/Python function "stupid5" DROP TRIGGER stupid_trigger5 ON trigger_test; -- TD not having string keys CREATE FUNCTION stupid6() RETURNS trigger @@ -379,7 +381,8 @@ BEFORE UPDATE ON trigger_test FOR EACH ROW EXECUTE PROCEDURE stupid6(); UPDATE trigger_test SET v = 'null' WHERE i = 0; ERROR: TD["new"] dictionary key at ordinal position 0 is not a string -CONTEXT: PL/Python function "stupid6" +CONTEXT: while modifying trigger row +PL/Python function "stupid6" DROP TRIGGER stupid_trigger6 ON trigger_test; -- TD keys not corresponding to row columns CREATE FUNCTION stupid7() RETURNS trigger @@ -392,7 +395,8 @@ BEFORE UPDATE ON trigger_test FOR EACH ROW EXECUTE PROCEDURE stupid7(); UPDATE trigger_test SET v = 'null' WHERE i = 0; ERROR: key "a" found in TD["new"] does not exist as a column in the triggering row -CONTEXT: PL/Python function "stupid7" +CONTEXT: while modifying trigger row +PL/Python function "stupid7" DROP TRIGGER stupid_trigger7 ON trigger_test; -- calling a trigger function directly SELECT stupid7(); diff --git a/src/pl/plpython/expected/plpython_types.out b/src/pl/plpython/expected/plpython_types.out index 476f32974b..19b3c9e47a 100644 --- a/src/pl/plpython/expected/plpython_types.out +++ b/src/pl/plpython/expected/plpython_types.out @@ -332,7 +332,8 @@ SELECT * FROM test_type_conversion_uint2(100::uint2, -50); INFO: (100, ) CONTEXT: PL/Python function "test_type_conversion_uint2" ERROR: value for domain uint2 violates check constraint "uint2_check" -CONTEXT: PL/Python function "test_type_conversion_uint2" +CONTEXT: while creating return value +PL/Python function "test_type_conversion_uint2" SELECT * FROM test_type_conversion_uint2(null, 1); INFO: (None, ) CONTEXT: PL/Python function "test_type_conversion_uint2" @@ -360,11 +361,13 @@ SELECT * FROM test_type_conversion_bytea10('hello word', 'hello world'); INFO: ('\\x68656c6c6f20776f7264', ) CONTEXT: PL/Python function "test_type_conversion_bytea10" ERROR: value for domain bytea10 violates check constraint "bytea10_check" -CONTEXT: PL/Python function "test_type_conversion_bytea10" +CONTEXT: while creating return value +PL/Python function "test_type_conversion_bytea10" SELECT * FROM test_type_conversion_bytea10(null, 'hello word'); ERROR: value for domain bytea10 violates check constraint "bytea10_check" SELECT * FROM test_type_conversion_bytea10('hello word', null); INFO: ('\\x68656c6c6f20776f7264', ) CONTEXT: PL/Python function "test_type_conversion_bytea10" ERROR: value for domain bytea10 violates check constraint "bytea10_check" -CONTEXT: PL/Python function "test_type_conversion_bytea10" +CONTEXT: while creating return value +PL/Python function "test_type_conversion_bytea10" diff --git a/src/pl/plpython/expected/plpython_unicode.out b/src/pl/plpython/expected/plpython_unicode.out index ce19eb980c..d3b6fd1db7 100644 --- a/src/pl/plpython/expected/plpython_unicode.out +++ b/src/pl/plpython/expected/plpython_unicode.out @@ -24,13 +24,15 @@ rv = plpy.execute(plan, u"\\x80", 1) return rv[0]["testvalue1"] ' LANGUAGE plpythonu; SELECT unicode_return_error(); -ERROR: PL/Python: could not create string representation of Python object, while creating return value +ERROR: PL/Python: could not create string representation of Python object DETAIL: : 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128) -CONTEXT: PL/Python function "unicode_return_error" +CONTEXT: while creating return value +PL/Python function "unicode_return_error" INSERT INTO unicode_test (testvalue) VALUES ('test'); -ERROR: PL/Python: could not compute string representation of Python object, while modifying trigger row +ERROR: PL/Python: could not create string representation of Python object DETAIL: : 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128) -CONTEXT: PL/Python function "unicode_trigger_error" +CONTEXT: while modifying trigger row +PL/Python function "unicode_trigger_error" SELECT unicode_plan_error1(); WARNING: PL/Python: : unrecognized error in PLy_spi_execute_plan CONTEXT: PL/Python function "unicode_plan_error1" diff --git a/src/pl/plpython/expected/plpython_unicode_2.out b/src/pl/plpython/expected/plpython_unicode_2.out index 9280fe7dde..1f393fbef3 100644 --- a/src/pl/plpython/expected/plpython_unicode_2.out +++ b/src/pl/plpython/expected/plpython_unicode_2.out @@ -24,13 +24,15 @@ rv = plpy.execute(plan, u"\\x80", 1) return rv[0]["testvalue1"] ' LANGUAGE plpythonu; SELECT unicode_return_error(); -ERROR: PL/Python: could not create string representation of Python object, while creating return value +ERROR: PL/Python: could not create string representation of Python object DETAIL: exceptions.UnicodeError: ASCII encoding error: ordinal not in range(128) -CONTEXT: PL/Python function "unicode_return_error" +CONTEXT: while creating return value +PL/Python function "unicode_return_error" INSERT INTO unicode_test (testvalue) VALUES ('test'); -ERROR: PL/Python: could not compute string representation of Python object, while modifying trigger row +ERROR: PL/Python: could not create string representation of Python object DETAIL: exceptions.UnicodeError: ASCII encoding error: ordinal not in range(128) -CONTEXT: PL/Python function "unicode_trigger_error" +CONTEXT: while modifying trigger row +PL/Python function "unicode_trigger_error" SELECT unicode_plan_error1(); WARNING: PL/Python: plpy.Error: unrecognized error in PLy_spi_execute_plan CONTEXT: PL/Python function "unicode_plan_error1" diff --git a/src/pl/plpython/expected/plpython_unicode_3.out b/src/pl/plpython/expected/plpython_unicode_3.out index f058e2b098..620f9f5790 100644 --- a/src/pl/plpython/expected/plpython_unicode_3.out +++ b/src/pl/plpython/expected/plpython_unicode_3.out @@ -24,13 +24,15 @@ rv = plpy.execute(plan, u"\\x80", 1) return rv[0]["testvalue1"] ' LANGUAGE plpythonu; SELECT unicode_return_error(); -ERROR: PL/Python: could not create string representation of Python object, while creating return value +ERROR: PL/Python: could not create string representation of Python object DETAIL: exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128) -CONTEXT: PL/Python function "unicode_return_error" +CONTEXT: while creating return value +PL/Python function "unicode_return_error" INSERT INTO unicode_test (testvalue) VALUES ('test'); -ERROR: PL/Python: could not compute string representation of Python object, while modifying trigger row +ERROR: PL/Python: could not create string representation of Python object DETAIL: exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128) -CONTEXT: PL/Python function "unicode_trigger_error" +CONTEXT: while modifying trigger row +PL/Python function "unicode_trigger_error" SELECT unicode_plan_error1(); WARNING: PL/Python: plpy.Error: unrecognized error in PLy_spi_execute_plan CONTEXT: PL/Python function "unicode_plan_error1" diff --git a/src/pl/plpython/expected/plpython_void.out b/src/pl/plpython/expected/plpython_void.out index d067de06c0..1080d12d6b 100644 --- a/src/pl/plpython/expected/plpython_void.out +++ b/src/pl/plpython/expected/plpython_void.out @@ -20,7 +20,8 @@ SELECT test_void_func1(), test_void_func1() IS NULL AS "is null"; SELECT test_void_func2(); -- should fail ERROR: PL/Python function with return type "void" did not return None -CONTEXT: PL/Python function "test_void_func2" +CONTEXT: while creating return value +PL/Python function "test_void_func2" SELECT test_return_none(), test_return_none() IS NULL AS "is null"; test_return_none | is null ------------------+--------- diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c index eec0288e49..4aba4ba95a 100644 --- a/src/pl/plpython/plpython.c +++ b/src/pl/plpython/plpython.c @@ -1,7 +1,7 @@ /********************************************************************** * plpython.c - python as a procedural language for PostgreSQL * - * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.126 2009/08/25 08:14:42 petere Exp $ + * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.127 2009/08/25 12:44:59 petere Exp $ * ********************************************************************* */ @@ -339,6 +339,20 @@ plpython_error_callback(void *arg) errcontext("PL/Python function \"%s\"", PLy_procedure_name(PLy_curr_procedure)); } +static void +plpython_trigger_error_callback(void *arg) +{ + if (PLy_curr_procedure) + errcontext("while modifying trigger row"); +} + +static void +plpython_return_error_callback(void *arg) +{ + if (PLy_curr_procedure) + errcontext("while creating return value"); +} + Datum plpython_call_handler(PG_FUNCTION_ARGS) { @@ -506,6 +520,11 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, Datum *volatile modvalues; char *volatile modnulls; TupleDesc tupdesc; + ErrorContextCallback plerrcontext; + + plerrcontext.callback = plpython_trigger_error_callback; + plerrcontext.previous = error_context_stack; + error_context_stack = &plerrcontext; plntup = plkeys = platt = plval = plstr = NULL; modattrs = NULL; @@ -563,7 +582,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, { plstr = PyObject_Str(plval); if (!plstr) - PLy_elog(ERROR, "could not compute string representation of Python object, while modifying trigger row"); + PLy_elog(ERROR, "could not create string representation of Python object"); src = PyString_AsString(plstr); modvalues[i] = @@ -620,6 +639,8 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, pfree(modvalues); pfree(modnulls); + error_context_stack = plerrcontext.previous; + return rtup; } @@ -811,6 +832,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc) PyObject *volatile plrv = NULL; PyObject *volatile plrv_so = NULL; char *plrv_sc; + ErrorContextCallback plerrcontext; PG_TRY(); { @@ -901,6 +923,10 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc) } } + plerrcontext.callback = plpython_return_error_callback; + plerrcontext.previous = error_context_stack; + error_context_stack = &plerrcontext; + /* * If the function is declared to return void, the Python return value * must be None. For void-returning functions, we also treat a None @@ -959,7 +985,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc) fcinfo->isnull = false; plrv_so = PyObject_Str(plrv); if (!plrv_so) - PLy_elog(ERROR, "could not create string representation of Python object, while creating return value"); + PLy_elog(ERROR, "could not create string representation of Python object"); plrv_sc = PyString_AsString(plrv_so); rv = InputFunctionCall(&proc->result.out.d.typfunc, plrv_sc, @@ -977,6 +1003,8 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc) } PG_END_TRY(); + error_context_stack = plerrcontext.previous; + Py_XDECREF(plargs); Py_DECREF(plrv); Py_XDECREF(plrv_so);