Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .unreleased/pr_9743
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixes: #9743 Fixes the composite bloom metadata column naming scheme
Thanks: @pavanmanishd for the first version of the fix
1 change: 0 additions & 1 deletion tsl/src/compression/compression_dml.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,6 @@ init_upsert_bloom_state(ChunkInsertState *cis)

/* Verify bloom column exists in the compressed chunk */
AttrNumber compressed_attnum = get_attnum(compressed_relid, col_name);
Assert(AttributeNumberIsValid(compressed_attnum));
if (!AttributeNumberIsValid(compressed_attnum))
{
continue;
Expand Down
16 changes: 12 additions & 4 deletions tsl/src/compression/create.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,10 @@ compressed_column_metadata_name_v2(const char *metadata_type, const char **colum
Assert(num_columns <= MAX_BLOOM_FILTER_COLUMNS);

int len = 0;
StringInfoData buf = { 0 };
/* Use a separate buffer for the hash computation */
StringInfoData buf = { 0 }, hash_buf = { 0 };
initStringInfo(&buf);
initStringInfo(&hash_buf);

for (int i = 0; i < num_columns; i++)
{
Expand All @@ -187,8 +189,12 @@ compressed_column_metadata_name_v2(const char *metadata_type, const char **colum
if (i > 0)
{
appendStringInfoChar(&buf, '_');
/* The separator for hash purposes needs to be something
* that is not valid in Postgres, hence the zero byte */
appendStringInfoChar(&hash_buf, '\0');
}
appendStringInfo(&buf, "%s", column_names[i]);
appendBinaryStringInfo(&hash_buf, column_names[i], strlen(column_names[i]));
}

len = buf.len;
Expand All @@ -197,14 +203,16 @@ compressed_column_metadata_name_v2(const char *metadata_type, const char **colum
* We have to fit the name into NAMEDATALEN - 1 which is 63 bytes:
* 12 (_ts_meta_v2_) + 6 (metadata_type) + [1 (_) + x (column_name)]x num_columns + 1 (_) + 4
* (hash) = 63; x = 63 - 24 = 39.
*
* Fix for bug #9578: we need to differentiate between ('a_b', 'c') and ('a', 'b_c') composite
* column names, for this reason we always go through the hash path for composite column names.
*/

char *result;
if (len > 39)
if (len > 39 || num_columns > 1)
{
const char *errstr = NULL;
char hash[33];
Ensure(pg_md5_hash(buf.data, len, hash, &errstr), "md5 computation failure");
Ensure(pg_md5_hash(hash_buf.data, hash_buf.len, hash, &errstr), "md5 computation failure");
result = psprintf("_ts_meta_v2_%.6s_%.4s_%.39s", metadata_type, hash, buf.data);
}
else
Expand Down
2 changes: 1 addition & 1 deletion tsl/test/expected/compress_bloom_dml.out
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ select * from dml_test where foo = 1001 and boo = 1002;
Custom Scan (ColumnarScan) on _hyper_1_1_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((foo = 1001) AND (boo = 1002))
-> Seq Scan on compress_hyper_2_2_chunk (actual rows=0.00 loops=1)
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_boo_foo, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_boo, TEST-HASHES::bigint[]))
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_701f_boo_foo, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_boo, TEST-HASHES::bigint[]))
Rows Removed by Filter: 50

SET timescaledb.enable_dml_bloom_filter = off;
Expand Down
130 changes: 65 additions & 65 deletions tsl/test/expected/compress_compbloom_basics.out

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions tsl/test/expected/compress_compbloom_config.out
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ select relid,compress_relid,segmentby,orderby,orderby_desc,orderby_nullsfirst,in

-- Check the auto generated compressed columns
select relname,attname from compressedcols order by 1,2;
relname | attname
--------------------------+--------------------------
relname | attname
--------------------------+-------------------------------
compress_hyper_4_2_chunk | _ts_meta_count
compress_hyper_4_2_chunk | _ts_meta_max_1
compress_hyper_4_2_chunk | _ts_meta_max_2
compress_hyper_4_2_chunk | _ts_meta_min_1
compress_hyper_4_2_chunk | _ts_meta_min_2
compress_hyper_4_2_chunk | regress-test-bloom_a_b_c
compress_hyper_4_2_chunk | regress-test-bloom_c
compress_hyper_4_2_chunk | regress-test-bloom_ed4b_a_b_c
compress_hyper_4_2_chunk | a
compress_hyper_4_2_chunk | b
compress_hyper_4_2_chunk | c
Expand Down Expand Up @@ -148,9 +148,9 @@ select relname,attname from compressedcols order by 1,2;
compress_hyper_6_4_chunk | _ts_meta_max_2
compress_hyper_6_4_chunk | _ts_meta_min_1
compress_hyper_6_4_chunk | _ts_meta_min_2
compress_hyper_6_4_chunk | regress-test-bloom_76d9_a_01234567890123456789_b_01234567890123
compress_hyper_6_4_chunk | regress-test-bloom_c_01234567890123456789
compress_hyper_6_4_chunk | regress-test-bloom_d_01234567890123456789
compress_hyper_6_4_chunk | regress-test-bloom_ddd4_a_01234567890123456789_b_01234567890123
compress_hyper_6_4_chunk | regress-test-bloom_e_01234567890123456789
compress_hyper_6_4_chunk | a_01234567890123456789
compress_hyper_6_4_chunk | b_01234567890123456789
Expand Down
2 changes: 1 addition & 1 deletion tsl/test/expected/compress_compbloom_hash_pushdown.out
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ select * from hash_pushdown_test where a = 1 and b = 2;
Custom Scan (ColumnarScan) on _hyper_1_1_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((a = 1) AND (b = 2))
-> Seq Scan on compress_hyper_2_2_chunk (actual rows=0.00 loops=1)
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]))
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_7035_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]))
Rows Removed by Filter: 10

-- saop with single bloom
Expand Down
2 changes: 1 addition & 1 deletion tsl/test/expected/compress_compbloom_index_add.out
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ ORDER BY 1,2,3,4;
-> Custom Scan (ColumnarScan) on _hyper_1_3_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((a = 1) AND (b = 2))
-> Seq Scan on compress_hyper_2_6_chunk (actual rows=0.00 loops=1)
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b, TEST-HASHES::bigint[]))
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_7035_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b, TEST-HASHES::bigint[]))
Rows Removed by Filter: 1

DROP TABLE IF EXISTS mixed_avail_add CASCADE;
8 changes: 4 additions & 4 deletions tsl/test/expected/compress_compbloom_index_drop.out
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ ORDER BY 1,2,3,4;
-> Custom Scan (ColumnarScan) on _hyper_1_1_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((a = 1) AND (b = 2))
-> Seq Scan on compress_hyper_2_4_chunk (actual rows=0.00 loops=1)
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b, TEST-HASHES::bigint[]))
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_7035_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b, TEST-HASHES::bigint[]))
Rows Removed by Filter: 2
-> Sort (actual rows=0.00 loops=1)
Sort Key: _hyper_1_2_chunk.ts, _hyper_1_2_chunk.seg
Sort Method: quicksort
-> Custom Scan (ColumnarScan) on _hyper_1_2_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((a = 1) AND (b = 2))
-> Seq Scan on compress_hyper_2_5_chunk (actual rows=0.00 loops=1)
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b, TEST-HASHES::bigint[]))
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_7035_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b, TEST-HASHES::bigint[]))
Rows Removed by Filter: 3
-> Sort (actual rows=0.00 loops=1)
Sort Key: _hyper_1_3_chunk.ts, _hyper_1_3_chunk.seg
Expand Down Expand Up @@ -87,15 +87,15 @@ ORDER BY 1,2,3,4;
-> Custom Scan (ColumnarScan) on _hyper_1_1_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((a = 1) AND (b = 2))
-> Seq Scan on compress_hyper_2_4_chunk (actual rows=0.00 loops=1)
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b, TEST-HASHES::bigint[]))
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_7035_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b, TEST-HASHES::bigint[]))
Rows Removed by Filter: 2
-> Sort (actual rows=0.00 loops=1)
Sort Key: _hyper_1_2_chunk.ts, _hyper_1_2_chunk.seg
Sort Method: quicksort
-> Custom Scan (ColumnarScan) on _hyper_1_2_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((a = 1) AND (b = 2))
-> Seq Scan on compress_hyper_2_5_chunk (actual rows=0.00 loops=1)
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b, TEST-HASHES::bigint[]))
Filter: (_timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_7035_a_b, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a, TEST-HASHES::bigint[]) AND _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b, TEST-HASHES::bigint[]))
Rows Removed by Filter: 3
-> Sort (actual rows=0.00 loops=1)
Sort Key: _hyper_1_3_chunk.ts, _hyper_1_3_chunk.seg
Expand Down
8 changes: 4 additions & 4 deletions tsl/test/expected/compress_compbloom_manual_config.out
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ ORDER BY 1,2,3,4;
-> Custom Scan (ColumnarScan) on _hyper_1_1_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((a = 1) AND (b = 2))
-> Seq Scan on compress_hyper_2_4_chunk (actual rows=0.00 loops=1)
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a_b, TEST-HASHES::bigint[])
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_7035_a_b, TEST-HASHES::bigint[])
Rows Removed by Filter: 2
-> Sort (actual rows=0.00 loops=1)
Sort Key: _hyper_1_2_chunk.ts, _hyper_1_2_chunk.c
Expand Down Expand Up @@ -175,7 +175,7 @@ ORDER BY 1,2,3,4;
-> Custom Scan (ColumnarScan) on _hyper_1_1_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((a = 1) AND (b = 2))
-> Seq Scan on compress_hyper_2_4_chunk (actual rows=0.00 loops=1)
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a_b, TEST-HASHES::bigint[])
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_7035_a_b, TEST-HASHES::bigint[])
Rows Removed by Filter: 2
-> Sort (actual rows=0.00 loops=1)
Sort Key: _hyper_1_2_chunk.ts, _hyper_1_2_chunk.c
Expand Down Expand Up @@ -212,7 +212,7 @@ ORDER BY 1,2,3,4;
Vectorized Filter: ((a = 1) AND (c = 2))
Rows Removed by Filter: 2328
-> Seq Scan on compress_hyper_2_5_chunk (actual rows=3.00 loops=1)
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_a_c, TEST-HASHES::bigint[])
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_e8f0_a_c, TEST-HASHES::bigint[])
-> Sort (actual rows=27.00 loops=1)
Sort Key: _hyper_1_3_chunk.ts, _hyper_1_3_chunk.b
Sort Method: quicksort
Expand Down Expand Up @@ -248,6 +248,6 @@ ORDER BY 1,2,3,4;
Vectorized Filter: ((b = 1) AND (c = 2))
Rows Removed by Filter: 846
-> Seq Scan on compress_hyper_2_6_chunk (actual rows=1.00 loops=1)
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_b_c, TEST-HASHES::bigint[])
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_7ba1_b_c, TEST-HASHES::bigint[])

DROP TABLE IF EXISTS mixed_avail_manual CASCADE;
73 changes: 73 additions & 0 deletions tsl/test/expected/compress_compbloom_naming.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
-- This file and its contents are licensed under the Timescale License.
-- Please see the included NOTICE for copyright information and
-- LICENSE-TIMESCALE for a copy of the license.
-- Testcase for issue #9578: the composite bloom filter naming
-- allowed to generate the same column name for ('a_b', 'c') and ('a', 'b_c').
CREATE TABLE t (
ts timestamptz NOT NULL,
a_b int,
c int,
a int,
b_c int
);
SELECT create_hypertable('t', 'ts');
create_hypertable
-------------------
(1,public,t,t)

ALTER TABLE t SET (
timescaledb.compress,
timescaledb.compress_orderby = 'ts',
timescaledb.compress_index = 'bloom(a_b, c), bloom(a, b_c)'
);
INSERT INTO t VALUES ('2024-01-01', 1, 2, 3, 4);
SELECT compress_chunk(c) FROM show_chunks('t') c;
compress_chunk
----------------------------------------
_timescaledb_internal._hyper_1_1_chunk

-- If the below error doesn't appear, then the bugfix worked:
-- ERROR: column regress-test-bloom_a_b_c specified more than once
-- Check the bloom column names in the compressed chunk
SELECT
relname,
attname
FROM
pg_attribute a,
pg_class c
WHERE
c.oid=a.attrelid AND
attname LIKE '%_ts_meta%bloom%a_b_c%' AND
relname LIKE '%chunk'
ORDER BY
relname::text COLLATE "C",
attname::text COLLATE "C";
relname | attname
--------------------------+-------------------------------
compress_hyper_2_2_chunk | regress-test-bloom_c66a_a_b_c
compress_hyper_2_2_chunk | regress-test-bloom_ee9c_a_b_c

-- Verify the assumption that the zero byte separator used in the
-- bloom column names is not allowed in Postgres column names:
-- 'a' || chr(0) || 'b' = 'a\u0000b'
\set ON_ERROR_STOP 0
CREATE TABLE t2 (
ts timestamptz NOT NULL,
U&"a\0000b" int,
c int,
a int,
U&"b\0000c" int);
ERROR: invalid Unicode escape value at character 60
CREATE TABLE t3 (
ts timestamptz NOT NULL,
E'a\000b' int,
c int,
a int,
E'b\000c' int);
ERROR: invalid byte sequence for encoding "UTF8": 0x00
DO $$
BEGIN
EXECUTE format('CREATE TABLE t4 (%I int)', E'a\000b');
END $$;
ERROR: invalid byte sequence for encoding "UTF8": 0x00
\set ON_ERROR_STOP 1
10 changes: 5 additions & 5 deletions tsl/test/expected/compress_composite_bloom_debug.out
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ WHERE attrelid = :'chunk'::regclass
LIMIT 1
\gset
\echo 'Composite bloom column: ' :composite_bloom_col
Composite bloom column: regress-test-bloom_device_id_sensor_type
Composite bloom column: regress-test-bloom_d3fa_device_id_sensor_type
-----------------------------------------------------------
-- Filtering Effectiveness Tests
-----------------------------------------------------------
Expand All @@ -211,7 +211,7 @@ SELECT * FROM composite_filter_test WHERE device_id = 1 AND sensor_type = 'temp'
Vectorized Filter: ((device_id = 1) AND (sensor_type = 'temp'::text))
Rows Removed by Filter: 600
-> Seq Scan on compress_hyper_2_2_chunk (actual rows=2.00 loops=1)
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_device_id_sensor_type, TEST-HASHES::bigint[])
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_d3fa_device_id_sensor_type, TEST-HASHES::bigint[])
Rows Removed by Filter: 2

-- Expected behavior:
Expand All @@ -227,7 +227,7 @@ SELECT * FROM composite_filter_test WHERE device_id = 2 AND sensor_type = 'humid
Vectorized Filter: ((device_id = 2) AND (sensor_type = 'humidity'::text))
Rows Removed by Filter: 600
-> Seq Scan on compress_hyper_2_2_chunk (actual rows=2.00 loops=1)
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_device_id_sensor_type, TEST-HASHES::bigint[])
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_d3fa_device_id_sensor_type, TEST-HASHES::bigint[])
Rows Removed by Filter: 2

-- Expected: Similar pruning as Test 5.1
Expand All @@ -238,7 +238,7 @@ SELECT * FROM composite_filter_test WHERE device_id = 5 AND sensor_type = 'temp'
Custom Scan (ColumnarScan) on _hyper_1_1_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((device_id = 5) AND (sensor_type = 'temp'::text))
-> Seq Scan on compress_hyper_2_2_chunk (actual rows=0.00 loops=1)
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_device_id_sensor_type, TEST-HASHES::bigint[])
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_d3fa_device_id_sensor_type, TEST-HASHES::bigint[])
Rows Removed by Filter: 4

-- Expected:
Expand All @@ -251,7 +251,7 @@ SELECT * FROM composite_filter_test WHERE device_id = 1 AND sensor_type = 'humid
Custom Scan (ColumnarScan) on _hyper_1_1_chunk (actual rows=0.00 loops=1)
Vectorized Filter: ((device_id = 1) AND (sensor_type = 'humidity'::text))
-> Seq Scan on compress_hyper_2_2_chunk (actual rows=0.00 loops=1)
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_device_id_sensor_type, TEST-HASHES::bigint[])
Filter: _timescaledb_functions.bloom1_contains_any_hashes(regress-test-bloom_d3fa_device_id_sensor_type, TEST-HASHES::bigint[])
Rows Removed by Filter: 4

-- Expected:
Expand Down
Loading
Loading