Fix failure to enforce partitioning contraint for internal partitions.

When a tuple is inherited into a partitioning root, no partition
constraints need to be enforced; when it is inserted into a leaf, the
parent's partitioning quals needed to be enforced.  The previous
coding got both of those cases right.  When a tuple is inserted into
an intermediate level of the partitioning hierarchy (i.e. a table
which is both a partition itself and in turn partitioned), it must
enforce the partitioning qual inherited from its parent.  That case
got overlooked; repair.

Amit Langote
This commit is contained in:
Robert Haas 2017-01-19 12:30:27 -05:00
parent bec96c82f8
commit 39162b2030
6 changed files with 44 additions and 12 deletions

View File

@ -2432,7 +2432,6 @@ CopyFrom(CopyState cstate)
InitResultRelInfo(resultRelInfo,
cstate->rel,
1, /* dummy rangetable index */
true, /* do load partition check expression */
NULL,
0);

View File

@ -1324,7 +1324,6 @@ ExecuteTruncate(TruncateStmt *stmt)
InitResultRelInfo(resultRelInfo,
rel,
0, /* dummy rangetable index */
false,
NULL,
0);
resultRelInfo++;

View File

@ -824,10 +824,10 @@ InitPlan(QueryDesc *queryDesc, int eflags)
resultRelationOid = getrelid(resultRelationIndex, rangeTable);
resultRelation = heap_open(resultRelationOid, RowExclusiveLock);
InitResultRelInfo(resultRelInfo,
resultRelation,
resultRelationIndex,
true,
NULL,
estate->es_instrument);
resultRelInfo++;
@ -1218,10 +1218,11 @@ void
InitResultRelInfo(ResultRelInfo *resultRelInfo,
Relation resultRelationDesc,
Index resultRelationIndex,
bool load_partition_check,
Relation partition_root,
int instrument_options)
{
List *partition_check = NIL;
MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
resultRelInfo->type = T_ResultRelInfo;
resultRelInfo->ri_RangeTableIndex = resultRelationIndex;
@ -1257,13 +1258,38 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
resultRelInfo->ri_ConstraintExprs = NULL;
resultRelInfo->ri_junkFilter = NULL;
resultRelInfo->ri_projectReturning = NULL;
if (load_partition_check)
resultRelInfo->ri_PartitionCheck =
RelationGetPartitionQual(resultRelationDesc);
/*
* The following gets set to NULL unless we are initializing leaf
* partitions for tuple-routing.
* If partition_root has been specified, that means we are builiding the
* ResultRelationInfo for one of its leaf partitions. In that case, we
* need *not* initialize the leaf partition's constraint, but rather the
* the partition_root's (if any). We must do that explicitly like this,
* because implicit partition constraints are not inherited like user-
* defined constraints and would fail to be enforced by ExecConstraints()
* after a tuple is routed to a leaf partition.
*/
if (partition_root)
{
/*
* Root table itself may or may not be a partition; partition_check
* would be NIL in the latter case.
*/
partition_check = RelationGetPartitionQual(partition_root);
/*
* This is not our own partition constraint, but rather an ancestor's.
* So any Vars in it bear the ancestor's attribute numbers. We must
* switch them to our own.
*/
if (partition_check != NIL)
partition_check = map_partition_varattnos(partition_check,
resultRelationDesc,
partition_root);
}
else
partition_check = RelationGetPartitionQual(resultRelationDesc);
resultRelInfo->ri_PartitionCheck = partition_check;
resultRelInfo->ri_PartitionRoot = partition_root;
}
@ -1327,7 +1353,6 @@ ExecGetTriggerResultRel(EState *estate, Oid relid)
InitResultRelInfo(rInfo,
rel,
0, /* dummy rangetable index */
true,
NULL,
estate->es_instrument);
estate->es_trig_target_relations =
@ -3132,7 +3157,6 @@ ExecSetupPartitionTupleRouting(Relation rel,
InitResultRelInfo(leaf_part_rri,
partrel,
1, /* dummy */
false,
rel,
0);

View File

@ -189,7 +189,6 @@ extern void CheckValidResultRel(Relation resultRel, CmdType operation);
extern void InitResultRelInfo(ResultRelInfo *resultRelInfo,
Relation resultRelationDesc,
Index resultRelationIndex,
bool load_partition_check,
Relation partition_root,
int instrument_options);
extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);

View File

@ -358,5 +358,11 @@ alter table p add constraint check_b check (b = 3);
insert into p values (1, 2);
ERROR: new row for relation "p11" violates check constraint "check_b"
DETAIL: Failing row contains (1, 2).
-- check that inserting into an internal partition successfully results in
-- checking its partition constraint before inserting into the leaf partition
-- selected by tuple-routing
insert into p1 (a, b) values (2, 3);
ERROR: new row for relation "p11" violates partition constraint
DETAIL: Failing row contains (3, 2).
-- cleanup
drop table p, p1, p11;

View File

@ -221,5 +221,10 @@ alter table p add constraint check_b check (b = 3);
-- after "(1, 2)" is routed to it
insert into p values (1, 2);
-- check that inserting into an internal partition successfully results in
-- checking its partition constraint before inserting into the leaf partition
-- selected by tuple-routing
insert into p1 (a, b) values (2, 3);
-- cleanup
drop table p, p1, p11;