From c34fd0b06c4daee1d0aaf7a1efb7aa7e1fc2fc04 Mon Sep 17 00:00:00 2001 From: Alexander Kuzmenkov <36882414+akuzm@users.noreply.github.com> Date: Mon, 6 Nov 2023 12:33:07 +0100 Subject: [PATCH] Do not use partial indexes for compression They refer only to a subset of the table. --- .unreleased/fix_partial_index | 1 + tsl/src/compression/compression.c | 11 ++++++ tsl/test/expected/compression_indexscan.out | 37 +++++++++++++++++++++ tsl/test/sql/compression_indexscan.sql | 10 +++++- 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 .unreleased/fix_partial_index diff --git a/.unreleased/fix_partial_index b/.unreleased/fix_partial_index new file mode 100644 index 00000000000..5cb091f3338 --- /dev/null +++ b/.unreleased/fix_partial_index @@ -0,0 +1 @@ +Fixes: #6280 Potential data loss when compressing a table with a partial index that matches compression order. diff --git a/tsl/src/compression/compression.c b/tsl/src/compression/compression.c index d7c916cec23..0b7b8dd1a87 100644 --- a/tsl/src/compression/compression.c +++ b/tsl/src/compression/compression.c @@ -291,6 +291,17 @@ compress_chunk(Oid in_table, Oid out_table, const ColumnCompressionInfo **column Oid index_oid = lfirst_oid(lc); Relation index_rel = index_open(index_oid, AccessShareLock); IndexInfo *index_info = BuildIndexInfo(index_rel); + + if (index_info->ii_Predicate != 0) + { + /* + * Can't use partial indexes for compression because they refer + * only to a subset of all rows. + */ + index_close(index_rel, AccessShareLock); + continue; + } + int previous_direction = NoMovementScanDirection; int current_direction = NoMovementScanDirection; diff --git a/tsl/test/expected/compression_indexscan.out b/tsl/test/expected/compression_indexscan.out index 6afc209e239..c259f64e22a 100644 --- a/tsl/test/expected/compression_indexscan.out +++ b/tsl/test/expected/compression_indexscan.out @@ -912,6 +912,43 @@ SELECT decompress_chunk(show_chunks('tab1')); (4 rows) DROP INDEX idx_asc_null_first; +-- Can't use partial indexes for compression because they refer only to a subset of the table. +create index predicate on tab1(id, c1, time nulls first) where c2 = 0; +select count(*) from tab1; + count +------- + 62400 +(1 row) + +select compress_chunk(show_chunks('tab1')); +INFO: compress_chunk_tuplesort_start +INFO: compress_chunk_tuplesort_start +INFO: compress_chunk_tuplesort_start +INFO: compress_chunk_tuplesort_start + compress_chunk +---------------------------------------- + _timescaledb_internal._hyper_1_1_chunk + _timescaledb_internal._hyper_1_2_chunk + _timescaledb_internal._hyper_1_3_chunk + _timescaledb_internal._hyper_1_4_chunk +(4 rows) + +select decompress_chunk(show_chunks('tab1')); + decompress_chunk +---------------------------------------- + _timescaledb_internal._hyper_1_1_chunk + _timescaledb_internal._hyper_1_2_chunk + _timescaledb_internal._hyper_1_3_chunk + _timescaledb_internal._hyper_1_4_chunk +(4 rows) + +select count(*) from tab1; + count +------- + 62400 +(1 row) + +drop index predicate; --Tear down DROP TABLE tab1; DROP TABLE tab2; diff --git a/tsl/test/sql/compression_indexscan.sql b/tsl/test/sql/compression_indexscan.sql index f9a8cb93e03..cf23a3b525c 100644 --- a/tsl/test/sql/compression_indexscan.sql +++ b/tsl/test/sql/compression_indexscan.sql @@ -251,8 +251,16 @@ SELECT compress_chunk(show_chunks('tab1')); SELECT decompress_chunk(show_chunks('tab1')); DROP INDEX idx_asc_null_first; +-- Can't use partial indexes for compression because they refer only to a subset of the table. +create index predicate on tab1(id, c1, time nulls first) where c2 = 0; +select count(*) from tab1; +select compress_chunk(show_chunks('tab1')); +select decompress_chunk(show_chunks('tab1')); +select count(*) from tab1; +drop index predicate; + --Tear down DROP TABLE tab1; DROP TABLE tab2; DROP TABLE tab3; -SET timescaledb.show_compression_path_info = 'off'; \ No newline at end of file +SET timescaledb.show_compression_path_info = 'off';