45
45
#define IndexCollMatchesExprColl (idxcollation , exprcollation ) \
46
46
((idxcollation) == InvalidOid || (idxcollation) == (exprcollation))
47
47
48
- /* Whether to use ScalarArrayOpExpr to build index qualifications */
49
- typedef enum
50
- {
51
- SAOP_PER_AM , /* Use ScalarArrayOpExpr if amsearcharray */
52
- SAOP_ALLOW , /* Use ScalarArrayOpExpr for all indexes */
53
- SAOP_REQUIRE /* Require ScalarArrayOpExpr to be used */
54
- } SaOpControl ;
55
-
56
48
/* Whether we are looking for plain indexscan, bitmap scan, or either */
57
49
typedef enum
58
50
{
@@ -118,7 +110,9 @@ static void get_index_paths(PlannerInfo *root, RelOptInfo *rel,
118
110
static List * build_index_paths (PlannerInfo * root , RelOptInfo * rel ,
119
111
IndexOptInfo * index , IndexClauseSet * clauses ,
120
112
bool useful_predicate ,
121
- SaOpControl saop_control , ScanTypeControl scantype );
113
+ ScanTypeControl scantype ,
114
+ bool * skip_nonnative_saop ,
115
+ bool * skip_lower_saop );
122
116
static List * build_paths_for_OR (PlannerInfo * root , RelOptInfo * rel ,
123
117
List * clauses , List * other_clauses );
124
118
static List * drop_indexable_join_clauses (RelOptInfo * rel , List * clauses );
@@ -727,23 +721,47 @@ bms_equal_any(Relids relids, List *relids_list)
727
721
* index AM supports them natively, we should just include them in simple
728
722
* index paths. If not, we should exclude them while building simple index
729
723
* paths, and then make a separate attempt to include them in bitmap paths.
724
+ * Furthermore, we should consider excluding lower-order ScalarArrayOpExpr
725
+ * quals so as to create ordered paths.
730
726
*/
731
727
static void
732
728
get_index_paths (PlannerInfo * root , RelOptInfo * rel ,
733
729
IndexOptInfo * index , IndexClauseSet * clauses ,
734
730
List * * bitindexpaths )
735
731
{
736
732
List * indexpaths ;
733
+ bool skip_nonnative_saop = false;
734
+ bool skip_lower_saop = false;
737
735
ListCell * lc ;
738
736
739
737
/*
740
738
* Build simple index paths using the clauses. Allow ScalarArrayOpExpr
741
- * clauses only if the index AM supports them natively.
739
+ * clauses only if the index AM supports them natively, and skip any such
740
+ * clauses for index columns after the first (so that we produce ordered
741
+ * paths if possible).
742
742
*/
743
743
indexpaths = build_index_paths (root , rel ,
744
744
index , clauses ,
745
745
index -> predOK ,
746
- SAOP_PER_AM , ST_ANYSCAN );
746
+ ST_ANYSCAN ,
747
+ & skip_nonnative_saop ,
748
+ & skip_lower_saop );
749
+
750
+ /*
751
+ * If we skipped any lower-order ScalarArrayOpExprs on an index with an AM
752
+ * that supports them, then try again including those clauses. This will
753
+ * produce paths with more selectivity but no ordering.
754
+ */
755
+ if (skip_lower_saop )
756
+ {
757
+ indexpaths = list_concat (indexpaths ,
758
+ build_index_paths (root , rel ,
759
+ index , clauses ,
760
+ index -> predOK ,
761
+ ST_ANYSCAN ,
762
+ & skip_nonnative_saop ,
763
+ NULL ));
764
+ }
747
765
748
766
/*
749
767
* Submit all the ones that can form plain IndexScan plans to add_path. (A
@@ -771,16 +789,18 @@ get_index_paths(PlannerInfo *root, RelOptInfo *rel,
771
789
}
772
790
773
791
/*
774
- * If the index doesn 't handle ScalarArrayOpExpr clauses natively, check
775
- * to see if there are any such clauses, and if so generate bitmap scan
776
- * paths relying on executor-managed ScalarArrayOpExpr.
792
+ * If there were ScalarArrayOpExpr clauses that the index can 't handle
793
+ * natively, generate bitmap scan paths relying on executor-managed
794
+ * ScalarArrayOpExpr.
777
795
*/
778
- if (! index -> amsearcharray )
796
+ if (skip_nonnative_saop )
779
797
{
780
798
indexpaths = build_index_paths (root , rel ,
781
799
index , clauses ,
782
800
false,
783
- SAOP_REQUIRE , ST_BITMAPSCAN );
801
+ ST_BITMAPSCAN ,
802
+ NULL ,
803
+ NULL );
784
804
* bitindexpaths = list_concat (* bitindexpaths , indexpaths );
785
805
}
786
806
}
@@ -803,26 +823,36 @@ get_index_paths(PlannerInfo *root, RelOptInfo *rel,
803
823
* Note that this routine should never be called at all if the index has an
804
824
* unprovable predicate.
805
825
*
806
- * saop_control indicates whether ScalarArrayOpExpr clauses can be used.
807
- * When it's SAOP_REQUIRE, index paths are created only if we found at least
808
- * one ScalarArrayOpExpr clause.
809
- *
810
826
* scantype indicates whether we want to create plain indexscans, bitmap
811
827
* indexscans, or both. When it's ST_BITMAPSCAN, we will not consider
812
828
* index ordering while deciding if a Path is worth generating.
813
829
*
830
+ * If skip_nonnative_saop is non-NULL, we ignore ScalarArrayOpExpr clauses
831
+ * unless the index AM supports them directly, and we set *skip_nonnative_saop
832
+ * to TRUE if we found any such clauses (caller must initialize the variable
833
+ * to FALSE). If it's NULL, we do not ignore ScalarArrayOpExpr clauses.
834
+ *
835
+ * If skip_lower_saop is non-NULL, we ignore ScalarArrayOpExpr clauses for
836
+ * non-first index columns, and we set *skip_lower_saop to TRUE if we found
837
+ * any such clauses (caller must initialize the variable to FALSE). If it's
838
+ * NULL, we do not ignore non-first ScalarArrayOpExpr clauses, but they will
839
+ * result in considering the scan's output to be unordered.
840
+ *
814
841
* 'rel' is the index's heap relation
815
842
* 'index' is the index for which we want to generate paths
816
843
* 'clauses' is the collection of indexable clauses (RestrictInfo nodes)
817
844
* 'useful_predicate' indicates whether the index has a useful predicate
818
- * 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used
819
845
* 'scantype' indicates whether we need plain or bitmap scan support
846
+ * 'skip_nonnative_saop' indicates whether to accept SAOP if index AM doesn't
847
+ * 'skip_lower_saop' indicates whether to accept non-first-column SAOP
820
848
*/
821
849
static List *
822
850
build_index_paths (PlannerInfo * root , RelOptInfo * rel ,
823
851
IndexOptInfo * index , IndexClauseSet * clauses ,
824
852
bool useful_predicate ,
825
- SaOpControl saop_control , ScanTypeControl scantype )
853
+ ScanTypeControl scantype ,
854
+ bool * skip_nonnative_saop ,
855
+ bool * skip_lower_saop )
826
856
{
827
857
List * result = NIL ;
828
858
IndexPath * ipath ;
@@ -834,7 +864,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
834
864
List * orderbyclausecols ;
835
865
List * index_pathkeys ;
836
866
List * useful_pathkeys ;
837
- bool found_clause ;
838
867
bool found_lower_saop_clause ;
839
868
bool pathkeys_possibly_useful ;
840
869
bool index_is_ordered ;
@@ -869,11 +898,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
869
898
* (This order is depended on by btree and possibly other places.) The
870
899
* lists can be empty, if the index AM allows that.
871
900
*
872
- * found_clause is set true only if there's at least one index clause; and
873
- * if saop_control is SAOP_REQUIRE, it has to be a ScalarArrayOpExpr
874
- * clause.
875
- *
876
- * found_lower_saop_clause is set true if there's a ScalarArrayOpExpr
901
+ * found_lower_saop_clause is set true if we accept a ScalarArrayOpExpr
877
902
* index clause for a non-first index column. This prevents us from
878
903
* assuming that the scan result is ordered. (Actually, the result is
879
904
* still ordered if there are equality constraints for all earlier
@@ -886,7 +911,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
886
911
*/
887
912
index_clauses = NIL ;
888
913
clause_columns = NIL ;
889
- found_clause = false;
890
914
found_lower_saop_clause = false;
891
915
outer_relids = bms_copy (rel -> lateral_relids );
892
916
for (indexcol = 0 ; indexcol < index -> ncolumns ; indexcol ++ )
@@ -899,17 +923,27 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
899
923
900
924
if (IsA (rinfo -> clause , ScalarArrayOpExpr ))
901
925
{
902
- /* Ignore if not supported by index */
903
- if (saop_control == SAOP_PER_AM && !index -> amsearcharray )
904
- continue ;
905
- found_clause = true;
926
+ if (!index -> amsearcharray )
927
+ {
928
+ if (skip_nonnative_saop )
929
+ {
930
+ /* Ignore because not supported by index */
931
+ * skip_nonnative_saop = true;
932
+ continue ;
933
+ }
934
+ /* Caller had better intend this only for bitmap scan */
935
+ Assert (scantype == ST_BITMAPSCAN );
936
+ }
906
937
if (indexcol > 0 )
938
+ {
939
+ if (skip_lower_saop )
940
+ {
941
+ /* Caller doesn't want to lose index ordering */
942
+ * skip_lower_saop = true;
943
+ continue ;
944
+ }
907
945
found_lower_saop_clause = true;
908
- }
909
- else
910
- {
911
- if (saop_control != SAOP_REQUIRE )
912
- found_clause = true;
946
+ }
913
947
}
914
948
index_clauses = lappend (index_clauses , rinfo );
915
949
clause_columns = lappend_int (clause_columns , indexcol );
@@ -989,7 +1023,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
989
1023
* later merging or final output ordering, OR the index has a useful
990
1024
* predicate, OR an index-only scan is possible.
991
1025
*/
992
- if (found_clause || useful_pathkeys != NIL || useful_predicate ||
1026
+ if (index_clauses != NIL || useful_pathkeys != NIL || useful_predicate ||
993
1027
index_only_scan )
994
1028
{
995
1029
ipath = create_index_path (root , index ,
@@ -1138,7 +1172,9 @@ build_paths_for_OR(PlannerInfo *root, RelOptInfo *rel,
1138
1172
indexpaths = build_index_paths (root , rel ,
1139
1173
index , & clauseset ,
1140
1174
useful_predicate ,
1141
- SAOP_ALLOW , ST_BITMAPSCAN );
1175
+ ST_BITMAPSCAN ,
1176
+ NULL ,
1177
+ NULL );
1142
1178
result = list_concat (result , indexpaths );
1143
1179
}
1144
1180
0 commit comments