]> granicus.if.org Git - postgresql/commitdiff
When restoring GUCs in parallel workers, show an error context.
authorThomas Munro <tmunro@postgresql.org>
Thu, 17 Oct 2019 00:24:50 +0000 (13:24 +1300)
committerThomas Munro <tmunro@postgresql.org>
Thu, 17 Oct 2019 01:00:15 +0000 (14:00 +1300)
Otherwise it can be hard to see where an error is coming from, when
the parallel worker sets all the GUCs that it received from the
leader.  Bug #15726.  Back-patch to 9.5, where RestoreGUCState()
appeared.

Reported-by: Tiago Anastacio
Reviewed-by: Daniel Gustafsson, Tom Lane
Discussion: https://postgr.es/m/15726-6d67e4fa14f027b3%40postgresql.org

src/backend/utils/misc/guc.c

index f0ed326a1b7988e0f4cd6393b68c530175ddaa16..dc8f910ea46bfaac67a36e9081814e00ff9483ec 100644 (file)
@@ -10209,6 +10209,21 @@ read_gucstate_binary(char **srcptr, char *srcend, void *dest, Size size)
        *srcptr += size;
 }
 
+/*
+ * Callback used to add a context message when reporting errors that occur
+ * while trying to restore GUCs in parallel workers.
+ */
+static void
+guc_restore_error_context_callback(void *arg)
+{
+       char      **error_context_name_and_value = (char **) arg;
+
+       if (error_context_name_and_value)
+               errcontext("while setting parameter \"%s\" to \"%s\"",
+                                  error_context_name_and_value[0],
+                                  error_context_name_and_value[1]);
+}
+
 /*
  * RestoreGUCState:
  * Reads the GUC state at the specified address and updates the GUCs with the
@@ -10227,6 +10242,7 @@ RestoreGUCState(void *gucstate)
        char       *srcend;
        Size            len;
        int                     i;
+       ErrorContextCallback error_context_callback;
 
        /* See comment at can_skip_gucvar(). */
        for (i = 0; i < num_guc_variables; i++)
@@ -10239,9 +10255,16 @@ RestoreGUCState(void *gucstate)
        srcptr += sizeof(len);
        srcend = srcptr + len;
 
+       /* If the GUC value check fails, we want errors to show useful context. */
+       error_context_callback.callback = guc_restore_error_context_callback;
+       error_context_callback.previous = error_context_stack;
+       error_context_callback.arg = NULL;
+       error_context_stack = &error_context_callback;
+
        while (srcptr < srcend)
        {
                int                     result;
+               char       *error_context_name_and_value[2];
 
                varname = read_gucstate(&srcptr, srcend);
                varvalue = read_gucstate(&srcptr, srcend);
@@ -10256,6 +10279,9 @@ RestoreGUCState(void *gucstate)
                read_gucstate_binary(&srcptr, srcend,
                                                         &varscontext, sizeof(varscontext));
 
+               error_context_name_and_value[0] = varname;
+               error_context_name_and_value[1] = varvalue;
+               error_context_callback.arg = &error_context_name_and_value[0];
                result = set_config_option(varname, varvalue, varscontext, varsource,
                                                                   GUC_ACTION_SET, true, ERROR, true);
                if (result <= 0)
@@ -10264,7 +10290,10 @@ RestoreGUCState(void *gucstate)
                                         errmsg("parameter \"%s\" could not be set", varname)));
                if (varsourcefile[0])
                        set_config_sourcefile(varname, varsourcefile, varsourceline);
+               error_context_callback.arg = NULL;
        }
+
+       error_context_stack = error_context_callback.previous;
 }
 
 /*