Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9178133

Browse files
committed
Code review for match_clause_to_partition_key().
Fix inconsistent decisions about NOMATCH vs UNSUPPORTED result codes.If we're going to cater for partkeys that have the same expression anddifferent collations, surely we should also support partkeys with thesame expression and different opclasses.Clean up shaky handling of commuted opclauses, eg checking the wrongoperator to see what its negator is. This wouldn't cause any actualbugs given a sane opclass definition, but it doesn't seem helpful toexpend more code to be less correct.Improve handling of null elements in ScalarArrayOp arrays: in the"op ALL" case, we can conclude they result in an unsatisfiable clause.Minor cosmetic changes and comment improvements.
1 parent1983275 commit9178133

File tree

1 file changed

+81
-65
lines changed

1 file changed

+81
-65
lines changed

‎src/backend/partitioning/partprune.c

Lines changed: 81 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -613,18 +613,17 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
613613
Expr*clause= (Expr*)lfirst(lc);
614614
inti;
615615

616+
/* Look through RestrictInfo, if any */
616617
if (IsA(clause,RestrictInfo))
617-
{
618-
RestrictInfo*rinfo= (RestrictInfo*)clause;
618+
clause= ((RestrictInfo*)clause)->clause;
619619

620-
clause=rinfo->clause;
621-
if (rinfo->pseudoconstant&&
622-
IsA(rinfo->clause,Const)&&
623-
!DatumGetBool(((Const*)clause)->constvalue))
624-
{
625-
*contradictory= true;
626-
returnNIL;
627-
}
620+
/* Constant-false-or-null is contradictory */
621+
if (IsA(clause,Const)&&
622+
(((Const*)clause)->constisnull||
623+
!DatumGetBool(((Const*)clause)->constvalue)))
624+
{
625+
*contradictory= true;
626+
returnNIL;
628627
}
629628

630629
/* Get the BoolExpr's out of the way. */
@@ -1378,13 +1377,13 @@ gen_prune_steps_from_opexps(PartitionScheme part_scheme,
13781377
* Output arguments: *clause_steps is set to a list of PartitionPruneStep
13791378
* generated for the clause.
13801379
*
1381-
* * PARTCLAUSE_MATCH_CONTRADICT if the clause is self-contradictory. This can
1382-
*only happen if it's a BoolExpr whose arguments are self-contradictory.
1380+
* * PARTCLAUSE_MATCH_CONTRADICT if the clause is self-contradictory, ie
1381+
*it provably returns FALSE or NULL.
13831382
* Output arguments: none set.
13841383
*
1385-
* * PARTCLAUSE_UNSUPPORTED if the clausecannot be used for pruning at all
1386-
*due to one of its properties, such as argument volatility, even if it may
1387-
*have been matched with akey.
1384+
* * PARTCLAUSE_UNSUPPORTED if the clausedoesn't match this partition key
1385+
*and couldn't possibly match any other one either, due to its form or
1386+
*properties (such as containing avolatile function).
13881387
* Output arguments: none set.
13891388
*/
13901389
staticPartClauseMatchStatus
@@ -1395,9 +1394,9 @@ match_clause_to_partition_key(RelOptInfo *rel,
13951394
List**clause_steps)
13961395
{
13971396
PartitionSchemepart_scheme=rel->part_scheme;
1398-
Expr*expr;
13991397
Oidpartopfamily=part_scheme->partopfamily[partkeyidx],
14001398
partcoll=part_scheme->partcollation[partkeyidx];
1399+
Expr*expr;
14011400

14021401
/*
14031402
* Recognize specially shaped clauses that match with the Boolean
@@ -1427,9 +1426,9 @@ match_clause_to_partition_key(RelOptInfo *rel,
14271426
OpExpr*opclause= (OpExpr*)clause;
14281427
Expr*leftop,
14291428
*rightop;
1430-
Oidop_lefttype,
1429+
Oidopno,
1430+
op_lefttype,
14311431
op_righttype,
1432-
commutator=InvalidOid,
14331432
negator=InvalidOid;
14341433
Oidcmpfn;
14351434
intop_strategy;
@@ -1442,79 +1441,88 @@ match_clause_to_partition_key(RelOptInfo *rel,
14421441
rightop= (Expr*)get_rightop(clause);
14431442
if (IsA(rightop,RelabelType))
14441443
rightop= ((RelabelType*)rightop)->arg;
1444+
opno=opclause->opno;
14451445

14461446
/* check if the clause matches this partition key */
14471447
if (equal(leftop,partkey))
14481448
expr=rightop;
14491449
elseif (equal(rightop,partkey))
14501450
{
1451-
expr=leftop;
1452-
commutator=get_commutator(opclause->opno);
1453-
1454-
/* nothing we can do unless we can swap the operands */
1455-
if (!OidIsValid(commutator))
1451+
/*
1452+
* It's only useful if we can commute the operator to put the
1453+
* partkey on the left. If we can't, the clause can be deemed
1454+
* UNSUPPORTED. Even if its leftop matches some later partkey, we
1455+
* now know it has Vars on the right, so it's no use.
1456+
*/
1457+
opno=get_commutator(opno);
1458+
if (!OidIsValid(opno))
14561459
returnPARTCLAUSE_UNSUPPORTED;
1460+
expr=leftop;
14571461
}
14581462
else
14591463
/* clause does not match this partition key, but perhaps next. */
14601464
returnPARTCLAUSE_NOMATCH;
14611465

14621466
/*
1463-
* Partition key alsoconsists of acollationthat's specified for it,
1464-
*so try to match it too. There may bemultiplekeys with the same
1465-
*expression but different collations.
1467+
* Partition keymatchalsorequirescollationmatch. There may be
1468+
* multiplepartkeys with the same expression but different
1469+
*collations, so failure is NOMATCH.
14661470
*/
14671471
if (!PartCollMatchesExprColl(partcoll,opclause->inputcollid))
14681472
returnPARTCLAUSE_NOMATCH;
14691473

14701474
/*
14711475
* Matched with this key. Now check various properties of the clause
1472-
* to see if it's sane to use it for pruning. If any of the
1473-
* properties makes it unsuitable for pruning, then the clause is
1474-
* useless no matter which key it's matched to.
1476+
* to see if it's sane to use it for pruning. In most of these cases,
1477+
* we can return UNSUPPORTED because the same failure would occur no
1478+
* matter which partkey it's matched to.
1479+
*/
1480+
1481+
/*
1482+
* We can't prune using an expression with Vars. (Report failure as
1483+
* UNSUPPORTED, not NOMATCH: as in the no-commutator case above, we
1484+
* now know there are Vars on both sides, so it's no good.)
14751485
*/
1486+
if (contain_var_clause((Node*)expr))
1487+
returnPARTCLAUSE_UNSUPPORTED;
14761488

14771489
/*
14781490
* Only allow strict operators. This will guarantee nulls are
14791491
* filtered.
14801492
*/
1481-
if (!op_strict(opclause->opno))
1493+
if (!op_strict(opno))
14821494
returnPARTCLAUSE_UNSUPPORTED;
14831495

14841496
/* We can't use any volatile expressions to prune partitions. */
14851497
if (contain_volatile_functions((Node*)expr))
14861498
returnPARTCLAUSE_UNSUPPORTED;
14871499

1488-
/* We can't prune using an expression with Vars. */
1489-
if (contain_var_clause((Node*)expr))
1490-
returnPARTCLAUSE_UNSUPPORTED;
1491-
14921500
/*
1493-
*Determinetheinput types oftheoperator we're considering.
1501+
*See iftheoperator is relevant tothepartitioning opfamily.
14941502
*
14951503
* Normally we only care about operators that are listed as being part
14961504
* of the partitioning operator family. But there is one exception:
14971505
* the not-equals operators are not listed in any operator family
14981506
* whatsoever, but their negators (equality) are. We can use one of
14991507
* those if we find it, but only for list partitioning.
1508+
*
1509+
* Note: we report NOMATCH on failure, in case a later partkey has the
1510+
* same expression but different opfamily. That's unlikely, but not
1511+
* much more so than duplicate expressions with different collations.
15001512
*/
1501-
if (op_in_opfamily(opclause->opno,partopfamily))
1513+
if (op_in_opfamily(opno,partopfamily))
15021514
{
1503-
Oidoper;
1504-
1505-
oper=OidIsValid(commutator) ?commutator :opclause->opno;
1506-
get_op_opfamily_properties(oper,partopfamily, false,
1515+
get_op_opfamily_properties(opno,partopfamily, false,
15071516
&op_strategy,&op_lefttype,
15081517
&op_righttype);
15091518
}
15101519
else
15111520
{
1512-
/* Not good unless list partitioning */
15131521
if (part_scheme->strategy!=PARTITION_STRATEGY_LIST)
1514-
returnPARTCLAUSE_UNSUPPORTED;
1522+
returnPARTCLAUSE_NOMATCH;
15151523

15161524
/* See if the negator is equality */
1517-
negator=get_negator(opclause->opno);
1525+
negator=get_negator(opno);
15181526
if (OidIsValid(negator)&&op_in_opfamily(negator,partopfamily))
15191527
{
15201528
get_op_opfamily_properties(negator,partopfamily, false,
@@ -1524,17 +1532,17 @@ match_clause_to_partition_key(RelOptInfo *rel,
15241532
is_opne_listp= true;/* bingo */
15251533
}
15261534

1527-
/*Operator isn't really what we were hoping it'd be. */
1535+
/*Nope, it's not <> either. */
15281536
if (!is_opne_listp)
1529-
returnPARTCLAUSE_UNSUPPORTED;
1537+
returnPARTCLAUSE_NOMATCH;
15301538
}
15311539

15321540
/*
15331541
* Now find the procedure to use, based on the types. If the clause's
15341542
* other argument is of the same type as the partitioning opclass's
15351543
* declared input type, we can use the procedure cached in
15361544
* PartitionKey. If not, search for a cross-type one in the same
1537-
* opfamily; if one doesn't exist,give up on pruning for this clause.
1545+
* opfamily; if one doesn't exist,report no match.
15381546
*/
15391547
if (op_righttype==part_scheme->partopcintype[partkeyidx])
15401548
cmpfn=part_scheme->partsupfunc[partkeyidx].fn_oid;
@@ -1569,16 +1577,16 @@ match_clause_to_partition_key(RelOptInfo *rel,
15691577
default:
15701578
elog(ERROR,"invalid partition strategy: %c",
15711579
part_scheme->strategy);
1580+
cmpfn=InvalidOid;/* keep compiler quiet */
15721581
break;
15731582
}
15741583

1575-
/* If we couldn't find one, we cannot use this expression. */
15761584
if (!OidIsValid(cmpfn))
1577-
returnPARTCLAUSE_UNSUPPORTED;
1585+
returnPARTCLAUSE_NOMATCH;
15781586
}
15791587

15801588
/*
1581-
* Build the clause, passing the negatoror commutatorif applicable.
1589+
* Build the clause, passing the negator if applicable.
15821590
*/
15831591
partclause= (PartClauseInfo*)palloc(sizeof(PartClauseInfo));
15841592
partclause->keyno=partkeyidx;
@@ -1591,8 +1599,7 @@ match_clause_to_partition_key(RelOptInfo *rel,
15911599
}
15921600
else
15931601
{
1594-
partclause->opno=OidIsValid(commutator) ?
1595-
commutator :opclause->opno;
1602+
partclause->opno=opno;
15961603
partclause->op_is_ne= false;
15971604
partclause->op_strategy=op_strategy;
15981605
}
@@ -1625,9 +1632,14 @@ match_clause_to_partition_key(RelOptInfo *rel,
16251632

16261633
/*
16271634
* Matched with this key. Check various properties of the clause to
1628-
* see if it can sanely be used for partition pruning.
1635+
* see if it can sanely be used for partition pruning (this is mostly
1636+
* the same as for a plain OpExpr).
16291637
*/
16301638

1639+
/* We can't prune using an expression with Vars. */
1640+
if (contain_var_clause((Node*)rightop))
1641+
returnPARTCLAUSE_UNSUPPORTED;
1642+
16311643
/*
16321644
* Only allow strict operators. This will guarantee nulls are
16331645
* filtered.
@@ -1639,22 +1651,18 @@ match_clause_to_partition_key(RelOptInfo *rel,
16391651
if (contain_volatile_functions((Node*)rightop))
16401652
returnPARTCLAUSE_UNSUPPORTED;
16411653

1642-
/* We can't prune using an expression with Vars. */
1643-
if (contain_var_clause((Node*)rightop))
1644-
returnPARTCLAUSE_UNSUPPORTED;
1645-
16461654
/*
16471655
* In case of NOT IN (..), we get a '<>', which we handle if list
16481656
* partitioning is in use and we're able to confirm that it's negator
16491657
* is a btree equality operator belonging to the partitioning operator
1650-
* family.
1658+
* family. As above, report NOMATCH for non-matching operator.
16511659
*/
16521660
if (!op_in_opfamily(saop_op,partopfamily))
16531661
{
16541662
Oidnegator;
16551663

16561664
if (part_scheme->strategy!=PARTITION_STRATEGY_LIST)
1657-
returnPARTCLAUSE_UNSUPPORTED;
1665+
returnPARTCLAUSE_NOMATCH;
16581666

16591667
negator=get_negator(saop_op);
16601668
if (OidIsValid(negator)&&op_in_opfamily(negator,partopfamily))
@@ -1667,10 +1675,10 @@ match_clause_to_partition_key(RelOptInfo *rel,
16671675
false,&strategy,
16681676
&lefttype,&righttype);
16691677
if (strategy!=BTEqualStrategyNumber)
1670-
returnPARTCLAUSE_UNSUPPORTED;
1678+
returnPARTCLAUSE_NOMATCH;
16711679
}
16721680
else
1673-
returnPARTCLAUSE_UNSUPPORTED;/* no useful negator */
1681+
returnPARTCLAUSE_NOMATCH;/* no useful negator */
16741682
}
16751683

16761684
/*
@@ -1680,7 +1688,7 @@ match_clause_to_partition_key(RelOptInfo *rel,
16801688
elem_exprs=NIL;
16811689
if (IsA(rightop,Const))
16821690
{
1683-
Const*arr=castNode(Const,rightop);
1691+
Const*arr= (Const*)rightop;
16841692
ArrayType*arrval=DatumGetArrayTypeP(arr->constvalue);
16851693
int16elemlen;
16861694
boolelembyval;
@@ -1701,9 +1709,17 @@ match_clause_to_partition_key(RelOptInfo *rel,
17011709
{
17021710
Const*elem_expr;
17031711

1704-
/* Only consider non-null values. */
1712+
/*
1713+
* A null array element must lead to a null comparison result,
1714+
* since saop_op is known strict. We can ignore it in the
1715+
* useOr case, but otherwise it implies self-contradiction.
1716+
*/
17051717
if (elem_nulls[i])
1706-
continue;
1718+
{
1719+
if (saop->useOr)
1720+
continue;
1721+
returnPARTCLAUSE_MATCH_CONTRADICT;
1722+
}
17071723

17081724
elem_expr=makeConst(ARR_ELEMTYPE(arrval),-1,
17091725
arr->constcollid,elemlen,
@@ -1748,7 +1764,7 @@ match_clause_to_partition_key(RelOptInfo *rel,
17481764
}
17491765

17501766
/*
1751-
* If we have an ANY clause and multiple elements,first turn the list
1767+
* If we have an ANY clause and multiple elements,now turn the list
17521768
* of clauses into an OR expression.
17531769
*/
17541770
if (saop->useOr&&list_length(elem_clauses)>1)
@@ -1776,7 +1792,7 @@ match_clause_to_partition_key(RelOptInfo *rel,
17761792
if (!equal(arg,partkey))
17771793
returnPARTCLAUSE_NOMATCH;
17781794

1779-
*clause_is_not_null=nulltest->nulltesttype==IS_NOT_NULL;
1795+
*clause_is_not_null=(nulltest->nulltesttype==IS_NOT_NULL);
17801796

17811797
returnPARTCLAUSE_MATCH_NULLNESS;
17821798
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp