postgres.git / summary / log / commit / refs

commit    89ef2aedae448cc51cd7bf7c81d56a08d1da7467
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Tue Jun 04 22:02:13 2024 +0000
First released in: 17.0, 12.20, 13.16, 14.13, 15.8, 16.4

    Fix pl/tcl's handling of errors from Tcl_ListObjGetElements().
    
    In a procedure or function returning tuple, we use that function to
    parse the Tcl script's result, which is supposed to be a Tcl list.
    If it isn't, you get an error.  Commit 26abb50c4 incautiously
    supposed that we could use throw_tcl_error() to report such an error.
    That doesn't actually work, because low-level functions like
    Tcl_ListObjGetElements() don't fill Tcl's errorInfo variable.
    The result is either a null-pointer-dereference crash or emission
    of misleading context information describing the previous Tcl error.
    
    Back off to just reporting the interpreter's result string, and
    improve throw_tcl_error()'s comment to explain when to use it.
    
    Also, although the similar code in pltcl_trigger_handler() avoided
    this mistake, it was using a fairly confusing wording of the
    error message.  Improve that while we're here.
    
    Per report from A. Kozhemyakin.  Back-patch to all supported
    branches.
    
    Erik Wienhold and Tom Lane
    
    Discussion: https://postgr.es/m/6a2a1c40-2b2c-4a33-8b72-243c0766fcda@postgrespro.ru


src/pl/tcl/expected/pltcl_call.out | 8 ++++++++ src/pl/tcl/pltcl.c | 11 +++++++++-- src/pl/tcl/sql/pltcl_call.sql | 11 +++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/pl/tcl/expected/pltcl_call.out b/src/pl/tcl/expected/pltcl_call.out index e4498375ec1..7bb5dffe5d7 100644 --- a/src/pl/tcl/expected/pltcl_call.out +++ b/src/pl/tcl/expected/pltcl_call.out @@ -66,6 +66,14 @@ END $$; NOTICE: a: 10 NOTICE: _a: 10, _b: 20 +-- syntax error in result tuple +CREATE PROCEDURE test_proc10(INOUT a text) +LANGUAGE pltcl +AS $$ +return [list a {$a + $a}]) +$$; +CALL test_proc10('abc'); +ERROR: could not parse function return value: list element in braces followed by ")" instead of space DROP PROCEDURE test_proc1; DROP PROCEDURE test_proc2; DROP PROCEDURE test_proc3; diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 11f1ff19139..ecf54b98942 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -1027,7 +1027,10 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, /* Convert function result to tuple */ resultObj = Tcl_GetObjResult(interp); if (Tcl_ListObjGetElements(interp, resultObj, &resultObjc, &resultObjv) == TCL_ERROR) - throw_tcl_error(interp, prodesc->user_proname); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("could not parse function return value: %s", + utf_u2e(Tcl_GetStringResult(interp))))); tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc, call_state); @@ -1293,7 +1296,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, &result_Objc, &result_Objv) != TCL_OK) ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), - errmsg("could not split return value from trigger: %s", + errmsg("could not parse trigger return value: %s", utf_u2e(Tcl_GetStringResult(interp))))); /* Convert function result to tuple */ @@ -1356,6 +1359,10 @@ pltcl_event_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, /********************************************************************** * throw_tcl_error - ereport an error returned from the Tcl interpreter + * + * Caution: use this only to report errors returned by Tcl_EvalObjEx() or + * other variants of Tcl_Eval(). Other functions may not fill "errorInfo", + * so it could be unset or even contain details from some previous error. **********************************************************************/ static void throw_tcl_error(Tcl_Interp *interp, const char *proname) diff --git a/src/pl/tcl/sql/pltcl_call.sql b/src/pl/tcl/sql/pltcl_call.sql index 37efbdefc23..fe64361c732 100644 --- a/src/pl/tcl/sql/pltcl_call.sql +++ b/src/pl/tcl/sql/pltcl_call.sql @@ -71,6 +71,17 @@ END $$; +-- syntax error in result tuple + +CREATE PROCEDURE test_proc10(INOUT a text) +LANGUAGE pltcl +AS $$ +return [list a {$a + $a}]) +$$; + +CALL test_proc10('abc'); + + DROP PROCEDURE test_proc1; DROP PROCEDURE test_proc2; DROP PROCEDURE test_proc3; [parent: 6b52e2298d85]