From a656a7ddd402c71f2b3c541497277cdc036fbac7 Mon Sep 17 00:00:00 2001 From: Youngwb Date: Sat, 9 May 2020 08:59:34 +0800 Subject: [PATCH] Support append_trailing_char_if_absent function (#3439) --- be/src/exprs/string_functions.cpp | 19 ++++++ be/src/exprs/string_functions.h | 5 +- be/test/exprs/string_functions_test.cpp | 40 ++++++++++++- docs/.vuepress/sidebar/en.js | 1 + docs/.vuepress/sidebar/zh-CN.js | 1 + .../append_trailing_char_if_absent.md | 60 +++++++++++++++++++ .../append_trailing_char_if_absent.md | 60 +++++++++++++++++++ gensrc/script/doris_builtins_functions.py | 2 + 8 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 docs/en/sql-reference/sql-functions/string-functions/append_trailing_char_if_absent.md create mode 100644 docs/zh-CN/sql-reference/sql-functions/string-functions/append_trailing_char_if_absent.md diff --git a/be/src/exprs/string_functions.cpp b/be/src/exprs/string_functions.cpp index 06895ce29f..b02bf56837 100644 --- a/be/src/exprs/string_functions.cpp +++ b/be/src/exprs/string_functions.cpp @@ -256,6 +256,25 @@ StringVal StringFunctions::rpad( } return result; } + +StringVal StringFunctions::append_trailing_char_if_absent(doris_udf::FunctionContext* context, + const doris_udf::StringVal& str, const doris_udf::StringVal& trailing_char) { + if (str.is_null || trailing_char.is_null || trailing_char.len != 1) { + return StringVal::null(); + } + if (str.len == 0) { + return trailing_char; + } + if (str.ptr[str.len - 1] == trailing_char.ptr[0]) { + return str; + } + + StringVal result(context, str.len + 1); + memcpy(result.ptr, str.ptr, str.len); + result.ptr[str.len] = trailing_char.ptr[0]; + return result; +} + // Implementation of LENGTH // int length(string input) // Returns the length in bytes of input. If input == NULL, returns diff --git a/be/src/exprs/string_functions.h b/be/src/exprs/string_functions.h index 3c395c9b9e..13b96bcf5f 100644 --- a/be/src/exprs/string_functions.h +++ b/be/src/exprs/string_functions.h @@ -67,7 +67,10 @@ public: const doris_udf::IntVal& len, const doris_udf::StringVal& pad); static doris_udf::StringVal rpad( doris_udf::FunctionContext* context, const doris_udf::StringVal& str, - const doris_udf::IntVal& len, const doris_udf::StringVal& pad); + const doris_udf::IntVal& len, const doris_udf::StringVal& pad); + static doris_udf::StringVal append_trailing_char_if_absent( + doris_udf::FunctionContext* context, const doris_udf::StringVal& str, + const doris_udf::StringVal& trailing_char); static doris_udf::IntVal length( doris_udf::FunctionContext* context, const doris_udf::StringVal& str); static doris_udf::IntVal char_utf8_length( diff --git a/be/test/exprs/string_functions_test.cpp b/be/test/exprs/string_functions_test.cpp index 3b257b9910..2670f576eb 100644 --- a/be/test/exprs/string_functions_test.cpp +++ b/be/test/exprs/string_functions_test.cpp @@ -28,8 +28,19 @@ namespace doris { class StringFunctionsTest : public testing::Test { public: - StringFunctionsTest() { + StringFunctionsTest() = default; + + void SetUp() { + utils = new FunctionUtils(); + ctx = utils->get_fn_ctx(); } + void TearDown() { + delete utils; + } + +private: + FunctionUtils* utils; + FunctionContext* ctx; }; TEST_F(StringFunctionsTest, money_format_bigint) { @@ -319,14 +330,37 @@ TEST_F(StringFunctionsTest, length) { StringFunctions::length(context, StringVal(""))); ASSERT_EQ(IntVal(0), StringFunctions::char_utf8_length(context, StringVal(""))); - + ASSERT_EQ(IntVal(11), StringFunctions::length(context, StringVal("hello你好"))); - + ASSERT_EQ(IntVal(7), StringFunctions::char_utf8_length(context, StringVal("hello你好"))); } +TEST_F(StringFunctionsTest, append_trailing_char_if_absent) { + ASSERT_EQ(StringVal("ac"), StringFunctions::append_trailing_char_if_absent(ctx, + StringVal("a"), StringVal("c"))); + + ASSERT_EQ(StringVal("c"), StringFunctions::append_trailing_char_if_absent(ctx, + StringVal("c"), StringVal("c"))); + + ASSERT_EQ(StringVal("123c"), StringFunctions::append_trailing_char_if_absent(ctx, + StringVal("123c"), StringVal("c"))); + + ASSERT_EQ(StringVal("c"), StringFunctions::append_trailing_char_if_absent(ctx, + StringVal(""), StringVal("c"))); + + ASSERT_EQ(StringVal::null(), StringFunctions::append_trailing_char_if_absent(ctx, + StringVal::null(), StringVal("c"))); + + ASSERT_EQ(StringVal::null(), StringFunctions::append_trailing_char_if_absent(ctx, + StringVal("a"), StringVal::null())); + + ASSERT_EQ(StringVal::null(), StringFunctions::append_trailing_char_if_absent(ctx, + StringVal("a"), StringVal("abc"))); +} + } int main(int argc, char** argv) { diff --git a/docs/.vuepress/sidebar/en.js b/docs/.vuepress/sidebar/en.js index 9cbbac3fee..c603bbd814 100644 --- a/docs/.vuepress/sidebar/en.js +++ b/docs/.vuepress/sidebar/en.js @@ -195,6 +195,7 @@ module.exports = [ title: "String Functions", directoryPath: "string-functions/", children: [ + "append_trailing_char_if_absent", "ascii", "concat", "concat_ws", diff --git a/docs/.vuepress/sidebar/zh-CN.js b/docs/.vuepress/sidebar/zh-CN.js index fe666970cb..7326f7184f 100644 --- a/docs/.vuepress/sidebar/zh-CN.js +++ b/docs/.vuepress/sidebar/zh-CN.js @@ -207,6 +207,7 @@ module.exports = [ title: "字符串函数", directoryPath: "string-functions/", children: [ + "append_trailing_char_if_absent", "ascii", "concat", "concat_ws", diff --git a/docs/en/sql-reference/sql-functions/string-functions/append_trailing_char_if_absent.md b/docs/en/sql-reference/sql-functions/string-functions/append_trailing_char_if_absent.md new file mode 100644 index 0000000000..cd24883ff0 --- /dev/null +++ b/docs/en/sql-reference/sql-functions/string-functions/append_trailing_char_if_absent.md @@ -0,0 +1,60 @@ +--- +{ + "title": "append_trailing_char_if_absent", + "language": "en" +} +--- + + + +# append_trailing_char_if_absent + +## description + +### Syntax + +`VARCHAR append_trailing_char_if_absent(VARCHAR str, VARCHAR trailing_char)` + +If the s string is non-empty and does not contain the c character at the end, it appends the c character to the end. +Trailing_char contains only one character, and it will return NULL if contains more than one character + +## example + +``` +MySQL [test]> select append_trailing_char_if_absent('a','c'); ++------------------------------------------+ +| append_trailing_char_if_absent('a', 'c') | ++------------------------------------------+ +| ac | ++------------------------------------------+ +1 row in set (0.02 sec) + +MySQL [test]> select append_trailing_char_if_absent('ac','c'); ++-------------------------------------------+ +| append_trailing_char_if_absent('ac', 'c') | ++-------------------------------------------+ +| ac | ++-------------------------------------------+ +1 row in set (0.00 sec) +``` + +## keyword + +APPEND_TRAILING_CHAR_IF_ABSENT diff --git a/docs/zh-CN/sql-reference/sql-functions/string-functions/append_trailing_char_if_absent.md b/docs/zh-CN/sql-reference/sql-functions/string-functions/append_trailing_char_if_absent.md new file mode 100644 index 0000000000..b6770ef2a0 --- /dev/null +++ b/docs/zh-CN/sql-reference/sql-functions/string-functions/append_trailing_char_if_absent.md @@ -0,0 +1,60 @@ +--- +{ + "title": "append_trailing_char_if_absent", + "language": "zh-CN" +} +--- + + + +# append_trailing_char_if_absent + +## description + +### Syntax + +`VARCHAR append_trailing_char_if_absent(VARCHAR str, VARCHAR trailing_char)` + +如果's'字符串非空并且末尾不包含'c'字符,则将'c'字符附加到末尾。 +trailing_char只包含一个字符,如果包含多个字符,将返回NULL + +## example + +``` +MySQL [test]> select append_trailing_char_if_absent('a','c'); ++------------------------------------------+ +| append_trailing_char_if_absent('a', 'c') | ++------------------------------------------+ +| ac | ++------------------------------------------+ +1 row in set (0.02 sec) + +MySQL [test]> select append_trailing_char_if_absent('ac','c'); ++-------------------------------------------+ +| append_trailing_char_if_absent('ac', 'c') | ++-------------------------------------------+ +| ac | ++-------------------------------------------+ +1 row in set (0.00 sec) +``` + +## keyword + +APPEND_TRAILING_CHAR_IF_ABSENT diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py index a2d972725a..9516371f83 100755 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -531,6 +531,8 @@ visible_functions = [ [['rpad'], 'VARCHAR', ['VARCHAR', 'INT', 'VARCHAR'], '_ZN5doris15StringFunctions4rpadEPN9doris_udf' '15FunctionContextERKNS1_9StringValERKNS1_6IntValES6_'], + [['append_trailing_char_if_absent'], 'VARCHAR', ['VARCHAR', 'VARCHAR'], + '_ZN5doris15StringFunctions30append_trailing_char_if_absentEPN9doris_udf15FunctionContextERKNS1_9StringValES6_'], [['length'], 'INT', ['VARCHAR'], '_ZN5doris15StringFunctions6lengthEPN9doris_udf15FunctionContextERKNS1_9StringValE'], [['char_length', 'character_length'], 'INT', ['VARCHAR'],