aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/explain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/explain.c')
-rw-r--r--src/backend/commands/explain.c160
1 files changed, 155 insertions, 5 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 2e4df5fcfef..232f41df65a 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -82,6 +82,12 @@ static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors,
ExplainState *es);
static void show_agg_keys(AggState *astate, List *ancestors,
ExplainState *es);
+static void show_grouping_sets(PlanState *planstate, Agg *agg,
+ List *ancestors, ExplainState *es);
+static void show_grouping_set_keys(PlanState *planstate,
+ Agg *aggnode, Sort *sortnode,
+ List *context, bool useprefix,
+ List *ancestors, ExplainState *es);
static void show_group_keys(GroupState *gstate, List *ancestors,
ExplainState *es);
static void show_sort_group_keys(PlanState *planstate, const char *qlabel,
@@ -1851,18 +1857,116 @@ show_agg_keys(AggState *astate, List *ancestors,
{
Agg *plan = (Agg *) astate->ss.ps.plan;
- if (plan->numCols > 0)
+ if (plan->numCols > 0 || plan->groupingSets)
{
/* The key columns refer to the tlist of the child plan */
ancestors = lcons(astate, ancestors);
- show_sort_group_keys(outerPlanState(astate), "Group Key",
- plan->numCols, plan->grpColIdx,
- NULL, NULL, NULL,
- ancestors, es);
+
+ if (plan->groupingSets)
+ show_grouping_sets(outerPlanState(astate), plan, ancestors, es);
+ else
+ show_sort_group_keys(outerPlanState(astate), "Group Key",
+ plan->numCols, plan->grpColIdx,
+ NULL, NULL, NULL,
+ ancestors, es);
+
ancestors = list_delete_first(ancestors);
}
}
+static void
+show_grouping_sets(PlanState *planstate, Agg *agg,
+ List *ancestors, ExplainState *es)
+{
+ List *context;
+ bool useprefix;
+ ListCell *lc;
+
+ /* Set up deparsing context */
+ context = set_deparse_context_planstate(es->deparse_cxt,
+ (Node *) planstate,
+ ancestors);
+ useprefix = (list_length(es->rtable) > 1 || es->verbose);
+
+ ExplainOpenGroup("Grouping Sets", "Grouping Sets", false, es);
+
+ show_grouping_set_keys(planstate, agg, NULL,
+ context, useprefix, ancestors, es);
+
+ foreach(lc, agg->chain)
+ {
+ Agg *aggnode = lfirst(lc);
+ Sort *sortnode = (Sort *) aggnode->plan.lefttree;
+
+ show_grouping_set_keys(planstate, aggnode, sortnode,
+ context, useprefix, ancestors, es);
+ }
+
+ ExplainCloseGroup("Grouping Sets", "Grouping Sets", false, es);
+}
+
+static void
+show_grouping_set_keys(PlanState *planstate,
+ Agg *aggnode, Sort *sortnode,
+ List *context, bool useprefix,
+ List *ancestors, ExplainState *es)
+{
+ Plan *plan = planstate->plan;
+ char *exprstr;
+ ListCell *lc;
+ List *gsets = aggnode->groupingSets;
+ AttrNumber *keycols = aggnode->grpColIdx;
+
+ ExplainOpenGroup("Grouping Set", NULL, true, es);
+
+ if (sortnode)
+ {
+ show_sort_group_keys(planstate, "Sort Key",
+ sortnode->numCols, sortnode->sortColIdx,
+ sortnode->sortOperators, sortnode->collations,
+ sortnode->nullsFirst,
+ ancestors, es);
+ if (es->format == EXPLAIN_FORMAT_TEXT)
+ es->indent++;
+ }
+
+ ExplainOpenGroup("Group Keys", "Group Keys", false, es);
+
+ foreach(lc, gsets)
+ {
+ List *result = NIL;
+ ListCell *lc2;
+
+ foreach(lc2, (List *) lfirst(lc))
+ {
+ Index i = lfirst_int(lc2);
+ AttrNumber keyresno = keycols[i];
+ TargetEntry *target = get_tle_by_resno(plan->targetlist,
+ keyresno);
+
+ if (!target)
+ elog(ERROR, "no tlist entry for key %d", keyresno);
+ /* Deparse the expression, showing any top-level cast */
+ exprstr = deparse_expression((Node *) target->expr, context,
+ useprefix, true);
+
+ result = lappend(result, exprstr);
+ }
+
+ if (!result && es->format == EXPLAIN_FORMAT_TEXT)
+ ExplainPropertyText("Group Key", "()", es);
+ else
+ ExplainPropertyListNested("Group Key", result, es);
+ }
+
+ ExplainCloseGroup("Group Keys", "Group Keys", false, es);
+
+ if (sortnode && es->format == EXPLAIN_FORMAT_TEXT)
+ es->indent--;
+
+ ExplainCloseGroup("Grouping Set", NULL, true, es);
+}
+
/*
* Show the grouping keys for a Group node.
*/
@@ -2613,6 +2717,52 @@ ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
}
/*
+ * Explain a property that takes the form of a list of unlabeled items within
+ * another list. "data" is a list of C strings.
+ */
+void
+ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
+{
+ ListCell *lc;
+ bool first = true;
+
+ switch (es->format)
+ {
+ case EXPLAIN_FORMAT_TEXT:
+ case EXPLAIN_FORMAT_XML:
+ ExplainPropertyList(qlabel, data, es);
+ return;
+
+ case EXPLAIN_FORMAT_JSON:
+ ExplainJSONLineEnding(es);
+ appendStringInfoSpaces(es->str, es->indent * 2);
+ appendStringInfoChar(es->str, '[');
+ foreach(lc, data)
+ {
+ if (!first)
+ appendStringInfoString(es->str, ", ");
+ escape_json(es->str, (const char *) lfirst(lc));
+ first = false;
+ }
+ appendStringInfoChar(es->str, ']');
+ break;
+
+ case EXPLAIN_FORMAT_YAML:
+ ExplainYAMLLineStarting(es);
+ appendStringInfoString(es->str, "- [");
+ foreach(lc, data)
+ {
+ if (!first)
+ appendStringInfoString(es->str, ", ");
+ escape_yaml(es->str, (const char *) lfirst(lc));
+ first = false;
+ }
+ appendStringInfoChar(es->str, ']');
+ break;
+ }
+}
+
+/*
* Explain a simple property.
*
* If "numeric" is true, the value is a number (or other value that