]> granicus.if.org Git - postgresql/commitdiff
Fix bugs in pltcl's new return_null command: it was liable to go belly up
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 16 Feb 2001 03:26:40 +0000 (03:26 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 16 Feb 2001 03:26:40 +0000 (03:26 +0000)
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

index f37b31a30dd772ed0ee967330046142ab1eb7729..f99be199b9f652d41b562ce567bf21141784dbc7 100644 (file)
@@ -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;
 }