diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-07-29 21:40:02 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-07-29 21:40:02 +0000 |
commit | 284e4739ef898807202337f830eee38ad7de18fc (patch) | |
tree | a0e5efe0195daf4426bc2c0b3ad255e61ba35594 /src/backend/optimizer/prep/prepqual.c | |
parent | 80f6c35833508a793b5b488fb56f52118259eba5 (diff) | |
download | postgresql-284e4739ef898807202337f830eee38ad7de18fc.tar.gz postgresql-284e4739ef898807202337f830eee38ad7de18fc.zip |
Fix an oversight I introduced on 2003-12-28: find_nots/push_nots should
continue to recurse after eliminating a NOT-below-a-NOT, since the
contained subexpression will now be part of the top-level AND/OR structure
and so deserves to be simplified. The real-world impact of this is
probably minimal, since it'd require at least three levels of NOT to make
a difference, but it's still a bug.
Also remove some redundant tests for NULL subexpressions.
Diffstat (limited to 'src/backend/optimizer/prep/prepqual.c')
-rw-r--r-- | src/backend/optimizer/prep/prepqual.c | 29 |
1 files changed, 10 insertions, 19 deletions
diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index c153d312fa6..2c39859a811 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -25,7 +25,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.49 2005/03/28 00:58:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.50 2005/07/29 21:40:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -167,9 +167,6 @@ pull_ors(List *orlist) static Expr * find_nots(Expr *qual) { - if (qual == NULL) - return NULL; - if (and_clause((Node *) qual)) { List *t_list = NIL; @@ -204,17 +201,13 @@ find_nots(Expr *qual) static Expr * push_nots(Expr *qual) { - if (qual == NULL) - return make_notclause(qual); /* XXX is this right? Or - * possible? */ - - /* - * Negate an operator clause if possible: (NOT (< A B)) => (>= A B) - * Otherwise, retain the clause as it is (the NOT can't be pushed down - * any farther). - */ if (is_opclause(qual)) { + /* + * Negate an operator clause if possible: (NOT (< A B)) => (>= A B) + * Otherwise, retain the clause as it is (the NOT can't be pushed down + * any farther). + */ OpExpr *opexpr = (OpExpr *) qual; Oid negator = get_negator(opexpr->opno); @@ -256,15 +249,16 @@ push_nots(Expr *qual) { /* * Another NOT cancels this NOT, so eliminate the NOT and stop - * negating this branch. + * negating this branch. But search the subexpression for more + * NOTs to simplify. */ - return get_notclausearg(qual); + return find_nots(get_notclausearg(qual)); } else { /* * We don't know how to negate anything else, place a NOT at this - * level. + * level. No point in recursing deeper, either. */ return make_notclause(qual); } @@ -303,9 +297,6 @@ push_nots(Expr *qual) static Expr * find_duplicate_ors(Expr *qual) { - if (qual == NULL) - return NULL; - if (or_clause((Node *) qual)) { List *orlist = NIL; |