Add new return codes SPI_OK_INSERT_RETURNING etc to the SPI API.
authorTom Lane
Sun, 27 Aug 2006 23:47:58 +0000 (23:47 +0000)
committerTom Lane
Sun, 27 Aug 2006 23:47:58 +0000 (23:47 +0000)
Fix all the standard PLs to be able to return tuples from FOO_RETURNING
statements as well as utility statements that return tuples.  Also,
fix oversight that SPI_processed wasn't set for a utility statement
returning tuples.  Per recent discussion.

doc/src/sgml/spi.sgml
src/backend/executor/spi.c
src/include/executor/spi.h
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_exec.c
src/pl/plpython/plpython.c
src/pl/tcl/pltcl.c

index 016874dce709b283c261ea8acd5811901dc2694f..b19189632e6e52eca776cebe72fa46ed0cbd5286 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
  Server Programming Interface
@@ -361,12 +361,16 @@ SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5);
 
   
    The actual number of rows for which the (last) command was executed
-   is returned in the global variable SPI_processed
-   (unless the return value of the function is
-   SPI_OK_UTILITY).  If the return value of the
-   function is SPI_OK_SELECT then you may use the
+   is returned in the global variable SPI_processed.
+   If the return value of the function is SPI_OK_SELECT,
+   SPI_OK_INSERT_RETURNING,
+   SPI_OK_DELETE_RETURNING, or
+   SPI_OK_UPDATE_RETURNING,
+   then you may use the
    global pointer SPITupleTable *SPI_tuptable to
-   access the result rows.
+   access the result rows.  Some utility commands (such as
+   EXPLAIN) also return rowsets, and SPI_tuptable 
+   will contain the result in these cases too.
   
 
   
@@ -459,19 +463,19 @@ typedef struct
     
 
     
-     SPI_OK_DELETE
+     SPI_OK_INSERT
      
       
-       if a DELETE was executed
+       if aINSERT was executed
       
      
     
 
     
-     SPI_OK_INSERT
+     SPI_OK_DELETE
      
       
-       if aINSERT was executed
+       if a DELETE was executed
       
      
     
@@ -485,6 +489,33 @@ typedef struct
      
     
 
+    
+     SPI_OK_INSERT_RETURNING
+     
+      
+       if an INSERT RETURNING was executed
+      
+     
+    
+
+    
+     SPI_OK_DELETE_RETURNING
+     
+      
+       if a DELETE RETURNING was executed
+      
+     
+    
+
+    
+     SPI_OK_UPDATE_RETURNING
+     
+      
+       if an UPDATE RETURNING was executed
+      
+     
+    
+
     
      SPI_OK_UTILITY
      
@@ -2987,10 +3018,9 @@ execq(text *sql, int cnt)
     
     proc = SPI_processed;
     /*
-     * If this is a SELECT and some rows were fetched,
-     * then the rows are printed via elog(INFO).
+     * If some rows were fetched, print them via elog(INFO).
      */
-    if (ret == SPI_OK_SELECT && SPI_processed > 0)
+    if (ret > 0 && SPI_tuptable != NULL)
     {
         TupleDesc tupdesc = SPI_tuptable->tupdesc;
         SPITupleTable *tuptable = SPI_tuptable;
@@ -3005,7 +3035,7 @@ execq(text *sql, int cnt)
                 snprintf(buf + strlen (buf), sizeof(buf) - strlen(buf), " %s%s",
                         SPI_getvalue(tuple, tupdesc, i),
                         (i == tupdesc->natts) ? " " : " |");
-            elog (INFO, "EXECQ: %s", buf);
+            elog(INFO, "EXECQ: %s", buf);
         }
     }
 
index 183969f1b85a76d4640ca13ed3604291acbcbaf0..dd22a2dd5f2e5fe8de913f5bd0868472f10fabd0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.157 2006/08/14 22:57:15 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.158 2006/08/27 23:47:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1136,6 +1136,12 @@ SPI_result_code_string(int code)
            return "SPI_OK_UPDATE";
        case SPI_OK_CURSOR:
            return "SPI_OK_CURSOR";
+       case SPI_OK_INSERT_RETURNING:
+           return "SPI_OK_INSERT_RETURNING";
+       case SPI_OK_DELETE_RETURNING:
+           return "SPI_OK_DELETE_RETURNING";
+       case SPI_OK_UPDATE_RETURNING:
+           return "SPI_OK_UPDATE_RETURNING";
    }
    /* Unrecognized code ... return something useful ... */
    sprintf(buf, "Unrecognized SPI code %d", code);
@@ -1454,6 +1460,9 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
                {
                    ProcessUtility(queryTree->utilityStmt, paramLI,
                                   dest, NULL);
+                   /* Update "processed" if stmt returned tuples */
+                   if (_SPI_current->tuptable)
+                       _SPI_current->processed = _SPI_current->tuptable->alloced - _SPI_current->tuptable->free;
                    res = SPI_OK_UTILITY;
                }
                else
@@ -1542,13 +1551,22 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
                res = SPI_OK_SELECT;
            break;
        case CMD_INSERT:
-           res = SPI_OK_INSERT;
+           if (queryDesc->parsetree->returningList)
+               res = SPI_OK_INSERT_RETURNING;
+           else
+               res = SPI_OK_INSERT;
            break;
        case CMD_DELETE:
-           res = SPI_OK_DELETE;
+           if (queryDesc->parsetree->returningList)
+               res = SPI_OK_DELETE_RETURNING;
+           else
+               res = SPI_OK_DELETE;
            break;
        case CMD_UPDATE:
-           res = SPI_OK_UPDATE;
+           if (queryDesc->parsetree->returningList)
+               res = SPI_OK_UPDATE_RETURNING;
+           else
+               res = SPI_OK_UPDATE;
            break;
        default:
            return SPI_ERROR_OPUNKNOWN;
@@ -1568,7 +1586,8 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
    _SPI_current->processed = queryDesc->estate->es_processed;
    _SPI_current->lastoid = queryDesc->estate->es_lastoid;
 
-   if (operation == CMD_SELECT && queryDesc->dest->mydest == DestSPI)
+   if ((res == SPI_OK_SELECT || queryDesc->parsetree->returningList) &&
+       queryDesc->dest->mydest == DestSPI)
    {
        if (_SPI_checktuples())
            elog(ERROR, "consistency check on SPI tuple count failed");
index b68f5932e39bbbb4782012893231a67f308ac4fb..0d91290968dabe3b8ac6ae228a9a013e8ca9d822 100644 (file)
@@ -2,7 +2,7 @@
  *
  * spi.h
  *
- * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.54 2006/07/11 18:26:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.55 2006/08/27 23:47:58 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -71,6 +71,9 @@ typedef struct
 #define SPI_OK_DELETE          8
 #define SPI_OK_UPDATE          9
 #define SPI_OK_CURSOR          10
+#define SPI_OK_INSERT_RETURNING    11
+#define SPI_OK_DELETE_RETURNING    12
+#define SPI_OK_UPDATE_RETURNING    13
 
 extern DLLIMPORT uint32 SPI_processed;
 extern DLLIMPORT Oid SPI_lastoid;
index c63e9d7b62eb8e0d99e49c41d06b73c504eb3234..0906d3186acd78956ab331a6697500168ffa376f 100644 (file)
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plperl.c - perl as a procedural language for PostgreSQL
  *
- *   $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.117 2006/08/13 17:31:10 momjian Exp $
+ *   $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.118 2006/08/27 23:47:58 tgl Exp $
  *
  **********************************************************************/
 
@@ -1630,7 +1630,7 @@ plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed,
    hv_store(result, "processed", strlen("processed"),
             newSViv(processed), 0);
 
-   if (status == SPI_OK_SELECT)
+   if (status > 0 && tuptable)
    {
        AV         *rows;
        SV         *row;
index f8213d4a50fe34304bbc03083570dfbbad4cf6c8..dedba151178c1b9b59f51a401543ac164ee9fdff 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.176 2006/08/15 19:01:17 tgl Exp $
+ *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.177 2006/08/27 23:47:58 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2370,23 +2370,16 @@ exec_stmt_execsql(PLpgSQL_execstate *estate,
        case SPI_OK_INSERT:
        case SPI_OK_UPDATE:
        case SPI_OK_DELETE:
+       case SPI_OK_INSERT_RETURNING:
+       case SPI_OK_UPDATE_RETURNING:
+       case SPI_OK_DELETE_RETURNING:
            Assert(stmt->mod_stmt);
            exec_set_found(estate, (SPI_processed != 0));
            break;
 
        case SPI_OK_SELINTO:
-           Assert(!stmt->mod_stmt);
-           break;
-
        case SPI_OK_UTILITY:
            Assert(!stmt->mod_stmt);
-           /*
-            * spi.c currently does not update SPI_processed for utility
-            * commands.  Not clear if this should be considered a bug;
-            * for the moment, work around it here.
-            */
-           if (SPI_tuptable)
-               SPI_processed = (SPI_tuptable->alloced - SPI_tuptable->free);
            break;
 
        default:
@@ -2505,16 +2498,10 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate,
        case SPI_OK_INSERT:
        case SPI_OK_UPDATE:
        case SPI_OK_DELETE:
-           break;
-
+       case SPI_OK_INSERT_RETURNING:
+       case SPI_OK_UPDATE_RETURNING:
+       case SPI_OK_DELETE_RETURNING:
        case SPI_OK_UTILITY:
-           /*
-            * spi.c currently does not update SPI_processed for utility
-            * commands.  Not clear if this should be considered a bug;
-            * for the moment, work around it here.
-            */
-           if (SPI_tuptable)
-               SPI_processed = (SPI_tuptable->alloced - SPI_tuptable->free);
            break;
 
        case 0:
index 289ab2e7b738cca3aa3ac9e8888e967c33e1cfea..f45ecd722225a84400bf6d234f8ecc4141b60767 100644 (file)
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plpython.c - python as a procedural language for PostgreSQL
  *
- * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.85 2006/08/08 19:15:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.86 2006/08/27 23:47:58 tgl Exp $
  *
  *********************************************************************
  */
@@ -2193,24 +2193,19 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
    Py_DECREF(result->status);
    result->status = PyInt_FromLong(status);
 
-   if (status == SPI_OK_UTILITY)
-   {
-       Py_DECREF(result->nrows);
-       result->nrows = PyInt_FromLong(0);
-   }
-   else if (status != SPI_OK_SELECT)
+   if (status > 0 && tuptable == NULL)
    {
        Py_DECREF(result->nrows);
        result->nrows = PyInt_FromLong(rows);
    }
-   else
+   else if (status > 0 && tuptable != NULL)
    {
        PLyTypeInfo args;
        int         i;
 
-       PLy_typeinfo_init(&args);
        Py_DECREF(result->nrows);
        result->nrows = PyInt_FromLong(rows);
+       PLy_typeinfo_init(&args);
 
        oldcontext = CurrentMemoryContext;
        PG_TRY();
index 54abd0967229aca033052891b1c7937a1dd114c5..44b2e405f32fd788d2f5de53049dff2c979791ef 100644 (file)
@@ -2,7 +2,7 @@
  * pltcl.c     - PostgreSQL support for Tcl as
  *               procedural language (PL)
  *
- *   $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.106 2006/08/08 19:15:09 tgl Exp $
+ *   $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.107 2006/08/27 23:47:58 tgl Exp $
  *
  **********************************************************************/
 
@@ -1663,10 +1663,6 @@ pltcl_process_SPI_result(Tcl_Interp *interp,
 
    switch (spi_rc)
    {
-       case SPI_OK_UTILITY:
-           Tcl_SetResult(interp, "0", TCL_VOLATILE);
-           break;
-
        case SPI_OK_SELINTO:
        case SPI_OK_INSERT:
        case SPI_OK_DELETE:
@@ -1675,7 +1671,18 @@ pltcl_process_SPI_result(Tcl_Interp *interp,
            Tcl_SetResult(interp, buf, TCL_VOLATILE);
            break;
 
+       case SPI_OK_UTILITY:
+           if (tuptable == NULL)
+           {
+               Tcl_SetResult(interp, "0", TCL_VOLATILE);
+               break;
+           }
+           /* FALL THRU for utility returning tuples */
+
        case SPI_OK_SELECT:
+       case SPI_OK_INSERT_RETURNING:
+       case SPI_OK_DELETE_RETURNING:
+       case SPI_OK_UPDATE_RETURNING:
 
            /*
             * Process the tuples we got