diff options
Diffstat (limited to 'src/backend/executor/nodeModifyTable.c')
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index b0fe50075ad..87c820276a8 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -4471,6 +4471,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) ModifyTableState *mtstate; Plan *subplan = outerPlan(node); CmdType operation = node->operation; + int total_nrels = list_length(node->resultRelations); int nrels; List *resultRelations = NIL; List *withCheckOptionLists = NIL; @@ -4490,13 +4491,35 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) /* * Only consider unpruned relations for initializing their ResultRelInfo * struct and other fields such as withCheckOptions, etc. + * + * Note: We must avoid pruning every result relation. This is important + * for MERGE, since even if every result relation is pruned from the + * subplan, there might still be NOT MATCHED rows, for which there may be + * INSERT actions to perform. To allow these actions to be found, at + * least one result relation must be kept. Also, when inserting into a + * partitioned table, ExecInitPartitionInfo() needs a ResultRelInfo struct + * as a reference for building the ResultRelInfo of the target partition. + * In either case, it doesn't matter which result relation is kept, so we + * just keep the first one, if all others have been pruned. See also, + * ExecDoInitialPruning(), which ensures that this first result relation + * has been locked. */ i = 0; foreach(l, node->resultRelations) { Index rti = lfirst_int(l); + bool keep_rel; + + keep_rel = bms_is_member(rti, estate->es_unpruned_relids); + if (!keep_rel && i == total_nrels - 1 && resultRelations == NIL) + { + /* all result relations pruned; keep the first one */ + keep_rel = true; + rti = linitial_int(node->resultRelations); + i = 0; + } - if (bms_is_member(rti, estate->es_unpruned_relids)) + if (keep_rel) { resultRelations = lappend_int(resultRelations, rti); if (node->withCheckOptionLists) @@ -4537,6 +4560,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) i++; } nrels = list_length(resultRelations); + Assert(nrels > 0); /* * create state structure @@ -4735,7 +4759,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) */ mtstate->mt_resultOidAttno = ExecFindJunkAttributeInTlist(subplan->targetlist, "tableoid"); - Assert(AttributeNumberIsValid(mtstate->mt_resultOidAttno) || nrels == 1); + Assert(AttributeNumberIsValid(mtstate->mt_resultOidAttno) || total_nrels == 1); mtstate->mt_lastResultOid = InvalidOid; /* force lookup at first tuple */ mtstate->mt_lastResultIndex = 0; /* must be zero if no such attr */ @@ -4832,7 +4856,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) if (node->onConflictAction != ONCONFLICT_NONE) { /* insert may only have one relation, inheritance is not expanded */ - Assert(nrels == 1); + Assert(total_nrels == 1); resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes; } @@ -4979,7 +5003,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) if (operation == CMD_INSERT) { /* insert may only have one relation, inheritance is not expanded */ - Assert(nrels == 1); + Assert(total_nrels == 1); resultRelInfo = mtstate->resultRelInfo; if (!resultRelInfo->ri_usesFdwDirectModify && resultRelInfo->ri_FdwRoutine != NULL && |