Commit 71a8a4f6 authored by Alvaro Herrera's avatar Alvaro Herrera

Add backtrace support for error reporting

Add some support for automatically showing backtraces in certain error
situations in the server.  Backtraces are shown on assertion failure;
also, a new setting backtrace_functions can be set to a list of C
function names, and all ereport()s and elog()s from the mentioned
functions will have backtraces generated.  Finally, the function
errbacktrace() can be manually added to an ereport() call to generate a
backtrace for that call.

Authors: Peter Eisentraut, Álvaro Herrera
Discussion: https://postgr.es/m//5f48cb47-bf1e-05b6-7aae-3bf2cd01586d@2ndquadrant.com
Discussion: https://postgr.es/m/CAMsr+YGL+yfWE=JvbUbnpWtrRZNey7hJ07+zT4bYJdVp4Szdrg@mail.gmail.com
parent 3dcffb38
...@@ -11607,6 +11607,63 @@ if test "$ac_res" != no; then : ...@@ -11607,6 +11607,63 @@ if test "$ac_res" != no; then :
fi fi
# *BSD:
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace_symbols" >&5
$as_echo_n "checking for library containing backtrace_symbols... " >&6; }
if ${ac_cv_search_backtrace_symbols+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char backtrace_symbols ();
int
main ()
{
return backtrace_symbols ();
;
return 0;
}
_ACEOF
for ac_lib in '' execinfo; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_backtrace_symbols=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_backtrace_symbols+:} false; then :
break
fi
done
if ${ac_cv_search_backtrace_symbols+:} false; then :
else
ac_cv_search_backtrace_symbols=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace_symbols" >&5
$as_echo "$ac_cv_search_backtrace_symbols" >&6; }
ac_res=$ac_cv_search_backtrace_symbols
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
if test "$with_readline" = yes; then if test "$with_readline" = yes; then
...@@ -12705,7 +12762,7 @@ $as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h ...@@ -12705,7 +12762,7 @@ $as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h
fi fi
for ac_header in atomic.h copyfile.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h mbarrier.h poll.h sys/epoll.h sys/ipc.h sys/prctl.h sys/procctl.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/sockio.h sys/tas.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h for ac_header in atomic.h copyfile.h execinfo.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h mbarrier.h poll.h sys/epoll.h sys/ipc.h sys/prctl.h sys/procctl.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/sockio.h sys/tas.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h
do : do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
...@@ -14935,7 +14992,7 @@ fi ...@@ -14935,7 +14992,7 @@ fi
LIBS_including_readline="$LIBS" LIBS_including_readline="$LIBS"
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
for ac_func in cbrt clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memset_s memmove poll posix_fallocate ppoll pstat pthread_is_threaded_np readlink setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range uselocale utime utimes wcstombs_l for ac_func in backtrace_symbols cbrt clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memset_s memmove poll posix_fallocate ppoll pstat pthread_is_threaded_np readlink setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range uselocale utime utimes wcstombs_l
do : do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
......
...@@ -1133,6 +1133,8 @@ AC_SEARCH_LIBS(sched_yield, rt) ...@@ -1133,6 +1133,8 @@ AC_SEARCH_LIBS(sched_yield, rt)
AC_SEARCH_LIBS(gethostbyname_r, nsl) AC_SEARCH_LIBS(gethostbyname_r, nsl)
# Cygwin: # Cygwin:
AC_SEARCH_LIBS(shmget, cygipc) AC_SEARCH_LIBS(shmget, cygipc)
# *BSD:
AC_SEARCH_LIBS(backtrace_symbols, execinfo)
if test "$with_readline" = yes; then if test "$with_readline" = yes; then
PGAC_CHECK_READLINE PGAC_CHECK_READLINE
...@@ -1275,6 +1277,7 @@ AC_HEADER_STDBOOL ...@@ -1275,6 +1277,7 @@ AC_HEADER_STDBOOL
AC_CHECK_HEADERS(m4_normalize([ AC_CHECK_HEADERS(m4_normalize([
atomic.h atomic.h
copyfile.h copyfile.h
execinfo.h
fp_class.h fp_class.h
getopt.h getopt.h
ieeefp.h ieeefp.h
...@@ -1608,6 +1611,7 @@ LIBS_including_readline="$LIBS" ...@@ -1608,6 +1611,7 @@ LIBS_including_readline="$LIBS"
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
AC_CHECK_FUNCS(m4_normalize([ AC_CHECK_FUNCS(m4_normalize([
backtrace_symbols
cbrt cbrt
clock_gettime clock_gettime
copyfile copyfile
......
...@@ -9489,6 +9489,32 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' ...@@ -9489,6 +9489,32 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry id="guc-backtrace-functions" xreflabel="backtrace_functions">
<term><varname>backtrace_functions</varname> (<type>string</type>)
<indexterm>
<primary><varname>backtrace_functions</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
This parameter contains a comma-separated list of C function names.
If an error is raised and the name of the internal C function where
the error happens matches a value in the list, then a backtrace is
written to the server log together with the error message. This can
be used to debug specific areas of the source code.
</para>
<para>
Backtrace support is not available on all platforms, and the quality
of the backtraces depends on compilation options.
</para>
<para>
This parameter can only be set by superusers.
</para>
</listitem>
</varlistentry>
<varlistentry id="guc-ignore-system-indexes" xreflabel="ignore_system_indexes"> <varlistentry id="guc-ignore-system-indexes" xreflabel="ignore_system_indexes">
<term><varname>ignore_system_indexes</varname> (<type>boolean</type>) <term><varname>ignore_system_indexes</varname> (<type>boolean</type>)
<indexterm> <indexterm>
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
#include "postgres.h" #include "postgres.h"
#include <unistd.h> #include <unistd.h>
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif
/* /*
* ExceptionalCondition - Handles the failure of an Assert() * ExceptionalCondition - Handles the failure of an Assert()
...@@ -42,6 +45,16 @@ ExceptionalCondition(const char *conditionName, ...@@ -42,6 +45,16 @@ ExceptionalCondition(const char *conditionName,
/* Usually this shouldn't be needed, but make sure the msg went out */ /* Usually this shouldn't be needed, but make sure the msg went out */
fflush(stderr); fflush(stderr);
#ifdef HAVE_BACKTRACE_SYMBOLS
{
void *buf[100];
int nframes;
nframes = backtrace(buf, lengthof(buf));
backtrace_symbols_fd(buf, nframes, fileno(stderr));
}
#endif
#ifdef SLEEP_ON_ASSERT #ifdef SLEEP_ON_ASSERT
/* /*
......
...@@ -62,6 +62,9 @@ ...@@ -62,6 +62,9 @@
#ifdef HAVE_SYSLOG #ifdef HAVE_SYSLOG
#include <syslog.h> #include <syslog.h>
#endif #endif
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif
#include "access/transam.h" #include "access/transam.h"
#include "access/xact.h" #include "access/xact.h"
...@@ -167,6 +170,7 @@ static char formatted_log_time[FORMATTED_TS_LEN]; ...@@ -167,6 +170,7 @@ static char formatted_log_time[FORMATTED_TS_LEN];
static const char *err_gettext(const char *str) pg_attribute_format_arg(1); static const char *err_gettext(const char *str) pg_attribute_format_arg(1);
static pg_noinline void set_backtrace(ErrorData *edata, int num_skip);
static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str); static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str);
static void write_console(const char *line, int len); static void write_console(const char *line, int len);
static void setup_formatted_log_time(void); static void setup_formatted_log_time(void);
...@@ -398,6 +402,32 @@ errstart(int elevel, const char *filename, int lineno, ...@@ -398,6 +402,32 @@ errstart(int elevel, const char *filename, int lineno,
return true; return true;
} }
/*
* Checks whether the given funcname matches backtrace_functions; see
* check_backtrace_functions.
*/
static bool
matches_backtrace_functions(const char *funcname)
{
char *p;
if (!backtrace_symbol_list || funcname == NULL || funcname[0] == '\0')
return false;
p = backtrace_symbol_list;
for (;;)
{
if (*p == '\0') /* end of backtrace_symbol_list */
break;
if (strcmp(funcname, p) == 0)
return true;
p += strlen(p) + 1;
}
return false;
}
/* /*
* errfinish --- end an error-reporting cycle * errfinish --- end an error-reporting cycle
* *
...@@ -424,6 +454,12 @@ errfinish(int dummy,...) ...@@ -424,6 +454,12 @@ errfinish(int dummy,...)
*/ */
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
if (!edata->backtrace &&
edata->funcname &&
backtrace_functions &&
matches_backtrace_functions(edata->funcname))
set_backtrace(edata, 2);
/* /*
* Call any context callback functions. Errors occurring in callback * Call any context callback functions. Errors occurring in callback
* functions will be treated as recursive errors --- this ensures we will * functions will be treated as recursive errors --- this ensures we will
...@@ -488,6 +524,8 @@ errfinish(int dummy,...) ...@@ -488,6 +524,8 @@ errfinish(int dummy,...)
pfree(edata->hint); pfree(edata->hint);
if (edata->context) if (edata->context)
pfree(edata->context); pfree(edata->context);
if (edata->backtrace)
pfree(edata->backtrace);
if (edata->schema_name) if (edata->schema_name)
pfree(edata->schema_name); pfree(edata->schema_name);
if (edata->table_name) if (edata->table_name)
...@@ -798,6 +836,65 @@ errmsg(const char *fmt,...) ...@@ -798,6 +836,65 @@ errmsg(const char *fmt,...)
return 0; /* return value does not matter */ return 0; /* return value does not matter */
} }
/*
* Add a backtrace to the containing ereport() call. This is intended to be
* added temporarily during debugging.
*/
int
errbacktrace(void)
{
ErrorData *edata = &errordata[errordata_stack_depth];
MemoryContext oldcontext;
Assert(false);
recursion_depth++;
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(edata->assoc_context);
set_backtrace(edata, 1);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
return 0;
}
/*
* Compute backtrace data and add it to the supplied ErrorData. num_skip
* specifies how many inner frames to skip. Use this to avoid showing the
* internal backtrace support functions in the backtrace. This requires that
* this and related functions are not inlined.
*/
static void
set_backtrace(ErrorData *edata, int num_skip)
{
StringInfoData errtrace;
initStringInfo(&errtrace);
#ifdef HAVE_BACKTRACE_SYMBOLS
{
void *buf[100];
int nframes;
char **strfrms;
nframes = backtrace(buf, lengthof(buf));
strfrms = backtrace_symbols(buf, nframes);
if (strfrms == NULL)
return;
for (int i = num_skip; i < nframes; i++)
appendStringInfo(&errtrace, "\n%s", strfrms[i]);
free(strfrms);
}
#else
appendStringInfoString(&errtrace,
"backtrace generation is not supported by this installation");
#endif
edata->backtrace = errtrace.data;
}
/* /*
* errmsg_internal --- add a primary error message text to the current error * errmsg_internal --- add a primary error message text to the current error
...@@ -1353,6 +1450,11 @@ elog_finish(int elevel, const char *fmt,...) ...@@ -1353,6 +1450,11 @@ elog_finish(int elevel, const char *fmt,...)
recursion_depth++; recursion_depth++;
oldcontext = MemoryContextSwitchTo(edata->assoc_context); oldcontext = MemoryContextSwitchTo(edata->assoc_context);
if (!edata->backtrace &&
edata->funcname &&
matches_backtrace_functions(edata->funcname))
set_backtrace(edata, 2);
edata->message_id = fmt; edata->message_id = fmt;
EVALUATE_MESSAGE(edata->domain, message, false, false); EVALUATE_MESSAGE(edata->domain, message, false, false);
...@@ -1509,6 +1611,8 @@ CopyErrorData(void) ...@@ -1509,6 +1611,8 @@ CopyErrorData(void)
newedata->hint = pstrdup(newedata->hint); newedata->hint = pstrdup(newedata->hint);
if (newedata->context) if (newedata->context)
newedata->context = pstrdup(newedata->context); newedata->context = pstrdup(newedata->context);
if (newedata->backtrace)
newedata->backtrace = pstrdup(newedata->backtrace);
if (newedata->schema_name) if (newedata->schema_name)
newedata->schema_name = pstrdup(newedata->schema_name); newedata->schema_name = pstrdup(newedata->schema_name);
if (newedata->table_name) if (newedata->table_name)
...@@ -1547,6 +1651,8 @@ FreeErrorData(ErrorData *edata) ...@@ -1547,6 +1651,8 @@ FreeErrorData(ErrorData *edata)
pfree(edata->hint); pfree(edata->hint);
if (edata->context) if (edata->context)
pfree(edata->context); pfree(edata->context);
if (edata->backtrace)
pfree(edata->backtrace);
if (edata->schema_name) if (edata->schema_name)
pfree(edata->schema_name); pfree(edata->schema_name);
if (edata->table_name) if (edata->table_name)
...@@ -1622,6 +1728,8 @@ ThrowErrorData(ErrorData *edata) ...@@ -1622,6 +1728,8 @@ ThrowErrorData(ErrorData *edata)
newedata->hint = pstrdup(edata->hint); newedata->hint = pstrdup(edata->hint);
if (edata->context) if (edata->context)
newedata->context = pstrdup(edata->context); newedata->context = pstrdup(edata->context);
if (edata->backtrace)
newedata->backtrace = pstrdup(edata->backtrace);
/* assume message_id is not available */ /* assume message_id is not available */
if (edata->schema_name) if (edata->schema_name)
newedata->schema_name = pstrdup(edata->schema_name); newedata->schema_name = pstrdup(edata->schema_name);
...@@ -1689,6 +1797,8 @@ ReThrowError(ErrorData *edata) ...@@ -1689,6 +1797,8 @@ ReThrowError(ErrorData *edata)
newedata->hint = pstrdup(newedata->hint); newedata->hint = pstrdup(newedata->hint);
if (newedata->context) if (newedata->context)
newedata->context = pstrdup(newedata->context); newedata->context = pstrdup(newedata->context);
if (newedata->backtrace)
newedata->backtrace = pstrdup(newedata->backtrace);
if (newedata->schema_name) if (newedata->schema_name)
newedata->schema_name = pstrdup(newedata->schema_name); newedata->schema_name = pstrdup(newedata->schema_name);
if (newedata->table_name) if (newedata->table_name)
...@@ -2914,6 +3024,13 @@ send_message_to_server_log(ErrorData *edata) ...@@ -2914,6 +3024,13 @@ send_message_to_server_log(ErrorData *edata)
append_with_tabs(&buf, edata->context); append_with_tabs(&buf, edata->context);
appendStringInfoChar(&buf, '\n'); appendStringInfoChar(&buf, '\n');
} }
if (edata->backtrace)
{
log_line_prefix(&buf, edata);
appendStringInfoString(&buf, _("BACKTRACE: "));
append_with_tabs(&buf, edata->backtrace);
appendStringInfoChar(&buf, '\n');
}
if (Log_error_verbosity >= PGERROR_VERBOSE) if (Log_error_verbosity >= PGERROR_VERBOSE)
{ {
/* assume no newlines in funcname or filename... */ /* assume no newlines in funcname or filename... */
......
...@@ -201,6 +201,8 @@ static bool check_cluster_name(char **newval, void **extra, GucSource source); ...@@ -201,6 +201,8 @@ static bool check_cluster_name(char **newval, void **extra, GucSource source);
static const char *show_unix_socket_permissions(void); static const char *show_unix_socket_permissions(void);
static const char *show_log_file_mode(void); static const char *show_log_file_mode(void);
static const char *show_data_directory_mode(void); static const char *show_data_directory_mode(void);
static bool check_backtrace_functions(char **newval, void **extra, GucSource source);
static void assign_backtrace_functions(const char *newval, void *extra);
static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source); static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
static void assign_recovery_target_timeline(const char *newval, void *extra); static void assign_recovery_target_timeline(const char *newval, void *extra);
static bool check_recovery_target(char **newval, void **extra, GucSource source); static bool check_recovery_target(char **newval, void **extra, GucSource source);
...@@ -515,6 +517,8 @@ int log_temp_files = -1; ...@@ -515,6 +517,8 @@ int log_temp_files = -1;
double log_statement_sample_rate = 1.0; double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0; double log_xact_sample_rate = 0;
int trace_recovery_messages = LOG; int trace_recovery_messages = LOG;
char *backtrace_functions;
char *backtrace_symbol_list;
int temp_file_limit = -1; int temp_file_limit = -1;
...@@ -4224,6 +4228,17 @@ static struct config_string ConfigureNamesString[] = ...@@ -4224,6 +4228,17 @@ static struct config_string ConfigureNamesString[] =
NULL, NULL, NULL NULL, NULL, NULL
}, },
{
{"backtrace_functions", PGC_SUSET, DEVELOPER_OPTIONS,
gettext_noop("Log backtrace for errors in these functions."),
NULL,
GUC_NOT_IN_SAMPLE
},
&backtrace_functions,
"",
check_backtrace_functions, assign_backtrace_functions, NULL
},
/* End-of-list marker */ /* End-of-list marker */
{ {
{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL
...@@ -11487,6 +11502,76 @@ show_data_directory_mode(void) ...@@ -11487,6 +11502,76 @@ show_data_directory_mode(void)
return buf; return buf;
} }
/*
* We split the input string, where commas separate function names
* and certain whitespace chars are ignored, into a \0-separated (and
* \0\0-terminated) list of function names. This formulation allows
* easy scanning when an error is thrown while avoiding the use of
* non-reentrant strtok(), as well as keeping the output data in a
* single palloc() chunk.
*/
static bool
check_backtrace_functions(char **newval, void **extra, GucSource source)
{
int newvallen = strlen(*newval);
char *someval;
int validlen;
int i;
int j;
/*
* Allow characters that can be C identifiers and commas as separators, as
* well as some whitespace for readability.
*/
validlen = strspn(*newval,
"0123456789_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
", \n\t");
if (validlen != newvallen)
{
GUC_check_errdetail("invalid character");
return false;
}
if (*newval[0] == '\0')
{
*extra = NULL;
return true;
}
/*
* Allocate space for the output and create the copy. We could discount
* whitespace chars to save some memory, but it doesn't seem worth the
* trouble.
*/
someval = guc_malloc(ERROR, newvallen + 1 + 1);
for (i = 0, j = 0; i < newvallen; i++)
{
if ((*newval)[i] == ',')
someval[j++] = '\0'; /* next item */
else if ((*newval)[i] == ' ' ||
(*newval)[i] == '\n' ||
(*newval)[i] == '\t')
; /* ignore these */
else
someval[j++] = (*newval)[i]; /* copy anything else */
}
/* two \0s end the setting */
someval[j] = '\0';
someval[j + 1] = '\0';
*extra = someval;
return true;
}
static void
assign_backtrace_functions(const char *newval, void *extra)
{
backtrace_symbol_list = (char *) extra;
}
static bool static bool
check_recovery_target_timeline(char **newval, void **extra, GucSource source) check_recovery_target_timeline(char **newval, void **extra, GucSource source)
{ {
......
...@@ -96,6 +96,9 @@ ...@@ -96,6 +96,9 @@
/* Define to 1 if you have the <atomic.h> header file. */ /* Define to 1 if you have the <atomic.h> header file. */
#undef HAVE_ATOMIC_H #undef HAVE_ATOMIC_H
/* Define to 1 if you have the `backtrace_symbols' function. */
#undef HAVE_BACKTRACE_SYMBOLS
/* Define to 1 if you have the `BIO_get_data' function. */ /* Define to 1 if you have the `BIO_get_data' function. */
#undef HAVE_BIO_GET_DATA #undef HAVE_BIO_GET_DATA
...@@ -198,6 +201,9 @@ ...@@ -198,6 +201,9 @@
/* Define to 1 if you have the `explicit_bzero' function. */ /* Define to 1 if you have the `explicit_bzero' function. */
#undef HAVE_EXPLICIT_BZERO #undef HAVE_EXPLICIT_BZERO
/* Define to 1 if you have the <execinfo.h> header file. */
#undef HAVE_EXECINFO_H
/* Define to 1 if you have the `fdatasync' function. */ /* Define to 1 if you have the `fdatasync' function. */
#undef HAVE_FDATASYNC #undef HAVE_FDATASYNC
......
...@@ -189,6 +189,8 @@ extern int errcontext_msg(const char *fmt,...) pg_attribute_printf(1, 2); ...@@ -189,6 +189,8 @@ extern int errcontext_msg(const char *fmt,...) pg_attribute_printf(1, 2);
extern int errhidestmt(bool hide_stmt); extern int errhidestmt(bool hide_stmt);
extern int errhidecontext(bool hide_ctx); extern int errhidecontext(bool hide_ctx);
extern int errbacktrace(void);
extern int errfunction(const char *funcname); extern int errfunction(const char *funcname);
extern int errposition(int cursorpos); extern int errposition(int cursorpos);
...@@ -392,6 +394,7 @@ typedef struct ErrorData ...@@ -392,6 +394,7 @@ typedef struct ErrorData
char *detail_log; /* detail error message for server log only */ char *detail_log; /* detail error message for server log only */
char *hint; /* hint message */ char *hint; /* hint message */
char *context; /* context message */ char *context; /* context message */
char *backtrace; /* backtrace */
const char *message_id; /* primary message's id (original string) */ const char *message_id; /* primary message's id (original string) */
char *schema_name; /* name of schema */ char *schema_name; /* name of schema */
char *table_name; /* name of table */ char *table_name; /* name of table */
......
...@@ -256,6 +256,8 @@ extern int log_min_duration_statement; ...@@ -256,6 +256,8 @@ extern int log_min_duration_statement;
extern int log_temp_files; extern int log_temp_files;
extern double log_statement_sample_rate; extern double log_statement_sample_rate;
extern double log_xact_sample_rate; extern double log_xact_sample_rate;
extern char *backtrace_functions;
extern char *backtrace_symbol_list;
extern int temp_file_limit; extern int temp_file_limit;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment