]> granicus.if.org Git - postgresql/commitdiff
Fix oversight in PG_RE_THROW processing: it's entirely possible that there
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 2 May 2007 15:32:42 +0000 (15:32 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 2 May 2007 15:32:42 +0000 (15:32 +0000)
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.

src/backend/utils/error/elog.c
src/include/utils/elog.h

index c76d817bb1464c122a99696ea5853867e6622406..d74442ee54b3ce368b76c8f765150f856fc9ae64 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1099,6 +1099,61 @@ ReThrowError(ErrorData *edata)
        PG_RE_THROW();
 }
 
+/*
+ * 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
  */
index 86fd4deb9eab74a5a5481ca3a0decd6d122784f4..e84d67345f9cf03e4249e2fa930d4b4ce7a48120 100644 (file)
@@ -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 */