summaryrefslogtreecommitdiff
path: root/src/backend/utils/misc/guc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/misc/guc.c')
-rw-r--r--src/backend/utils/misc/guc.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index e84c8cc4cfc..994bf37477a 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -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_log_file_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 void assign_recovery_target_timeline(const char *newval, void *extra);
static bool check_recovery_target(char **newval, void **extra, GucSource source);
@@ -515,6 +517,8 @@ int log_temp_files = -1;
double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
int trace_recovery_messages = LOG;
+char *backtrace_functions;
+char *backtrace_symbol_list;
int temp_file_limit = -1;
@@ -4224,6 +4228,17 @@ static struct config_string ConfigureNamesString[] =
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 */
{
{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL
@@ -11487,6 +11502,76 @@ show_data_directory_mode(void)
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
check_recovery_target_timeline(char **newval, void **extra, GucSource source)
{