Skip to content

Commit 807a40c

Browse files
committed
Fix planning of btree index scans using ScalarArrayOpExpr quals.
In commit 9e8da0f, I improved btree to handle ScalarArrayOpExpr quals natively, so that constructs like "indexedcol IN (list)" could be supported by index-only scans. Using such a qual results in multiple scans of the index, under-the-hood. I went to some lengths to ensure that this still produces rows in index order ... but I failed to recognize that if a higher-order index column is lacking an equality constraint, rescans can produce out-of-order data from that column. Tweak the planner to not expect sorted output in that case. Per trouble report from Robert McGehee.
1 parent 3f828fa commit 807a40c

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

src/backend/optimizer/path/indxpath.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
787787
List *index_pathkeys;
788788
List *useful_pathkeys;
789789
bool found_clause;
790+
bool found_lower_saop_clause;
790791
bool pathkeys_possibly_useful;
791792
bool index_is_ordered;
792793
bool index_only_scan;
@@ -824,13 +825,21 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
824825
* if saop_control is SAOP_REQUIRE, it has to be a ScalarArrayOpExpr
825826
* clause.
826827
*
828+
* found_lower_saop_clause is set true if there's a ScalarArrayOpExpr
829+
* index clause for a non-first index column. This prevents us from
830+
* assuming that the scan result is ordered. (Actually, the result is
831+
* still ordered if there are equality constraints for all earlier
832+
* columns, but it seems too expensive and non-modular for this code to be
833+
* aware of that refinement.)
834+
*
827835
* We also build a Relids set showing which outer rels are required by the
828836
* selected clauses. Any lateral_relids are included in that, but not
829837
* otherwise accounted for.
830838
*/
831839
index_clauses = NIL;
832840
clause_columns = NIL;
833841
found_clause = false;
842+
found_lower_saop_clause = false;
834843
outer_relids = bms_copy(rel->lateral_relids);
835844
for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
836845
{
@@ -846,6 +855,8 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
846855
if (saop_control == SAOP_PER_AM && !index->amsearcharray)
847856
continue;
848857
found_clause = true;
858+
if (indexcol > 0)
859+
found_lower_saop_clause = true;
849860
}
850861
else
851862
{
@@ -882,9 +893,11 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
882893
/*
883894
* 2. Compute pathkeys describing index's ordering, if any, then see how
884895
* many of them are actually useful for this query. This is not relevant
885-
* if we are only trying to build bitmap indexscans.
896+
* if we are only trying to build bitmap indexscans, nor if we have to
897+
* assume the scan is unordered.
886898
*/
887899
pathkeys_possibly_useful = (scantype != ST_BITMAPSCAN &&
900+
!found_lower_saop_clause &&
888901
has_useful_pathkeys(root, rel));
889902
index_is_ordered = (index->sortopfamily != NULL);
890903
if (index_is_ordered && pathkeys_possibly_useful)

src/test/regress/expected/create_index.out

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2676,3 +2676,48 @@ SELECT count(*) FROM dupindexcols
26762676
97
26772677
(1 row)
26782678

2679+
--
2680+
-- Check ordering of =ANY indexqual results (bug in 9.2.0)
2681+
--
2682+
vacuum analyze tenk1; -- ensure we get consistent plans here
2683+
explain (costs off)
2684+
SELECT unique1 FROM tenk1
2685+
WHERE unique1 IN (1,42,7)
2686+
ORDER BY unique1;
2687+
QUERY PLAN
2688+
-------------------------------------------------------
2689+
Index Only Scan using tenk1_unique1 on tenk1
2690+
Index Cond: (unique1 = ANY ('{1,42,7}'::integer[]))
2691+
(2 rows)
2692+
2693+
SELECT unique1 FROM tenk1
2694+
WHERE unique1 IN (1,42,7)
2695+
ORDER BY unique1;
2696+
unique1
2697+
---------
2698+
1
2699+
7
2700+
42
2701+
(3 rows)
2702+
2703+
explain (costs off)
2704+
SELECT thousand, tenthous FROM tenk1
2705+
WHERE thousand < 2 AND tenthous IN (1001,3000)
2706+
ORDER BY thousand;
2707+
QUERY PLAN
2708+
--------------------------------------------------------------------------------------
2709+
Sort
2710+
Sort Key: thousand
2711+
-> Index Only Scan using tenk1_thous_tenthous on tenk1
2712+
Index Cond: ((thousand < 2) AND (tenthous = ANY ('{1001,3000}'::integer[])))
2713+
(4 rows)
2714+
2715+
SELECT thousand, tenthous FROM tenk1
2716+
WHERE thousand < 2 AND tenthous IN (1001,3000)
2717+
ORDER BY thousand;
2718+
thousand | tenthous
2719+
----------+----------
2720+
0 | 3000
2721+
1 | 1001
2722+
(2 rows)
2723+

src/test/regress/sql/create_index.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,3 +888,27 @@ EXPLAIN (COSTS OFF)
888888
WHERE f1 > 'WA' and id < 1000 and f1 ~<~ 'YX';
889889
SELECT count(*) FROM dupindexcols
890890
WHERE f1 > 'WA' and id < 1000 and f1 ~<~ 'YX';
891+
892+
--
893+
-- Check ordering of =ANY indexqual results (bug in 9.2.0)
894+
--
895+
896+
vacuum analyze tenk1; -- ensure we get consistent plans here
897+
898+
explain (costs off)
899+
SELECT unique1 FROM tenk1
900+
WHERE unique1 IN (1,42,7)
901+
ORDER BY unique1;
902+
903+
SELECT unique1 FROM tenk1
904+
WHERE unique1 IN (1,42,7)
905+
ORDER BY unique1;
906+
907+
explain (costs off)
908+
SELECT thousand, tenthous FROM tenk1
909+
WHERE thousand < 2 AND tenthous IN (1001,3000)
910+
ORDER BY thousand;
911+
912+
SELECT thousand, tenthous FROM tenk1
913+
WHERE thousand < 2 AND tenthous IN (1001,3000)
914+
ORDER BY thousand;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy