Skip to content
Snippets Groups Projects
Commit 807a40c5 authored by Tom Lane's avatar Tom Lane
Browse files

Fix planning of btree index scans using ScalarArrayOpExpr quals.

In commit 9e8da0f7, 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.
parent 3f828fae
No related branches found
No related tags found
No related merge requests found
......@@ -787,6 +787,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
List *index_pathkeys;
List *useful_pathkeys;
bool found_clause;
bool found_lower_saop_clause;
bool pathkeys_possibly_useful;
bool index_is_ordered;
bool index_only_scan;
......@@ -824,6 +825,13 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
* if saop_control is SAOP_REQUIRE, it has to be a ScalarArrayOpExpr
* clause.
*
* found_lower_saop_clause is set true if there's a ScalarArrayOpExpr
* index clause for a non-first index column. This prevents us from
* assuming that the scan result is ordered. (Actually, the result is
* still ordered if there are equality constraints for all earlier
* columns, but it seems too expensive and non-modular for this code to be
* aware of that refinement.)
*
* We also build a Relids set showing which outer rels are required by the
* selected clauses. Any lateral_relids are included in that, but not
* otherwise accounted for.
......@@ -831,6 +839,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
index_clauses = NIL;
clause_columns = NIL;
found_clause = false;
found_lower_saop_clause = false;
outer_relids = bms_copy(rel->lateral_relids);
for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
{
......@@ -846,6 +855,8 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
if (saop_control == SAOP_PER_AM && !index->amsearcharray)
continue;
found_clause = true;
if (indexcol > 0)
found_lower_saop_clause = true;
}
else
{
......@@ -882,9 +893,11 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
/*
* 2. Compute pathkeys describing index's ordering, if any, then see how
* many of them are actually useful for this query. This is not relevant
* if we are only trying to build bitmap indexscans.
* if we are only trying to build bitmap indexscans, nor if we have to
* assume the scan is unordered.
*/
pathkeys_possibly_useful = (scantype != ST_BITMAPSCAN &&
!found_lower_saop_clause &&
has_useful_pathkeys(root, rel));
index_is_ordered = (index->sortopfamily != NULL);
if (index_is_ordered && pathkeys_possibly_useful)
......
......@@ -2676,3 +2676,48 @@ SELECT count(*) FROM dupindexcols
97
(1 row)
--
-- Check ordering of =ANY indexqual results (bug in 9.2.0)
--
vacuum analyze tenk1; -- ensure we get consistent plans here
explain (costs off)
SELECT unique1 FROM tenk1
WHERE unique1 IN (1,42,7)
ORDER BY unique1;
QUERY PLAN
-------------------------------------------------------
Index Only Scan using tenk1_unique1 on tenk1
Index Cond: (unique1 = ANY ('{1,42,7}'::integer[]))
(2 rows)
SELECT unique1 FROM tenk1
WHERE unique1 IN (1,42,7)
ORDER BY unique1;
unique1
---------
1
7
42
(3 rows)
explain (costs off)
SELECT thousand, tenthous FROM tenk1
WHERE thousand < 2 AND tenthous IN (1001,3000)
ORDER BY thousand;
QUERY PLAN
--------------------------------------------------------------------------------------
Sort
Sort Key: thousand
-> Index Only Scan using tenk1_thous_tenthous on tenk1
Index Cond: ((thousand < 2) AND (tenthous = ANY ('{1001,3000}'::integer[])))
(4 rows)
SELECT thousand, tenthous FROM tenk1
WHERE thousand < 2 AND tenthous IN (1001,3000)
ORDER BY thousand;
thousand | tenthous
----------+----------
0 | 3000
1 | 1001
(2 rows)
......@@ -888,3 +888,27 @@ EXPLAIN (COSTS OFF)
WHERE f1 > 'WA' and id < 1000 and f1 ~<~ 'YX';
SELECT count(*) FROM dupindexcols
WHERE f1 > 'WA' and id < 1000 and f1 ~<~ 'YX';
--
-- Check ordering of =ANY indexqual results (bug in 9.2.0)
--
vacuum analyze tenk1; -- ensure we get consistent plans here
explain (costs off)
SELECT unique1 FROM tenk1
WHERE unique1 IN (1,42,7)
ORDER BY unique1;
SELECT unique1 FROM tenk1
WHERE unique1 IN (1,42,7)
ORDER BY unique1;
explain (costs off)
SELECT thousand, tenthous FROM tenk1
WHERE thousand < 2 AND tenthous IN (1001,3000)
ORDER BY thousand;
SELECT thousand, tenthous FROM tenk1
WHERE thousand < 2 AND tenthous IN (1001,3000)
ORDER BY thousand;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment