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

Commit b08df9c

Browse files
committed
Teach predtest.c about CHECK clauses to fix partitioning bugs.
In a CHECK clause, a null result means true, whereas in a WHERE clause it means false. predtest.c provided different functions depending on which set of semantics applied to the predicate being proved, but had no option to control what a null meant in the clauses provided as axioms. Add one. Use that in the partitioning code when figuring out whether the validation scan on a new partition can be skipped. Rip out the old logic that attempted (not very successfully) to compensate for the absence of the necessary support in predtest.c. Ashutosh Bapat and Robert Haas, reviewed by Amit Langote and incorporating feedback from Tom Lane. Discussion: http://postgr.es/m/CAFjFpReT_kq_uwU_B8aWDxR7jNGE=P0iELycdq5oupi=xSQTOw@mail.gmail.com
1 parent a12c09a commit b08df9c

File tree

9 files changed

+129
-132
lines changed

9 files changed

+129
-132
lines changed

src/backend/commands/tablecmds.c

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -13410,7 +13410,6 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
1341013410
static ObjectAddress
1341113411
ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1341213412
{
13413-
PartitionKey key = RelationGetPartitionKey(rel);
1341413413
Relation attachRel,
1341513414
catalog;
1341613415
List *childrels;
@@ -13596,11 +13595,6 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1359613595
{
1359713596
int num_check = attachRel_constr->num_check;
1359813597
int i;
13599-
Bitmapset *not_null_attrs = NULL;
13600-
List *part_constr;
13601-
ListCell *lc;
13602-
bool partition_accepts_null = true;
13603-
int partnatts;
1360413598

1360513599
if (attachRel_constr->has_not_null)
1360613600
{
@@ -13630,7 +13624,6 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1363013624
ntest->argisrow = false;
1363113625
ntest->location = -1;
1363213626
existConstraint = lappend(existConstraint, ntest);
13633-
not_null_attrs = bms_add_member(not_null_attrs, i);
1363413627
}
1363513628
}
1363613629
}
@@ -13664,59 +13657,8 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1366413657
existConstraint = list_make1(make_ands_explicit(existConstraint));
1366513658

1366613659
/* And away we go ... */
13667-
if (predicate_implied_by(partConstraint, existConstraint))
13660+
if (predicate_implied_by(partConstraint, existConstraint, true))
1366813661
skip_validate = true;
13669-
13670-
/*
13671-
* We choose to err on the safer side, i.e., give up on skipping the
13672-
* validation scan, if the partition key column doesn't have the NOT
13673-
* NULL constraint and the table is to become a list partition that
13674-
* does not accept nulls. In this case, the partition predicate
13675-
* (partConstraint) does include an 'key IS NOT NULL' expression,
13676-
* however, because of the way predicate_implied_by_simple_clause() is
13677-
* designed to handle IS NOT NULL predicates in the absence of a IS
13678-
* NOT NULL clause, we cannot rely on just the above proof.
13679-
*
13680-
* That is not an issue in case of a range partition, because if there
13681-
* were no NOT NULL constraint defined on the key columns, an error
13682-
* would be thrown before we get here anyway. That is not true,
13683-
* however, if any of the partition keys is an expression, which is
13684-
* handled below.
13685-
*/
13686-
part_constr = linitial(partConstraint);
13687-
part_constr = make_ands_implicit((Expr *) part_constr);
13688-
13689-
/*
13690-
* part_constr contains an IS NOT NULL expression, if this is a list
13691-
* partition that does not accept nulls (in fact, also if this is a
13692-
* range partition and some partition key is an expression, but we
13693-
* never skip validation in that case anyway; see below)
13694-
*/
13695-
foreach(lc, part_constr)
13696-
{
13697-
Node *expr = lfirst(lc);
13698-
13699-
if (IsA(expr, NullTest) &&
13700-
((NullTest *) expr)->nulltesttype == IS_NOT_NULL)
13701-
{
13702-
partition_accepts_null = false;
13703-
break;
13704-
}
13705-
}
13706-
13707-
partnatts = get_partition_natts(key);
13708-
for (i = 0; i < partnatts; i++)
13709-
{
13710-
AttrNumber partattno;
13711-
13712-
partattno = get_partition_col_attnum(key, i);
13713-
13714-
/* If partition key is an expression, must not skip validation */
13715-
if (!partition_accepts_null &&
13716-
(partattno == 0 ||
13717-
!bms_is_member(partattno, not_null_attrs)))
13718-
skip_validate = false;
13719-
}
1372013662
}
1372113663

1372213664
/* It's safe to skip the validation scan after all */

src/backend/optimizer/path/indxpath.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,10 +1210,10 @@ build_paths_for_OR(PlannerInfo *root, RelOptInfo *rel,
12101210
all_clauses = list_concat(list_copy(clauses),
12111211
other_clauses);
12121212

1213-
if (!predicate_implied_by(index->indpred, all_clauses))
1213+
if (!predicate_implied_by(index->indpred, all_clauses, false))
12141214
continue; /* can't use it at all */
12151215

1216-
if (!predicate_implied_by(index->indpred, other_clauses))
1216+
if (!predicate_implied_by(index->indpred, other_clauses, false))
12171217
useful_predicate = true;
12181218
}
12191219
}
@@ -1519,7 +1519,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
15191519
{
15201520
Node *np = (Node *) lfirst(l);
15211521

1522-
if (predicate_implied_by(list_make1(np), qualsofar))
1522+
if (predicate_implied_by(list_make1(np), qualsofar, false))
15231523
{
15241524
redundant = true;
15251525
break; /* out of inner foreach loop */
@@ -2871,7 +2871,8 @@ check_index_predicates(PlannerInfo *root, RelOptInfo *rel)
28712871
continue; /* ignore non-partial indexes here */
28722872

28732873
if (!index->predOK) /* don't repeat work if already proven OK */
2874-
index->predOK = predicate_implied_by(index->indpred, clauselist);
2874+
index->predOK = predicate_implied_by(index->indpred, clauselist,
2875+
false);
28752876

28762877
/* If rel is an update target, leave indrestrictinfo as set above */
28772878
if (is_target_rel)
@@ -2886,7 +2887,7 @@ check_index_predicates(PlannerInfo *root, RelOptInfo *rel)
28862887
/* predicate_implied_by() assumes first arg is immutable */
28872888
if (contain_mutable_functions((Node *) rinfo->clause) ||
28882889
!predicate_implied_by(list_make1(rinfo->clause),
2889-
index->indpred))
2890+
index->indpred, false))
28902891
index->indrestrictinfo = lappend(index->indrestrictinfo, rinfo);
28912892
}
28922893
}

src/backend/optimizer/plan/createplan.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2576,7 +2576,7 @@ create_indexscan_plan(PlannerInfo *root,
25762576
if (is_redundant_derived_clause(rinfo, indexquals))
25772577
continue; /* derived from same EquivalenceClass */
25782578
if (!contain_mutable_functions((Node *) rinfo->clause) &&
2579-
predicate_implied_by(list_make1(rinfo->clause), indexquals))
2579+
predicate_implied_by(list_make1(rinfo->clause), indexquals, false))
25802580
continue; /* provably implied by indexquals */
25812581
qpqual = lappend(qpqual, rinfo);
25822582
}
@@ -2737,7 +2737,7 @@ create_bitmap_scan_plan(PlannerInfo *root,
27372737
if (rinfo->parent_ec && list_member_ptr(indexECs, rinfo->parent_ec))
27382738
continue; /* derived from same EquivalenceClass */
27392739
if (!contain_mutable_functions(clause) &&
2740-
predicate_implied_by(list_make1(clause), indexquals))
2740+
predicate_implied_by(list_make1(clause), indexquals, false))
27412741
continue; /* provably implied by indexquals */
27422742
qpqual = lappend(qpqual, rinfo);
27432743
}
@@ -2968,7 +2968,8 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
29682968
* the conditions that got pushed into the bitmapqual. Avoid
29692969
* generating redundant conditions.
29702970
*/
2971-
if (!predicate_implied_by(list_make1(pred), ipath->indexclauses))
2971+
if (!predicate_implied_by(list_make1(pred), ipath->indexclauses,
2972+
false))
29722973
{
29732974
*qual = lappend(*qual, pred);
29742975
*indexqual = lappend(*indexqual, pred);

src/backend/optimizer/util/plancat.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ infer_arbiter_indexes(PlannerInfo *root)
776776
*/
777777
predExprs = RelationGetIndexPredicate(idxRel);
778778

779-
if (!predicate_implied_by(predExprs, (List *) onconflict->arbiterWhere))
779+
if (!predicate_implied_by(predExprs, (List *) onconflict->arbiterWhere, false))
780780
goto next;
781781

782782
results = lappend_oid(results, idxForm->indexrelid);
@@ -1399,7 +1399,7 @@ relation_excluded_by_constraints(PlannerInfo *root,
13991399
safe_restrictions = lappend(safe_restrictions, rinfo->clause);
14001400
}
14011401

1402-
if (predicate_refuted_by(safe_restrictions, safe_restrictions))
1402+
if (predicate_refuted_by(safe_restrictions, safe_restrictions, false))
14031403
return true;
14041404

14051405
/* Only plain relations have constraints */
@@ -1438,7 +1438,7 @@ relation_excluded_by_constraints(PlannerInfo *root,
14381438
* have volatile and nonvolatile subclauses, and it's OK to make
14391439
* deductions with the nonvolatile parts.
14401440
*/
1441-
if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo))
1441+
if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false))
14421442
return true;
14431443

14441444
return false;

0 commit comments

Comments
 (0)