From a2dafc64165fd1ae6c9f143552cb62d61c4bf819 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 16 Feb 2001 03:26:40 +0000 Subject: [PATCH] Fix bugs in pltcl's new return_null command: it was liable to go belly up if the return datatype's input converter was at all strict, because the converter would get called on junk data when returning NULL. Also ensure that it gives an error rather than coredumping if someone tries to use it in a trigger function. --- src/pl/tcl/pltcl.c | 61 +++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index f37b31a30d..f99be199b9 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -31,7 +31,7 @@ * ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.31 2000/12/08 00:09:07 tgl Exp $ + * $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.32 2001/02/16 03:26:40 tgl Exp $ * **********************************************************************/ @@ -103,7 +103,7 @@ static Tcl_Interp *pltcl_safe_interp = NULL; static Tcl_HashTable *pltcl_proc_hash = NULL; static Tcl_HashTable *pltcl_norm_query_hash = NULL; static Tcl_HashTable *pltcl_safe_query_hash = NULL; -static FunctionCallInfo pltcl_actual_fcinfo = NULL; +static FunctionCallInfo pltcl_current_fcinfo = NULL; /********************************************************************** * Forward declarations @@ -354,18 +354,18 @@ pltcl_call_handler(PG_FUNCTION_ARGS) * Determine if called as function or trigger and * call appropriate subhandler ************************************************************/ - save_fcinfo = pltcl_actual_fcinfo; + save_fcinfo = pltcl_current_fcinfo; if (CALLED_AS_TRIGGER(fcinfo)) { - pltcl_actual_fcinfo = NULL; + pltcl_current_fcinfo = NULL; retval = PointerGetDatum(pltcl_trigger_handler(fcinfo)); } else { - pltcl_actual_fcinfo = fcinfo; + pltcl_current_fcinfo = fcinfo; retval = pltcl_func_handler(fcinfo); } - pltcl_actual_fcinfo = save_fcinfo; + pltcl_current_fcinfo = save_fcinfo; pltcl_call_level--; @@ -743,17 +743,27 @@ pltcl_func_handler(PG_FUNCTION_ARGS) * Disconnect from SPI manager and then create the return * values datum (if the input function does a palloc for it * this must not be allocated in the SPI memory context - * because SPI_finish would free it). + * because SPI_finish would free it). But don't try to call + * the result_in_func if we've been told to return a NULL; + * the contents of interp->result may not be a valid value of + * the result type in that case. ************************************************************/ if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "pltcl: SPI_finish() failed"); - retval = FunctionCall3(&prodesc->result_in_func, - PointerGetDatum(interp->result), - ObjectIdGetDatum(prodesc->result_in_elem), - Int32GetDatum(-1)); + if (fcinfo->isnull) + retval = (Datum) 0; + else + retval = FunctionCall3(&prodesc->result_in_func, + PointerGetDatum(interp->result), + ObjectIdGetDatum(prodesc->result_in_elem), + Int32GetDatum(-1)); + /************************************************************ + * Finally we may restore normal error handling. + ************************************************************/ memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); + return retval; } @@ -1345,7 +1355,7 @@ pltcl_argisnull(ClientData cdata, Tcl_Interp *interp, int argc, char *argv[]) { int argno; - FunctionCallInfo fcinfo = pltcl_actual_fcinfo; + FunctionCallInfo fcinfo = pltcl_current_fcinfo; /************************************************************ * Check call syntax @@ -1356,22 +1366,22 @@ pltcl_argisnull(ClientData cdata, Tcl_Interp *interp, return TCL_ERROR; } - /************************************************************ - * Get the argument number - ************************************************************/ - if (Tcl_GetInt(interp, argv[1], &argno) != TCL_OK) - return TCL_ERROR; - /************************************************************ * Check that we're called as a normal function ************************************************************/ if (fcinfo == NULL) { Tcl_SetResult(interp, "argisnull cannot be used in triggers", - TCL_VOLATILE); + TCL_VOLATILE); return TCL_ERROR; } + /************************************************************ + * Get the argument number + ************************************************************/ + if (Tcl_GetInt(interp, argv[1], &argno) != TCL_OK) + return TCL_ERROR; + /************************************************************ * Check that the argno is valid ************************************************************/ @@ -1402,7 +1412,7 @@ pltcl_returnnull(ClientData cdata, Tcl_Interp *interp, int argc, char *argv[]) { int argno; - FunctionCallInfo fcinfo = pltcl_actual_fcinfo; + FunctionCallInfo fcinfo = pltcl_current_fcinfo; /************************************************************ * Check call syntax @@ -1413,11 +1423,22 @@ pltcl_returnnull(ClientData cdata, Tcl_Interp *interp, return TCL_ERROR; } + /************************************************************ + * Check that we're called as a normal function + ************************************************************/ + if (fcinfo == NULL) + { + Tcl_SetResult(interp, "return_null cannot be used in triggers", + TCL_VOLATILE); + return TCL_ERROR; + } + /************************************************************ * Set the NULL return flag and cause Tcl to return from the * procedure. ************************************************************/ fcinfo->isnull = true; + return TCL_RETURN; } -- 2.40.0