diff --git a/src/Compression/CompressionCodecGorilla.cpp b/src/Compression/CompressionCodecGorilla.cpp index acad0f69f9e9..61ab6c2a2913 100644 --- a/src/Compression/CompressionCodecGorilla.cpp +++ b/src/Compression/CompressionCodecGorilla.cpp @@ -438,10 +438,14 @@ UInt32 CompressionCodecGorilla::doDecompressData(const char * source, UInt32 sou if (static_cast(2 + bytes_to_skip) > source_size) throw Exception(ErrorCodes::CANNOT_DECOMPRESS, "Cannot decompress Gorilla-encoded data. File has wrong header"); - if (bytes_to_skip >= uncompressed_size) + if (bytes_to_skip > uncompressed_size) throw Exception(ErrorCodes::CANNOT_DECOMPRESS, "Cannot decompress Gorilla-encoded data. File has wrong header"); memcpy(dest, &source[2], bytes_to_skip); + + /// All data is in the skip section when data_bytes_size > uncompressed_size. + if (bytes_to_skip == uncompressed_size) + return uncompressed_size; UInt32 source_size_no_header = source_size - bytes_to_skip - 2; UInt32 uncompressed_size_left = uncompressed_size - bytes_to_skip; switch (bytes_size) diff --git a/tests/queries/0_stateless/03823_gorilla_codec_mismatched_size.reference b/tests/queries/0_stateless/03823_gorilla_codec_mismatched_size.reference new file mode 100644 index 000000000000..02c7b154cc58 --- /dev/null +++ b/tests/queries/0_stateless/03823_gorilla_codec_mismatched_size.reference @@ -0,0 +1,4 @@ +1 +42 +100 +7 diff --git a/tests/queries/0_stateless/03823_gorilla_codec_mismatched_size.sql b/tests/queries/0_stateless/03823_gorilla_codec_mismatched_size.sql new file mode 100644 index 000000000000..963c72add6f4 --- /dev/null +++ b/tests/queries/0_stateless/03823_gorilla_codec_mismatched_size.sql @@ -0,0 +1,31 @@ +-- Gorilla codec with data_bytes_size larger than the column type. +-- When all data fits in the "skip" section (uncompressed_size < data_bytes_size), +-- decompression should still work correctly. + +SET allow_suspicious_codecs = 1; + +DROP TABLE IF EXISTS t_gorilla_mismatched; + +CREATE TABLE t_gorilla_mismatched (c0 Int16 CODEC(Gorilla(4))) ENGINE = MergeTree() ORDER BY tuple(); +INSERT INTO t_gorilla_mismatched (c0) VALUES (1); +SELECT * FROM t_gorilla_mismatched; + +-- Also test with codec pipeline +DROP TABLE IF EXISTS t_gorilla_mismatched; +CREATE TABLE t_gorilla_mismatched (c0 Int16 CODEC(Gorilla(4), ZSTD)) ENGINE = MergeTree() ORDER BY tuple(); +INSERT INTO t_gorilla_mismatched (c0) VALUES (42); +SELECT * FROM t_gorilla_mismatched; + +-- Test with Gorilla(8) on Int16 +DROP TABLE IF EXISTS t_gorilla_mismatched; +CREATE TABLE t_gorilla_mismatched (c0 Int16 CODEC(Gorilla(8))) ENGINE = MergeTree() ORDER BY tuple(); +INSERT INTO t_gorilla_mismatched (c0) VALUES (100); +SELECT * FROM t_gorilla_mismatched; + +-- Test with compact parts (the original issue scenario) +DROP TABLE IF EXISTS t_gorilla_mismatched; +CREATE TABLE t_gorilla_mismatched (c0 Int16 CODEC(Gorilla(4))) ENGINE = MergeTree() ORDER BY tuple() SETTINGS min_bytes_for_wide_part = 10000000000; +INSERT INTO t_gorilla_mismatched (c0) VALUES (7); +SELECT * FROM t_gorilla_mismatched; + +DROP TABLE IF EXISTS t_gorilla_mismatched;