This is an automated email from the ASF dual-hosted git repository. lihaopeng pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new 3d13dbefeb7 [Enhancement] Support some compress functions (#47307) 3d13dbefeb7 is described below commit 3d13dbefeb74c6be7be3bc509c696320823526df Author: lzyy2024 <2972013...@qq.com> AuthorDate: Fri Feb 7 10:26:22 2025 +0800 [Enhancement] Support some compress functions (#47307) Added the compress and uncompressed functions similar to mysql --- be/src/vec/functions/function_compress.cpp | 209 +++++++++++++++++++++ be/src/vec/functions/simple_function_factory.h | 2 + .../doris/catalog/BuiltinScalarFunctions.java | 6 +- .../expressions/functions/scalar/Compress.java | 69 +++++++ .../expressions/functions/scalar/Uncompress.java | 69 +++++++ .../expressions/visitor/ScalarFunctionVisitor.java | 10 + .../string_functions/test_compress_uncompress.out | Bin 0 -> 741 bytes .../test_compress_uncompress.groovy | 139 ++++++++++++++ 8 files changed, 503 insertions(+), 1 deletion(-) diff --git a/be/src/vec/functions/function_compress.cpp b/be/src/vec/functions/function_compress.cpp new file mode 100644 index 00000000000..4c175a5fd44 --- /dev/null +++ b/be/src/vec/functions/function_compress.cpp @@ -0,0 +1,209 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +#include <glog/logging.h> + +#include <array> +#include <cctype> +#include <cstddef> +#include <cstring> +#include <functional> +#include <memory> +#include <string> +#include <utility> + +#include "common/status.h" +#include "util/block_compression.h" +#include "util/faststring.h" +#include "vec/aggregate_functions/aggregate_function.h" +#include "vec/columns/column.h" +#include "vec/columns/column_nullable.h" +#include "vec/columns/column_string.h" +#include "vec/columns/column_vector.h" +#include "vec/columns/columns_number.h" +#include "vec/common/assert_cast.h" +#include "vec/core/block.h" +#include "vec/core/column_numbers.h" +#include "vec/core/column_with_type_and_name.h" +#include "vec/core/types.h" +#include "vec/data_types/data_type.h" +#include "vec/data_types/data_type_nullable.h" +#include "vec/data_types/data_type_number.h" +#include "vec/data_types/data_type_string.h" +#include "vec/functions/function.h" +#include "vec/functions/simple_function_factory.h" + +namespace doris { +class FunctionContext; +} // namespace doris + +namespace doris::vectorized { + +class FunctionCompress : public IFunction { +public: + static constexpr auto name = "compress"; + static FunctionPtr create() { return std::make_shared<FunctionCompress>(); } + + String get_name() const override { return name; } + + size_t get_number_of_arguments() const override { return 1; } + + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + return std::make_shared<DataTypeString>(); + } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + uint32_t result, size_t input_rows_count) const override { + // Get the compression algorithm object + BlockCompressionCodec* compression_codec; + RETURN_IF_ERROR(get_block_compression_codec(segment_v2::CompressionTypePB::ZLIB, + &compression_codec)); + + const auto& arg_column = + assert_cast<const ColumnString&>(*block.get_by_position(arguments[0]).column); + auto result_column = ColumnString::create(); + + auto& arg_data = arg_column.get_chars(); + auto& arg_offset = arg_column.get_offsets(); + const char* arg_begin = reinterpret_cast<const char*>(arg_data.data()); + + auto& col_data = result_column->get_chars(); + auto& col_offset = result_column->get_offsets(); + col_offset.resize(input_rows_count); + + faststring compressed_str; + Slice data; + + // When the original string is large, the result is roughly this value + size_t total = arg_offset[input_rows_count - 1]; + col_data.reserve(total / 1000); + + for (size_t row = 0; row < input_rows_count; row++) { + uint32_t length = arg_offset[row] - arg_offset[row - 1]; + data = Slice(arg_begin + arg_offset[row - 1], length); + + size_t idx = col_data.size(); + if (!length) { // data is '' + col_offset[row] = col_offset[row - 1]; + continue; + } + + // Z_MEM_ERROR and Z_BUF_ERROR are already handled in compress, making sure st is always Z_OK + auto st = compression_codec->compress(data, &compressed_str); + col_data.resize(col_data.size() + 4 + compressed_str.size()); + + std::memcpy(col_data.data() + idx, &length, sizeof(length)); + idx += 4; + + // The length of compress_str is not known in advance, so it cannot be compressed directly into col_data + unsigned char* src = compressed_str.data(); + for (size_t i = 0; i < compressed_str.size(); idx++, i++, src++) { + col_data[idx] = *src; + } + col_offset[row] = col_offset[row - 1] + 10 + compressed_str.size(); + } + + block.replace_by_position(result, std::move(result_column)); + return Status::OK(); + } +}; + +class FunctionUncompress : public IFunction { +public: + static constexpr auto name = "uncompress"; + static FunctionPtr create() { return std::make_shared<FunctionUncompress>(); } + + String get_name() const override { return name; } + + size_t get_number_of_arguments() const override { return 1; } + + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + return make_nullable(std::make_shared<DataTypeString>()); + } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + uint32_t result, size_t input_rows_count) const override { + // Get the compression algorithm object + BlockCompressionCodec* compression_codec; + RETURN_IF_ERROR(get_block_compression_codec(segment_v2::CompressionTypePB::ZLIB, + &compression_codec)); + + const auto& arg_column = + assert_cast<const ColumnString&>(*block.get_by_position(arguments[0]).column); + + auto& arg_data = arg_column.get_chars(); + auto& arg_offset = arg_column.get_offsets(); + const char* arg_begin = reinterpret_cast<const char*>(arg_data.data()); + + auto result_column = ColumnString::create(); + auto& col_data = result_column->get_chars(); + auto& col_offset = result_column->get_offsets(); + col_offset.resize(input_rows_count); + + auto null_column = ColumnUInt8::create(input_rows_count); + auto& null_map = null_column->get_data(); + + std::string uncompressed; + Slice data; + Slice uncompressed_slice; + + size_t total = arg_offset[input_rows_count - 1]; + col_data.reserve(total * 1000); + + for (size_t row = 0; row < input_rows_count; row++) { + null_map[row] = false; + data = Slice(arg_begin + arg_offset[row - 1], arg_offset[row] - arg_offset[row - 1]); + size_t data_length = arg_offset[row] - arg_offset[row - 1]; + + if (data_length == 0) { // The original data is '' + col_offset[row] = col_offset[row - 1]; + continue; + } + + union { + char bytes[4]; + uint32_t value; + } length; + std::memcpy(length.bytes, data.data, 4); + + size_t idx = col_data.size(); + col_data.resize(col_data.size() + length.value); + uncompressed_slice = Slice(col_data.data() + idx, length.value); + + Slice compressed_data(data.data + 4, data.size - 4); + auto st = compression_codec->decompress(compressed_data, &uncompressed_slice); + + if (!st.ok()) { // is not a legal compressed string + col_data.resize(col_data.size() - length.value); // remove compressed_data + col_offset[row] = col_offset[row - 1]; + null_map[row] = true; + continue; + } + col_offset[row] = col_offset[row - 1] + length.value; + } + + block.replace_by_position( + result, ColumnNullable::create(std::move(result_column), std::move(null_column))); + return Status::OK(); + } +}; + +void register_function_compress(SimpleFunctionFactory& factory) { + factory.register_function<FunctionCompress>(); + factory.register_function<FunctionUncompress>(); +} + +} // namespace doris::vectorized diff --git a/be/src/vec/functions/simple_function_factory.h b/be/src/vec/functions/simple_function_factory.h index 98f2917d163..46eca0cb419 100644 --- a/be/src/vec/functions/simple_function_factory.h +++ b/be/src/vec/functions/simple_function_factory.h @@ -110,6 +110,7 @@ void register_function_ip(SimpleFunctionFactory& factory); void register_function_multi_match(SimpleFunctionFactory& factory); void register_function_split_by_regexp(SimpleFunctionFactory& factory); void register_function_assert_true(SimpleFunctionFactory& factory); +void register_function_compress(SimpleFunctionFactory& factory); void register_function_bit_test(SimpleFunctionFactory& factory); class SimpleFunctionFactory { @@ -301,6 +302,7 @@ public: register_function_split_by_regexp(instance); register_function_assert_true(instance); register_function_bit_test(instance); + register_function_compress(instance); }); return instance; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java index c3c344436ee..e482b419ac5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java @@ -120,6 +120,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Ceil; import org.apache.doris.nereids.trees.expressions.functions.scalar.Char; import org.apache.doris.nereids.trees.expressions.functions.scalar.CharacterLength; import org.apache.doris.nereids.trees.expressions.functions.scalar.Coalesce; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Compress; import org.apache.doris.nereids.trees.expressions.functions.scalar.Concat; import org.apache.doris.nereids.trees.expressions.functions.scalar.ConcatWs; import org.apache.doris.nereids.trees.expressions.functions.scalar.ConnectionId; @@ -451,6 +452,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Translate; import org.apache.doris.nereids.trees.expressions.functions.scalar.Trim; import org.apache.doris.nereids.trees.expressions.functions.scalar.TrimIn; import org.apache.doris.nereids.trees.expressions.functions.scalar.Truncate; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Uncompress; import org.apache.doris.nereids.trees.expressions.functions.scalar.Unhex; import org.apache.doris.nereids.trees.expressions.functions.scalar.UnixTimestamp; import org.apache.doris.nereids.trees.expressions.functions.scalar.Upper; @@ -978,7 +980,9 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(YearsSub.class, "years_sub"), scalar(MultiMatch.class, "multi_match"), scalar(SessionUser.class, "session_user"), - scalar(LastQueryId.class, "last_query_id")); + scalar(LastQueryId.class, "last_query_id"), + scalar(Compress.class, "compress"), + scalar(Uncompress.class, "uncompress")); public static final BuiltinScalarFunctions INSTANCE = new BuiltinScalarFunctions(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Compress.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Compress.java new file mode 100644 index 00000000000..9422d72bca7 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Compress.java @@ -0,0 +1,69 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.trees.expressions.functions.scalar; + +import org.apache.doris.catalog.FunctionSignature; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable; +import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression; +import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; +import org.apache.doris.nereids.types.StringType; +import org.apache.doris.nereids.types.VarcharType; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * ScalarFunction 'compress'. + */ +public class Compress extends ScalarFunction + implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullable { + + public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( + FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(VarcharType.SYSTEM_DEFAULT), + FunctionSignature.ret(StringType.INSTANCE).args(StringType.INSTANCE)); + + /** + * constructor with 1 argument. + */ + public Compress(Expression arg) { + super("compress", arg); + } + + /** + * withChildren. + */ + @Override + public Compress withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 1); + return new Compress(children.get(0)); + } + + @Override + public List<FunctionSignature> getSignatures() { + return SIGNATURES; + } + + @Override + public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { + return visitor.visitCompress(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uncompress.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uncompress.java new file mode 100644 index 00000000000..8726963f486 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uncompress.java @@ -0,0 +1,69 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.trees.expressions.functions.scalar; + +import org.apache.doris.catalog.FunctionSignature; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable; +import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression; +import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; +import org.apache.doris.nereids.types.StringType; +import org.apache.doris.nereids.types.VarcharType; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * ScalarFunction 'uncompress'. + */ +public class Uncompress extends ScalarFunction + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNullable { + + public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( + FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(VarcharType.SYSTEM_DEFAULT), + FunctionSignature.ret(StringType.INSTANCE).args(StringType.INSTANCE)); + + /** + * constructor with 1 argument. + */ + public Uncompress(Expression arg) { + super("uncompress", arg); + } + + /** + * withChildren. + */ + @Override + public Uncompress withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 1); + return new Uncompress(children.get(0)); + } + + @Override + public List<FunctionSignature> getSignatures() { + return SIGNATURES; + } + + @Override + public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { + return visitor.visitUncompress(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java index 5a57688302e..4346fb71591 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java @@ -127,6 +127,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Ceil; import org.apache.doris.nereids.trees.expressions.functions.scalar.Char; import org.apache.doris.nereids.trees.expressions.functions.scalar.CharacterLength; import org.apache.doris.nereids.trees.expressions.functions.scalar.Coalesce; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Compress; import org.apache.doris.nereids.trees.expressions.functions.scalar.Concat; import org.apache.doris.nereids.trees.expressions.functions.scalar.ConcatWs; import org.apache.doris.nereids.trees.expressions.functions.scalar.ConnectionId; @@ -448,6 +449,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Translate; import org.apache.doris.nereids.trees.expressions.functions.scalar.Trim; import org.apache.doris.nereids.trees.expressions.functions.scalar.TrimIn; import org.apache.doris.nereids.trees.expressions.functions.scalar.Truncate; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Uncompress; import org.apache.doris.nereids.trees.expressions.functions.scalar.Unhex; import org.apache.doris.nereids.trees.expressions.functions.scalar.UnixTimestamp; import org.apache.doris.nereids.trees.expressions.functions.scalar.Upper; @@ -2338,4 +2340,12 @@ public interface ScalarFunctionVisitor<R, C> { default R visitLastQueryId(LastQueryId queryId, C context) { return visitScalarFunction(queryId, context); } + + default R visitCompress(Compress compress, C context) { + return visitScalarFunction(compress, context); + } + + default R visitUncompress(Uncompress uncompress, C context) { + return visitScalarFunction(uncompress, context); + } } diff --git a/regression-test/data/query_p0/sql_functions/string_functions/test_compress_uncompress.out b/regression-test/data/query_p0/sql_functions/string_functions/test_compress_uncompress.out new file mode 100644 index 00000000000..be60951c955 Binary files /dev/null and b/regression-test/data/query_p0/sql_functions/string_functions/test_compress_uncompress.out differ diff --git a/regression-test/suites/query_p0/sql_functions/string_functions/test_compress_uncompress.groovy b/regression-test/suites/query_p0/sql_functions/string_functions/test_compress_uncompress.groovy new file mode 100644 index 00000000000..9c4df7b1ec9 --- /dev/null +++ b/regression-test/suites/query_p0/sql_functions/string_functions/test_compress_uncompress.groovy @@ -0,0 +1,139 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_compress_uncompress") { + // Drop the existing table + sql "DROP TABLE IF EXISTS test_compression" + + // Create the test table + sql """ + CREATE TABLE test_compression ( + k0 INT, -- Primary key + text_col STRING, -- String column for input data + binary_col STRING -- Binary column for compressed data + ) + DISTRIBUTED BY HASH(k0) + PROPERTIES ( + "replication_num" = "1" + ); + """ + + // Insert test data with various cases + sql """ + INSERT INTO test_compression VALUES + (1, 'Hello, world!', COMPRESS('Hello, world!')), -- Plain string + (2, 'Doris测试中文字符', COMPRESS('Doris测试中文字符')), -- Chinese characters + (3, NULL, NULL), -- Null values + (4, '', COMPRESS('')), -- Empty string + (5, NULL, 'invalid_compressed_data'), -- Invalid binary data + (6, REPEAT('a', 50), COMPRESS(REPEAT('a', 50))); -- Short repeated string + """ + + // Test 1: Verify that UNCOMPRESS can correctly restore the original data + order_qt_restore_original_data """ + SELECT + k0, + UNCOMPRESS(binary_col) AS decompressed_data + FROM test_compression + WHERE binary_col IS NOT NULL + ORDER BY k0; + """ + + // Test 2: Verify that UNCOMPRESS returns NULL for NULL input + order_qt_uncompress_null_input """ + SELECT + k0, + UNCOMPRESS(binary_col) AS decompressed_data + FROM test_compression + WHERE binary_col IS NULL + ORDER BY k0; + """ + + // Test 3: Verify that UNCOMPRESS handles invalid binary data gracefully + order_qt_uncompress_invalid_data """ + SELECT + k0, + UNCOMPRESS(binary_col) AS decompressed_data + FROM test_compression + WHERE k0 = 5 + ORDER BY k0; + """ + + // Test 4: Verify that COMPRESS and UNCOMPRESS work correctly with empty strings + order_qt_compress_empty_string """ + SELECT + k0, + UNCOMPRESS(binary_col) AS decompressed_data + FROM test_compression + WHERE k0 = 4 + ORDER BY k0; + """ + + // Test 5: Verify that COMPRESS and UNCOMPRESS work correctly with repeated strings + order_qt_compress_repeated_string """ + SELECT + k0, + UNCOMPRESS(binary_col) AS decompressed_data + FROM test_compression + WHERE k0 = 6 + ORDER BY k0; + """ + + // Additional tests using SELECT UNCOMPRESS(COMPRESS()) directly + + // Test 6: Verify that COMPRESS and UNCOMPRESS work with a single character string + order_qt_compress_single_char """ + SELECT + UNCOMPRESS(COMPRESS('x')) AS decompressed_data + LIMIT 1; + """ + + // Test 7: Verify that COMPRESS handles NULL text values correctly + order_qt_compress_null_text """ + SELECT + UNCOMPRESS(COMPRESS(NULL)) AS decompressed_data + LIMIT 1; + """ + + // Test 8: Verify that COMPRESS and UNCOMPRESS work with long repeated strings + order_qt_compress_large_repeated_string """ + SELECT + UNCOMPRESS(COMPRESS(REPEAT('a', 100))) AS decompressed_data + LIMIT 1; + """ + + // Test 9: Verify that COMPRESS and UNCOMPRESS work with an empty string + order_qt_compress_empty_string_direct """ + SELECT + UNCOMPRESS(COMPRESS('')) AS decompressed_data + LIMIT 1; + """ + + // Test 10: Verify that COMPRESS and UNCOMPRESS work with the string 'Hello, world!' + order_qt_compress_string_direct """ + SELECT + UNCOMPRESS(COMPRESS('Hello, world!')) AS decompressed_data + LIMIT 1; + """ + + // Test 11: Verify that COMPRESS and UNCOMPRESS work with a numeric value + order_qt_compress_numeric_direct """ + SELECT + UNCOMPRESS(COMPRESS('12345')) AS decompressed_data + LIMIT 1; + """ +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org