aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/explain.c23
-rw-r--r--src/backend/utils/adt/ruleutils.c73
-rw-r--r--src/include/commands/explain.h1
-rw-r--r--src/include/utils/ruleutils.h7
4 files changed, 66 insertions, 38 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 8a0be5df0bf..39ceaf26639 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -563,6 +563,8 @@ ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
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);
}
@@ -1678,10 +1680,9 @@ show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *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) */
@@ -1710,10 +1711,9 @@ show_expression(Node *node, const char *qlabel,
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);
@@ -1855,10 +1855,9 @@ show_sort_group_keys(PlanState *planstate, const char *qlabel,
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++)
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index dd748acffdf..c1d860ceffd 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2520,7 +2520,43 @@ deparse_context_for(const char *aliasname, Oid relid)
}
/*
- * 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
@@ -2533,43 +2569,34 @@ deparse_context_for(const char *aliasname, Oid relid)
* fields, which won't contain INDEX_VAR Vars.)
*
* Note: planstate really ought to be declared as "PlanState *", but we use
- * "Node *" to avoid having to include execnodes.h in builtins.h.
+ * "Node *" to avoid having to include execnodes.h in ruleutils.h.
*
* The ancestors list is a list of the PlanState's parent PlanStates, the
* 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;
}
/*
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
index 6e269501f48..598f37428d2 100644
--- a/src/include/commands/explain.h
+++ b/src/include/commands/explain.h
@@ -41,6 +41,7 @@ typedef struct ExplainState
List *rtable_names; /* alias names for RTEs */
int indent; /* current indentation level */
List *grouping_stack; /* format-specific grouping state */
+ List *deparse_cxt; /* context list for deparsing expressions */
} ExplainState;
/* Hook for plugins to get control in ExplainOneQuery() */
diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h
index 188503caa04..fed9c7b6ffa 100644
--- a/src/include/utils/ruleutils.h
+++ b/src/include/utils/ruleutils.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * src/include/ruleutils.h
+ * src/include/utils/ruleutils.h
*
*-------------------------------------------------------------------------
*/
@@ -25,8 +25,9 @@ extern char *pg_get_constraintdef_string(Oid constraintId);
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 char *generate_collation_name(Oid collid);