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
This commit is contained in:
parent
1d5c5ae8e5
commit
dda633a039
@ -49,6 +49,14 @@ CALL test_proc6(2, 3, 4);
|
|||||||
6 | 8
|
6 | 8
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- 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_proc1;
|
||||||
DROP PROCEDURE test_proc2;
|
DROP PROCEDURE test_proc2;
|
||||||
DROP PROCEDURE test_proc3;
|
DROP PROCEDURE test_proc3;
|
||||||
|
@ -1022,7 +1022,10 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
|
|||||||
/* Convert function result to tuple */
|
/* Convert function result to tuple */
|
||||||
resultObj = Tcl_GetObjResult(interp);
|
resultObj = Tcl_GetObjResult(interp);
|
||||||
if (Tcl_ListObjGetElements(interp, resultObj, &resultObjc, &resultObjv) == TCL_ERROR)
|
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,
|
tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
|
||||||
call_state);
|
call_state);
|
||||||
@ -1289,7 +1292,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
|
|||||||
&result_Objc, &result_Objv) != TCL_OK)
|
&result_Objc, &result_Objv) != TCL_OK)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
|
(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)))));
|
utf_u2e(Tcl_GetStringResult(interp)))));
|
||||||
|
|
||||||
/* Convert function result to tuple */
|
/* Convert function result to tuple */
|
||||||
@ -1352,6 +1355,10 @@ pltcl_event_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
|
|||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* throw_tcl_error - ereport an error returned from the Tcl interpreter
|
* 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
|
static void
|
||||||
throw_tcl_error(Tcl_Interp *interp, const char *proname)
|
throw_tcl_error(Tcl_Interp *interp, const char *proname)
|
||||||
|
@ -52,6 +52,17 @@ $$;
|
|||||||
CALL test_proc6(2, 3, 4);
|
CALL test_proc6(2, 3, 4);
|
||||||
|
|
||||||
|
|
||||||
|
-- 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_proc1;
|
||||||
DROP PROCEDURE test_proc2;
|
DROP PROCEDURE test_proc2;
|
||||||
DROP PROCEDURE test_proc3;
|
DROP PROCEDURE test_proc3;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user