From 94136d5a18403445cd60ae6beb470f6ebecca8b3 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Wed, 21 Jan 2009 11:02:40 +0000
Subject: [PATCH] Add new SPI_OK_REWRITTEN return code to SPI_execute and
 friends, for the 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        | 12 +++++++++++-
 src/backend/executor/spi.c   | 11 +++++++----
 src/include/executor/spi.h   |  3 ++-
 src/pl/plpgsql/src/pl_exec.c | 26 ++++++++++++++++----------
 4 files changed, 36 insertions(+), 16 deletions(-)

diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml
index 9df76db0457..32cc6149f98 100644
--- a/doc/src/sgml/spi.sgml
+++ b/doc/src/sgml/spi.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.63 2009/01/07 13:44:36 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.64 2009/01/21 11:02:40 heikki Exp $ -->
 
 <chapter id="spi">
  <title>Server Programming Interface</title>
@@ -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>
 
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index aa562c2ea9a..f750560c6f4 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.206 2009/01/07 20:38:56 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.207 2009/01/21 11:02:40 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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;
 }
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 66a77ce4778..8b9fe32d7ba 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.70 2009/01/07 20:38:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.71 2009/01/21 11:02:40 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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;
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index fd7cce3aedd..7443c62feef 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.229 2009/01/14 09:53:51 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.230 2009/01/21 11:02:40 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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:
-- 
GitLab