Add infrastructure to save and restore GUC values.
authorRobert Haas <[email protected]>
Mon, 24 Nov 2014 21:13:11 +0000 (16:13 -0500)
committerRobert Haas <[email protected]>
Mon, 24 Nov 2014 21:37:56 +0000 (16:37 -0500)
This is further infrastructure for parallelism.

Amit Khandekar, Noah Misch, Robert Haas

contrib/dblink/dblink.c
contrib/postgres_fdw/postgres_fdw.c
src/backend/commands/extension.c
src/backend/utils/adt/ri_triggers.c
src/backend/utils/misc/guc-file.l
src/backend/utils/misc/guc.c
src/include/utils/guc.h

index d77b3ee34ba2e7b28558636ccbd1ba1f2bcdb1df..18ae318cd3b581d203e6c565c639b708b65007e6 100644 (file)
@@ -2980,7 +2980,7 @@ applyRemoteGucs(PGconn *conn)
        /* Apply the option (this will throw error on failure) */
        (void) set_config_option(gucName, remoteVal,
                                 PGC_USERSET, PGC_S_SESSION,
-                                GUC_ACTION_SAVE, true, 0);
+                                GUC_ACTION_SAVE, true, 0, false);
    }
 
    return nestlevel;
index 905a821ad076dcf8f345e4b8b8594a18bf8a803d..76bda73935779093f7174f356a63ee6fb70f6b74 100644 (file)
@@ -2104,15 +2104,15 @@ set_transmission_modes(void)
    if (DateStyle != USE_ISO_DATES)
        (void) set_config_option("datestyle", "ISO",
                                 PGC_USERSET, PGC_S_SESSION,
-                                GUC_ACTION_SAVE, true, 0);
+                                GUC_ACTION_SAVE, true, 0, false);
    if (IntervalStyle != INTSTYLE_POSTGRES)
        (void) set_config_option("intervalstyle", "postgres",
                                 PGC_USERSET, PGC_S_SESSION,
-                                GUC_ACTION_SAVE, true, 0);
+                                GUC_ACTION_SAVE, true, 0, false);
    if (extra_float_digits < 3)
        (void) set_config_option("extra_float_digits", "3",
                                 PGC_USERSET, PGC_S_SESSION,
-                                GUC_ACTION_SAVE, true, 0);
+                                GUC_ACTION_SAVE, true, 0, false);
 
    return nestlevel;
 }
index 9a0afa4b5dcc63431be3a21155ad068ada9a11f7..6692bb545c44a6787779c0198983f327f254f574 100644 (file)
@@ -814,11 +814,11 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
    if (client_min_messages < WARNING)
        (void) set_config_option("client_min_messages", "warning",
                                 PGC_USERSET, PGC_S_SESSION,
-                                GUC_ACTION_SAVE, true, 0);
+                                GUC_ACTION_SAVE, true, 0, false);
    if (log_min_messages < WARNING)
        (void) set_config_option("log_min_messages", "warning",
                                 PGC_SUSET, PGC_S_SESSION,
-                                GUC_ACTION_SAVE, true, 0);
+                                GUC_ACTION_SAVE, true, 0, false);
 
    /*
     * Set up the search path to contain the target schema, then the schemas
@@ -843,7 +843,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 
    (void) set_config_option("search_path", pathbuf.data,
                             PGC_USERSET, PGC_S_SESSION,
-                            GUC_ACTION_SAVE, true, 0);
+                            GUC_ACTION_SAVE, true, 0, false);
 
    /*
     * Set creating_extension and related variables so that
index c0156fab1f9e7092320c5b7286dac37469f9ee60..2f0230384f42a0f3d9c2397f7b8fd2ad3070edd6 100644 (file)
@@ -2422,7 +2422,7 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
    snprintf(workmembuf, sizeof(workmembuf), "%d", maintenance_work_mem);
    (void) set_config_option("work_mem", workmembuf,
                             PGC_USERSET, PGC_S_SESSION,
-                            GUC_ACTION_SAVE, true, 0);
+                            GUC_ACTION_SAVE, true, 0, false);
 
    if (SPI_connect() != SPI_OK_CONNECT)
        elog(ERROR, "SPI_connect failed");
index bb9207a777a9da8823f983976f83169813428e6b..6dca5dfa74618817d6ae266a5d66fc5a1783fff1 100644 (file)
@@ -318,7 +318,7 @@ ProcessConfigFile(GucContext context)
        /* 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) > 0)
+                             GUC_ACTION_SET, true, 0, false) > 0)
        {
            /* Log the change if appropriate */
            if (context == PGC_SIGHUP)
@@ -373,7 +373,7 @@ ProcessConfigFile(GucContext context)
 
        scres = set_config_option(item->name, item->value,
                                  context, PGC_S_FILE,
-                                 GUC_ACTION_SET, true, 0);
+                                 GUC_ACTION_SET, true, 0, false);
        if (scres > 0)
        {
            /* variable was updated, so log the change if appropriate */
index 23cbe906a789382e8e7c5ca9fc01165edda37c7a..f04757c5826218fd167ad06a2a8494b181b09084 100644 (file)
 #define S_PER_D (60 * 60 * 24)
 #define MS_PER_D (1000 * 60 * 60 * 24)
 
+/*
+ * Precision with which REAL type guc values are to be printed for GUC
+ * serialization.
+ */
+#define REALTYPE_PRECISION 17
+
 /* XXX these should appear in other modules' header files */
 extern bool Log_disconnections;
 extern int CommitDelay;
@@ -136,6 +142,10 @@ char      *GUC_check_errmsg_string;
 char      *GUC_check_errdetail_string;
 char      *GUC_check_errhint_string;
 
+static void
+do_serialize(char **destptr, Size *maxbytes, const char *fmt,...)
+/* This lets gcc check the format string for consistency. */
+__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
 
 static void set_config_sourcefile(const char *name, char *sourcefile,
                      int sourceline);
@@ -5612,7 +5622,8 @@ validate_conf_option(struct config_generic * record, const char *name,
 int
 set_config_option(const char *name, const char *value,
                  GucContext context, GucSource source,
-                 GucAction action, bool changeVal, int elevel)
+                 GucAction action, bool changeVal, int elevel,
+                 bool is_reload)
 {
    struct config_generic *record;
    bool        prohibitValueChange = false;
@@ -5726,18 +5737,13 @@ set_config_option(const char *name, const char *value,
                 * nondefault settings from the CONFIG_EXEC_PARAMS file during
                 * backend start.  In that case we must accept PGC_SIGHUP
                 * settings, so as to have the same value as if we'd forked
-                * from the postmaster.  We detect this situation by checking
-                * IsInitProcessingMode, which is a bit ugly, but it doesn't
-                * seem worth passing down an explicit flag saying we're doing
-                * read_nondefault_variables().
+                * from the postmaster.  This can also happen when using
+                * RestoreGUCState() within a background worker that needs to
+                * have the same settings as the user backend that started it.
+                * is_reload will be true when either situation applies.
                 */
-#ifdef EXEC_BACKEND
-               if (IsUnderPostmaster && !IsInitProcessingMode())
-                   return -1;
-#else
-               if (IsUnderPostmaster)
+               if (IsUnderPostmaster && !is_reload)
                    return -1;
-#endif
            }
            else if (context != PGC_POSTMASTER &&
                     context != PGC_BACKEND &&
@@ -6343,7 +6349,7 @@ SetConfigOption(const char *name, const char *value,
                GucContext context, GucSource source)
 {
    (void) set_config_option(name, value, context, source,
-                            GUC_ACTION_SET, true, 0);
+                            GUC_ACTION_SET, true, 0, false);
 }
 
 
@@ -6923,9 +6929,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
                                     ExtractSetVariableArgs(stmt),
                                     (superuser() ? PGC_SUSET : PGC_USERSET),
                                     PGC_S_SESSION,
-                                    action,
-                                    true,
-                                    0);
+                                    action, true, 0, false);
            break;
        case VAR_SET_MULTI:
 
@@ -7012,9 +7016,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
                                     NULL,
                                     (superuser() ? PGC_SUSET : PGC_USERSET),
                                     PGC_S_SESSION,
-                                    action,
-                                    true,
-                                    0);
+                                    action, true, 0, false);
            break;
        case VAR_RESET_ALL:
            ResetAllOptions();
@@ -7059,8 +7061,7 @@ SetPGVariable(const char *name, List *args, bool is_local)
                             (superuser() ? PGC_SUSET : PGC_USERSET),
                             PGC_S_SESSION,
                             is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
-                            true,
-                            0);
+                            true, 0, false);
 }
 
 /*
@@ -7103,8 +7104,7 @@ set_config_by_name(PG_FUNCTION_ARGS)
                             (superuser() ? PGC_SUSET : PGC_USERSET),
                             PGC_S_SESSION,
                             is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
-                            true,
-                            0);
+                            true, 0, false);
 
    /* get the new current value */
    new_value = GetConfigOptionByName(name, NULL);
@@ -7225,7 +7225,7 @@ define_custom_variable(struct config_generic * variable)
        (void) set_config_option(name, pHolder->reset_val,
                                 pHolder->gen.reset_scontext,
                                 pHolder->gen.reset_source,
-                                GUC_ACTION_SET, true, WARNING);
+                                GUC_ACTION_SET, true, WARNING, false);
    /* That should not have resulted in stacking anything */
    Assert(variable->stack == NULL);
 
@@ -7281,30 +7281,35 @@ reapply_stacked_values(struct config_generic * variable,
            case GUC_SAVE:
                (void) set_config_option(name, curvalue,
                                         curscontext, cursource,
-                                        GUC_ACTION_SAVE, true, WARNING);
+                                        GUC_ACTION_SAVE, true,
+                                        WARNING, false);
                break;
 
            case GUC_SET:
                (void) set_config_option(name, curvalue,
                                         curscontext, cursource,
-                                        GUC_ACTION_SET, true, WARNING);
+                                        GUC_ACTION_SET, true,
+                                        WARNING, false);
                break;
 
            case GUC_LOCAL:
                (void) set_config_option(name, curvalue,
                                         curscontext, cursource,
-                                        GUC_ACTION_LOCAL, true, WARNING);
+                                        GUC_ACTION_LOCAL, true,
+                                        WARNING, false);
                break;
 
            case GUC_SET_LOCAL:
                /* first, apply the masked value as SET */
                (void) set_config_option(name, stack->masked.val.stringval,
                                       stack->masked_scontext, PGC_S_SESSION,
-                                        GUC_ACTION_SET, true, WARNING);
+                                        GUC_ACTION_SET, true,
+                                        WARNING, false);
                /* then apply the current value as LOCAL */
                (void) set_config_option(name, curvalue,
                                         curscontext, cursource,
-                                        GUC_ACTION_LOCAL, true, WARNING);
+                                        GUC_ACTION_LOCAL, true,
+                                        WARNING, false);
                break;
        }
 
@@ -7328,7 +7333,7 @@ reapply_stacked_values(struct config_generic * variable,
        {
            (void) set_config_option(name, curvalue,
                                     curscontext, cursource,
-                                    GUC_ACTION_SET, true, WARNING);
+                                    GUC_ACTION_SET, true, WARNING, false);
            variable->stack = NULL;
        }
    }
@@ -8452,7 +8457,7 @@ read_nondefault_variables(void)
 
        (void) set_config_option(varname, varvalue,
                                 varscontext, varsource,
-                                GUC_ACTION_SET, true, 0);
+                                GUC_ACTION_SET, true, 0, true);
        if (varsourcefile[0])
            set_config_sourcefile(varname, varsourcefile, varsourceline);
 
@@ -8465,6 +8470,398 @@ read_nondefault_variables(void)
 }
 #endif   /* EXEC_BACKEND */
 
+/*
+ * can_skip_gucvar:
+ * When serializing, determine whether to skip this GUC.  When restoring, the
+ * negation of this test determines whether to restore the compiled-in default
+ * value before processing serialized values.
+ *
+ * A PGC_S_DEFAULT setting on the serialize side will typically match new
+ * postmaster children, but that can be false when got_SIGHUP == true and the
+ * pending configuration change modifies this setting.  Nonetheless, we omit
+ * PGC_S_DEFAULT settings from serialization and make up for that by restoring
+ * defaults before applying serialized values.
+ *
+ * PGC_POSTMASTER variables always have the same value in every child of a
+ * particular postmaster.  Most PGC_INTERNAL variables are compile-time
+ * constants; a few, like server_encoding and lc_ctype, are handled specially
+ * outside the serialize/restore procedure.  Therefore, SerializeGUCState()
+ * never sends these, and and RestoreGUCState() never changes them.
+ */
+static bool
+can_skip_gucvar(struct config_generic * gconf)
+{
+   return gconf->context == PGC_POSTMASTER ||
+       gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT;
+}
+
+/*
+ * estimate_variable_size:
+ * Estimate max size for dumping the given GUC variable.
+ */
+static Size
+estimate_variable_size(struct config_generic * gconf)
+{
+   Size        size;
+   Size        valsize;
+
+   if (can_skip_gucvar(gconf))
+       return 0;
+
+   size = 0;
+
+   size = add_size(size, strlen(gconf->name) + 1);
+
+   /* Get the maximum display length of the GUC value. */
+   switch (gconf->vartype)
+   {
+       case PGC_BOOL:
+           {
+               valsize = 5;    /* max(strlen('true'), strlen('false')) */
+           }
+           break;
+
+       case PGC_INT:
+           {
+               struct config_int *conf = (struct config_int *) gconf;
+
+               /*
+                * Instead of getting the exact display length, use max
+                * length.  Also reduce the max length for typical ranges of
+                * small values.  Maximum value is 2147483647, i.e. 10 chars.
+                * Include one byte for sign.
+                */
+               if (abs(*conf->variable) < 1000)
+                   valsize = 3 + 1;
+               else
+                   valsize = 10 + 1;
+           }
+           break;
+
+       case PGC_REAL:
+           {
+               /*
+                * We are going to print it with %.17g. Account for sign,
+                * decimal point, and e+nnn notation. E.g.
+                * -3.9932904234000002e+110
+                */
+               valsize = REALTYPE_PRECISION + 1 + 1 + 5;
+           }
+           break;
+
+       case PGC_STRING:
+           {
+               struct config_string *conf = (struct config_string *) gconf;
+
+               valsize = strlen(*conf->variable);
+           }
+           break;
+
+       case PGC_ENUM:
+           {
+               struct config_enum *conf = (struct config_enum *) gconf;
+
+               valsize = strlen(config_enum_lookup_by_value(conf, *conf->variable));
+           }
+           break;
+   }
+
+   /* Allow space for terminating zero-byte */
+   size = add_size(size, valsize + 1);
+
+   if (gconf->sourcefile)
+       size = add_size(size, strlen(gconf->sourcefile));
+
+   /* Allow space for terminating zero-byte */
+   size = add_size(size, 1);
+
+   /* Include line whenever we include file. */
+   if (gconf->sourcefile)
+       size = add_size(size, sizeof(gconf->sourceline));
+
+   size = add_size(size, sizeof(gconf->source));
+   size = add_size(size, sizeof(gconf->scontext));
+
+   return size;
+}
+
+/*
+ * EstimateGUCStateSpace:
+ * Returns the size needed to store the GUC state for the current process
+ */
+Size
+EstimateGUCStateSpace(void)
+{
+   Size        size;
+   int         i;
+
+   /* Add space reqd for saving the data size of the guc state */
+   size = sizeof(Size);
+
+   /* Add up the space needed for each GUC variable */
+   for (i = 0; i < num_guc_variables; i++)
+       size = add_size(size,
+                       estimate_variable_size(guc_variables[i]));
+
+   return size;
+}
+
+/*
+ * do_serialize:
+ * Copies the formatted string into the destination.  Moves ahead the
+ * destination pointer, and decrements the maxbytes by that many bytes. If
+ * maxbytes is not sufficient to copy the string, error out.
+ */
+static void
+do_serialize(char **destptr, Size *maxbytes, const char *fmt,...)
+{
+   va_list     vargs;
+   int         n;
+
+   if (*maxbytes <= 0)
+       elog(ERROR, "not enough space to serialize GUC state");
+
+   va_start(vargs, fmt);
+   n = vsnprintf(*destptr, *maxbytes, fmt, vargs);
+   va_end(vargs);
+
+   /*
+    * Cater to portability hazards in the vsnprintf() return value just like
+    * appendPQExpBufferVA() does.  Note that this requires an extra byte of
+    * slack at the end of the buffer.  Since serialize_variable() ends with a
+    * do_serialize_binary() rather than a do_serialize(), we'll always have
+    * that slack; estimate_variable_size() need not add a byte for it.
+    */
+   if (n < 0 || n >= *maxbytes - 1)
+   {
+       if (n < 0 && errno != 0 && errno != ENOMEM)
+           /* Shouldn't happen. Better show errno description. */
+           elog(ERROR, "vsnprintf failed: %m");
+       else
+           elog(ERROR, "not enough space to serialize GUC state");
+   }
+
+   /* Shift the destptr ahead of the null terminator */
+   *destptr += n + 1;
+   *maxbytes -= n + 1;
+}
+
+/* Binary copy version of do_serialize() */
+static void
+do_serialize_binary(char **destptr, Size *maxbytes, void *val, Size valsize)
+{
+   if (valsize > *maxbytes)
+       elog(ERROR, "not enough space to serialize GUC state");
+
+   memcpy(*destptr, val, valsize);
+   *destptr += valsize;
+   *maxbytes -= valsize;
+}
+
+/*
+ * serialize_variable:
+ * Dumps name, value and other information of a GUC variable into destptr.
+ */
+static void
+serialize_variable(char **destptr, Size *maxbytes,
+                  struct config_generic * gconf)
+{
+   if (can_skip_gucvar(gconf))
+       return;
+
+   do_serialize(destptr, maxbytes, "%s", gconf->name);
+
+   switch (gconf->vartype)
+   {
+       case PGC_BOOL:
+           {
+               struct config_bool *conf = (struct config_bool *) gconf;
+
+               do_serialize(destptr, maxbytes,
+                            (*conf->variable ? "true" : "false"));
+           }
+           break;
+
+       case PGC_INT:
+           {
+               struct config_int *conf = (struct config_int *) gconf;
+
+               do_serialize(destptr, maxbytes, "%d", *conf->variable);
+           }
+           break;
+
+       case PGC_REAL:
+           {
+               struct config_real *conf = (struct config_real *) gconf;
+
+               do_serialize(destptr, maxbytes, "%.*g",
+                            REALTYPE_PRECISION, *conf->variable);
+           }
+           break;
+
+       case PGC_STRING:
+           {
+               struct config_string *conf = (struct config_string *) gconf;
+
+               do_serialize(destptr, maxbytes, "%s", *conf->variable);
+           }
+           break;
+
+       case PGC_ENUM:
+           {
+               struct config_enum *conf = (struct config_enum *) gconf;
+
+               do_serialize(destptr, maxbytes, "%s",
+                        config_enum_lookup_by_value(conf, *conf->variable));
+           }
+           break;
+   }
+
+   do_serialize(destptr, maxbytes, "%s",
+                (gconf->sourcefile ? gconf->sourcefile : ""));
+
+   if (gconf->sourcefile)
+       do_serialize_binary(destptr, maxbytes, &gconf->sourceline,
+                           sizeof(gconf->sourceline));
+
+   do_serialize_binary(destptr, maxbytes, &gconf->source,
+                       sizeof(gconf->source));
+   do_serialize_binary(destptr, maxbytes, &gconf->scontext,
+                       sizeof(gconf->scontext));
+}
+
+/*
+ * SerializeGUCState:
+ * Dumps the complete GUC state onto the memory location at start_address.
+ */
+void
+SerializeGUCState(Size maxsize, char *start_address)
+{
+   char       *curptr;
+   Size        actual_size;
+   Size        bytes_left;
+   int         i;
+   int         i_role;
+
+   /* Reserve space for saving the actual size of the guc state */
+   curptr = start_address + sizeof(actual_size);
+   bytes_left = maxsize - sizeof(actual_size);
+
+   for (i = 0; i < num_guc_variables; i++)
+   {
+       /*
+        * It's pretty ugly, but we've got to force "role" to be initialized
+        * after "session_authorization"; otherwise, the latter will override
+        * the former.
+        */
+       if (strcmp(guc_variables[i]->name, "role") == 0)
+           i_role = i;
+       else
+           serialize_variable(&curptr, &bytes_left, guc_variables[i]);
+   }
+   serialize_variable(&curptr, &bytes_left, guc_variables[i_role]);
+
+   /* Store actual size without assuming alignment of start_address. */
+   actual_size = maxsize - bytes_left - sizeof(actual_size);
+   memcpy(start_address, &actual_size, sizeof(actual_size));
+}
+
+/*
+ * read_gucstate:
+ * Actually it does not read anything, just returns the srcptr. But it does
+ * move the srcptr past the terminating zero byte, so that the caller is ready
+ * to read the next string.
+ */
+static char *
+read_gucstate(char **srcptr, char *srcend)
+{
+   char       *retptr = *srcptr;
+   char       *ptr;
+
+   if (*srcptr >= srcend)
+       elog(ERROR, "incomplete GUC state");
+
+   /* The string variables are all null terminated */
+   for (ptr = *srcptr; ptr < srcend && *ptr != '\0'; ptr++)
+       ;
+
+   if (ptr > srcend)
+       elog(ERROR, "could not find null terminator in GUC state");
+
+   /* Set the new position to the byte following the terminating NUL */
+   *srcptr = ptr + 1;
+
+   return retptr;
+}
+
+/* Binary read version of read_gucstate(). Copies into dest */
+static void
+read_gucstate_binary(char **srcptr, char *srcend, void *dest, Size size)
+{
+   if (*srcptr + size > srcend)
+       elog(ERROR, "incomplete GUC state");
+
+   memcpy(dest, *srcptr, size);
+   *srcptr += size;
+}
+
+/*
+ * RestoreGUCState:
+ * Reads the GUC state at the specified address and updates the GUCs with the
+ * values read from the GUC state.
+ */
+void
+RestoreGUCState(void *gucstate)
+{
+   char       *varname,
+              *varvalue,
+              *varsourcefile;
+   int         varsourceline;
+   GucSource   varsource;
+   GucContext  varscontext;
+   char       *srcptr = (char *) gucstate;
+   char       *srcend;
+   Size        len;
+   int         i;
+
+   /* See comment at can_skip_gucvar(). */
+   for (i = 0; i < num_guc_variables; i++)
+       if (!can_skip_gucvar(guc_variables[i]))
+           InitializeOneGUCOption(guc_variables[i]);
+
+   /* First item is the length of the subsequent data */
+   memcpy(&len, gucstate, sizeof(len));
+
+   srcptr += sizeof(len);
+   srcend = srcptr + len;
+
+   while (srcptr < srcend)
+   {
+       int     result;
+
+       if ((varname = read_gucstate(&srcptr, srcend)) == NULL)
+           break;
+
+       varvalue = read_gucstate(&srcptr, srcend);
+       varsourcefile = read_gucstate(&srcptr, srcend);
+       if (varsourcefile[0])
+           read_gucstate_binary(&srcptr, srcend,
+                                &varsourceline, sizeof(varsourceline));
+       read_gucstate_binary(&srcptr, srcend,
+                            &varsource, sizeof(varsource));
+       read_gucstate_binary(&srcptr, srcend,
+                            &varscontext, sizeof(varscontext));
+
+       result = set_config_option(varname, varvalue, varscontext, varsource,
+                                  GUC_ACTION_SET, true, ERROR, true);
+       if (result <= 0)
+           ereport(ERROR,
+                   (errcode(ERRCODE_INTERNAL_ERROR),
+                    errmsg("parameter \"%s\" could not be set", varname)));
+       if (varsourcefile[0])
+           set_config_sourcefile(varname, varsourcefile, varsourceline);
+   }
+}
 
 /*
  * A little "long argument" simulation, although not quite GNU
@@ -8555,7 +8952,7 @@ ProcessGUCArray(ArrayType *array,
 
        (void) set_config_option(name, value,
                                 context, source,
-                                action, true, 0);
+                                action, true, 0, false);
 
        free(name);
        if (value)
@@ -8858,7 +9255,7 @@ validate_option_array_item(const char *name, const char *value,
    /* test for permissions and valid option value */
    (void) set_config_option(name, value,
                             superuser() ? PGC_SUSET : PGC_USERSET,
-                            PGC_S_TEST, GUC_ACTION_SET, false, 0);
+                            PGC_S_TEST, GUC_ACTION_SET, false, 0, false);
 
    return true;
 }
index 2b2aaf4ac26f6316f6b7685127bc3b0c93f8add3..395858b102297efcbe19b964d29f9ec687841aba 100644 (file)
@@ -339,7 +339,8 @@ extern bool parse_int(const char *value, int *result, int flags,
 extern bool parse_real(const char *value, double *result);
 extern int set_config_option(const char *name, const char *value,
                  GucContext context, GucSource source,
-                 GucAction action, bool changeVal, int elevel);
+                 GucAction action, bool changeVal, int elevel,
+                 bool is_reload);
 extern void AlterSystemSetConfigFile(AlterSystemStmt *setstmt);
 extern char *GetConfigOptionByName(const char *name, const char **varname);
 extern void GetConfigOptionByNum(int varnum, const char **values, bool *noshow);
@@ -363,6 +364,11 @@ extern void write_nondefault_variables(GucContext context);
 extern void read_nondefault_variables(void);
 #endif
 
+/* GUC serialization */
+extern Size EstimateGUCStateSpace(void);
+extern void SerializeGUCState(Size maxsize, char *start_address);
+extern void RestoreGUCState(void *gucstate);
+
 /* Support for messages reported from GUC check hooks */
 
 extern PGDLLIMPORT char *GUC_check_errmsg_string;