@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / optimizer / util / predtest . c , v 1.20 2008 / 08 / 25 22 : 42 : 33 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / optimizer / util / predtest . c , v 1.21 2008 / 11 / 12 23 : 08 : 37 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -19,6 +19,7 @@
# include "catalog/pg_proc.h"
# include "catalog/pg_type.h"
# include "executor/executor.h"
# include "miscadmin.h"
# include "nodes/nodeFuncs.h"
# include "optimizer/clauses.h"
# include "optimizer/predtest.h"
@ -27,6 +28,15 @@
# include "utils/syscache.h"
/*
* Proof attempts involving many AND or OR branches are likely to require
* O ( N ^ 2 ) time , and more often than not fail anyway . So we set an arbitrary
* limit on the number of branches that we will allow at any one level of
* clause . ( Note that this is only effective because the trees have been
* AND / OR flattened ! ) XXX is it worth exposing this as a GUC knob ?
*/
# define MAX_BRANCHES_TO_TEST 100
/*
* To avoid redundant coding in predicate_implied_by_recurse and
* predicate_refuted_by_recurse , we need to abstract out the notion of
@ -686,6 +696,13 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate)
*
* If the expression is classified as AND - or OR - type , then * info is filled
* in with the functions needed to iterate over its components .
*
* This function also implements enforcement of MAX_BRANCHES_TO_TEST : if an
* AND / OR expression has too many branches , we just classify it as an atom .
* ( This will result in its being passed as - is to the simple_clause functions ,
* which will fail to prove anything about it . ) Note that we cannot just stop
* after considering MAX_BRANCHES_TO_TEST branches ; in general that would
* result in wrong proofs rather than failing to prove anything .
*/
static PredClass
predicate_classify ( Node * clause , PredIterInfo info )
@ -698,7 +715,8 @@ predicate_classify(Node *clause, PredIterInfo info)
* If we see a List , assume it ' s an implicit - AND list ; this is the correct
* semantics for lists of RestrictInfo nodes .
*/
if ( IsA ( clause , List ) )
if ( IsA ( clause , List ) & &
list_length ( ( List * ) clause ) < = MAX_BRANCHES_TO_TEST )
{
info - > startup_fn = list_startup_fn ;
info - > next_fn = list_next_fn ;
@ -707,14 +725,16 @@ predicate_classify(Node *clause, PredIterInfo info)
}
/* Handle normal AND and OR boolean clauses */
if ( and_clause ( clause ) )
if ( and_clause ( clause ) & &
list_length ( ( ( BoolExpr * ) clause ) - > args ) < = MAX_BRANCHES_TO_TEST )
{
info - > startup_fn = boolexpr_startup_fn ;
info - > next_fn = list_next_fn ;
info - > cleanup_fn = list_cleanup_fn ;
return CLASS_AND ;
}
if ( or_clause ( clause ) )
if ( or_clause ( clause ) & &
list_length ( ( ( BoolExpr * ) clause ) - > args ) < = MAX_BRANCHES_TO_TEST )
{
info - > startup_fn = boolexpr_startup_fn ;
info - > next_fn = list_next_fn ;
@ -737,13 +757,22 @@ predicate_classify(Node *clause, PredIterInfo info)
if ( arraynode & & IsA ( arraynode , Const ) & &
! ( ( Const * ) arraynode ) - > constisnull )
{
info - > startup_fn = arrayconst_startup_fn ;
info - > next_fn = arrayconst_next_fn ;
info - > cleanup_fn = arrayconst_cleanup_fn ;
return saop - > useOr ? CLASS_OR : CLASS_AND ;
ArrayType * arrayval ;
int nelems ;
arrayval = DatumGetArrayTypeP ( ( ( Const * ) arraynode ) - > constvalue ) ;
nelems = ArrayGetNItems ( ARR_NDIM ( arrayval ) , ARR_DIMS ( arrayval ) ) ;
if ( nelems < = MAX_BRANCHES_TO_TEST )
{
info - > startup_fn = arrayconst_startup_fn ;
info - > next_fn = arrayconst_next_fn ;
info - > cleanup_fn = arrayconst_cleanup_fn ;
return saop - > useOr ? CLASS_OR : CLASS_AND ;
}
}
if ( arraynode & & IsA ( arraynode , ArrayExpr ) & &
! ( ( ArrayExpr * ) arraynode ) - > multidims )
else if ( arraynode & & IsA ( arraynode , ArrayExpr ) & &
! ( ( ArrayExpr * ) arraynode ) - > multidims & &
list_length ( ( ( ArrayExpr * ) arraynode ) - > elements ) < = MAX_BRANCHES_TO_TEST )
{
info - > startup_fn = arrayexpr_startup_fn ;
info - > next_fn = arrayexpr_next_fn ;
@ -964,6 +993,9 @@ arrayexpr_cleanup_fn(PredIterInfo info)
static bool
predicate_implied_by_simple_clause ( Expr * predicate , Node * clause )
{
/* Allow interrupting long proof attempts */
CHECK_FOR_INTERRUPTS ( ) ;
/* First try the equal() test */
if ( equal ( ( Node * ) predicate , clause ) )
return true ;
@ -1019,6 +1051,9 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
static bool
predicate_refuted_by_simple_clause ( Expr * predicate , Node * clause )
{
/* Allow interrupting long proof attempts */
CHECK_FOR_INTERRUPTS ( ) ;
/* A simple clause can't refute itself */
/* Worth checking because of relation_excluded_by_constraints() */
if ( ( Node * ) predicate = = clause )