aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-05-02 15:32:42 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-05-02 15:32:42 +0000
commit88f1fd29897df477f0af3c5ffcefe53c697a6ff3 (patch)
treee279b7a47d27c209a2c2019c3b3069a346a49483
parentd6013a34f29777254eb5e285a3468960f449de50 (diff)
downloadpostgresql-88f1fd29897df477f0af3c5ffcefe53c697a6ff3.tar.gz
postgresql-88f1fd29897df477f0af3c5ffcefe53c697a6ff3.zip
Fix oversight in PG_RE_THROW processing: it's entirely possible that there
isn't any place to throw the error to. If so, we should treat the error as FATAL, just as we would have if it'd been thrown outside the PG_TRY block to begin with. Although this is clearly a *potential* source of bugs, it is not clear at the moment whether it is an *actual* source of bugs; there may not presently be any PG_TRY blocks in code that can be reached with no outer longjmp catcher. So for the moment I'm going to be conservative and not back-patch this. The change breaks ABI for users of PG_RE_THROW and hence might create compatibility problems for loadable modules, so we should not put it into released branches without proof that it's needed.
-rw-r--r--src/backend/utils/error/elog.c57
-rw-r--r--src/include/utils/elog.h5
2 files changed, 59 insertions, 3 deletions
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index c76d817bb14..d74442ee54b 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -42,7 +42,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.183 2007/03/02 23:37:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.184 2007/05/02 15:32:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1100,6 +1100,61 @@ ReThrowError(ErrorData *edata)
}
/*
+ * pg_re_throw --- out-of-line implementation of PG_RE_THROW() macro
+ */
+void
+pg_re_throw(void)
+{
+ /* If possible, throw the error to the next outer setjmp handler */
+ if (PG_exception_stack != NULL)
+ siglongjmp(*PG_exception_stack, 1);
+ else
+ {
+ /*
+ * If we get here, elog(ERROR) was thrown inside a PG_TRY block, which
+ * we have now exited only to discover that there is no outer setjmp
+ * handler to pass the error to. Had the error been thrown outside the
+ * block to begin with, we'd have promoted the error to FATAL, so the
+ * correct behavior is to make it FATAL now; that is, emit it and then
+ * call proc_exit.
+ */
+ ErrorData *edata = &errordata[errordata_stack_depth];
+
+ Assert(errordata_stack_depth >= 0);
+ Assert(edata->elevel == ERROR);
+ edata->elevel = FATAL;
+
+ /*
+ * At least in principle, the increase in severity could have changed
+ * where-to-output decisions, so recalculate. This should stay in
+ * sync with errstart(), which see for comments.
+ */
+ if (IsPostmasterEnvironment)
+ edata->output_to_server = is_log_level_output(FATAL,
+ log_min_messages);
+ else
+ edata->output_to_server = (FATAL >= log_min_messages);
+ if (whereToSendOutput == DestRemote)
+ {
+ if (ClientAuthInProgress)
+ edata->output_to_client = true;
+ else
+ edata->output_to_client = (FATAL >= client_min_messages);
+ }
+
+ /*
+ * We can use errfinish() for the rest, but we don't want it to call
+ * any error context routines a second time. Since we know we are
+ * about to exit, it should be OK to just clear the context stack.
+ */
+ error_context_stack = NULL;
+
+ errfinish(0);
+ }
+}
+
+
+/*
* Initialization of error output file
*/
void
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 86fd4deb9ea..e84d67345f9 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.84 2007/03/02 23:37:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.85 2007/05/02 15:32:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -223,7 +223,7 @@ extern DLLIMPORT ErrorContextCallback *error_context_stack;
} while (0)
#define PG_RE_THROW() \
- siglongjmp(*PG_exception_stack, 1)
+ pg_re_throw()
extern DLLIMPORT sigjmp_buf *PG_exception_stack;
@@ -262,6 +262,7 @@ extern ErrorData *CopyErrorData(void);
extern void FreeErrorData(ErrorData *edata);
extern void FlushErrorState(void);
extern void ReThrowError(ErrorData *edata);
+extern void pg_re_throw(void);
/* GUC-configurable parameters */