=== Applying patches on top of PostgreSQL commit ID 5941946d0934b9eccb0d5bfebd40b155249a0130 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Wed Mar 19 20:21:23 UTC 2025 On branch cf/5359 nothing to commit, working tree clean === using 'git am' to apply patch ./0001-Add-a-new-option-STATS-to-EXPLAIN-command-r3.patch === Applying: Add a new option STATS to EXPLAIN command Using index info to reconstruct a base tree... M doc/src/sgml/ref/explain.sgml M src/backend/commands/explain.c M src/backend/nodes/makefuncs.c M src/backend/optimizer/plan/createplan.c M src/backend/utils/adt/selfuncs.c M src/backend/utils/cache/lsyscache.c M src/include/commands/explain.h M src/include/nodes/parsenodes.h M src/include/nodes/pathnodes.h M src/include/nodes/plannodes.h M src/include/utils/lsyscache.h Falling back to patching base and 3-way merge... Auto-merging src/include/utils/lsyscache.h Auto-merging src/include/nodes/plannodes.h Auto-merging src/include/nodes/pathnodes.h Auto-merging src/include/nodes/parsenodes.h Auto-merging src/include/commands/explain.h CONFLICT (content): Merge conflict in src/include/commands/explain.h Auto-merging src/backend/utils/cache/lsyscache.c Auto-merging src/backend/utils/adt/selfuncs.c Auto-merging src/backend/optimizer/plan/createplan.c Auto-merging src/backend/nodes/makefuncs.c Auto-merging src/backend/commands/explain.c CONFLICT (content): Merge conflict in src/backend/commands/explain.c Auto-merging doc/src/sgml/ref/explain.sgml error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Add a new option STATS to EXPLAIN command When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". Unstaged changes after reset: M doc/src/sgml/ref/explain.sgml M src/backend/commands/explain.c M src/backend/nodes/makefuncs.c M src/backend/optimizer/plan/createplan.c M src/backend/optimizer/util/relnode.c M src/backend/optimizer/util/restrictinfo.c M src/backend/statistics/extended_stats.c M src/backend/utils/adt/selfuncs.c M src/backend/utils/cache/lsyscache.c M src/include/commands/explain.h M src/include/nodes/makefuncs.h M src/include/nodes/parsenodes.h M src/include/nodes/pathnodes.h M src/include/nodes/plannodes.h M src/include/optimizer/restrictinfo.h M src/include/utils/lsyscache.h === using patch(1) to apply patch ./0001-Add-a-new-option-STATS-to-EXPLAIN-command-r3.patch === patch: unrecognized option `--no-backup-if-mismatch' usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory] [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count] [-r rej-name] [-V t | nil | never | none] [-x number] [-z backup-ext] [--posix] [origfile [patchfile]] patch options) + { + DefElem *opt = (DefElem *) lfirst(lc); + + if (strcmp(opt->defname, "analyze") == 0) + es->analyze = defGetBoolean(opt); + else if (strcmp(opt->defname, "verbose") == 0) + es->verbose = defGetBoolean(opt); + else if (strcmp(opt->defname, "costs") == 0) + es->costs = defGetBoolean(opt); + else if (strcmp(opt->defname, "buffers") == 0) + { + buffers_set = true; + es->buffers = defGetBoolean(opt); + } + else if (strcmp(opt->defname, "wal") == 0) + es->wal = defGetBoolean(opt); + else if (strcmp(opt->defname, "settings") == 0) + es->settings = defGetBoolean(opt); + else if (strcmp(opt->defname, "generic_plan") == 0) + es->generic = defGetBoolean(opt); + else if (strcmp(opt->defname, "stats") == 0) + es->stats = defGetBoolean(opt); + else if (strcmp(opt->defname, "timing") == 0) + { + timing_set = true; + es->timing = defGetBoolean(opt); + } + else if (strcmp(opt->defname, "summary") == 0) + { + summary_set = true; + es->summary = defGetBoolean(opt); + } + else if (strcmp(opt->defname, "memory") == 0) + es->memory = defGetBoolean(opt); + else if (strcmp(opt->defname, "serialize") == 0) + { + if (opt->arg) + { + char *p = defGetString(opt); + + if (strcmp(p, "off") == 0 || strcmp(p, "none") == 0) + es->serialize = EXPLAIN_SERIALIZE_NONE; + else if (strcmp(p, "text") == 0) + es->serialize = EXPLAIN_SERIALIZE_TEXT; + else if (strcmp(p, "binary") == 0) + es->serialize = EXPLAIN_SERIALIZE_BINARY; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"", + opt->defname, p), + parser_errposition(pstate, opt->location))); + } + else + { + /* SERIALIZE without an argument is taken as 'text' */ + es->serialize = EXPLAIN_SERIALIZE_TEXT; + } + } + else if (strcmp(opt->defname, "format") == 0) + { + char *p = defGetString(opt); + + if (strcmp(p, "text") == 0) + es->format = EXPLAIN_FORMAT_TEXT; + else if (strcmp(p, "xml") == 0) + es->format = EXPLAIN_FORMAT_XML; + else if (strcmp(p, "json") == 0) + es->format = EXPLAIN_FORMAT_JSON; + else if (strcmp(p, "yaml") == 0) + es->format = EXPLAIN_FORMAT_YAML; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"", + opt->defname, p), + parser_errposition(pstate, opt->location))); + } + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unrecognized EXPLAIN option \"%s\"", + opt->defname), + parser_errposition(pstate, opt->location))); + } + + /* check that WAL is used with EXPLAIN ANALYZE */ + if (es->wal && !es->analyze) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("EXPLAIN option %s requires ANALYZE", "WAL"))); + + /* if the timing was not set explicitly, set default value */ + es->timing = (timing_set) ? es->timing : es->analyze; + + /* if the buffers was not set explicitly, set default value */ + es->buffers = (buffers_set) ? es->buffers : es->analyze; ++>>>>>>> theirs - /* check that timing is used with EXPLAIN ANALYZE */ - if (es->timing && !es->analyze) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("EXPLAIN option %s requires ANALYZE", "TIMING"))); - - /* check that serialize is used with EXPLAIN ANALYZE */ - if (es->serialize != EXPLAIN_SERIALIZE_NONE && !es->analyze) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("EXPLAIN option %s requires ANALYZE", "SERIALIZE"))); - - /* check that GENERIC_PLAN is not used with EXPLAIN ANALYZE */ - if (es->generic && es->analyze) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("EXPLAIN options ANALYZE and GENERIC_PLAN cannot be used together"))); - - /* if the summary was not set explicitly, set default value */ - es->summary = (summary_set) ? es->summary : es->analyze; + /* Configure the ExplainState based on the provided options */ + ParseExplainOptionList(es, stmt->options, pstate); + /* Extract the query and, if enabled, jumble it */ query = castNode(Query, stmt->query); if (IsQueryIdEnabled()) jstate = JumbleQuery(query); @@@ -1977,7 -2130,11 +2098,15 @@@ ExplainNode(PlanState *planstate, List if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); ++<<<<<<< ours + show_indexsearches_info(planstate, es); ++======= + if (es->stats) + show_scan_stats(plan->app_extstats->applied_stats, + plan->app_extstats->applied_clauses, + plan->app_extstats->applied_clauses_or, + planstate, ancestors, es); ++>>>>>>> theirs break; case T_IndexOnlyScan: show_scan_qual(((IndexOnlyScan *) plan)->indexqual, @@@ -1994,12 -2151,20 +2123,28 @@@ if (es->analyze) ExplainPropertyFloat("Heap Fetches", NULL, planstate->instrument->ntuples2, 0, es); ++<<<<<<< ours + show_indexsearches_info(planstate, es); ++======= + if (es->stats) + show_scan_stats(plan->app_extstats->applied_stats, + plan->app_extstats->applied_clauses, + plan->app_extstats->applied_clauses_or, + planstate, ancestors, es); ++>>>>>>> theirs break; case T_BitmapIndexScan: show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig, "Index Cond", planstate, ancestors, es); ++<<<<<<< ours + show_indexsearches_info(planstate, es); ++======= + if (es->stats) + show_scan_stats(plan->app_extstats->applied_stats, + plan->app_extstats->applied_clauses, + plan->app_extstats->applied_clauses_or, + planstate, ancestors, es); ++>>>>>>> theirs break; case T_BitmapHeapScan: show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig, @@@ -2211,11 -2387,13 +2367,16 @@@ if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); + if (es->stats) + show_scan_stats(plan->app_extstats->applied_stats, + plan->app_extstats->applied_clauses, + plan->app_extstats->applied_clauses_or, + planstate, ancestors, es); break; case T_WindowAgg: + show_window_def(castNode(WindowAggState, planstate), ancestors, es); + show_upper_qual(((WindowAgg *) plan)->runConditionOrig, + "Run Condition", planstate, ancestors, es); show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, diff --cc src/include/commands/explain.h index 387839eb5d2,797075126a0..00000000000 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@@ -14,9 -14,65 +14,68 @@@ #define EXPLAIN_H #include "executor/executor.h" -#include "lib/stringinfo.h" #include "parser/parse_node.h" ++<<<<<<< ours +struct ExplainState; /* defined in explain_state.h */ ++======= + typedef enum ExplainSerializeOption + { + EXPLAIN_SERIALIZE_NONE, + EXPLAIN_SERIALIZE_TEXT, + EXPLAIN_SERIALIZE_BINARY, + } ExplainSerializeOption; + + typedef enum ExplainFormat + { + EXPLAIN_FORMAT_TEXT, + EXPLAIN_FORMAT_XML, + EXPLAIN_FORMAT_JSON, + EXPLAIN_FORMAT_YAML, + } ExplainFormat; + + typedef struct ExplainWorkersState + { + int num_workers; /* # of worker processes the plan used */ + bool *worker_inited; /* per-worker state-initialized flags */ + StringInfoData *worker_str; /* per-worker transient output buffers */ + int *worker_state_save; /* per-worker grouping state save areas */ + StringInfo prev_str; /* saved output buffer while redirecting */ + } ExplainWorkersState; + + typedef struct ExplainState + { + StringInfo str; /* output buffer */ + /* options */ + bool verbose; /* be verbose */ + bool analyze; /* print actual times */ + bool costs; /* print estimated costs */ + bool buffers; /* print buffer usage */ + bool wal; /* print WAL usage */ + bool timing; /* print detailed node timing */ + bool summary; /* print total planning and execution timing */ + bool memory; /* print planner's memory usage information */ + bool settings; /* print modified settings */ + bool generic; /* generate a generic plan */ + bool stats; /* print applied extended stats */ + ExplainSerializeOption serialize; /* serialize the query's output? */ + ExplainFormat format; /* output format */ + /* state for output formatting --- not reset for each new plan tree */ + int indent; /* current indentation level */ + List *grouping_stack; /* format-specific grouping state */ + /* state related to the current plan tree (filled by ExplainPrintPlan) */ + PlannedStmt *pstmt; /* top of plan */ + List *rtable; /* range table */ + List *rtable_names; /* alias names for RTEs */ + List *deparse_cxt; /* context list for deparsing expressions */ + Bitmapset *printed_subplans; /* ids of SubPlans we've printed */ + bool hide_workers; /* set if we find an invisible Gather */ + int rtable_size; /* length of rtable excluding the RTE_GROUP + * entry */ + /* state related to the current plan node */ + ExplainWorkersState *workers_state; /* needed if parallel plan */ + } ExplainState; ++>>>>>>> theirs /* Hook for plugins to get control in ExplainOneQuery() */ typedef void (*ExplainOneQuery_hook_type) (Query *query,