Preparatory refactoring for compiling guc-file.c standalone
authorJohn Naylor <[email protected]>
Tue, 16 Aug 2022 03:42:19 +0000 (10:42 +0700)
committerJohn Naylor <[email protected]>
Sun, 4 Sep 2022 03:12:56 +0000 (10:12 +0700)
Mostly this involves moving ProcessConfigFileInternal() to guc.c
and fixing the shared API to match.

Reviewed by Andres Freund
Discussion: https://www.postgresql.org/message-id/20220810171935.7k5zgnjwqzalzmtm%40awork3.anarazel.de
Discussion: https://www.postgresql.org/message-id/CAFBsxsF8Gc2StS3haXofshHCzqNMRXiSxvQEYGwnFsTmsdwNeg@mail.gmail.com

src/backend/utils/misc/guc-file.l
src/backend/utils/misc/guc.c
src/include/utils/guc.h

index 88460422dd398c378d9a9dacaeb2aa460cbae1db..47d4bd18d56a4aaf6f1ded24e5a4a10a1157ab2b 100644 (file)
@@ -49,12 +49,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 */
@@ -160,358 +154,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
@@ -660,7 +302,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,
index 9fbbfb1be5432a0b6f62577608f095ffd2c7ec73..66ab3912a0e7a7a3d1c437bf22873496de621cff 100644 (file)
@@ -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.
@@ -5160,8 +5156,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);
@@ -5180,7 +5176,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
@@ -5737,7 +6085,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)
 {
        /*
index e734493a4846c57d857cc637c413269a07b73a57..aae071cd82565dffd5ca7890f799f38fa3971668 100644 (file)
@@ -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