From: Tom Lane Date: Sun, 7 Mar 2004 05:43:53 +0000 (+0000) Subject: When testing usability of a partial index, recognize that an index X-Git-Tag: REL8_0_0BETA1~1051 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bc19d6641a1dbb6ce227b0fdd2de1635aa2bc91b;p=postgresql When testing usability of a partial index, recognize that an index predicate of the form 'foo IS NOT NULL' is implied by a WHERE clause that uses 'foo' in any strict operator or function. Per suggestion and preliminary implementation by John Siracusa; some further hacking by moi. --- diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index ecd126da7f..7d04ef14b7 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.156 2004/01/07 22:02:48 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.157 2004/03/07 05:43:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -965,24 +965,38 @@ static const StrategyNumber }; -/* +/*---------- * pred_test_simple_clause * Does the "predicate inclusion test" for a "simple clause" predicate * and a "simple clause" restriction. * - * We have two strategies for determining whether one simple clause - * implies another. A simple and general way is to see if they are - * equal(); this works for any kind of expression. (Actually, there - * is an implied assumption that the functions in the expression are - * immutable, ie dependent only on their input arguments --- but this - * was checked for the predicate by CheckPredicate().) + * We have three strategies for determining whether one simple clause + * implies another: + * + * A simple and general way is to see if they are equal(); this works for any + * kind of expression. (Actually, there is an implied assumption that the + * functions in the expression are immutable, ie dependent only on their input + * arguments --- but this was checked for the predicate by CheckPredicate().) * - * Our other way works only for (binary boolean) operators that are - * in some btree operator class. We use the above operator implication - * table to be able to derive implications between nonidentical clauses. + * When the predicate is of the form "foo IS NOT NULL", we can conclude that + * the predicate is implied if the clause is a strict operator or function + * that has "foo" as an input. In this case the clause must yield NULL when + * "foo" is NULL, which we can take as equivalent to FALSE because we know + * we are within an AND/OR subtree of a WHERE clause. (Again, "foo" is + * already known immutable, so the clause will certainly always fail.) * - * Eventually, rtree operators could also be handled by defining an - * appropriate "RT_implic_table" array. + * Our other way works only for binary boolean opclauses of the form + * "foo op constant", where "foo" is the same in both clauses. The operators + * and constants can be different but the operators must be in the same btree + * operator class. We use the above operator implication table to be able to + * derive implications between nonidentical clauses. (Note: "foo" is known + * immutable, and constants are surely immutable, and we assume that operators + * that are in btree opclasses are immutable, so there's no need to do extra + * mutability checks in this case either.) + * + * Eventually, rtree operators could also be handled by defining an + * appropriate "RT_implic_table" array. + *---------- */ static bool pred_test_simple_clause(Expr *predicate, Node *clause) @@ -1020,6 +1034,23 @@ pred_test_simple_clause(Expr *predicate, Node *clause) if (equal((Node *) predicate, clause)) return true; + /* Next try the IS NOT NULL case */ + if (predicate && IsA(predicate, NullTest) && + ((NullTest *) predicate)->nulltesttype == IS_NOT_NULL) + { + Expr *nonnullarg = ((NullTest *) predicate)->arg; + + if (is_opclause(clause) && + member(nonnullarg, ((OpExpr *) clause)->args) && + op_strict(((OpExpr *) clause)->opno)) + return true; + if (is_funcclause(clause) && + member(nonnullarg, ((FuncExpr *) clause)->args) && + func_strict(((FuncExpr *) clause)->funcid)) + return true; + return false; /* we can't succeed below... */ + } + /* * Can't do anything more unless they are both binary opclauses with a * Const on one side, and identical subexpressions on the other sides.