33 * prepqual.c
44 * Routines for preprocessing qualification expressions
55 *
6+ *
7+ * The parser regards AND and OR as purely binary operators, so a qual like
8+ * (A = 1) OR (A = 2) OR (A = 3) ...
9+ * will produce a nested parsetree
10+ * (OR (A = 1) (OR (A = 2) (OR (A = 3) ...)))
11+ * In reality, the optimizer and executor regard AND and OR as N-argument
12+ * operators, so this tree can be flattened to
13+ * (OR (A = 1) (A = 2) (A = 3) ...)
14+ *
15+ * Formerly, this module was responsible for doing the initial flattening,
16+ * but now we leave it to eval_const_expressions to do that since it has to
17+ * make a complete pass over the expression tree anyway. Instead, we just
18+ * have to ensure that our manipulations preserve AND/OR flatness.
19+ * pull_ands() and pull_ors() are used to maintain flatness of the AND/OR
20+ * tree after local transformations that might introduce nested AND/ORs.
21+ *
22+ *
623 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
724 * Portions Copyright (c) 1994, Regents of the University of California
825 *
926 *
1027 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.48 2004/12/31 22: 00:20 pgsql Exp $
28+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.49 2005/03/28 00:58:23 tgl Exp $
1229 *
1330 *-------------------------------------------------------------------------
1431 */
2138#include "utils/lsyscache.h"
2239
2340
24- static Node * flatten_andors_mutator (Node * node , void * context );
2541static List * pull_ands (List * andlist );
2642static List * pull_ors (List * orlist );
2743static Expr * find_nots (Expr * qual );
@@ -40,6 +56,11 @@ static Expr *process_duplicate_ors(List *orlist);
4056 * actual usefulness, and so now the transformation doesn't involve any
4157 * notion of reaching a canonical form.
4258 *
59+ * NOTE: we assume the input has already been through eval_const_expressions
60+ * and therefore possesses AND/OR flatness. Formerly this function included
61+ * its own flattening logic, but that requires a useless extra pass over the
62+ * tree.
63+ *
4364 * Returns the modified qualification.
4465 */
4566Expr *
@@ -51,18 +72,13 @@ canonicalize_qual(Expr *qual)
5172 if (qual == NULL )
5273 return NULL ;
5374
54- /*
55- * Flatten AND and OR groups throughout the expression tree.
56- */
57- newqual = (Expr * ) flatten_andors ((Node * ) qual );
58-
5975 /*
6076 * Push down NOTs. We do this only in the top-level boolean
6177 * expression, without examining arguments of operators/functions. The
6278 * main reason for doing this is to expose as much top-level AND/OR
6379 * structure as we can, so there's no point in descending further.
6480 */
65- newqual = find_nots (newqual );
81+ newqual = find_nots (qual );
6682
6783 /*
6884 * Pull up redundant subclauses in OR-of-AND trees. Again, we do this
@@ -74,101 +90,6 @@ canonicalize_qual(Expr *qual)
7490}
7591
7692
77- /*--------------------
78- * The parser regards AND and OR as purely binary operators, so a qual like
79- * (A = 1) OR (A = 2) OR (A = 3) ...
80- * will produce a nested parsetree
81- * (OR (A = 1) (OR (A = 2) (OR (A = 3) ...)))
82- * In reality, the optimizer and executor regard AND and OR as n-argument
83- * operators, so this tree can be flattened to
84- * (OR (A = 1) (A = 2) (A = 3) ...)
85- * which is the responsibility of the routines below.
86- *
87- * flatten_andors() does the basic transformation with no initial assumptions.
88- * pull_ands() and pull_ors() are used to maintain flatness of the AND/OR
89- * tree after local transformations that might introduce nested AND/ORs.
90- *--------------------
91- */
92-
93- /*
94- * flatten_andors
95- * Given an expression tree, simplify nested AND/OR clauses into flat
96- * AND/OR clauses with more arguments. The entire tree is processed.
97- *
98- * Returns the rebuilt expr (note original structure is not touched).
99- *
100- * This is exported so that other modules can perform the part of
101- * canonicalize_qual processing that applies to entire trees, rather
102- * than just the top-level boolean expressions.
103- */
104- Node *
105- flatten_andors (Node * node )
106- {
107- return flatten_andors_mutator (node , NULL );
108- }
109-
110- static Node *
111- flatten_andors_mutator (Node * node , void * context )
112- {
113- if (node == NULL )
114- return NULL ;
115- if (IsA (node , BoolExpr ))
116- {
117- BoolExpr * bexpr = (BoolExpr * ) node ;
118-
119- if (bexpr -> boolop == AND_EXPR )
120- {
121- List * out_list = NIL ;
122- ListCell * arg ;
123-
124- foreach (arg , bexpr -> args )
125- {
126- Node * subexpr = flatten_andors ((Node * ) lfirst (arg ));
127-
128- /*
129- * Note: we can destructively concat the subexpression's
130- * arglist because we know the recursive invocation of
131- * flatten_andors will have built a new arglist not shared
132- * with any other expr. Otherwise we'd need a list_copy
133- * here.
134- */
135- if (and_clause (subexpr ))
136- out_list = list_concat (out_list ,
137- ((BoolExpr * ) subexpr )-> args );
138- else
139- out_list = lappend (out_list , subexpr );
140- }
141- return (Node * ) make_andclause (out_list );
142- }
143- if (bexpr -> boolop == OR_EXPR )
144- {
145- List * out_list = NIL ;
146- ListCell * arg ;
147-
148- foreach (arg , bexpr -> args )
149- {
150- Node * subexpr = flatten_andors ((Node * ) lfirst (arg ));
151-
152- /*
153- * Note: we can destructively concat the subexpression's
154- * arglist because we know the recursive invocation of
155- * flatten_andors will have built a new arglist not shared
156- * with any other expr. Otherwise we'd need a list_copy
157- * here.
158- */
159- if (or_clause (subexpr ))
160- out_list = list_concat (out_list ,
161- ((BoolExpr * ) subexpr )-> args );
162- else
163- out_list = lappend (out_list , subexpr );
164- }
165- return (Node * ) make_orclause (out_list );
166- }
167- /* else it's a NOT clause, fall through */
168- }
169- return expression_tree_mutator (node , flatten_andors_mutator , context );
170- }
171-
17293/*
17394 * pull_ands
17495 * Recursively flatten nested AND clauses into a single and-clause list.
0 commit comments