This is an automated email from the ASF dual-hosted git repository.

zclllyybb 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 14f7cd2247e [feature](function) Support murmur_hash3_128 function 
(#63196)
14f7cd2247e is described below

commit 14f7cd2247e1023888dd1e51f2d5a426e6c221cf
Author: seawinde <[email protected]>
AuthorDate: Tue Jun 2 10:19:36 2026 +0800

    [feature](function) Support murmur_hash3_128 function (#63196)
    
    This PR adds a builtin 128-bit MurmurHash3 scalar function,
    `murmur_hash3_128`, for callers that need a wider hash value than the
    existing 32-bit and 64-bit variants.
    
    | File | Change Description |
    |------|--------------------|
    | `be/src/exprs/function/function_hash.cpp` | Adds BE implementation for
    `murmur_hash3_128`, returning LARGEINT. |
    | `be/test/exprs/function/function_hash_test.cpp` | Adds unit coverage
    for constant and multi-argument hash cases. |
    | `BuiltinScalarFunctions.java` | Registers the Nereids scalar function.
    |
    | `MurmurHash3128.java` | Adds FE scalar function metadata and
    signatures. |
    | `ScalarFunctionVisitor.java` | Adds visitor entry for the new scalar
    function. |
    
    Design rationale: the function reuses the existing MurmurHash3 x64
    128-bit processing path in BE and exposes the packed 128-bit result as
    LARGEINT, matching Doris' existing signed 128-bit integer
    representation.
    
    BE execution logic:
    
    `murmur_hash3_128` follows the same variadic hash execution model as the
    existing Doris hash functions. The BE function framework does not
    evaluate all arguments for one row in a single call. Instead,
    `FunctionVariadicArgumentsBase` invokes the implementation once per
    argument column:
    
    ```text
    first_apply(arg0, result_column)
    combine_apply(arg1, result_column)
    combine_apply(arg2, result_column)
    ...
    ```
    
    For a query such as:
    
    ```sql
    SELECT murmur_hash3_128(k1, 'world') FROM t;
    ```
    
    the first round processes the whole `k1` column with `execute<true>()`.
    It creates one LARGEINT result slot per row and initializes each row's
    MurmurHash3 128-bit state from seed `0`. The second round processes the
    constant argument `'world'` with `execute<false>()`. It reads each row's
    previous state from the result column, updates that state with the new
    argument bytes, and writes the packed state back.
    
    For example, if `k1` has two rows:
    
    ```text
    row0: "hello"
    row1: "apache"
    ```
    
    the state evolves as:
    
    ```text
    Initial result column:
    row0: empty
    row1: empty
    
    Round 1: execute<true>() for k1
    row0: init_hash("hello")  -> state_hello
    row1: init_hash("apache") -> state_apache
    
    Result column:
    row0: pack(state_hello)
    row1: pack(state_apache)
    
    Round 2: execute<false>() for 'world'
    row0: unpack(state_hello)  -> update_hash("world") -> state_hello_world
    row1: unpack(state_apache) -> update_hash("world") -> state_apache_world
    
    Final result column:
    row0: pack(state_hello_world)
    row1: pack(state_apache_world)
    ```
    
    The underlying MurmurHash3 128-bit state is the pair `(h1, h2)`. For a
    single argument, the implementation can call the existing
    `murmur_hash3_x64_128(data, len, 0, out)` directly. For multiple
    arguments, each later argument must continue from the previous `(h1,
    h2)` state; calling `murmur_hash3_x64_128` independently for every
    argument would restart from seed `0` and lose the effect of earlier
    arguments.
    
    Because the SQL return type is LARGEINT and the BE result column stores
    one `__int128_t` value per row, the implementation packs `(h1, h2)` into
    the result column between argument rounds and unpacks it before
    processing the next argument:
    
    ```text
    high 64 bits                 low 64 bits
    +-------------------------+-------------------------+
    |           h2            |           h1            |
    +-------------------------+-------------------------+
    ```
---
 be/src/exprs/function/function_hash.cpp            | 158 ++++++++++++++++++++-
 be/src/util/hash/murmur_hash3.cpp                  |  17 ++-
 be/src/util/hash/murmur_hash3.h                    |   7 +-
 be/test/exprs/function/function_hash_test.cpp      | 137 ++++++++++++++++++
 .../doris/catalog/BuiltinScalarFunctions.java      |   4 +
 .../functions/scalar/MurmurHash3128.java           |  82 +++++++++++
 .../functions/scalar/MurmurHash3U128.java          |  81 +++++++++++
 .../expressions/visitor/ScalarFunctionVisitor.java |  10 ++
 .../hash_functions/test_hash_function.out          | 123 +++++++++++++++-
 .../hash_functions/test_hash_function.groovy       |  65 ++++++++-
 10 files changed, 671 insertions(+), 13 deletions(-)

diff --git a/be/src/exprs/function/function_hash.cpp 
b/be/src/exprs/function/function_hash.cpp
index 7e3072a91e9..74eb06e297d 100644
--- a/be/src/exprs/function/function_hash.cpp
+++ b/be/src/exprs/function/function_hash.cpp
@@ -20,6 +20,8 @@
 
 #include "exprs/function/function_hash.h"
 
+#include <vector>
+
 #include "common/status.h"
 #include "core/assert_cast.h"
 #include "core/column/column.h"
@@ -29,7 +31,9 @@
 #include "core/column/column_vector.h"
 #include "core/data_type/data_type.h"
 #include "core/data_type/data_type_number.h"
+#include "core/data_type/data_type_string.h"
 #include "core/field.h"
+#include "core/value/large_int_value.h"
 #include "exec/common/template_helpers.hpp"
 #include "exprs/function/function_helpers.h"
 #include "exprs/function/function_variadic_arguments.h"
@@ -40,6 +44,78 @@
 namespace doris {
 constexpr uint64_t emtpy_value = 0xe28dbde7fe22e41c;
 
+namespace {
+
+__int128_t pack_murmur_hash3_128(uint64_t h1, uint64_t h2) {
+    static_assert(sizeof(__int128_t) == sizeof(uint64_t) * 2);
+    // Store the two MurmurHash3 x64 128-bit lanes in a single LARGEINT value. 
Keep h1 in the
+    // low 64 bits and h2 in the high 64 bits to match murmur_hash3_x64_128's 
out[0]/out[1].
+    const auto value =
+            (static_cast<unsigned __int128>(h2) << 64) | static_cast<unsigned 
__int128>(h1);
+    return static_cast<__int128_t>(value);
+}
+
+void unpack_murmur_hash3_128(__int128_t value, uint64_t& h1, uint64_t& h2) {
+    static_assert(sizeof(__int128_t) == sizeof(uint64_t) * 2);
+    const auto unsigned_value = static_cast<unsigned __int128>(value);
+    h1 = static_cast<uint64_t>(unsigned_value);
+    h2 = static_cast<uint64_t>(unsigned_value >> 64);
+}
+
+void init_murmur_hash3_128(__int128_t& value, const void* data, size_t size) {
+    uint64_t hash[2] = {0, 0};
+    murmur_hash3_x64_128(data, size, 0, hash);
+    value = pack_murmur_hash3_128(hash[0], hash[1]);
+}
+
+void update_murmur_hash3_128(__int128_t& value, const void* data, size_t size) 
{
+    uint64_t h1 = 0;
+    uint64_t h2 = 0;
+    unpack_murmur_hash3_128(value, h1, h2);
+    murmur_hash3_x64_process(data, size, h1, h2);
+    value = pack_murmur_hash3_128(h1, h2);
+}
+
+template <bool first, typename StateContainer>
+Status execute_murmur_hash3_128_column(const IColumn* column, size_t 
input_rows_count,
+                                       StateContainer& state, const char* 
function_name) {
+    if (const auto* col_from = check_and_get_column<ColumnString>(column)) {
+        const typename ColumnString::Chars& data = col_from->get_chars();
+        const typename ColumnString::Offsets& offsets = 
col_from->get_offsets();
+        size_t size = offsets.size();
+        ColumnString::Offset current_offset = 0;
+        for (size_t i = 0; i < size; ++i) {
+            if constexpr (first) {
+                init_murmur_hash3_128(state[i],
+                                      reinterpret_cast<const 
char*>(&data[current_offset]),
+                                      offsets[i] - current_offset);
+            } else {
+                update_murmur_hash3_128(state[i],
+                                        reinterpret_cast<const 
char*>(&data[current_offset]),
+                                        offsets[i] - current_offset);
+            }
+            current_offset = offsets[i];
+        }
+    } else if (const ColumnConst* col_from_const =
+                       
check_and_get_column_const_string_or_fixedstring(column)) {
+        auto value = col_from_const->get_value<TYPE_STRING>();
+        for (size_t i = 0; i < input_rows_count; ++i) {
+            if constexpr (first) {
+                init_murmur_hash3_128(state[i], value.data(), value.size());
+            } else {
+                update_murmur_hash3_128(state[i], value.data(), value.size());
+            }
+        }
+    } else {
+        DCHECK(false);
+        return Status::NotSupported("Illegal column {} of argument of function 
{}",
+                                    column->get_name(), function_name);
+    }
+    return Status::OK();
+}
+
+} // namespace
+
 template <PrimitiveType ReturnType, bool is_mmh64_v2 = false>
 struct MurmurHash3Impl {
     static constexpr auto get_name() {
@@ -133,6 +209,84 @@ using FunctionMurmurHash3_64_V2 =
 using FunctionMurmurHash3U64V2 =
         FunctionVariadicArgumentsBase<DataTypeInt128, 
MurmurHash3Impl<TYPE_LARGEINT, true>>;
 
+struct MurmurHash3128Impl {
+    static constexpr auto name = "murmur_hash3_128";
+
+    static Status empty_apply(IColumn& /*icolumn*/, size_t 
/*input_rows_count*/) {
+        return Status::InvalidArgument("Function {} requires at least one 
argument", name);
+    }
+
+    static Status first_apply(const IDataType* type, const IColumn* column, 
size_t input_rows_count,
+                              IColumn& icolumn) {
+        return execute<true>(type, column, input_rows_count, icolumn);
+    }
+
+    static Status combine_apply(const IDataType* type, const IColumn* column,
+                                size_t input_rows_count, IColumn& icolumn) {
+        return execute<false>(type, column, input_rows_count, icolumn);
+    }
+
+    template <bool first>
+    static Status execute(const IDataType* type, const IColumn* column, size_t 
input_rows_count,
+                          IColumn& col_to) {
+        auto& to_column = assert_cast<ColumnVector<TYPE_LARGEINT>&>(col_to);
+        if constexpr (first) {
+            // The first argument initializes one 128-bit hash state per row. 
Later arguments reuse
+            // the same result column and update the saved state in place.
+            to_column.insert_many_defaults(input_rows_count);
+        }
+        auto& col_to_data = to_column.get_data();
+        return execute_murmur_hash3_128_column<first>(column, 
input_rows_count, col_to_data, name);
+    }
+};
+
+using FunctionMurmurHash3_128 = FunctionVariadicArgumentsBase<DataTypeInt128, 
MurmurHash3128Impl>;
+
+class FunctionMurmurHash3U128 : public IFunction {
+public:
+    static constexpr auto name = "murmur_hash3_u128";
+
+    static FunctionPtr create() { return 
std::make_shared<FunctionMurmurHash3U128>(); }
+
+    String get_name() const override { return name; }
+
+    bool is_variadic() const override { return true; }
+
+    size_t get_number_of_arguments() const override { return 0; }
+
+    DataTypePtr get_return_type_impl(const ColumnsWithTypeAndName& 
/*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 {
+        if (arguments.empty()) {
+            return Status::InvalidArgument("Function {} requires at least one 
argument", name);
+        }
+
+        std::vector<__int128_t> state(input_rows_count);
+        const ColumnWithTypeAndName& first_col = 
block.get_by_position(arguments[0]);
+        
RETURN_IF_ERROR(execute_murmur_hash3_128_column<true>(first_col.column.get(),
+                                                              
input_rows_count, state, name));
+
+        for (size_t i = 1; i < arguments.size(); ++i) {
+            const ColumnWithTypeAndName& col = 
block.get_by_position(arguments[i]);
+            
RETURN_IF_ERROR(execute_murmur_hash3_128_column<false>(col.column.get(),
+                                                                   
input_rows_count, state, name));
+        }
+
+        auto result_column = ColumnString::create();
+        result_column->reserve(input_rows_count);
+        for (const auto value : state) {
+            auto unsigned_value = static_cast<__uint128_t>(value);
+            std::string value_str = LargeIntValue::to_string(unsigned_value);
+            result_column->insert_data(value_str.data(), value_str.size());
+        }
+        block.get_by_position(result).column = std::move(result_column);
+        return Status::OK();
+    }
+};
+
 #ifdef BE_TEST
 const char* murmur_hash3_get_name_type_int_for_test() {
     return MurmurHash3Impl<TYPE_INT>::get_name();
@@ -234,8 +388,10 @@ void register_function_hash(SimpleFunctionFactory& 
factory) {
     factory.register_function<FunctionMurmurHash3_64>();
     factory.register_function<FunctionMurmurHash3_64_V2>();
     factory.register_function<FunctionMurmurHash3U64V2>();
+    factory.register_function<FunctionMurmurHash3_128>();
+    factory.register_function<FunctionMurmurHash3U128>();
     factory.register_function<FunctionXxHash_32>();
     factory.register_function<FunctionXxHash_64>();
     factory.register_alias("xxhash_64", "xxhash3_64");
 }
-} // namespace doris
\ No newline at end of file
+} // namespace doris
diff --git a/be/src/util/hash/murmur_hash3.cpp 
b/be/src/util/hash/murmur_hash3.cpp
index 7cd22dd59ec..d53bbc821b3 100644
--- a/be/src/util/hash/murmur_hash3.cpp
+++ b/be/src/util/hash/murmur_hash3.cpp
@@ -30,6 +30,8 @@
 #include <stdlib.h>
 #endif
 
+#include <glog/logging.h>
+
 #include "util/unaligned.h"
 
 namespace doris {
@@ -72,7 +74,7 @@ FORCE_INLINE uint32_t getblock32(const uint32_t* p, int i) {
     return unaligned_load<uint32_t>(&p[i]);
 }
 
-FORCE_INLINE uint64_t getblock64(const uint64_t* p, int i) {
+FORCE_INLINE uint64_t getblock64(const uint64_t* p, size_t i) {
     return unaligned_load<uint64_t>(&p[i]);
 }
 
@@ -334,9 +336,9 @@ void murmur_hash3_x86_128(const void* key, const int len, 
uint32_t seed, void* o
 //-----------------------------------------------------------------------------
 
 // Helper function that implements the core MurmurHash3 128-bit hashing 
algorithm
-void murmur_hash3_x64_process(const void* key, const int len, uint64_t& h1, 
uint64_t& h2) {
+void murmur_hash3_x64_process(const void* key, const size_t len, uint64_t& h1, 
uint64_t& h2) {
     const uint8_t* data = (const uint8_t*)key;
-    const int nblocks = len / 16;
+    const size_t nblocks = len / 16;
 
     const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
     const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
@@ -346,7 +348,7 @@ void murmur_hash3_x64_process(const void* key, const int 
len, uint64_t& h1, uint
 
     const uint64_t* blocks = (const uint64_t*)(data);
 
-    for (int i = 0; i < nblocks; i++) {
+    for (size_t i = 0; i < nblocks; i++) {
         uint64_t k1 = getblock64(blocks, i * 2 + 0);
         uint64_t k2 = getblock64(blocks, i * 2 + 1);
 
@@ -453,7 +455,7 @@ void murmur_hash3_x64_process(const void* key, const int 
len, uint64_t& h1, uint
 // The origin function `murmur_hash3_x64_128` is copied from: 
https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
 // And Doris modified it into function `murmur_hash3_x64_process`
 // For this reason, this function is still retained even though it has no 
calls.
-void murmur_hash3_x64_128(const void* key, const int len, const uint32_t seed, 
void* out) {
+void murmur_hash3_x64_128(const void* key, const size_t len, const uint32_t 
seed, void* out) {
     uint64_t h1 = seed;
     uint64_t h2 = seed;
     murmur_hash3_x64_process(key, len, h1, h2);
@@ -468,9 +470,10 @@ void murmur_hash3_x64_128(const void* key, const int len, 
const uint32_t seed, v
 // Used for function mmh3_64_v2
 void murmur_hash3_x64_64_shared(const void* key, const int64_t len, const 
uint64_t seed,
                                 void* out) {
+    DCHECK_GE(len, 0);
     uint64_t h1 = seed;
     uint64_t h2 = seed;
-    murmur_hash3_x64_process(key, static_cast<int>(len), h1, h2);
+    murmur_hash3_x64_process(key, static_cast<size_t>(len), h1, h2);
     ((uint64_t*)out)[0] = h1;
 }
 
@@ -546,4 +549,4 @@ void murmur_hash3_x64_64(const void* key, const int64_t 
len, const uint64_t seed
     ((uint64_t*)out)[0] = h1;
 }
 
-} // namespace doris
\ No newline at end of file
+} // namespace doris
diff --git a/be/src/util/hash/murmur_hash3.h b/be/src/util/hash/murmur_hash3.h
index f72f08336c7..bcb34a3ad98 100644
--- a/be/src/util/hash/murmur_hash3.h
+++ b/be/src/util/hash/murmur_hash3.h
@@ -20,6 +20,7 @@
 
 #pragma once
 
+#include <cstddef>
 #include <cstdint>
 namespace doris {
 
@@ -27,12 +28,12 @@ void murmur_hash3_x86_32(const void* key, int64_t len, 
uint32_t seed, void* out)
 
 void murmur_hash3_x86_128(const void* key, int len, uint32_t seed, void* out);
 
-void murmur_hash3_x64_process(const void* key, const int len, uint64_t& h1, 
uint64_t& h2);
+void murmur_hash3_x64_process(const void* key, size_t len, uint64_t& h1, 
uint64_t& h2);
 
-void murmur_hash3_x64_128(const void* key, int len, uint32_t seed, void* out);
+void murmur_hash3_x64_128(const void* key, size_t len, uint32_t seed, void* 
out);
 
 void murmur_hash3_x64_64_shared(const void* key, const int64_t len, const 
uint64_t seed, void* out);
 
 void murmur_hash3_x64_64(const void* key, int64_t len, uint64_t seed, void* 
out);
 
-} // namespace doris
\ No newline at end of file
+} // namespace doris
diff --git a/be/test/exprs/function/function_hash_test.cpp 
b/be/test/exprs/function/function_hash_test.cpp
index ad4b47f5c5b..2d3f2ad1cc0 100644
--- a/be/test/exprs/function/function_hash_test.cpp
+++ b/be/test/exprs/function/function_hash_test.cpp
@@ -25,7 +25,9 @@
 #include "common/status.h"
 #include "core/data_type/data_type_nullable.h"
 #include "core/data_type/data_type_number.h"
+#include "core/data_type/data_type_string.h"
 #include "core/types.h"
+#include "core/value/large_int_value.h"
 #include "exprs/function/function_test_util.h"
 #include "gtest/gtest_pred_impl.h"
 #include "testutil/any_type.h"
@@ -34,6 +36,30 @@
 namespace doris {
 using namespace ut_type;
 
+namespace {
+
+__int128_t pack_murmur_hash3_128_for_test(uint64_t h1, uint64_t h2) {
+    static_assert(sizeof(__int128_t) == sizeof(uint64_t) * 2);
+    const auto value =
+            (static_cast<unsigned __int128>(h2) << 64) | static_cast<unsigned 
__int128>(h1);
+    return static_cast<__int128_t>(value);
+}
+
+__int128_t murmur_hash3_128_for_test(const std::vector<std::string>& values) {
+    uint64_t h1 = 0;
+    uint64_t h2 = 0;
+    for (const std::string& value : values) {
+        murmur_hash3_x64_process(value.data(), value.size(), h1, h2);
+    }
+    return pack_murmur_hash3_128_for_test(h1, h2);
+}
+
+std::string murmur_hash3_u128_for_test(const std::vector<std::string>& values) 
{
+    return 
LargeIntValue::to_string(static_cast<__uint128_t>(murmur_hash3_128_for_test(values)));
+}
+
+} // namespace
+
 TEST(HashFunctionTest, murmur_hash_3_test) {
     std::string func_name = "murmur_hash3_32";
 
@@ -114,6 +140,117 @@ TEST(HashFunctionTest, murmur_hash_3_64_v2_test) {
     };
 }
 
+TEST(HashFunctionTest, murmur_hash_3_128_test) {
+    std::string func_name = "murmur_hash3_128";
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR};
+
+        DataSet data_set = {
+                {{Null()}, Null()},
+                {{std::string("hello world")},
+                 pack_murmur_hash3_128_for_test(5998619086395760910ULL, 
12364428806279881649ULL)}};
+
+        static_cast<void>(check_function<DataTypeInt128, true>(func_name, 
input_types, data_set));
+        check_function_all_arg_comb<DataTypeInt128, true>(func_name, 
input_types, data_set);
+    };
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR, 
PrimitiveType::TYPE_VARCHAR};
+
+        DataSet data_set = {{{std::string("hello"), std::string("world")},
+                             murmur_hash3_128_for_test({"hello", "world"})},
+                            {{std::string("hello"), Null()}, Null()}};
+
+        static_cast<void>(check_function<DataTypeInt128, true>(func_name, 
input_types, data_set));
+        check_function_all_arg_comb<DataTypeInt128, true>(func_name, 
input_types, data_set);
+    };
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR, 
PrimitiveType::TYPE_VARCHAR,
+                                    PrimitiveType::TYPE_VARCHAR};
+
+        DataSet data_set = {{{std::string("hello"), std::string("world"), 
std::string("!")},
+                             murmur_hash3_128_for_test({"hello", "world", 
"!"})},
+                            {{std::string("hello"), std::string("world"), 
Null()}, Null()}};
+
+        check_function_all_arg_comb<DataTypeInt128, true>(func_name, 
input_types, data_set);
+    };
+}
+
+TEST(HashFunctionTest, murmur_hash_3_128_empty_arguments_test) {
+    auto check_empty_arguments = [](const std::string& func_name, const 
DataTypePtr& return_type) {
+        Block block;
+        FunctionBasePtr func = SimpleFunctionFactory::instance().get_function(
+                func_name, block.get_columns_with_type_and_name(), 
return_type);
+        ASSERT_TRUE(func != nullptr);
+
+        FunctionUtils fn_utils(return_type, {}, false);
+        auto* fn_ctx = fn_utils.get_fn_ctx();
+        ASSERT_TRUE(func->open(fn_ctx, FunctionContext::FRAGMENT_LOCAL).ok());
+        ASSERT_TRUE(func->open(fn_ctx, FunctionContext::THREAD_LOCAL).ok());
+
+        block.insert({nullptr, return_type, "result"});
+        const auto st = func->execute(fn_ctx, block, {}, 0, 1);
+        EXPECT_FALSE(st.ok());
+        EXPECT_NE(st.to_string().find("requires at least one argument"), 
std::string::npos);
+
+        static_cast<void>(func->close(fn_ctx, FunctionContext::THREAD_LOCAL));
+        static_cast<void>(func->close(fn_ctx, 
FunctionContext::FRAGMENT_LOCAL));
+    };
+
+    check_empty_arguments("murmur_hash3_128", 
std::make_shared<DataTypeInt128>());
+    check_empty_arguments("murmur_hash3_u128", 
std::make_shared<DataTypeString>());
+}
+
+TEST(HashFunctionTest, murmur_hash_3_u128_test) {
+    std::string func_name = "murmur_hash3_u128";
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR};
+
+        DataSet data_set = {
+                {{Null()}, Null()},
+                {{std::string("")}, std::string("0")},
+                {{std::string("hello world")}, 
murmur_hash3_u128_for_test({"hello world"})}};
+
+        static_cast<void>(check_function<DataTypeString, true>(func_name, 
input_types, data_set));
+        check_function_all_arg_comb<DataTypeString, true>(func_name, 
input_types, data_set);
+    };
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR, 
PrimitiveType::TYPE_VARCHAR};
+
+        DataSet data_set = {{{std::string("hello"), std::string("world")},
+                             murmur_hash3_u128_for_test({"hello", "world"})},
+                            {{std::string("hello"), Null()}, Null()}};
+
+        static_cast<void>(check_function<DataTypeString, true>(func_name, 
input_types, data_set));
+        check_function_all_arg_comb<DataTypeString, true>(func_name, 
input_types, data_set);
+    };
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR, 
PrimitiveType::TYPE_VARCHAR,
+                                    PrimitiveType::TYPE_VARCHAR};
+
+        DataSet data_set = {{{std::string("hello"), std::string("world"), 
std::string("!")},
+                             murmur_hash3_u128_for_test({"hello", "world", 
"!"})},
+                            {{std::string("hello"), std::string("world"), 
Null()}, Null()}};
+
+        check_function_all_arg_comb<DataTypeString, true>(func_name, 
input_types, data_set);
+    };
+}
+
+TEST(HashFunctionTest, murmur_hash_3_u128_unsigned_range_test) {
+    std::string func_name = "murmur_hash3_u128";
+
+    InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR};
+    DataSet data_set = {
+            {{std::string("hello world")}, 
std::string("228083453807047072434243676435732455694")}};
+
+    static_cast<void>(check_function<DataTypeString, true>(func_name, 
input_types, data_set));
+}
+
 TEST(HashFunctionTest, murmur_hash_get_name_test) {
     EXPECT_STREQ(murmur_hash3_get_name_type_int_for_test(), "murmur_hash3_32");
     EXPECT_STREQ(murmur_hash3_get_name_type_bigint_for_test(), 
"murmur_hash3_64");
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 0883b93e5a8..4478bc9bcfe 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
@@ -376,9 +376,11 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsSub;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.MultiMatch;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MultiMatchAny;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MultiSearchAllPositions;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash3128;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash332;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash364;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash364V2;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash3U128;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash3U64V2;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Negative;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.NextDay;
@@ -953,9 +955,11 @@ public class BuiltinScalarFunctions implements 
FunctionHelper {
             scalar(MultiMatch.class, "multi_match"),
             scalar(MultiMatchAny.class, "multi_match_any"),
             scalar(MultiSearchAllPositions.class, 
"multi_search_all_positions"),
+            scalar(MurmurHash3128.class, "murmur_hash3_128"),
             scalar(MurmurHash332.class, "murmur_hash3_32"),
             scalar(MurmurHash364.class, "murmur_hash3_64"),
             scalar(MurmurHash364V2.class, "murmur_hash3_64_v2"),
+            scalar(MurmurHash3U128.class, "murmur_hash3_u128"),
             scalar(MurmurHash3U64V2.class, "murmur_hash3_u64_v2"),
             scalar(Negative.class, "negative"),
             scalar(NextDay.class, "next_day"),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MurmurHash3128.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MurmurHash3128.java
new file mode 100644
index 00000000000..edc6be080fe
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MurmurHash3128.java
@@ -0,0 +1,82 @@
+// 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.LargeIntType;
+import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.VarcharType;
+import org.apache.doris.nereids.util.ExpressionUtils;
+import org.apache.doris.nereids.util.Utils;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'murmur_hash3_128'.
+ */
+public class MurmurHash3128 extends ScalarFunction
+        implements ExplicitlyCastableSignature, PropagateNullable {
+
+    public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            
FunctionSignature.ret(LargeIntType.INSTANCE).varArgs(VarcharType.SYSTEM_DEFAULT),
+            
FunctionSignature.ret(LargeIntType.INSTANCE).varArgs(StringType.INSTANCE)
+    );
+
+    /**
+     * constructor with 1 or more arguments.
+     */
+    public MurmurHash3128(Expression arg, Expression... varArgs) {
+        this(ExpressionUtils.mergeArguments(arg, varArgs));
+    }
+
+    /** constructor with list arguments. */
+    public MurmurHash3128(List<Expression> args) {
+        super("murmur_hash3_128", Utils.fastToImmutableList(args));
+    }
+
+    /** constructor for withChildren and reuse signature */
+    private MurmurHash3128(ScalarFunctionParams functionParams) {
+        super(functionParams);
+    }
+
+    /**
+     * withChildren.
+     */
+    @Override
+    public MurmurHash3128 withChildren(List<Expression> children) {
+        Preconditions.checkArgument(!children.isEmpty());
+        return new MurmurHash3128(getFunctionParams(children));
+    }
+
+    @Override
+    public List<FunctionSignature> getSignatures() {
+        return SIGNATURES;
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitMurmurHash3128(this, context);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MurmurHash3U128.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MurmurHash3U128.java
new file mode 100644
index 00000000000..34e8ad67e53
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MurmurHash3U128.java
@@ -0,0 +1,81 @@
+// 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 org.apache.doris.nereids.util.ExpressionUtils;
+import org.apache.doris.nereids.util.Utils;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'murmur_hash3_u128'.
+ */
+public class MurmurHash3U128 extends ScalarFunction
+        implements ExplicitlyCastableSignature, PropagateNullable {
+
+    public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            
FunctionSignature.ret(StringType.INSTANCE).varArgs(VarcharType.SYSTEM_DEFAULT),
+            
FunctionSignature.ret(StringType.INSTANCE).varArgs(StringType.INSTANCE)
+    );
+
+    /**
+     * constructor with 1 or more arguments.
+     */
+    public MurmurHash3U128(Expression arg, Expression... varArgs) {
+        this(ExpressionUtils.mergeArguments(arg, varArgs));
+    }
+
+    /** constructor with list arguments. */
+    public MurmurHash3U128(List<Expression> args) {
+        super("murmur_hash3_u128", Utils.fastToImmutableList(args));
+    }
+
+    /** constructor for withChildren and reuse signature */
+    private MurmurHash3U128(ScalarFunctionParams functionParams) {
+        super(functionParams);
+    }
+
+    /**
+     * withChildren.
+     */
+    @Override
+    public MurmurHash3U128 withChildren(List<Expression> children) {
+        Preconditions.checkArgument(!children.isEmpty());
+        return new MurmurHash3U128(getFunctionParams(children));
+    }
+
+    @Override
+    public List<FunctionSignature> getSignatures() {
+        return SIGNATURES;
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitMurmurHash3U128(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 ce9deb2776d..1f82a48f1d7 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
@@ -397,9 +397,11 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsSub;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.MultiMatch;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MultiMatchAny;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MultiSearchAllPositions;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash3128;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash332;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash364;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash364V2;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash3U128;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.MurmurHash3U64V2;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Negative;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.NextDay;
@@ -2012,6 +2014,10 @@ public interface ScalarFunctionVisitor<R, C> {
         return visitScalarFunction(function, context);
     }
 
+    default R visitMurmurHash3128(MurmurHash3128 murmurHash3128, C context) {
+        return visitScalarFunction(murmurHash3128, context);
+    }
+
     default R visitMurmurHash332(MurmurHash332 murmurHash332, C context) {
         return visitScalarFunction(murmurHash332, context);
     }
@@ -2024,6 +2030,10 @@ public interface ScalarFunctionVisitor<R, C> {
         return visitScalarFunction(murmurHash364V2, context);
     }
 
+    default R visitMurmurHash3U128(MurmurHash3U128 murmurHash3U128, C context) 
{
+        return visitScalarFunction(murmurHash3U128, context);
+    }
+
     default R visitMurmurHash3U64V2(MurmurHash3U64V2 murmurHash3U64V2, C 
context) {
         return visitScalarFunction(murmurHash3U64V2, context);
     }
diff --git 
a/regression-test/data/query_p0/sql_functions/hash_functions/test_hash_function.out
 
b/regression-test/data/query_p0/sql_functions/hash_functions/test_hash_function.out
index 764d533fcc7..b98d9b506fa 100644
--- 
a/regression-test/data/query_p0/sql_functions/hash_functions/test_hash_function.out
+++ 
b/regression-test/data/query_p0/sql_functions/hash_functions/test_hash_function.out
@@ -87,6 +87,50 @@
 8      5163374697039953916
 9      16930717985386452140
 
+-- !sql_mmh3_128_table --
+1      160552765667853844864347215091851402511
+2      -112198913113891391029130930996035755762
+3      \N
+4      0
+5      125233622341202073067337261280912046255
+6      15723305950287370021067100420381546638
+7      76022033372587150664028094316560832338
+8      8282804273666544992604160676428939260
+9      54500626245739954189896806014374040748
+
+-- !sql_mmh3_u128_table --
+1      160552765667853844864347215091851402511
+2      228083453807047072434243676435732455694
+3      \N
+4      0
+5      125233622341202073067337261280912046255
+6      15723305950287370021067100420381546638
+7      76022033372587150664028094316560832338
+8      8282804273666544992604160676428939260
+9      54500626245739954189896806014374040748
+
+-- !sql_mmh3_128_multi_arg_table --
+1      1446959605745449161743580155912574278   
-56339891497867408245721289945506420485 -168178611131198900113957651047418886169
+2      -149549192126671924717567585844879967555        
-60587747024077554617701559639572348746 65424866033221268138215169303830582651
+3      \N      \N      \N
+4      -78565033930154308766756204499853146902 
84714210717646297788662261898201230080  0
+5      -39544922153624419472698581057092341686 
164681627131843042222834911849678645237 -461669328540671960194073097226353499
+6      3855286205383178813738041956665736806   
114705208091273276245241207548307136670 126143460685998379802738880954496866607
+7      -66251693712752822782446614605307054187 
145660169740749413061118106551153383205 167010716176867357320321384372081403147
+8      -53522276451386554290637598501892217568 
-49434810126805792985863702972638694950 -162781926366258959505488386157422138285
+9      46144780234418243372325741019404497451  
109924268220979943366442352659211725694 -68242619748682641450662548496031489232
+
+-- !sql_mmh3_u128_multi_arg_table --
+1      1446959605745449161743580155912574278   
283942475423071055217653317486261790971 172103755789739563349416956384349325287
+2      190733174794266538745807021586888243901 
279694619896860908845673047792195862710 65424866033221268138215169303830582651
+3      \N      \N      \N
+4      261717332990784154696618402931915064554 
84714210717646297788662261898201230080  0
+5      300737444767314043990676026374675869770 
164681627131843042222834911849678645237 339820697592397791503180534334541857957
+6      3855286205383178813738041956665736806   
114705208091273276245241207548307136670 126143460685998379802738880954496866607
+7      274030673208185640680927992826461157269 
145660169740749413061118106551153383205 167010716176867357320321384372081403147
+8      286760090469551909172737008929875993888 
290847556794132670477510904459129516506 177500440554679503957886221274346073171
+9      46144780234418243372325741019404497451  
109924268220979943366442352659211725694 272039747172255822012712058935736722224
+
 -- !mmh3_64_v2_fold_1 --
 -6017608668500074082
 
@@ -99,6 +143,84 @@
 -- !mmh3_u64_v2_fold_2 --
 14339120766958605182
 
+-- !sql_mmh3_128_null --
+\N
+
+-- !sql_mmh3_128_empty --
+0
+
+-- !sql_mmh3_128_hello --
+121118445609844952839898260755277781762
+
+-- !sql_mmh3_128_hello_world --
+-112198913113891391029130930996035755762
+
+-- !sql_mmh3_128_apache_doris --
+125233622341202073067337261280912046255
+
+-- !sql_mmh3_128_two_args --
+-17367660094379006912106945534038101931
+
+-- !sql_mmh3_128_three_args --
+9994430460069927257443176797242139063
+
+-- !sql_mmh3_128_null_second --
+\N
+
+-- !sql_mmh3_128_null_first --
+\N
+
+-- !sql_mmh3_128_all_null --
+\N
+
+-- !sql_mmh3_128_unicode_zh --
+8282804273666544992604160676428939260
+
+-- !sql_mmh3_128_unicode_ja --
+54500626245739954189896806014374040748
+
+-- !sql_mmh3_128_other_types --
+88386560642490731012209186590589091690 112229221047929881211004856197893237700 
6504046186406760443866950209489696482
+
+-- !sql_mmh3_u128_null --
+\N
+
+-- !sql_mmh3_u128_empty --
+0
+
+-- !sql_mmh3_u128_hello --
+121118445609844952839898260755277781762
+
+-- !sql_mmh3_u128_hello_world --
+228083453807047072434243676435732455694
+
+-- !sql_mmh3_u128_apache_doris --
+125233622341202073067337261280912046255
+
+-- !sql_mmh3_u128_two_args --
+322914706826559456551267661897730109525
+
+-- !sql_mmh3_u128_three_args --
+9994430460069927257443176797242139063
+
+-- !sql_mmh3_u128_null_second --
+\N
+
+-- !sql_mmh3_u128_null_first --
+\N
+
+-- !sql_mmh3_u128_all_null --
+\N
+
+-- !sql_mmh3_u128_unicode_zh --
+8282804273666544992604160676428939260
+
+-- !sql_mmh3_u128_unicode_ja --
+54500626245739954189896806014374040748
+
+-- !sql_mmh3_u128_other_types --
+88386560642490731012209186590589091690 112229221047929881211004856197893237700 
6504046186406760443866950209489696482
+
 -- !sql --
 \N
 
@@ -116,4 +238,3 @@
 
 -- !sql --
 7001965798170371843
-
diff --git 
a/regression-test/suites/query_p0/sql_functions/hash_functions/test_hash_function.groovy
 
b/regression-test/suites/query_p0/sql_functions/hash_functions/test_hash_function.groovy
index ace3379c99e..0a15cc73e3b 100644
--- 
a/regression-test/suites/query_p0/sql_functions/hash_functions/test_hash_function.groovy
+++ 
b/regression-test/suites/query_p0/sql_functions/hash_functions/test_hash_function.groovy
@@ -91,8 +91,26 @@ suite("test_hash_function", "arrow_flight_sql") {
 
     qt_mmh3_64_v2_table "SELECT id, MURMUR_HASH3_64_V2(str_col) FROM 
test_hash_tbl ORDER BY id;"
     qt_mmh3_u64_v2_table "SELECT id, MURMUR_HASH3_U64_V2(str_col) FROM 
test_hash_tbl ORDER BY id;"
+    qt_sql_mmh3_128_table "SELECT id, MURMUR_HASH3_128(str_col) FROM 
test_hash_tbl ORDER BY id;"
+    qt_sql_mmh3_u128_table "SELECT id, MURMUR_HASH3_U128(str_col) FROM 
test_hash_tbl ORDER BY id;"
+
+    qt_sql_mmh3_128_multi_arg_table """
+        SELECT id,
+               MURMUR_HASH3_128(str_col, 'world'),
+               MURMUR_HASH3_128('hello', str_col),
+               MURMUR_HASH3_128(str_col, str_col)
+        FROM test_hash_tbl
+        ORDER BY id;
+    """
 
-    sql "DROP TABLE IF EXISTS test_hash_tbl;"
+    qt_sql_mmh3_u128_multi_arg_table """
+        SELECT id,
+               MURMUR_HASH3_U128(str_col, 'world'),
+               MURMUR_HASH3_U128('hello', str_col),
+               MURMUR_HASH3_U128(str_col, str_col)
+        FROM test_hash_tbl
+        ORDER BY id;
+    """
 
     // Constant folding tests
     qt_mmh3_64_v2_fold_1 "SELECT MURMUR_HASH3_64_V2('test') + 1;"
@@ -100,6 +118,51 @@ suite("test_hash_function", "arrow_flight_sql") {
     qt_mmh3_u64_v2_fold_1 "SELECT MURMUR_HASH3_U64_V2('test') + 1;"
     qt_mmh3_u64_v2_fold_2 "SELECT MURMUR_HASH3_U64_V2('a', 'b') * 2;"
 
+    qt_sql_mmh3_128_null "SELECT MURMUR_HASH3_128(NULL);"
+    qt_sql_mmh3_128_empty "SELECT MURMUR_HASH3_128('');"
+    qt_sql_mmh3_128_hello "SELECT MURMUR_HASH3_128('hello');"
+    qt_sql_mmh3_128_hello_world "SELECT MURMUR_HASH3_128('hello world');"
+    qt_sql_mmh3_128_apache_doris "SELECT MURMUR_HASH3_128('apache doris');"
+    qt_sql_mmh3_128_two_args "SELECT MURMUR_HASH3_128('hello', 'world');"
+    qt_sql_mmh3_128_three_args "SELECT MURMUR_HASH3_128('hello', 'world', 
'!');"
+    qt_sql_mmh3_128_null_second "SELECT MURMUR_HASH3_128('hello', NULL);"
+    qt_sql_mmh3_128_null_first "SELECT MURMUR_HASH3_128(NULL, 'hello');"
+    qt_sql_mmh3_128_all_null "SELECT MURMUR_HASH3_128(NULL, NULL);"
+    qt_sql_mmh3_128_unicode_zh "SELECT MURMUR_HASH3_128('你好🤣');"
+    qt_sql_mmh3_128_unicode_ja "SELECT MURMUR_HASH3_128('アパッチドリス');"
+    qt_sql_mmh3_128_other_types """
+        SELECT MURMUR_HASH3_128(123),
+               MURMUR_HASH3_128(CAST(123.45 AS DECIMAL(9, 2))),
+               MURMUR_HASH3_128(CAST('2026-05-28' AS DATE));
+    """
+    qt_sql_mmh3_u128_null "SELECT MURMUR_HASH3_U128(NULL);"
+    qt_sql_mmh3_u128_empty "SELECT MURMUR_HASH3_U128('');"
+    qt_sql_mmh3_u128_hello "SELECT MURMUR_HASH3_U128('hello');"
+    qt_sql_mmh3_u128_hello_world "SELECT MURMUR_HASH3_U128('hello world');"
+    qt_sql_mmh3_u128_apache_doris "SELECT MURMUR_HASH3_U128('apache doris');"
+    qt_sql_mmh3_u128_two_args "SELECT MURMUR_HASH3_U128('hello', 'world');"
+    qt_sql_mmh3_u128_three_args "SELECT MURMUR_HASH3_U128('hello', 'world', 
'!');"
+    qt_sql_mmh3_u128_null_second "SELECT MURMUR_HASH3_U128('hello', NULL);"
+    qt_sql_mmh3_u128_null_first "SELECT MURMUR_HASH3_U128(NULL, 'hello');"
+    qt_sql_mmh3_u128_all_null "SELECT MURMUR_HASH3_U128(NULL, NULL);"
+    qt_sql_mmh3_u128_unicode_zh "SELECT MURMUR_HASH3_U128('你好🤣');"
+    qt_sql_mmh3_u128_unicode_ja "SELECT MURMUR_HASH3_U128('アパッチドリス');"
+    qt_sql_mmh3_u128_other_types """
+        SELECT MURMUR_HASH3_U128(123),
+               MURMUR_HASH3_U128(CAST(123.45 AS DECIMAL(9, 2))),
+               MURMUR_HASH3_U128(CAST('2026-05-28' AS DATE));
+    """
+
+    test {
+        sql "SELECT MURMUR_HASH3_128();"
+        exception "0 arity"
+    }
+
+    test {
+        sql "SELECT MURMUR_HASH3_U128();"
+        exception "0 arity"
+    }
+
     qt_sql "SELECT xxhash_32(null);"
     qt_sql "SELECT xxhash_32(\"hello\");"
     qt_sql "SELECT xxhash_32(\"hello\", \"world\");"


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to