88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.141 2005/06/09 21:25:22 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.142 2005/10/01 18:43:19 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -104,6 +104,7 @@ SPI_connect(void)
104104
105105_SPI_current = & (_SPI_stack [_SPI_connected ]);
106106_SPI_current -> processed = 0 ;
107+ _SPI_current -> lastoid = InvalidOid ;
107108_SPI_current -> tuptable = NULL ;
108109_SPI_current -> procCxt = NULL ;/* in case we fail to create 'em */
109110_SPI_current -> execCxt = NULL ;
@@ -859,7 +860,7 @@ SPI_cursor_open(const char *name, void *plan,
859860break ;
860861}
861862
862- /* Reset SPI result */
863+ /* Reset SPI result(note we deliberately don't touch lastoid) */
863864SPI_processed = 0 ;
864865SPI_tuptable = NULL ;
865866_SPI_current -> processed = 0 ;
@@ -1313,6 +1314,9 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
13131314bool read_only ,long tcount )
13141315{
13151316volatile int res = 0 ;
1317+ volatile uint32 my_processed = 0 ;
1318+ volatile Oid my_lastoid = InvalidOid ;
1319+ SPITupleTable * volatile my_tuptable = NULL ;
13161320Snapshot saveActiveSnapshot ;
13171321
13181322/* Be sure to restore ActiveSnapshot on error exit */
@@ -1347,12 +1351,6 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
13471351else
13481352paramLI = NULL ;
13491353
1350- /* Reset state (only needed in case string is empty) */
1351- SPI_processed = 0 ;
1352- SPI_lastoid = InvalidOid ;
1353- SPI_tuptable = NULL ;
1354- _SPI_current -> tuptable = NULL ;
1355-
13561354/*
13571355 * Setup error traceback support for ereport()
13581356 */
@@ -1366,13 +1364,6 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
13661364List * query_list = lfirst (query_list_list_item );
13671365ListCell * query_list_item ;
13681366
1369- /* Reset state for each original parsetree */
1370- /* (at most one of its querytrees will be marked canSetTag) */
1371- SPI_processed = 0 ;
1372- SPI_lastoid = InvalidOid ;
1373- SPI_tuptable = NULL ;
1374- _SPI_current -> tuptable = NULL ;
1375-
13761367foreach (query_list_item ,query_list )
13771368{
13781369Query * queryTree = (Query * )lfirst (query_list_item );
@@ -1383,6 +1374,10 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
13831374planTree = lfirst (plan_list_item );
13841375plan_list_item = lnext (plan_list_item );
13851376
1377+ _SPI_current -> processed = 0 ;
1378+ _SPI_current -> lastoid = InvalidOid ;
1379+ _SPI_current -> tuptable = NULL ;
1380+
13861381if (queryTree -> commandType == CMD_UTILITY )
13871382{
13881383if (IsA (queryTree -> utilityStmt ,CopyStmt ))
@@ -1467,6 +1462,23 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
14671462}
14681463FreeSnapshot (ActiveSnapshot );
14691464ActiveSnapshot = NULL ;
1465+ /*
1466+ * The last canSetTag query sets the auxiliary values returned
1467+ * to the caller. Be careful to free any tuptables not
1468+ * returned, to avoid intratransaction memory leak.
1469+ */
1470+ if (queryTree -> canSetTag )
1471+ {
1472+ my_processed = _SPI_current -> processed ;
1473+ my_lastoid = _SPI_current -> lastoid ;
1474+ SPI_freetuptable (my_tuptable );
1475+ my_tuptable = _SPI_current -> tuptable ;
1476+ }
1477+ else
1478+ {
1479+ SPI_freetuptable (_SPI_current -> tuptable );
1480+ _SPI_current -> tuptable = NULL ;
1481+ }
14701482/* we know that the receiver doesn't need a destroy call */
14711483if (res < 0 )
14721484gotofail ;
@@ -1490,16 +1502,19 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
14901502
14911503ActiveSnapshot = saveActiveSnapshot ;
14921504
1505+ /* Save results for caller */
1506+ SPI_processed = my_processed ;
1507+ SPI_lastoid = my_lastoid ;
1508+ SPI_tuptable = my_tuptable ;
1509+
14931510return res ;
14941511}
14951512
14961513static int
14971514_SPI_pquery (QueryDesc * queryDesc ,long tcount )
14981515{
14991516int operation = queryDesc -> operation ;
1500- CommandDest origDest = queryDesc -> dest -> mydest ;
15011517int res ;
1502- Oid save_lastoid ;
15031518
15041519switch (operation )
15051520{
@@ -1510,6 +1525,11 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
15101525res = SPI_OK_SELINTO ;
15111526queryDesc -> dest = None_Receiver ;/* don't output results */
15121527}
1528+ else if (queryDesc -> dest -> mydest != SPI )
1529+ {
1530+ /* Don't return SPI_OK_SELECT if we're discarding result */
1531+ res = SPI_OK_UTILITY ;
1532+ }
15131533break ;
15141534case CMD_INSERT :
15151535res = SPI_OK_INSERT ;
@@ -1536,7 +1556,7 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
15361556ExecutorRun (queryDesc ,ForwardScanDirection ,tcount );
15371557
15381558_SPI_current -> processed = queryDesc -> estate -> es_processed ;
1539- save_lastoid = queryDesc -> estate -> es_lastoid ;
1559+ _SPI_current -> lastoid = queryDesc -> estate -> es_lastoid ;
15401560
15411561if (operation == CMD_SELECT && queryDesc -> dest -> mydest == SPI )
15421562{
@@ -1549,19 +1569,6 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
15491569
15501570ExecutorEnd (queryDesc );
15511571
1552- /* Test origDest here so that SPI_processed gets set in SELINTO case */
1553- if (origDest == SPI )
1554- {
1555- SPI_processed = _SPI_current -> processed ;
1556- SPI_lastoid = save_lastoid ;
1557- SPI_tuptable = _SPI_current -> tuptable ;
1558- }
1559- else if (res == SPI_OK_SELECT )
1560- {
1561- /* Don't return SPI_OK_SELECT if we discarded the result */
1562- res = SPI_OK_UTILITY ;
1563- }
1564-
15651572#ifdef SPI_EXECUTOR_STATS
15661573if (ShowExecutorStats )
15671574ShowUsage ("SPI EXECUTOR STATS" );
@@ -1615,7 +1622,7 @@ _SPI_cursor_operation(Portal portal, bool forward, long count,
16151622if (_SPI_begin_call (true)< 0 )
16161623elog (ERROR ,"SPI cursor operation called while not connected" );
16171624
1618- /* Reset the SPI result */
1625+ /* Reset the SPI result(note we deliberately don't touch lastoid) */
16191626SPI_processed = 0 ;
16201627SPI_tuptable = NULL ;
16211628_SPI_current -> processed = 0 ;