diff options
Diffstat (limited to 'src/backend/optimizer/prep/prepqual.c')
-rw-r--r-- | src/backend/optimizer/prep/prepqual.c | 127 |
1 files changed, 24 insertions, 103 deletions
diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index 8d92ee317a0..c153d312fa6 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -3,12 +3,29 @@ * prepqual.c * Routines for preprocessing qualification expressions * + * + * The parser regards AND and OR as purely binary operators, so a qual like + * (A = 1) OR (A = 2) OR (A = 3) ... + * will produce a nested parsetree + * (OR (A = 1) (OR (A = 2) (OR (A = 3) ...))) + * In reality, the optimizer and executor regard AND and OR as N-argument + * operators, so this tree can be flattened to + * (OR (A = 1) (A = 2) (A = 3) ...) + * + * Formerly, this module was responsible for doing the initial flattening, + * but now we leave it to eval_const_expressions to do that since it has to + * make a complete pass over the expression tree anyway. Instead, we just + * have to ensure that our manipulations preserve AND/OR flatness. + * pull_ands() and pull_ors() are used to maintain flatness of the AND/OR + * tree after local transformations that might introduce nested AND/ORs. + * + * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.48 2004/12/31 22:00:20 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.49 2005/03/28 00:58:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,7 +38,6 @@ #include "utils/lsyscache.h" -static Node *flatten_andors_mutator(Node *node, void *context); static List *pull_ands(List *andlist); static List *pull_ors(List *orlist); static Expr *find_nots(Expr *qual); @@ -40,6 +56,11 @@ static Expr *process_duplicate_ors(List *orlist); * actual usefulness, and so now the transformation doesn't involve any * notion of reaching a canonical form. * + * NOTE: we assume the input has already been through eval_const_expressions + * and therefore possesses AND/OR flatness. Formerly this function included + * its own flattening logic, but that requires a useless extra pass over the + * tree. + * * Returns the modified qualification. */ Expr * @@ -52,17 +73,12 @@ canonicalize_qual(Expr *qual) return NULL; /* - * Flatten AND and OR groups throughout the expression tree. - */ - newqual = (Expr *) flatten_andors((Node *) qual); - - /* * Push down NOTs. We do this only in the top-level boolean * expression, without examining arguments of operators/functions. The * main reason for doing this is to expose as much top-level AND/OR * structure as we can, so there's no point in descending further. */ - newqual = find_nots(newqual); + newqual = find_nots(qual); /* * Pull up redundant subclauses in OR-of-AND trees. Again, we do this @@ -74,101 +90,6 @@ canonicalize_qual(Expr *qual) } -/*-------------------- - * The parser regards AND and OR as purely binary operators, so a qual like - * (A = 1) OR (A = 2) OR (A = 3) ... - * will produce a nested parsetree - * (OR (A = 1) (OR (A = 2) (OR (A = 3) ...))) - * In reality, the optimizer and executor regard AND and OR as n-argument - * operators, so this tree can be flattened to - * (OR (A = 1) (A = 2) (A = 3) ...) - * which is the responsibility of the routines below. - * - * flatten_andors() does the basic transformation with no initial assumptions. - * pull_ands() and pull_ors() are used to maintain flatness of the AND/OR - * tree after local transformations that might introduce nested AND/ORs. - *-------------------- - */ - -/* - * flatten_andors - * Given an expression tree, simplify nested AND/OR clauses into flat - * AND/OR clauses with more arguments. The entire tree is processed. - * - * Returns the rebuilt expr (note original structure is not touched). - * - * This is exported so that other modules can perform the part of - * canonicalize_qual processing that applies to entire trees, rather - * than just the top-level boolean expressions. - */ -Node * -flatten_andors(Node *node) -{ - return flatten_andors_mutator(node, NULL); -} - -static Node * -flatten_andors_mutator(Node *node, void *context) -{ - if (node == NULL) - return NULL; - if (IsA(node, BoolExpr)) - { - BoolExpr *bexpr = (BoolExpr *) node; - - if (bexpr->boolop == AND_EXPR) - { - List *out_list = NIL; - ListCell *arg; - - foreach(arg, bexpr->args) - { - Node *subexpr = flatten_andors((Node *) lfirst(arg)); - - /* - * Note: we can destructively concat the subexpression's - * arglist because we know the recursive invocation of - * flatten_andors will have built a new arglist not shared - * with any other expr. Otherwise we'd need a list_copy - * here. - */ - if (and_clause(subexpr)) - out_list = list_concat(out_list, - ((BoolExpr *) subexpr)->args); - else - out_list = lappend(out_list, subexpr); - } - return (Node *) make_andclause(out_list); - } - if (bexpr->boolop == OR_EXPR) - { - List *out_list = NIL; - ListCell *arg; - - foreach(arg, bexpr->args) - { - Node *subexpr = flatten_andors((Node *) lfirst(arg)); - - /* - * Note: we can destructively concat the subexpression's - * arglist because we know the recursive invocation of - * flatten_andors will have built a new arglist not shared - * with any other expr. Otherwise we'd need a list_copy - * here. - */ - if (or_clause(subexpr)) - out_list = list_concat(out_list, - ((BoolExpr *) subexpr)->args); - else - out_list = lappend(out_list, subexpr); - } - return (Node *) make_orclause(out_list); - } - /* else it's a NOT clause, fall through */ - } - return expression_tree_mutator(node, flatten_andors_mutator, context); -} - /* * pull_ands * Recursively flatten nested AND clauses into a single and-clause list. |