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]

Reply via email to