diff options
Diffstat (limited to 'src/backend/tcop')
-rw-r--r-- | src/backend/tcop/postgres.c | 109 | ||||
-rw-r--r-- | src/backend/tcop/pquery.c | 348 |
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); |