This is an automated email from the ASF dual-hosted git repository. kxiao pushed a commit to branch branch-2.0 in repository https://gitbox.apache.org/repos/asf/doris.git
commit bd3ee3ebdca08743c14ac62f971929f7d98aee68 Author: zclllyybb <zhaochan...@selectdb.com> AuthorDate: Wed Sep 20 17:21:45 2023 +0800 [feature](function) Support SHA family functions (#24342) --- be/src/util/sha.cpp | 118 +++++++++++++++++++++ be/src/util/sha.h | 75 +++++++++++++ be/src/vec/functions/function_string.cpp | 11 +- be/src/vec/functions/function_string.h | 107 ++++++++++++++++++- .../sql-functions/encrypt-digest-functions/sha.md | 53 +++++++++ .../sql-functions/encrypt-digest-functions/sha2.md | 70 ++++++++++++ docs/sidebars.json | 4 +- .../sql-functions/encrypt-digest-functions/sha.md | 54 ++++++++++ .../sql-functions/encrypt-digest-functions/sha2.md | 70 ++++++++++++ .../apache/doris/analysis/FunctionCallExpr.java | 13 +++ .../doris/catalog/BuiltinScalarFunctions.java | 4 + .../trees/expressions/functions/scalar/Sha1.java | 68 ++++++++++++ .../trees/expressions/functions/scalar/Sha2.java | 69 ++++++++++++ .../expressions/visitor/ScalarFunctionVisitor.java | 10 ++ gensrc/script/doris_builtins_functions.py | 7 ++ .../encryption_digest/test_digest.out | 39 +++++++ .../sql_functions/encryption_digest/test_md5.out | 6 -- .../{test_md5.groovy => test_digest.groovy} | 19 +++- 18 files changed, 781 insertions(+), 16 deletions(-) diff --git a/be/src/util/sha.cpp b/be/src/util/sha.cpp new file mode 100644 index 00000000000..68099ff9269 --- /dev/null +++ b/be/src/util/sha.cpp @@ -0,0 +1,118 @@ +// 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 "util/sha.h" + +#include <openssl/sha.h> + +#include <string_view> + +namespace doris { + +constexpr static char dig_vec_lower[] = "0123456789abcdef"; + +void SHA1Digest::reset(const void* data, size_t length) { + SHA1_Init(&_sha_ctx); + SHA1_Update(&_sha_ctx, data, length); +} + +std::string_view SHA1Digest::digest() { + unsigned char buf[SHA_DIGEST_LENGTH]; + SHA1_Final(buf, &_sha_ctx); + + char* to = _reuse_hex; + for (int i = 0; i < SHA_DIGEST_LENGTH; ++i) { + *to++ = dig_vec_lower[buf[i] >> 4]; + *to++ = dig_vec_lower[buf[i] & 0x0F]; + } + + return std::string_view {_reuse_hex, _reuse_hex + 2 * SHA_DIGEST_LENGTH}; +} + +void SHA224Digest::reset(const void* data, size_t length) { + SHA224_Init(&_sha224_ctx); + SHA224_Update(&_sha224_ctx, data, length); +} + +std::string_view SHA224Digest::digest() { + unsigned char buf[SHA224_DIGEST_LENGTH]; + SHA224_Final(buf, &_sha224_ctx); + + char* to = _reuse_hex; + for (int i = 0; i < SHA224_DIGEST_LENGTH; ++i) { + *to++ = dig_vec_lower[buf[i] >> 4]; + *to++ = dig_vec_lower[buf[i] & 0x0F]; + } + + return std::string_view {_reuse_hex, _reuse_hex + 2 * SHA224_DIGEST_LENGTH}; +} + +void SHA256Digest::reset(const void* data, size_t length) { + SHA256_Init(&_sha256_ctx); + SHA256_Update(&_sha256_ctx, data, length); +} + +std::string_view SHA256Digest::digest() { + unsigned char buf[SHA256_DIGEST_LENGTH]; + SHA256_Final(buf, &_sha256_ctx); + + char* to = _reuse_hex; + for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) { + *to++ = dig_vec_lower[buf[i] >> 4]; + *to++ = dig_vec_lower[buf[i] & 0x0F]; + } + + return std::string_view {_reuse_hex, _reuse_hex + 2 * SHA256_DIGEST_LENGTH}; +} + +void SHA384Digest::reset(const void* data, size_t length) { + SHA384_Init(&_sha384_ctx); + SHA384_Update(&_sha384_ctx, data, length); +} + +std::string_view SHA384Digest::digest() { + unsigned char buf[SHA384_DIGEST_LENGTH]; + SHA384_Final(buf, &_sha384_ctx); + + char* to = _reuse_hex; + for (int i = 0; i < SHA384_DIGEST_LENGTH; ++i) { + *to++ = dig_vec_lower[buf[i] >> 4]; + *to++ = dig_vec_lower[buf[i] & 0x0F]; + } + + return std::string_view {_reuse_hex, _reuse_hex + 2 * SHA384_DIGEST_LENGTH}; +} + +void SHA512Digest::reset(const void* data, size_t length) { + SHA512_Init(&_sha512_ctx); + SHA512_Update(&_sha512_ctx, data, length); +} + +std::string_view SHA512Digest::digest() { + unsigned char buf[SHA512_DIGEST_LENGTH]; + SHA512_Final(buf, &_sha512_ctx); + + char* to = _reuse_hex; + for (int i = 0; i < SHA512_DIGEST_LENGTH; ++i) { + *to++ = dig_vec_lower[buf[i] >> 4]; + *to++ = dig_vec_lower[buf[i] & 0x0F]; + } + + return std::string_view {_reuse_hex, _reuse_hex + 2 * SHA512_DIGEST_LENGTH}; +} + +} // namespace doris diff --git a/be/src/util/sha.h b/be/src/util/sha.h new file mode 100644 index 00000000000..1545dd3c031 --- /dev/null +++ b/be/src/util/sha.h @@ -0,0 +1,75 @@ +// 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. + +#pragma once + +#include <openssl/sha.h> + +#include <string_view> + +namespace doris { + +class SHA1Digest { +public: + void reset(const void* data, size_t length); + std::string_view digest(); + +private: + SHA_CTX _sha_ctx; + char _reuse_hex[2 * SHA_DIGEST_LENGTH]; +}; + +class SHA224Digest { +public: + void reset(const void* data, size_t length); + std::string_view digest(); + +private: + SHA256_CTX _sha224_ctx; + char _reuse_hex[2 * SHA224_DIGEST_LENGTH]; +}; + +class SHA256Digest { +public: + void reset(const void* data, size_t length); + std::string_view digest(); + +private: + SHA256_CTX _sha256_ctx; + char _reuse_hex[2 * SHA256_DIGEST_LENGTH]; +}; + +class SHA384Digest { +public: + void reset(const void* data, size_t length); + std::string_view digest(); + +private: + SHA512_CTX _sha384_ctx; + char _reuse_hex[2 * SHA384_DIGEST_LENGTH]; +}; + +class SHA512Digest { +public: + void reset(const void* data, size_t length); + std::string_view digest(); + +private: + SHA512_CTX _sha512_ctx; + char _reuse_hex[2 * SHA512_DIGEST_LENGTH]; +}; +} // namespace doris diff --git a/be/src/vec/functions/function_string.cpp b/be/src/vec/functions/function_string.cpp index 5812c7badbf..df9f28a5798 100644 --- a/be/src/vec/functions/function_string.cpp +++ b/be/src/vec/functions/function_string.cpp @@ -972,7 +972,6 @@ void register_function_string(SimpleFunctionFactory& factory) { factory.register_function<FunctionFromBase64>(); factory.register_function<FunctionSplitPart>(); factory.register_function<FunctionSplitByString>(); - factory.register_function<FunctionStringMd5AndSM3<MD5Sum>>(); factory.register_function<FunctionSubstringIndex>(); factory.register_function<FunctionExtractURLParameter>(); factory.register_function<FunctionStringParseUrl>(); @@ -980,7 +979,10 @@ void register_function_string(SimpleFunctionFactory& factory) { factory.register_function<FunctionMoneyFormat<MoneyFormatInt64Impl>>(); factory.register_function<FunctionMoneyFormat<MoneyFormatInt128Impl>>(); factory.register_function<FunctionMoneyFormat<MoneyFormatDecimalImpl>>(); - factory.register_function<FunctionStringMd5AndSM3<SM3Sum>>(); + factory.register_function<FunctionStringDigestOneArg<SM3Sum>>(); + factory.register_function<FunctionStringDigestOneArg<MD5Sum>>(); + factory.register_function<FunctionStringDigestSHA1>(); + factory.register_function<FunctionStringDigestSHA2>(); factory.register_function<FunctionReplace>(); factory.register_function<FunctionMask>(); factory.register_function<FunctionMaskPartial<true>>(); @@ -993,9 +995,10 @@ void register_function_string(SimpleFunctionFactory& factory) { factory.register_alias(SubstringUtil::name, "substr"); factory.register_alias(FunctionToLower::name, "lcase"); factory.register_alias(FunctionToUpper::name, "ucase"); - factory.register_alias(FunctionStringMd5AndSM3<MD5Sum>::name, "md5"); + factory.register_alias(FunctionStringDigestOneArg<MD5Sum>::name, "md5"); factory.register_alias(FunctionStringUTF8Length::name, "character_length"); - factory.register_alias(FunctionStringMd5AndSM3<SM3Sum>::name, "sm3"); + factory.register_alias(FunctionStringDigestOneArg<SM3Sum>::name, "sm3"); + factory.register_alias(FunctionStringDigestSHA1::name, "sha"); /// @TEMPORARY: for be_exec_version=2 factory.register_alternative_function<FunctionStringEltOld>(); diff --git a/be/src/vec/functions/function_string.h b/be/src/vec/functions/function_string.h index 32e373ffa05..37a21a3ea5b 100644 --- a/be/src/vec/functions/function_string.h +++ b/be/src/vec/functions/function_string.h @@ -41,6 +41,7 @@ #include "runtime/decimalv2_value.h" #include "runtime/runtime_state.h" #include "runtime/string_search.hpp" +#include "util/sha.h" #include "util/string_util.h" #include "util/utf8_check.h" #include "vec/aggregate_functions/aggregate_function.h" @@ -1980,10 +1981,10 @@ struct MD5Sum { }; template <typename Impl> -class FunctionStringMd5AndSM3 : public IFunction { +class FunctionStringDigestOneArg : public IFunction { public: static constexpr auto name = Impl::name; - static FunctionPtr create() { return std::make_shared<FunctionStringMd5AndSM3>(); } + static FunctionPtr create() { return std::make_shared<FunctionStringDigestOneArg>(); } String get_name() const override { return name; } size_t get_number_of_arguments() const override { return 0; } bool is_variadic() const override { return true; } @@ -1991,7 +1992,6 @@ public: DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { return std::make_shared<DataTypeString>(); } - bool use_default_implementation_for_nulls() const override { return true; } Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, size_t result, size_t input_rows_count) override { @@ -2045,6 +2045,107 @@ public: } }; +class FunctionStringDigestSHA1 : public IFunction { +public: + static constexpr auto name = "sha1"; + static FunctionPtr create() { return std::make_shared<FunctionStringDigestSHA1>(); } + String get_name() const override { return name; } + size_t get_number_of_arguments() const override { return 1; } + bool is_variadic() const override { return true; } + + 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, + size_t result, size_t input_rows_count) override { + DCHECK_EQ(arguments.size(), 1); + + ColumnPtr str_col = block.get_by_position(arguments[0]).column; + auto& data = assert_cast<const ColumnString*>(str_col.get())->get_chars(); + auto& offset = assert_cast<const ColumnString*>(str_col.get())->get_offsets(); + + auto res_col = ColumnString::create(); + auto& res_data = res_col->get_chars(); + auto& res_offset = res_col->get_offsets(); + res_offset.resize(input_rows_count); + + SHA1Digest digest; + for (size_t i = 0; i < input_rows_count; ++i) { + int size = offset[i] - offset[i - 1]; + digest.reset(&data[offset[i - 1]], size); + std::string_view ans = digest.digest(); + + StringOP::push_value_string(ans, i, res_data, res_offset); + } + + block.replace_by_position(result, std::move(res_col)); + return Status::OK(); + } +}; + +class FunctionStringDigestSHA2 : public IFunction { +public: + static constexpr auto name = "sha2"; + static FunctionPtr create() { return std::make_shared<FunctionStringDigestSHA2>(); } + String get_name() const override { return name; } + size_t get_number_of_arguments() const override { return 2; } + bool is_variadic() const override { return true; } + + 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, + size_t result, size_t input_rows_count) override { + DCHECK(!is_column_const(*block.get_by_position(arguments[0]).column)); + + ColumnPtr str_col = block.get_by_position(arguments[0]).column; + auto& data = assert_cast<const ColumnString*>(str_col.get())->get_chars(); + auto& offset = assert_cast<const ColumnString*>(str_col.get())->get_offsets(); + + [[maybe_unused]] const auto& [right_column, right_const] = + unpack_if_const(block.get_by_position(arguments[1]).column); + auto digest_length = assert_cast<const ColumnInt32*>(right_column.get())->get_data()[0]; + + auto res_col = ColumnString::create(); + auto& res_data = res_col->get_chars(); + auto& res_offset = res_col->get_offsets(); + res_offset.resize(input_rows_count); + + if (digest_length == 224) { + execute_base<SHA224Digest>(data, offset, input_rows_count, res_data, res_offset); + } else if (digest_length == 256) { + execute_base<SHA256Digest>(data, offset, input_rows_count, res_data, res_offset); + } else if (digest_length == 384) { + execute_base<SHA384Digest>(data, offset, input_rows_count, res_data, res_offset); + } else if (digest_length == 512) { + execute_base<SHA512Digest>(data, offset, input_rows_count, res_data, res_offset); + } else { + return Status::InvalidArgument( + "sha2's digest length only support 224/256/384/512 but meet {}", digest_length); + } + + block.replace_by_position(result, std::move(res_col)); + return Status::OK(); + } + +private: + template <typename T> + void execute_base(const ColumnString::Chars& data, const ColumnString::Offsets& offset, + int input_rows_count, ColumnString::Chars& res_data, + ColumnString::Offsets& res_offset) { + T digest; + for (size_t i = 0; i < input_rows_count; ++i) { + int size = offset[i] - offset[i - 1]; + digest.reset(&data[offset[i - 1]], size); + std::string_view ans = digest.digest(); + + StringOP::push_value_string(ans, i, res_data, res_offset); + } + } +}; + class FunctionExtractURLParameter : public IFunction { public: static constexpr auto name = "extract_url_parameter"; diff --git a/docs/en/docs/sql-manual/sql-functions/encrypt-digest-functions/sha.md b/docs/en/docs/sql-manual/sql-functions/encrypt-digest-functions/sha.md new file mode 100644 index 00000000000..8e9a4573c1c --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/encrypt-digest-functions/sha.md @@ -0,0 +1,53 @@ +--- +{ +"title": "SHA", +"language": "en" +} +--- + +<!-- +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. +--> + +## SHA + +### description + +Use SHA1 to digest the message. + +#### Syntax + +`SHA(str)` or `SHA1(str)` + +#### Arguments + +- `str`: content to be encrypted + +### example + +```SQL +mysql> select sha("123"); ++------------------------------------------+ +| sha1('123') | ++------------------------------------------+ +| 40bd001563085fc35165329ea1ff5c5ecbdbbeef | ++------------------------------------------+ +1 row in set (0.13 sec) +``` + +### keywords + + SHA,SHA1 diff --git a/docs/en/docs/sql-manual/sql-functions/encrypt-digest-functions/sha2.md b/docs/en/docs/sql-manual/sql-functions/encrypt-digest-functions/sha2.md new file mode 100644 index 00000000000..2f7f838b1ff --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/encrypt-digest-functions/sha2.md @@ -0,0 +1,70 @@ +--- +{ +"title": "SHA2", +"language": "en" +} +--- + +<!-- +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. +--> + +## SHA2 + +### description + +Use SHA2 to digest the message. + +#### Syntax + +`SHA2(str, digest_length)` + +#### Arguments + +- `str`: content to be encrypted +- `digest_length`: the length of the digest + +### example + +```SQL +mysql> select sha2('abc', 224); ++----------------------------------------------------------+ +| sha2('abc', 224) | ++----------------------------------------------------------+ +| 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 | ++----------------------------------------------------------+ +1 row in set (0.13 sec) + +mysql> select sha2('abc', 384); ++--------------------------------------------------------------------------------------------------+ +| sha2('abc', 384) | ++--------------------------------------------------------------------------------------------------+ +| cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 | ++--------------------------------------------------------------------------------------------------+ +1 row in set (0.13 sec) + +mysql> select sha2(NULL, 512); ++-----------------+ +| sha2(NULL, 512) | ++-----------------+ +| NULL | ++-----------------+ +1 row in set (0.09 sec) +``` + +### keywords + + SHA2 diff --git a/docs/sidebars.json b/docs/sidebars.json index 089f0022d75..c6acf27aea3 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -690,7 +690,9 @@ "sql-manual/sql-functions/encrypt-digest-functions/md5sum", "sql-manual/sql-functions/encrypt-digest-functions/sm4", "sql-manual/sql-functions/encrypt-digest-functions/sm3", - "sql-manual/sql-functions/encrypt-digest-functions/sm3sum" + "sql-manual/sql-functions/encrypt-digest-functions/sm3sum", + "sql-manual/sql-functions/encrypt-digest-functions/sha", + "sql-manual/sql-functions/encrypt-digest-functions/sha2" ] }, { diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/encrypt-digest-functions/sha.md b/docs/zh-CN/docs/sql-manual/sql-functions/encrypt-digest-functions/sha.md new file mode 100644 index 00000000000..1d0f4d59324 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/encrypt-digest-functions/sha.md @@ -0,0 +1,54 @@ +--- +{ +"title": "SHA", +"language": "zh-CN" +} +--- + +<!-- +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. +--> + +## SHA + +### description + +使用SHA1算法对信息进行摘要处理。 + +#### Syntax + +`SHA(str)` 或 `SHA1(str)` + +#### Arguments + +- `str`: 待加密的内容 + +### example + +```SQL +mysql> select sha("123"); ++------------------------------------------+ +| sha1('123') | ++------------------------------------------+ +| 40bd001563085fc35165329ea1ff5c5ecbdbbeef | ++------------------------------------------+ +1 row in set (0.13 sec) +``` + +### keywords + + SHA,SHA1 + diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/encrypt-digest-functions/sha2.md b/docs/zh-CN/docs/sql-manual/sql-functions/encrypt-digest-functions/sha2.md new file mode 100644 index 00000000000..f4a55f31724 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/encrypt-digest-functions/sha2.md @@ -0,0 +1,70 @@ +--- +{ +"title": "SHA2", +"language": "zh-CN" +} +--- + +<!-- +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. +--> + +## SHA2 + +### description + +使用SHA2对信息进行摘要处理。 + +#### Syntax + +`SHA2(str, digest_length)` + +#### Arguments + +- `str`: 待加密的内容 +- `digest_length`: 摘要长度 + +### example + +```SQL +mysql> select sha2('abc', 224); ++----------------------------------------------------------+ +| sha2('abc', 224) | ++----------------------------------------------------------+ +| 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 | ++----------------------------------------------------------+ +1 row in set (0.13 sec) + +mysql> select sha2('abc', 384); ++--------------------------------------------------------------------------------------------------+ +| sha2('abc', 384) | ++--------------------------------------------------------------------------------------------------+ +| cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 | ++--------------------------------------------------------------------------------------------------+ +1 row in set (0.13 sec) + +mysql> select sha2(NULL, 512); ++-----------------+ +| sha2(NULL, 512) | ++-----------------+ +| NULL | ++-----------------+ +1 row in set (0.09 sec) +``` + +### keywords + + SHA2 diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java index c551250063e..e6dd768267c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java @@ -1743,6 +1743,19 @@ public class FunctionCallExpr extends Expr { } } + if (fn.getFunctionName().getFunction().equals("sha2")) { + if ((children.size() != 2) || (getChild(1).isConstant() == false) + || !(getChild(1) instanceof IntLiteral)) { + throw new AnalysisException( + fnName.getFunction() + " needs two params, and the second is must be a integer constant: " + + this.toSql()); + } + final Integer constParam = (int) ((IntLiteral) getChild(1)).getValue(); + if (!Lists.newArrayList(224, 256, 384, 512).contains(constParam)) { + throw new AnalysisException("sha2 functions only support digest length of 224/256/384/512"); + } + } + if (isAggregateFunction()) { final String functionName = fnName.getFunction(); // subexprs must not contain aggregates 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 71647def182..e87f1ebaa96 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 @@ -281,6 +281,8 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondTimesta import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd; import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsDiff; import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsSub; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Sha1; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Sha2; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sign; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sin; import org.apache.doris.nereids.trees.expressions.functions.scalar.Size; @@ -644,6 +646,8 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(SecondTimestamp.class, "second_timestamp"), scalar(MilliSecondTimestamp.class, "millisecond_timestamp"), scalar(MicroSecondTimestamp.class, "microsecond_timestamp"), + scalar(Sha1.class, "sha1", "sha"), + scalar(Sha2.class, "sha2"), scalar(Sign.class, "sign"), scalar(Sin.class, "sin"), scalar(Size.class, "size"), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Sha1.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Sha1.java new file mode 100644 index 00000000000..b405e544086 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Sha1.java @@ -0,0 +1,68 @@ +// 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.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 'sha1'. This class is not generated by GenerateFunction. + */ +public class Sha1 extends ScalarFunction + implements ExplicitlyCastableSignature, PropagateNullable { + + public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( + FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(VarcharType.SYSTEM_DEFAULT), + FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(StringType.INSTANCE)); + + /** + * constructor with 1 arguments. + */ + public Sha1(Expression arg0) { + super("sha1", arg0); + } + + /** + * withChildren. + */ + @Override + public Sha1 withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 1); + return new Sha1(children.get(0)); + } + + @Override + public List<FunctionSignature> getSignatures() { + return SIGNATURES; + } + + @Override + public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { + return visitor.visitSha1(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Sha2.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Sha2.java new file mode 100644 index 00000000000..2b37e66943d --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Sha2.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.visitor.ExpressionVisitor; +import org.apache.doris.nereids.types.IntegerType; +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 'sha2'. This class is not generated by GenerateFunction. + */ +public class Sha2 extends ScalarFunction + implements ExplicitlyCastableSignature, PropagateNullable { + + public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( + FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(VarcharType.SYSTEM_DEFAULT, IntegerType.INSTANCE), + FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(StringType.INSTANCE, IntegerType.INSTANCE)); + + /** + * constructor with 2 arguments. + */ + public Sha2(Expression arg0, Expression arg1) { + super("sha2", arg0, arg1); + } + + /** + * withChildren. + */ + @Override + public Sha2 withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 2); + return new Sha2(children.get(0), children.get(1)); + } + + @Override + public List<FunctionSignature> getSignatures() { + return SIGNATURES; + } + + @Override + public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { + return visitor.visitSha2(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 75f1ea6ae31..5a12d755c50 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 @@ -276,6 +276,8 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondFloor; import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd; import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsDiff; import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsSub; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Sha1; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Sha2; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sign; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sin; import org.apache.doris.nereids.trees.expressions.functions.scalar.Size; @@ -1396,6 +1398,14 @@ public interface ScalarFunctionVisitor<R, C> { return visitScalarFunction(secondsDiff, context); } + default R visitSha1(Sha1 sha1, C context) { + return visitScalarFunction(sha1, context); + } + + default R visitSha2(Sha2 sha2, C context) { + return visitScalarFunction(sha2, context); + } + default R visitMilliSecondsDiff(MilliSecondsDiff milliSecondsDiff, C context) { return visitScalarFunction(milliSecondsDiff, context); } diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py index 8e5ed56d0ff..f9b1c883313 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -1895,6 +1895,13 @@ visible_functions = { [['sm3sum'], 'VARCHAR', ['VARCHAR', '...'], ''], [['sm3'], 'VARCHAR', ['STRING'], ''], [['sm3sum'], 'VARCHAR', ['STRING', '...'], ''], + + [['sha'], 'VARCHAR', ['VARCHAR'], ''], + [['sha'], 'VARCHAR', ['STRING'], ''], + [['sha1'], 'VARCHAR', ['VARCHAR'], ''], + [['sha1'], 'VARCHAR', ['STRING'], ''], + [['sha2'], 'VARCHAR', ['VARCHAR', 'INT'], ''], + [['sha2'], 'VARCHAR', ['STRING', 'INT'], ''], ], # geo functions diff --git a/regression-test/data/query_p0/sql_functions/encryption_digest/test_digest.out b/regression-test/data/query_p0/sql_functions/encryption_digest/test_digest.out new file mode 100644 index 00000000000..56d37cf1ea9 --- /dev/null +++ b/regression-test/data/query_p0/sql_functions/encryption_digest/test_digest.out @@ -0,0 +1,39 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !md5 -- +68934a3e9455fa72420237eb05902327 +68934a3e9455fa72420237eb05902327 +b326b5062b2f0e69046810717534cb09 + +-- !sha1_1 -- +40bd001563085fc35165329ea1ff5c5ecbdbbeef + +-- !sha1_2 -- +01b61f61abb0108346025d913eba241ec600da51 01b61f61abb0108346025d913eba241ec600da51 +e20afd4c8d2f7966348494bc4a8b3ba2406479c3 e20afd4c8d2f7966348494bc4a8b3ba2406479c3 +ecfb6e9d7b67d81c6f4a11c6df1bd5cc7d38d21e ecfb6e9d7b67d81c6f4a11c6df1bd5cc7d38d21e + +-- !sha1_3 -- +da39a3ee5e6b4b0d3255bfef95601890afd80709 + +-- !sha1_4 -- +\N + +-- !sha2_1 -- +be504c074c5a9e0a461d8dd6e1160ac8343e5d70bbd05082868e09edc9b17c50 +86aa74b42da827c630e4a3efaeb660823af67e540828576e8413e31ac95fd494 +86d137f8ee3da44ded006c55a3b6f3460121711df8a789bf146a6d2ce3995311 + +-- !sha2_2 -- +10a699b0850fad1c219f933f821e472630eac91cc34b2e8d254b2326ab8ca025ea9fdaa1db5e7b4c1d6b84a525524f8f3100e9847e1504b199728ddf0ce3e134 +a0296b74d1f31c0ce956f793efeb003c5e987b8f4546c8a02dcadf19073ff717d86fca57bdd0f532067b4757a7d0b924bcf4c471c05f671d775bac4f00638152 +6f2c68ec336dab0e4eb4746053bd4040b181cf75a4189dff729c6ac9a8e5062440bf5b6dc0f8ae3ed8859e1aa2a55626b1ae36191c34d41362766bcac9bc2ace + +-- !sha2_3 -- +23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 + +-- !sha2_4 -- +cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 + +-- !sha2_5 -- +\N + diff --git a/regression-test/data/query_p0/sql_functions/encryption_digest/test_md5.out b/regression-test/data/query_p0/sql_functions/encryption_digest/test_md5.out deleted file mode 100644 index 9bfed7153fa..00000000000 --- a/regression-test/data/query_p0/sql_functions/encryption_digest/test_md5.out +++ /dev/null @@ -1,6 +0,0 @@ --- This file is automatically generated. You should know what you did if you want to edit this --- !select -- -68934a3e9455fa72420237eb05902327 -68934a3e9455fa72420237eb05902327 -b326b5062b2f0e69046810717534cb09 - diff --git a/regression-test/suites/query_p0/sql_functions/encryption_digest/test_md5.groovy b/regression-test/suites/query_p0/sql_functions/encryption_digest/test_digest.groovy similarity index 53% rename from regression-test/suites/query_p0/sql_functions/encryption_digest/test_md5.groovy rename to regression-test/suites/query_p0/sql_functions/encryption_digest/test_digest.groovy index 152baae5a04..ebd9bd7d1db 100644 --- a/regression-test/suites/query_p0/sql_functions/encryption_digest/test_md5.groovy +++ b/regression-test/suites/query_p0/sql_functions/encryption_digest/test_digest.groovy @@ -15,6 +15,21 @@ // specific language governing permissions and limitations // under the License. -suite("test_md5") { - qt_select "select md5(k6) from test_query_db.test order by k6" +suite("test_digest") { + qt_md5 "select md5(k6) from test_query_db.test order by k6" + qt_sha1_1 "select sha1(\"123\")" + qt_sha1_2 "select sha(k7), sha1(k7) from test_query_db.test order by k7" + qt_sha1_3 "select sha1(\"\")" + qt_sha1_4 "select sha1(NULL)" + qt_sha2_1 "select sha2(k7, 256) from test_query_db.test order by k7" + qt_sha2_2 "select sha2(k7, 512) from test_query_db.test order by k7" + qt_sha2_3 "select sha2('abc', 224)" + qt_sha2_4 "select sha2('abc', 384)" + qt_sha2_5 "select sha2(NULL, 384)" + + try { + result = sql """ select sha2("123", 255) """ + } catch (Exception e) { + assertTrue(e.getMessage().contains("only support 224/256/384/512")) + } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org