@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / optimizer / path / indxpath . c , v 1.186 2005 / 07 / 02 23 : 00 : 4 0 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / optimizer / path / indxpath . c , v 1.187 2005 / 07 / 28 20 : 26 : 2 0 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -212,6 +212,8 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
* subclause to any index on x alone , because such a Path would already have
* been generated at the upper level . So we could use an index on x , y , z
* or an index on x , y for the OR subclause , but not an index on just x .
* When dealing with a partial index , a match of the index predicate to
* one of the " current " clauses also makes the index usable .
*
* If istoplevel is true ( indicating we are considering the top level of a
* rel ' s restriction clauses ) , we will include indexes in the result that
@ -248,6 +250,8 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
List * restrictclauses ;
List * index_pathkeys ;
List * useful_pathkeys ;
bool useful_predicate ;
bool found_clause ;
bool index_is_ordered ;
/*
@ -258,29 +262,60 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
* Otherwise , we have to test whether the added clauses are
* sufficient to imply the predicate . If so , we could use
* the index in the current context .
*
* We set useful_predicate to true iff the predicate was proven
* using the current set of clauses . This is needed to prevent
* matching a predOK index to an arm of an OR , which would be
* a legal but pointlessly inefficient plan . ( A better plan will
* be generated by just scanning the predOK index alone , no OR . )
*/
if ( index - > indpred ! = NIL & & ! index - > predOK )
useful_predicate = false ;
if ( index - > indpred ! = NIL )
{
if ( istoplevel )
continue ; /* no point in trying to prove it */
if ( index - > predOK )
{
if ( istoplevel )
{
/* we know predicate was proven from these clauses */
useful_predicate = true ;
}
}
else
{
if ( istoplevel )
continue ; /* no point in trying to prove it */
/* Form all_clauses if not done already */
if ( all_clauses = = NIL )
all_clauses = list_concat ( list_copy ( clauses ) ,
outer_clauses ) ;
/* Form all_clauses if not done already */
if ( all_clauses = = NIL )
all_clauses = list_concat ( list_copy ( clauses ) ,
outer_clauses ) ;
if ( ! predicate_implied_by ( index - > indpred , all_clauses ) | |
predicate_implied_by ( index - > indpred , outer_clauses ) )
continue ;
if ( ! predicate_implied_by ( index - > indpred , all_clauses ) )
continue ; /* can't use it at all */
if ( ! predicate_implied_by ( index - > indpred , outer_clauses ) )
useful_predicate = true ;
}
}
/*
* 1. Match the index against the available restriction clauses .
* found_clause is set true only if at least one of the current
* clauses was used .
*/
restrictclauses = group_clauses_by_indexkey ( index ,
clauses ,
outer_clauses ,
outer_relids ) ;
outer_relids ,
& found_clause ) ;
/*
* Not all index AMs support scans with no restriction clauses .
* We can ' t generate a scan over an index with amoptionalkey = false
* unless there ' s at least one restriction clause .
*/
if ( restrictclauses = = NIL & & ! index - > amoptionalkey )
continue ;
/*
* 2. Compute pathkeys describing index ' s ordering , if any , then
@ -300,20 +335,12 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
/*
* 3. Generate an indexscan path if there are relevant restriction
* clauses OR the index ordering is potentially useful for later
* merging or final output ordering .
*
* If there is a predicate , consider it anyway since the index
* predicate has already been found to match the query . The
* selectivity of the predicate might alone make the index useful .
*
* Note : not all index AMs support scans with no restriction clauses .
* We can ' t generate a scan over an index with amoptionalkey = false
* unless there ' s at least one restriction clause .
* clauses in the current clauses , OR the index ordering is
* potentially useful for later merging or final output ordering ,
* OR the index has a predicate that was proven by the current
* clauses .
*/
if ( restrictclauses ! = NIL | |
( index - > amoptionalkey & &
( useful_pathkeys ! = NIL | | index - > indpred ! = NIL ) ) )
if ( found_clause | | useful_pathkeys ! = NIL | | useful_predicate )
{
ipath = create_index_path ( root , index ,
restrictclauses ,
@ -627,10 +654,9 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
* with one index key ( in no particular order ) ; the top list is ordered by
* index key . ( This is depended on by expand_indexqual_conditions ( ) . )
*
* As explained in the comments for find_usable_indexes ( ) , we can use
* clauses from either of the given lists , but the result is required to
* use at least one clause from the " current clauses " list . We return
* NIL if we don ' t find any such clause .
* We can use clauses from either the current clauses or outer_clauses lists ,
* but * found_clause is set TRUE only if we used at least one clause from
* the " current clauses " list . See find_usable_indexes ( ) for motivation .
*
* outer_relids determines what Vars will be allowed on the other side
* of a possible index qual ; see match_clause_to_indexcol ( ) .
@ -643,18 +669,25 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
* Example : given an index on ( A , B , C ) , we would return ( ( C1 C2 ) ( ) ( C3 C4 ) )
* if we find that clauses C1 and C2 use column A , clauses C3 and C4 use
* column C , and no clauses use column B .
*
* Note : in some circumstances we may find the same RestrictInfos coming
* from multiple places . Defend against redundant outputs by using
* list_append_unique_ptr ( pointer equality should be good enough ) .
*/
List *
group_clauses_by_indexkey ( IndexOptInfo * index ,
List * clauses , List * outer_clauses ,
Relids outer_relids )
Relids outer_relids ,
bool * found_clause )
{
List * clausegroup_list = NIL ;
bool found_clause = false ;
bool found_outer_ clause = false ;
int indexcol = 0 ;
Oid * classes = index - > classlist ;
if ( clauses = = NIL )
* found_clause = false ; /* default result */
if ( clauses = = NIL & & outer_clauses = = NIL )
return NIL ; /* cannot succeed */
do
@ -675,8 +708,8 @@ group_clauses_by_indexkey(IndexOptInfo *index,
rinfo ,
outer_relids ) )
{
clausegroup = lappend ( clausegroup , rinfo ) ;
found_clause = true ;
clausegroup = list_ append_unique_ptr ( clausegroup , rinfo ) ;
* found_clause = true ;
}
}
@ -691,7 +724,10 @@ group_clauses_by_indexkey(IndexOptInfo *index,
curClass ,
rinfo ,
outer_relids ) )
clausegroup = lappend ( clausegroup , rinfo ) ;
{
clausegroup = list_append_unique_ptr ( clausegroup , rinfo ) ;
found_outer_clause = true ;
}
}
/*
@ -707,8 +743,8 @@ group_clauses_by_indexkey(IndexOptInfo *index,
} while ( ! DoneMatchingIndexKeys ( classes ) ) ;
if ( ! found_clause )
return NIL ;
if ( ! * found_clause & & ! found_outer _clause )
return NIL ; /* no indexable clauses anywhere */
return clausegroup_list ;
}