@ -45,14 +45,6 @@
# define IndexCollMatchesExprColl(idxcollation, exprcollation) \
# define IndexCollMatchesExprColl(idxcollation, exprcollation) \
( ( idxcollation ) = = InvalidOid | | ( idxcollation ) = = ( exprcollation ) )
( ( idxcollation ) = = InvalidOid | | ( idxcollation ) = = ( exprcollation ) )
/* Whether to use ScalarArrayOpExpr to build index qualifications */
typedef enum
{
SAOP_PER_AM , /* Use ScalarArrayOpExpr if amsearcharray */
SAOP_ALLOW , /* Use ScalarArrayOpExpr for all indexes */
SAOP_REQUIRE /* Require ScalarArrayOpExpr to be used */
} SaOpControl ;
/* Whether we are looking for plain indexscan, bitmap scan, or either */
/* Whether we are looking for plain indexscan, bitmap scan, or either */
typedef enum
typedef enum
{
{
@ -118,7 +110,9 @@ static void get_index_paths(PlannerInfo *root, RelOptInfo *rel,
static List * build_index_paths ( PlannerInfo * root , RelOptInfo * rel ,
static List * build_index_paths ( PlannerInfo * root , RelOptInfo * rel ,
IndexOptInfo * index , IndexClauseSet * clauses ,
IndexOptInfo * index , IndexClauseSet * clauses ,
bool useful_predicate ,
bool useful_predicate ,
SaOpControl saop_control , ScanTypeControl scantype ) ;
ScanTypeControl scantype ,
bool * skip_nonnative_saop ,
bool * skip_lower_saop ) ;
static List * build_paths_for_OR ( PlannerInfo * root , RelOptInfo * rel ,
static List * build_paths_for_OR ( PlannerInfo * root , RelOptInfo * rel ,
List * clauses , List * other_clauses ) ;
List * clauses , List * other_clauses ) ;
static List * generate_bitmap_or_paths ( PlannerInfo * root , RelOptInfo * rel ,
static List * generate_bitmap_or_paths ( PlannerInfo * root , RelOptInfo * rel ,
@ -726,6 +720,8 @@ bms_equal_any(Relids relids, List *relids_list)
* index AM supports them natively , we should just include them in simple
* index AM supports them natively , we should just include them in simple
* index paths . If not , we should exclude them while building simple index
* index paths . If not , we should exclude them while building simple index
* paths , and then make a separate attempt to include them in bitmap paths .
* paths , and then make a separate attempt to include them in bitmap paths .
* Furthermore , we should consider excluding lower - order ScalarArrayOpExpr
* quals so as to create ordered paths .
*/
*/
static void
static void
get_index_paths ( PlannerInfo * root , RelOptInfo * rel ,
get_index_paths ( PlannerInfo * root , RelOptInfo * rel ,
@ -733,16 +729,38 @@ get_index_paths(PlannerInfo *root, RelOptInfo *rel,
List * * bitindexpaths )
List * * bitindexpaths )
{
{
List * indexpaths ;
List * indexpaths ;
bool skip_nonnative_saop = false ;
bool skip_lower_saop = false ;
ListCell * lc ;
ListCell * lc ;
/*
/*
* Build simple index paths using the clauses . Allow ScalarArrayOpExpr
* Build simple index paths using the clauses . Allow ScalarArrayOpExpr
* clauses only if the index AM supports them natively .
* clauses only if the index AM supports them natively , and skip any such
* clauses for index columns after the first ( so that we produce ordered
* paths if possible ) .
*/
*/
indexpaths = build_index_paths ( root , rel ,
indexpaths = build_index_paths ( root , rel ,
index , clauses ,
index , clauses ,
index - > predOK ,
index - > predOK ,
SAOP_PER_AM , ST_ANYSCAN ) ;
ST_ANYSCAN ,
& skip_nonnative_saop ,
& skip_lower_saop ) ;
/*
* If we skipped any lower - order ScalarArrayOpExprs on an index with an AM
* that supports them , then try again including those clauses . This will
* produce paths with more selectivity but no ordering .
*/
if ( skip_lower_saop )
{
indexpaths = list_concat ( indexpaths ,
build_index_paths ( root , rel ,
index , clauses ,
index - > predOK ,
ST_ANYSCAN ,
& skip_nonnative_saop ,
NULL ) ) ;
}
/*
/*
* Submit all the ones that can form plain IndexScan plans to add_path . ( A
* Submit all the ones that can form plain IndexScan plans to add_path . ( A
@ -770,16 +788,18 @@ get_index_paths(PlannerInfo *root, RelOptInfo *rel,
}
}
/*
/*
* If the index doesn ' t handle ScalarArrayOpExpr clauses natively , check
* If there were ScalarArrayOpExpr clauses that the index can ' t handle
* to see if there are any such clauses , and if so generate bitmap scan
* natively , generate bitmap scan paths relying on executor - managed
* paths relying on executor - managed ScalarArrayOpExpr .
* ScalarArrayOpExpr .
*/
*/
if ( ! index - > amsearcharray )
if ( skip_nonnative_saop )
{
{
indexpaths = build_index_paths ( root , rel ,
indexpaths = build_index_paths ( root , rel ,
index , clauses ,
index , clauses ,
false ,
false ,
SAOP_REQUIRE , ST_BITMAPSCAN ) ;
ST_BITMAPSCAN ,
NULL ,
NULL ) ;
* bitindexpaths = list_concat ( * bitindexpaths , indexpaths ) ;
* bitindexpaths = list_concat ( * bitindexpaths , indexpaths ) ;
}
}
}
}
@ -802,26 +822,36 @@ get_index_paths(PlannerInfo *root, RelOptInfo *rel,
* Note that this routine should never be called at all if the index has an
* Note that this routine should never be called at all if the index has an
* unprovable predicate .
* unprovable predicate .
*
*
* saop_control indicates whether ScalarArrayOpExpr clauses can be used .
* When it ' s SAOP_REQUIRE , index paths are created only if we found at least
* one ScalarArrayOpExpr clause .
*
* scantype indicates whether we want to create plain indexscans , bitmap
* scantype indicates whether we want to create plain indexscans , bitmap
* indexscans , or both . When it ' s ST_BITMAPSCAN , we will not consider
* indexscans , or both . When it ' s ST_BITMAPSCAN , we will not consider
* index ordering while deciding if a Path is worth generating .
* index ordering while deciding if a Path is worth generating .
*
*
* If skip_nonnative_saop is non - NULL , we ignore ScalarArrayOpExpr clauses
* unless the index AM supports them directly , and we set * skip_nonnative_saop
* to TRUE if we found any such clauses ( caller must initialize the variable
* to FALSE ) . If it ' s NULL , we do not ignore ScalarArrayOpExpr clauses .
*
* If skip_lower_saop is non - NULL , we ignore ScalarArrayOpExpr clauses for
* non - first index columns , and we set * skip_lower_saop to TRUE if we found
* any such clauses ( caller must initialize the variable to FALSE ) . If it ' s
* NULL , we do not ignore non - first ScalarArrayOpExpr clauses , but they will
* result in considering the scan ' s output to be unordered .
*
* ' rel ' is the index ' s heap relation
* ' rel ' is the index ' s heap relation
* ' index ' is the index for which we want to generate paths
* ' index ' is the index for which we want to generate paths
* ' clauses ' is the collection of indexable clauses ( RestrictInfo nodes )
* ' clauses ' is the collection of indexable clauses ( RestrictInfo nodes )
* ' useful_predicate ' indicates whether the index has a useful predicate
* ' useful_predicate ' indicates whether the index has a useful predicate
* ' saop_control ' indicates whether ScalarArrayOpExpr clauses can be used
* ' scantype ' indicates whether we need plain or bitmap scan support
* ' scantype ' indicates whether we need plain or bitmap scan support
* ' skip_nonnative_saop ' indicates whether to accept SAOP if index AM doesn ' t
* ' skip_lower_saop ' indicates whether to accept non - first - column SAOP
*/
*/
static List *
static List *
build_index_paths ( PlannerInfo * root , RelOptInfo * rel ,
build_index_paths ( PlannerInfo * root , RelOptInfo * rel ,
IndexOptInfo * index , IndexClauseSet * clauses ,
IndexOptInfo * index , IndexClauseSet * clauses ,
bool useful_predicate ,
bool useful_predicate ,
SaOpControl saop_control , ScanTypeControl scantype )
ScanTypeControl scantype ,
bool * skip_nonnative_saop ,
bool * skip_lower_saop )
{
{
List * result = NIL ;
List * result = NIL ;
IndexPath * ipath ;
IndexPath * ipath ;
@ -833,7 +863,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
List * orderbyclausecols ;
List * orderbyclausecols ;
List * index_pathkeys ;
List * index_pathkeys ;
List * useful_pathkeys ;
List * useful_pathkeys ;
bool found_clause ;
bool found_lower_saop_clause ;
bool found_lower_saop_clause ;
bool pathkeys_possibly_useful ;
bool pathkeys_possibly_useful ;
bool index_is_ordered ;
bool index_is_ordered ;
@ -868,11 +897,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
* ( This order is depended on by btree and possibly other places . ) The
* ( This order is depended on by btree and possibly other places . ) The
* lists can be empty , if the index AM allows that .
* lists can be empty , if the index AM allows that .
*
*
* found_clause is set true only if there ' s at least one index clause ; and
* found_lower_saop_clause is set true if we accept a ScalarArrayOpExpr
* if saop_control is SAOP_REQUIRE , it has to be a ScalarArrayOpExpr
* clause .
*
* found_lower_saop_clause is set true if there ' s a ScalarArrayOpExpr
* index clause for a non - first index column . This prevents us from
* index clause for a non - first index column . This prevents us from
* assuming that the scan result is ordered . ( Actually , the result is
* assuming that the scan result is ordered . ( Actually , the result is
* still ordered if there are equality constraints for all earlier
* still ordered if there are equality constraints for all earlier
@ -885,7 +910,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
*/
*/
index_clauses = NIL ;
index_clauses = NIL ;
clause_columns = NIL ;
clause_columns = NIL ;
found_clause = false ;
found_lower_saop_clause = false ;
found_lower_saop_clause = false ;
outer_relids = bms_copy ( rel - > lateral_relids ) ;
outer_relids = bms_copy ( rel - > lateral_relids ) ;
for ( indexcol = 0 ; indexcol < index - > ncolumns ; indexcol + + )
for ( indexcol = 0 ; indexcol < index - > ncolumns ; indexcol + + )
@ -898,17 +922,27 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
if ( IsA ( rinfo - > clause , ScalarArrayOpExpr ) )
if ( IsA ( rinfo - > clause , ScalarArrayOpExpr ) )
{
{
/* Ignore if not supported by index */
if ( ! index - > amsearcharray )
if ( saop_control = = SAOP_PER_AM & & ! index - > amsearcharray )
{
continue ;
if ( skip_nonnative_saop )
found_clause = true ;
{
/* Ignore because not supported by index */
* skip_nonnative_saop = true ;
continue ;
}
/* Caller had better intend this only for bitmap scan */
Assert ( scantype = = ST_BITMAPSCAN ) ;
}
if ( indexcol > 0 )
if ( indexcol > 0 )
{
if ( skip_lower_saop )
{
/* Caller doesn't want to lose index ordering */
* skip_lower_saop = true ;
continue ;
}
found_lower_saop_clause = true ;
found_lower_saop_clause = true ;
}
}
else
{
if ( saop_control ! = SAOP_REQUIRE )
found_clause = true ;
}
}
index_clauses = lappend ( index_clauses , rinfo ) ;
index_clauses = lappend ( index_clauses , rinfo ) ;
clause_columns = lappend_int ( clause_columns , indexcol ) ;
clause_columns = lappend_int ( clause_columns , indexcol ) ;
@ -988,7 +1022,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
* later merging or final output ordering , OR the index has a useful
* later merging or final output ordering , OR the index has a useful
* predicate , OR an index - only scan is possible .
* predicate , OR an index - only scan is possible .
*/
*/
if ( found_clause | | useful_pathkeys ! = NIL | | useful_predicate | |
if ( index_clauses ! = NIL | | useful_pathkeys ! = NIL | | useful_predicate | |
index_only_scan )
index_only_scan )
{
{
ipath = create_index_path ( root , index ,
ipath = create_index_path ( root , index ,
@ -1137,7 +1171,9 @@ build_paths_for_OR(PlannerInfo *root, RelOptInfo *rel,
indexpaths = build_index_paths ( root , rel ,
indexpaths = build_index_paths ( root , rel ,
index , & clauseset ,
index , & clauseset ,
useful_predicate ,
useful_predicate ,
SAOP_ALLOW , ST_BITMAPSCAN ) ;
ST_BITMAPSCAN ,
NULL ,
NULL ) ;
result = list_concat ( result , indexpaths ) ;
result = list_concat ( result , indexpaths ) ;
}
}