@@ -87,7 +87,7 @@ err_gettext(const char *str)
8787/* This extension allows gcc to check the format string for consistency with
8888 the supplied arguments. */
8989__attribute__((format_arg (1 )));
90- static void set_errdata_field (char * * ptr , const char * str );
90+ static void set_errdata_field (MemoryContextData * cxt , char * * ptr , const char * str );
9191
9292/* Global variables */
9393ErrorContextCallback * error_context_stack = NULL ;
@@ -373,6 +373,11 @@ errstart(int elevel, const char *filename, int lineno,
373373 /* errno is saved here so that error parameter eval can't change it */
374374 edata -> saved_errno = errno ;
375375
376+ /*
377+ * Any allocations for this error state level should go into ErrorContext
378+ */
379+ edata -> assoc_context = ErrorContext ;
380+
376381 recursion_depth -- ;
377382 return true;
378383}
@@ -786,7 +791,7 @@ errmsg(const char *fmt,...)
786791
787792 recursion_depth ++ ;
788793 CHECK_STACK_DEPTH ();
789- oldcontext = MemoryContextSwitchTo (ErrorContext );
794+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
790795
791796 EVALUATE_MESSAGE (edata -> domain , message , false, true);
792797
@@ -815,7 +820,7 @@ errmsg_internal(const char *fmt,...)
815820
816821 recursion_depth ++ ;
817822 CHECK_STACK_DEPTH ();
818- oldcontext = MemoryContextSwitchTo (ErrorContext );
823+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
819824
820825 EVALUATE_MESSAGE (edata -> domain , message , false, false);
821826
@@ -838,7 +843,7 @@ errmsg_plural(const char *fmt_singular, const char *fmt_plural,
838843
839844 recursion_depth ++ ;
840845 CHECK_STACK_DEPTH ();
841- oldcontext = MemoryContextSwitchTo (ErrorContext );
846+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
842847
843848 EVALUATE_MESSAGE_PLURAL (edata -> domain , message , false);
844849
@@ -859,7 +864,7 @@ errdetail(const char *fmt,...)
859864
860865 recursion_depth ++ ;
861866 CHECK_STACK_DEPTH ();
862- oldcontext = MemoryContextSwitchTo (ErrorContext );
867+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
863868
864869 EVALUATE_MESSAGE (edata -> domain , detail , false, true);
865870
@@ -886,7 +891,7 @@ errdetail_internal(const char *fmt,...)
886891
887892 recursion_depth ++ ;
888893 CHECK_STACK_DEPTH ();
889- oldcontext = MemoryContextSwitchTo (ErrorContext );
894+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
890895
891896 EVALUATE_MESSAGE (edata -> domain , detail , false, false);
892897
@@ -907,7 +912,7 @@ errdetail_log(const char *fmt,...)
907912
908913 recursion_depth ++ ;
909914 CHECK_STACK_DEPTH ();
910- oldcontext = MemoryContextSwitchTo (ErrorContext );
915+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
911916
912917 EVALUATE_MESSAGE (edata -> domain , detail_log , false, true);
913918
@@ -930,7 +935,7 @@ errdetail_plural(const char *fmt_singular, const char *fmt_plural,
930935
931936 recursion_depth ++ ;
932937 CHECK_STACK_DEPTH ();
933- oldcontext = MemoryContextSwitchTo (ErrorContext );
938+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
934939
935940 EVALUATE_MESSAGE_PLURAL (edata -> domain , detail , false);
936941
@@ -951,7 +956,7 @@ errhint(const char *fmt,...)
951956
952957 recursion_depth ++ ;
953958 CHECK_STACK_DEPTH ();
954- oldcontext = MemoryContextSwitchTo (ErrorContext );
959+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
955960
956961 EVALUATE_MESSAGE (edata -> domain , hint , false, true);
957962
@@ -976,7 +981,7 @@ errcontext_msg(const char *fmt,...)
976981
977982 recursion_depth ++ ;
978983 CHECK_STACK_DEPTH ();
979- oldcontext = MemoryContextSwitchTo (ErrorContext );
984+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
980985
981986 EVALUATE_MESSAGE (edata -> context_domain , context , true, true);
982987
@@ -1102,7 +1107,7 @@ internalerrquery(const char *query)
11021107 }
11031108
11041109 if (query )
1105- edata -> internalquery = MemoryContextStrdup (ErrorContext , query );
1110+ edata -> internalquery = MemoryContextStrdup (edata -> assoc_context , query );
11061111
11071112 return 0 ; /* return value does not matter */
11081113}
@@ -1128,19 +1133,19 @@ err_generic_string(int field, const char *str)
11281133 switch (field )
11291134 {
11301135 case PG_DIAG_SCHEMA_NAME :
1131- set_errdata_field (& edata -> schema_name , str );
1136+ set_errdata_field (edata -> assoc_context , & edata -> schema_name , str );
11321137 break ;
11331138 case PG_DIAG_TABLE_NAME :
1134- set_errdata_field (& edata -> table_name , str );
1139+ set_errdata_field (edata -> assoc_context , & edata -> table_name , str );
11351140 break ;
11361141 case PG_DIAG_COLUMN_NAME :
1137- set_errdata_field (& edata -> column_name , str );
1142+ set_errdata_field (edata -> assoc_context , & edata -> column_name , str );
11381143 break ;
11391144 case PG_DIAG_DATATYPE_NAME :
1140- set_errdata_field (& edata -> datatype_name , str );
1145+ set_errdata_field (edata -> assoc_context , & edata -> datatype_name , str );
11411146 break ;
11421147 case PG_DIAG_CONSTRAINT_NAME :
1143- set_errdata_field (& edata -> constraint_name , str );
1148+ set_errdata_field (edata -> assoc_context , & edata -> constraint_name , str );
11441149 break ;
11451150 default :
11461151 elog (ERROR , "unsupported ErrorData field id: %d" , field );
@@ -1154,10 +1159,10 @@ err_generic_string(int field, const char *str)
11541159 * set_errdata_field --- set an ErrorData string field
11551160 */
11561161static void
1157- set_errdata_field (char * * ptr , const char * str )
1162+ set_errdata_field (MemoryContextData * cxt , char * * ptr , const char * str )
11581163{
11591164 Assert (* ptr == NULL );
1160- * ptr = MemoryContextStrdup (ErrorContext , str );
1165+ * ptr = MemoryContextStrdup (cxt , str );
11611166}
11621167
11631168/*
@@ -1257,6 +1262,9 @@ elog_start(const char *filename, int lineno, const char *funcname)
12571262 edata -> funcname = funcname ;
12581263 /* errno is saved now so that error parameter eval can't change it */
12591264 edata -> saved_errno = errno ;
1265+
1266+ /* Use ErrorContext for any allocations done at this level. */
1267+ edata -> assoc_context = ErrorContext ;
12601268}
12611269
12621270/*
@@ -1282,7 +1290,7 @@ elog_finish(int elevel, const char *fmt,...)
12821290 * Format error message just like errmsg_internal().
12831291 */
12841292 recursion_depth ++ ;
1285- oldcontext = MemoryContextSwitchTo (ErrorContext );
1293+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
12861294
12871295 EVALUATE_MESSAGE (edata -> domain , message , false, false);
12881296
@@ -1366,7 +1374,7 @@ EmitErrorReport(void)
13661374
13671375 recursion_depth ++ ;
13681376 CHECK_STACK_DEPTH ();
1369- oldcontext = MemoryContextSwitchTo (ErrorContext );
1377+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
13701378
13711379 /*
13721380 * Call hook before sending message to log. The hook function is allowed
@@ -1446,6 +1454,9 @@ CopyErrorData(void)
14461454 if (newedata -> internalquery )
14471455 newedata -> internalquery = pstrdup (newedata -> internalquery );
14481456
1457+ /* Use the calling context for string allocation */
1458+ newedata -> assoc_context = CurrentMemoryContext ;
1459+
14491460 return newedata ;
14501461}
14511462
@@ -1563,6 +1574,9 @@ ReThrowError(ErrorData *edata)
15631574 if (newedata -> internalquery )
15641575 newedata -> internalquery = pstrdup (newedata -> internalquery );
15651576
1577+ /* Reset the assoc_context to be ErrorContext */
1578+ newedata -> assoc_context = ErrorContext ;
1579+
15661580 recursion_depth -- ;
15671581 PG_RE_THROW ();
15681582}
@@ -1630,12 +1644,8 @@ pg_re_throw(void)
16301644 * GetErrorContextStack - Return the context stack, for display/diags
16311645 *
16321646 * Returns a pstrdup'd string in the caller's context which includes the PG
1633- * call stack. It is the caller's responsibility to ensure this string is
1634- * pfree'd (or its context cleaned up) when done.
1635- *
1636- * Note that this function may *not* be called from any existing error case
1637- * and is not for error-reporting (use ereport() and friends instead, which
1638- * will also produce a stack trace).
1647+ * error call stack. It is the caller's responsibility to ensure this string
1648+ * is pfree'd (or its context cleaned up) when done.
16391649 *
16401650 * This information is collected by traversing the error contexts and calling
16411651 * each context's callback function, each of which is expected to call
@@ -1644,78 +1654,64 @@ pg_re_throw(void)
16441654char *
16451655GetErrorContextStack (void )
16461656{
1647- char * result = NULL ;
16481657 ErrorData * edata ;
16491658 ErrorContextCallback * econtext ;
1650- MemoryContext oldcontext = CurrentMemoryContext ;
1651-
1652- /* this function should not be called from an exception handler */
1653- Assert (recursion_depth == 0 );
16541659
16551660 /*
1656- * This function should never be called from an exception handler and
1657- * therefore will only ever be the top item on the errordata stack
1658- * (which is set up so that the calls to the callback functions are
1659- * able to use it).
1660- *
1661- * Better safe than sorry, so double-check that we are not being called
1662- * from an exception handler.
1661+ * Okay, crank up a stack entry to store the info in.
16631662 */
1664- if (errordata_stack_depth != -1 )
1663+ recursion_depth ++ ;
1664+
1665+ if (++ errordata_stack_depth >= ERRORDATA_STACK_SIZE )
16651666 {
1667+ /*
1668+ * Wups, stack not big enough. We treat this as a PANIC condition
1669+ * because it suggests an infinite loop of errors during error
1670+ * recovery.
1671+ */
16661672 errordata_stack_depth = -1 ; /* make room on stack */
1667- ereport (PANIC ,
1668- (errmsg_internal ("GetErrorContextStack called from exception handler" )));
1673+ ereport (PANIC , (errmsg_internal ("ERRORDATA_STACK_SIZE exceeded" )));
16691674 }
16701675
16711676 /*
1672- * Initialize data for the top, and only at this point, error frame as the
1673- * callback functions we're about to call will turn around and call
1674- * errcontext(), which expects to find a valid errordata stack.
1677+ * Things look good so far, so initialize our error frame
16751678 */
1676- errordata_stack_depth = 0 ;
16771679 edata = & errordata [errordata_stack_depth ];
16781680 MemSet (edata , 0 , sizeof (ErrorData ));
16791681
16801682 /*
1681- * Use ErrorContext as a short lived context for calling the callbacks;
1682- * the callbacks will use it through errcontext() even if we don't call
1683- * them with it, so we have to clean it up below either way.
1683+ * Set up assoc_context to be the caller's context, so any allocations
1684+ * done (which will include edata->context) will use their context.
16841685 */
1685- MemoryContextSwitchTo ( ErrorContext ) ;
1686+ edata -> assoc_context = CurrentMemoryContext ;
16861687
16871688 /*
16881689 * Call any context callback functions to collect the context information
16891690 * into edata->context.
16901691 *
16911692 * Errors occurring in callback functions should go through the regular
1692- * error handling code which should handle any recursive errors and must
1693- * never call back to us .
1693+ * error handling code which should handle any recursive errors, though
1694+ * we double-check above, just in case .
16941695 */
16951696 for (econtext = error_context_stack ;
16961697 econtext != NULL ;
16971698 econtext = econtext -> previous )
16981699 (* econtext -> callback ) (econtext -> arg );
16991700
1700- MemoryContextSwitchTo (oldcontext );
1701-
17021701 /*
1703- * Copy out the string into the caller's context, so we can free our
1704- * error context and reset the error stack. Caller is expected to
1705- * pfree() the result or throw away the context.
1702+ * Clean ourselves off the stack, any allocations done should have been
1703+ * using edata->assoc_context, which we set up earlier to be the caller's
1704+ * context, so we're free to just remove our entry off the stack and
1705+ * decrement recursion depth and exit.
17061706 */
1707- if ( edata -> context )
1708- result = pstrdup ( edata -> context ) ;
1707+ errordata_stack_depth -- ;
1708+ recursion_depth -- ;
17091709
17101710 /*
1711- * Reset error stack- note that we should be the only item on the error
1712- * stack at this point and therefore it's safe to clean up the whole stack.
1713- * This function is not intended nor able to be called from exception
1714- * handlers.
1711+ * Return a pointer to the string the caller asked for, which should have
1712+ * been allocated in their context.
17151713 */
1716- FlushErrorState ();
1717-
1718- return result ;
1714+ return edata -> context ;
17191715}
17201716
17211717
0 commit comments