Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5b0c7e2

Browse files
committed
Don't needlessly check the partition contraint twice
Starting with commit f0e4475, ExecConstraints was in charge of running the partition constraint; commit 19c47e7 modified that so that caller could request to skip that checking depending on some conditions, but that commit and 15ce775 together introduced a small bug there which caused ExecInsert to request skipping the constraint check but have this not be honored -- in effect doing the check twice. This could have been fixed in a very small patch, but on further analysis of the involved function and its callsites, it turns out to be simpler to give the responsibility of checking the partition constraint fully to the caller, and return ExecConstraints to its original (pre-partitioning) shape where it only checked tuple descriptor-related constraints. Each caller must do partition constraint checking on its own schedule, which is more convenient after commit 2f17844 anyway. Reported-by: David Rowley Author: David Rowley, Álvaro Herrera Reviewed-by: Amit Langote, Amit Khandekar, Simon Riggs Discussion: https://postgr.es/m/CAKJS1f8w8+awsxgea8wt7_UX8qzOQ=Tm1LD+U1fHqBAkXxkW2w@mail.gmail.com
1 parent 85dd744 commit 5b0c7e2

File tree

6 files changed

+56
-62
lines changed

6 files changed

+56
-62
lines changed

src/backend/commands/copy.c

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2725,30 +2725,25 @@ CopyFrom(CopyState cstate)
27252725
}
27262726
else
27272727
{
2728-
/*
2729-
* We always check the partition constraint, including when
2730-
* the tuple got here via tuple-routing. However we don't
2731-
* need to in the latter case if no BR trigger is defined on
2732-
* the partition. Note that a BR trigger might modify the
2733-
* tuple such that the partition constraint is no longer
2734-
* satisfied, so we need to check in that case.
2735-
*/
2736-
bool check_partition_constr =
2737-
(resultRelInfo->ri_PartitionCheck != NIL);
2738-
2739-
if (saved_resultRelInfo != NULL &&
2740-
!(resultRelInfo->ri_TrigDesc &&
2741-
resultRelInfo->ri_TrigDesc->trig_insert_before_row))
2742-
check_partition_constr = false;
2743-
27442728
/*
27452729
* If the target is a plain table, check the constraints of
27462730
* the tuple.
27472731
*/
27482732
if (resultRelInfo->ri_FdwRoutine == NULL &&
2749-
(resultRelInfo->ri_RelationDesc->rd_att->constr ||
2750-
check_partition_constr))
2751-
ExecConstraints(resultRelInfo, slot, estate, true);
2733+
resultRelInfo->ri_RelationDesc->rd_att->constr)
2734+
ExecConstraints(resultRelInfo, slot, estate);
2735+
2736+
/*
2737+
* Also check the tuple against the partition constraint, if
2738+
* there is one; except that if we got here via tuple-routing,
2739+
* we don't need to if there's no BR trigger defined on the
2740+
* partition.
2741+
*/
2742+
if (resultRelInfo->ri_PartitionCheck &&
2743+
(saved_resultRelInfo == NULL ||
2744+
(resultRelInfo->ri_TrigDesc &&
2745+
resultRelInfo->ri_TrigDesc->trig_insert_before_row)))
2746+
ExecPartitionCheck(resultRelInfo, slot, estate, true);
27522747

27532748
if (useHeapMultiInsert)
27542749
{

src/backend/executor/execMain.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,14 +1856,16 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
18561856
/*
18571857
* ExecPartitionCheck --- check that tuple meets the partition constraint.
18581858
*
1859-
* Exported in executor.h for outside use.
1860-
* Returns true if it meets the partition constraint, else returns false.
1859+
* Returns true if it meets the partition constraint. If the constraint
1860+
* fails and we're asked to emit to error, do so and don't return; otherwise
1861+
* return false.
18611862
*/
18621863
bool
18631864
ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
1864-
EState *estate)
1865+
EState *estate, bool emitError)
18651866
{
18661867
ExprContext *econtext;
1868+
bool success;
18671869

18681870
/*
18691871
* If first time through, build expression state tree for the partition
@@ -1890,7 +1892,13 @@ ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
18901892
* As in case of the catalogued constraints, we treat a NULL result as
18911893
* success here, not a failure.
18921894
*/
1893-
return ExecCheck(resultRelInfo->ri_PartitionCheckExpr, econtext);
1895+
success = ExecCheck(resultRelInfo->ri_PartitionCheckExpr, econtext);
1896+
1897+
/* if asked to emit error, don't actually return on failure */
1898+
if (!success && emitError)
1899+
ExecPartitionCheckEmitError(resultRelInfo, slot, estate);
1900+
1901+
return success;
18941902
}
18951903

18961904
/*
@@ -1951,17 +1959,17 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
19511959
/*
19521960
* ExecConstraints - check constraints of the tuple in 'slot'
19531961
*
1954-
* This checks the traditional NOT NULL and check constraints, and if
1955-
* requested, checks the partition constraint.
1962+
* This checks the traditional NOT NULL and check constraints.
1963+
*
1964+
* The partition constraint is *NOT* checked.
19561965
*
19571966
* Note: 'slot' contains the tuple to check the constraints of, which may
19581967
* have been converted from the original input tuple after tuple routing.
1959-
* 'resultRelInfo' is the original result relation, before tuple routing.
1968+
* 'resultRelInfo' is the final result relation, after tuple routing.
19601969
*/
19611970
void
19621971
ExecConstraints(ResultRelInfo *resultRelInfo,
1963-
TupleTableSlot *slot, EState *estate,
1964-
bool check_partition_constraint)
1972+
TupleTableSlot *slot, EState *estate)
19651973
{
19661974
Relation rel = resultRelInfo->ri_RelationDesc;
19671975
TupleDesc tupdesc = RelationGetDescr(rel);
@@ -2076,13 +2084,8 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
20762084
errtableconstraint(orig_rel, failed)));
20772085
}
20782086
}
2079-
2080-
if (check_partition_constraint && resultRelInfo->ri_PartitionCheck &&
2081-
!ExecPartitionCheck(resultRelInfo, slot, estate))
2082-
ExecPartitionCheckEmitError(resultRelInfo, slot, estate);
20832087
}
20842088

2085-
20862089
/*
20872090
* ExecWithCheckOptions -- check that tuple satisfies any WITH CHECK OPTIONs
20882091
* of the specified kind.

src/backend/executor/execPartition.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,8 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
201201
* First check the root table's partition constraint, if any. No point in
202202
* routing the tuple if it doesn't belong in the root table itself.
203203
*/
204-
if (resultRelInfo->ri_PartitionCheck &&
205-
!ExecPartitionCheck(resultRelInfo, slot, estate))
206-
ExecPartitionCheckEmitError(resultRelInfo, slot, estate);
204+
if (resultRelInfo->ri_PartitionCheck)
205+
ExecPartitionCheck(resultRelInfo, slot, estate, true);
207206

208207
/* start with the root partitioned table */
209208
parent = pd[0];

src/backend/executor/execReplication.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,9 @@ ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot)
413413

414414
/* Check the constraints of the tuple */
415415
if (rel->rd_att->constr)
416-
ExecConstraints(resultRelInfo, slot, estate, true);
416+
ExecConstraints(resultRelInfo, slot, estate);
417+
if (resultRelInfo->ri_PartitionCheck)
418+
ExecPartitionCheck(resultRelInfo, slot, estate, true);
417419

418420
/* Store the slot into tuple that we can inspect. */
419421
tuple = ExecMaterializeSlot(slot);
@@ -478,7 +480,9 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
478480

479481
/* Check the constraints of the tuple */
480482
if (rel->rd_att->constr)
481-
ExecConstraints(resultRelInfo, slot, estate, true);
483+
ExecConstraints(resultRelInfo, slot, estate);
484+
if (resultRelInfo->ri_PartitionCheck)
485+
ExecPartitionCheck(resultRelInfo, slot, estate, true);
482486

483487
/* Store the slot into tuple that we can write. */
484488
tuple = ExecMaterializeSlot(slot);

src/backend/executor/nodeModifyTable.c

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -365,16 +365,6 @@ ExecInsert(ModifyTableState *mtstate,
365365
else
366366
{
367367
WCOKind wco_kind;
368-
bool check_partition_constr;
369-
370-
/*
371-
* We always check the partition constraint, including when the tuple
372-
* got here via tuple-routing. However we don't need to in the latter
373-
* case if no BR trigger is defined on the partition. Note that a BR
374-
* trigger might modify the tuple such that the partition constraint
375-
* is no longer satisfied, so we need to check in that case.
376-
*/
377-
check_partition_constr = (resultRelInfo->ri_PartitionCheck != NIL);
378368

379369
/*
380370
* Constraints might reference the tableoid column, so initialize
@@ -402,17 +392,21 @@ ExecInsert(ModifyTableState *mtstate,
402392
ExecWithCheckOptions(wco_kind, resultRelInfo, slot, estate);
403393

404394
/*
405-
* No need though if the tuple has been routed, and a BR trigger
406-
* doesn't exist.
395+
* Check the constraints of the tuple.
407396
*/
408-
if (resultRelInfo->ri_PartitionRoot != NULL &&
409-
!(resultRelInfo->ri_TrigDesc &&
410-
resultRelInfo->ri_TrigDesc->trig_insert_before_row))
411-
check_partition_constr = false;
397+
if (resultRelationDesc->rd_att->constr)
398+
ExecConstraints(resultRelInfo, slot, estate);
412399

413-
/* Check the constraints of the tuple */
414-
if (resultRelationDesc->rd_att->constr || check_partition_constr)
415-
ExecConstraints(resultRelInfo, slot, estate, true);
400+
/*
401+
* Also check the tuple against the partition constraint, if there is
402+
* one; except that if we got here via tuple-routing, we don't need to
403+
* if there's no BR trigger defined on the partition.
404+
*/
405+
if (resultRelInfo->ri_PartitionCheck &&
406+
(resultRelInfo->ri_PartitionRoot == NULL ||
407+
(resultRelInfo->ri_TrigDesc &&
408+
resultRelInfo->ri_TrigDesc->trig_insert_before_row)))
409+
ExecPartitionCheck(resultRelInfo, slot, estate, true);
416410

417411
if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
418412
{
@@ -1037,7 +1031,7 @@ lreplace:;
10371031
*/
10381032
partition_constraint_failed =
10391033
resultRelInfo->ri_PartitionCheck &&
1040-
!ExecPartitionCheck(resultRelInfo, slot, estate);
1034+
!ExecPartitionCheck(resultRelInfo, slot, estate, false);
10411035

10421036
if (!partition_constraint_failed &&
10431037
resultRelInfo->ri_WithCheckOptions != NIL)
@@ -1168,7 +1162,7 @@ lreplace:;
11681162
* have it validate all remaining checks.
11691163
*/
11701164
if (resultRelationDesc->rd_att->constr)
1171-
ExecConstraints(resultRelInfo, slot, estate, false);
1165+
ExecConstraints(resultRelInfo, slot, estate);
11721166

11731167
/*
11741168
* replace the heap tuple

src/include/executor/executor.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,9 @@ extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
180180
extern void ExecCleanUpTriggerState(EState *estate);
181181
extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
182182
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
183-
TupleTableSlot *slot, EState *estate,
184-
bool check_partition_constraint);
183+
TupleTableSlot *slot, EState *estate);
185184
extern bool ExecPartitionCheck(ResultRelInfo *resultRelInfo,
186-
TupleTableSlot *slot, EState *estate);
185+
TupleTableSlot *slot, EState *estate, bool emitError);
187186
extern void ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
188187
TupleTableSlot *slot, EState *estate);
189188
extern void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,

0 commit comments

Comments
 (0)