8000 Enhanced error context support in PL/Python · postgrespro/postgres@27c405d · GitHub
[go: up one dir, main page]

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

    File tree

    8 files changed

    +71
    -26
    lines changed

    8 files changed

    +71
    -26
    lines changed

    src/pl/plpython/expected/plpython_record.out

    Lines changed: 6 additions & 3 deletions
    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

    Lines changed: 8 additions & 4 deletions
    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

    Lines changed: 6 additions & 3 deletions
    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

    Lines changed: 6 additions & 4 deletions
    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

    Lines changed: 6 additions & 4 deletions
    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

    Lines changed: 6 additions & 4 deletions
    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

    Lines changed: 2 additions & 1 deletion
    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

    Lines changed: 31 additions & 3 deletions
    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) A377
    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)
    0