Fix SkipScan for IndexPaths without pathkeys

The SkipScan code assumed IndexPaths on ordered indexes always
have pathkeys which is not true when the pathkeys are not useful
for the query, leading to a segfault for those queries.
This commit is contained in:
Sven Klemm 2021-04-21 19:17:46 +02:00 committed by Sven Klemm
parent 242919bc49
commit 8fd4ecbdd9
6 changed files with 34 additions and 3 deletions

View File

@ -15,6 +15,10 @@ accidentally triggering the load of a previous DB version.**
* #3106 Fix use after free in chunk_api_get_chunk_stats
* #3123 Fix crash while using REINDEX TABLE CONCURRENTLY
* #3135 Fix SkipScan path generation in DISTINCT queries with expressions
* #3146 Fix SkipScan for IndexPaths without pathkeys
**Thanks**
* @hperez75 for reporting an issue with Skip Scan
## 2.2.0 (2021-04-13)

View File

@ -336,8 +336,9 @@ skip_scan_path_create(PlannerInfo *root, IndexPath *index_path, double ndistinct
double total = index_path->path.total_cost;
double rows = index_path->path.rows;
if (index_path->indexinfo->sortopfamily == NULL)
return NULL; /* non-orderable index, skip these for now */
/* cannot use SkipScan with non-orderable index or IndexPath without pathkeys */
if (!index_path->path.pathkeys || !index_path->indexinfo->sortopfamily)
return NULL;
/* orderbyops are not compatible with skipscan */
if (index_path->indexorderbys != NIL)
@ -424,7 +425,7 @@ build_subpath(PlannerInfo *root, List *subpaths, double ndistinct)
new_paths = lappend(new_paths, child);
}
if (!has_skip_path)
if (!has_skip_path && new_paths)
{
pfree(new_paths);
return NIL;

View File

@ -3823,6 +3823,14 @@ DROP INDEX _timescaledb_internal._hyper_1_1_chunk_skip_scan_ht_dev_idx;
-> Index Scan using _hyper_1_4_chunk_skip_scan_ht_dev_idx1 on _hyper_1_4_chunk (actual rows=11 loops=1)
(11 rows)
-- IndexPath without pathkeys doesnt use SkipScan
EXPLAIN (costs off, timing off, summary off) SELECT DISTINCT 1 FROM pg_rewrite;
QUERY PLAN
-------------------------------------------------------------------------
Unique
-> Index Only Scan using pg_rewrite_rel_rulename_index on pg_rewrite
(2 rows)
-- try one query with EXPLAIN only for coverage
EXPLAIN (costs off, timing off, summary off) SELECT DISTINCT ON (dev_name) dev_name FROM skip_scan;
QUERY PLAN

View File

@ -3794,6 +3794,14 @@ DROP INDEX _timescaledb_internal._hyper_1_1_chunk_skip_scan_ht_dev_idx;
-> Index Scan using _hyper_1_4_chunk_skip_scan_ht_dev_idx1 on _hyper_1_4_chunk (actual rows=11 loops=1)
(11 rows)
-- IndexPath without pathkeys doesnt use SkipScan
EXPLAIN (costs off, timing off, summary off) SELECT DISTINCT 1 FROM pg_rewrite;
QUERY PLAN
-------------------------------------------------------------------------
Unique
-> Index Only Scan using pg_rewrite_rel_rulename_index on pg_rewrite
(2 rows)
-- try one query with EXPLAIN only for coverage
EXPLAIN (costs off, timing off, summary off) SELECT DISTINCT ON (dev_name) dev_name FROM skip_scan;
QUERY PLAN

View File

@ -3786,6 +3786,14 @@ DROP INDEX _timescaledb_internal._hyper_1_1_chunk_skip_scan_ht_dev_idx;
-> Index Scan using _hyper_1_4_chunk_skip_scan_ht_dev_idx1 on _hyper_1_4_chunk (actual rows=11 loops=1)
(11 rows)
-- IndexPath without pathkeys doesnt use SkipScan
EXPLAIN (costs off, timing off, summary off) SELECT DISTINCT 1 FROM pg_rewrite;
QUERY PLAN
-------------------------------------------------------------------------
Unique
-> Index Only Scan using pg_rewrite_rel_rulename_index on pg_rewrite
(2 rows)
-- try one query with EXPLAIN only for coverage
EXPLAIN (costs off, timing off, summary off) SELECT DISTINCT ON (dev_name) dev_name FROM skip_scan;
QUERY PLAN

View File

@ -23,3 +23,5 @@ SELECT decompress_chunk('_timescaledb_internal._hyper_1_1_chunk');
DROP INDEX _timescaledb_internal._hyper_1_1_chunk_skip_scan_ht_dev_idx;
:PREFIX SELECT DISTINCT ON (dev) dev, dev_name FROM :TABLE;
-- IndexPath without pathkeys doesnt use SkipScan
EXPLAIN (costs off, timing off, summary off) SELECT DISTINCT 1 FROM pg_rewrite;