diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2004-07-31 00:45:57 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2004-07-31 00:45:57 +0000 |
commit | a393fbf93763709f90ba1f968e50a35bd4cabcfb (patch) | |
tree | 955d74e7181214688b575f31c243005fe470dfe1 /src/backend/tcop/postgres.c | |
parent | 94f8f63fdbcf61a56a23b8052d68fd78bec86a3b (diff) | |
download | postgresql-a393fbf93763709f90ba1f968e50a35bd4cabcfb.tar.gz postgresql-a393fbf93763709f90ba1f968e50a35bd4cabcfb.zip |
Restructure error handling as recently discussed. It is now really
possible to trap an error inside a function rather than letting it
propagate out to PostgresMain. You still have to use AbortCurrentTransaction
to clean up, but at least the error handling itself will cooperate.
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r-- | src/backend/tcop/postgres.c | 109 |
1 files changed, 50 insertions, 59 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); |