summaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/explain.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 8345bc0264b..207f86f1d39 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -147,6 +147,7 @@ static void show_buffer_usage(ExplainState *es, const BufferUsage *usage);
static void show_wal_usage(ExplainState *es, const WalUsage *usage);
static void show_memory_counters(ExplainState *es,
const MemoryContextCounters *mem_counters);
+static void show_result_replacement_info(Result *result, ExplainState *es);
static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir,
ExplainState *es);
static void ExplainScanTarget(Scan *plan, ExplainState *es);
@@ -1229,6 +1230,10 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
*rels_used = bms_add_members(*rels_used,
((MergeAppend *) plan)->apprelids);
break;
+ case T_Result:
+ *rels_used = bms_add_members(*rels_used,
+ ((Result *) plan)->relids);
+ break;
default:
break;
}
@@ -2232,6 +2237,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
ancestors, es);
break;
case T_Result:
+ show_result_replacement_info(castNode(Result, plan), es);
show_upper_qual((List *) ((Result *) plan)->resconstantqual,
"One-Time Filter", planstate, ancestors, es);
show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
@@ -4751,6 +4757,102 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
}
/*
+ * Explain what a "Result" node replaced.
+ */
+static void
+show_result_replacement_info(Result *result, ExplainState *es)
+{
+ StringInfoData buf;
+ int nrels = 0;
+ int rti = -1;
+ bool found_non_result = false;
+ char *replacement_type = "???";
+
+ /* If the Result node has a subplan, it didn't replace anything. */
+ if (result->plan.lefttree != NULL)
+ return;
+
+ /* Gating result nodes should have a subplan, and we don't. */
+ Assert(result->result_type != RESULT_TYPE_GATING);
+
+ switch (result->result_type)
+ {
+ case RESULT_TYPE_GATING:
+ replacement_type = "Gating";
+ break;
+ case RESULT_TYPE_SCAN:
+ replacement_type = "Scan";
+ break;
+ case RESULT_TYPE_JOIN:
+ replacement_type = "Join";
+ break;
+ case RESULT_TYPE_UPPER:
+ /* a small white lie */
+ replacement_type = "Aggregate";
+ break;
+ case RESULT_TYPE_MINMAX:
+ replacement_type = "MinMaxAggregate";
+ break;
+ }
+
+ /*
+ * Build up a comma-separated list of user-facing names for the range
+ * table entries in the relids set.
+ */
+ initStringInfo(&buf);
+ while ((rti = bms_next_member(result->relids, rti)) >= 0)
+ {
+ RangeTblEntry *rte = rt_fetch(rti, es->rtable);
+ char *refname;
+
+ /*
+ * add_outer_joins_to_relids will add join RTIs to the relids set of a
+ * join; if that join is then replaced with a Result node, we may see
+ * such RTIs here. But we want to completely ignore those here,
+ * because "a LEFT JOIN b ON whatever" is a join between a and b, not
+ * a join between a, b, and an unnamed join.
+ */
+ if (rte->rtekind == RTE_JOIN)
+ continue;
+
+ /* Count the number of rels that aren't ignored completely. */
+ ++nrels;
+
+ /* Work out what reference name to use and add it to the string. */
+ refname = (char *) list_nth(es->rtable_names, rti - 1);
+ if (refname == NULL)
+ refname = rte->eref->aliasname;
+ if (buf.len > 0)
+ appendStringInfoString(&buf, ", ");
+ appendStringInfoString(&buf, refname);
+
+ /* Keep track of whether we see anything other than RTE_RESULT. */
+ if (rte->rtekind != RTE_RESULT)
+ found_non_result = true;
+ }
+
+ /*
+ * If this Result node is because of a single RTE that is RTE_RESULT, it
+ * is not really replacing anything at all, because there's no other
+ * method for implementing a scan of such an RTE, so we don't display the
+ * Replaces line in such cases.
+ */
+ if (nrels <= 1 && !found_non_result &&
+ result->result_type == RESULT_TYPE_SCAN)
+ return;
+
+ /* Say what we replaced, with list of rels if available. */
+ if (buf.len == 0)
+ ExplainPropertyText("Replaces", replacement_type, es);
+ else
+ {
+ char *s = psprintf("%s on %s", replacement_type, buf.data);
+
+ ExplainPropertyText("Replaces", s, es);
+ }
+}
+
+/*
* Explain the constituent plans of an Append, MergeAppend,
* BitmapAnd, or BitmapOr node.
*