You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by ya...@apache.org on 2021/09/02 01:59:20 UTC
[incubator-doris] branch master updated: [Feature]Support functions
of json_array, json_object, json_quote (#6504)
This is an automated email from the ASF dual-hosted git repository.
yangzhg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git
The following commit(s) were added to refs/heads/master by this push:
new 7a15e58 [Feature]Support functions of json_array, json_object, json_quote (#6504)
7a15e58 is described below
commit 7a15e583a7da7b19f9ba9e873ff34b1e0a780182
Author: zhangstar333 <87...@users.noreply.github.com>
AuthorDate: Thu Sep 2 09:59:02 2021 +0800
[Feature]Support functions of json_array, json_object, json_quote (#6504)
---
be/src/exprs/json_functions.cpp | 93 +++++++++++++++++-
be/src/exprs/json_functions.h | 10 ++
be/test/exprs/json_function_test.cpp | 67 ++++++++++++-
.../sql-functions/string-functions/json_array.md | 70 ++++++++++++++
.../sql-functions/string-functions/json_object.md | 71 ++++++++++++++
.../sql-functions/string-functions/json_quote.md | 70 ++++++++++++++
.../sql-functions/string-functions/json_array.md | 70 ++++++++++++++
.../sql-functions/string-functions/json_object.md | 70 ++++++++++++++
.../sql-functions/string-functions/json_quote.md | 70 ++++++++++++++
.../apache/doris/analysis/FunctionCallExpr.java | 107 ++++++++++++++++++++-
gensrc/script/doris_builtins_functions.py | 14 ++-
11 files changed, 705 insertions(+), 7 deletions(-)
diff --git a/be/src/exprs/json_functions.cpp b/be/src/exprs/json_functions.cpp
index 470902f..94e26ce 100644
--- a/be/src/exprs/json_functions.cpp
+++ b/be/src/exprs/json_functions.cpp
@@ -26,6 +26,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
+#include <iomanip>
#include <sstream>
#include <string>
#include <string_view>
@@ -34,11 +35,11 @@
#include "common/logging.h"
#include "exprs/anyval_util.h"
#include "exprs/expr.h"
+#include "gutil/strings/stringpiece.h"
#include "olap/olap_define.h"
#include "rapidjson/error/en.h"
#include "runtime/string_value.h"
#include "runtime/tuple_row.h"
-
namespace doris {
// static const re2::RE2 JSON_PATTERN("^([a-zA-Z0-9_\\-\\:\\s#\\|\\.]*)(?:\\[([0-9]+)\\])?");
@@ -108,6 +109,96 @@ DoubleVal JsonFunctions::get_json_double(FunctionContext* context, const StringV
}
}
+StringVal JsonFunctions::json_array(FunctionContext* context, int num_args,
+ const StringVal* json_str) {
+ if (json_str->is_null) {
+ return StringVal::null();
+ }
+ rapidjson::Value array_obj(rapidjson::kArrayType);
+ rapidjson::Document document;
+ rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
+ //flag: The number it contains represents the type of previous parameters
+ const StringVal& flag = json_str[num_args - 1];
+ DCHECK_EQ(num_args - 1, flag.len);
+ for (int i = 0; i < num_args - 1; ++i) {
+ const StringVal& arg = json_str[i];
+ rapidjson::Value val = parse_str_with_flag(arg, flag, i, allocator);
+ array_obj.PushBack(val, allocator);
+ }
+ rapidjson::StringBuffer buf;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(buf);
+ array_obj.Accept(writer);
+ return AnyValUtil::from_string_temp(context, std::string(buf.GetString()));
+}
+
+StringVal JsonFunctions::json_object(FunctionContext* context, int num_args,
+ const StringVal* json_str) {
+ if (json_str->is_null) {
+ return StringVal::null();
+ }
+ rapidjson::Document document(rapidjson::kObjectType);
+ rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
+ const StringVal& flag = json_str[num_args - 1];
+ document.SetObject();
+ DCHECK_EQ(num_args - 1, flag.len);
+ for (int i = 1; i < num_args - 1; i = i + 2) {
+ const StringVal& arg = json_str[i];
+ rapidjson::Value key(rapidjson::kStringType);
+ key.SetString((char*)json_str[i - 1].ptr, json_str[i - 1].len, allocator);
+ rapidjson::Value val = parse_str_with_flag(arg, flag, i, allocator);
+ document.AddMember(key, val, allocator);
+ }
+ rapidjson::StringBuffer buf;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(buf);
+ document.Accept(writer);
+ return AnyValUtil::from_string_temp(context, std::string(buf.GetString()));
+}
+
+rapidjson::Value JsonFunctions::parse_str_with_flag(const StringVal& arg, const StringVal& flag,
+ const int num,
+ rapidjson::Document::AllocatorType& allocator) {
+ rapidjson::Value val;
+ if (*(flag.ptr + num) == '0') { //null
+ rapidjson::Value nullObject(rapidjson::kNullType);
+ val = nullObject;
+ } else if (*(flag.ptr + num) == '1') { //bool
+ bool res = ((arg == "1") ? true : false);
+ val.SetBool(res);
+ } else if (*(flag.ptr + num) == '2') { //int
+ std::stringstream ss;
+ ss << arg.ptr;
+ int number = 0;
+ ss >> number;
+ val.SetInt(number);
+ } else if (*(flag.ptr + num) == '3') { //double
+ std::stringstream ss;
+ ss << arg.ptr;
+ double number = 0.0;
+ ss >> number;
+ val.SetDouble(number);
+ } else if (*(flag.ptr + num) == '4' || *(flag.ptr + num) == '5') {
+ StringPiece str((char*)arg.ptr, arg.len);
+ if (*(flag.ptr + num) == '4') str = str.substr(1, str.length() - 2);
+ val.SetString(str.data(), str.length(), allocator);
+ } else {
+ DCHECK(false) << "parse json type error with unknown type";
+ }
+ return val;
+}
+StringVal JsonFunctions::json_quote(FunctionContext* context, const StringVal& json_str) {
+ if (json_str.is_null) {
+ return StringVal::null();
+ }
+ rapidjson::Value array_obj(rapidjson::kObjectType);
+ rapidjson::Document document;
+ rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
+ array_obj.SetString(rapidjson::StringRef((char*)json_str.ptr, json_str.len));
+ rapidjson::StringBuffer buf;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(buf);
+ array_obj.Accept(writer);
+ return AnyValUtil::from_string_temp(context, std::string(buf.GetString()));
+}
+
rapidjson::Value* JsonFunctions::match_value(const std::vector<JsonPath>& parsed_paths,
rapidjson::Value* document,
rapidjson::Document::AllocatorType& mem_allocator,
diff --git a/be/src/exprs/json_functions.h b/be/src/exprs/json_functions.h
index 86ce673..c16d51c 100644
--- a/be/src/exprs/json_functions.h
+++ b/be/src/exprs/json_functions.h
@@ -88,6 +88,13 @@ public:
const JsonFunctionType& fntype,
rapidjson::Document* document);
+ static doris_udf::StringVal json_array(doris_udf::FunctionContext* context, int num_args,
+ const doris_udf::StringVal* json_str);
+ static doris_udf::StringVal json_object(doris_udf::FunctionContext* context, int num_args,
+ const doris_udf::StringVal* json_str);
+ static doris_udf::StringVal json_quote(doris_udf::FunctionContext* context,
+ const doris_udf::StringVal& json_str);
+
/**
* The `document` parameter must be has parsed.
* return Value Is Array object
@@ -122,6 +129,9 @@ private:
bool is_insert_null = false);
static void get_parsed_paths(const std::vector<std::string>& path_exprs,
std::vector<JsonPath>* parsed_paths);
+ static rapidjson::Value parse_str_with_flag(const StringVal& arg, const StringVal& flag,
+ const int num,
+ rapidjson::Document::AllocatorType& allocator);
};
} // namespace doris
#endif
diff --git a/be/test/exprs/json_function_test.cpp b/be/test/exprs/json_function_test.cpp
index d1c4a4f..354f36a 100644
--- a/be/test/exprs/json_function_test.cpp
+++ b/be/test/exprs/json_function_test.cpp
@@ -26,11 +26,11 @@
#include <string>
#include "common/object_pool.h"
+#include "exprs/anyval_util.h"
#include "exprs/json_functions.h"
#include "runtime/runtime_state.h"
#include "util/logging.h"
#include "util/stopwatch.hpp"
-
namespace doris {
// mock
@@ -106,6 +106,71 @@ TEST_F(JsonFunctionTest, string) {
ASSERT_EQ(std::string(buf5_3.GetString()), "205705999");
}
+TEST_F(JsonFunctionTest, json_quote) {
+ doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
+
+ ASSERT_EQ(StringVal::null(), JsonFunctions::json_quote(context, StringVal::null()));
+
+ doris_udf::StringVal res1 = JsonFunctions::json_quote(context, StringVal("null"));
+ ASSERT_EQ(std::string("\"null\""), std::string((char*)res1.ptr, res1.len));
+
+ doris_udf::StringVal res2 = JsonFunctions::json_quote(context, StringVal("[1, 2, 3]"));
+ ASSERT_EQ(std::string("\"[1, 2, 3]\""), std::string((char*)res2.ptr, res2.len));
+
+ doris_udf::StringVal res3 = JsonFunctions::json_quote(context, StringVal("\n\b\r\t"));
+ ASSERT_EQ(std::string("\"\\n\\b\\r\\t\""), std::string((char*)res3.ptr, res3.len));
+
+ doris_udf::StringVal res4 = JsonFunctions::json_quote(context, StringVal("\""));
+ ASSERT_EQ(std::string("\"\\\"\""), std::string((char*)res4.ptr, res4.len));
+
+ doris_udf::StringVal json_str= {""};
+ doris_udf::StringVal res5 = JsonFunctions::json_quote(context, json_str);
+ ASSERT_EQ(std::string("\"\""), std::string((char*)res5.ptr, res5.len));
+ delete context;
+}
+
+TEST_F(JsonFunctionTest, json_array) {
+ doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
+
+ doris_udf::StringVal json_str1[2] = {"[1,2,3]", "5"};
+ doris_udf::StringVal res1 = JsonFunctions::json_array(context, 2, json_str1);
+ ASSERT_EQ(std::string("[\"[1,2,3]\"]"), std::string((char*)res1.ptr, res1.len));
+
+ doris_udf::StringVal json_str2[4] = {"1", "abc", "null", "250"};
+ doris_udf::StringVal res2 = JsonFunctions::json_array(context, 4, json_str2);
+ ASSERT_EQ(std::string("[1,\"abc\",null]"), std::string((char*)res2.ptr, res2.len));
+
+ doris_udf::StringVal json_str3[1]= {""};
+ doris_udf::StringVal res3 = JsonFunctions::json_array(context, 1, json_str3);
+ ASSERT_EQ(std::string("[]"), std::string((char*)res3.ptr, res3.len));
+
+ doris_udf::StringVal json_str4[2]= {"null","0"};
+ doris_udf::StringVal res4 = JsonFunctions::json_array(context, 2, json_str4);
+ ASSERT_EQ(std::string("[null]"), std::string((char*)res4.ptr, res4.len));
+ delete context;
+}
+
+TEST_F(JsonFunctionTest, json_object) {
+ doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
+ doris_udf::StringVal json_str1[3] = {"id", "87", "52"};
+ doris_udf::StringVal res1 = JsonFunctions::json_object(context, 3, json_str1);
+ ASSERT_EQ(std::string("{\"id\":87}"), std::string((char*)res1.ptr, res1.len));
+
+ doris_udf::StringVal json_str2[5] = {"name", "Jack", "score", "[87,98,90]", "5555"};
+ doris_udf::StringVal res2 = JsonFunctions::json_object(context, 5, json_str2);
+ ASSERT_EQ(std::string("{\"name\":\"Jack\",\"score\":\"[87,98,90]\"}"),
+ std::string((char*)res2.ptr, res2.len));
+
+ doris_udf::StringVal json_str3[3] = {"key", "null","50"};
+ doris_udf::StringVal res3 = JsonFunctions::json_object(context, 3, json_str3);
+ ASSERT_EQ(std::string("{\"key\":null}"), std::string((char*)res3.ptr, res3.len));
+
+ doris_udf::StringVal json_str4[1]= {""};
+ doris_udf::StringVal res4 = JsonFunctions::json_object(context, 1, json_str4);
+ ASSERT_EQ(std::string("{}"), std::string((char*)res4.ptr, res4.len));
+ delete context;
+}
+
TEST_F(JsonFunctionTest, int) {
std::string json_string("{\"id\":\"name\",\"age\":11,\"money\":123000.789}");
std::string path_string("$.age");
diff --git a/docs/en/sql-reference/sql-functions/string-functions/json_array.md b/docs/en/sql-reference/sql-functions/string-functions/json_array.md
new file mode 100644
index 0000000..cceb11c
--- /dev/null
+++ b/docs/en/sql-reference/sql-functions/string-functions/json_array.md
@@ -0,0 +1,70 @@
+---
+{
+ "title": "json_array",
+ "language": "en"
+}
+---
+
+<!--
+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.
+-->
+
+# json_array
+## Description
+### Syntax
+
+`VARCHAR json_array(VARCHAR,...)`
+
+
+Generate a json array containing the specified values, return empty if no values
+
+## example
+
+```
+MySQL> select json_array();
++--------------+
+| json_array() |
++--------------+
+| [] |
++--------------+
+
+MySQL> select json_array(null);
++--------------------+
+| json_array('NULL') |
++--------------------+
+| [NULL] |
++--------------------+
+
+
+MySQL> SELECT json_array(1, "abc", NULL, TRUE, CURTIME());
++-----------------------------------------------+
+| json_array(1, 'abc', 'NULL', TRUE, curtime()) |
++-----------------------------------------------+
+| [1, "abc", NULL, TRUE, "10:41:15"] |
++-----------------------------------------------+
+
+
+MySQL> select json_array("a", null, "c");
++------------------------------+
+| json_array('a', 'NULL', 'c') |
++------------------------------+
+| ["a", NULL, "c"] |
++------------------------------+
+```
+## keyword
+json_array
diff --git a/docs/en/sql-reference/sql-functions/string-functions/json_object.md b/docs/en/sql-reference/sql-functions/string-functions/json_object.md
new file mode 100644
index 0000000..917f172
--- /dev/null
+++ b/docs/en/sql-reference/sql-functions/string-functions/json_object.md
@@ -0,0 +1,71 @@
+---
+{
+ "title": "json_object",
+ "language": "en"
+}
+---
+
+<!--
+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.
+-->
+
+# json_object
+## Description
+### Syntax
+
+`VARCHAR json_object(VARCHAR,...)`
+
+
+Generate a json object containing the specified Key-Value,
+an exception error is returned when Key is NULL or the number of parameters are odd.
+
+## example
+
+```
+MySQL> select json_object();
++---------------+
+| json_object() |
++---------------+
+| {} |
++---------------+
+
+MySQL> select json_object('time',curtime());
++--------------------------------+
+| json_object('time', curtime()) |
++--------------------------------+
+| {"time": "10:49:18"} |
++--------------------------------+
+
+
+MySQL> SELECT json_object('id', 87, 'name', 'carrot');
++-----------------------------------------+
+| json_object('id', 87, 'name', 'carrot') |
++-----------------------------------------+
+| {"id": 87, "name": "carrot"} |
++-----------------------------------------+
+
+
+MySQL> select json_object('username',null);
++---------------------------------+
+| json_object('username', 'NULL') |
++---------------------------------+
+| {"username": NULL} |
++---------------------------------+
+```
+## keyword
+json_object
diff --git a/docs/en/sql-reference/sql-functions/string-functions/json_quote.md b/docs/en/sql-reference/sql-functions/string-functions/json_quote.md
new file mode 100644
index 0000000..e02168e
--- /dev/null
+++ b/docs/en/sql-reference/sql-functions/string-functions/json_quote.md
@@ -0,0 +1,70 @@
+---
+{
+ "title": "json_quote",
+ "language": "en"
+}
+---
+
+<!--
+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.
+-->
+
+# json_quote
+## Description
+### Syntax
+
+`VARCHAR json_quote(VARCHAR)`
+
+
+Enclose json_value in double quotes ("), escape special characters contained.
+
+## example
+
+```
+MySQL> SELECT json_quote('null'), json_quote('"null"');
++--------------------+----------------------+
+| json_quote('null') | json_quote('"null"') |
++--------------------+----------------------+
+| "null" | "\"null\"" |
++--------------------+----------------------+
+
+
+MySQL> SELECT json_quote('[1, 2, 3]');
++-------------------------+
+| json_quote('[1, 2, 3]') |
++-------------------------+
+| "[1, 2, 3]" |
++-------------------------+
+
+
+MySQL> SELECT json_quote(null);
++------------------+
+| json_quote(null) |
++------------------+
+| NULL |
++------------------+
+
+MySQL> select json_quote("\n\b\r\t");
++------------------------+
+| json_quote('\n\b\r\t') |
++------------------------+
+| "\n\b\r\t" |
++------------------------+
+```
+## keyword
+json_quote
diff --git a/docs/zh-CN/sql-reference/sql-functions/string-functions/json_array.md b/docs/zh-CN/sql-reference/sql-functions/string-functions/json_array.md
new file mode 100644
index 0000000..ff6a622
--- /dev/null
+++ b/docs/zh-CN/sql-reference/sql-functions/string-functions/json_array.md
@@ -0,0 +1,70 @@
+---
+{
+ "title": "json_array",
+ "language": "zh-CN"
+}
+---
+
+<!--
+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.
+-->
+
+# json_array
+## description
+### Syntax
+
+`VARCHAR json_array(VARCHAR,...)`
+
+
+生成一个包含指定元素的json数组,未指定时返回空数组
+
+## example
+
+```
+MySQL> select json_array();
++--------------+
+| json_array() |
++--------------+
+| [] |
++--------------+
+
+MySQL> select json_array(null);
++--------------------+
+| json_array('NULL') |
++--------------------+
+| [NULL] |
++--------------------+
+
+
+MySQL> SELECT json_array(1, "abc", NULL, TRUE, CURTIME());
++-----------------------------------------------+
+| json_array(1, 'abc', 'NULL', TRUE, curtime()) |
++-----------------------------------------------+
+| [1, "abc", NULL, TRUE, "10:41:15"] |
++-----------------------------------------------+
+
+
+MySQL> select json_array("a", null, "c");
++------------------------------+
+| json_array('a', 'NULL', 'c') |
++------------------------------+
+| ["a", NULL, "c"] |
++------------------------------+
+```
+## keyword
+json_array
diff --git a/docs/zh-CN/sql-reference/sql-functions/string-functions/json_object.md b/docs/zh-CN/sql-reference/sql-functions/string-functions/json_object.md
new file mode 100644
index 0000000..0f3b1fe
--- /dev/null
+++ b/docs/zh-CN/sql-reference/sql-functions/string-functions/json_object.md
@@ -0,0 +1,70 @@
+---
+{
+ "title": "json_object",
+ "language": "zh-CN"
+}
+---
+
+<!--
+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.
+-->
+
+# json_object
+## description
+### Syntax
+
+`VARCHAR json_object(VARCHAR,...)`
+
+
+生成一个包含指定Key-Value对的json object, 当Key值为NULL或者传入参数为奇数个时,返回异常错误
+
+## example
+
+```
+MySQL> select json_object();
++---------------+
+| json_object() |
++---------------+
+| {} |
++---------------+
+
+MySQL> select json_object('time',curtime());
++--------------------------------+
+| json_object('time', curtime()) |
++--------------------------------+
+| {"time": "10:49:18"} |
++--------------------------------+
+
+
+MySQL> SELECT json_object('id', 87, 'name', 'carrot');
++-----------------------------------------+
+| json_object('id', 87, 'name', 'carrot') |
++-----------------------------------------+
+| {"id": 87, "name": "carrot"} |
++-----------------------------------------+
+
+
+MySQL> select json_object('username',null);
++---------------------------------+
+| json_object('username', 'NULL') |
++---------------------------------+
+| {"username": NULL} |
++---------------------------------+
+```
+## keyword
+json_object
diff --git a/docs/zh-CN/sql-reference/sql-functions/string-functions/json_quote.md b/docs/zh-CN/sql-reference/sql-functions/string-functions/json_quote.md
new file mode 100644
index 0000000..67ed605
--- /dev/null
+++ b/docs/zh-CN/sql-reference/sql-functions/string-functions/json_quote.md
@@ -0,0 +1,70 @@
+---
+{
+ "title": "json_quote",
+ "language": "zh-CN"
+}
+---
+
+<!--
+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.
+-->
+
+# json_quote
+## description
+### Syntax
+
+`VARCHAR json_quote(VARCHAR)`
+
+
+将json_value用双引号(")括起来,跳过其中包含的特殊转义字符
+
+## example
+
+```
+MySQL> SELECT json_quote('null'), json_quote('"null"');
++--------------------+----------------------+
+| json_quote('null') | json_quote('"null"') |
++--------------------+----------------------+
+| "null" | "\"null\"" |
++--------------------+----------------------+
+
+
+MySQL> SELECT json_quote('[1, 2, 3]');
++-------------------------+
+| json_quote('[1, 2, 3]') |
++-------------------------+
+| "[1, 2, 3]" |
++-------------------------+
+
+
+MySQL> SELECT json_quote(null);
++------------------+
+| json_quote(null) |
++------------------+
+| NULL |
++------------------+
+
+MySQL> select json_quote("\n\b\r\t");
++------------------------+
+| json_quote('\n\b\r\t') |
++------------------------+
+| "\n\b\r\t" |
++------------------------+
+```
+## keyword
+json_quote
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java
index 18c8ddd..a624cb0 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java
@@ -44,6 +44,7 @@ import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Lists;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -53,7 +54,7 @@ import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
-
+import java.text.StringCharacterIterator;
// TODO: for aggregations, we need to unify the code paths for builtins and UDAs.
public class FunctionCallExpr extends Expr {
private static final Logger LOG = LogManager.getLogger(FunctionCallExpr.class);
@@ -74,12 +75,14 @@ public class FunctionCallExpr extends Expr {
.add("stddev").add("stddev_val").add("stddev_samp")
.add("variance").add("variance_pop").add("variance_pop").add("var_samp").add("var_pop").build();
private static final String ELEMENT_EXTRACT_FN_NAME = "%element_extract%";
-
+
+ //use to record the num of json_object parameters
+ private int originChildSize;
// Save the functionCallExpr in the original statement
private Expr originStmtFnExpr;
private boolean isRewrote = false;
-
+
public void setIsAnalyticFnCall(boolean v) {
isAnalyticFnCall = v;
}
@@ -125,6 +128,7 @@ public class FunctionCallExpr extends Expr {
this.isMergeAggFn = isMergeAggFn;
if (params.exprs() != null) {
children.addAll(params.exprs());
+ originChildSize = children.size();
}
}
@@ -162,6 +166,31 @@ public class FunctionCallExpr extends Expr {
fn = other.fn;
}
+ public String parseJsonDataType(boolean useKeyCheck) throws AnalysisException {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < children.size(); ++i) {
+ Type type = getChild(i).getType();
+ if (type.isNull()) { //Not to return NULL directly, so save string, but flag is '0'
+ if (((i & 1) == 0) && useKeyCheck == true) {
+ throw new AnalysisException("json_object key can't be NULL: " + this.toSql());
+ }
+ children.set(i, new StringLiteral("NULL"));
+ sb.append("0");
+ } else if (type.isBoolean()) {
+ sb.append("1");
+ } else if (type.isFixedPointType()) {
+ sb.append("2");
+ } else if (type.isFloatingPointType() || type.isDecimalV2()) {
+ sb.append("3");
+ } else if (type.isTime()) {
+ sb.append("4");
+ } else {
+ sb.append("5");
+ }
+ }
+ return sb.toString();
+ }
+
public boolean isMergeAggFn() {
return isMergeAggFn;
}
@@ -209,8 +238,22 @@ public class FunctionCallExpr extends Expr {
}
if (((FunctionCallExpr) expr).fnParams.isDistinct()) {
sb.append("DISTINCT ");
+ }
+ boolean isJsonFunction = false;
+ int len = children.size();
+ List<String> result = Lists.newArrayList();
+ if ((fnName.getFunction().equalsIgnoreCase("json_array")) ||
+ (fnName.getFunction().equalsIgnoreCase("json_object"))) {
+ len = len - 1;
+ isJsonFunction = true;
+ }
+ for (int i = 0; i < len; ++i) {
+ result.add(children.get(i).toSql());
+ }
+ sb.append(Joiner.on(", ").join(result)).append(")");
+ if (fnName.getFunction().equalsIgnoreCase("json_quote") || isJsonFunction) {
+ return forJSON(sb.toString());
}
- sb.append(Joiner.on(", ").join(expr.childrenToSql())).append(")");
return sb.toString();
}
@@ -322,6 +365,25 @@ public class FunctionCallExpr extends Expr {
}
return;
}
+
+ if(fnName.getFunction().equalsIgnoreCase("json_array")) {
+ String res = parseJsonDataType(false);
+ if (children.size() == originChildSize) {
+ children.add(new StringLiteral(res));
+ }
+ return;
+ }
+
+ if(fnName.getFunction().equalsIgnoreCase("json_object")) {
+ if ((children.size()&1) == 1 && (originChildSize == children.size())) {
+ throw new AnalysisException("json_object can't be odd parameters, need even parameters: " + this.toSql());
+ }
+ String res = parseJsonDataType(true);
+ if (children.size() == originChildSize) {
+ children.add(new StringLiteral(res));
+ }
+ return;
+ }
if (fnName.getFunction().equalsIgnoreCase("group_concat")) {
if (children.size() > 2 || children.isEmpty()) {
@@ -510,6 +572,7 @@ public class FunctionCallExpr extends Expr {
}
}
}
+
}
// Provide better error message for some aggregate builtins. These can be
@@ -914,4 +977,40 @@ public class FunctionCallExpr extends Expr {
result = 31 * result + Objects.hashCode(fnParams);
return result;
}
+ public String forJSON(String str){
+ final StringBuilder result = new StringBuilder();
+ StringCharacterIterator iterator = new StringCharacterIterator(str);
+ char character = iterator.current();
+ while (character != StringCharacterIterator.DONE){
+ if( character == '\"' ){
+ result.append("\\\"");
+ }
+ else if(character == '\\'){
+ result.append("\\\\");
+ }
+ else if(character == '/'){
+ result.append("\\/");
+ }
+ else if(character == '\b'){
+ result.append("\\b");
+ }
+ else if(character == '\f'){
+ result.append("\\f");
+ }
+ else if(character == '\n'){
+ result.append("\\n");
+ }
+ else if(character == '\r'){
+ result.append("\\r");
+ }
+ else if(character == '\t'){
+ result.append("\\t");
+ }
+ else {
+ result.append(character);
+ }
+ character = iterator.next();
+ }
+ return result.toString();
+ }
}
diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py
index 032b7ad..0a7a742 100755
--- a/gensrc/script/doris_builtins_functions.py
+++ b/gensrc/script/doris_builtins_functions.py
@@ -1125,6 +1125,16 @@ visible_functions = [
'_ZN5doris13JsonFunctions15json_path_closeEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
'vec', ''],
+ [['json_array'], 'VARCHAR', ['VARCHAR', '...'],
+ '_ZN5doris13JsonFunctions10json_arrayEPN9doris_udf15FunctionContextEiPKNS1_9StringValE',
+ '', '', '', ''],
+ [['json_object'], 'VARCHAR', ['VARCHAR', '...'],
+ '_ZN5doris13JsonFunctions11json_objectEPN9doris_udf15FunctionContextEiPKNS1_9StringValE',
+ '', '', '', ''],
+ [['json_quote'], 'VARCHAR', ['VARCHAR'],
+ '_ZN5doris13JsonFunctions10json_quoteEPN9doris_udf15FunctionContextERKNS1_9StringValE',
+ '', '', '', ''],
+
#hll function
[['hll_cardinality'], 'BIGINT', ['VARCHAR'],
'_ZN5doris12HllFunctions15hll_cardinalityEPN9doris_udf15FunctionContextERKNS1_9StringValE',
@@ -1330,7 +1340,9 @@ non_null_result_with_null_param_functions = [
'nullif',
'null_or_empty',
'coalesce',
- 'array'
+ 'array',
+ 'json_array',
+ 'json_object'
]
# Nondeterministic functions may return different results each time they are called
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org