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
{
@@ -111,7 +103,9 @@ static void get_index_paths(PlannerInfo *root, RelOptInfo *rel,
111
103
static List * build_index_paths (PlannerInfo * root , RelOptInfo * rel ,
112
104
IndexOptInfo * index , IndexClauseSet * clauses ,
113
105
bool useful_predicate ,
114
- SaOpControl saop_control , ScanTypeControl scantype );
106
+ ScanTypeControl scantype ,
107
+ bool * skip_nonnative_saop ,
108
+ bool * skip_lower_saop );
115
109
static List * build_paths_for_OR (PlannerInfo * root , RelOptInfo * rel ,
116
110
List * clauses , List * other_clauses );
117
111
static List * drop_indexable_join_clauses (RelOptInfo * rel , List * clauses );
@@ -706,23 +700,47 @@ bms_equal_any(Relids relids, List *relids_list)
706
700
* index AM supports them natively, we should just include them in simple
707
701
* index paths. If not, we should exclude them while building simple index
708
702
* paths, and then make a separate attempt to include them in bitmap paths.
703
+ * Furthermore, we should consider excluding lower-order ScalarArrayOpExpr
704
+ * quals so as to create ordered paths.
709
705
*/
710
706
static void
711
707
get_index_paths (PlannerInfo * root , RelOptInfo * rel ,
712
708
IndexOptInfo * index , IndexClauseSet * clauses ,
713
709
List * * bitindexpaths )
714
710
{
715
711
List * indexpaths ;
712
+ bool skip_nonnative_saop = false;
713
+ bool skip_lower_saop = false;
716
714
ListCell * lc ;
717
715
718
716
/*
719
717
* Build simple index paths using the clauses. Allow ScalarArrayOpExpr
720
- * clauses only if the index AM supports them natively.
718
+ * clauses only if the index AM supports them natively, and skip any such
719
+ * clauses for index columns after the first (so that we produce ordered
720
+ * paths if possible).
721
721
*/
722
722
indexpaths = build_index_paths (root , rel ,
723
723
index , clauses ,
724
724
index -> predOK ,
725
- SAOP_PER_AM , ST_ANYSCAN );
725
+ ST_ANYSCAN ,
726
+ & skip_nonnative_saop ,
727
+ & skip_lower_saop );
728
+
729
+ /*
730
+ * If we skipped any lower-order ScalarArrayOpExprs on an index with an AM
731
+ * that supports them, then try again including those clauses. This will
732
+ * produce paths with more selectivity but no ordering.
733
+ */
734
+ if (skip_lower_saop )
735
+ {
736
+ indexpaths = list_concat (indexpaths ,
737
+ build_index_paths (root , rel ,
738
+ index , clauses ,
739
+ index -> predOK ,
740
+ ST_ANYSCAN ,
741
+ & skip_nonnative_saop ,
742
+ NULL ));
743
+ }
726
744
727
745
/*
728
746
* Submit all the ones that can form plain IndexScan plans to add_path. (A
@@ -750,16 +768,18 @@ get_index_paths(PlannerInfo *root, RelOptInfo *rel,
750
768
}
751
769
752
770
/*
753
- * If the index doesn 't handle ScalarArrayOpExpr clauses natively, check
754
- * to see if there are any such clauses, and if so generate bitmap scan
755
- * paths relying on executor-managed ScalarArrayOpExpr.
771
+ * If there were ScalarArrayOpExpr clauses that the index can 't handle
772
+ * natively, generate bitmap scan paths relying on executor-managed
773
+ * ScalarArrayOpExpr.
756
774
*/
757
- if (! index -> amsearcharray )
775
+ if (skip_nonnative_saop )
758
776
{
759
777
indexpaths = build_index_paths (root , rel ,
760
778
index , clauses ,
761
779
false,
762
- SAOP_REQUIRE , ST_BITMAPSCAN );
780
+ ST_BITMAPSCAN ,
781
+ NULL ,
782
+ NULL );
763
783
* bitindexpaths = list_concat (* bitindexpaths , indexpaths );
764
784
}
765
785
}
@@ -782,26 +802,36 @@ get_index_paths(PlannerInfo *root, RelOptInfo *rel,
782
802
* Note that this routine should never be called at all if the index has an
783
803
* unprovable predicate.
784
804
*
785
- * saop_control indicates whether ScalarArrayOpExpr clauses can be used.
786
- * When it's SAOP_REQUIRE, index paths are created only if we found at least
787
- * one ScalarArrayOpExpr clause.
788
- *
789
805
* scantype indicates whether we want to create plain indexscans, bitmap
790
806
* indexscans, or both. When it's ST_BITMAPSCAN, we will not consider
791
807
* index ordering while deciding if a Path is worth generating.
792
808
*
809
+ * If skip_nonnative_saop is non-NULL, we ignore ScalarArrayOpExpr clauses
810
+ * unless the index AM supports them directly, and we set *skip_nonnative_saop
811
+ * to TRUE if we found any such clauses (caller must initialize the variable
812
+ * to FALSE). If it's NULL, we do not ignore ScalarArrayOpExpr clauses.
813
+ *
814
+ * If skip_lower_saop is non-NULL, we ignore ScalarArrayOpExpr clauses for
815
+ * non-first index columns, and we set *skip_lower_saop to TRUE if we found
816
+ * any such clauses (caller must initialize the variable to FALSE). If it's
817
+ * NULL, we do not ignore non-first ScalarArrayOpExpr clauses, but they will
818
+ * result in considering the scan's output to be unordered.
819
+ *
793
820
* 'rel' is the index's heap relation
794
821
* 'index' is the index for which we want to generate paths
795
822
* 'clauses' is the collection of indexable clauses (RestrictInfo nodes)
796
823
* 'useful_predicate' indicates whether the index has a useful predicate
797
- * 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used
798
824
* 'scantype' indicates whether we need plain or bitmap scan support
825
+ * 'skip_nonnative_saop' indicates whether to accept SAOP if index AM doesn't
826
+ * 'skip_lower_saop' indicates whether to accept non-first-column SAOP
799
827
*/
800
828
static List *
801
829
build_index_paths (PlannerInfo * root , RelOptInfo * rel ,
802
830
IndexOptInfo * index , IndexClauseSet * clauses ,
803
831
bool useful_predicate ,
804
- SaOpControl saop_control , ScanTypeControl scantype )
832
+ ScanTypeControl scantype ,
833
+ bool * skip_nonnative_saop ,
834
+ bool * skip_lower_saop )
805
835
{
806
836
List * result = NIL ;
807
837
IndexPath * ipath ;
@@ -813,7 +843,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
813
843
List * orderbyclausecols ;
814
844
List * index_pathkeys ;
815
845
List * useful_pathkeys ;
816
- bool found_clause ;
817
846
bool found_lower_saop_clause ;
818
847
bool pathkeys_possibly_useful ;
819
848
bool index_is_ordered ;
@@ -848,11 +877,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
848
877
* (This order is depended on by btree and possibly other places.) The
849
878
* lists can be empty, if the index AM allows that.
850
879
*
851
- * found_clause is set true only if there's at least one index clause; and
852
- * if saop_control is SAOP_REQUIRE, it has to be a ScalarArrayOpExpr
853
- * clause.
854
- *
855
- * found_lower_saop_clause is set true if there's a ScalarArrayOpExpr
880
+ * found_lower_saop_clause is set true if we accept a ScalarArrayOpExpr
856
881
* index clause for a non-first index column. This prevents us from
857
882
* assuming that the scan result is ordered. (Actually, the result is
858
883
* still ordered if there are equality constraints for all earlier
@@ -864,7 +889,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
864
889
*/
865
890
index_clauses = NIL ;
866
891
clause_columns = NIL ;
867
- found_clause = false;
868
892
found_lower_saop_clause = false;
869
893
outer_relids = NULL ;
870
894
for (indexcol = 0 ; indexcol < index -> ncolumns ; indexcol ++ )
@@ -877,17 +901,27 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
877
901
878
902
if (IsA (rinfo -> clause , ScalarArrayOpExpr ))
879
903
{
880
- /* Ignore if not supported by index */
881
- if (saop_control == SAOP_PER_AM && !index -> amsearcharray )
882
- continue ;
883
- found_clause = true;
904
+ if (!index -> amsearcharray )
905
+ {
906
+ if (skip_nonnative_saop )
907
+ {
908
+ /* Ignore because not supported by index */
909
+ * skip_nonnative_saop = true;
910
+ continue ;
911
+ }
912
+ /* Caller had better intend this only for bitmap scan */
913
+ Assert (scantype == ST_BITMAPSCAN );
914
+ }
884
915
if (indexcol > 0 )
916
+ {
917
+ if (skip_lower_saop )
918
+ {
919
+ /* Caller doesn't want to lose index ordering */
920
+ * skip_lower_saop = true;
921
+ continue ;
922
+ }
885
923
found_lower_saop_clause = true;
886
- }
887
- else
888
- {
889
- if (saop_control != SAOP_REQUIRE )
890
- found_clause = true;
924
+ }
891
925
}
892
926
index_clauses = lappend (index_clauses , rinfo );
893
927
clause_columns = lappend_int (clause_columns , indexcol );
@@ -967,7 +1001,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
967
1001
* later merging or final output ordering, OR the index has a useful
968
1002
* predicate, OR an index-only scan is possible.
969
1003
*/
970
- if (found_clause || useful_pathkeys != NIL || useful_predicate ||
1004
+ if (index_clauses != NIL || useful_pathkeys != NIL || useful_predicate ||
971
1005
index_only_scan )
972
1006
{
973
1007
ipath = create_index_path (root , index ,
@@ -1116,7 +1150,9 @@ build_paths_for_OR(PlannerInfo *root, RelOptInfo *rel,
1116
1150
indexpaths = build_index_paths (root , rel ,
1117
1151
index , & clauseset ,
1118
1152
useful_predicate ,
1119
- SAOP_ALLOW , ST_BITMAPSCAN );
1153
+ ST_BITMAPSCAN ,
1154
+ NULL ,
1155
+ NULL );
1120
1156
result = list_concat (result , indexpaths );
1121
1157
}
1122
1158
0 commit comments