aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2021-02-08 11:01:51 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2021-02-08 11:01:55 +0200
commit8e56684d54d44ba4ed737d5847d31fba6fb13763 (patch)
tree45755445ea059c3dbfa9da83e7ee4e9334e5f883 /src/backend/executor
parentb4199a94946388c60586b44ad82e77755e1543f4 (diff)
downloadpostgresql-8e56684d54d44ba4ed737d5847d31fba6fb13763.tar.gz
postgresql-8e56684d54d44ba4ed737d5847d31fba6fb13763.zip
Fix permission checks on constraint violation errors on partitions.
If a cross-partition UPDATE violates a constraint on the target partition, and the columns in the new partition are in different physical order than in the parent, the error message can reveal columns that the user does not have SELECT permission on. A similar bug was fixed earlier in commit 804b6b6db4. The cause of the bug is that the callers of the ExecBuildSlotValueDescription() function got confused when constructing the list of modified columns. If the tuple was routed from a parent, we converted the tuple to the parent's format, but the list of modified columns was grabbed directly from the child's RTE entry. ExecUpdateLockMode() had a similar issue. That lead to confusion on which columns are key columns, leading to wrong tuple lock being taken on tables referenced by foreign keys, when a row is updated with INSERT ON CONFLICT UPDATE. A new isolation test is added for that corner case. With this patch, the ri_RangeTableIndex field is no longer set for partitions that don't have an entry in the range table. Previously, it was set to the RTE entry of the parent relation, but that was confusing. NOTE: This modifies the ResultRelInfo struct, replacing the ri_PartitionRoot field with ri_RootResultRelInfo. That's a bit risky to backpatch, because it breaks any extensions accessing the field. The change that ri_RangeTableIndex is not set for partitions could potentially break extensions, too. The ResultRelInfos are visible to FDWs at least, and this patch required small changes to postgres_fdw. Nevertheless, this seem like the least bad option. I don't think these fields widely used in extensions; I don't think there are FDWs out there that uses the FDW "direct update" API, other than postgres_fdw. If there is, you will get a compilation error, so hopefully it is caught quickly. Backpatch to 11, where support for both cross-partition UPDATEs, and unique indexes on partitioned tables, were added. Reviewed-by: Amit Langote Security: CVE-2021-3393
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c87
-rw-r--r--src/backend/executor/execPartition.c33
-rw-r--r--src/backend/executor/execUtils.c89
-rw-r--r--src/backend/executor/nodeModifyTable.c4
4 files changed, 147 insertions, 66 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 4fdffad6f35..565262dd27d 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -100,20 +100,6 @@ static char *ExecBuildSlotValueDescription(Oid reloid,
int maxfieldlen);
static void EvalPlanQualStart(EPQState *epqstate, Plan *planTree);
-/*
- * Note that GetAllUpdatedColumns() also exists in commands/trigger.c. There does
- * not appear to be any good header to put it into, given the structures that
- * it uses, so we let them be duplicated. Be sure to update both if one needs
- * to be changed, however.
- */
-#define GetInsertedColumns(relinfo, estate) \
- (exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->insertedCols)
-#define GetUpdatedColumns(relinfo, estate) \
- (exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols)
-#define GetAllUpdatedColumns(relinfo, estate) \
- (bms_union(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols, \
- exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->extraUpdatedCols))
-
/* end of local decls */
@@ -1277,7 +1263,7 @@ void
InitResultRelInfo(ResultRelInfo *resultRelInfo,
Relation resultRelationDesc,
Index resultRelationIndex,
- Relation partition_root,
+ ResultRelInfo *partition_root_rri,
int instrument_options)
{
List *partition_check = NIL;
@@ -1342,7 +1328,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
partition_check = RelationGetPartitionQual(resultRelationDesc);
resultRelInfo->ri_PartitionCheck = partition_check;
- resultRelInfo->ri_PartitionRoot = partition_root;
+ resultRelInfo->ri_RootResultRelInfo = partition_root_rri;
resultRelInfo->ri_PartitionInfo = NULL; /* may be set later */
resultRelInfo->ri_CopyMultiInsertBuffer = NULL;
}
@@ -1840,13 +1826,14 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
* back to the root table's rowtype so that val_desc in the error message
* matches the input tuple.
*/
- if (resultRelInfo->ri_PartitionRoot)
+ if (resultRelInfo->ri_RootResultRelInfo)
{
+ ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
TupleDesc old_tupdesc;
AttrMap *map;
- root_relid = RelationGetRelid(resultRelInfo->ri_PartitionRoot);
- tupdesc = RelationGetDescr(resultRelInfo->ri_PartitionRoot);
+ root_relid = RelationGetRelid(rootrel->ri_RelationDesc);
+ tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
old_tupdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
/* a reverse map */
@@ -1859,16 +1846,17 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
if (map != NULL)
slot = execute_attr_map_slot(map, slot,
MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
+ modifiedCols = bms_union(ExecGetInsertedCols(rootrel, estate),
+ ExecGetUpdatedCols(rootrel, estate));
}
else
{
root_relid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
tupdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
+ modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
+ ExecGetUpdatedCols(resultRelInfo, estate));
}
- modifiedCols = bms_union(GetInsertedColumns(resultRelInfo, estate),
- GetUpdatedColumns(resultRelInfo, estate));
-
val_desc = ExecBuildSlotValueDescription(root_relid,
slot,
tupdesc,
@@ -1901,8 +1889,6 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
TupleDesc tupdesc = RelationGetDescr(rel);
TupleConstr *constr = tupdesc->constr;
Bitmapset *modifiedCols;
- Bitmapset *insertedCols;
- Bitmapset *updatedCols;
Assert(constr || resultRelInfo->ri_PartitionCheck);
@@ -1928,12 +1914,12 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
* rowtype so that val_desc shown error message matches the
* input tuple.
*/
- if (resultRelInfo->ri_PartitionRoot)
+ if (resultRelInfo->ri_RootResultRelInfo)
{
+ ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
AttrMap *map;
- rel = resultRelInfo->ri_PartitionRoot;
- tupdesc = RelationGetDescr(rel);
+ tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
/* a reverse map */
map = build_attrmap_by_name_if_req(orig_tupdesc,
tupdesc);
@@ -1945,11 +1931,13 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
if (map != NULL)
slot = execute_attr_map_slot(map, slot,
MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
+ modifiedCols = bms_union(ExecGetInsertedCols(rootrel, estate),
+ ExecGetUpdatedCols(rootrel, estate));
+ rel = rootrel->ri_RelationDesc;
}
-
- insertedCols = GetInsertedColumns(resultRelInfo, estate);
- updatedCols = GetUpdatedColumns(resultRelInfo, estate);
- modifiedCols = bms_union(insertedCols, updatedCols);
+ else
+ modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
+ ExecGetUpdatedCols(resultRelInfo, estate));
val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
slot,
tupdesc,
@@ -1977,13 +1965,13 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
Relation orig_rel = rel;
/* See the comment above. */
- if (resultRelInfo->ri_PartitionRoot)
+ if (resultRelInfo->ri_RootResultRelInfo)
{
+ ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
TupleDesc old_tupdesc = RelationGetDescr(rel);
AttrMap *map;
- rel = resultRelInfo->ri_PartitionRoot;
- tupdesc = RelationGetDescr(rel);
+ tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
/* a reverse map */
map = build_attrmap_by_name_if_req(old_tupdesc,
tupdesc);
@@ -1995,11 +1983,13 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
if (map != NULL)
slot = execute_attr_map_slot(map, slot,
MakeTupleTableSlot(tupdesc, &TTSOpsVirtual));
+ modifiedCols = bms_union(ExecGetInsertedCols(rootrel, estate),
+ ExecGetUpdatedCols(rootrel, estate));
+ rel = rootrel->ri_RelationDesc;
}
-
- insertedCols = GetInsertedColumns(resultRelInfo, estate);
- updatedCols = GetUpdatedColumns(resultRelInfo, estate);
- modifiedCols = bms_union(insertedCols, updatedCols);
+ else
+ modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
+ ExecGetUpdatedCols(resultRelInfo, estate));
val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
slot,
tupdesc,
@@ -2068,8 +2058,6 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
{
char *val_desc;
Bitmapset *modifiedCols;
- Bitmapset *insertedCols;
- Bitmapset *updatedCols;
switch (wco->kind)
{
@@ -2084,13 +2072,13 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
*/
case WCO_VIEW_CHECK:
/* See the comment in ExecConstraints(). */
- if (resultRelInfo->ri_PartitionRoot)
+ if (resultRelInfo->ri_RootResultRelInfo)
{
+ ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
TupleDesc old_tupdesc = RelationGetDescr(rel);
AttrMap *map;
- rel = resultRelInfo->ri_PartitionRoot;
- tupdesc = RelationGetDescr(rel);
+ tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
/* a reverse map */
map = build_attrmap_by_name_if_req(old_tupdesc,
tupdesc);
@@ -2102,11 +2090,14 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
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);
+ modifiedCols = bms_union(ExecGetInsertedCols(rootrel, estate),
+ ExecGetUpdatedCols(rootrel, estate));
+ rel = rootrel->ri_RelationDesc;
+ }
+ else
+ modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
+ ExecGetUpdatedCols(resultRelInfo, estate));
val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
slot,
tupdesc,
@@ -2320,7 +2311,7 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
* been modified, then we can use a weaker lock, allowing for better
* concurrency.
*/
- updatedCols = GetAllUpdatedColumns(relinfo, estate);
+ updatedCols = ExecGetAllUpdatedCols(relinfo, estate);
keyCols = RelationGetIndexAttrBitmap(relinfo->ri_RelationDesc,
INDEX_ATTR_BITMAP_KEY);
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 2e9bb13c536..e64bb2b6052 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -176,7 +176,8 @@ static void ExecInitRoutingInfo(ModifyTableState *mtstate,
int partidx);
static PartitionDispatch ExecInitPartitionDispatchInfo(EState *estate,
PartitionTupleRouting *proute,
- Oid partoid, PartitionDispatch parent_pd, int partidx);
+ Oid partoid, PartitionDispatch parent_pd,
+ int partidx, ResultRelInfo *rootResultRelInfo);
static void FormPartitionKeyDatum(PartitionDispatch pd,
TupleTableSlot *slot,
EState *estate,
@@ -238,7 +239,7 @@ ExecSetupPartitionTupleRouting(EState *estate, ModifyTableState *mtstate,
* partitioned table.
*/
ExecInitPartitionDispatchInfo(estate, proute, RelationGetRelid(rel),
- NULL, 0);
+ NULL, 0, NULL);
/*
* If performing an UPDATE with tuple routing, we can reuse partition
@@ -426,10 +427,11 @@ ExecFindPartition(ModifyTableState *mtstate,
* Create the new PartitionDispatch. We pass the current one
* in as the parent PartitionDispatch
*/
- subdispatch = ExecInitPartitionDispatchInfo(mtstate->ps.state,
+ subdispatch = ExecInitPartitionDispatchInfo(estate,
proute,
partdesc->oids[partidx],
- dispatch, partidx);
+ dispatch, partidx,
+ mtstate->rootResultRelInfo);
Assert(dispatch->indexes[partidx] >= 0 &&
dispatch->indexes[partidx] < proute->num_dispatch);
@@ -544,7 +546,7 @@ ExecHashSubPlanResultRelsByOid(ModifyTableState *mtstate,
* 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;
+ rri->ri_RootResultRelInfo = mtstate->rootResultRelInfo;
}
}
@@ -564,8 +566,8 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
int partidx)
{
ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
- Relation rootrel = rootResultRelInfo->ri_RelationDesc,
- partrel;
+ Relation partrel;
+ int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
Relation firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;
ResultRelInfo *leaf_part_rri;
MemoryContext oldcxt;
@@ -579,8 +581,8 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
leaf_part_rri = makeNode(ResultRelInfo);
InitResultRelInfo(leaf_part_rri,
partrel,
- node ? node->rootRelation : 1,
- rootrel,
+ 0,
+ rootResultRelInfo,
estate->es_instrument);
/*
@@ -614,7 +616,6 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
List *wcoList;
List *wcoExprs = NIL;
ListCell *ll;
- int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
/*
* In the case of INSERT on a partitioned table, there is only one
@@ -678,7 +679,6 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
TupleTableSlot *slot;
ExprContext *econtext;
List *returningList;
- int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
/* See the comment above for WCO lists. */
Assert((node->operation == CMD_INSERT &&
@@ -737,7 +737,6 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
*/
if (node && node->onConflictAction != ONCONFLICT_NONE)
{
- int firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
TupleDesc partrelDesc = RelationGetDescr(partrel);
ExprContext *econtext = mtstate->ps.ps_ExprContext;
ListCell *lc;
@@ -939,6 +938,7 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
ResultRelInfo *partRelInfo,
int partidx)
{
+ ResultRelInfo *rootRelInfo = partRelInfo->ri_RootResultRelInfo;
MemoryContext oldcxt;
PartitionRoutingInfo *partrouteinfo;
int rri_index;
@@ -952,7 +952,7 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
* partition from the parent's type to the partition's.
*/
partrouteinfo->pi_RootToPartitionMap =
- convert_tuples_by_name(RelationGetDescr(partRelInfo->ri_PartitionRoot),
+ convert_tuples_by_name(RelationGetDescr(rootRelInfo->ri_RelationDesc),
RelationGetDescr(partRelInfo->ri_RelationDesc));
/*
@@ -985,7 +985,7 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
{
partrouteinfo->pi_PartitionToRootMap =
convert_tuples_by_name(RelationGetDescr(partRelInfo->ri_RelationDesc),
- RelationGetDescr(partRelInfo->ri_PartitionRoot));
+ RelationGetDescr(rootRelInfo->ri_RelationDesc));
}
else
partrouteinfo->pi_PartitionToRootMap = NULL;
@@ -1044,7 +1044,8 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
static PartitionDispatch
ExecInitPartitionDispatchInfo(EState *estate,
PartitionTupleRouting *proute, Oid partoid,
- PartitionDispatch parent_pd, int partidx)
+ PartitionDispatch parent_pd, int partidx,
+ ResultRelInfo *rootResultRelInfo)
{
Relation rel;
PartitionDesc partdesc;
@@ -1142,7 +1143,7 @@ ExecInitPartitionDispatchInfo(EState *estate,
{
ResultRelInfo *rri = makeNode(ResultRelInfo);
- InitResultRelInfo(rri, rel, 1, proute->partition_root, 0);
+ InitResultRelInfo(rri, rel, 0, rootResultRelInfo, 0);
proute->nonleaf_partitions[dispatchidx] = rri;
}
else
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d0e65b86473..57771ba78f7 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -51,6 +51,7 @@
#include "access/tableam.h"
#include "access/transam.h"
#include "executor/executor.h"
+#include "executor/execPartition.h"
#include "jit/jit.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
@@ -1203,3 +1204,91 @@ ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo)
return relInfo->ri_ReturningSlot;
}
+
+/* Return a bitmap representing columns being inserted */
+Bitmapset *
+ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
+{
+ /*
+ * The columns are stored in the range table entry. If this ResultRelInfo
+ * doesn't have an entry in the range table (i.e. if it represents a
+ * partition routing target), fetch the parent's RTE and map the columns
+ * to the order they are in the partition.
+ */
+ if (relinfo->ri_RangeTableIndex != 0)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(relinfo->ri_RangeTableIndex, estate);
+
+ return rte->insertedCols;
+ }
+ else
+ {
+ ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
+ RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
+ PartitionRoutingInfo *partrouteinfo = relinfo->ri_PartitionInfo;
+
+ if (partrouteinfo->pi_RootToPartitionMap != NULL)
+ return execute_attr_map_cols(partrouteinfo->pi_RootToPartitionMap->attrMap,
+ rte->insertedCols);
+ else
+ return rte->insertedCols;
+ }
+}
+
+/* Return a bitmap representing columns being updated */
+Bitmapset *
+ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
+{
+ /* see ExecGetInsertedCols() */
+ if (relinfo->ri_RangeTableIndex != 0)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(relinfo->ri_RangeTableIndex, estate);
+
+ return rte->updatedCols;
+ }
+ else
+ {
+ ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
+ RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
+ PartitionRoutingInfo *partrouteinfo = relinfo->ri_PartitionInfo;
+
+ if (partrouteinfo->pi_RootToPartitionMap != NULL)
+ return execute_attr_map_cols(partrouteinfo->pi_RootToPartitionMap->attrMap,
+ rte->updatedCols);
+ else
+ return rte->updatedCols;
+ }
+}
+
+/* Return a bitmap representing generated columns being updated */
+Bitmapset *
+ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
+{
+ /* see ExecGetInsertedCols() */
+ if (relinfo->ri_RangeTableIndex != 0)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(relinfo->ri_RangeTableIndex, estate);
+
+ return rte->extraUpdatedCols;
+ }
+ else
+ {
+ ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
+ RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
+ PartitionRoutingInfo *partrouteinfo = relinfo->ri_PartitionInfo;
+
+ if (partrouteinfo->pi_RootToPartitionMap != NULL)
+ return execute_attr_map_cols(partrouteinfo->pi_RootToPartitionMap->attrMap,
+ rte->extraUpdatedCols);
+ else
+ return rte->extraUpdatedCols;
+ }
+}
+
+/* Return columns being updated, including generated columns */
+Bitmapset *
+ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
+{
+ return bms_union(ExecGetUpdatedCols(relinfo, estate),
+ ExecGetExtraUpdatedCols(relinfo, estate));
+}
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index f450e4d80ad..9572ef0690e 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -286,7 +286,7 @@ ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot, CmdType cmdtype
if (cmdtype == CMD_UPDATE &&
!(rel->trigdesc && rel->trigdesc->trig_update_before_row) &&
!bms_is_member(i + 1 - FirstLowInvalidHeapAttributeNumber,
- exec_rt_fetch(resultRelInfo->ri_RangeTableIndex, estate)->extraUpdatedCols))
+ ExecGetExtraUpdatedCols(resultRelInfo, estate)))
{
resultRelInfo->ri_GeneratedExprs[i] = NULL;
continue;
@@ -492,7 +492,7 @@ ExecInsert(ModifyTableState *mtstate,
* if there's no BR trigger defined on the partition.
*/
if (resultRelInfo->ri_PartitionCheck &&
- (resultRelInfo->ri_PartitionRoot == NULL ||
+ (resultRelInfo->ri_RootResultRelInfo == NULL ||
(resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_insert_before_row)))
ExecPartitionCheck(resultRelInfo, slot, estate, true);