diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 9bdef7a319cf01926b2206dff7ce6c18cd47091d..3280612dfd5b4877dca95d6ff747f1c8fbf94c16 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.15 2007/05/12 19:22:35 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.16 2007/07/24 17:22:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -84,6 +84,7 @@ static bool predicate_implied_by_simple_clause(Expr *predicate, Node *clause); static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause); static bool is_null_contradicts(NullTest *ntest, Node *clause); static Node *extract_not_arg(Node *clause); +static bool list_member_strip(List *list, Expr *datum); static bool btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it); @@ -961,11 +962,11 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause) if (!type_is_rowtype(exprType((Node *) nonnullarg))) { if (is_opclause(clause) && - list_member(((OpExpr *) clause)->args, nonnullarg) && + list_member_strip(((OpExpr *) clause)->args, nonnullarg) && op_strict(((OpExpr *) clause)->opno)) return true; if (is_funcclause(clause) && - list_member(((FuncExpr *) clause)->args, nonnullarg) && + list_member_strip(((FuncExpr *) clause)->args, nonnullarg) && func_strict(((FuncExpr *) clause)->funcid)) return true; } @@ -1044,11 +1045,11 @@ is_null_contradicts(NullTest *ntest, Node *clause) /* foo IS NULL contradicts any strict op/func on foo */ if (is_opclause(clause) && - list_member(((OpExpr *) clause)->args, isnullarg) && + list_member_strip(((OpExpr *) clause)->args, isnullarg) && op_strict(((OpExpr *) clause)->opno)) return true; if (is_funcclause(clause) && - list_member(((FuncExpr *) clause)->args, isnullarg) && + list_member_strip(((FuncExpr *) clause)->args, isnullarg) && func_strict(((FuncExpr *) clause)->funcid)) return true; @@ -1091,6 +1092,36 @@ extract_not_arg(Node *clause) } +/* + * Check whether an Expr is equal() to any member of a list, ignoring + * any top-level RelabelType nodes. This is legitimate for the purposes + * we use it for (matching IS [NOT] NULL arguments to arguments of strict + * functions) because RelabelType doesn't change null-ness. It's helpful + * for cases such as a varchar argument of a strict function on text. + */ +static bool +list_member_strip(List *list, Expr *datum) +{ + ListCell *cell; + + if (datum && IsA(datum, RelabelType)) + datum = ((RelabelType *) datum)->arg; + + foreach(cell, list) + { + Expr *elem = (Expr *) lfirst(cell); + + if (elem && IsA(elem, RelabelType)) + elem = ((RelabelType *) elem)->arg; + + if (equal(elem, datum)) + return true; + } + + return false; +} + + /* * Define an "operator implication table" for btree operators ("strategies"), * and a similar table for refutation.