summaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c23
-rw-r--r--src/backend/executor/execPartition.c9
-rw-r--r--src/backend/executor/nodeModifyTable.c12
3 files changed, 35 insertions, 9 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index b8b9d2a85f7..ff12e2e1364 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1036,6 +1036,9 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* Generally the parser and/or planner should have noticed any such mistake
* already, but let's make sure.
*
+ * For INSERT ON CONFLICT, the result relation is required to support the
+ * onConflictAction, regardless of whether a conflict actually occurs.
+ *
* For MERGE, mergeActions is the list of actions that may be performed. The
* result relation is required to support every action, regardless of whether
* or not they are all executed.
@@ -1045,7 +1048,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
*/
void
CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation,
- List *mergeActions)
+ OnConflictAction onConflictAction, List *mergeActions)
{
Relation resultRel = resultRelInfo->ri_RelationDesc;
FdwRoutine *fdwroutine;
@@ -1058,7 +1061,23 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation,
{
case RELKIND_RELATION:
case RELKIND_PARTITIONED_TABLE:
- CheckCmdReplicaIdentity(resultRel, operation);
+
+ /*
+ * For MERGE, check that the target relation supports each action.
+ * For other operations, just check the operation itself.
+ */
+ if (operation == CMD_MERGE)
+ foreach_node(MergeAction, action, mergeActions)
+ CheckCmdReplicaIdentity(resultRel, action->commandType);
+ else
+ CheckCmdReplicaIdentity(resultRel, operation);
+
+ /*
+ * For INSERT ON CONFLICT DO UPDATE, additionally check that the
+ * target relation supports UPDATE.
+ */
+ if (onConflictAction == ONCONFLICT_UPDATE)
+ CheckCmdReplicaIdentity(resultRel, CMD_UPDATE);
break;
case RELKIND_SEQUENCE:
ereport(ERROR,
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 514eae1037d..1f2da072632 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -360,8 +360,12 @@ ExecFindPartition(ModifyTableState *mtstate,
true, false);
if (rri)
{
+ ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
+
/* Verify this ResultRelInfo allows INSERTs */
- CheckValidResultRel(rri, CMD_INSERT, NIL);
+ CheckValidResultRel(rri, CMD_INSERT,
+ node ? node->onConflictAction : ONCONFLICT_NONE,
+ NIL);
/*
* Initialize information needed to insert this and
@@ -527,7 +531,8 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
* partition-key becomes a DELETE+INSERT operation, so this check is still
* required when the operation is CMD_UPDATE.
*/
- CheckValidResultRel(leaf_part_rri, CMD_INSERT, NIL);
+ CheckValidResultRel(leaf_part_rri, CMD_INSERT,
+ node ? node->onConflictAction : ONCONFLICT_NONE, NIL);
/*
* Open partition indices. The user may have asked to check for conflicts
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 7c6c2c1f6e4..4c5647ac38a 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -3402,7 +3402,7 @@ lmerge_matched:
* the tuple moved, and setting our current
* resultRelInfo to that.
*/
- if (ItemPointerIndicatesMovedPartitions(&context->tmfd.ctid))
+ if (ItemPointerIndicatesMovedPartitions(tupleid))
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("tuple to be merged was already moved to another partition due to concurrent update")));
@@ -3450,12 +3450,13 @@ lmerge_matched:
if (ItemPointerIsValid(&lockedtid))
UnlockTuple(resultRelInfo->ri_RelationDesc, &lockedtid,
InplaceUpdateTupleLock);
- LockTuple(resultRelInfo->ri_RelationDesc, &context->tmfd.ctid,
+ LockTuple(resultRelInfo->ri_RelationDesc, tupleid,
InplaceUpdateTupleLock);
- lockedtid = context->tmfd.ctid;
+ lockedtid = *tupleid;
}
+
if (!table_tuple_fetch_row_version(resultRelationDesc,
- &context->tmfd.ctid,
+ tupleid,
SnapshotAny,
resultRelInfo->ri_oldTupleSlot))
elog(ERROR, "failed to fetch the target tuple");
@@ -4811,7 +4812,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/*
* Verify result relation is a valid target for the current operation
*/
- CheckValidResultRel(resultRelInfo, operation, mergeActions);
+ CheckValidResultRel(resultRelInfo, operation, node->onConflictAction,
+ mergeActions);
resultRelInfo++;
i++;