@ -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 tg l 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 *
@ -51,18 +72,13 @@ canonicalize_qual(Expr *qual)
if ( qual = = NULL )
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 ( new qual) ;
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 .