mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Fix replica identity check for MERGE.
When executing a MERGE, check that the target relation supports all actions mentioned in the MERGE command. Specifically, check that it has a REPLICA IDENTITY if it publishes updates or deletes and the MERGE command contains update or delete actions. Failing to do this can silently break replication. Author: Zhijie Hou <houzj.fnst@fujitsu.com> Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com> Tested-by: Chao Li <li.evan.chao@gmail.com> Discussion: https://postgr.es/m/OS3PR01MB57180C87E43A679A730482DF94B62@OS3PR01MB5718.jpnprd01.prod.outlook.com Backpatch-through: 15
This commit is contained in:
		@@ -984,12 +984,16 @@ InitPlan(QueryDesc *queryDesc, int eflags)
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Note: when changing this function, you probably also need to look at
 | 
			
		||||
 * CheckValidRowMarkRel.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
CheckValidResultRelNew(ResultRelInfo *resultRelInfo, CmdType operation,
 | 
			
		||||
					   OnConflictAction onConflictAction)
 | 
			
		||||
					   OnConflictAction onConflictAction, List *mergeActions)
 | 
			
		||||
{
 | 
			
		||||
	Relation	resultRel = resultRelInfo->ri_RelationDesc;
 | 
			
		||||
	TriggerDesc *trigDesc = resultRel->trigdesc;
 | 
			
		||||
@@ -1003,7 +1007,24 @@ CheckValidResultRelNew(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)
 | 
			
		||||
			{
 | 
			
		||||
				ListCell   *lc;
 | 
			
		||||
 | 
			
		||||
				foreach(lc, mergeActions)
 | 
			
		||||
				{
 | 
			
		||||
					MergeAction *action = (MergeAction *) lfirst(lc);
 | 
			
		||||
 | 
			
		||||
					CheckCmdReplicaIdentity(resultRel, action->commandType);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				CheckCmdReplicaIdentity(resultRel, operation);
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * For INSERT ON CONFLICT DO UPDATE, additionally check that the
 | 
			
		||||
@@ -1136,7 +1157,7 @@ CheckValidResultRelNew(ResultRelInfo *resultRelInfo, CmdType operation,
 | 
			
		||||
void
 | 
			
		||||
CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
 | 
			
		||||
{
 | 
			
		||||
	return CheckValidResultRelNew(resultRelInfo, operation, ONCONFLICT_NONE);
 | 
			
		||||
	return CheckValidResultRelNew(resultRelInfo, operation, ONCONFLICT_NONE, NIL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -364,7 +364,8 @@ ExecFindPartition(ModifyTableState *mtstate,
 | 
			
		||||
 | 
			
		||||
					/* Verify this ResultRelInfo allows INSERTs */
 | 
			
		||||
					CheckValidResultRelNew(rri, CMD_INSERT,
 | 
			
		||||
										   node ? node->onConflictAction : ONCONFLICT_NONE);
 | 
			
		||||
										   node ? node->onConflictAction : ONCONFLICT_NONE,
 | 
			
		||||
										   NIL);
 | 
			
		||||
 | 
			
		||||
					/*
 | 
			
		||||
					 * Initialize information needed to insert this and
 | 
			
		||||
@@ -531,7 +532,8 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
 | 
			
		||||
	 * required when the operation is CMD_UPDATE.
 | 
			
		||||
	 */
 | 
			
		||||
	CheckValidResultRelNew(leaf_part_rri, CMD_INSERT,
 | 
			
		||||
						   node ? node->onConflictAction : ONCONFLICT_NONE);
 | 
			
		||||
						   node ? node->onConflictAction : ONCONFLICT_NONE,
 | 
			
		||||
						   NIL);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Open partition indices.  The user may have asked to check for conflicts
 | 
			
		||||
 
 | 
			
		||||
@@ -4220,6 +4220,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 | 
			
		||||
	foreach(l, node->resultRelations)
 | 
			
		||||
	{
 | 
			
		||||
		Index		resultRelation = lfirst_int(l);
 | 
			
		||||
		List	   *mergeActions = NIL;
 | 
			
		||||
 | 
			
		||||
		if (node->mergeActionLists)
 | 
			
		||||
			mergeActions = list_nth(node->mergeActionLists, i);
 | 
			
		||||
 | 
			
		||||
		if (resultRelInfo != mtstate->rootResultRelInfo)
 | 
			
		||||
		{
 | 
			
		||||
@@ -4242,7 +4246,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 | 
			
		||||
		 * Verify result relation is a valid target for the current operation
 | 
			
		||||
		 */
 | 
			
		||||
		CheckValidResultRelNew(resultRelInfo, operation,
 | 
			
		||||
							   node->onConflictAction);
 | 
			
		||||
							   node->onConflictAction, mergeActions);
 | 
			
		||||
 | 
			
		||||
		resultRelInfo++;
 | 
			
		||||
		i++;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user