pg.ddx.io pgsql-hackers@postgresql.org mailing list archive
help / color / mirror / Atom feed From: Tomas Vondra <tomas.vondra@2ndquadrant.com>
To: Rafia Sabih <rafia.pghackers@gmail.com>
Cc: Michael Paquier <michael@paquier.xyz>
Cc: John Naylor <john.naylor@2ndquadrant.com>
Cc: Sergei Agalakov <sergei.agalakov@gmail.com>
Cc: PostgreSQL-development <pgsql-hackers@postgresql.org>
Subject: Re: explain plans with information about (modified) gucs
Date: Fri, 29 Mar 2019 22:07:17 +0100
Message-ID: <20190329210717.GD4719@development> (raw )
In-Reply-To: <CA+FpmFcf=mbTShN9NfGMXfMA0QpfdpneU_t7N_BwJnaJ=fshJQ@mail.gmail.com >
References: <5396e093-ed6b-5962-2ed5-337a0425160b@2ndquadrant.com >
<CACPNZCsZ=VA-A+rMjxE4mm9iXcHEz1teMN=QYN8DsWmeHMOMqg@mail.gmail.com >
<f95ff490-672b-032c-6876-2e83661b93bb@2ndquadrant.com >
<CACPNZCuYOk1YtAK8CL5b0N76DV7E8ybmPgp=3Fd3HC3DXMFu4A@mail.gmail.com >
<603089e0-3387-30f1-3cbc-25dd7797e17a@2ndquadrant.com >
<20190204022209.GY1881@paquier.xyz >
<905460bc-db16-112f-1e2c-8dd48667f000@2ndquadrant.com >
<CA+FpmFeBVwVyAxyMd9MX1jD8fUA3Qg96Po6sV+Po57egySKpGQ@mail.gmail.com >
<20190326200453.GA16551@development >
<CA+FpmFcf=mbTShN9NfGMXfMA0QpfdpneU_t7N_BwJnaJ=fshJQ@mail.gmail.com >
On Wed, Mar 27, 2019 at 09:06:04AM +0100, Rafia Sabih wrote:
>On Tue, 26 Mar 2019 at 21:04, Tomas Vondra <tomas.vondra@2ndquadrant.com>
>wrote:
>
>> On Mon, Mar 18, 2019 at 11:31:48AM +0100, Rafia Sabih wrote:
>> >On Sun, 24 Feb 2019 at 00:06, Tomas Vondra <tomas.vondra@2ndquadrant.com>
>> wrote:
>> >>
>> >> Hi,
>> >>
>> >> attached is an updated patch, fixing and slightly tweaking the docs.
>> >>
>> >>
>> >> Barring objections, I'll get this committed later next week.
>> >>
>> >I was having a look at this patch, and this kept me wondering,
>> >
>> >+static void
>> >+ExplainShowSettings(ExplainState *es)
>> >+{
>> >Is there some reason for not providing any explanation above this
>> >function just like the rest of the functions in this file?
>> >
>> >Similarly, for
>> >
>> >struct config_generic **
>> >get_explain_guc_options(int *num)
>> >{
>> >
>> >/* also bail out of there are no options */
>> >+ if (!num)
>> >+ return;
>> >I think you meant 'if' instead if 'of' here.
>>
>> Thanks for the review - attached is a patch adding the missing comments,
>> and doing two additional minor improvements:
>>
>> 1) Renaming ExplainShowSettings to ExplainPrintSettings, to make it more
>> consistent with naming of the other functions in explain.c.
>>
>> 2) Actually counting GUC_EXPLAIN options, and only allocating space for
>> those in get_explain_guc_options, instead of using num_guc_variables. The
>> diffrence is quite significant (~50 vs. ~300), and considering each entry
>> is 8B it makes a difference because such large chunks tend to have higher
>> palloc overhed (due to ALLOCSET_SEPARATE_THRESHOLD).
>>
>>
> Looks like the patch is in need of a rebase.
>At commit: 1983af8e899389187026cb34c1ca9d89ea986120
>
>P.S. reject files attached.
>
D'oh! That was a stupid mistake - I apparently attched just the delta against
the previous patch version, i.e. the improvements I described. Attaches is a
correct (and complete) patch.
I planned to get this committed today, but considering this I'll wait until
early next week to allow for feedback.
regards
--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c
index 7b22927674..edc50f9368 100644
--- a/contrib/auto_explain/auto_explain.c
+++ b/contrib/auto_explain/auto_explain.c
@@ -28,6 +28,7 @@ static bool auto_explain_log_verbose = false;
static bool auto_explain_log_buffers = false;
static bool auto_explain_log_triggers = false;
static bool auto_explain_log_timing = true;
+static bool auto_explain_log_settings = false;
static int auto_explain_log_format = EXPLAIN_FORMAT_TEXT;
static int auto_explain_log_level = LOG;
static bool auto_explain_log_nested_statements = false;
@@ -112,6 +113,17 @@ _PG_init(void)
NULL,
NULL);
+ DefineCustomBoolVariable("auto_explain.log_settings",
+ "Log modified configuration parameters affecting query planning.",
+ NULL,
+ &auto_explain_log_settings,
+ false,
+ PGC_SUSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+
DefineCustomBoolVariable("auto_explain.log_verbose",
"Use EXPLAIN VERBOSE for plan logging.",
NULL,
@@ -356,6 +368,7 @@ explain_ExecutorEnd(QueryDesc *queryDesc)
es->timing = (es->analyze && auto_explain_log_timing);
es->summary = es->analyze;
es->format = auto_explain_log_format;
+ es->settings = auto_explain_log_settings;
ExplainBeginOutput(es);
ExplainQueryText(es, queryDesc);
diff --git a/doc/src/sgml/auto-explain.sgml b/doc/src/sgml/auto-explain.sgml
index 120b168d45..296ae2de80 100644
--- a/doc/src/sgml/auto-explain.sgml
+++ b/doc/src/sgml/auto-explain.sgml
@@ -169,6 +169,24 @@ LOAD 'auto_explain';
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <varname>auto_explain.log_settings</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>auto_explain.log_settings</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ <varname>auto_explain.log_settings</varname> controls whether information
+ about modified configuration options affecting query planning are logged
+ with the execution plan. Only options affecting query planning with value
+ different from the built-in default value are considered. This parameter is
+ off by default. Only superusers can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term>
<varname>auto_explain.log_format</varname> (<type>enum</type>)
diff --git a/doc/src/sgml/ref/explain.sgml b/doc/src/sgml/ref/explain.sgml
index 8dc0d7038a..385d10411f 100644
--- a/doc/src/sgml/ref/explain.sgml
+++ b/doc/src/sgml/ref/explain.sgml
@@ -39,6 +39,7 @@ EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replac
ANALYZE [ <replaceable class="parameter">boolean</replaceable> ]
VERBOSE [ <replaceable class="parameter">boolean</replaceable> ]
COSTS [ <replaceable class="parameter">boolean</replaceable> ]
+ SETTINGS [ <replaceable class="parameter">boolean</replaceable> ]
BUFFERS [ <replaceable class="parameter">boolean</replaceable> ]
TIMING [ <replaceable class="parameter">boolean</replaceable> ]
SUMMARY [ <replaceable class="parameter">boolean</replaceable> ]
@@ -152,6 +153,17 @@ ROLLBACK;
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>SETTINGS</literal></term>
+ <listitem>
+ <para>
+ Include information on configuration parameters. Specifically, include
+ options affecting query planning with value different from the built-in
+ default value. This parameter defaults to <literal>FALSE</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>BUFFERS</literal></term>
<listitem>
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 1831ea81cf..2a289b8b94 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -29,6 +29,7 @@
#include "storage/bufmgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
+#include "utils/guc_tables.h"
#include "utils/json.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -162,6 +163,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString,
es->costs = defGetBoolean(opt);
else if (strcmp(opt->defname, "buffers") == 0)
es->buffers = defGetBoolean(opt);
+ else if (strcmp(opt->defname, "settings") == 0)
+ es->settings = defGetBoolean(opt);
else if (strcmp(opt->defname, "timing") == 0)
{
timing_set = true;
@@ -596,6 +599,72 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
ExplainCloseGroup("Query", NULL, true, es);
}
+/*
+ * ExplainPrintSettings -
+ * Print summary of modified settings affecting query planning.
+ */
+static void
+ExplainPrintSettings(ExplainState *es)
+{
+ int num;
+ struct config_generic **gucs;
+
+ /* bail out if GUC information not requested */
+ if (!es->settings)
+ return;
+
+ gucs = get_explain_guc_options(&num);
+
+ /* also bail out of there are no options */
+ if (!num)
+ return;
+
+ if (es->format != EXPLAIN_FORMAT_TEXT)
+ {
+ int i;
+
+ ExplainOpenGroup("Settings", "Settings", false, es);
+
+ for (i = 0; i < num; i++)
+ {
+ char *setting;
+ struct config_generic *conf = gucs[i];
+
+ setting = GetConfigOptionByName(conf->name, NULL, true);
+
+ ExplainPropertyText(conf->name, setting, es);
+ }
+
+ ExplainCloseGroup("Settings", "Settings", false, es);
+ }
+ else
+ {
+ int i;
+ StringInfoData str;
+
+ initStringInfo(&str);
+
+ for (i = 0; i < num; i++)
+ {
+ char *setting;
+ struct config_generic *conf = gucs[i];
+
+ if (i > 0)
+ appendStringInfoString(&str, ", ");
+
+ setting = GetConfigOptionByName(conf->name, NULL, true);
+
+ if (setting)
+ appendStringInfo(&str, "%s = '%s'", conf->name, setting);
+ else
+ appendStringInfo(&str, "%s = NULL", conf->name);
+ }
+
+ if (num > 0)
+ ExplainPropertyText("Settings", str.data, es);
+ }
+}
+
/*
* ExplainPrintPlan -
* convert a QueryDesc's plan tree to text and append it to es->str
@@ -633,6 +702,12 @@ ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
ps = outerPlanState(ps);
ExplainNode(ps, NIL, NULL, NULL, es);
+
+ /*
+ * If requested, include information about GUC parameters with values
+ * that don't match the built-in defaults.
+ */
+ ExplainPrintSettings(es);
}
/*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index aa564d153a..39f844ebc5 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -881,7 +881,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of sequential-scan plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_seqscan,
true,
@@ -890,7 +891,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_indexscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of index-scan plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_indexscan,
true,
@@ -899,7 +901,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_indexonlyscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of index-only-scan plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_indexonlyscan,
true,
@@ -908,7 +911,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_bitmapscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of bitmap-scan plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_bitmapscan,
true,
@@ -917,7 +921,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_tidscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of TID scan plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_tidscan,
true,
@@ -926,7 +931,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_sort", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of explicit sort steps."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_sort,
true,
@@ -935,7 +941,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_hashagg", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of hashed aggregation plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_hashagg,
true,
@@ -944,7 +951,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_material", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of materialization."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_material,
true,
@@ -953,7 +961,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_nestloop", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of nested-loop join plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_nestloop,
true,
@@ -962,7 +971,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_mergejoin", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of merge join plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_mergejoin,
true,
@@ -971,7 +981,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_hashjoin", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of hash join plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_hashjoin,
true,
@@ -980,7 +991,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_gathermerge", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of gather merge plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_gathermerge,
true,
@@ -989,7 +1001,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_partitionwise_join", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables partitionwise join."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_partitionwise_join,
false,
@@ -998,7 +1011,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_partitionwise_aggregate", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables partitionwise aggregation and grouping."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_partitionwise_aggregate,
false,
@@ -1007,7 +1021,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_parallel_append", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of parallel append plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_parallel_append,
true,
@@ -1016,7 +1031,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_parallel_hash", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of parallel hash plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_parallel_hash,
true,
@@ -1027,7 +1043,8 @@ static struct config_bool ConfigureNamesBool[] =
gettext_noop("Enable plan-time and run-time partition pruning."),
gettext_noop("Allows the query planner and executor to compare partition "
"bounds to conditions in the query to determine which "
- "partitions must be scanned.")
+ "partitions must be scanned."),
+ GUC_EXPLAIN
},
&enable_partition_pruning,
true,
@@ -1037,7 +1054,8 @@ static struct config_bool ConfigureNamesBool[] =
{"geqo", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("Enables genetic query optimization."),
gettext_noop("This algorithm attempts to do planning without "
- "exhaustive searching.")
+ "exhaustive searching."),
+ GUC_EXPLAIN
},
&enable_geqo,
true,
@@ -1625,7 +1643,7 @@ static struct config_bool ConfigureNamesBool[] =
"optimize_bounded_sort", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enable bounded sorting using heap sort."),
NULL,
- GUC_NOT_IN_SAMPLE
+ GUC_NOT_IN_SAMPLE | GUC_EXPLAIN
},
&optimize_bounded_sort,
true,
@@ -1816,7 +1834,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"parallel_leader_participation", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
gettext_noop("Controls whether Gather and Gather Merge also run subplans."),
- gettext_noop("Should gather nodes also run subplans, or just gather tuples?")
+ gettext_noop("Should gather nodes also run subplans, or just gather tuples?"),
+ GUC_EXPLAIN
},
¶llel_leader_participation,
true,
@@ -1826,7 +1845,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"jit", PGC_USERSET, QUERY_TUNING_OTHER,
gettext_noop("Allow JIT compilation."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&jit_enabled,
true,
@@ -1955,7 +1975,8 @@ static struct config_int ConfigureNamesInt[] =
"are not collapsed."),
gettext_noop("The planner will merge subqueries into upper "
"queries if the resulting FROM list would have no more than "
- "this many items.")
+ "this many items."),
+ GUC_EXPLAIN
},
&from_collapse_limit,
8, 1, INT_MAX,
@@ -1967,7 +1988,8 @@ static struct config_int ConfigureNamesInt[] =
"constructs are not flattened."),
gettext_noop("The planner will flatten explicit JOIN "
"constructs into lists of FROM items whenever a "
- "list of no more than this many items would result.")
+ "list of no more than this many items would result."),
+ GUC_EXPLAIN
},
&join_collapse_limit,
8, 1, INT_MAX,
@@ -1976,7 +1998,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"geqo_threshold", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("Sets the threshold of FROM items beyond which GEQO is used."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&geqo_threshold,
12, 2, INT_MAX,
@@ -1985,7 +2008,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"geqo_effort", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("GEQO: effort is used to set the default for other GEQO parameters."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&Geqo_effort,
DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT,
@@ -1994,7 +2018,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"geqo_pool_size", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("GEQO: number of individuals in the population."),
- gettext_noop("Zero selects a suitable default value.")
+ gettext_noop("Zero selects a suitable default value."),
+ GUC_EXPLAIN
},
&Geqo_pool_size,
0, 0, INT_MAX,
@@ -2003,7 +2028,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"geqo_generations", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("GEQO: number of iterations of the algorithm."),
- gettext_noop("Zero selects a suitable default value.")
+ gettext_noop("Zero selects a suitable default value."),
+ GUC_EXPLAIN
},
&Geqo_generations,
0, 0, INT_MAX,
@@ -2117,7 +2143,7 @@ static struct config_int ConfigureNamesInt[] =
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
NULL,
- GUC_UNIT_BLOCKS
+ GUC_UNIT_BLOCKS | GUC_EXPLAIN
},
&num_temp_buffers,
1024, 100, INT_MAX / 2,
@@ -2184,7 +2210,7 @@ static struct config_int ConfigureNamesInt[] =
gettext_noop("This much memory can be used by each internal "
"sort operation and hash table before switching to "
"temporary disk files."),
- GUC_UNIT_KB
+ GUC_UNIT_KB | GUC_EXPLAIN
},
&work_mem,
4096, 64, MAX_KILOBYTES,
@@ -2713,7 +2739,8 @@ static struct config_int ConfigureNamesInt[] =
PGC_USERSET,
RESOURCES_ASYNCHRONOUS,
gettext_noop("Number of simultaneous requests that can be handled efficiently by the disk subsystem."),
- gettext_noop("For RAID arrays, this should be approximately the number of drive spindles in the array.")
+ gettext_noop("For RAID arrays, this should be approximately the number of drive spindles in the array."),
+ GUC_EXPLAIN
},
&effective_io_concurrency,
#ifdef USE_PREFETCH
@@ -2958,7 +2985,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"max_parallel_workers_per_gather", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
gettext_noop("Sets the maximum number of parallel processes per executor node."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&max_parallel_workers_per_gather,
2, 0, MAX_PARALLEL_WORKER_LIMIT,
@@ -2968,7 +2996,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"max_parallel_workers", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
gettext_noop("Sets the maximum number of parallel workers that can be active at one time."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&max_parallel_workers,
8, 0, MAX_PARALLEL_WORKER_LIMIT,
@@ -3058,7 +3087,7 @@ static struct config_int ConfigureNamesInt[] =
gettext_noop("Sets the planner's assumption about the total size of the data caches."),
gettext_noop("That is, the total size of the caches (kernel cache and shared buffers) used for PostgreSQL data files. "
"This is measured in disk pages, which are normally 8 kB each."),
- GUC_UNIT_BLOCKS,
+ GUC_UNIT_BLOCKS | GUC_EXPLAIN,
},
&effective_cache_size,
DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX,
@@ -3069,7 +3098,7 @@ static struct config_int ConfigureNamesInt[] =
{"min_parallel_table_scan_size", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the minimum amount of table data for a parallel scan."),
gettext_noop("If the planner estimates that it will read a number of table pages too small to reach this limit, a parallel scan will not be considered."),
- GUC_UNIT_BLOCKS,
+ GUC_UNIT_BLOCKS | GUC_EXPLAIN,
},
&min_parallel_table_scan_size,
(8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3,
@@ -3080,7 +3109,7 @@ static struct config_int ConfigureNamesInt[] =
{"min_parallel_index_scan_size", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the minimum amount of index data for a parallel scan."),
gettext_noop("If the planner estimates that it will read a number of index pages too small to reach this limit, a parallel scan will not be considered."),
- GUC_UNIT_BLOCKS,
+ GUC_UNIT_BLOCKS | GUC_EXPLAIN,
},
&min_parallel_index_scan_size,
(512 * 1024) / BLCKSZ, 0, INT_MAX / 3,
@@ -3145,7 +3174,8 @@ static struct config_real ConfigureNamesReal[] =
{"seq_page_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of a "
"sequentially fetched disk page."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&seq_page_cost,
DEFAULT_SEQ_PAGE_COST, 0, DBL_MAX,
@@ -3155,7 +3185,8 @@ static struct config_real ConfigureNamesReal[] =
{"random_page_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of a "
"nonsequentially fetched disk page."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&random_page_cost,
DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX,
@@ -3165,7 +3196,8 @@ static struct config_real ConfigureNamesReal[] =
{"cpu_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of "
"processing each tuple (row)."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&cpu_tuple_cost,
DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX,
@@ -3175,7 +3207,8 @@ static struct config_real ConfigureNamesReal[] =
{"cpu_index_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of "
"processing each index entry during an index scan."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&cpu_index_tuple_cost,
DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX,
@@ -3185,7 +3218,8 @@ static struct config_real ConfigureNamesReal[] =
{"cpu_operator_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of "
"processing each operator or function call."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&cpu_operator_cost,
DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX,
@@ -3195,7 +3229,8 @@ static struct config_real ConfigureNamesReal[] =
{"parallel_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of "
"passing each tuple (row) from worker to master backend."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
¶llel_tuple_cost,
DEFAULT_PARALLEL_TUPLE_COST, 0, DBL_MAX,
@@ -3205,7 +3240,8 @@ static struct config_real ConfigureNamesReal[] =
{"parallel_setup_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of "
"starting up worker processes for parallel query."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
¶llel_setup_cost,
DEFAULT_PARALLEL_SETUP_COST, 0, DBL_MAX,
@@ -3215,7 +3251,8 @@ static struct config_real ConfigureNamesReal[] =
{
{"jit_above_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Perform JIT compilation if query is more expensive."),
- gettext_noop("-1 disables JIT compilation.")
+ gettext_noop("-1 disables JIT compilation."),
+ GUC_EXPLAIN
},
&jit_above_cost,
100000, -1, DBL_MAX,
@@ -3225,7 +3262,8 @@ static struct config_real ConfigureNamesReal[] =
{
{"jit_optimize_above_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Optimize JITed functions if query is more expensive."),
- gettext_noop("-1 disables optimization.")
+ gettext_noop("-1 disables optimization."),
+ GUC_EXPLAIN
},
&jit_optimize_above_cost,
500000, -1, DBL_MAX,
@@ -3235,7 +3273,8 @@ static struct config_real ConfigureNamesReal[] =
{
{"jit_inline_above_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Perform JIT inlining if query is more expensive."),
- gettext_noop("-1 disables inlining.")
+ gettext_noop("-1 disables inlining."),
+ GUC_EXPLAIN
},
&jit_inline_above_cost,
500000, -1, DBL_MAX,
@@ -3246,7 +3285,8 @@ static struct config_real ConfigureNamesReal[] =
{"cursor_tuple_fraction", PGC_USERSET, QUERY_TUNING_OTHER,
gettext_noop("Sets the planner's estimate of the fraction of "
"a cursor's rows that will be retrieved."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&cursor_tuple_fraction,
DEFAULT_CURSOR_TUPLE_FRACTION, 0.0, 1.0,
@@ -3256,7 +3296,8 @@ static struct config_real ConfigureNamesReal[] =
{
{"geqo_selection_bias", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("GEQO: selective pressure within the population."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&Geqo_selection_bias,
DEFAULT_GEQO_SELECTION_BIAS,
@@ -3266,7 +3307,8 @@ static struct config_real ConfigureNamesReal[] =
{
{"geqo_seed", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("GEQO: seed for random path selection."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&Geqo_seed,
0.0, 0.0, 1.0,
@@ -3714,7 +3756,7 @@ static struct config_string ConfigureNamesString[] =
{"search_path", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the schema search order for names that are not schema-qualified."),
NULL,
- GUC_LIST_INPUT | GUC_LIST_QUOTE
+ GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_EXPLAIN
},
&namespace_search_path,
"\"$user\", public",
@@ -4167,7 +4209,8 @@ static struct config_enum ConfigureNamesEnum[] =
{"constraint_exclusion", PGC_USERSET, QUERY_TUNING_OTHER,
gettext_noop("Enables the planner to use constraints to optimize queries."),
gettext_noop("Table scans will be skipped if their constraints"
- " guarantee that no rows match the query.")
+ " guarantee that no rows match the query."),
+ GUC_EXPLAIN
},
&constraint_exclusion,
CONSTRAINT_EXCLUSION_PARTITION, constraint_exclusion_options,
@@ -4403,7 +4446,8 @@ static struct config_enum ConfigureNamesEnum[] =
{
{"force_parallel_mode", PGC_USERSET, QUERY_TUNING_OTHER,
gettext_noop("Forces use of parallel query facilities."),
- gettext_noop("If possible, run query using a parallel worker and with parallel restrictions.")
+ gettext_noop("If possible, run query using a parallel worker and with parallel restrictions."),
+ GUC_EXPLAIN
},
&force_parallel_mode,
FORCE_PARALLEL_OFF, force_parallel_mode_options,
@@ -4427,7 +4471,8 @@ static struct config_enum ConfigureNamesEnum[] =
gettext_noop("Controls the planner's selection of custom or generic plan."),
gettext_noop("Prepared statements can have custom and generic plans, and the planner "
"will attempt to choose which is better. This can be set to override "
- "the default behavior.")
+ "the default behavior."),
+ GUC_EXPLAIN
},
&plan_cache_mode,
PLAN_CACHE_MODE_AUTO, plan_cache_mode_options,
@@ -4487,6 +4532,7 @@ static struct config_generic **guc_variables;
/* Current number of variables contained in the vector */
static int num_guc_variables;
+static int num_guc_explain_variables;
/* Vector capacity */
static int size_guc_variables;
@@ -4751,6 +4797,7 @@ build_guc_variables(void)
{
int size_vars;
int num_vars = 0;
+ int num_explain_vars = 0;
struct config_generic **guc_vars;
int i;
@@ -4761,6 +4808,9 @@ build_guc_variables(void)
/* Rather than requiring vartype to be filled in by hand, do this: */
conf->gen.vartype = PGC_BOOL;
num_vars++;
+
+ if (conf->gen.flags & GUC_EXPLAIN)
+ num_explain_vars++;
}
for (i = 0; ConfigureNamesInt[i].gen.name; i++)
@@ -4769,6 +4819,9 @@ build_guc_variables(void)
conf->gen.vartype = PGC_INT;
num_vars++;
+
+ if (conf->gen.flags & GUC_EXPLAIN)
+ num_explain_vars++;
}
for (i = 0; ConfigureNamesReal[i].gen.name; i++)
@@ -4777,6 +4830,9 @@ build_guc_variables(void)
conf->gen.vartype = PGC_REAL;
num_vars++;
+
+ if (conf->gen.flags & GUC_EXPLAIN)
+ num_explain_vars++;
}
for (i = 0; ConfigureNamesString[i].gen.name; i++)
@@ -4785,6 +4841,9 @@ build_guc_variables(void)
conf->gen.vartype = PGC_STRING;
num_vars++;
+
+ if (conf->gen.flags & GUC_EXPLAIN)
+ num_explain_vars++;
}
for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
@@ -4793,6 +4852,9 @@ build_guc_variables(void)
conf->gen.vartype = PGC_ENUM;
num_vars++;
+
+ if (conf->gen.flags & GUC_EXPLAIN)
+ num_explain_vars++;
}
/*
@@ -4824,6 +4886,7 @@ build_guc_variables(void)
free(guc_variables);
guc_variables = guc_vars;
num_guc_variables = num_vars;
+ num_guc_explain_variables = num_explain_vars;
size_guc_variables = size_vars;
qsort((void *) guc_variables, num_guc_variables,
sizeof(struct config_generic *), guc_var_compare);
@@ -8774,6 +8837,99 @@ ShowAllGUCConfig(DestReceiver *dest)
end_tup_output(tstate);
}
+/*
+ * Returns an array of modified GUC options to show in EXPLAIN. Only options
+ * related to query planning (marked with GUC_EXPLAIN), with values different
+ * from built-in defaults.
+ */
+struct config_generic **
+get_explain_guc_options(int *num)
+{
+ int i;
+ struct config_generic **result;
+
+ *num = 0;
+
+ /*
+ * Allocate enough space to fit all GUC_EXPLAIN options. We may not
+ * need all the space, but there are fairly few such options so we
+ * don't waste a lot of memory.
+ */
+ result = palloc(sizeof(struct config_generic *) * num_guc_explain_variables);
+
+ for (i = 0; i < num_guc_variables; i++)
+ {
+ bool modified;
+ struct config_generic *conf = guc_variables[i];
+
+ /* return only options visible to the user */
+ if ((conf->flags & GUC_NO_SHOW_ALL) ||
+ ((conf->flags & GUC_SUPERUSER_ONLY) &&
+ !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)))
+ continue;
+
+ /* only parameters explicitly marked for inclusion in explain */
+ if (!(conf->flags & GUC_EXPLAIN))
+ continue;
+
+ /* return only options that were modified (w.r.t. config file) */
+ modified = false;
+
+ switch (conf->vartype)
+ {
+ case PGC_BOOL:
+ {
+ struct config_bool *lconf = (struct config_bool *) conf;
+ modified = (lconf->boot_val != *(lconf->variable));
+ }
+ break;
+
+ case PGC_INT:
+ {
+ struct config_int *lconf = (struct config_int *) conf;
+ modified = (lconf->boot_val != *(lconf->variable));
+ }
+ break;
+
+ case PGC_REAL:
+ {
+ struct config_real *lconf = (struct config_real *) conf;
+ modified = (lconf->boot_val != *(lconf->variable));
+ }
+ break;
+
+ case PGC_STRING:
+ {
+ struct config_string *lconf = (struct config_string *) conf;
+ modified = (strcmp(lconf->boot_val, *(lconf->variable)) != 0);
+ }
+ break;
+
+ case PGC_ENUM:
+ {
+ struct config_enum *lconf = (struct config_enum *) conf;
+ modified = (lconf->boot_val != *(lconf->variable));
+ }
+ break;
+
+ default:
+ elog(ERROR, "unexcpected GUC type: %d", conf->vartype);
+ }
+
+ /* skip GUC variables that match the built-in default */
+ if (!modified)
+ continue;
+
+ /* assign to the values array */
+ result[*num] = conf;
+ *num = *num + 1;
+
+ Assert(*num <= num_guc_explain_variables);
+ }
+
+ return result;
+}
+
/*
* Return GUC variable value by name; optionally return canonical form of
* name. If the GUC is unset, then throw an error unless missing_ok is true,
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
index e8854db459..db48f29501 100644
--- a/src/include/commands/explain.h
+++ b/src/include/commands/explain.h
@@ -35,6 +35,7 @@ typedef struct ExplainState
bool buffers; /* print buffer usage */
bool timing; /* print detailed node timing */
bool summary; /* print total planning and execution timing */
+ bool settings; /* print modified settings */
ExplainFormat format; /* output format */
/* state for output formatting --- not reset for each new plan tree */
int indent; /* current indentation level */
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 2712a774f7..f73edc3edc 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -227,6 +227,8 @@ typedef enum
#define GUC_UNIT_MIN 0x30000 /* value is in minutes */
#define GUC_UNIT_TIME 0xF0000 /* mask for time-related units */
+#define GUC_EXPLAIN 0x100000 /* include in explain */
+
#define GUC_UNIT (GUC_UNIT_MEMORY | GUC_UNIT_TIME)
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index a0970b2e1c..2a74b30b2f 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -267,5 +267,6 @@ extern void build_guc_variables(void);
extern const char *config_enum_lookup_by_value(struct config_enum *record, int val);
extern bool config_enum_lookup_by_name(struct config_enum *record,
const char *value, int *retval);
+extern struct config_generic **get_explain_guc_options(int *num);
#endif /* GUC_TABLES_H */
Attachments:
[text/plain] explain-with-settings-20190329.patch (30.1K, ../20190329210717.GD4719@development/2-explain-with-settings-20190329.patch)
download | inline diff:
diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c
index 7b22927674..edc50f9368 100644
--- a/contrib/auto_explain/auto_explain.c
+++ b/contrib/auto_explain/auto_explain.c
@@ -28,6 +28,7 @@ static bool auto_explain_log_verbose = false;
static bool auto_explain_log_buffers = false;
static bool auto_explain_log_triggers = false;
static bool auto_explain_log_timing = true;
+static bool auto_explain_log_settings = false;
static int auto_explain_log_format = EXPLAIN_FORMAT_TEXT;
static int auto_explain_log_level = LOG;
static bool auto_explain_log_nested_statements = false;
@@ -112,6 +113,17 @@ _PG_init(void)
NULL,
NULL);
+ DefineCustomBoolVariable("auto_explain.log_settings",
+ "Log modified configuration parameters affecting query planning.",
+ NULL,
+ &auto_explain_log_settings,
+ false,
+ PGC_SUSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+
DefineCustomBoolVariable("auto_explain.log_verbose",
"Use EXPLAIN VERBOSE for plan logging.",
NULL,
@@ -356,6 +368,7 @@ explain_ExecutorEnd(QueryDesc *queryDesc)
es->timing = (es->analyze && auto_explain_log_timing);
es->summary = es->analyze;
es->format = auto_explain_log_format;
+ es->settings = auto_explain_log_settings;
ExplainBeginOutput(es);
ExplainQueryText(es, queryDesc);
diff --git a/doc/src/sgml/auto-explain.sgml b/doc/src/sgml/auto-explain.sgml
index 120b168d45..296ae2de80 100644
--- a/doc/src/sgml/auto-explain.sgml
+++ b/doc/src/sgml/auto-explain.sgml
@@ -169,6 +169,24 @@ LOAD 'auto_explain';
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <varname>auto_explain.log_settings</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>auto_explain.log_settings</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ <varname>auto_explain.log_settings</varname> controls whether information
+ about modified configuration options affecting query planning are logged
+ with the execution plan. Only options affecting query planning with value
+ different from the built-in default value are considered. This parameter is
+ off by default. Only superusers can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term>
<varname>auto_explain.log_format</varname> (<type>enum</type>)
diff --git a/doc/src/sgml/ref/explain.sgml b/doc/src/sgml/ref/explain.sgml
index 8dc0d7038a..385d10411f 100644
--- a/doc/src/sgml/ref/explain.sgml
+++ b/doc/src/sgml/ref/explain.sgml
@@ -39,6 +39,7 @@ EXPLAIN [ ANALYZE ] [ VERBOSE ] <replaceable class="parameter">statement</replac
ANALYZE [ <replaceable class="parameter">boolean</replaceable> ]
VERBOSE [ <replaceable class="parameter">boolean</replaceable> ]
COSTS [ <replaceable class="parameter">boolean</replaceable> ]
+ SETTINGS [ <replaceable class="parameter">boolean</replaceable> ]
BUFFERS [ <replaceable class="parameter">boolean</replaceable> ]
TIMING [ <replaceable class="parameter">boolean</replaceable> ]
SUMMARY [ <replaceable class="parameter">boolean</replaceable> ]
@@ -152,6 +153,17 @@ ROLLBACK;
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>SETTINGS</literal></term>
+ <listitem>
+ <para>
+ Include information on configuration parameters. Specifically, include
+ options affecting query planning with value different from the built-in
+ default value. This parameter defaults to <literal>FALSE</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>BUFFERS</literal></term>
<listitem>
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 1831ea81cf..2a289b8b94 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -29,6 +29,7 @@
#include "storage/bufmgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
+#include "utils/guc_tables.h"
#include "utils/json.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -162,6 +163,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString,
es->costs = defGetBoolean(opt);
else if (strcmp(opt->defname, "buffers") == 0)
es->buffers = defGetBoolean(opt);
+ else if (strcmp(opt->defname, "settings") == 0)
+ es->settings = defGetBoolean(opt);
else if (strcmp(opt->defname, "timing") == 0)
{
timing_set = true;
@@ -596,6 +599,72 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
ExplainCloseGroup("Query", NULL, true, es);
}
+/*
+ * ExplainPrintSettings -
+ * Print summary of modified settings affecting query planning.
+ */
+static void
+ExplainPrintSettings(ExplainState *es)
+{
+ int num;
+ struct config_generic **gucs;
+
+ /* bail out if GUC information not requested */
+ if (!es->settings)
+ return;
+
+ gucs = get_explain_guc_options(&num);
+
+ /* also bail out of there are no options */
+ if (!num)
+ return;
+
+ if (es->format != EXPLAIN_FORMAT_TEXT)
+ {
+ int i;
+
+ ExplainOpenGroup("Settings", "Settings", false, es);
+
+ for (i = 0; i < num; i++)
+ {
+ char *setting;
+ struct config_generic *conf = gucs[i];
+
+ setting = GetConfigOptionByName(conf->name, NULL, true);
+
+ ExplainPropertyText(conf->name, setting, es);
+ }
+
+ ExplainCloseGroup("Settings", "Settings", false, es);
+ }
+ else
+ {
+ int i;
+ StringInfoData str;
+
+ initStringInfo(&str);
+
+ for (i = 0; i < num; i++)
+ {
+ char *setting;
+ struct config_generic *conf = gucs[i];
+
+ if (i > 0)
+ appendStringInfoString(&str, ", ");
+
+ setting = GetConfigOptionByName(conf->name, NULL, true);
+
+ if (setting)
+ appendStringInfo(&str, "%s = '%s'", conf->name, setting);
+ else
+ appendStringInfo(&str, "%s = NULL", conf->name);
+ }
+
+ if (num > 0)
+ ExplainPropertyText("Settings", str.data, es);
+ }
+}
+
/*
* ExplainPrintPlan -
* convert a QueryDesc's plan tree to text and append it to es->str
@@ -633,6 +702,12 @@ ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
ps = outerPlanState(ps);
ExplainNode(ps, NIL, NULL, NULL, es);
+
+ /*
+ * If requested, include information about GUC parameters with values
+ * that don't match the built-in defaults.
+ */
+ ExplainPrintSettings(es);
}
/*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index aa564d153a..39f844ebc5 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -881,7 +881,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of sequential-scan plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_seqscan,
true,
@@ -890,7 +891,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_indexscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of index-scan plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_indexscan,
true,
@@ -899,7 +901,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_indexonlyscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of index-only-scan plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_indexonlyscan,
true,
@@ -908,7 +911,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_bitmapscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of bitmap-scan plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_bitmapscan,
true,
@@ -917,7 +921,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_tidscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of TID scan plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_tidscan,
true,
@@ -926,7 +931,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_sort", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of explicit sort steps."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_sort,
true,
@@ -935,7 +941,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_hashagg", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of hashed aggregation plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_hashagg,
true,
@@ -944,7 +951,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_material", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of materialization."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_material,
true,
@@ -953,7 +961,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_nestloop", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of nested-loop join plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_nestloop,
true,
@@ -962,7 +971,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_mergejoin", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of merge join plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_mergejoin,
true,
@@ -971,7 +981,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_hashjoin", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of hash join plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_hashjoin,
true,
@@ -980,7 +991,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_gathermerge", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of gather merge plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_gathermerge,
true,
@@ -989,7 +1001,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_partitionwise_join", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables partitionwise join."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_partitionwise_join,
false,
@@ -998,7 +1011,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_partitionwise_aggregate", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables partitionwise aggregation and grouping."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_partitionwise_aggregate,
false,
@@ -1007,7 +1021,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_parallel_append", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of parallel append plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_parallel_append,
true,
@@ -1016,7 +1031,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"enable_parallel_hash", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of parallel hash plans."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&enable_parallel_hash,
true,
@@ -1027,7 +1043,8 @@ static struct config_bool ConfigureNamesBool[] =
gettext_noop("Enable plan-time and run-time partition pruning."),
gettext_noop("Allows the query planner and executor to compare partition "
"bounds to conditions in the query to determine which "
- "partitions must be scanned.")
+ "partitions must be scanned."),
+ GUC_EXPLAIN
},
&enable_partition_pruning,
true,
@@ -1037,7 +1054,8 @@ static struct config_bool ConfigureNamesBool[] =
{"geqo", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("Enables genetic query optimization."),
gettext_noop("This algorithm attempts to do planning without "
- "exhaustive searching.")
+ "exhaustive searching."),
+ GUC_EXPLAIN
},
&enable_geqo,
true,
@@ -1625,7 +1643,7 @@ static struct config_bool ConfigureNamesBool[] =
"optimize_bounded_sort", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enable bounded sorting using heap sort."),
NULL,
- GUC_NOT_IN_SAMPLE
+ GUC_NOT_IN_SAMPLE | GUC_EXPLAIN
},
&optimize_bounded_sort,
true,
@@ -1816,7 +1834,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"parallel_leader_participation", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
gettext_noop("Controls whether Gather and Gather Merge also run subplans."),
- gettext_noop("Should gather nodes also run subplans, or just gather tuples?")
+ gettext_noop("Should gather nodes also run subplans, or just gather tuples?"),
+ GUC_EXPLAIN
},
¶llel_leader_participation,
true,
@@ -1826,7 +1845,8 @@ static struct config_bool ConfigureNamesBool[] =
{
{"jit", PGC_USERSET, QUERY_TUNING_OTHER,
gettext_noop("Allow JIT compilation."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&jit_enabled,
true,
@@ -1955,7 +1975,8 @@ static struct config_int ConfigureNamesInt[] =
"are not collapsed."),
gettext_noop("The planner will merge subqueries into upper "
"queries if the resulting FROM list would have no more than "
- "this many items.")
+ "this many items."),
+ GUC_EXPLAIN
},
&from_collapse_limit,
8, 1, INT_MAX,
@@ -1967,7 +1988,8 @@ static struct config_int ConfigureNamesInt[] =
"constructs are not flattened."),
gettext_noop("The planner will flatten explicit JOIN "
"constructs into lists of FROM items whenever a "
- "list of no more than this many items would result.")
+ "list of no more than this many items would result."),
+ GUC_EXPLAIN
},
&join_collapse_limit,
8, 1, INT_MAX,
@@ -1976,7 +1998,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"geqo_threshold", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("Sets the threshold of FROM items beyond which GEQO is used."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&geqo_threshold,
12, 2, INT_MAX,
@@ -1985,7 +2008,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"geqo_effort", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("GEQO: effort is used to set the default for other GEQO parameters."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&Geqo_effort,
DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT,
@@ -1994,7 +2018,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"geqo_pool_size", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("GEQO: number of individuals in the population."),
- gettext_noop("Zero selects a suitable default value.")
+ gettext_noop("Zero selects a suitable default value."),
+ GUC_EXPLAIN
},
&Geqo_pool_size,
0, 0, INT_MAX,
@@ -2003,7 +2028,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"geqo_generations", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("GEQO: number of iterations of the algorithm."),
- gettext_noop("Zero selects a suitable default value.")
+ gettext_noop("Zero selects a suitable default value."),
+ GUC_EXPLAIN
},
&Geqo_generations,
0, 0, INT_MAX,
@@ -2117,7 +2143,7 @@ static struct config_int ConfigureNamesInt[] =
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
NULL,
- GUC_UNIT_BLOCKS
+ GUC_UNIT_BLOCKS | GUC_EXPLAIN
},
&num_temp_buffers,
1024, 100, INT_MAX / 2,
@@ -2184,7 +2210,7 @@ static struct config_int ConfigureNamesInt[] =
gettext_noop("This much memory can be used by each internal "
"sort operation and hash table before switching to "
"temporary disk files."),
- GUC_UNIT_KB
+ GUC_UNIT_KB | GUC_EXPLAIN
},
&work_mem,
4096, 64, MAX_KILOBYTES,
@@ -2713,7 +2739,8 @@ static struct config_int ConfigureNamesInt[] =
PGC_USERSET,
RESOURCES_ASYNCHRONOUS,
gettext_noop("Number of simultaneous requests that can be handled efficiently by the disk subsystem."),
- gettext_noop("For RAID arrays, this should be approximately the number of drive spindles in the array.")
+ gettext_noop("For RAID arrays, this should be approximately the number of drive spindles in the array."),
+ GUC_EXPLAIN
},
&effective_io_concurrency,
#ifdef USE_PREFETCH
@@ -2958,7 +2985,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"max_parallel_workers_per_gather", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
gettext_noop("Sets the maximum number of parallel processes per executor node."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&max_parallel_workers_per_gather,
2, 0, MAX_PARALLEL_WORKER_LIMIT,
@@ -2968,7 +2996,8 @@ static struct config_int ConfigureNamesInt[] =
{
{"max_parallel_workers", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
gettext_noop("Sets the maximum number of parallel workers that can be active at one time."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&max_parallel_workers,
8, 0, MAX_PARALLEL_WORKER_LIMIT,
@@ -3058,7 +3087,7 @@ static struct config_int ConfigureNamesInt[] =
gettext_noop("Sets the planner's assumption about the total size of the data caches."),
gettext_noop("That is, the total size of the caches (kernel cache and shared buffers) used for PostgreSQL data files. "
"This is measured in disk pages, which are normally 8 kB each."),
- GUC_UNIT_BLOCKS,
+ GUC_UNIT_BLOCKS | GUC_EXPLAIN,
},
&effective_cache_size,
DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX,
@@ -3069,7 +3098,7 @@ static struct config_int ConfigureNamesInt[] =
{"min_parallel_table_scan_size", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the minimum amount of table data for a parallel scan."),
gettext_noop("If the planner estimates that it will read a number of table pages too small to reach this limit, a parallel scan will not be considered."),
- GUC_UNIT_BLOCKS,
+ GUC_UNIT_BLOCKS | GUC_EXPLAIN,
},
&min_parallel_table_scan_size,
(8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3,
@@ -3080,7 +3109,7 @@ static struct config_int ConfigureNamesInt[] =
{"min_parallel_index_scan_size", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the minimum amount of index data for a parallel scan."),
gettext_noop("If the planner estimates that it will read a number of index pages too small to reach this limit, a parallel scan will not be considered."),
- GUC_UNIT_BLOCKS,
+ GUC_UNIT_BLOCKS | GUC_EXPLAIN,
},
&min_parallel_index_scan_size,
(512 * 1024) / BLCKSZ, 0, INT_MAX / 3,
@@ -3145,7 +3174,8 @@ static struct config_real ConfigureNamesReal[] =
{"seq_page_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of a "
"sequentially fetched disk page."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&seq_page_cost,
DEFAULT_SEQ_PAGE_COST, 0, DBL_MAX,
@@ -3155,7 +3185,8 @@ static struct config_real ConfigureNamesReal[] =
{"random_page_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of a "
"nonsequentially fetched disk page."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&random_page_cost,
DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX,
@@ -3165,7 +3196,8 @@ static struct config_real ConfigureNamesReal[] =
{"cpu_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of "
"processing each tuple (row)."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&cpu_tuple_cost,
DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX,
@@ -3175,7 +3207,8 @@ static struct config_real ConfigureNamesReal[] =
{"cpu_index_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of "
"processing each index entry during an index scan."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&cpu_index_tuple_cost,
DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX,
@@ -3185,7 +3218,8 @@ static struct config_real ConfigureNamesReal[] =
{"cpu_operator_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of "
"processing each operator or function call."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&cpu_operator_cost,
DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX,
@@ -3195,7 +3229,8 @@ static struct config_real ConfigureNamesReal[] =
{"parallel_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of "
"passing each tuple (row) from worker to master backend."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
¶llel_tuple_cost,
DEFAULT_PARALLEL_TUPLE_COST, 0, DBL_MAX,
@@ -3205,7 +3240,8 @@ static struct config_real ConfigureNamesReal[] =
{"parallel_setup_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Sets the planner's estimate of the cost of "
"starting up worker processes for parallel query."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
¶llel_setup_cost,
DEFAULT_PARALLEL_SETUP_COST, 0, DBL_MAX,
@@ -3215,7 +3251,8 @@ static struct config_real ConfigureNamesReal[] =
{
{"jit_above_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Perform JIT compilation if query is more expensive."),
- gettext_noop("-1 disables JIT compilation.")
+ gettext_noop("-1 disables JIT compilation."),
+ GUC_EXPLAIN
},
&jit_above_cost,
100000, -1, DBL_MAX,
@@ -3225,7 +3262,8 @@ static struct config_real ConfigureNamesReal[] =
{
{"jit_optimize_above_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Optimize JITed functions if query is more expensive."),
- gettext_noop("-1 disables optimization.")
+ gettext_noop("-1 disables optimization."),
+ GUC_EXPLAIN
},
&jit_optimize_above_cost,
500000, -1, DBL_MAX,
@@ -3235,7 +3273,8 @@ static struct config_real ConfigureNamesReal[] =
{
{"jit_inline_above_cost", PGC_USERSET, QUERY_TUNING_COST,
gettext_noop("Perform JIT inlining if query is more expensive."),
- gettext_noop("-1 disables inlining.")
+ gettext_noop("-1 disables inlining."),
+ GUC_EXPLAIN
},
&jit_inline_above_cost,
500000, -1, DBL_MAX,
@@ -3246,7 +3285,8 @@ static struct config_real ConfigureNamesReal[] =
{"cursor_tuple_fraction", PGC_USERSET, QUERY_TUNING_OTHER,
gettext_noop("Sets the planner's estimate of the fraction of "
"a cursor's rows that will be retrieved."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&cursor_tuple_fraction,
DEFAULT_CURSOR_TUPLE_FRACTION, 0.0, 1.0,
@@ -3256,7 +3296,8 @@ static struct config_real ConfigureNamesReal[] =
{
{"geqo_selection_bias", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("GEQO: selective pressure within the population."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&Geqo_selection_bias,
DEFAULT_GEQO_SELECTION_BIAS,
@@ -3266,7 +3307,8 @@ static struct config_real ConfigureNamesReal[] =
{
{"geqo_seed", PGC_USERSET, QUERY_TUNING_GEQO,
gettext_noop("GEQO: seed for random path selection."),
- NULL
+ NULL,
+ GUC_EXPLAIN
},
&Geqo_seed,
0.0, 0.0, 1.0,
@@ -3714,7 +3756,7 @@ static struct config_string ConfigureNamesString[] =
{"search_path", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the schema search order for names that are not schema-qualified."),
NULL,
- GUC_LIST_INPUT | GUC_LIST_QUOTE
+ GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_EXPLAIN
},
&namespace_search_path,
"\"$user\", public",
@@ -4167,7 +4209,8 @@ static struct config_enum ConfigureNamesEnum[] =
{"constraint_exclusion", PGC_USERSET, QUERY_TUNING_OTHER,
gettext_noop("Enables the planner to use constraints to optimize queries."),
gettext_noop("Table scans will be skipped if their constraints"
- " guarantee that no rows match the query.")
+ " guarantee that no rows match the query."),
+ GUC_EXPLAIN
},
&constraint_exclusion,
CONSTRAINT_EXCLUSION_PARTITION, constraint_exclusion_options,
@@ -4403,7 +4446,8 @@ static struct config_enum ConfigureNamesEnum[] =
{
{"force_parallel_mode", PGC_USERSET, QUERY_TUNING_OTHER,
gettext_noop("Forces use of parallel query facilities."),
- gettext_noop("If possible, run query using a parallel worker and with parallel restrictions.")
+ gettext_noop("If possible, run query using a parallel worker and with parallel restrictions."),
+ GUC_EXPLAIN
},
&force_parallel_mode,
FORCE_PARALLEL_OFF, force_parallel_mode_options,
@@ -4427,7 +4471,8 @@ static struct config_enum ConfigureNamesEnum[] =
gettext_noop("Controls the planner's selection of custom or generic plan."),
gettext_noop("Prepared statements can have custom and generic plans, and the planner "
"will attempt to choose which is better. This can be set to override "
- "the default behavior.")
+ "the default behavior."),
+ GUC_EXPLAIN
},
&plan_cache_mode,
PLAN_CACHE_MODE_AUTO, plan_cache_mode_options,
@@ -4487,6 +4532,7 @@ static struct config_generic **guc_variables;
/* Current number of variables contained in the vector */
static int num_guc_variables;
+static int num_guc_explain_variables;
/* Vector capacity */
static int size_guc_variables;
@@ -4751,6 +4797,7 @@ build_guc_variables(void)
{
int size_vars;
int num_vars = 0;
+ int num_explain_vars = 0;
struct config_generic **guc_vars;
int i;
@@ -4761,6 +4808,9 @@ build_guc_variables(void)
/* Rather than requiring vartype to be filled in by hand, do this: */
conf->gen.vartype = PGC_BOOL;
num_vars++;
+
+ if (conf->gen.flags & GUC_EXPLAIN)
+ num_explain_vars++;
}
for (i = 0; ConfigureNamesInt[i].gen.name; i++)
@@ -4769,6 +4819,9 @@ build_guc_variables(void)
conf->gen.vartype = PGC_INT;
num_vars++;
+
+ if (conf->gen.flags & GUC_EXPLAIN)
+ num_explain_vars++;
}
for (i = 0; ConfigureNamesReal[i].gen.name; i++)
@@ -4777,6 +4830,9 @@ build_guc_variables(void)
conf->gen.vartype = PGC_REAL;
num_vars++;
+
+ if (conf->gen.flags & GUC_EXPLAIN)
+ num_explain_vars++;
}
for (i = 0; ConfigureNamesString[i].gen.name; i++)
@@ -4785,6 +4841,9 @@ build_guc_variables(void)
conf->gen.vartype = PGC_STRING;
num_vars++;
+
+ if (conf->gen.flags & GUC_EXPLAIN)
+ num_explain_vars++;
}
for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
@@ -4793,6 +4852,9 @@ build_guc_variables(void)
conf->gen.vartype = PGC_ENUM;
num_vars++;
+
+ if (conf->gen.flags & GUC_EXPLAIN)
+ num_explain_vars++;
}
/*
@@ -4824,6 +4886,7 @@ build_guc_variables(void)
free(guc_variables);
guc_variables = guc_vars;
num_guc_variables = num_vars;
+ num_guc_explain_variables = num_explain_vars;
size_guc_variables = size_vars;
qsort((void *) guc_variables, num_guc_variables,
sizeof(struct config_generic *), guc_var_compare);
@@ -8774,6 +8837,99 @@ ShowAllGUCConfig(DestReceiver *dest)
end_tup_output(tstate);
}
+/*
+ * Returns an array of modified GUC options to show in EXPLAIN. Only options
+ * related to query planning (marked with GUC_EXPLAIN), with values different
+ * from built-in defaults.
+ */
+struct config_generic **
+get_explain_guc_options(int *num)
+{
+ int i;
+ struct config_generic **result;
+
+ *num = 0;
+
+ /*
+ * Allocate enough space to fit all GUC_EXPLAIN options. We may not
+ * need all the space, but there are fairly few such options so we
+ * don't waste a lot of memory.
+ */
+ result = palloc(sizeof(struct config_generic *) * num_guc_explain_variables);
+
+ for (i = 0; i < num_guc_variables; i++)
+ {
+ bool modified;
+ struct config_generic *conf = guc_variables[i];
+
+ /* return only options visible to the user */
+ if ((conf->flags & GUC_NO_SHOW_ALL) ||
+ ((conf->flags & GUC_SUPERUSER_ONLY) &&
+ !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)))
+ continue;
+
+ /* only parameters explicitly marked for inclusion in explain */
+ if (!(conf->flags & GUC_EXPLAIN))
+ continue;
+
+ /* return only options that were modified (w.r.t. config file) */
+ modified = false;
+
+ switch (conf->vartype)
+ {
+ case PGC_BOOL:
+ {
+ struct config_bool *lconf = (struct config_bool *) conf;
+ modified = (lconf->boot_val != *(lconf->variable));
+ }
+ break;
+
+ case PGC_INT:
+ {
+ struct config_int *lconf = (struct config_int *) conf;
+ modified = (lconf->boot_val != *(lconf->variable));
+ }
+ break;
+
+ case PGC_REAL:
+ {
+ struct config_real *lconf = (struct config_real *) conf;
+ modified = (lconf->boot_val != *(lconf->variable));
+ }
+ break;
+
+ case PGC_STRING:
+ {
+ struct config_string *lconf = (struct config_string *) conf;
+ modified = (strcmp(lconf->boot_val, *(lconf->variable)) != 0);
+ }
+ break;
+
+ case PGC_ENUM:
+ {
+ struct config_enum *lconf = (struct config_enum *) conf;
+ modified = (lconf->boot_val != *(lconf->variable));
+ }
+ break;
+
+ default:
+ elog(ERROR, "unexcpected GUC type: %d", conf->vartype);
+ }
+
+ /* skip GUC variables that match the built-in default */
+ if (!modified)
+ continue;
+
+ /* assign to the values array */
+ result[*num] = conf;
+ *num = *num + 1;
+
+ Assert(*num <= num_guc_explain_variables);
+ }
+
+ return result;
+}
+
/*
* Return GUC variable value by name; optionally return canonical form of
* name. If the GUC is unset, then throw an error unless missing_ok is true,
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
index e8854db459..db48f29501 100644
--- a/src/include/commands/explain.h
+++ b/src/include/commands/explain.h
@@ -35,6 +35,7 @@ typedef struct ExplainState
bool buffers; /* print buffer usage */
bool timing; /* print detailed node timing */
bool summary; /* print total planning and execution timing */
+ bool settings; /* print modified settings */
ExplainFormat format; /* output format */
/* state for output formatting --- not reset for each new plan tree */
int indent; /* current indentation level */
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 2712a774f7..f73edc3edc 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -227,6 +227,8 @@ typedef enum
#define GUC_UNIT_MIN 0x30000 /* value is in minutes */
#define GUC_UNIT_TIME 0xF0000 /* mask for time-related units */
+#define GUC_EXPLAIN 0x100000 /* include in explain */
+
#define GUC_UNIT (GUC_UNIT_MEMORY | GUC_UNIT_TIME)
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index a0970b2e1c..2a74b30b2f 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -267,5 +267,6 @@ extern void build_guc_variables(void);
extern const char *config_enum_lookup_by_value(struct config_enum *record, int val);
extern bool config_enum_lookup_by_name(struct config_enum *record,
const char *value, int *retval);
+extern struct config_generic **get_explain_guc_options(int *num);
#endif /* GUC_TABLES_H */
view thread (40+ messages) latest in thread
Message-ID: <20190329210717.GD4719@development>
Permalink: ../20190329210717.GD4719@development/
Also on: postgresql.org/message-id/20190329210717.GD4719@development
copy link · copy postgr.es · copy git am
reply Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: tomas.vondra@2ndquadrant.com, rafia.pghackers@gmail.com, michael@paquier.xyz, john.naylor@2ndquadrant.com, sergei.agalakov@gmail.com
Subject: Re: explain plans with information about (modified) gucs
In-Reply-To: <20190329210717.GD4719@development>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox