Preparatory refactoring for compiling guc-file.c standalone
authorJohn Naylor
Tue, 16 Aug 2022 03:42:19 +0000 (10:42 +0700)
committerJohn Naylor
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