diff options
Diffstat (limited to 'src/backend/commands/explain.c')
-rw-r--r-- | src/backend/commands/explain.c | 160 |
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 |