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