mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
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.
This commit is contained in:
parent
346900e83b
commit
cefb4b141b
@ -24,12 +24,17 @@
|
||||
* 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
|
||||
* 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
|
||||
* such messages up to ERROR level if they aren't already (so that we will
|
||||
* not need to return to the outer elog.c call), and to reset the ErrorContext
|
||||
* to empty before trying to process the inner message. Since ErrorContext
|
||||
* is guaranteed to have at least 8K of space in it (see mcxt.c), we should
|
||||
* be able to process an "out of memory" message successfully.
|
||||
* report this error! Our escape hatch for this case is to reset the
|
||||
* ErrorContext to empty before trying to process the inner error. Since
|
||||
* ErrorContext is guaranteed to have at least 8K of space in it (see mcxt.c),
|
||||
* we should be able to process an "out of memory" message successfully.
|
||||
* Since we lose the prior error state due to the reset, we won't be able
|
||||
* 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
|
||||
@ -37,7 +42,7 @@
|
||||
*
|
||||
*
|
||||
* 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,
|
||||
ErrorData *edata;
|
||||
bool output_to_server = false;
|
||||
bool output_to_client = false;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* First 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Convert initialization errors into fatal errors. This is probably
|
||||
* redundant, because PG_exception_stack will still be null anyway.
|
||||
*/
|
||||
if (elevel == ERROR && IsInitProcessingMode())
|
||||
elevel = FATAL;
|
||||
|
||||
/*
|
||||
* If we are inside a critical section, all errors become PANIC
|
||||
* errors. See miscadmin.h.
|
||||
* Check some cases in which we want to promote an error into a more
|
||||
* severe error. None of this logic applies for non-error messages.
|
||||
*/
|
||||
if (elevel >= ERROR)
|
||||
{
|
||||
/*
|
||||
* If we are inside a critical section, all errors become PANIC
|
||||
* errors. See miscadmin.h.
|
||||
*/
|
||||
if (CritSectionCount > 0)
|
||||
elevel = PANIC;
|
||||
|
||||
/*
|
||||
* Check 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 (PG_exception_stack == NULL ||
|
||||
ExitOnAnyError ||
|
||||
proc_exit_inprogress)
|
||||
elevel = FATAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the error level is ERROR or more, errfinish is not going to
|
||||
* 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.
|
||||
*/
|
||||
for (i = 0; i <= errordata_stack_depth; i++)
|
||||
elevel = Max(elevel, errordata[i].elevel);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
if (IsPostmasterEnvironment)
|
||||
{
|
||||
@ -210,18 +244,14 @@ errstart(int elevel, const char *filename, int lineno,
|
||||
* 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
|
||||
* force level up to ERROR or greater, as discussed at top of
|
||||
* file. Adjust output decisions too.
|
||||
* Ooops, error during error processing. Clear ErrorContext as
|
||||
* discussed at top of file. We will not return to the original
|
||||
* error's reporter or handler, so we don't need it.
|
||||
*/
|
||||
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
|
||||
@ -300,74 +330,39 @@ errfinish(int dummy,...)
|
||||
(*econtext->callback) (econtext->arg);
|
||||
|
||||
/*
|
||||
* If the error level is ERROR or more, we are not going to 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)
|
||||
{
|
||||
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 ERROR (not more nor less) we pass it off to the current handler.
|
||||
* Printing it and popping the stack is the responsibility of
|
||||
* the handler.
|
||||
*/
|
||||
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
|
||||
* can execute in a reasonably sane state.
|
||||
*/
|
||||
/*
|
||||
* We do some minimal cleanup before longjmp'ing so that handlers
|
||||
* can execute in a reasonably sane state.
|
||||
*/
|
||||
|
||||
/* This is just in case the error came while waiting for input */
|
||||
ImmediateInterruptOK = false;
|
||||
/* This is just in case the error came while waiting for input */
|
||||
ImmediateInterruptOK = false;
|
||||
|
||||
/*
|
||||
* Reset InterruptHoldoffCount in case we ereport'd from
|
||||
* inside an interrupt holdoff section. (We assume here that
|
||||
* no handler will itself be inside a holdoff section. If
|
||||
* necessary, such a handler could save and restore
|
||||
* InterruptHoldoffCount for itself, but this should make life
|
||||
* easier for most.)
|
||||
*/
|
||||
InterruptHoldoffCount = 0;
|
||||
/*
|
||||
* Reset InterruptHoldoffCount in case we ereport'd from
|
||||
* inside an interrupt holdoff section. (We assume here that
|
||||
* no handler will itself be inside a holdoff section. If
|
||||
* necessary, such a handler could save and restore
|
||||
* InterruptHoldoffCount for itself, but this should make life
|
||||
* easier for most.)
|
||||
*/
|
||||
InterruptHoldoffCount = 0;
|
||||
|
||||
CritSectionCount = 0; /* should be unnecessary, but... */
|
||||
CritSectionCount = 0; /* should be unnecessary, but... */
|
||||
|
||||
/*
|
||||
* Note that we leave CurrentMemoryContext set to
|
||||
* ErrorContext. The handler should reset it to something else
|
||||
* soon.
|
||||
*/
|
||||
/*
|
||||
* Note that we leave CurrentMemoryContext set to ErrorContext.
|
||||
* The handler should reset it to something else soon.
|
||||
*/
|
||||
|
||||
recursion_depth--;
|
||||
PG_RE_THROW();
|
||||
}
|
||||
recursion_depth--;
|
||||
PG_RE_THROW();
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user