From 953d6232ed51694d82a23ced8ade86efe650c28f Mon Sep 17 00:00:00 2001 From: heikki 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 | 10 ++++++++++ src/backend/executor/spi.c | 9 ++++++--- src/include/executor/spi.h | 1 + src/pl/plpgsql/src/pl_exec.c | 24 +++++++++++++++--------- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index 248564f92b..0db9c32904 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -527,6 +527,16 @@ typedef struct + + + SPI_OK_REWRITTEN + + + if the command was rewritten into another kind of command (e.g., + UPDATE became an INSERT) by a rule. + + + diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index a49f14f12d..a4d08e5595 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -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 1c422cfa13..25b92229ac 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -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 4421521ca9..68e7941d18 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -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: -- 2.11.4.GIT