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.
This commit is contained in:
Heikki Linnakangas 2009-01-21 11:02:40 +00:00
parent 0154345078
commit 94136d5a18
4 changed files with 36 additions and 16 deletions

View File

@ -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>

View File

@ -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;
}

View File

@ -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;

View File

@ -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: