Commit cefb4b14 authored by Tom Lane's avatar Tom Lane

Tweak elog.c's logic for promoting errors into more severe errors.

Messages of less than ERROR severity should never be promoted (this
fixes Gaetano Mendola's problem with a COMMERROR becoming a PANIC,
and is obvious in hindsight anyway).  Do all promotion in errstart
not errfinish, to ensure that output decisions are made correctly;
the former coding could suppress logging of promoted errors, which
doesn't seem like a good idea.  Eliminate some redundant code too.
parent 346900e8
...@@ -24,12 +24,17 @@ ...@@ -24,12 +24,17 @@
* the elog.c routines or something they call. By far the most probable * the elog.c routines or something they call. By far the most probable
* scenario of this sort is "out of memory"; and it's also the nastiest * scenario of this sort is "out of memory"; and it's also the nastiest
* to handle because we'd likely also run out of memory while trying to * to handle because we'd likely also run out of memory while trying to
* report this error! Our escape hatch for this condition is to force any * report this error! Our escape hatch for this case is to reset the
* such messages up to ERROR level if they aren't already (so that we will * ErrorContext to empty before trying to process the inner error. Since
* not need to return to the outer elog.c call), and to reset the ErrorContext * ErrorContext is guaranteed to have at least 8K of space in it (see mcxt.c),
* to empty before trying to process the inner message. Since ErrorContext * we should be able to process an "out of memory" message successfully.
* is guaranteed to have at least 8K of space in it (see mcxt.c), we should * Since we lose the prior error state due to the reset, we won't be able
* be able to process an "out of memory" message successfully. * to return to processing the original error, but we wouldn't have anyway.
* (NOTE: the escape hatch is not used for recursive situations where the
* inner message is of less than ERROR severity; in that case we just
* try to process it and return normally. Usually this will work, but if
* it ends up in infinite recursion, we will PANIC due to error stack
* overflow.)
* *
* *
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
...@@ -37,7 +42,7 @@ ...@@ -37,7 +42,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.148 2004/08/29 05:06:50 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.149 2004/09/05 02:01:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -132,30 +137,59 @@ errstart(int elevel, const char *filename, int lineno, ...@@ -132,30 +137,59 @@ errstart(int elevel, const char *filename, int lineno,
ErrorData *edata; ErrorData *edata;
bool output_to_server = false; bool output_to_server = false;
bool output_to_client = false; bool output_to_client = false;
int i;
/* /*
* First decide whether we need to process this report at all; if it's * Check some cases in which we want to promote an error into a more
* warning or less and not enabled for logging, just return FALSE * severe error. None of this logic applies for non-error messages.
* without starting up any error logging machinery. */
if (elevel >= ERROR)
{
/*
* If we are inside a critical section, all errors become PANIC
* errors. See miscadmin.h.
*/ */
if (CritSectionCount > 0)
elevel = PANIC;
/* /*
* Convert initialization errors into fatal errors. This is probably * Check reasons for treating ERROR as FATAL:
* redundant, because PG_exception_stack will still be null anyway. *
* 1. we have no handler to pass the error to (implies we are in the
* postmaster or in backend startup).
*
* 2. ExitOnAnyError mode switch is set (initdb uses this).
*
* 3. the error occurred after proc_exit has begun to run. (It's
* proc_exit's responsibility to see that this doesn't turn into
* infinite recursion!)
*/ */
if (elevel == ERROR && IsInitProcessingMode()) if (elevel == ERROR)
{
if (PG_exception_stack == NULL ||
ExitOnAnyError ||
proc_exit_inprogress)
elevel = FATAL; elevel = FATAL;
}
/* /*
* If we are inside a critical section, all errors become PANIC * If the error level is ERROR or more, errfinish is not going to
* errors. See miscadmin.h. * return to caller; therefore, if there is any stacked error already
* in progress it will be lost. This is more or less okay, except we
* do not want to have a FATAL or PANIC error downgraded because the
* reporting process was interrupted by a lower-grade error. So check
* the stack and make sure we panic if panic is warranted.
*/ */
if (elevel >= ERROR) for (i = 0; i <= errordata_stack_depth; i++)
{ elevel = Max(elevel, errordata[i].elevel);
if (CritSectionCount > 0)
elevel = PANIC;
} }
/*
* Now decide whether we need to process this report at all; if it's
* warning or less and not enabled for logging, just return FALSE
* without starting up any error logging machinery.
*/
/* Determine whether message is enabled for server log output */ /* Determine whether message is enabled for server log output */
if (IsPostmasterEnvironment) if (IsPostmasterEnvironment)
{ {
...@@ -210,18 +244,14 @@ errstart(int elevel, const char *filename, int lineno, ...@@ -210,18 +244,14 @@ errstart(int elevel, const char *filename, int lineno,
* Okay, crank up a stack entry to store the info in. * Okay, crank up a stack entry to store the info in.
*/ */
if (recursion_depth++ > 0) if (recursion_depth++ > 0 && elevel >= ERROR)
{ {
/* /*
* Ooops, error during error processing. Clear ErrorContext and * Ooops, error during error processing. Clear ErrorContext as
* force level up to ERROR or greater, as discussed at top of * discussed at top of file. We will not return to the original
* file. Adjust output decisions too. * error's reporter or handler, so we don't need it.
*/ */
MemoryContextReset(ErrorContext); MemoryContextReset(ErrorContext);
output_to_server = true;
if (whereToSendOutput == Remote && elevel != COMMERROR)
output_to_client = true;
elevel = Max(elevel, ERROR);
/* /*
* If we recurse more than once, the problem might be something * If we recurse more than once, the problem might be something
...@@ -300,46 +330,13 @@ errfinish(int dummy,...) ...@@ -300,46 +330,13 @@ errfinish(int dummy,...)
(*econtext->callback) (econtext->arg); (*econtext->callback) (econtext->arg);
/* /*
* If the error level is ERROR or more, we are not going to return to * If ERROR (not more nor less) we pass it off to the current handler.
* caller; therefore, if there is any stacked error already in * Printing it and popping the stack is the responsibility of
* progress it will be lost. This is more or less okay, except we do * the handler.
* not want to have a FATAL or PANIC error downgraded because the
* reporting process was interrupted by a lower-grade error. So check
* the stack and make sure we panic if panic is warranted.
*/
if (elevel >= ERROR)
{
int i;
for (i = 0; i <= errordata_stack_depth; i++)
elevel = Max(elevel, errordata[i].elevel);
}
/*
* Check some other reasons for treating ERROR as FATAL:
*
* 1. we have no handler to pass the error to (implies we are in the
* postmaster or in backend startup).
*
* 2. ExitOnAnyError mode switch is set (initdb uses this).
*
* 3. the error occurred after proc_exit has begun to run. (It's
* proc_exit's responsibility to see that this doesn't turn into
* infinite recursion!)
*/ */
if (elevel == ERROR) if (elevel == ERROR)
{
if (PG_exception_stack == NULL ||
ExitOnAnyError ||
proc_exit_inprogress)
elevel = FATAL;
else
{ {
/* /*
* Otherwise we can pass the error off to the current handler.
* Printing it and popping the stack is the responsibility of
* the handler.
*
* We do some minimal cleanup before longjmp'ing so that handlers * We do some minimal cleanup before longjmp'ing so that handlers
* can execute in a reasonably sane state. * can execute in a reasonably sane state.
*/ */
...@@ -360,15 +357,13 @@ errfinish(int dummy,...) ...@@ -360,15 +357,13 @@ errfinish(int dummy,...)
CritSectionCount = 0; /* should be unnecessary, but... */ CritSectionCount = 0; /* should be unnecessary, but... */
/* /*
* Note that we leave CurrentMemoryContext set to * Note that we leave CurrentMemoryContext set to ErrorContext.
* ErrorContext. The handler should reset it to something else * The handler should reset it to something else soon.
* soon.
*/ */
recursion_depth--; recursion_depth--;
PG_RE_THROW(); PG_RE_THROW();
} }
}
/* /*
* If we are doing FATAL or PANIC, abort any old-style COPY OUT in * If we are doing FATAL or PANIC, abort any old-style COPY OUT in
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment