#include "utils/xml.h"
+/* Crude hack to avoid changing sizeof(ExplainState) in released branches */
+#define grouping_stack extra->groupingstack
+#define deparse_cxt extra->deparsecxt
+
/* Hook for plugins to get control in ExplainOneQuery() */
ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
es->costs = true;
/* Prepare output buffer. */
es->str = makeStringInfo();
+ /* Kluge to avoid changing sizeof(ExplainState) in released branches. */
+ es->extra = (ExplainStateExtra *) palloc0(sizeof(ExplainStateExtra));
}
/*
es->rtable = queryDesc->plannedstmt->rtable;
ExplainPreScanNode(queryDesc->planstate, &rels_used);
es->rtable_names = select_rtable_names_for_explain(es->rtable, rels_used);
+ es->deparse_cxt = deparse_context_for_plan_rtable(es->rtable,
+ es->rtable_names);
ExplainNode(queryDesc->planstate, NIL, NULL, NULL, es);
}
return;
/* Set up deparsing context */
- context = deparse_context_for_planstate((Node *) planstate,
- ancestors,
- es->rtable,
- es->rtable_names);
+ context = set_deparse_context_planstate(es->deparse_cxt,
+ (Node *) planstate,
+ ancestors);
useprefix = list_length(es->rtable) > 1;
/* Deparse each result column (we now include resjunk ones) */
char *exprstr;
/* Set up deparsing context */
- context = deparse_context_for_planstate((Node *) planstate,
- ancestors,
- es->rtable,
- es->rtable_names);
+ context = set_deparse_context_planstate(es->deparse_cxt,
+ (Node *) planstate,
+ ancestors);
/* Deparse the expression */
exprstr = deparse_expression(node, context, useprefix, false);
return;
/* Set up deparsing context */
- context = deparse_context_for_planstate((Node *) planstate,
- ancestors,
- es->rtable,
- es->rtable_names);
+ context = set_deparse_context_planstate(es->deparse_cxt,
+ (Node *) planstate,
+ ancestors);
useprefix = (list_length(es->rtable) > 1 || es->verbose);
for (keyno = 0; keyno < nkeys; keyno++)
}
/*
- * deparse_context_for_planstate - Build deparse context for a plan
+ * deparse_context_for_plan_rtable - Build deparse context for a plan's rtable
+ *
+ * When deparsing an expression in a Plan tree, we use the plan's rangetable
+ * to resolve names of simple Vars. The initialization of column names for
+ * this is rather expensive if the rangetable is large, and it'll be the same
+ * for every expression in the Plan tree; so we do it just once and re-use
+ * the result of this function for each expression. (Note that the result
+ * is not usable until set_deparse_context_planstate() is applied to it.)
+ *
+ * In addition to the plan's rangetable list, pass the per-RTE alias names
+ * assigned by a previous call to select_rtable_names_for_explain.
+ */
+List *
+deparse_context_for_plan_rtable(List *rtable, List *rtable_names)
+{
+ deparse_namespace *dpns;
+
+ dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
+
+ /* Initialize fields that stay the same across the whole plan tree */
+ dpns->rtable = rtable;
+ dpns->rtable_names = rtable_names;
+ dpns->ctes = NIL;
+
+ /*
+ * Set up column name aliases. We will get rather bogus results for join
+ * RTEs, but that doesn't matter because plan trees don't contain any join
+ * alias Vars.
+ */
+ set_simple_column_names(dpns);
+
+ /* Return a one-deep namespace stack */
+ return list_make1(dpns);
+}
+
+/*
+ * set_deparse_context_planstate - Specify Plan node containing expression
*
* When deparsing an expression in a Plan tree, we might have to resolve
* OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
* most-closely-nested first. This is needed to resolve PARAM_EXEC Params.
* Note we assume that all the PlanStates share the same rtable.
*
- * The plan's rangetable list must also be passed, along with the per-RTE
- * alias names assigned by a previous call to select_rtable_names_for_explain.
- * (We use the rangetable to resolve simple Vars, but the plan inputs are
- * necessary for Vars with special varnos.)
+ * Once this function has been called, deparse_expression() can be called on
+ * subsidiary expression(s) of the specified PlanState node. To deparse
+ * expressions of a different Plan node in the same Plan tree, re-call this
+ * function to identify the new parent Plan node.
+ *
+ * The result is the same List passed in; this is a notational convenience.
*/
List *
-deparse_context_for_planstate(Node *planstate, List *ancestors,
- List *rtable, List *rtable_names)
+set_deparse_context_planstate(List *dpcontext,
+ Node *planstate, List *ancestors)
{
deparse_namespace *dpns;
- dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
-
- /* Initialize fields that stay the same across the whole plan tree */
- dpns->rtable = rtable;
- dpns->rtable_names = rtable_names;
- dpns->ctes = NIL;
-
- /*
- * Set up column name aliases. We will get rather bogus results for join
- * RTEs, but that doesn't matter because plan trees don't contain any join
- * alias Vars.
- */
- set_simple_column_names(dpns);
+ /* Should always have one-entry namespace list for Plan deparsing */
+ Assert(list_length(dpcontext) == 1);
+ dpns = (deparse_namespace *) linitial(dpcontext);
/* Set our attention on the specific plan node passed in */
set_deparse_planstate(dpns, (PlanState *) planstate);
dpns->ancestors = ancestors;
- /* Return a one-deep namespace stack */
- return list_make1(dpns);
+ return dpcontext;
}
/*
EXPLAIN_FORMAT_YAML
} ExplainFormat;
+/* Crude hack to avoid changing sizeof(ExplainState) in released branches */
+typedef struct ExplainStateExtra
+{
+ List *groupingstack; /* format-specific grouping state */
+ List *deparsecxt; /* context list for deparsing expressions */
+} ExplainStateExtra;
+
typedef struct ExplainState
{
StringInfo str; /* output buffer */
List *rtable; /* range table */
List *rtable_names; /* alias names for RTEs */
int indent; /* current indentation level */
- List *grouping_stack; /* format-specific grouping state */
+ ExplainStateExtra *extra; /* pointer to additional data */
} ExplainState;
/* Hook for plugins to get control in ExplainOneQuery() */
extern char *deparse_expression(Node *expr, List *dpcontext,
bool forceprefix, bool showimplicit);
extern List *deparse_context_for(const char *aliasname, Oid relid);
-extern List *deparse_context_for_planstate(Node *planstate, List *ancestors,
- List *rtable, List *rtable_names);
+extern List *deparse_context_for_plan_rtable(List *rtable, List *rtable_names);
+extern List *set_deparse_context_planstate(List *dpcontext,
+ Node *planstate, List *ancestors);
extern List *select_rtable_names_for_explain(List *rtable,
Bitmapset *rels_used);
extern const char *quote_identifier(const char *ident);