diff options
Diffstat (limited to 'src/backend/utils/misc/guc.c')
-rw-r--r-- | src/backend/utils/misc/guc.c | 85 |
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) { |