summaryrefslogtreecommitdiff
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.c114
1 files changed, 97 insertions, 17 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index a951c55ed34..315a52849c9 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -2187,6 +2187,10 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
/*
* Show the target of a ModifyTable node
+ *
+ * Here we show the nominal target (ie, the relation that was named in the
+ * original query). If the actual target(s) is/are different, we'll show them
+ * in show_modifytable_info().
*/
static void
ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
@@ -2303,30 +2307,106 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
/*
* Show extra information for a ModifyTable node
+ *
+ * We have two objectives here. First, if there's more than one target table
+ * or it's different from the nominal target, identify the actual target(s).
+ * Second, give FDWs a chance to display extra info about foreign targets.
*/
static void
show_modifytable_info(ModifyTableState *mtstate, ExplainState *es)
{
- FdwRoutine *fdwroutine = mtstate->resultRelInfo->ri_FdwRoutine;
+ ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
+ const char *operation;
+ const char *foperation;
+ bool labeltargets;
+ int j;
- /*
- * If the first target relation is a foreign table, call its FDW to
- * display whatever additional fields it wants to. For now, we ignore the
- * possibility of other targets being foreign tables, although the API for
- * ExplainForeignModify is designed to allow them to be processed.
- */
- if (fdwroutine != NULL &&
- fdwroutine->ExplainForeignModify != NULL)
+ switch (node->operation)
{
- ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
- List *fdw_private = (List *) linitial(node->fdwPrivLists);
-
- fdwroutine->ExplainForeignModify(mtstate,
- mtstate->resultRelInfo,
- fdw_private,
- 0,
- es);
+ case CMD_INSERT:
+ operation = "Insert";
+ foperation = "Foreign Insert";
+ break;
+ case CMD_UPDATE:
+ operation = "Update";
+ foperation = "Foreign Update";
+ break;
+ case CMD_DELETE:
+ operation = "Delete";
+ foperation = "Foreign Delete";
+ break;
+ default:
+ operation = "???";
+ foperation = "Foreign ???";
+ break;
+ }
+
+ /* Should we explicitly label target relations? */
+ labeltargets = (mtstate->mt_nplans > 1 ||
+ (mtstate->mt_nplans == 1 &&
+ mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
+
+ if (labeltargets)
+ ExplainOpenGroup("Target Tables", "Target Tables", false, es);
+
+ for (j = 0; j < mtstate->mt_nplans; j++)
+ {
+ ResultRelInfo *resultRelInfo = mtstate->resultRelInfo + j;
+ FdwRoutine *fdwroutine = resultRelInfo->ri_FdwRoutine;
+
+ if (labeltargets)
+ {
+ /* Open a group for this target */
+ ExplainOpenGroup("Target Table", NULL, true, es);
+
+ /*
+ * In text mode, decorate each target with operation type, so that
+ * ExplainTargetRel's output of " on foo" will read nicely.
+ */
+ if (es->format == EXPLAIN_FORMAT_TEXT)
+ {
+ appendStringInfoSpaces(es->str, es->indent * 2);
+ appendStringInfoString(es->str,
+ fdwroutine ? foperation : operation);
+ }
+
+ /* Identify target */
+ ExplainTargetRel((Plan *) node,
+ resultRelInfo->ri_RangeTableIndex,
+ es);
+
+ if (es->format == EXPLAIN_FORMAT_TEXT)
+ {
+ appendStringInfoChar(es->str, '\n');
+ es->indent++;
+ }
+ }
+
+ /* Give FDW a chance */
+ if (fdwroutine && fdwroutine->ExplainForeignModify != NULL)
+ {
+ List *fdw_private = (List *) list_nth(node->fdwPrivLists, j);
+
+ fdwroutine->ExplainForeignModify(mtstate,
+ resultRelInfo,
+ fdw_private,
+ j,
+ es);
+ }
+
+ if (labeltargets)
+ {
+ /* Undo the indentation we added in text format */
+ if (es->format == EXPLAIN_FORMAT_TEXT)
+ es->indent--;
+
+ /* Close the group */
+ ExplainCloseGroup("Target Table", NULL, true, es);
+ }
}
+
+ if (labeltargets)
+ ExplainCloseGroup("Target Tables", "Target Tables", false, es);
}
/*