From 13ee7d66b9c0bc9a16252c163bfcfda06728a2b2 Mon Sep 17 00:00:00 2001
From: amitlan <amitlangote09@gmail.com>
Date: Thu, 12 Nov 2020 15:04:02 +0900
Subject: [PATCH v12 2/3] Rethink ResultRelInfo.ri_PartitionRoot

Its current usage is specific to partition tuple routing, although
there are other places that could use it do determine the original
target relation of the query without having access to the
ModifyTableState.  So set it in all result relations, not just
those that are targets of tuple routing.  While at it, also rename
the field to ri_RootTargetDesc to denote its wider scope.

This also removes the many instances of a stanza to convert a routed
tuple in the partition's format into the format of the original target
relation of the query in favor of just showing the partition format
tuple in the error messages, which seems harmless, but wasn't thought
to be so when the code was originally written.
---
 src/backend/commands/copyfrom.c               |   2 +-
 src/backend/commands/tablecmds.c              |   2 +-
 src/backend/executor/execMain.c               | 181 +++---------------
 src/backend/executor/execPartition.c          |  11 +-
 src/backend/executor/execUtils.c              |   4 +-
 src/backend/executor/nodeModifyTable.c        |  18 +-
 src/backend/replication/logical/worker.c      |   6 +-
 src/include/executor/executor.h               |   4 +-
 src/include/nodes/execnodes.h                 |   4 +-
 src/test/regress/expected/inherit.out         |   8 +-
 src/test/regress/expected/insert.out          |   6 +-
 src/test/regress/expected/updatable_views.out |   4 +-
 src/test/regress/expected/update.out          |   2 +-
 13 files changed, 61 insertions(+), 191 deletions(-)

diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 1b14e9a6eb..804526e80e 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -648,7 +648,7 @@ CopyFrom(CopyFromState cstate)
 	 */
 	ExecInitRangeTable(estate, cstate->range_table);
 	resultRelInfo = target_resultRelInfo = makeNode(ResultRelInfo);
-	ExecInitResultRelation(estate, resultRelInfo, 1);
+	ExecInitResultRelation(estate, resultRelInfo, 1, cstate->rel);
 
 	/* Verify the named relation is a valid target for INSERT */
 	CheckValidResultRel(resultRelInfo, CMD_INSERT);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1fa9f19f08..e52f74413a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1804,7 +1804,7 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
 		InitResultRelInfo(resultRelInfo,
 						  rel,
 						  0,	/* dummy rangetable index */
-						  NULL,
+						  rel,
 						  0);
 		estate->es_opened_result_relations =
 			lappend(estate->es_opened_result_relations, resultRelInfo);
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 7179f589f9..d133a14f61 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -93,11 +93,10 @@ static bool ExecCheckRTEPermsModified(Oid relOid, Oid userid,
 									  Bitmapset *modifiedCols,
 									  AclMode requiredPerms);
 static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt);
-static char *ExecBuildSlotValueDescription(Oid reloid,
-										   TupleTableSlot *slot,
-										   TupleDesc tupdesc,
-										   Bitmapset *modifiedCols,
-										   int maxfieldlen);
+static char *ExecBuildSlotValueDescription(EState *estate,
+							  ResultRelInfo *resultRelInfo,
+							  TupleTableSlot *slot,
+							  int maxfieldlen);
 static void EvalPlanQualStart(EPQState *epqstate, Plan *planTree);
 
 /*
@@ -1196,13 +1195,14 @@ void
 InitResultRelInfo(ResultRelInfo *resultRelInfo,
 				  Relation resultRelationDesc,
 				  Index resultRelationIndex,
-				  Relation partition_root,
+				  Relation rootTargetDesc,
 				  int instrument_options)
 {
 	MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
 	resultRelInfo->type = T_ResultRelInfo;
 	resultRelInfo->ri_RangeTableIndex = resultRelationIndex;
 	resultRelInfo->ri_RelationDesc = resultRelationDesc;
+	resultRelInfo->ri_RootTargetDesc = rootTargetDesc;
 	resultRelInfo->ri_NumIndices = 0;
 	resultRelInfo->ri_IndexRelationDescs = NULL;
 	resultRelInfo->ri_IndexRelationInfo = NULL;
@@ -1242,7 +1242,6 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
 	resultRelInfo->ri_ReturningSlot = NULL;
 	resultRelInfo->ri_TrigOldSlot = NULL;
 	resultRelInfo->ri_TrigNewSlot = NULL;
-	resultRelInfo->ri_PartitionRoot = partition_root;
 	resultRelInfo->ri_RootToPartitionMap = NULL;	/* set by
 													 * ExecInitRoutingInfo */
 	resultRelInfo->ri_PartitionTupleSlot = NULL;	/* ditto */
@@ -1321,7 +1320,7 @@ ExecGetTriggerResultRel(EState *estate, Oid relid)
 	InitResultRelInfo(rInfo,
 					  rel,
 					  0,		/* dummy rangetable index */
-					  NULL,
+					  rel,
 					  estate->es_instrument);
 	estate->es_trig_target_relations =
 		lappend(estate->es_trig_target_relations, rInfo);
@@ -1733,50 +1732,11 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
 							TupleTableSlot *slot,
 							EState *estate)
 {
-	Oid			root_relid;
-	TupleDesc	tupdesc;
 	char	   *val_desc;
-	Bitmapset  *modifiedCols;
-
-	/*
-	 * If the tuple has been routed, it's been converted to the partition's
-	 * rowtype, which might differ from the root table's.  We must convert it
-	 * back to the root table's rowtype so that val_desc in the error message
-	 * matches the input tuple.
-	 */
-	if (resultRelInfo->ri_PartitionRoot)
-	{
-		TupleDesc	old_tupdesc;
-		AttrMap    *map;
-
-		root_relid = RelationGetRelid(resultRelInfo->ri_PartitionRoot);
-		tupdesc = RelationGetDescr(resultRelInfo->ri_PartitionRoot);
-
-		old_tupdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
-		/* a reverse map */
-		map = build_attrmap_by_name_if_req(old_tupdesc, tupdesc);
-
-		/*
-		 * Partition-specific slot's tupdesc can't be changed, so allocate a
-		 * new one.
-		 */
-		if (map != NULL)
-			slot = execute_attr_map_slot(map, slot,
-										 MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
-	}
-	else
-	{
-		root_relid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
-		tupdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
-	}
-
-	modifiedCols = bms_union(GetInsertedColumns(resultRelInfo, estate),
-							 GetUpdatedColumns(resultRelInfo, estate));
 
-	val_desc = ExecBuildSlotValueDescription(root_relid,
+	val_desc = ExecBuildSlotValueDescription(estate,
+											 resultRelInfo,
 											 slot,
-											 tupdesc,
-											 modifiedCols,
 											 64);
 	ereport(ERROR,
 			(errcode(ERRCODE_CHECK_VIOLATION),
@@ -1804,9 +1764,6 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
 	Relation	rel = resultRelInfo->ri_RelationDesc;
 	TupleDesc	tupdesc = RelationGetDescr(rel);
 	TupleConstr *constr = tupdesc->constr;
-	Bitmapset  *modifiedCols;
-	Bitmapset  *insertedCols;
-	Bitmapset  *updatedCols;
 
 	Assert(constr);				/* we should not be called otherwise */
 
@@ -1821,52 +1778,20 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
 
 			if (att->attnotnull && slot_attisnull(slot, attrChk))
 			{
-				char	   *val_desc;
-				Relation	orig_rel = rel;
-				TupleDesc	orig_tupdesc = RelationGetDescr(rel);
-
-				/*
-				 * If the tuple has been routed, it's been converted to the
-				 * partition's rowtype, which might differ from the root
-				 * table's.  We must convert it back to the root table's
-				 * rowtype so that val_desc shown error message matches the
-				 * input tuple.
-				 */
-				if (resultRelInfo->ri_PartitionRoot)
-				{
-					AttrMap    *map;
-
-					rel = resultRelInfo->ri_PartitionRoot;
-					tupdesc = RelationGetDescr(rel);
-					/* a reverse map */
-					map = build_attrmap_by_name_if_req(orig_tupdesc,
-													   tupdesc);
-
-					/*
-					 * Partition-specific slot's tupdesc can't be changed, so
-					 * allocate a new one.
-					 */
-					if (map != NULL)
-						slot = execute_attr_map_slot(map, slot,
-													 MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
-				}
+				char   *val_desc;
 
-				insertedCols = GetInsertedColumns(resultRelInfo, estate);
-				updatedCols = GetUpdatedColumns(resultRelInfo, estate);
-				modifiedCols = bms_union(insertedCols, updatedCols);
-				val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
+				val_desc = ExecBuildSlotValueDescription(estate,
+														 resultRelInfo,
 														 slot,
-														 tupdesc,
-														 modifiedCols,
 														 64);
 
 				ereport(ERROR,
 						(errcode(ERRCODE_NOT_NULL_VIOLATION),
 						 errmsg("null value in column \"%s\" of relation \"%s\" violates not-null constraint",
 								NameStr(att->attname),
-								RelationGetRelationName(orig_rel)),
+								RelationGetRelationName(rel)),
 						 val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
-						 errtablecol(orig_rel, attrChk)));
+						 errtablecol(rel, attrChk)));
 			}
 		}
 	}
@@ -1878,43 +1803,16 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
 		if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)
 		{
 			char	   *val_desc;
-			Relation	orig_rel = rel;
 
-			/* See the comment above. */
-			if (resultRelInfo->ri_PartitionRoot)
-			{
-				TupleDesc	old_tupdesc = RelationGetDescr(rel);
-				AttrMap    *map;
-
-				rel = resultRelInfo->ri_PartitionRoot;
-				tupdesc = RelationGetDescr(rel);
-				/* a reverse map */
-				map = build_attrmap_by_name_if_req(old_tupdesc,
-												   tupdesc);
-
-				/*
-				 * Partition-specific slot's tupdesc can't be changed, so
-				 * allocate a new one.
-				 */
-				if (map != NULL)
-					slot = execute_attr_map_slot(map, slot,
-												 MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
-			}
-
-			insertedCols = GetInsertedColumns(resultRelInfo, estate);
-			updatedCols = GetUpdatedColumns(resultRelInfo, estate);
-			modifiedCols = bms_union(insertedCols, updatedCols);
-			val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
+			val_desc = ExecBuildSlotValueDescription(estate, resultRelInfo,
 													 slot,
-													 tupdesc,
-													 modifiedCols,
 													 64);
 			ereport(ERROR,
 					(errcode(ERRCODE_CHECK_VIOLATION),
 					 errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
-							RelationGetRelationName(orig_rel), failed),
+							RelationGetRelationName(rel), failed),
 					 val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
-					 errtableconstraint(orig_rel, failed)));
+					 errtableconstraint(rel, failed)));
 		}
 	}
 }
@@ -1932,8 +1830,6 @@ void
 ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
 					 TupleTableSlot *slot, EState *estate)
 {
-	Relation	rel = resultRelInfo->ri_RelationDesc;
-	TupleDesc	tupdesc = RelationGetDescr(rel);
 	ExprContext *econtext;
 	ListCell   *l1,
 			   *l2;
@@ -1971,9 +1867,6 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
 		if (!ExecQual(wcoExpr, econtext))
 		{
 			char	   *val_desc;
-			Bitmapset  *modifiedCols;
-			Bitmapset  *insertedCols;
-			Bitmapset  *updatedCols;
 
 			switch (wco->kind)
 			{
@@ -1987,34 +1880,9 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
 					 * USING policy.
 					 */
 				case WCO_VIEW_CHECK:
-					/* See the comment in ExecConstraints(). */
-					if (resultRelInfo->ri_PartitionRoot)
-					{
-						TupleDesc	old_tupdesc = RelationGetDescr(rel);
-						AttrMap    *map;
-
-						rel = resultRelInfo->ri_PartitionRoot;
-						tupdesc = RelationGetDescr(rel);
-						/* a reverse map */
-						map = build_attrmap_by_name_if_req(old_tupdesc,
-														   tupdesc);
-
-						/*
-						 * Partition-specific slot's tupdesc can't be changed,
-						 * so allocate a new one.
-						 */
-						if (map != NULL)
-							slot = execute_attr_map_slot(map, slot,
-														 MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
-					}
-
-					insertedCols = GetInsertedColumns(resultRelInfo, estate);
-					updatedCols = GetUpdatedColumns(resultRelInfo, estate);
-					modifiedCols = bms_union(insertedCols, updatedCols);
-					val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
+					val_desc = ExecBuildSlotValueDescription(estate,
+															 resultRelInfo,
 															 slot,
-															 tupdesc,
-															 modifiedCols,
 															 64);
 
 					ereport(ERROR,
@@ -2077,10 +1945,9 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
  * columns they are.
  */
 static char *
-ExecBuildSlotValueDescription(Oid reloid,
+ExecBuildSlotValueDescription(EState *estate,
+							  ResultRelInfo *resultRelInfo,
 							  TupleTableSlot *slot,
-							  TupleDesc tupdesc,
-							  Bitmapset *modifiedCols,
 							  int maxfieldlen)
 {
 	StringInfoData buf;
@@ -2091,6 +1958,9 @@ ExecBuildSlotValueDescription(Oid reloid,
 	AclResult	aclresult;
 	bool		table_perm = false;
 	bool		any_perm = false;
+	Oid			reloid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
+	TupleDesc	tupdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
+	Bitmapset  *modifiedCols;
 
 	/*
 	 * Check if RLS is enabled and should be active for the relation; if so,
@@ -2100,6 +1970,9 @@ ExecBuildSlotValueDescription(Oid reloid,
 	if (check_enable_rls(reloid, InvalidOid, true) == RLS_ENABLED)
 		return NULL;
 
+	modifiedCols = bms_union(GetInsertedColumns(resultRelInfo, estate),
+							 GetUpdatedColumns(resultRelInfo, estate));
+
 	initStringInfo(&buf);
 
 	appendStringInfoChar(&buf, '(');
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 97bfc8bd71..50ed83e4c8 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -541,13 +541,6 @@ ExecHashSubPlanResultRelsByOid(ModifyTableState *mtstate,
 			hash_search(htab, &partoid, HASH_ENTER, &found);
 		Assert(!found);
 		elem->rri = rri;
-
-		/*
-		 * This is required in order to convert the partition's tuple to be
-		 * compatible with the root partitioned table's tuple descriptor. When
-		 * generating the per-subplan result rels, this was not set.
-		 */
-		rri->ri_PartitionRoot = proute->partition_root;
 	}
 }
 
@@ -917,7 +910,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
 	if (mtstate->mt_transition_capture || mtstate->mt_oc_transition_capture)
 		leaf_part_rri->ri_ChildToRootMap =
 			convert_tuples_by_name(RelationGetDescr(leaf_part_rri->ri_RelationDesc),
-								   RelationGetDescr(leaf_part_rri->ri_PartitionRoot));
+								   RelationGetDescr(leaf_part_rri->ri_RootTargetDesc));
 
 	/*
 	 * Since we've just initialized this ResultRelInfo, it's not in any list
@@ -961,7 +954,7 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
 	 * partition from the parent's type to the partition's.
 	 */
 	partRelInfo->ri_RootToPartitionMap =
-		convert_tuples_by_name(RelationGetDescr(partRelInfo->ri_PartitionRoot),
+		convert_tuples_by_name(RelationGetDescr(partRelInfo->ri_RootTargetDesc),
 							   RelationGetDescr(partRelInfo->ri_RelationDesc));
 
 	/*
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 071a0007eb..9819e7ae6f 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -831,7 +831,7 @@ ExecGetRangeTableRelation(EState *estate, Index rti)
  */
 void
 ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo,
-					   Index rti)
+					   Index rti, Relation rootTargetDesc)
 {
 	Relation	resultRelationDesc;
 
@@ -839,7 +839,7 @@ ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo,
 	InitResultRelInfo(resultRelInfo,
 					  resultRelationDesc,
 					  rti,
-					  NULL,
+					  rootTargetDesc,
 					  estate->es_instrument);
 
 	if (estate->es_result_relations == NULL)
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index ab3d655e60..3e325435ba 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -508,7 +508,8 @@ ExecInsert(ModifyTableState *mtstate,
 		 * if there's no BR trigger defined on the partition.
 		 */
 		if (resultRelationDesc->rd_rel->relispartition &&
-			(resultRelInfo->ri_PartitionRoot == NULL ||
+			(resultRelInfo->ri_RelationDesc ==
+			 resultRelInfo->ri_RootTargetDesc ||
 			 (resultRelInfo->ri_TrigDesc &&
 			  resultRelInfo->ri_TrigDesc->trig_insert_before_row)))
 			ExecPartitionCheck(resultRelInfo, slot, estate, true);
@@ -2216,15 +2217,19 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 	 */
 	if (node->rootRelation > 0)
 	{
+		rel = ExecGetRangeTableRelation(estate, node->rootRelation);
 		mtstate->rootResultRelInfo = makeNode(ResultRelInfo);
 		ExecInitResultRelation(estate, mtstate->rootResultRelInfo,
-							   node->rootRelation);
+							   node->rootRelation, rel);
 	}
 	else
 	{
+		Index	rootRelation = linitial_int(node->resultRelations);
+
+		rel = ExecGetRangeTableRelation(estate, rootRelation);
 		mtstate->rootResultRelInfo = mtstate->resultRelInfo;
-		ExecInitResultRelation(estate, mtstate->resultRelInfo,
-							   linitial_int(node->resultRelations));
+		ExecInitResultRelation(estate, mtstate->resultRelInfo, rootRelation,
+							   rel);
 	}
 
 	mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
@@ -2260,7 +2265,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 		 * was initialized already.)
 		 */
 		if (resultRelInfo != mtstate->rootResultRelInfo)
-			ExecInitResultRelation(estate, resultRelInfo, resultRelation);
+			ExecInitResultRelation(estate, resultRelInfo, resultRelation, rel);
 
 		/* Initialize the usesFdwDirectModify flag */
 		resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
@@ -2337,9 +2342,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 		i++;
 	}
 
-	/* Get the target relation */
-	rel = mtstate->rootResultRelInfo->ri_RelationDesc;
-
 	/*
 	 * If it's not a partitioned table after all, UPDATE tuple routing should
 	 * not be attempted.
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 3874939380..2720375e40 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -1181,7 +1181,7 @@ apply_handle_insert(StringInfo s)
 										RelationGetDescr(rel->localrel),
 										&TTSOpsVirtual);
 	resultRelInfo = makeNode(ResultRelInfo);
-	InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
+	InitResultRelInfo(resultRelInfo, rel->localrel, 1, rel->localrel, 0);
 
 	/* Input functions may need an active snapshot, so get one */
 	PushActiveSnapshot(GetTransactionSnapshot());
@@ -1306,7 +1306,7 @@ apply_handle_update(StringInfo s)
 										RelationGetDescr(rel->localrel),
 										&TTSOpsVirtual);
 	resultRelInfo = makeNode(ResultRelInfo);
-	InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
+	InitResultRelInfo(resultRelInfo, rel->localrel, 1, rel->localrel, 0);
 
 	/*
 	 * Populate updatedCols so that per-column triggers can fire.  This could
@@ -1462,7 +1462,7 @@ apply_handle_delete(StringInfo s)
 										RelationGetDescr(rel->localrel),
 										&TTSOpsVirtual);
 	resultRelInfo = makeNode(ResultRelInfo);
-	InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
+	InitResultRelInfo(resultRelInfo, rel->localrel, 1, rel->localrel, 0);
 
 	PushActiveSnapshot(GetTransactionSnapshot());
 
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 0c48d2a519..2bc349b782 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -191,7 +191,7 @@ extern void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
 extern void InitResultRelInfo(ResultRelInfo *resultRelInfo,
 							  Relation resultRelationDesc,
 							  Index resultRelationIndex,
-							  Relation partition_root,
+							  Relation rootTargetDesc,
 							  int instrument_options);
 extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
 extern void ExecConstraints(ResultRelInfo *resultRelInfo,
@@ -551,7 +551,7 @@ exec_rt_fetch(Index rti, EState *estate)
 
 extern Relation ExecGetRangeTableRelation(EState *estate, Index rti);
 extern void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo,
-								   Index rti);
+								   Index rti, Relation rootTargetDesc);
 
 extern int	executor_errposition(EState *estate, int location);
 
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 61ba4c3666..e6bdf80555 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -411,6 +411,9 @@ typedef struct ResultRelInfo
 	/* relation descriptor for result relation */
 	Relation	ri_RelationDesc;
 
+	/* relation descriptor of the original target relation */
+	Relation	ri_RootTargetDesc;
+
 	/* # of indices existing on result relation */
 	int			ri_NumIndices;
 
@@ -487,7 +490,6 @@ typedef struct ResultRelInfo
 	 * ExecInitRoutingInfo, are non-NULL if partition has a different tuple
 	 * format than the root table.
 	 */
-	Relation	ri_PartitionRoot;
 	TupleConversionMap *ri_RootToPartitionMap;
 	TupleTableSlot *ri_PartitionTupleSlot;
 
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 2b68aef654..42efca0581 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -2458,7 +2458,7 @@ ERROR:  new row for relation "errtst_child_plaindef" violates check constraint "
 DETAIL:  Failing row contains (10, 1, 10).
 INSERT INTO errtst_parent(partid, shdata, data) VALUES ('20', '1', '10');
 ERROR:  new row for relation "errtst_child_reorder" violates check constraint "errtst_child_reorder_data_check"
-DETAIL:  Failing row contains (20, 1, 10).
+DETAIL:  Failing row contains (10, 1, 20).
 -- insert with child not null constraint error
 INSERT INTO errtst_parent(partid, shdata, data) VALUES ( '0', '1', NULL);
 ERROR:  null value in column "data" of relation "errtst_child_fastdef" violates not-null constraint
@@ -2468,7 +2468,7 @@ ERROR:  null value in column "data" of relation "errtst_child_plaindef" violates
 DETAIL:  Failing row contains (10, 1, null).
 INSERT INTO errtst_parent(partid, shdata, data) VALUES ('20', '1', NULL);
 ERROR:  null value in column "data" of relation "errtst_child_reorder" violates not-null constraint
-DETAIL:  Failing row contains (20, 1, null).
+DETAIL:  Failing row contains (null, 1, 20).
 -- insert with shared check constraint error
 INSERT INTO errtst_parent(partid, shdata, data) VALUES ( '0', '5', '5');
 ERROR:  new row for relation "errtst_child_fastdef" violates check constraint "shdata_small"
@@ -2478,7 +2478,7 @@ ERROR:  new row for relation "errtst_child_plaindef" violates check constraint "
 DETAIL:  Failing row contains (10, 5, 5).
 INSERT INTO errtst_parent(partid, shdata, data) VALUES ('20', '5', '5');
 ERROR:  new row for relation "errtst_child_reorder" violates check constraint "shdata_small"
-DETAIL:  Failing row contains (20, 5, 5).
+DETAIL:  Failing row contains (5, 5, 20).
 -- within partition update without child check constraint violation
 BEGIN;
 UPDATE errtst_parent SET data = data + 1 WHERE partid = 0;
@@ -2523,7 +2523,7 @@ ERROR:  new row for relation "errtst_child_plaindef" violates check constraint "
 DETAIL:  Failing row contains (10, 1, 15).
 UPDATE errtst_parent SET partid = 20, data = data + 10 WHERE partid = 10;
 ERROR:  new row for relation "errtst_child_reorder" violates check constraint "errtst_child_reorder_data_check"
-DETAIL:  Failing row contains (20, 1, 15).
+DETAIL:  Failing row contains (15, 1, 20).
 UPDATE errtst_parent SET partid = 0, data = data + 10 WHERE partid = 20;
 ERROR:  new row for relation "errtst_child_fastdef" violates check constraint "errtest_child_fastdef_data_check"
 DETAIL:  Failing row contains (0, 1, 15).
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index da50ee3b67..f132d7458b 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -546,7 +546,7 @@ create trigger mlparted11_trig before insert ON mlparted11
 -- to the BR trigger mlparted11_trig_fn)
 insert into mlparted values (1, 2);
 ERROR:  new row for relation "mlparted11" violates check constraint "check_b"
-DETAIL:  Failing row contains (1, 4).
+DETAIL:  Failing row contains (4, 1).
 drop trigger mlparted11_trig on mlparted11;
 drop function mlparted11_trig_fn();
 -- check that inserting into an internal partition successfully results in
@@ -592,12 +592,12 @@ alter table mlparted attach partition mlparted5 for values from (1, 40) to (1, 5
 alter table mlparted add constraint check_b check (a = 1 and b < 45);
 insert into mlparted values (1, 45, 'a');
 ERROR:  new row for relation "mlparted5a" violates check constraint "check_b"
-DETAIL:  Failing row contains (1, 45, a).
+DETAIL:  Failing row contains (1, a, 45).
 create function mlparted5abrtrig_func() returns trigger as $$ begin new.c = 'b'; return new; end; $$ language plpgsql;
 create trigger mlparted5abrtrig before insert on mlparted5a for each row execute procedure mlparted5abrtrig_func();
 insert into mlparted5 (a, b, c) values (1, 40, 'a');
 ERROR:  new row for relation "mlparted5a" violates partition constraint
-DETAIL:  Failing row contains (b, 1, 40).
+DETAIL:  Failing row contains (1, b, 40).
 drop table mlparted5;
 alter table mlparted drop constraint check_b;
 -- Check multi-level default partition
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index 24905332b1..e77a2ee41c 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -2648,7 +2648,7 @@ select tableoid::regclass, * from uv_pt;
 create view uv_ptv_wco as select * from uv_pt where a = 0 with check option;
 insert into uv_ptv_wco values (1, 2);
 ERROR:  new row violates check option for view "uv_ptv_wco"
-DETAIL:  Failing row contains (1, 2, null).
+DETAIL:  Failing row contains (2, null, 1).
 drop view uv_ptv, uv_ptv_wco;
 drop table uv_pt, uv_pt1, uv_pt11;
 -- check that wholerow vars appearing in WITH CHECK OPTION constraint expressions
@@ -2674,7 +2674,7 @@ with check option;
 -- rowtype after tuple-routing
 insert into wcowrtest_v2 values (2, 'no such row in sometable');
 ERROR:  new row violates check option for view "wcowrtest_v2"
-DETAIL:  Failing row contains (2, no such row in sometable).
+DETAIL:  Failing row contains (no such row in sometable, 2).
 drop view wcowrtest_v, wcowrtest_v2;
 drop table wcowrtest, sometable;
 -- Check INSERT .. ON CONFLICT DO UPDATE works correctly when the view's
diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out
index bf939d79f6..8819921d0a 100644
--- a/src/test/regress/expected/update.out
+++ b/src/test/regress/expected/update.out
@@ -409,7 +409,7 @@ DETAIL:  Failing row contains (a, 4, 120, 1, 1).
 -- fail, row movement with check option violation
 UPDATE upview set a = 'b', b = 15, c = 120 WHERE b = 4;
 ERROR:  new row violates check option for view "upview"
-DETAIL:  Failing row contains (b, 15, 120, 1, 1).
+DETAIL:  Failing row contains (1, 120, 1, b, 15).
 -- ok, row movement, check option passes
 UPDATE upview set a = 'b', b = 15 WHERE b = 4;
 :show_data;
-- 
2.24.1

