From: Tom Lane Date: Tue, 24 Jul 2007 17:22:07 +0000 (+0000) Subject: Fix predicate-proving logic to cope with binary-compatibility cases when X-Git-Tag: REL8_3_BETA1~399 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=507b53c8338c176edb27804573e5747874b171f2;p=postgresql Fix predicate-proving logic to cope with binary-compatibility cases when checking whether an IS NULL/IS NOT NULL clause is implied or refuted by a strict function. Per example from Dawid Kuroczko. Backpatch to 8.2 since this is arguably a performance bug. --- diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 9bdef7a319..3280612dfd 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.