This is an automated email from the ASF dual-hosted git repository.
HappenLee 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 74e9233f7b1 [fix](function) Require constant mode arguments for
encryption functions (#68487)
74e9233f7b1 is described below
commit 74e9233f7b13246dbc1156591517e53e6ac118c6
Author: Mryange <[email protected]>
AuthorDate: Mon Sep 28 14:00:59 2026 +0800
[fix](function) Require constant mode arguments for encryption functions
(#68487)
[fix](function) Require constant mode arguments for encryption functions
### What problem does this PR solve?
Issue Number: N/A
Problem Summary: AES and SM4 encryption functions resolve the encryption
mode as function-level execution state, but previously accepted a
non-constant mode column. This allowed rows in one function invocation
to request different modes even though optimized execution paths assume
one stable mode. Root cause: the encryption function implementations did
not declare the mode argument through
`get_arguments_that_are_always_constant()`. This change marks argument 2
as constant for three-argument signatures and argument 3 for four- and
five-argument signatures, adds BE unit coverage for valid constant
combinations and rejected dynamic modes, and updates the GCM regression
case to use literal modes while verifying that a mode column is
rejected.
### Release note
AES_ENCRYPT, AES_DECRYPT, SM4_ENCRYPT, and SM4_DECRYPT now require the
mode argument to be constant.
### Check List (For Author)
- Test
- [x] Regression test
- `./run-regression-test.sh --run -d
query_p0/sql_functions/encryption_digest -s test_encryption_function
-forceGenOut`
- 1 suite passed; generated `.out` content is unchanged because the
updated literal-mode queries produce the existing expected rows.
- [x] Unit Test
- `./run-be-ut.sh --run
--filter='function_string_test.function_aes_encrypt_test:function_string_test.function_aes_decrypt_test:function_string_test.function_encryption_mode_must_be_constant_test:function_string_test.function_sm4_encrypt_test:function_string_test.function_sm4_decrypt_test'
-j 48`
- [ ] Manual test
- [ ] No need to test or manual test
- Behavior changed:
- [ ] No.
- [x] Yes. Encryption mode expressions must now be constant.
- Does this need documentation?
- [x] No.
- [ ] Yes.
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label
---
be/src/exprs/function/function_encryption.cpp | 8 +++
be/test/exprs/function/function_string_test.cpp | 83 +++++++++++++++++++---
.../test_encryption_function.groovy | 23 +++++-
3 files changed, 104 insertions(+), 10 deletions(-)
diff --git a/be/src/exprs/function/function_encryption.cpp
b/be/src/exprs/function/function_encryption.cpp
index efb388b2524..a72a78bacb8 100644
--- a/be/src/exprs/function/function_encryption.cpp
+++ b/be/src/exprs/function/function_encryption.cpp
@@ -103,6 +103,10 @@ public:
return get_variadic_argument_types_impl().size();
}
+ ColumnNumbers get_arguments_that_are_always_constant() const override {
+ return Impl::get_arguments_that_are_always_constant();
+ }
+
Status execute_impl(FunctionContext* context, Block& block, const
ColumnNumbers& arguments,
uint32_t result, size_t input_rows_count) const
override {
return Impl::execute_impl_inner(context, block, arguments, result,
input_rows_count);
@@ -170,6 +174,8 @@ void execute_result(const char* src_raw, size_t src_size,
const char* key_raw, s
template <typename Impl, EncryptionMode mode, bool is_encrypt>
struct EncryptionAndDecryptTwoImpl {
+ static ColumnNumbers get_arguments_that_are_always_constant() { return
{2}; }
+
static DataTypes get_variadic_argument_types_impl() {
return {std::make_shared<DataTypeString>(),
std::make_shared<DataTypeString>(),
std::make_shared<DataTypeString>()};
@@ -275,6 +281,8 @@ struct EncryptionAndDecryptTwoImpl {
template <typename Impl, EncryptionMode mode, bool is_encrypt, bool
is_sm_mode, int arg_num = 4>
struct EncryptionAndDecryptMultiImpl {
+ static ColumnNumbers get_arguments_that_are_always_constant() { return
{3}; }
+
static DataTypes get_variadic_argument_types_impl() {
if constexpr (arg_num == 5) {
return {std::make_shared<DataTypeString>(),
std::make_shared<DataTypeString>(),
diff --git a/be/test/exprs/function/function_string_test.cpp
b/be/test/exprs/function/function_string_test.cpp
index f49d15b0167..52c1a067491 100644
--- a/be/test/exprs/function/function_string_test.cpp
+++ b/be/test/exprs/function/function_string_test.cpp
@@ -79,6 +79,28 @@ DataSet make_md5_varbinary_dataset(const
std::vector<std::string>& inputs) {
return data_set;
}
+void check_encryption_function_all_arg_comb(const std::string& func_name,
+ const InputTypeSet& base_types,
+ const DataSet& data_set) {
+ const auto argument_count = base_types.size();
+ const auto mode_index = argument_count - 1;
+ for (const auto& row : data_set) {
+ for (size_t const_mask = 0; const_mask < (1UL << mode_index);
++const_mask) {
+ InputTypeSet input_types;
+ input_types.reserve(argument_count);
+ for (size_t index = 0; index < argument_count; ++index) {
+ const auto primitive_type =
any_cast<PrimitiveType>(base_types[index]);
+ if (index == mode_index || (const_mask & (1UL << index))) {
+ input_types.emplace_back(Consted {primitive_type});
+ } else {
+ input_types.emplace_back(primitive_type);
+ }
+ }
+ static_cast<void>(check_function<DataTypeString, true>(func_name,
input_types, {row}));
+ }
+ }
+}
+
} // namespace
TEST(function_string_test, parse_data_size_nullable) {
@@ -2423,7 +2445,7 @@ TEST(function_string_test, function_aes_encrypt_test) {
{{std::string(src[5]), std::string(key),
std::string(mode)}, r[5]},
{{Null(), std::string(key), std::string(mode)},
Null()}};
- check_function_all_arg_comb<DataTypeString, true>(func_name,
input_types, data_set);
+ check_encryption_function_all_arg_comb(func_name, input_types,
data_set);
}
{
InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR,
PrimitiveType::TYPE_VARCHAR,
@@ -2458,7 +2480,7 @@ TEST(function_string_test, function_aes_encrypt_test) {
{{std::string(src[5]), std::string(key), std::string(iv),
std::string(mode)}, r[5]},
{{Null(), std::string(key), std::string(iv),
std::string(mode)}, Null()}};
- check_function_all_arg_comb<DataTypeString, true>(func_name,
input_types, data_set);
+ check_encryption_function_all_arg_comb(func_name, input_types,
data_set);
}
}
@@ -2490,7 +2512,7 @@ TEST(function_string_test, function_aes_decrypt_test) {
{{r[4], std::string(key), std::string(mode)},
std::string(src[4])},
{{Null(), std::string(key), std::string(mode)},
Null()}};
- check_function_all_arg_comb<DataTypeString, true>(func_name,
input_types, data_set);
+ check_encryption_function_all_arg_comb(func_name, input_types,
data_set);
}
{
InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR,
PrimitiveType::TYPE_VARCHAR,
@@ -2523,7 +2545,52 @@ TEST(function_string_test, function_aes_decrypt_test) {
{{r[4], std::string(key), std::string(iv), std::string(mode)},
std::string(src[4])},
{{Null(), std::string(key), std::string(iv),
std::string(mode)}, Null()}};
- check_function_all_arg_comb<DataTypeString, true>(func_name,
input_types, data_set);
+ check_encryption_function_all_arg_comb(func_name, input_types,
data_set);
+ }
+}
+
+TEST(function_string_test, function_encryption_mode_must_be_constant_test) {
+ const auto check_non_const_mode = [](const std::string& func_name,
+ const InputTypeSet& input_types,
const InputCell& input,
+ size_t mode_index) {
+ const auto status = check_function<DataTypeString, true>(func_name,
input_types,
+ {{input,
Null()}}, -1, -1, true);
+ const auto expected_message = "Argument at index " +
std::to_string(mode_index) +
+ " for function " + func_name + " must be
constant";
+ EXPECT_NE(std::string::npos,
status.to_string().find(expected_message));
+ };
+
+ const InputTypeSet three_argument_types = {
+ PrimitiveType::TYPE_VARCHAR, PrimitiveType::TYPE_VARCHAR,
PrimitiveType::TYPE_VARCHAR};
+ const InputTypeSet four_argument_types = {
+ PrimitiveType::TYPE_VARCHAR, PrimitiveType::TYPE_VARCHAR,
PrimitiveType::TYPE_VARCHAR,
+ PrimitiveType::TYPE_VARCHAR};
+ const InputTypeSet five_argument_types = {
+ PrimitiveType::TYPE_VARCHAR, PrimitiveType::TYPE_VARCHAR,
PrimitiveType::TYPE_VARCHAR,
+ PrimitiveType::TYPE_VARCHAR, PrimitiveType::TYPE_VARCHAR};
+
+ for (const auto& func_name : {"aes_encrypt", "aes_decrypt"}) {
+ check_non_const_mode(func_name, three_argument_types,
+ {std::string("text"), std::string("key"),
std::string("AES_128_ECB")},
+ 2);
+ check_non_const_mode(func_name, four_argument_types,
+ {std::string("text"), std::string("key"),
std::string("iv"),
+ std::string("AES_128_CBC")},
+ 3);
+ check_non_const_mode(func_name, five_argument_types,
+ {std::string("text"), std::string("key"),
std::string("iv"),
+ std::string("AES_128_GCM"), std::string("aad")},
+ 3);
+ }
+
+ for (const auto& func_name : {"sm4_encrypt", "sm4_decrypt"}) {
+ check_non_const_mode(func_name, three_argument_types,
+ {std::string("text"), std::string("key"),
std::string("SM4_128_ECB")},
+ 2);
+ check_non_const_mode(func_name, four_argument_types,
+ {std::string("text"), std::string("key"),
std::string("iv"),
+ std::string("SM4_128_CBC")},
+ 3);
}
}
@@ -2563,7 +2630,7 @@ TEST(function_string_test, function_sm4_encrypt_test) {
{{std::string(src[5]), std::string(key), std::string(iv),
std::string(mode)}, r[5]},
{{Null(), std::string(key), std::string(iv),
std::string(mode)}, Null()}};
- check_function_all_arg_comb<DataTypeString, true>(func_name,
input_types, data_set);
+ check_encryption_function_all_arg_comb(func_name, input_types,
data_set);
}
{
@@ -2600,7 +2667,7 @@ TEST(function_string_test, function_sm4_encrypt_test) {
{{std::string(src[5]), std::string(key), std::string(iv),
std::string(mode)}, r[5]},
{{Null(), std::string(key), std::string(iv),
std::string(mode)}, Null()}};
- check_function_all_arg_comb<DataTypeString, true>(func_name,
input_types, data_set);
+ check_encryption_function_all_arg_comb(func_name, input_types,
data_set);
}
}
@@ -2639,7 +2706,7 @@ TEST(function_string_test, function_sm4_decrypt_test) {
{{r[4], std::string(key), std::string(iv), std::string(mode)},
std::string(src[4])},
{{Null(), std::string(key), std::string(iv),
std::string(mode)}, Null()}};
- check_function_all_arg_comb<DataTypeString, true>(func_name,
input_types, data_set);
+ check_encryption_function_all_arg_comb(func_name, input_types,
data_set);
}
{
@@ -2675,7 +2742,7 @@ TEST(function_string_test, function_sm4_decrypt_test) {
{{r[4], std::string(key), std::string(iv), std::string(mode)},
std::string(src[4])},
{{Null(), Null(), std::string(iv), std::string(mode)},
Null()}};
- check_function_all_arg_comb<DataTypeString, true>(func_name,
input_types, data_set);
+ check_encryption_function_all_arg_comb(func_name, input_types,
data_set);
}
}
diff --git
a/regression-test/suites/query_p0/sql_functions/encryption_digest/test_encryption_function.groovy
b/regression-test/suites/query_p0/sql_functions/encryption_digest/test_encryption_function.groovy
index 7cfc36097bd..c909f5eba2c 100644
---
a/regression-test/suites/query_p0/sql_functions/encryption_digest/test_encryption_function.groovy
+++
b/regression-test/suites/query_p0/sql_functions/encryption_digest/test_encryption_function.groovy
@@ -100,8 +100,27 @@ suite("test_encryption_function") {
sql """ insert into aes_encrypt_decrypt_tbl
values(2,'Spark','AAAAAAAAAAAAAAAAQiYi+sTLm7KD9UcZ2nlRdYDe/PX4','abcdefghijklmnop12345678ABCDEFGH',unhex('000000000000000000000000'),'aes_256_gcm','This
is an AAD mixed into the input');"""
sql """ sync """
- qt_sql_gcm_5 "SELECT id,TO_BASE64(AES_ENCRYPT(plain_txt,k,iv,mode,aad))
from aes_encrypt_decrypt_tbl order by id;"
- qt_sql_gcm_6 "SELECT id,AES_DECRYPT(FROM_BASE64(enc_txt),k,'',mode,aad)
from aes_encrypt_decrypt_tbl order by id;"
+ test {
+ sql "SELECT AES_ENCRYPT(plain_txt, k, iv, mode, aad) FROM
aes_encrypt_decrypt_tbl"
+ exception "Argument at index 3 for function aes_encrypt must be
constant"
+ }
+
+ qt_sql_gcm_5 """
+ SELECT id, TO_BASE64(AES_ENCRYPT(plain_txt, k, iv, 'aes_128_gcm', aad))
+ FROM aes_encrypt_decrypt_tbl WHERE id = 1
+ UNION ALL
+ SELECT id, TO_BASE64(AES_ENCRYPT(plain_txt, k, iv, 'aes_256_gcm', aad))
+ FROM aes_encrypt_decrypt_tbl WHERE id = 2
+ ORDER BY id
+ """
+ qt_sql_gcm_6 """
+ SELECT id, AES_DECRYPT(FROM_BASE64(enc_txt), k, '', 'aes_128_gcm', aad)
+ FROM aes_encrypt_decrypt_tbl WHERE id = 1
+ UNION ALL
+ SELECT id, AES_DECRYPT(FROM_BASE64(enc_txt), k, '', 'aes_256_gcm', aad)
+ FROM aes_encrypt_decrypt_tbl WHERE id = 2
+ ORDER BY id
+ """
// test for const opt branch, only first column is not const
qt_sql_gcm_7 "SELECT id,TO_BASE64(AES_ENCRYPT(plain_txt,
'1234567890abcdef', '123456789012', 'aes_128_gcm', 'Some AAD')) from
aes_encrypt_decrypt_tbl where id=1"
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]