aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/pquery.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2004-10-04 21:52:15 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2004-10-04 21:52:15 +0000
commit4c77cbb272948e96ce3ed02d444a944eb45d45e3 (patch)
treef3dfa5472465d452fad976c83cc15b1038249fe8 /src/backend/tcop/pquery.c
parentee7de3d66296513d50b6df1166f6fc84e2b9b5fe (diff)
downloadpostgresql-4c77cbb272948e96ce3ed02d444a944eb45d45e3.tar.gz
postgresql-4c77cbb272948e96ce3ed02d444a944eb45d45e3.zip
PortalRun must guard against the possibility that the portal it's
running contains VACUUM or a similar command that will internally start and commit transactions. In such a case, the original caller values of CurrentMemoryContext and CurrentResourceOwner will point to objects that will be destroyed by the internal commit. We must restore these pointers to point to the newly-manufactured transaction context and resource owner, rather than possibly pointing to deleted memory. Also tweak xact.c so that AbortTransaction and AbortSubTransaction forcibly restore a sane value for CurrentResourceOwner, much as they have always done for CurrentMemoryContext. I'm not certain this is necessary but I'm feeling paranoid today. Responds to Sean Chittenden's bug report of 4-Oct.
Diffstat (limited to 'src/backend/tcop/pquery.c')
-rw-r--r--src/backend/tcop/pquery.c42
1 files changed, 35 insertions, 7 deletions
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 5a1c8b4867b..2c4c2f3c7e5 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.87 2004/09/13 20:07:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.88 2004/10/04 21:52:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -491,12 +491,14 @@ PortalRun(Portal portal, long count,
char *completionTag)
{
bool result;
+ ResourceOwner saveTopTransactionResourceOwner;
+ MemoryContext saveTopTransactionContext;
Portal saveActivePortal;
Snapshot saveActiveSnapshot;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext;
MemoryContext saveQueryContext;
- MemoryContext oldContext;
+ MemoryContext saveMemoryContext;
AssertArg(PortalIsValid(portal));
@@ -523,12 +525,26 @@ PortalRun(Portal portal, long count,
/*
* Set up global portal context pointers.
+ *
+ * We have to play a special game here to support utility commands like
+ * VACUUM and CLUSTER, which internally start and commit transactions.
+ * When we are called to execute such a command, CurrentResourceOwner
+ * will be pointing to the TopTransactionResourceOwner --- which will
+ * be destroyed and replaced in the course of the internal commit and
+ * restart. So we need to be prepared to restore it as pointing to
+ * the exit-time TopTransactionResourceOwner. (Ain't that ugly? This
+ * idea of internally starting whole new transactions is not good.)
+ * CurrentMemoryContext has a similar problem, but the other pointers
+ * we save here will be NULL or pointing to longer-lived objects.
*/
+ saveTopTransactionResourceOwner = TopTransactionResourceOwner;
+ saveTopTransactionContext = TopTransactionContext;
saveActivePortal = ActivePortal;
saveActiveSnapshot = ActiveSnapshot;
saveResourceOwner = CurrentResourceOwner;
savePortalContext = PortalContext;
saveQueryContext = QueryContext;
+ saveMemoryContext = CurrentMemoryContext;
PG_TRY();
{
ActivePortal = portal;
@@ -537,7 +553,7 @@ PortalRun(Portal portal, long count,
PortalContext = PortalGetHeapMemory(portal);
QueryContext = portal->queryContext;
- oldContext = MemoryContextSwitchTo(PortalContext);
+ MemoryContextSwitchTo(PortalContext);
switch (portal->strategy)
{
@@ -620,9 +636,16 @@ PortalRun(Portal portal, long count,
portal->status = PORTAL_FAILED;
/* Restore global vars and propagate error */
+ if (saveMemoryContext == saveTopTransactionContext)
+ MemoryContextSwitchTo(TopTransactionContext);
+ else
+ MemoryContextSwitchTo(saveMemoryContext);
ActivePortal = saveActivePortal;
ActiveSnapshot = saveActiveSnapshot;
- CurrentResourceOwner = saveResourceOwner;
+ if (saveResourceOwner == saveTopTransactionResourceOwner)
+ CurrentResourceOwner = TopTransactionResourceOwner;
+ else
+ CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
@@ -630,11 +653,16 @@ PortalRun(Portal portal, long count,
}
PG_END_TRY();
- MemoryContextSwitchTo(oldContext);
-
+ if (saveMemoryContext == saveTopTransactionContext)
+ MemoryContextSwitchTo(TopTransactionContext);
+ else
+ MemoryContextSwitchTo(saveMemoryContext);
ActivePortal = saveActivePortal;
ActiveSnapshot = saveActiveSnapshot;
- CurrentResourceOwner = saveResourceOwner;
+ if (saveResourceOwner == saveTopTransactionResourceOwner)
+ CurrentResourceOwner = TopTransactionResourceOwner;
+ else
+ CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;