4545#define IndexCollMatchesExprColl (idxcollation ,exprcollation ) \
4646((idxcollation) == InvalidOid || (idxcollation) == (exprcollation))
4747
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-
5648/* Whether we are looking for plain indexscan, bitmap scan, or either */
5749typedef enum
5850{
@@ -111,7 +103,9 @@ static void get_index_paths(PlannerInfo *root, RelOptInfo *rel,
111103static List * build_index_paths (PlannerInfo * root ,RelOptInfo * rel ,
112104IndexOptInfo * index ,IndexClauseSet * clauses ,
113105bool useful_predicate ,
114- SaOpControl saop_control ,ScanTypeControl scantype );
106+ ScanTypeControl scantype ,
107+ bool * skip_nonnative_saop ,
108+ bool * skip_lower_saop );
115109static List * build_paths_for_OR (PlannerInfo * root ,RelOptInfo * rel ,
116110List * clauses ,List * other_clauses );
117111static List * drop_indexable_join_clauses (RelOptInfo * rel ,List * clauses );
@@ -706,23 +700,47 @@ bms_equal_any(Relids relids, List *relids_list)
706700 * index AM supports them natively, we should just include them in simple
707701 * index paths. If not, we should exclude them while building simple index
708702 * 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.
709705 */
710706static void
711707get_index_paths (PlannerInfo * root ,RelOptInfo * rel ,
712708IndexOptInfo * index ,IndexClauseSet * clauses ,
713709List * * bitindexpaths )
714710{
715711List * indexpaths ;
712+ bool skip_nonnative_saop = false;
713+ bool skip_lower_saop = false;
716714ListCell * lc ;
717715
718716/*
719717 * 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).
721721 */
722722indexpaths = build_index_paths (root ,rel ,
723723index ,clauses ,
724724index -> 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+ }
726744
727745/*
728746 * 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,
750768}
751769
752770/*
753- * If the indexdoesn '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+ * Ifthere were ScalarArrayOpExpr clauses that the indexcan 't handle
772+ *natively, generate bitmap scan paths relying on executor-managed
773+ * ScalarArrayOpExpr.
756774 */
757- if (! index -> amsearcharray )
775+ if (skip_nonnative_saop )
758776{
759777indexpaths = build_index_paths (root ,rel ,
760778index ,clauses ,
761779 false,
762- SAOP_REQUIRE ,ST_BITMAPSCAN );
780+ ST_BITMAPSCAN ,
781+ NULL ,
782+ NULL );
763783* bitindexpaths = list_concat (* bitindexpaths ,indexpaths );
764784}
765785}
@@ -782,26 +802,36 @@ get_index_paths(PlannerInfo *root, RelOptInfo *rel,
782802 * Note that this routine should never be called at all if the index has an
783803 * unprovable predicate.
784804 *
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- *
789805 * scantype indicates whether we want to create plain indexscans, bitmap
790806 * indexscans, or both. When it's ST_BITMAPSCAN, we will not consider
791807 * index ordering while deciding if a Path is worth generating.
792808 *
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+ *
793820 * 'rel' is the index's heap relation
794821 * 'index' is the index for which we want to generate paths
795822 * 'clauses' is the collection of indexable clauses (RestrictInfo nodes)
796823 * 'useful_predicate' indicates whether the index has a useful predicate
797- * 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used
798824 * '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
799827 */
800828static List *
801829build_index_paths (PlannerInfo * root ,RelOptInfo * rel ,
802830IndexOptInfo * index ,IndexClauseSet * clauses ,
803831bool useful_predicate ,
804- SaOpControl saop_control ,ScanTypeControl scantype )
832+ ScanTypeControl scantype ,
833+ bool * skip_nonnative_saop ,
834+ bool * skip_lower_saop )
805835{
806836List * result = NIL ;
807837IndexPath * ipath ;
@@ -813,7 +843,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
813843List * orderbyclausecols ;
814844List * index_pathkeys ;
815845List * useful_pathkeys ;
816- bool found_clause ;
817846bool found_lower_saop_clause ;
818847bool pathkeys_possibly_useful ;
819848bool index_is_ordered ;
@@ -848,11 +877,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
848877 * (This order is depended on by btree and possibly other places.)The
849878 * lists can be empty, if the index AM allows that.
850879 *
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
856881 * index clause for a non-first index column. This prevents us from
857882 * assuming that the scan result is ordered. (Actually, the result is
858883 * still ordered if there are equality constraints for all earlier
@@ -864,7 +889,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
864889 */
865890index_clauses = NIL ;
866891clause_columns = NIL ;
867- found_clause = false;
868892found_lower_saop_clause = false;
869893outer_relids = NULL ;
870894for (indexcol = 0 ;indexcol < index -> ncolumns ;indexcol ++ )
@@ -877,17 +901,27 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
877901
878902if (IsA (rinfo -> clause ,ScalarArrayOpExpr ))
879903{
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+ }
884915if (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+ }
885923found_lower_saop_clause = true;
886- }
887- else
888- {
889- if (saop_control != SAOP_REQUIRE )
890- found_clause = true;
924+ }
891925}
892926index_clauses = lappend (index_clauses ,rinfo );
893927clause_columns = lappend_int (clause_columns ,indexcol );
@@ -967,7 +1001,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
9671001 * later merging or final output ordering, OR the index has a useful
9681002 * predicate, OR an index-only scan is possible.
9691003 */
970- if (found_clause || useful_pathkeys != NIL || useful_predicate ||
1004+ if (index_clauses != NIL || useful_pathkeys != NIL || useful_predicate ||
9711005index_only_scan )
9721006{
9731007ipath = create_index_path (root ,index ,
@@ -1116,7 +1150,9 @@ build_paths_for_OR(PlannerInfo *root, RelOptInfo *rel,
11161150indexpaths = build_index_paths (root ,rel ,
11171151index ,& clauseset ,
11181152useful_predicate ,
1119- SAOP_ALLOW ,ST_BITMAPSCAN );
1153+ ST_BITMAPSCAN ,
1154+ NULL ,
1155+ NULL );
11201156result = list_concat (result ,indexpaths );
11211157}
11221158