aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/spi.c')
-rw-r--r--src/backend/executor/spi.c42
1 files changed, 33 insertions, 9 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 6d9dd9cc9f9..3574c854f1b 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -36,10 +36,16 @@
#include "utils/typcache.h"
+/*
+ * These global variables are part of the API for various SPI functions
+ * (a horrible API choice, but it's too late now). To reduce the risk of
+ * interference between different SPI callers, we save and restore them
+ * when entering/exiting a SPI nesting level.
+ */
uint64 SPI_processed = 0;
Oid SPI_lastoid = InvalidOid;
SPITupleTable *SPI_tuptable = NULL;
-int SPI_result;
+int SPI_result = 0;
static _SPI_connection *_SPI_stack = NULL;
static _SPI_connection *_SPI_current = NULL;
@@ -124,6 +130,10 @@ SPI_connect(void)
_SPI_current->execCxt = NULL;
_SPI_current->connectSubid = GetCurrentSubTransactionId();
_SPI_current->queryEnv = NULL;
+ _SPI_current->outer_processed = SPI_processed;
+ _SPI_current->outer_lastoid = SPI_lastoid;
+ _SPI_current->outer_tuptable = SPI_tuptable;
+ _SPI_current->outer_result = SPI_result;
/*
* Create memory contexts for this procedure
@@ -142,6 +152,15 @@ SPI_connect(void)
/* ... and switch to procedure's context */
_SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
+ /*
+ * Reset API global variables so that current caller cannot accidentally
+ * depend on state of an outer caller.
+ */
+ SPI_processed = 0;
+ SPI_lastoid = InvalidOid;
+ SPI_tuptable = NULL;
+ SPI_result = 0;
+
return SPI_OK_CONNECT;
}
@@ -164,12 +183,13 @@ SPI_finish(void)
_SPI_current->procCxt = NULL;
/*
- * Reset result variables, especially SPI_tuptable which is probably
+ * Restore outer API variables, especially SPI_tuptable which is probably
* pointing at a just-deleted tuptable
*/
- SPI_processed = 0;
- SPI_lastoid = InvalidOid;
- SPI_tuptable = NULL;
+ SPI_processed = _SPI_current->outer_processed;
+ SPI_lastoid = _SPI_current->outer_lastoid;
+ SPI_tuptable = _SPI_current->outer_tuptable;
+ SPI_result = _SPI_current->outer_result;
/* Exit stack level */
_SPI_connected--;
@@ -201,9 +221,11 @@ AtEOXact_SPI(bool isCommit)
_SPI_current = _SPI_stack = NULL;
_SPI_stack_depth = 0;
_SPI_connected = -1;
+ /* Reset API global variables, too */
SPI_processed = 0;
SPI_lastoid = InvalidOid;
SPI_tuptable = NULL;
+ SPI_result = 0;
}
/*
@@ -241,18 +263,20 @@ AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid)
}
/*
- * Pop the stack entry and reset global variables. Unlike
+ * Restore outer global variables and pop the stack entry. Unlike
* SPI_finish(), we don't risk switching to memory contexts that might
* be already gone.
*/
+ SPI_processed = connection->outer_processed;
+ SPI_lastoid = connection->outer_lastoid;
+ SPI_tuptable = connection->outer_tuptable;
+ SPI_result = connection->outer_result;
+
_SPI_connected--;
if (_SPI_connected < 0)
_SPI_current = NULL;
else
_SPI_current = &(_SPI_stack[_SPI_connected]);
- SPI_processed = 0;
- SPI_lastoid = InvalidOid;
- SPI_tuptable = NULL;
}
if (found && isCommit)