mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-10-01 05:31:15 +02: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
|
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
if (elevel >= ERROR)
|
if (elevel >= ERROR)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* If we are inside a critical section, all errors become PANIC
|
||||||
|
* errors. See miscadmin.h.
|
||||||
|
*/
|
||||||
if (CritSectionCount > 0)
|
if (CritSectionCount > 0)
|
||||||
elevel = PANIC;
|
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 */
|
/* 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,
|
|||||||
* 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,74 +330,39 @@ 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 ||
|
* We do some minimal cleanup before longjmp'ing so that handlers
|
||||||
proc_exit_inprogress)
|
* can execute in a reasonably sane state.
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* This is just in case the error came while waiting for input */
|
/* This is just in case the error came while waiting for input */
|
||||||
ImmediateInterruptOK = false;
|
ImmediateInterruptOK = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset InterruptHoldoffCount in case we ereport'd from
|
* Reset InterruptHoldoffCount in case we ereport'd from
|
||||||
* inside an interrupt holdoff section. (We assume here that
|
* inside an interrupt holdoff section. (We assume here that
|
||||||
* no handler will itself be inside a holdoff section. If
|
* no handler will itself be inside a holdoff section. If
|
||||||
* necessary, such a handler could save and restore
|
* necessary, such a handler could save and restore
|
||||||
* InterruptHoldoffCount for itself, but this should make life
|
* InterruptHoldoffCount for itself, but this should make life
|
||||||
* easier for most.)
|
* easier for most.)
|
||||||
*/
|
*/
|
||||||
InterruptHoldoffCount = 0;
|
InterruptHoldoffCount = 0;
|
||||||
|
|
||||||
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();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user