diff --git a/be/src/vec/functions/function_string.cpp b/be/src/vec/functions/function_string.cpp index ab4ac6c86a..ce2c94b937 100644 --- a/be/src/vec/functions/function_string.cpp +++ b/be/src/vec/functions/function_string.cpp @@ -1116,6 +1116,7 @@ void register_function_string(SimpleFunctionFactory& factory) { factory.register_function(); factory.register_function(); factory.register_function(); + factory.register_function(); factory.register_function>(); factory.register_function>(); factory.register_function>(); diff --git a/be/src/vec/functions/function_string.h b/be/src/vec/functions/function_string.h index f57fe6d626..c789345743 100644 --- a/be/src/vec/functions/function_string.h +++ b/be/src/vec/functions/function_string.h @@ -26,8 +26,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -2879,6 +2882,61 @@ public: } }; +class FunctionRandomBytes : public IFunction { +public: + static constexpr auto name = "random_bytes"; + static FunctionPtr create() { return std::make_shared(); } + String get_name() const override { return name; } + size_t get_number_of_arguments() const override { return 1; } + bool is_variadic() const override { return false; } + + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + return std::make_shared(); + } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + size_t result, size_t input_rows_count) const override { + auto res = ColumnString::create(); + auto& res_offsets = res->get_offsets(); + auto& res_chars = res->get_chars(); + res_offsets.resize(input_rows_count); + + ColumnPtr argument_column = + block.get_by_position(arguments[0]).column->convert_to_full_column_if_const(); + const auto* length_col = check_and_get_column(argument_column.get()); + + if (!length_col) { + return Status::InternalError("Not supported input argument type"); + } + + std::vector random_bytes; + std::random_device rd; + std::mt19937 gen(rd()); + + for (size_t i = 0; i < input_rows_count; ++i) { + UInt64 length = length_col->get64(i); + random_bytes.resize(length); + + std::uniform_int_distribution distribution(0, 255); + for (auto& byte : random_bytes) { + byte = distribution(gen); + } + + std::ostringstream oss; + for (const auto& byte : random_bytes) { + oss << std::setw(2) << std::setfill('0') << std::hex << static_cast(byte); + } + + StringOP::push_value_string("0x" + oss.str(), i, res_chars, res_offsets); + random_bytes.clear(); + } + + block.get_by_position(result).column = std::move(res); + + return Status::OK(); + } +}; + template class FunctionMoneyFormat : public IFunction { public: diff --git a/docs/en/docs/sql-manual/sql-functions/string-functions/random_bytes.md b/docs/en/docs/sql-manual/sql-functions/string-functions/random_bytes.md new file mode 100644 index 0000000000..0e54641d29 --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/string-functions/random_bytes.md @@ -0,0 +1,54 @@ +--- +{ + "title": "random_bytes", + "language": "en" +} +--- + + + +## random_bytes +### description + +The `random_bytes` function generates a sequence of random bytes. + +#### Syntax + +```sql +VARCHAR random_bytes(INT len) +``` + +### Parameters + +- len: The `random_bytes` function takes a single argument, which specifies the length of the generated random byte sequence. + +### example + +``` +mysql> select random_bytes(7); ++------------------------------------------------+ +| random_bytes(7) | ++------------------------------------------------+ +| 0x53edd97401fb6d | ++------------------------------------------------+ +``` + +### keywords + RANDOM BYTES diff --git a/docs/sidebars.json b/docs/sidebars.json index 44f226723f..b44a593e38 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -520,6 +520,7 @@ "sql-manual/sql-functions/string-functions/space", "sql-manual/sql-functions/string-functions/sleep", "sql-manual/sql-functions/string-functions/esquery", + "sql-manual/sql-functions/string-functions/random_bytes", { "type": "category", "label": "Search in String", diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/string-functions/random_bytes.md b/docs/zh-CN/docs/sql-manual/sql-functions/string-functions/random_bytes.md new file mode 100644 index 0000000000..bceb2a8824 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/string-functions/random_bytes.md @@ -0,0 +1,54 @@ +--- +{ + "title": "random_bytes", + "language": "zh-CN" +} +--- + + + +## random_bytes +### description + +random_bytes函数用于生成随机字节序列。 + +#### Syntax + +```sql +VARCHAR random_bytes(INT len) +``` + +### Parameters + +- len: 该参数指定生成的随机字节序列的长度。 + +### example + +``` +mysql> select random_bytes(7); ++------------------------------------------------+ +| random_bytes(7) | ++------------------------------------------------+ +| 0x53edd97401fb6d | ++------------------------------------------------+ +``` + +### keywords + RANDOM BYTES diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/string-functions/url-decode.md b/docs/zh-CN/docs/sql-manual/sql-functions/string-functions/url-decode.md index 8b171bf573..01fb280db4 100644 --- a/docs/zh-CN/docs/sql-manual/sql-functions/string-functions/url-decode.md +++ b/docs/zh-CN/docs/sql-manual/sql-functions/string-functions/url-decode.md @@ -1,7 +1,7 @@ --- { "title": "url_decode", - "language": "en" + "language": "zh-CN" } --- 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 33f353503a..9d19ea9e2e 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 @@ -318,6 +318,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.QuantileState import org.apache.doris.nereids.trees.expressions.functions.scalar.Quarter; import org.apache.doris.nereids.trees.expressions.functions.scalar.Radians; import org.apache.doris.nereids.trees.expressions.functions.scalar.Random; +import org.apache.doris.nereids.trees.expressions.functions.scalar.RandomBytes; import org.apache.doris.nereids.trees.expressions.functions.scalar.RegexpExtract; import org.apache.doris.nereids.trees.expressions.functions.scalar.RegexpExtractAll; import org.apache.doris.nereids.trees.expressions.functions.scalar.RegexpReplace; @@ -796,6 +797,7 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(SecondTimestamp.class, "second_timestamp"), scalar(MilliSecondTimestamp.class, "millisecond_timestamp"), scalar(MicroSecondTimestamp.class, "microsecond_timestamp"), + scalar(RandomBytes.class, "random_bytes"), scalar(Sha1.class, "sha1", "sha"), scalar(Sha2.class, "sha2"), scalar(Sign.class, "sign"), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/RandomBytes.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/RandomBytes.java new file mode 100644 index 0000000000..f5906670f8 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/RandomBytes.java @@ -0,0 +1,71 @@ +// 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 'random_bytes'. This class is generated by GenerateFunction. + */ +public class RandomBytes extends ScalarFunction + implements ExplicitlyCastableSignature, PropagateNullable { + + public static final List SIGNATURES = ImmutableList.of( + FunctionSignature.ret(StringType.INSTANCE).args(IntegerType.INSTANCE), + FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(IntegerType.INSTANCE) + ); + + /** + * constructor with 1 argument. + */ + public RandomBytes(Expression arg0) { + super("random_bytes", arg0); + } + + + /** + * withChildren. + */ + @Override + public RandomBytes withChildren(List children) { + Preconditions.checkArgument(children.size() == 1); + return new RandomBytes(children.get(0)); + } + + @Override + public List getSignatures() { + return SIGNATURES; + } + + @Override + public R accept(ExpressionVisitor visitor, C context) { + return visitor.visitRandomBytes(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 7bf020ad84..7cef47557c 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 @@ -317,6 +317,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.QuantileState import org.apache.doris.nereids.trees.expressions.functions.scalar.Quarter; import org.apache.doris.nereids.trees.expressions.functions.scalar.Radians; import org.apache.doris.nereids.trees.expressions.functions.scalar.Random; +import org.apache.doris.nereids.trees.expressions.functions.scalar.RandomBytes; import org.apache.doris.nereids.trees.expressions.functions.scalar.RegexpExtract; import org.apache.doris.nereids.trees.expressions.functions.scalar.RegexpExtractAll; import org.apache.doris.nereids.trees.expressions.functions.scalar.RegexpReplace; @@ -1592,6 +1593,10 @@ public interface ScalarFunctionVisitor { return visitScalarFunction(urlDecode, context); } + default R visitRandomBytes(RandomBytes randomBytes, C context) { + return visitScalarFunction(randomBytes, context); + } + default R visitPassword(Password password, C context) { return visitScalarFunction(password, context); } diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py index 0e96d3fa75..629f83f6a1 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -1612,6 +1612,7 @@ visible_functions = { [['substring_index'], 'VARCHAR', ['VARCHAR', 'VARCHAR', 'INT'], 'DEPEND_ON_ARGUMENT'], [['extract_url_parameter'], 'VARCHAR', ['VARCHAR', 'VARCHAR'], ''], [['url_decode'], 'VARCHAR', ['VARCHAR'], ''], + [['random_bytes'], 'VARCHAR', ['INT'], ''], [['sub_replace'], 'VARCHAR', ['VARCHAR', 'VARCHAR', 'INT'], 'ALWAYS_NULLABLE'], [['sub_replace'], 'VARCHAR', ['VARCHAR', 'VARCHAR', 'INT', 'INT'], 'ALWAYS_NULLABLE'], @@ -1666,7 +1667,8 @@ visible_functions = { [['money_format'], 'STRING', ['DECIMAL128'], ''], [['split_part'], 'STRING', ['STRING', 'STRING', 'INT'], 'ALWAYS_NULLABLE'], [['substring_index'], 'STRING', ['STRING', 'STRING', 'INT'], 'DEPEND_ON_ARGUMENT'], - [['url_decode'], 'STRING', ['STRING'], ''] + [['url_decode'], 'STRING', ['STRING'], ''], + [['random_bytes'], 'STRING', ['INT'], ''] ], diff --git a/regression-test/data/nereids_function_p0/scalar_function/R.out b/regression-test/data/nereids_function_p0/scalar_function/R.out index 1aaff36e65..7b8252223a 100644 --- a/regression-test/data/nereids_function_p0/scalar_function/R.out +++ b/regression-test/data/nereids_function_p0/scalar_function/R.out @@ -1101,3 +1101,6 @@ string3 string3 string3 +-- !sql_random_bytes -- +\N + diff --git a/regression-test/suites/nereids_function_p0/scalar_function/R.groovy b/regression-test/suites/nereids_function_p0/scalar_function/R.groovy index 597841acde..fa58e6d0cb 100644 --- a/regression-test/suites/nereids_function_p0/scalar_function/R.groovy +++ b/regression-test/suites/nereids_function_p0/scalar_function/R.groovy @@ -99,4 +99,6 @@ suite("nereids_scalar_fn_R") { qt_sql_rtrim_Varchar_Varchar_notnull "select rtrim(kvchrs1, '1') from fn_test_not_nullable order by kvchrs1" qt_sql_rtrim_String_String "select rtrim(kstr, '1') from fn_test order by kstr" qt_sql_rtrim_String_String_notnull "select rtrim(kstr, '1') from fn_test_not_nullable order by kstr" + sql "SELECT random_bytes(7);" + qt_sql_random_bytes "SELECT random_bytes(null);" }