aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/tcop')
-rw-r--r--src/backend/tcop/postgres.c109
-rw-r--r--src/backend/tcop/pquery.c348
2 files changed, 249 insertions, 208 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index a8a7e0197ae..89ee40a5321 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.426 2004/07/28 22:05:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.427 2004/07/31 00:45:36 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -23,7 +23,6 @@
#include <signal.h>
#include <fcntl.h>
#include <sys/socket.h>
-#include <errno.h>
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
@@ -77,12 +76,6 @@ const char *debug_query_string; /* for pgmonitor and
/* Note: whereToSendOutput is initialized for the bootstrap/standalone case */
CommandDest whereToSendOutput = Debug;
-/* note: these declarations had better match tcopprot.h */
-sigjmp_buf Warn_restart;
-
-bool Warn_restart_ready = false;
-bool InError = false;
-
/* flag for logging end of session */
bool Log_disconnections = false;
@@ -1876,7 +1869,7 @@ quickdie(SIGNAL_ARGS)
/*
* Ideally this should be ereport(FATAL), but then we'd not get
- * control back (perhaps could fix by doing local sigsetjmp?)
+ * control back...
*/
ereport(WARNING,
(errcode(ERRCODE_CRASH_SHUTDOWN),
@@ -1962,10 +1955,9 @@ StatementCancelHandler(SIGNAL_ARGS)
int save_errno = errno;
/*
- * Don't joggle the elbow of proc_exit, nor an already-in-progress
- * abort
+ * Don't joggle the elbow of proc_exit
*/
- if (!proc_exit_inprogress && !InError)
+ if (!proc_exit_inprogress)
{
InterruptPending = true;
QueryCancelPending = true;
@@ -2148,7 +2140,6 @@ usage(const char *progname)
}
-
/* ----------------------------------------------------------------
* PostgresMain
* postgres main loop -- all backends, interactive or otherwise start here
@@ -2175,6 +2166,7 @@ PostgresMain(int argc, char *argv[], const char *username)
int firstchar;
char stack_base;
StringInfoData input_message;
+ sigjmp_buf local_sigjmp_buf;
volatile bool send_rfq = true;
/*
@@ -2772,50 +2764,61 @@ PostgresMain(int argc, char *argv[], const char *username)
*
* If an exception is encountered, processing resumes here so we abort
* the current transaction and start a new one.
+ *
+ * You might wonder why this isn't coded as an infinite loop around
+ * a PG_TRY construct. The reason is that this is the bottom of the
+ * exception stack, and so with PG_TRY there would be no exception
+ * handler in force at all during the CATCH part. By leaving the
+ * outermost setjmp always active, we have at least some chance of
+ * recovering from an error during error recovery. (If we get into
+ * an infinite loop thereby, it will soon be stopped by overflow of
+ * elog.c's internal state stack.)
*/
- if (sigsetjmp(Warn_restart, 1) != 0)
+ if (sigsetjmp(local_sigjmp_buf, 1) != 0)
{
/*
* NOTE: if you are tempted to add more code in this if-block,
- * consider the probability that it should be in
- * AbortTransaction() instead.
- *
- * Make sure we're not interrupted while cleaning up. Also forget
- * any pending QueryCancel request, since we're aborting anyway.
- * Force InterruptHoldoffCount to a known state in case we
- * ereport'd from inside a holdoff section.
+ * consider the high probability that it should be in
+ * AbortTransaction() instead. The only stuff done directly here
+ * should be stuff that is guaranteed to apply *only* for outer-level
+ * error recovery, such as adjusting the FE/BE protocol status.
+ */
+
+ /* Since not using PG_TRY, must reset error stack by hand */
+ error_context_stack = NULL;
+
+ /* Prevent interrupts while cleaning up */
+ HOLD_INTERRUPTS();
+
+ /*
+ * Forget any pending QueryCancel request, since we're returning
+ * to the idle loop anyway, and cancel the statement timer if running.
*/
- ImmediateInterruptOK = false;
QueryCancelPending = false;
- InterruptHoldoffCount = 1;
- CritSectionCount = 0; /* should be unnecessary, but... */
disable_sig_alarm(true);
QueryCancelPending = false; /* again in case timeout occurred */
+
+ /*
+ * Turn off these interrupts too. This is only needed here and not
+ * in other exception-catching places since these interrupts are
+ * only enabled while we wait for client input.
+ */
DisableNotifyInterrupt();
DisableCatchupInterrupt();
- debug_query_string = NULL;
+
+ /* Report the error to the client and/or server log */
+ EmitErrorReport();
/*
- * If there's an active portal, mark it as failed
+ * Make sure debug_query_string gets reset before we possibly clobber
+ * the storage it points at.
*/
- if (ActivePortal)
- ActivePortal->status = PORTAL_FAILED;
+ debug_query_string = NULL;
/*
- * Make sure we are in a valid memory context during recovery.
- *
- * We use ErrorContext in hopes that it will have some free space
- * even if we're otherwise up against it...
+ * Abort the current transaction in order to recover.
*/
- MemoryContextSwitchTo(ErrorContext);
-
- /* Make sure we are using a sane ResourceOwner, too */
- CurrentResourceOwner = CurTransactionResourceOwner;
-
- /* Do the recovery */
- ereport(DEBUG2,
- (errmsg_internal("AbortCurrentTransaction")));
AbortCurrentTransaction();
/*
@@ -2823,24 +2826,10 @@ PostgresMain(int argc, char *argv[], const char *username)
* for next time.
*/
MemoryContextSwitchTo(TopMemoryContext);
- MemoryContextResetAndDeleteChildren(ErrorContext);
- ActivePortal = NULL;
- PortalContext = NULL;
+ FlushErrorState();
QueryContext = NULL;
/*
- * Clear flag to indicate that we got out of error recovery mode
- * successfully. (Flag was set in elog.c before longjmp().)
- */
- InError = false;
- xact_started = false;
-
- /*
- * Clear flag that causes accounting for cost based vacuum.
- */
- VacuumCostActive = false;
-
- /*
* If we were handling an extended-query-protocol message,
* initiate skip till next Sync. This also causes us not to issue
* ReadyForQuery (until we get Sync).
@@ -2848,13 +2837,15 @@ PostgresMain(int argc, char *argv[], const char *username)
if (doing_extended_query_message)
ignore_till_sync = true;
- /*
- * Exit interrupt holdoff section we implicitly established above.
- */
+ /* We don't have a transaction command open anymore */
+ xact_started = false;
+
+ /* Now we can allow interrupts again */
RESUME_INTERRUPTS();
}
- Warn_restart_ready = true; /* we can now handle ereport(ERROR) */
+ /* We can now handle ereport(ERROR) */
+ PG_exception_stack = &local_sigjmp_buf;
PG_SETMASK(&UnBlockSig);
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 49e2a4b0082..8973cca6d26 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.81 2004/07/17 03:29:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.82 2004/07/31 00:45:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -246,94 +246,110 @@ PortalStart(Portal portal, ParamListInfo params)
AssertState(portal->status == PORTAL_NEW); /* else extra PortalStart */
/*
- * Set global portal context pointers. (Should we set QueryContext?)
+ * Set up global portal context pointers. (Should we set QueryContext?)
*/
saveActivePortal = ActivePortal;
- ActivePortal = portal;
saveResourceOwner = CurrentResourceOwner;
- CurrentResourceOwner = portal->resowner;
savePortalContext = PortalContext;
- PortalContext = PortalGetHeapMemory(portal);
+ PG_TRY();
+ {
+ ActivePortal = portal;
+ CurrentResourceOwner = portal->resowner;
+ PortalContext = PortalGetHeapMemory(portal);
- oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
+ oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
- /* Must remember portal param list, if any */
- portal->portalParams = params;
+ /* Must remember portal param list, if any */
+ portal->portalParams = params;
- /*
- * Determine the portal execution strategy
- */
- portal->strategy = ChoosePortalStrategy(portal->parseTrees);
+ /*
+ * Determine the portal execution strategy
+ */
+ portal->strategy = ChoosePortalStrategy(portal->parseTrees);
- /*
- * Fire her up according to the strategy
- */
- switch (portal->strategy)
- {
- case PORTAL_ONE_SELECT:
+ /*
+ * Fire her up according to the strategy
+ */
+ switch (portal->strategy)
+ {
+ case PORTAL_ONE_SELECT:
- /*
- * Must set query snapshot before starting executor.
- */
- SetQuerySnapshot();
+ /*
+ * Must set query snapshot before starting executor.
+ */
+ SetQuerySnapshot();
- /*
- * Create QueryDesc in portal's context; for the moment, set
- * the destination to None.
- */
- queryDesc = CreateQueryDesc((Query *) linitial(portal->parseTrees),
- (Plan *) linitial(portal->planTrees),
- None_Receiver,
- params,
- false);
+ /*
+ * Create QueryDesc in portal's context; for the moment, set
+ * the destination to None.
+ */
+ queryDesc = CreateQueryDesc((Query *) linitial(portal->parseTrees),
+ (Plan *) linitial(portal->planTrees),
+ None_Receiver,
+ params,
+ false);
- /*
- * Call ExecStart to prepare the plan for execution
- */
- ExecutorStart(queryDesc, false, false);
+ /*
+ * Call ExecStart to prepare the plan for execution
+ */
+ ExecutorStart(queryDesc, false, false);
- /*
- * This tells PortalCleanup to shut down the executor
- */
- portal->queryDesc = queryDesc;
+ /*
+ * This tells PortalCleanup to shut down the executor
+ */
+ portal->queryDesc = queryDesc;
- /*
- * Remember tuple descriptor (computed by ExecutorStart)
- */
- portal->tupDesc = queryDesc->tupDesc;
+ /*
+ * Remember tuple descriptor (computed by ExecutorStart)
+ */
+ portal->tupDesc = queryDesc->tupDesc;
- /*
- * Reset cursor position data to "start of query"
- */
- portal->atStart = true;
- portal->atEnd = false; /* allow fetches */
- portal->portalPos = 0;
- portal->posOverflow = false;
- break;
+ /*
+ * Reset cursor position data to "start of query"
+ */
+ portal->atStart = true;
+ portal->atEnd = false; /* allow fetches */
+ portal->portalPos = 0;
+ portal->posOverflow = false;
+ break;
- case PORTAL_UTIL_SELECT:
+ case PORTAL_UTIL_SELECT:
- /*
- * We don't set query snapshot here, because PortalRunUtility
- * will take care of it.
- */
- portal->tupDesc =
- UtilityTupleDescriptor(((Query *) linitial(portal->parseTrees))->utilityStmt);
+ /*
+ * We don't set query snapshot here, because PortalRunUtility
+ * will take care of it.
+ */
+ portal->tupDesc =
+ UtilityTupleDescriptor(((Query *) linitial(portal->parseTrees))->utilityStmt);
- /*
- * Reset cursor position data to "start of query"
- */
- portal->atStart = true;
- portal->atEnd = false; /* allow fetches */
- portal->portalPos = 0;
- portal->posOverflow = false;
- break;
+ /*
+ * Reset cursor position data to "start of query"
+ */
+ portal->atStart = true;
+ portal->atEnd = false; /* allow fetches */
+ portal->portalPos = 0;
+ portal->posOverflow = false;
+ break;
- case PORTAL_MULTI_QUERY:
- /* Need do nothing now */
- portal->tupDesc = NULL;
- break;
+ case PORTAL_MULTI_QUERY:
+ /* Need do nothing now */
+ portal->tupDesc = NULL;
+ break;
+ }
}
+ PG_CATCH();
+ {
+ /* Uncaught error while executing portal: mark it dead */
+ portal->status = PORTAL_FAILED;
+
+ /* Restore global vars and propagate error */
+ ActivePortal = saveActivePortal;
+ CurrentResourceOwner = saveResourceOwner;
+ PortalContext = savePortalContext;
+
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
MemoryContextSwitchTo(oldContext);
@@ -449,91 +465,108 @@ PortalRun(Portal portal, long count,
portal->status = PORTAL_ACTIVE;
/*
- * Set global portal context pointers.
+ * Set up global portal context pointers.
*/
saveActivePortal = ActivePortal;
- ActivePortal = portal;
saveResourceOwner = CurrentResourceOwner;
- CurrentResourceOwner = portal->resowner;
savePortalContext = PortalContext;
- PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext;
- QueryContext = portal->queryContext;
+ PG_TRY();
+ {
+ ActivePortal = portal;
+ CurrentResourceOwner = portal->resowner;
+ PortalContext = PortalGetHeapMemory(portal);
+ QueryContext = portal->queryContext;
- oldContext = MemoryContextSwitchTo(PortalContext);
+ oldContext = MemoryContextSwitchTo(PortalContext);
- switch (portal->strategy)
- {
- case PORTAL_ONE_SELECT:
- (void) PortalRunSelect(portal, true, count, dest);
- /* we know the query is supposed to set the tag */
- if (completionTag && portal->commandTag)
- strcpy(completionTag, portal->commandTag);
+ switch (portal->strategy)
+ {
+ case PORTAL_ONE_SELECT:
+ (void) PortalRunSelect(portal, true, count, dest);
+ /* we know the query is supposed to set the tag */
+ if (completionTag && portal->commandTag)
+ strcpy(completionTag, portal->commandTag);
- /* Mark portal not active */
- portal->status = PORTAL_READY;
+ /* Mark portal not active */
+ portal->status = PORTAL_READY;
- /*
- * Since it's a forward fetch, say DONE iff atEnd is now true.
- */
- result = portal->atEnd;
- break;
+ /*
+ * Since it's a forward fetch, say DONE iff atEnd is now true.
+ */
+ result = portal->atEnd;
+ break;
- case PORTAL_UTIL_SELECT:
+ case PORTAL_UTIL_SELECT:
- /*
- * If we have not yet run the utility statement, do so,
- * storing its results in the portal's tuplestore.
- */
- if (!portal->portalUtilReady)
- {
- DestReceiver *treceiver;
-
- PortalCreateHoldStore(portal);
- treceiver = CreateDestReceiver(Tuplestore, portal);
- PortalRunUtility(portal, linitial(portal->parseTrees),
- treceiver, NULL);
- (*treceiver->rDestroy) (treceiver);
- portal->portalUtilReady = true;
- }
+ /*
+ * If we have not yet run the utility statement, do so,
+ * storing its results in the portal's tuplestore.
+ */
+ if (!portal->portalUtilReady)
+ {
+ DestReceiver *treceiver;
+
+ PortalCreateHoldStore(portal);
+ treceiver = CreateDestReceiver(Tuplestore, portal);
+ PortalRunUtility(portal, linitial(portal->parseTrees),
+ treceiver, NULL);
+ (*treceiver->rDestroy) (treceiver);
+ portal->portalUtilReady = true;
+ }
- /*
- * Now fetch desired portion of results.
- */
- (void) PortalRunSelect(portal, true, count, dest);
+ /*
+ * Now fetch desired portion of results.
+ */
+ (void) PortalRunSelect(portal, true, count, dest);
- /*
- * We know the query is supposed to set the tag; we assume
- * only the default tag is needed.
- */
- if (completionTag && portal->commandTag)
- strcpy(completionTag, portal->commandTag);
+ /*
+ * We know the query is supposed to set the tag; we assume
+ * only the default tag is needed.
+ */
+ if (completionTag && portal->commandTag)
+ strcpy(completionTag, portal->commandTag);
- /* Mark portal not active */
- portal->status = PORTAL_READY;
+ /* Mark portal not active */
+ portal->status = PORTAL_READY;
- /*
- * Since it's a forward fetch, say DONE iff atEnd is now true.
- */
- result = portal->atEnd;
- break;
+ /*
+ * Since it's a forward fetch, say DONE iff atEnd is now true.
+ */
+ result = portal->atEnd;
+ break;
- case PORTAL_MULTI_QUERY:
- PortalRunMulti(portal, dest, altdest, completionTag);
+ case PORTAL_MULTI_QUERY:
+ PortalRunMulti(portal, dest, altdest, completionTag);
- /* Prevent portal's commands from being re-executed */
- portal->status = PORTAL_DONE;
+ /* Prevent portal's commands from being re-executed */
+ portal->status = PORTAL_DONE;
- /* Always complete at end of RunMulti */
- result = true;
- break;
+ /* Always complete at end of RunMulti */
+ result = true;
+ break;
- default:
- elog(ERROR, "unrecognized portal strategy: %d",
- (int) portal->strategy);
- result = false; /* keep compiler quiet */
- break;
+ default:
+ elog(ERROR, "unrecognized portal strategy: %d",
+ (int) portal->strategy);
+ result = false; /* keep compiler quiet */
+ break;
+ }
+ }
+ PG_CATCH();
+ {
+ /* Uncaught error while executing portal: mark it dead */
+ portal->status = PORTAL_FAILED;
+
+ /* Restore global vars and propagate error */
+ ActivePortal = saveActivePortal;
+ CurrentResourceOwner = saveResourceOwner;
+ PortalContext = savePortalContext;
+ QueryContext = saveQueryContext;
+
+ PG_RE_THROW();
}
+ PG_END_TRY();
MemoryContextSwitchTo(oldContext);
@@ -970,30 +1003,47 @@ PortalRunFetch(Portal portal,
portal->status = PORTAL_ACTIVE;
/*
- * Set global portal context pointers.
+ * Set up global portal context pointers.
*/
saveActivePortal = ActivePortal;
- ActivePortal = portal;
saveResourceOwner = CurrentResourceOwner;
- CurrentResourceOwner = portal->resowner;
savePortalContext = PortalContext;
- PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext;
- QueryContext = portal->queryContext;
+ PG_TRY();
+ {
+ ActivePortal = portal;
+ CurrentResourceOwner = portal->resowner;
+ PortalContext = PortalGetHeapMemory(portal);
+ QueryContext = portal->queryContext;
- oldContext = MemoryContextSwitchTo(PortalContext);
+ oldContext = MemoryContextSwitchTo(PortalContext);
- switch (portal->strategy)
+ switch (portal->strategy)
+ {
+ case PORTAL_ONE_SELECT:
+ result = DoPortalRunFetch(portal, fdirection, count, dest);
+ break;
+
+ default:
+ elog(ERROR, "unsupported portal strategy");
+ result = 0; /* keep compiler quiet */
+ break;
+ }
+ }
+ PG_CATCH();
{
- case PORTAL_ONE_SELECT:
- result = DoPortalRunFetch(portal, fdirection, count, dest);
- break;
+ /* Uncaught error while executing portal: mark it dead */
+ portal->status = PORTAL_FAILED;
- default:
- elog(ERROR, "unsupported portal strategy");
- result = 0; /* keep compiler quiet */
- break;
+ /* Restore global vars and propagate error */
+ ActivePortal = saveActivePortal;
+ CurrentResourceOwner = saveResourceOwner;
+ PortalContext = savePortalContext;
+ QueryContext = saveQueryContext;
+
+ PG_RE_THROW();
}
+ PG_END_TRY();
MemoryContextSwitchTo(oldContext);