*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.141 2005/06/09 21:25:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.142 2005/10/01 18:43:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
_SPI_current = &(_SPI_stack[_SPI_connected]);
_SPI_current->processed = 0;
+ _SPI_current->lastoid = InvalidOid;
_SPI_current->tuptable = NULL;
_SPI_current->procCxt = NULL; /* in case we fail to create 'em */
_SPI_current->execCxt = NULL;
break;
}
- /* Reset SPI result */
+ /* Reset SPI result (note we deliberately don't touch lastoid) */
SPI_processed = 0;
SPI_tuptable = NULL;
_SPI_current->processed = 0;
bool read_only, long tcount)
{
volatile int res = 0;
+ volatile uint32 my_processed = 0;
+ volatile Oid my_lastoid = InvalidOid;
+ SPITupleTable * volatile my_tuptable = NULL;
Snapshot saveActiveSnapshot;
/* Be sure to restore ActiveSnapshot on error exit */
else
paramLI = NULL;
- /* Reset state (only needed in case string is empty) */
- SPI_processed = 0;
- SPI_lastoid = InvalidOid;
- SPI_tuptable = NULL;
- _SPI_current->tuptable = NULL;
-
/*
* Setup error traceback support for ereport()
*/
List *query_list = lfirst(query_list_list_item);
ListCell *query_list_item;
- /* Reset state for each original parsetree */
- /* (at most one of its querytrees will be marked canSetTag) */
- SPI_processed = 0;
- SPI_lastoid = InvalidOid;
- SPI_tuptable = NULL;
- _SPI_current->tuptable = NULL;
-
foreach(query_list_item, query_list)
{
Query *queryTree = (Query *) lfirst(query_list_item);
planTree = lfirst(plan_list_item);
plan_list_item = lnext(plan_list_item);
+ _SPI_current->processed = 0;
+ _SPI_current->lastoid = InvalidOid;
+ _SPI_current->tuptable = NULL;
+
if (queryTree->commandType == CMD_UTILITY)
{
if (IsA(queryTree->utilityStmt, CopyStmt))
}
FreeSnapshot(ActiveSnapshot);
ActiveSnapshot = NULL;
+ /*
+ * The last canSetTag query sets the auxiliary values returned
+ * to the caller. Be careful to free any tuptables not
+ * returned, to avoid intratransaction memory leak.
+ */
+ if (queryTree->canSetTag)
+ {
+ my_processed = _SPI_current->processed;
+ my_lastoid = _SPI_current->lastoid;
+ SPI_freetuptable(my_tuptable);
+ my_tuptable = _SPI_current->tuptable;
+ }
+ else
+ {
+ SPI_freetuptable(_SPI_current->tuptable);
+ _SPI_current->tuptable = NULL;
+ }
/* we know that the receiver doesn't need a destroy call */
if (res < 0)
goto fail;
ActiveSnapshot = saveActiveSnapshot;
+ /* Save results for caller */
+ SPI_processed = my_processed;
+ SPI_lastoid = my_lastoid;
+ SPI_tuptable = my_tuptable;
+
return res;
}
_SPI_pquery(QueryDesc *queryDesc, long tcount)
{
int operation = queryDesc->operation;
- CommandDest origDest = queryDesc->dest->mydest;
int res;
- Oid save_lastoid;
switch (operation)
{
res = SPI_OK_SELINTO;
queryDesc->dest = None_Receiver; /* don't output results */
}
+ else if (queryDesc->dest->mydest != SPI)
+ {
+ /* Don't return SPI_OK_SELECT if we're discarding result */
+ res = SPI_OK_UTILITY;
+ }
break;
case CMD_INSERT:
res = SPI_OK_INSERT;
ExecutorRun(queryDesc, ForwardScanDirection, tcount);
_SPI_current->processed = queryDesc->estate->es_processed;
- save_lastoid = queryDesc->estate->es_lastoid;
+ _SPI_current->lastoid = queryDesc->estate->es_lastoid;
if (operation == CMD_SELECT && queryDesc->dest->mydest == SPI)
{
ExecutorEnd(queryDesc);
- /* Test origDest here so that SPI_processed gets set in SELINTO case */
- if (origDest == SPI)
- {
- SPI_processed = _SPI_current->processed;
- SPI_lastoid = save_lastoid;
- SPI_tuptable = _SPI_current->tuptable;
- }
- else if (res == SPI_OK_SELECT)
- {
- /* Don't return SPI_OK_SELECT if we discarded the result */
- res = SPI_OK_UTILITY;
- }
-
#ifdef SPI_EXECUTOR_STATS
if (ShowExecutorStats)
ShowUsage("SPI EXECUTOR STATS");
if (_SPI_begin_call(true) < 0)
elog(ERROR, "SPI cursor operation called while not connected");
- /* Reset the SPI result */
+ /* Reset the SPI result (note we deliberately don't touch lastoid) */
SPI_processed = 0;
SPI_tuptable = NULL;
_SPI_current->processed = 0;