@@ -613,18 +613,17 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
613613 Expr * clause = (Expr * ) lfirst (lc );
614614 int i ;
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- return NIL ;
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+ return NIL ;
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 clause cannot 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 a key .
1384+ * * PARTCLAUSE_UNSUPPORTED if the clause doesn'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 a volatile function) .
13881387 * Output arguments: none set.
13891388 */
13901389static PartClauseMatchStatus
@@ -1395,9 +1394,9 @@ match_clause_to_partition_key(RelOptInfo *rel,
13951394 List * * clause_steps )
13961395{
13971396 PartitionScheme part_scheme = rel -> part_scheme ;
1398- Expr * expr ;
13991397 Oid partopfamily = 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- Oid op_lefttype ,
1429+ Oid opno ,
1430+ op_lefttype ,
14311431 op_righttype ,
1432- commutator = InvalidOid ,
14331432 negator = InvalidOid ;
14341433 Oid cmpfn ;
14351434 int op_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 else if (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 return PARTCLAUSE_UNSUPPORTED ;
1460+ expr = leftop ;
14571461 }
14581462 else
14591463 /* clause does not match this partition key, but perhaps next. */
14601464 return PARTCLAUSE_NOMATCH ;
14611465
14621466 /*
1463- * Partition key also consists of a collation that's specified for it,
1464- * so try to match it too. There may be multiple keys with the same
1465- * expression but different collations .
1467+ * Partition key match also requires collation match. There may be
1468+ * multiple partkeys with the same expression but different
1469+ * collations, so failure is NOMATCH .
14661470 */
14671471 if (!PartCollMatchesExprColl (partcoll , opclause -> inputcollid ))
14681472 return PARTCLAUSE_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+ return PARTCLAUSE_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 return PARTCLAUSE_UNSUPPORTED ;
14831495
14841496 /* We can't use any volatile expressions to prune partitions. */
14851497 if (contain_volatile_functions ((Node * ) expr ))
14861498 return PARTCLAUSE_UNSUPPORTED ;
14871499
1488- /* We can't prune using an expression with Vars. */
1489- if (contain_var_clause ((Node * ) expr ))
1490- return PARTCLAUSE_UNSUPPORTED ;
1491-
14921500 /*
1493- * Determine the input types of the operator we're considering .
1501+ * See if the operator is relevant to the partitioning 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- Oid oper ;
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- return PARTCLAUSE_UNSUPPORTED ;
1522+ return PARTCLAUSE_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- return PARTCLAUSE_UNSUPPORTED ;
1537+ return PARTCLAUSE_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- return PARTCLAUSE_UNSUPPORTED ;
1585+ return PARTCLAUSE_NOMATCH ;
15781586 }
15791587
15801588 /*
1581- * Build the clause, passing the negator or commutator if 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+ return PARTCLAUSE_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 return PARTCLAUSE_UNSUPPORTED ;
16411653
1642- /* We can't prune using an expression with Vars. */
1643- if (contain_var_clause ((Node * ) rightop ))
1644- return PARTCLAUSE_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 Oid negator ;
16551663
16561664 if (part_scheme -> strategy != PARTITION_STRATEGY_LIST )
1657- return PARTCLAUSE_UNSUPPORTED ;
1665+ return PARTCLAUSE_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- return PARTCLAUSE_UNSUPPORTED ;
1678+ return PARTCLAUSE_NOMATCH ;
16711679 }
16721680 else
1673- return PARTCLAUSE_UNSUPPORTED ; /* no useful negator */
1681+ return PARTCLAUSE_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 int16 elemlen ;
16861694 bool elembyval ;
@@ -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+ return PARTCLAUSE_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 return PARTCLAUSE_NOMATCH ;
17781794
1779- * clause_is_not_null = nulltest -> nulltesttype == IS_NOT_NULL ;
1795+ * clause_is_not_null = ( nulltest -> nulltesttype == IS_NOT_NULL ) ;
17801796
17811797 return PARTCLAUSE_MATCH_NULLNESS ;
17821798 }
0 commit comments