Starting a new thread to control clutter. [was: Re: [RFC] building postgres with meson]
motivation: https://www.postgresql.org/message-id/20220810171935.7k5zgnjwqzalzmtm%40awork3.anarazel.de On Thu, Aug 11, 2022 at 11:07 AM Andres Freund <and...@anarazel.de> wrote: > I think we should consider compiling it separately from guc.c. guc.c already > compiles quite slowly (iirc beat only by ecpg and main grammar), and it's a > relatively commonly changed source file. Done in the attached, and will do the rest in time. It seemed most straightforward to put ProcessConfigFileInternal() in guc.c since that's where most of its callers are, and it relies on some vars and types declared there. There are a couple new extern declarations in guc.h that are only for guc.c and guc-file.c: +/* functions shared between guc.c and guc-file.l */ +extern int guc_name_compare(const char *namea, const char *nameb); +extern ConfigVariable *ProcessConfigFileInternal(GucContext context, + bool applySettings, int elevel); +extern void record_config_file_error(const char *errmsg, + const char *config_file, + int lineno, + ConfigVariable **head_p, + ConfigVariable **tail_p); These might be better placed in a new guc_internal.h. Thoughts? > It might even be a good idea to split guc.c so it only contains the settings > arrays + direct dependencies... Perhaps this can be a TODO item, one which falls under "[E] marks items that are easier to implement". I've been slacking on removing the old/intractable cruft from the TODO list, but we should also be sticking small nice-but-not-necessary things in there. That said, if this idea has any bearing on the guc_internal.h idea, it might be better dealt with now. -- John Naylor EDB: http://www.enterprisedb.com
From d723ba14acf56fd432e9e263db937fcc13fc0355 Mon Sep 17 00:00:00 2001 From: John Naylor <john.nay...@postgresql.org> Date: Thu, 11 Aug 2022 19:38:37 +0700 Subject: [PATCH v1] Build guc-file.c standalone The proposed Meson build system will need a way to ignore certain generated files in order to coexist with the autoconf build system, and #include'd C files generated by Flex make this more difficult. Build guc-file.c separately from guc.c, as was done in 72b1e3a21. TODO: other Flex-generated files Discussion: https://www.postgresql.org/message-id/20220810171935.7k5zgnjwqzalzmtm%40awork3.anarazel.de --- src/backend/utils/misc/Makefile | 5 +- src/backend/utils/misc/guc-file.l | 367 +----------------------------- src/backend/utils/misc/guc.c | 362 ++++++++++++++++++++++++++++- src/include/utils/guc.h | 9 + 4 files changed, 370 insertions(+), 373 deletions(-) diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile index 1d5327cf64..cf7ce9bc83 100644 --- a/src/backend/utils/misc/Makefile +++ b/src/backend/utils/misc/Makefile @@ -16,6 +16,7 @@ override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) OBJS = \ guc.o \ + guc-file.o \ help_config.o \ pg_config.o \ pg_controldata.o \ @@ -37,10 +38,6 @@ endif include $(top_srcdir)/src/backend/common.mk -# guc-file is compiled as part of guc -guc.o: guc-file.c - # Note: guc-file.c is not deleted by 'make clean', # since we want to ship it in distribution tarballs. clean: - @rm -f lex.yy.c diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l index ce5633844c..08adb454de 100644 --- a/src/backend/utils/misc/guc-file.l +++ b/src/backend/utils/misc/guc-file.l @@ -7,7 +7,7 @@ * src/backend/utils/misc/guc-file.l */ -%{ +%top{ #include "postgres.h" @@ -17,9 +17,12 @@ #include "mb/pg_wchar.h" #include "miscadmin.h" #include "storage/fd.h" +#include <sys/stat.h> #include "utils/guc.h" +#include "utils/memutils.h" +} - +%{ /* * flex emits a yy_fatal_error() function that it calls in response to * critical errors like malloc failure, file I/O errors, and detection of @@ -48,12 +51,6 @@ static sigjmp_buf *GUC_flex_fatal_jmp; static void FreeConfigVariable(ConfigVariable *item); -static void record_config_file_error(const char *errmsg, - const char *config_file, - int lineno, - ConfigVariable **head_p, - ConfigVariable **tail_p); - static int GUC_flex_fatal(const char *msg); /* LCOV_EXCL_START */ @@ -159,358 +156,6 @@ ProcessConfigFile(GucContext context) MemoryContextDelete(config_cxt); } -/* - * This function handles both actual config file (re)loads and execution of - * show_all_file_settings() (i.e., the pg_file_settings view). In the latter - * case we don't apply any of the settings, but we make all the usual validity - * checks, and we return the ConfigVariable list so that it can be printed out - * by show_all_file_settings(). - */ -static ConfigVariable * -ProcessConfigFileInternal(GucContext context, bool applySettings, int elevel) -{ - bool error = false; - bool applying = false; - const char *ConfFileWithError; - ConfigVariable *item, - *head, - *tail; - int i; - - /* Parse the main config file into a list of option names and values */ - ConfFileWithError = ConfigFileName; - head = tail = NULL; - - if (!ParseConfigFile(ConfigFileName, true, - NULL, 0, 0, elevel, - &head, &tail)) - { - /* Syntax error(s) detected in the file, so bail out */ - error = true; - goto bail_out; - } - - /* - * Parse the PG_AUTOCONF_FILENAME file, if present, after the main file to - * replace any parameters set by ALTER SYSTEM command. Because this file - * is in the data directory, we can't read it until the DataDir has been - * set. - */ - if (DataDir) - { - if (!ParseConfigFile(PG_AUTOCONF_FILENAME, false, - NULL, 0, 0, elevel, - &head, &tail)) - { - /* Syntax error(s) detected in the file, so bail out */ - error = true; - ConfFileWithError = PG_AUTOCONF_FILENAME; - goto bail_out; - } - } - else - { - /* - * If DataDir is not set, the PG_AUTOCONF_FILENAME file cannot be - * read. In this case, we don't want to accept any settings but - * data_directory from postgresql.conf, because they might be - * overwritten with settings in the PG_AUTOCONF_FILENAME file which - * will be read later. OTOH, since data_directory isn't allowed in the - * PG_AUTOCONF_FILENAME file, it will never be overwritten later. - */ - ConfigVariable *newlist = NULL; - - /* - * Prune all items except the last "data_directory" from the list. - */ - for (item = head; item; item = item->next) - { - if (!item->ignore && - strcmp(item->name, "data_directory") == 0) - newlist = item; - } - - if (newlist) - newlist->next = NULL; - head = tail = newlist; - - /* - * Quick exit if data_directory is not present in file. - * - * We need not do any further processing, in particular we don't set - * PgReloadTime; that will be set soon by subsequent full loading of - * the config file. - */ - if (head == NULL) - goto bail_out; - } - - /* - * Mark all extant GUC variables as not present in the config file. We - * need this so that we can tell below which ones have been removed from - * the file since we last processed it. - */ - for (i = 0; i < num_guc_variables; i++) - { - struct config_generic *gconf = guc_variables[i]; - - gconf->status &= ~GUC_IS_IN_FILE; - } - - /* - * Check if all the supplied option names are valid, as an additional - * quasi-syntactic check on the validity of the config file. It is - * important that the postmaster and all backends agree on the results of - * this phase, else we will have strange inconsistencies about which - * processes accept a config file update and which don't. Hence, unknown - * custom variable names have to be accepted without complaint. For the - * same reason, we don't attempt to validate the options' values here. - * - * In addition, the GUC_IS_IN_FILE flag is set on each existing GUC - * variable mentioned in the file; and we detect duplicate entries in the - * file and mark the earlier occurrences as ignorable. - */ - for (item = head; item; item = item->next) - { - struct config_generic *record; - - /* Ignore anything already marked as ignorable */ - if (item->ignore) - continue; - - /* - * Try to find the variable; but do not create a custom placeholder if - * it's not there already. - */ - record = find_option(item->name, false, true, elevel); - - if (record) - { - /* If it's already marked, then this is a duplicate entry */ - if (record->status & GUC_IS_IN_FILE) - { - /* - * Mark the earlier occurrence(s) as dead/ignorable. We could - * avoid the O(N^2) behavior here with some additional state, - * but it seems unlikely to be worth the trouble. - */ - ConfigVariable *pitem; - - for (pitem = head; pitem != item; pitem = pitem->next) - { - if (!pitem->ignore && - strcmp(pitem->name, item->name) == 0) - pitem->ignore = true; - } - } - /* Now mark it as present in file */ - record->status |= GUC_IS_IN_FILE; - } - else if (!valid_custom_variable_name(item->name)) - { - /* Invalid non-custom variable, so complain */ - ereport(elevel, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("unrecognized configuration parameter \"%s\" in file \"%s\" line %d", - item->name, - item->filename, item->sourceline))); - item->errmsg = pstrdup("unrecognized configuration parameter"); - error = true; - ConfFileWithError = item->filename; - } - } - - /* - * If we've detected any errors so far, we don't want to risk applying any - * changes. - */ - if (error) - goto bail_out; - - /* Otherwise, set flag that we're beginning to apply changes */ - applying = true; - - /* - * Check for variables having been removed from the config file, and - * revert their reset values (and perhaps also effective values) to the - * boot-time defaults. If such a variable can't be changed after startup, - * report that and continue. - */ - for (i = 0; i < num_guc_variables; i++) - { - struct config_generic *gconf = guc_variables[i]; - GucStack *stack; - - if (gconf->reset_source != PGC_S_FILE || - (gconf->status & GUC_IS_IN_FILE)) - continue; - if (gconf->context < PGC_SIGHUP) - { - /* The removal can't be effective without a restart */ - gconf->status |= GUC_PENDING_RESTART; - ereport(elevel, - (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), - errmsg("parameter \"%s\" cannot be changed without restarting the server", - gconf->name))); - record_config_file_error(psprintf("parameter \"%s\" cannot be changed without restarting the server", - gconf->name), - NULL, 0, - &head, &tail); - error = true; - continue; - } - - /* No more to do if we're just doing show_all_file_settings() */ - if (!applySettings) - continue; - - /* - * Reset any "file" sources to "default", else set_config_option will - * not override those settings. - */ - if (gconf->reset_source == PGC_S_FILE) - gconf->reset_source = PGC_S_DEFAULT; - if (gconf->source == PGC_S_FILE) - gconf->source = PGC_S_DEFAULT; - for (stack = gconf->stack; stack; stack = stack->prev) - { - if (stack->source == PGC_S_FILE) - stack->source = PGC_S_DEFAULT; - } - - /* Now we can re-apply the wired-in default (i.e., the boot_val) */ - if (set_config_option(gconf->name, NULL, - context, PGC_S_DEFAULT, - GUC_ACTION_SET, true, 0, false) > 0) - { - /* Log the change if appropriate */ - if (context == PGC_SIGHUP) - ereport(elevel, - (errmsg("parameter \"%s\" removed from configuration file, reset to default", - gconf->name))); - } - } - - /* - * Restore any variables determined by environment variables or - * dynamically-computed defaults. This is a no-op except in the case - * where one of these had been in the config file and is now removed. - * - * In particular, we *must not* do this during the postmaster's initial - * loading of the file, since the timezone functions in particular should - * be run only after initialization is complete. - * - * XXX this is an unmaintainable crock, because we have to know how to set - * (or at least what to call to set) every non-PGC_INTERNAL variable that - * could potentially have PGC_S_DYNAMIC_DEFAULT or PGC_S_ENV_VAR source. - */ - if (context == PGC_SIGHUP && applySettings) - { - InitializeGUCOptionsFromEnvironment(); - pg_timezone_abbrev_initialize(); - /* this selects SQL_ASCII in processes not connected to a database */ - SetConfigOption("client_encoding", GetDatabaseEncodingName(), - PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT); - } - - /* - * Now apply the values from the config file. - */ - for (item = head; item; item = item->next) - { - char *pre_value = NULL; - int scres; - - /* Ignore anything marked as ignorable */ - if (item->ignore) - continue; - - /* In SIGHUP cases in the postmaster, we want to report changes */ - if (context == PGC_SIGHUP && applySettings && !IsUnderPostmaster) - { - const char *preval = GetConfigOption(item->name, true, false); - - /* If option doesn't exist yet or is NULL, treat as empty string */ - if (!preval) - preval = ""; - /* must dup, else might have dangling pointer below */ - pre_value = pstrdup(preval); - } - - scres = set_config_option(item->name, item->value, - context, PGC_S_FILE, - GUC_ACTION_SET, applySettings, 0, false); - if (scres > 0) - { - /* variable was updated, so log the change if appropriate */ - if (pre_value) - { - const char *post_value = GetConfigOption(item->name, true, false); - - if (!post_value) - post_value = ""; - if (strcmp(pre_value, post_value) != 0) - ereport(elevel, - (errmsg("parameter \"%s\" changed to \"%s\"", - item->name, item->value))); - } - item->applied = true; - } - else if (scres == 0) - { - error = true; - item->errmsg = pstrdup("setting could not be applied"); - ConfFileWithError = item->filename; - } - else - { - /* no error, but variable's active value was not changed */ - item->applied = true; - } - - /* - * We should update source location unless there was an error, since - * even if the active value didn't change, the reset value might have. - * (In the postmaster, there won't be a difference, but it does matter - * in backends.) - */ - if (scres != 0 && applySettings) - set_config_sourcefile(item->name, item->filename, - item->sourceline); - - if (pre_value) - pfree(pre_value); - } - - /* Remember when we last successfully loaded the config file. */ - if (applySettings) - PgReloadTime = GetCurrentTimestamp(); - -bail_out: - if (error && applySettings) - { - /* During postmaster startup, any error is fatal */ - if (context == PGC_POSTMASTER) - ereport(ERROR, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("configuration file \"%s\" contains errors", - ConfFileWithError))); - else if (applying) - ereport(elevel, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("configuration file \"%s\" contains errors; unaffected changes were applied", - ConfFileWithError))); - else - ereport(elevel, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("configuration file \"%s\" contains errors; no changes were applied", - ConfFileWithError))); - } - - /* Successful or otherwise, return the collected data list */ - return head; -} - /* * Given a configuration file or directory location that may be a relative * path, return an absolute one. We consider the location to be relative to @@ -659,7 +304,7 @@ cleanup: * Capture an error message in the ConfigVariable list returned by * config file parsing. */ -static void +void record_config_file_error(const char *errmsg, const char *config_file, int lineno, diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 5db5df6285..e4a00f1205 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -243,10 +243,6 @@ static void assign_recovery_target_lsn(const char *newval, void *extra); static bool check_primary_slot_name(char **newval, void **extra, GucSource source); static bool check_default_with_oids(bool *newval, void **extra, GucSource source); -/* Private functions in guc-file.l that need to be called from guc.c */ -static ConfigVariable *ProcessConfigFileInternal(GucContext context, - bool applySettings, int elevel); - /* * Track whether there were any deferred checks for custom resource managers * specified in wal_consistency_checking. @@ -5164,8 +5160,8 @@ static bool report_needed; /* true if any GUC_REPORT reports are needed */ static int GUCNestLevel = 0; /* 1 when in main transaction */ +static struct config_generic *find_option(const char *name, bool create_placeholders, bool skip_errors, int elevel); static int guc_var_compare(const void *a, const void *b); -static int guc_name_compare(const char *namea, const char *nameb); static void InitializeGUCOptionsFromEnvironment(void); static void InitializeOneGUCOption(struct config_generic *gconf); static void push_old_value(struct config_generic *gconf, GucAction action); @@ -5184,7 +5180,359 @@ static bool validate_option_array_item(const char *name, const char *value, static void write_auto_conf_file(int fd, const char *filename, ConfigVariable *head_p); static void replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p, const char *name, const char *value); +static bool valid_custom_variable_name(const char *name); + +/* + * This function handles both actual config file (re)loads and execution of + * show_all_file_settings() (i.e., the pg_file_settings view). In the latter + * case we don't apply any of the settings, but we make all the usual validity + * checks, and we return the ConfigVariable list so that it can be printed out + * by show_all_file_settings(). + */ +ConfigVariable * +ProcessConfigFileInternal(GucContext context, bool applySettings, int elevel) +{ + bool error = false; + bool applying = false; + const char *ConfFileWithError; + ConfigVariable *item, + *head, + *tail; + int i; + + /* Parse the main config file into a list of option names and values */ + ConfFileWithError = ConfigFileName; + head = tail = NULL; + + if (!ParseConfigFile(ConfigFileName, true, + NULL, 0, 0, elevel, + &head, &tail)) + { + /* Syntax error(s) detected in the file, so bail out */ + error = true; + goto bail_out; + } + + /* + * Parse the PG_AUTOCONF_FILENAME file, if present, after the main file to + * replace any parameters set by ALTER SYSTEM command. Because this file + * is in the data directory, we can't read it until the DataDir has been + * set. + */ + if (DataDir) + { + if (!ParseConfigFile(PG_AUTOCONF_FILENAME, false, + NULL, 0, 0, elevel, + &head, &tail)) + { + /* Syntax error(s) detected in the file, so bail out */ + error = true; + ConfFileWithError = PG_AUTOCONF_FILENAME; + goto bail_out; + } + } + else + { + /* + * If DataDir is not set, the PG_AUTOCONF_FILENAME file cannot be + * read. In this case, we don't want to accept any settings but + * data_directory from postgresql.conf, because they might be + * overwritten with settings in the PG_AUTOCONF_FILENAME file which + * will be read later. OTOH, since data_directory isn't allowed in the + * PG_AUTOCONF_FILENAME file, it will never be overwritten later. + */ + ConfigVariable *newlist = NULL; + + /* + * Prune all items except the last "data_directory" from the list. + */ + for (item = head; item; item = item->next) + { + if (!item->ignore && + strcmp(item->name, "data_directory") == 0) + newlist = item; + } + + if (newlist) + newlist->next = NULL; + head = tail = newlist; + + /* + * Quick exit if data_directory is not present in file. + * + * We need not do any further processing, in particular we don't set + * PgReloadTime; that will be set soon by subsequent full loading of + * the config file. + */ + if (head == NULL) + goto bail_out; + } + + /* + * Mark all extant GUC variables as not present in the config file. We + * need this so that we can tell below which ones have been removed from + * the file since we last processed it. + */ + for (i = 0; i < num_guc_variables; i++) + { + struct config_generic *gconf = guc_variables[i]; + + gconf->status &= ~GUC_IS_IN_FILE; + } + + /* + * Check if all the supplied option names are valid, as an additional + * quasi-syntactic check on the validity of the config file. It is + * important that the postmaster and all backends agree on the results of + * this phase, else we will have strange inconsistencies about which + * processes accept a config file update and which don't. Hence, unknown + * custom variable names have to be accepted without complaint. For the + * same reason, we don't attempt to validate the options' values here. + * + * In addition, the GUC_IS_IN_FILE flag is set on each existing GUC + * variable mentioned in the file; and we detect duplicate entries in the + * file and mark the earlier occurrences as ignorable. + */ + for (item = head; item; item = item->next) + { + struct config_generic *record; + + /* Ignore anything already marked as ignorable */ + if (item->ignore) + continue; + + /* + * Try to find the variable; but do not create a custom placeholder if + * it's not there already. + */ + record = find_option(item->name, false, true, elevel); + + if (record) + { + /* If it's already marked, then this is a duplicate entry */ + if (record->status & GUC_IS_IN_FILE) + { + /* + * Mark the earlier occurrence(s) as dead/ignorable. We could + * avoid the O(N^2) behavior here with some additional state, + * but it seems unlikely to be worth the trouble. + */ + ConfigVariable *pitem; + + for (pitem = head; pitem != item; pitem = pitem->next) + { + if (!pitem->ignore && + strcmp(pitem->name, item->name) == 0) + pitem->ignore = true; + } + } + /* Now mark it as present in file */ + record->status |= GUC_IS_IN_FILE; + } + else if (!valid_custom_variable_name(item->name)) + { + /* Invalid non-custom variable, so complain */ + ereport(elevel, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("unrecognized configuration parameter \"%s\" in file \"%s\" line %d", + item->name, + item->filename, item->sourceline))); + item->errmsg = pstrdup("unrecognized configuration parameter"); + error = true; + ConfFileWithError = item->filename; + } + } + + /* + * If we've detected any errors so far, we don't want to risk applying any + * changes. + */ + if (error) + goto bail_out; + + /* Otherwise, set flag that we're beginning to apply changes */ + applying = true; + + /* + * Check for variables having been removed from the config file, and + * revert their reset values (and perhaps also effective values) to the + * boot-time defaults. If such a variable can't be changed after startup, + * report that and continue. + */ + for (i = 0; i < num_guc_variables; i++) + { + struct config_generic *gconf = guc_variables[i]; + GucStack *stack; + + if (gconf->reset_source != PGC_S_FILE || + (gconf->status & GUC_IS_IN_FILE)) + continue; + if (gconf->context < PGC_SIGHUP) + { + /* The removal can't be effective without a restart */ + gconf->status |= GUC_PENDING_RESTART; + ereport(elevel, + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("parameter \"%s\" cannot be changed without restarting the server", + gconf->name))); + record_config_file_error(psprintf("parameter \"%s\" cannot be changed without restarting the server", + gconf->name), + NULL, 0, + &head, &tail); + error = true; + continue; + } + + /* No more to do if we're just doing show_all_file_settings() */ + if (!applySettings) + continue; + + /* + * Reset any "file" sources to "default", else set_config_option will + * not override those settings. + */ + if (gconf->reset_source == PGC_S_FILE) + gconf->reset_source = PGC_S_DEFAULT; + if (gconf->source == PGC_S_FILE) + gconf->source = PGC_S_DEFAULT; + for (stack = gconf->stack; stack; stack = stack->prev) + { + if (stack->source == PGC_S_FILE) + stack->source = PGC_S_DEFAULT; + } + + /* Now we can re-apply the wired-in default (i.e., the boot_val) */ + if (set_config_option(gconf->name, NULL, + context, PGC_S_DEFAULT, + GUC_ACTION_SET, true, 0, false) > 0) + { + /* Log the change if appropriate */ + if (context == PGC_SIGHUP) + ereport(elevel, + (errmsg("parameter \"%s\" removed from configuration file, reset to default", + gconf->name))); + } + } + + /* + * Restore any variables determined by environment variables or + * dynamically-computed defaults. This is a no-op except in the case + * where one of these had been in the config file and is now removed. + * + * In particular, we *must not* do this during the postmaster's initial + * loading of the file, since the timezone functions in particular should + * be run only after initialization is complete. + * + * XXX this is an unmaintainable crock, because we have to know how to set + * (or at least what to call to set) every non-PGC_INTERNAL variable that + * could potentially have PGC_S_DYNAMIC_DEFAULT or PGC_S_ENV_VAR source. + */ + if (context == PGC_SIGHUP && applySettings) + { + InitializeGUCOptionsFromEnvironment(); + pg_timezone_abbrev_initialize(); + /* this selects SQL_ASCII in processes not connected to a database */ + SetConfigOption("client_encoding", GetDatabaseEncodingName(), + PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT); + } + /* + * Now apply the values from the config file. + */ + for (item = head; item; item = item->next) + { + char *pre_value = NULL; + int scres; + + /* Ignore anything marked as ignorable */ + if (item->ignore) + continue; + + /* In SIGHUP cases in the postmaster, we want to report changes */ + if (context == PGC_SIGHUP && applySettings && !IsUnderPostmaster) + { + const char *preval = GetConfigOption(item->name, true, false); + + /* If option doesn't exist yet or is NULL, treat as empty string */ + if (!preval) + preval = ""; + /* must dup, else might have dangling pointer below */ + pre_value = pstrdup(preval); + } + + scres = set_config_option(item->name, item->value, + context, PGC_S_FILE, + GUC_ACTION_SET, applySettings, 0, false); + if (scres > 0) + { + /* variable was updated, so log the change if appropriate */ + if (pre_value) + { + const char *post_value = GetConfigOption(item->name, true, false); + + if (!post_value) + post_value = ""; + if (strcmp(pre_value, post_value) != 0) + ereport(elevel, + (errmsg("parameter \"%s\" changed to \"%s\"", + item->name, item->value))); + } + item->applied = true; + } + else if (scres == 0) + { + error = true; + item->errmsg = pstrdup("setting could not be applied"); + ConfFileWithError = item->filename; + } + else + { + /* no error, but variable's active value was not changed */ + item->applied = true; + } + + /* + * We should update source location unless there was an error, since + * even if the active value didn't change, the reset value might have. + * (In the postmaster, there won't be a difference, but it does matter + * in backends.) + */ + if (scres != 0 && applySettings) + set_config_sourcefile(item->name, item->filename, + item->sourceline); + + if (pre_value) + pfree(pre_value); + } + + /* Remember when we last successfully loaded the config file. */ + if (applySettings) + PgReloadTime = GetCurrentTimestamp(); + +bail_out: + if (error && applySettings) + { + /* During postmaster startup, any error is fatal */ + if (context == PGC_POSTMASTER) + ereport(ERROR, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("configuration file \"%s\" contains errors", + ConfFileWithError))); + else if (applying) + ereport(elevel, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("configuration file \"%s\" contains errors; unaffected changes were applied", + ConfFileWithError))); + else + ereport(elevel, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("configuration file \"%s\" contains errors; no changes were applied", + ConfFileWithError))); + } + + /* Successful or otherwise, return the collected data list */ + return head; +} /* * Some infrastructure for checking malloc/strdup/realloc calls @@ -5741,7 +6089,7 @@ guc_var_compare(const void *a, const void *b) /* * the bare comparison function for GUC names */ -static int +int guc_name_compare(const char *namea, const char *nameb) { /* @@ -12988,5 +13336,3 @@ check_default_with_oids(bool *newval, void **extra, GucSource source) return true; } - -#include "guc-file.c" diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index e734493a48..aae071cd82 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -442,6 +442,15 @@ extern void GUC_check_errcode(int sqlerrcode); pre_format_elog_string(errno, TEXTDOMAIN), \ GUC_check_errhint_string = format_elog_string +/* functions shared between guc.c and guc-file.l */ +extern int guc_name_compare(const char *namea, const char *nameb); +extern ConfigVariable *ProcessConfigFileInternal(GucContext context, + bool applySettings, int elevel); +extern void record_config_file_error(const char *errmsg, + const char *config_file, + int lineno, + ConfigVariable **head_p, + ConfigVariable **tail_p); /* * The following functions are not in guc.c, but are declared here to avoid -- 2.36.1