-<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.46 2006/08/12 20:05:54 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.47 2006/08/27 23:47:57 tgl Exp $ -->
<chapter id="spi">
<title>Server Programming Interface</title>
<para>
The actual number of rows for which the (last) command was executed
- is returned in the global variable <varname>SPI_processed</varname>
- (unless the return value of the function is
- <symbol>SPI_OK_UTILITY</symbol>). If the return value of the
- function is <symbol>SPI_OK_SELECT</symbol> then you may use the
+ is returned in the global variable <varname>SPI_processed</varname>.
+ If the return value of the function is <symbol>SPI_OK_SELECT</symbol>,
+ <symbol>SPI_OK_INSERT_RETURNING</symbol>,
+ <symbol>SPI_OK_DELETE_RETURNING</symbol>, or
+ <symbol>SPI_OK_UPDATE_RETURNING</symbol>,
+ then you may use the
global pointer <literal>SPITupleTable *SPI_tuptable</literal> to
- access the result rows.
+ access the result rows. Some utility commands (such as
+ <command>EXPLAIN</>) also return rowsets, and <literal>SPI_tuptable</>
+ will contain the result in these cases too.
</para>
<para>
</varlistentry>
<varlistentry>
- <term><symbol>SPI_OK_DELETE</symbol></term>
+ <term><symbol>SPI_OK_INSERT</symbol></term>
<listitem>
<para>
- if a <command>DELETE</command> was executed
+ if an <command>INSERT</command> was executed
</para>
</listitem>
</varlistentry>
<varlistentry>
- <term><symbol>SPI_OK_INSERT</symbol></term>
+ <term><symbol>SPI_OK_DELETE</symbol></term>
<listitem>
<para>
- if an <command>INSERT</command> was executed
+ if a <command>DELETE</command> was executed
</para>
</listitem>
</varlistentry>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><symbol>SPI_OK_INSERT_RETURNING</symbol></term>
+ <listitem>
+ <para>
+ if an <command>INSERT RETURNING</command> was executed
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><symbol>SPI_OK_DELETE_RETURNING</symbol></term>
+ <listitem>
+ <para>
+ if a <command>DELETE RETURNING</command> was executed
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><symbol>SPI_OK_UPDATE_RETURNING</symbol></term>
+ <listitem>
+ <para>
+ if an <command>UPDATE RETURNING</command> was executed
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><symbol>SPI_OK_UTILITY</symbol></term>
<listitem>
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;
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);
}
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
{
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
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;
_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");
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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;
/**********************************************************************
* 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 $
*
**********************************************************************/
hv_store(result, "processed", strlen("processed"),
newSViv(processed), 0);
- if (status == SPI_OK_SELECT)
+ if (status > 0 && tuptable)
{
AV *rows;
SV *row;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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:
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:
/**********************************************************************
* 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 $
*
*********************************************************************
*/
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();
* 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 $
*
**********************************************************************/
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:
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