Commit a2dafc64 authored by Tom Lane's avatar Tom Lane

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.
parent 60d1d671
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* ENHANCEMENTS, OR MODIFICATIONS. * ENHANCEMENTS, OR MODIFICATIONS.
* *
* IDENTIFICATION * 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; ...@@ -103,7 +103,7 @@ static Tcl_Interp *pltcl_safe_interp = NULL;
static Tcl_HashTable *pltcl_proc_hash = NULL; static Tcl_HashTable *pltcl_proc_hash = NULL;
static Tcl_HashTable *pltcl_norm_query_hash = NULL; static Tcl_HashTable *pltcl_norm_query_hash = NULL;
static Tcl_HashTable *pltcl_safe_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 * Forward declarations
...@@ -354,18 +354,18 @@ pltcl_call_handler(PG_FUNCTION_ARGS) ...@@ -354,18 +354,18 @@ pltcl_call_handler(PG_FUNCTION_ARGS)
* Determine if called as function or trigger and * Determine if called as function or trigger and
* call appropriate subhandler * call appropriate subhandler
************************************************************/ ************************************************************/
save_fcinfo = pltcl_actual_fcinfo; save_fcinfo = pltcl_current_fcinfo;
if (CALLED_AS_TRIGGER(fcinfo)) if (CALLED_AS_TRIGGER(fcinfo))
{ {
pltcl_actual_fcinfo = NULL; pltcl_current_fcinfo = NULL;
retval = PointerGetDatum(pltcl_trigger_handler(fcinfo)); retval = PointerGetDatum(pltcl_trigger_handler(fcinfo));
} else { } else {
pltcl_actual_fcinfo = fcinfo; pltcl_current_fcinfo = fcinfo;
retval = pltcl_func_handler(fcinfo); retval = pltcl_func_handler(fcinfo);
} }
pltcl_actual_fcinfo = save_fcinfo; pltcl_current_fcinfo = save_fcinfo;
pltcl_call_level--; pltcl_call_level--;
...@@ -743,17 +743,27 @@ pltcl_func_handler(PG_FUNCTION_ARGS) ...@@ -743,17 +743,27 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
* Disconnect from SPI manager and then create the return * Disconnect from SPI manager and then create the return
* values datum (if the input function does a palloc for it * values datum (if the input function does a palloc for it
* this must not be allocated in the SPI memory context * 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) if (SPI_finish() != SPI_OK_FINISH)
elog(ERROR, "pltcl: SPI_finish() failed"); elog(ERROR, "pltcl: SPI_finish() failed");
if (fcinfo->isnull)
retval = (Datum) 0;
else
retval = FunctionCall3(&prodesc->result_in_func, retval = FunctionCall3(&prodesc->result_in_func,
PointerGetDatum(interp->result), PointerGetDatum(interp->result),
ObjectIdGetDatum(prodesc->result_in_elem), ObjectIdGetDatum(prodesc->result_in_elem),
Int32GetDatum(-1)); Int32GetDatum(-1));
/************************************************************
* Finally we may restore normal error handling.
************************************************************/
memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));
return retval; return retval;
} }
...@@ -1345,7 +1355,7 @@ pltcl_argisnull(ClientData cdata, Tcl_Interp *interp, ...@@ -1345,7 +1355,7 @@ pltcl_argisnull(ClientData cdata, Tcl_Interp *interp,
int argc, char *argv[]) int argc, char *argv[])
{ {
int argno; int argno;
FunctionCallInfo fcinfo = pltcl_actual_fcinfo; FunctionCallInfo fcinfo = pltcl_current_fcinfo;
/************************************************************ /************************************************************
* Check call syntax * Check call syntax
...@@ -1356,12 +1366,6 @@ pltcl_argisnull(ClientData cdata, Tcl_Interp *interp, ...@@ -1356,12 +1366,6 @@ pltcl_argisnull(ClientData cdata, Tcl_Interp *interp,
return TCL_ERROR; 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 * Check that we're called as a normal function
************************************************************/ ************************************************************/
...@@ -1372,6 +1376,12 @@ pltcl_argisnull(ClientData cdata, Tcl_Interp *interp, ...@@ -1372,6 +1376,12 @@ pltcl_argisnull(ClientData cdata, Tcl_Interp *interp,
return TCL_ERROR; 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 * Check that the argno is valid
************************************************************/ ************************************************************/
...@@ -1402,7 +1412,7 @@ pltcl_returnnull(ClientData cdata, Tcl_Interp *interp, ...@@ -1402,7 +1412,7 @@ pltcl_returnnull(ClientData cdata, Tcl_Interp *interp,
int argc, char *argv[]) int argc, char *argv[])
{ {
int argno; int argno;
FunctionCallInfo fcinfo = pltcl_actual_fcinfo; FunctionCallInfo fcinfo = pltcl_current_fcinfo;
/************************************************************ /************************************************************
* Check call syntax * Check call syntax
...@@ -1413,11 +1423,22 @@ pltcl_returnnull(ClientData cdata, Tcl_Interp *interp, ...@@ -1413,11 +1423,22 @@ pltcl_returnnull(ClientData cdata, Tcl_Interp *interp,
return TCL_ERROR; 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 * Set the NULL return flag and cause Tcl to return from the
* procedure. * procedure.
************************************************************/ ************************************************************/
fcinfo->isnull = true; fcinfo->isnull = true;
return TCL_RETURN; return TCL_RETURN;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment