Add new SPI_OK_REWRITTEN return code to SPI_execute and friends, for the
authorHeikki Linnakangas <heikki@enterprisedb.com>
Wed, 21 Jan 2009 11:02:40 +0000 (11:02 +0000)
committerHeikki Linnakangas <heikki@enterprisedb.com>
Wed, 21 Jan 2009 11:02:40 +0000 (11:02 +0000)
case that the command is rewritten into another type of command. The old
behavior to return the command tag of the last executed command was
pretty surprising. In PL/pgSQL, for example, it meant that if a command
was rewritten to a utility statement, FOUND wasn't set at all.

doc/src/sgml/spi.sgml
src/backend/executor/spi.c
src/include/executor/spi.h
src/pl/plpgsql/src/pl_exec.c

index 248564f92b3b34abbde939eabf1f873b6634fa55..0db9c329042d823668d9b0b09f27aa17f25caf57 100644 (file)
@@ -527,6 +527,16 @@ typedef struct
       </para>
      </listitem>
     </varlistentry>
+
+    <varlistentry>
+     <term><symbol>SPI_OK_REWRITTEN</symbol></term>
+     <listitem>
+      <para>
+       if the command was rewritten into another kind of command (e.g.,
+       <command>UPDATE</command> became an <command>INSERT</command>) by a <link linkend="rules">rule</link>.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </para>
 
index a49f14f12ddfaa67b29ab24bbfbe823f8c27ee34..a4d08e55956a80c178324c58d09b8531971d10e1 100644 (file)
@@ -1490,6 +1490,8 @@ SPI_result_code_string(int code)
                        return "SPI_OK_DELETE_RETURNING";
                case SPI_OK_UPDATE_RETURNING:
                        return "SPI_OK_UPDATE_RETURNING";
+               case SPI_OK_REWRITTEN:
+                       return "SPI_OK_REWRITTEN";
        }
        /* Unrecognized code ... return something useful ... */
        sprintf(buf, "Unrecognized SPI code %d", code);
@@ -1910,11 +1912,12 @@ fail:
        _SPI_current->tuptable = NULL;
 
        /*
-        * If none of the queries had canSetTag, we return the last query's result
-        * code, but not its auxiliary results (for backwards compatibility).
+        * If none of the queries had canSetTag, return SPI_OK_REWRITTEN. Prior
+        * to 8.4, we used return the last query's result code, but not its
+        * auxiliary results, but that's confusing.
         */
        if (my_res == 0)
-               my_res = res;
+               my_res = SPI_OK_REWRITTEN;
 
        return my_res;
 }
index 1c422cfa1380e7ff8a0c5b7b65c3e53454157a36..25b92229acd32dc8e0372ad3ceb2b674c3dc7ebf 100644 (file)
@@ -56,6 +56,7 @@ typedef struct _SPI_plan *SPIPlanPtr;
 #define SPI_OK_INSERT_RETURNING 11
 #define SPI_OK_DELETE_RETURNING 12
 #define SPI_OK_UPDATE_RETURNING 13
+#define SPI_OK_REWRITTEN               14
 
 extern PGDLLIMPORT uint32 SPI_processed;
 extern PGDLLIMPORT Oid SPI_lastoid;
index 4421521ca9cf6cfd7faecbaa6236f337a221edec..68e7941d18cf24c750089d2c38167ad7ef63db2c 100644 (file)
@@ -2782,19 +2782,13 @@ exec_stmt_execsql(PLpgSQL_execstate *estate,
 
        /*
         * Check for error, and set FOUND if appropriate (for historical reasons
-        * we set FOUND only for certain query types).
-        *
-        * Note: the command type indicated by return code might not match
-        * mod_stmt, if there is an INSTEAD OF rule rewriting an UPDATE into an
-        * INSERT, for example. In that case, the INSERT doesn't have canSetTag
-        * set, mod_stmt is false, and SPI_execute_plan sets SPI_processed to
-        * zero. We'll set FOUND to false here in that case. If the statement is
-        * rewritten into a utility statement, however, FOUND is left unchanged.
-        * Arguably that's a bug, but changing it now could break applications.
+        * we set FOUND only for certain query types).  Also Assert that we
+        * identified the statement type the same as SPI did.
         */
        switch (rc)
        {
                case SPI_OK_SELECT:
+                       Assert(!stmt->mod_stmt);
                        exec_set_found(estate, (SPI_processed != 0));
                        break;
 
@@ -2804,11 +2798,23 @@ exec_stmt_execsql(PLpgSQL_execstate *estate,
                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:
                case SPI_OK_UTILITY:
+                       Assert(!stmt->mod_stmt);
+                       break;
+
+               case SPI_OK_REWRITTEN:
+                       Assert(!stmt->mod_stmt);
+                       /*
+                        * The command was rewritten into another kind of command. It's
+                        * not clear what FOUND would mean in that case (and SPI doesn't
+                        * return the row count either), so just set it to false.
+                        */
+                       exec_set_found(estate, false);
                        break;
 
                default: