You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2022/10/19 00:44:15 UTC
[doris] branch master updated: [feature](jsonb) jsonb functions (#13366)
This is an automated email from the ASF dual-hosted git repository.
morningman 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 755a946516 [feature](jsonb) jsonb functions (#13366)
755a946516 is described below
commit 755a9465169dfdc8074e2e7ed7d456bfed5766d8
Author: Kang <kx...@gmail.com>
AuthorDate: Wed Oct 19 08:44:08 2022 +0800
[feature](jsonb) jsonb functions (#13366)
Issue Number: Step3 of DSIP-016: Support JSON type
---
be/src/util/jsonb_document.h | 122 ++++-
be/src/util/jsonb_writer.h | 3 +-
be/src/vec/functions/function_jsonb.cpp | 363 ++++++++++++-
be/test/vec/function/function_jsonb_test.cpp | 771 ++++++++++++++++++++++++++-
be/test/vec/function/function_test_util.cpp | 9 +
be/test/vec/function/function_test_util.h | 28 +-
gensrc/script/doris_builtins_functions.py | 56 ++
7 files changed, 1284 insertions(+), 68 deletions(-)
diff --git a/be/src/util/jsonb_document.h b/be/src/util/jsonb_document.h
index 94b3c9cc8a..98f98b8377 100644
--- a/be/src/util/jsonb_document.h
+++ b/be/src/util/jsonb_document.h
@@ -72,6 +72,8 @@
#include <limits>
+// #include "util/string_parser.hpp"
+
namespace doris {
#pragma pack(push, 1)
@@ -348,6 +350,34 @@ public:
JsonbType type() const { return type_; }
+ const char* typeName() const {
+ switch (type_) {
+ case JsonbType::T_Null:
+ return "null";
+ case JsonbType::T_True:
+ case JsonbType::T_False:
+ return "bool";
+ case JsonbType::T_Int8:
+ case JsonbType::T_Int16:
+ case JsonbType::T_Int32:
+ return "int";
+ case JsonbType::T_Int64:
+ return "bigint";
+ case JsonbType::T_Double:
+ return "double";
+ case JsonbType::T_String:
+ return "string";
+ case JsonbType::T_Binary:
+ return "binary";
+ case JsonbType::T_Object:
+ return "object";
+ case JsonbType::T_Array:
+ return "array";
+ default:
+ return "unknown";
+ }
+ }
+
// size of the total packed bytes
unsigned int numPackedBytes() const;
@@ -997,7 +1027,20 @@ inline const char* JsonbValue::getValuePtr() const {
inline JsonbValue* JsonbValue::findPath(const char* key_path, unsigned int kp_len,
const char* delim = ".", hDictFind handler = nullptr) {
- if (!key_path || !kp_len) return nullptr;
+ if (!key_path) return nullptr;
+ if (kp_len == 0) return this;
+
+ // skip $ and . at beginning
+ if (kp_len > 0 && *key_path == '$') {
+ key_path++;
+ kp_len--;
+ if (kp_len > 0 && *key_path == '.') {
+ key_path++;
+ kp_len--;
+ }
+ }
+
+ if (kp_len == 0) return this;
if (!delim) delim = "."; // default delimiter
@@ -1008,37 +1051,66 @@ inline JsonbValue* JsonbValue::findPath(const char* key_path, unsigned int kp_le
while (pval && key_path < fence) {
const char* key = key_path;
unsigned int klen = 0;
- // find the current key
- for (; key_path != fence && *key_path != *delim; ++key_path, ++klen)
- ;
-
- if (!klen) return nullptr;
-
- switch (pval->type_) {
- case JsonbType::T_Object: {
- pval = ((ObjectVal*)pval)->find(key, klen, handler);
- break;
+ const char* left_bracket = nullptr;
+ const char* right_bracket = nullptr;
+ size_t idx_len = 0;
+ // find the current key and [] bracket position
+ for (; key_path != fence && *key_path != *delim; ++key_path, ++klen) {
+ if ('[' == *key_path) {
+ left_bracket = key_path;
+ } else if (']' == *key_path) {
+ right_bracket = key_path;
+ }
}
- case JsonbType::T_Array: {
- // parse string into an integer (array index)
- if (klen >= sizeof(idx_buf)) return nullptr;
+ // check brackets and array index length
+ if (left_bracket || right_bracket) {
+ if (!left_bracket || !right_bracket) {
+ return nullptr;
+ }
+ // check the last char is ]
+ if (key + klen - 1 != right_bracket) {
+ return nullptr;
+ }
+ // the part before left_bracket is object key
+ klen = left_bracket - key;
+ // the part between left_bracket and right_bracket is array index
+ idx_len = right_bracket - left_bracket - 1;
+ }
- memcpy(idx_buf, key, klen);
- idx_buf[klen] = 0;
+ if (!klen && !idx_len) return nullptr;
- char* end = nullptr;
- int index = (int)strtol(idx_buf, &end, 10);
- if (end && !*end)
- pval = ((ArrayVal*)pval)->get(index);
- else
- // incorrect index string
+ // get value of key in object
+ if (klen) {
+ if (LIKELY(pval->type_ == JsonbType::T_Object)) {
+ pval = ((ObjectVal*)pval)->find(key, klen, handler);
+ if (!pval) return nullptr;
+ } else {
return nullptr;
- break;
+ }
}
- default:
- return nullptr;
+ // get value at idx in array
+ if (idx_len) {
+ if (LIKELY(pval->type_ == JsonbType::T_Array)) {
+ if (idx_len >= sizeof(idx_buf)) return nullptr;
+ memcpy(idx_buf, left_bracket + 1, idx_len);
+ idx_buf[idx_len] = 0;
+
+ char* end = nullptr;
+ int index = (int)strtol(idx_buf, &end, 10);
+ if (end && !*end)
+ pval = ((ArrayVal*)pval)->get(index);
+ else
+ // incorrect index string
+ return nullptr;
+
+ // doris::StringParser::ParseResult parse_result;
+ // int index = doris::StringParser::string_to_int<int>(left_bracket + 1, idx_len, &parse_result);
+ // if (parse_result == doris::StringParser::ParseResult::PARSE_SUCCESS)
+ } else {
+ return nullptr;
+ }
}
// skip the delimiter
diff --git a/be/src/util/jsonb_writer.h b/be/src/util/jsonb_writer.h
index ccce7d98e0..fa3098cb55 100644
--- a/be/src/util/jsonb_writer.h
+++ b/be/src/util/jsonb_writer.h
@@ -106,7 +106,8 @@ public:
}
uint32_t writeValue(const JsonbValue* value) {
- if (!stack_.empty() && verifyValueState()) {
+ if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
+ if (!writeFirstHeader()) return 0;
os_->write((char*)value, value->numPackedBytes());
kvState_ = WS_Value;
return value->size();
diff --git a/be/src/vec/functions/function_jsonb.cpp b/be/src/vec/functions/function_jsonb.cpp
index 39cf25de81..a480735ca4 100644
--- a/be/src/vec/functions/function_jsonb.cpp
+++ b/be/src/vec/functions/function_jsonb.cpp
@@ -18,7 +18,6 @@
#include <boost/token_functions.hpp>
#include <vector>
-#include "exprs/json_functions.h"
#include "util/string_parser.hpp"
#include "util/string_util.h"
#include "vec/columns/column.h"
@@ -290,6 +289,357 @@ using FunctionJsonbParseNotnullErrorValue =
using FunctionJsonbParseNotnullErrorInvalid =
FunctionJsonbParseBase<NullalbeMode::NOT_NULL, JsonbParseErrorMode::RETURN_INVALID>;
+// func(json,string) -> nullable(type)
+template <typename Impl>
+class FunctionJsonbExtract : public IFunction {
+public:
+ static constexpr auto name = Impl::name;
+ static FunctionPtr create() { return std::make_shared<FunctionJsonbExtract>(); }
+ String get_name() const override { return name; }
+ size_t get_number_of_arguments() const override { return 2; }
+ DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
+ return make_nullable(std::make_shared<typename Impl::ReturnType>());
+ }
+
+ bool use_default_implementation_for_constants() const override { return true; }
+
+ Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
+ size_t result, size_t input_rows_count) override {
+ auto null_map = ColumnUInt8::create(input_rows_count, 0);
+ DCHECK_EQ(arguments.size(), 2);
+ ColumnPtr argument_columns[2];
+ for (int i = 0; i < 2; ++i) {
+ argument_columns[i] =
+ block.get_by_position(arguments[i]).column->convert_to_full_column_if_const();
+ if (auto* nullable = check_and_get_column<ColumnNullable>(*argument_columns[i])) {
+ // Danger: Here must dispose the null map data first! Because
+ // argument_columns[i]=nullable->get_nested_column_ptr(); will release the mem
+ // of column nullable mem of null map
+ VectorizedUtils::update_null_map(null_map->get_data(),
+ nullable->get_null_map_data());
+ argument_columns[i] = nullable->get_nested_column_ptr();
+ }
+ }
+
+ auto res = Impl::ColumnType::create();
+
+ auto jsonb_data_column = assert_cast<const ColumnJsonb*>(argument_columns[0].get());
+ auto jsonb_path_column = assert_cast<const ColumnString*>(argument_columns[1].get());
+
+ auto& ldata = jsonb_data_column->get_chars();
+ auto& loffsets = jsonb_data_column->get_offsets();
+
+ auto& rdata = jsonb_path_column->get_chars();
+ auto& roffsets = jsonb_path_column->get_offsets();
+
+ // execute Impl
+ if constexpr (std::is_same_v<typename Impl::ReturnType, DataTypeString> ||
+ std::is_same_v<typename Impl::ReturnType, DataTypeJsonb>) {
+ auto& res_data = res->get_chars();
+ auto& res_offsets = res->get_offsets();
+ Impl::vector_vector(context, ldata, loffsets, rdata, roffsets, res_data, res_offsets,
+ null_map->get_data());
+ } else {
+ Impl::vector_vector(context, ldata, loffsets, rdata, roffsets, res->get_data(),
+ null_map->get_data());
+ }
+ block.get_by_position(result).column =
+ ColumnNullable::create(std::move(res), std::move(null_map));
+ return Status::OK();
+ }
+};
+
+template <typename ValueType>
+struct JsonbExtractStringImpl {
+ using ReturnType = typename ValueType::ReturnType;
+ using ColumnType = typename ValueType::ColumnType;
+ static const bool only_check_exists = ValueType::only_check_exists;
+
+ // for jsonb_extract_string
+ static void vector_vector(FunctionContext* context, const ColumnString::Chars& ldata,
+ const ColumnString::Offsets& loffsets,
+ const ColumnString::Chars& rdata,
+ const ColumnString::Offsets& roffsets, ColumnString::Chars& res_data,
+ ColumnString::Offsets& res_offsets, NullMap& null_map) {
+ size_t input_rows_count = loffsets.size();
+ res_offsets.resize(input_rows_count);
+
+ std::unique_ptr<JsonbWriter> writer;
+ if constexpr (std::is_same_v<DataTypeJsonb, ReturnType>) {
+ writer.reset(new JsonbWriter());
+ }
+
+ for (size_t i = 0; i < input_rows_count; ++i) {
+ int l_size = loffsets[i] - loffsets[i - 1] - 1;
+ const auto l_raw = reinterpret_cast<const char*>(&ldata[loffsets[i - 1]]);
+
+ int r_size = roffsets[i] - roffsets[i - 1];
+ const auto r_raw = reinterpret_cast<const char*>(&rdata[roffsets[i - 1]]);
+ String path(r_raw, r_size);
+
+ if (null_map[i]) {
+ StringOP::push_null_string(i, res_data, res_offsets, null_map);
+ continue;
+ }
+
+ // doc is NOT necessary to be deleted since JsonbDocument will not allocate memory
+ JsonbDocument* doc = JsonbDocument::createDocument(l_raw, l_size);
+ if (UNLIKELY(!doc || !doc->getValue())) {
+ StringOP::push_null_string(i, res_data, res_offsets, null_map);
+ continue;
+ }
+
+ // value is NOT necessary to be deleted since JsonbValue will not allocate memory
+ JsonbValue* value = doc->getValue()->findPath(r_raw, r_size, ".", nullptr);
+ if (UNLIKELY(!value)) {
+ StringOP::push_null_string(i, res_data, res_offsets, null_map);
+ continue;
+ }
+
+ if constexpr (ValueType::only_get_type) {
+ StringOP::push_value_string(std::string_view(value->typeName()), i, res_data,
+ res_offsets);
+ continue;
+ }
+
+ if constexpr (std::is_same_v<DataTypeJsonb, ReturnType>) {
+ writer->reset();
+ writer->writeValue(value);
+ // StringOP::push_value_string(
+ // std::string_view(writer->getOutput()->getBuffer(), writer->getOutput()->getSize()),
+ // i, res_data, res_offsets);
+ res_data.insert(writer->getOutput()->getBuffer(),
+ writer->getOutput()->getBuffer() + writer->getOutput()->getSize());
+ res_data.push_back('\0');
+ res_offsets[i] = res_data.size();
+ } else {
+ if (LIKELY(value->isString())) {
+ auto str_value = (JsonbStringVal*)value;
+ StringOP::push_value_string(
+ std::string_view(str_value->getBlob(), str_value->length()), i,
+ res_data, res_offsets);
+ } else {
+ StringOP::push_null_string(i, res_data, res_offsets, null_map);
+ continue;
+ }
+ }
+ }
+ }
+};
+
+template <typename ValueType>
+struct JsonbExtractImpl {
+ using ReturnType = typename ValueType::ReturnType;
+ using ColumnType = typename ValueType::ColumnType;
+ using Container = typename ColumnType::Container;
+ static const bool only_check_exists = ValueType::only_check_exists;
+
+ // for jsonb_extract_int/int64/double
+ static void vector_vector(FunctionContext* context, const ColumnString::Chars& ldata,
+ const ColumnString::Offsets& loffsets,
+ const ColumnString::Chars& rdata,
+ const ColumnString::Offsets& roffsets, Container& res,
+ NullMap& null_map) {
+ size_t size = loffsets.size();
+ res.resize(size);
+
+ for (size_t i = 0; i < loffsets.size(); i++) {
+ if constexpr (only_check_exists) {
+ res[i] = 0;
+ }
+
+ const char* l_raw_str = reinterpret_cast<const char*>(&ldata[loffsets[i - 1]]);
+ int l_str_size = loffsets[i] - loffsets[i - 1] - 1;
+
+ const char* r_raw_str = reinterpret_cast<const char*>(&rdata[roffsets[i - 1]]);
+ int r_str_size = roffsets[i] - roffsets[i - 1];
+
+ if (null_map[i]) {
+ res[i] = 0;
+ continue;
+ }
+
+ // doc is NOT necessary to be deleted since JsonbDocument will not allocate memory
+ JsonbDocument* doc = JsonbDocument::createDocument(l_raw_str, l_str_size);
+ if (UNLIKELY(!doc || !doc->getValue())) {
+ null_map[i] = 1;
+ res[i] = 0;
+ continue;
+ }
+
+ // value is NOT necessary to be deleted since JsonbValue will not allocate memory
+ JsonbValue* value = doc->getValue()->findPath(r_raw_str, r_str_size, ".", nullptr);
+ if (UNLIKELY(!value)) {
+ null_map[i] = 1;
+ res[i] = 0;
+ continue;
+ }
+
+ // if only check path exists, it's true here and skip check value
+ if constexpr (only_check_exists) {
+ res[i] = 1;
+ continue;
+ }
+
+ if constexpr (std::is_same_v<void, typename ValueType::T>) {
+ if (value->isNull()) {
+ res[i] = 1;
+ } else {
+ res[i] = 0;
+ }
+ } else if constexpr (std::is_same_v<bool, typename ValueType::T>) {
+ if (value->isTrue()) {
+ res[i] = 1;
+ } else if (value->isFalse()) {
+ res[i] = 0;
+ } else {
+ null_map[i] = 1;
+ res[i] = 0;
+ }
+ } else if constexpr (std::is_same_v<int32_t, typename ValueType::T>) {
+ if (value->isInt8() || value->isInt16() || value->isInt32()) {
+ res[i] = (int32_t)((const JsonbIntVal*)value)->val();
+ } else {
+ null_map[i] = 1;
+ res[i] = 0;
+ }
+ } else if constexpr (std::is_same_v<int64_t, typename ValueType::T>) {
+ if (value->isInt8() || value->isInt16() || value->isInt32() || value->isInt64()) {
+ res[i] = ((const JsonbIntVal*)value)->val();
+ } else {
+ null_map[i] = 1;
+ res[i] = 0;
+ }
+ } else if constexpr (std::is_same_v<double, typename ValueType::T>) {
+ if (value->isDouble()) {
+ res[i] = ((const JsonbDoubleVal*)value)->val();
+ } else if (value->isInt8() || value->isInt16() || value->isInt32() ||
+ value->isInt64()) {
+ res[i] = ((const JsonbIntVal*)value)->val();
+ } else {
+ null_map[i] = 1;
+ res[i] = 0;
+ }
+ } else {
+ LOG(FATAL) << "unexpected type ";
+ }
+ }
+ }
+};
+
+struct JsonbTypeExists {
+ using T = uint8_t;
+ using ReturnType = DataTypeUInt8;
+ using ColumnType = ColumnVector<T>;
+ static const bool only_check_exists = true;
+};
+
+struct JsonbTypeNull {
+ using T = void;
+ using ReturnType = DataTypeUInt8;
+ using ColumnType = ColumnVector<uint8_t>;
+ static const bool only_check_exists = false;
+};
+
+struct JsonbTypeBool {
+ using T = bool;
+ using ReturnType = DataTypeUInt8;
+ using ColumnType = ColumnVector<uint8_t>;
+ static const bool only_check_exists = false;
+};
+
+struct JsonbTypeInt {
+ using T = int32_t;
+ using ReturnType = DataTypeInt32;
+ using ColumnType = ColumnVector<T>;
+ static const bool only_check_exists = false;
+};
+
+struct JsonbTypeInt64 {
+ using T = int64_t;
+ using ReturnType = DataTypeInt64;
+ using ColumnType = ColumnVector<T>;
+ static const bool only_check_exists = false;
+};
+
+struct JsonbTypeDouble {
+ using T = double;
+ using ReturnType = DataTypeFloat64;
+ using ColumnType = ColumnVector<T>;
+ static const bool only_check_exists = false;
+};
+
+struct JsonbTypeString {
+ using T = std::string;
+ using ReturnType = DataTypeString;
+ using ColumnType = ColumnString;
+ static const bool only_check_exists = false;
+ static const bool only_get_type = false;
+};
+
+struct JsonbTypeJson {
+ using T = std::string;
+ using ReturnType = DataTypeJsonb;
+ using ColumnType = ColumnJsonb;
+ static const bool only_check_exists = false;
+ static const bool only_get_type = false;
+};
+
+struct JsonbTypeType {
+ using T = std::string;
+ using ReturnType = DataTypeString;
+ using ColumnType = ColumnString;
+ static const bool only_check_exists = false;
+ static const bool only_get_type = true;
+};
+
+struct JsonbExists : public JsonbExtractImpl<JsonbTypeExists> {
+ static constexpr auto name = "jsonb_exists_path";
+};
+
+struct JsonbExtractIsnull : public JsonbExtractImpl<JsonbTypeNull> {
+ static constexpr auto name = "jsonb_extract_isnull";
+};
+
+struct JsonbExtractBool : public JsonbExtractImpl<JsonbTypeBool> {
+ static constexpr auto name = "jsonb_extract_bool";
+};
+
+struct JsonbExtractInt : public JsonbExtractImpl<JsonbTypeInt> {
+ static constexpr auto name = "jsonb_extract_int";
+};
+
+struct JsonbExtractBigInt : public JsonbExtractImpl<JsonbTypeInt64> {
+ static constexpr auto name = "jsonb_extract_bigint";
+};
+
+struct JsonbExtractDouble : public JsonbExtractImpl<JsonbTypeDouble> {
+ static constexpr auto name = "jsonb_extract_double";
+};
+
+struct JsonbExtractString : public JsonbExtractStringImpl<JsonbTypeString> {
+ static constexpr auto name = "jsonb_extract_string";
+};
+
+struct JsonbExtractJsonb : public JsonbExtractStringImpl<JsonbTypeJson> {
+ static constexpr auto name = "jsonb_extract";
+};
+
+struct JsonbType : public JsonbExtractStringImpl<JsonbTypeType> {
+ static constexpr auto name = "jsonb_type";
+};
+
+using FunctionJsonbExists = FunctionJsonbExtract<JsonbExists>;
+using FunctionJsonbType = FunctionJsonbExtract<JsonbType>;
+
+using FunctionJsonbExtractIsnull = FunctionJsonbExtract<JsonbExtractIsnull>;
+using FunctionJsonbExtractBool = FunctionJsonbExtract<JsonbExtractBool>;
+using FunctionJsonbExtractInt = FunctionJsonbExtract<JsonbExtractInt>;
+using FunctionJsonbExtractBigInt = FunctionJsonbExtract<JsonbExtractBigInt>;
+using FunctionJsonbExtractDouble = FunctionJsonbExtract<JsonbExtractDouble>;
+using FunctionJsonbExtractString = FunctionJsonbExtract<JsonbExtractString>;
+using FunctionJsonbExtractJsonb = FunctionJsonbExtract<JsonbExtractJsonb>;
+
void register_function_jsonb(SimpleFunctionFactory& factory) {
factory.register_function<FunctionJsonbParse>("jsonb_parse");
factory.register_function<FunctionJsonbParseErrorNull>("jsonb_parse_error_to_null");
@@ -309,6 +659,17 @@ void register_function_jsonb(SimpleFunctionFactory& factory) {
"jsonb_parse_notnull_error_to_value");
factory.register_function<FunctionJsonbParseNotnullErrorInvalid>(
"jsonb_parse_notnull_error_to_invalid");
+
+ factory.register_function<FunctionJsonbExists>();
+ factory.register_function<FunctionJsonbType>();
+
+ factory.register_function<FunctionJsonbExtractIsnull>();
+ factory.register_function<FunctionJsonbExtractBool>();
+ factory.register_function<FunctionJsonbExtractInt>();
+ factory.register_function<FunctionJsonbExtractBigInt>();
+ factory.register_function<FunctionJsonbExtractDouble>();
+ factory.register_function<FunctionJsonbExtractString>();
+ factory.register_function<FunctionJsonbExtractJsonb>();
}
} // namespace doris::vectorized
diff --git a/be/test/vec/function/function_jsonb_test.cpp b/be/test/vec/function/function_jsonb_test.cpp
index 68f58e9bc4..a31bcc8939 100644
--- a/be/test/vec/function/function_jsonb_test.cpp
+++ b/be/test/vec/function/function_jsonb_test.cpp
@@ -35,7 +35,7 @@ TEST(FunctionJsonbTEST, JsonbParseTest) {
{{STRING("false")}, STRING("false")},
{{STRING("100")}, STRING("100")}, //int8
{{STRING("10000")}, STRING("10000")}, // int16
- {{STRING("1073741820")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18")}, STRING("6.18")}, // double
{{STRING(R"("abcd")")}, STRING(R"("abcd")")}, // string
@@ -56,37 +56,37 @@ TEST(FunctionJsonbTEST, JsonbParseTest) {
DataSet data_set_invalid = {
{{STRING("abc")}, Null()}, // invalid string
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("'abc'")}, Null()}, // invalid string
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("100x")}, Null()}, // invalid int
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("6.a8")}, Null()}, // invalid double
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("{x")}, Null()}, // invalid object
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("[123, abc]")}, Null()} // invalid array
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
}
@@ -100,7 +100,7 @@ TEST(FunctionJsonbTEST, JsonbParseErrorToNullTest) {
{{STRING("false")}, STRING("false")},
{{STRING("100")}, STRING("100")}, //int8
{{STRING("10000")}, STRING("10000")}, // int16
- {{STRING("1073741820")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18")}, STRING("6.18")}, // double
{{STRING(R"("abcd")")}, STRING(R"("abcd")")}, // string
@@ -135,7 +135,7 @@ TEST(FunctionJsonbTEST, JsonbParseErrorToValueTest) {
{{STRING("false"), STRING("{}")}, STRING("false")},
{{STRING("100"), STRING("{}")}, STRING("100")}, //int8
{{STRING("10000"), STRING("{}")}, STRING("10000")}, // int16
- {{STRING("1073741820"), STRING("{}")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000"), STRING("{}")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976"), STRING("{}")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18"), STRING("{}")}, STRING("6.18")}, // double
{{STRING(R"("abcd")"), STRING("{}")}, STRING(R"("abcd")")}, // string
@@ -173,7 +173,7 @@ TEST(FunctionJsonbTEST, JsonbParseErrorToInvalidTest) {
{{STRING("false")}, STRING("false")},
{{STRING("100")}, STRING("100")}, //int8
{{STRING("10000")}, STRING("10000")}, // int16
- {{STRING("1073741820")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18")}, STRING("6.18")}, // double
{{STRING(R"("abcd")")}, STRING(R"("abcd")")}, // string
@@ -208,7 +208,7 @@ TEST(FunctionJsonbTEST, JsonbParseNullableTest) {
{{STRING("false")}, STRING("false")},
{{STRING("100")}, STRING("100")}, //int8
{{STRING("10000")}, STRING("10000")}, // int16
- {{STRING("1073741820")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18")}, STRING("6.18")}, // double
{{STRING(R"("abcd")")}, STRING(R"("abcd")")}, // string
@@ -229,37 +229,37 @@ TEST(FunctionJsonbTEST, JsonbParseNullableTest) {
DataSet data_set_invalid = {
{{STRING("abc")}, Null()}, // invalid string
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("'abc'")}, Null()}, // invalid string
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("100x")}, Null()}, // invalid int
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("6.a8")}, Null()}, // invalid double
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("{x")}, Null()}, // invalid object
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("[123, abc]")}, Null()} // invalid array
};
- st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
}
@@ -273,7 +273,7 @@ TEST(FunctionJsonbTEST, JsonbParseNullableErrorToNullTest) {
{{STRING("false")}, STRING("false")},
{{STRING("100")}, STRING("100")}, //int8
{{STRING("10000")}, STRING("10000")}, // int16
- {{STRING("1073741820")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18")}, STRING("6.18")}, // double
{{STRING(R"("abcd")")}, STRING(R"("abcd")")}, // string
@@ -308,7 +308,7 @@ TEST(FunctionJsonbTEST, JsonbParseNullableErrorToValueTest) {
{{STRING("false"), STRING("{}")}, STRING("false")},
{{STRING("100"), STRING("{}")}, STRING("100")}, //int8
{{STRING("10000"), STRING("{}")}, STRING("10000")}, // int16
- {{STRING("1073741820"), STRING("{}")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000"), STRING("{}")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976"), STRING("{}")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18"), STRING("{}")}, STRING("6.18")}, // double
{{STRING(R"("abcd")"), STRING("{}")}, STRING(R"("abcd")")}, // string
@@ -346,7 +346,7 @@ TEST(FunctionJsonbTEST, JsonbParseNullableErrorToInvalidTest) {
{{STRING("false")}, STRING("false")},
{{STRING("100")}, STRING("100")}, //int8
{{STRING("10000")}, STRING("10000")}, // int16
- {{STRING("1073741820")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18")}, STRING("6.18")}, // double
{{STRING(R"("abcd")")}, STRING(R"("abcd")")}, // string
@@ -381,7 +381,7 @@ TEST(FunctionJsonbTEST, JsonbParseNotnullTest) {
{{STRING("false")}, STRING("false")},
{{STRING("100")}, STRING("100")}, //int8
{{STRING("10000")}, STRING("10000")}, // int16
- {{STRING("1073741820")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18")}, STRING("6.18")}, // double
{{STRING(R"("abcd")")}, STRING(R"("abcd")")}, // string
@@ -402,37 +402,37 @@ TEST(FunctionJsonbTEST, JsonbParseNotnullTest) {
DataSet data_set_invalid = {
{{STRING("abc")}, Null()}, // invalid string
};
- st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("'abc'")}, Null()}, // invalid string
};
- st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("100x")}, Null()}, // invalid int
};
- st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("6.a8")}, Null()}, // invalid double
};
- st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("{x")}, Null()}, // invalid object
};
- st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
data_set_invalid = {
{{STRING("[123, abc]")}, Null()} // invalid array
};
- st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid);
+ st = check_function<DataTypeJsonb, false>(func_name, input_types, data_set_invalid, true);
EXPECT_NE(Status::OK(), st);
}
@@ -446,7 +446,7 @@ TEST(FunctionJsonbTEST, JsonbParseNotnullErrorToValueTest) {
{{STRING("false"), STRING("{}")}, STRING("false")},
{{STRING("100"), STRING("{}")}, STRING("100")}, //int8
{{STRING("10000"), STRING("{}")}, STRING("10000")}, // int16
- {{STRING("1073741820"), STRING("{}")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000"), STRING("{}")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976"), STRING("{}")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18"), STRING("{}")}, STRING("6.18")}, // double
{{STRING(R"("abcd")"), STRING("{}")}, STRING(R"("abcd")")}, // string
@@ -484,7 +484,7 @@ TEST(FunctionJsonbTEST, JsonbParseNotnullErrorToInvalidTest) {
{{STRING("false")}, STRING("false")},
{{STRING("100")}, STRING("100")}, //int8
{{STRING("10000")}, STRING("10000")}, // int16
- {{STRING("1073741820")}, STRING("1073741820")}, // int32
+ {{STRING("1000000000")}, STRING("1000000000")}, // int32
{{STRING("1152921504606846976")}, STRING("1152921504606846976")}, // int64
{{STRING("6.18")}, STRING("6.18")}, // double
{{STRING(R"("abcd")")}, STRING(R"("abcd")")}, // string
@@ -509,4 +509,717 @@ TEST(FunctionJsonbTEST, JsonbParseNotnullErrorToInvalidTest) {
EXPECT_EQ(Status::OK(), st);
}
+TEST(FunctionJsonbTEST, JsonbExtractTest) {
+ std::string func_name = "jsonb_extract";
+ InputTypeSet input_types = {TypeIndex::JSONB, TypeIndex::String};
+
+ // jsonb_extract root
+ DataSet data_set = {
+ {{STRING("null"), STRING("$")}, STRING("null")},
+ {{STRING("true"), STRING("$")}, STRING("true")},
+ {{STRING("false"), STRING("$")}, STRING("false")},
+ {{STRING("100"), STRING("$")}, STRING("100")}, //int8
+ {{STRING("10000"), STRING("$")}, STRING("10000")}, // int16
+ {{STRING("1000000000"), STRING("$")}, STRING("1000000000")}, // int32
+ {{STRING("1152921504606846976"), STRING("$")}, STRING("1152921504606846976")}, // int64
+ {{STRING("6.18"), STRING("$")}, STRING("6.18")}, // double
+ {{STRING(R"("abcd")"), STRING("$")}, STRING(R"("abcd")")}, // string
+ {{STRING("{}"), STRING("$")}, STRING("{}")}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$")},
+ STRING(R"({"k1":"v31","k2":300})")}, // object
+ {{STRING("[]"), STRING("$")}, STRING("[]")}, // empty array
+ {{STRING("[123, 456]"), STRING("$")}, STRING("[123,456]")}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$")},
+ STRING(R"(["abc","def"])")}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$")},
+ STRING(R"([null,true,false,100,6.18,"abc"])")}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$")},
+ STRING(R"([{"k1":"v41","k2":400},1,"a",3.14])")}, // complex array
+ };
+
+ auto st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract obejct
+ data_set = {
+ {{STRING("null"), STRING("$.k1")}, Null()},
+ {{STRING("true"), STRING("$.k1")}, Null()},
+ {{STRING("false"), STRING("$.k1")}, Null()},
+ {{STRING("100"), STRING("$.k1")}, Null()}, //int8
+ {{STRING("10000"), STRING("$.k1")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$.k1")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$.k1")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$.k1")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$.k1")}, Null()}, // string
+ {{STRING("{}"), STRING("$.k1")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$.k1")}, STRING(R"("v31")")}, // object
+ {{STRING("[]"), STRING("$.k1")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$.k1")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$.k1")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$.k1")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$.k1")},
+ Null()}, // complex array
+ };
+
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract array
+ data_set = {
+ {{STRING("null"), STRING("$[0]")}, Null()},
+ {{STRING("true"), STRING("$[0]")}, Null()},
+ {{STRING("false"), STRING("$[0]")}, Null()},
+ {{STRING("100"), STRING("$[0]")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[0]")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[0]")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[0]")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[0]")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[0]")}, Null()}, // string
+ {{STRING("{}"), STRING("$[0]")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[0]")}, Null()}, // object
+ {{STRING("[]"), STRING("$[0]")}, Null()}, // empty array
+ {{STRING("null"), STRING("$[1]")}, Null()},
+ {{STRING("true"), STRING("$[1]")}, Null()},
+ {{STRING("false"), STRING("$[1]")}, Null()},
+ {{STRING("100"), STRING("$[1]")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[1]")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[1]")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[1]")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[1]")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[1]")}, Null()}, // string
+ {{STRING("{}"), STRING("$[1]")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[1]")}, Null()}, // object
+ {{STRING("[]"), STRING("$[1]")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$[0]")}, STRING("123")}, // int array
+ {{STRING("[123, 456]"), STRING("$[1]")}, STRING("456")}, // int array
+ {{STRING("[123, 456]"), STRING("$[2]")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$[0]")}, STRING(R"("abc")")}, // string array
+ {{STRING(R"(["abc", "def"])"), STRING("$[1]")}, STRING(R"("def")")}, // string array
+ {{STRING(R"(["abc", "def"])"), STRING("$[2]")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[0]")},
+ STRING("null")}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[1]")},
+ STRING("true")}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[2]")},
+ STRING("false")}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[3]")},
+ STRING("100")}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[4]")},
+ STRING("6.18")}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[5]")},
+ STRING(R"("abc")")}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[6]")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0]")},
+ STRING(R"({"k1":"v41","k2":400})")}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[1]")},
+ STRING("1")}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[2]")},
+ STRING(R"("a")")}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[3]")},
+ STRING("3.14")}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[4]")},
+ Null()}, // complex array
+ };
+
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract $[0].k1
+ data_set = {
+ {{STRING("null"), STRING("$[0].k1")}, Null()},
+ {{STRING("true"), STRING("$[0].k1")}, Null()},
+ {{STRING("false"), STRING("$[0].k1")}, Null()},
+ {{STRING("100"), STRING("$[0].k1")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[0].k1")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[0].k1")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[0].k1")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[0].k1")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[0].k1")}, Null()}, // string
+ {{STRING("{}"), STRING("$[0].k1")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[0].k1")}, Null()}, // object
+ {{STRING("[]"), STRING("$[0].k1")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$[0].k1")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$[0].k1")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[0].k1")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0].k1")},
+ STRING(R"("v41")")}, // complex array
+ };
+
+ st = check_function<DataTypeJsonb, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+}
+
+TEST(FunctionJsonbTEST, JsonbExtractStringTest) {
+ std::string func_name = "jsonb_extract_string";
+ InputTypeSet input_types = {TypeIndex::JSONB, TypeIndex::String};
+
+ // jsonb_extract root
+ DataSet data_set = {
+ {{STRING("null"), STRING("$")}, Null()},
+ {{STRING("true"), STRING("$")}, Null()},
+ {{STRING("false"), STRING("$")}, Null()},
+ {{STRING("100"), STRING("$")}, Null()}, //int8
+ {{STRING("10000"), STRING("$")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$")}, STRING("abcd")}, // string
+ {{STRING("{}"), STRING("$")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$")}, Null()}, // object
+ {{STRING("[]"), STRING("$")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$")},
+ Null()}, // complex array
+ };
+
+ auto st = check_function<DataTypeString, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract obejct
+ data_set = {
+ {{STRING("null"), STRING("$.k1")}, Null()},
+ {{STRING("true"), STRING("$.k1")}, Null()},
+ {{STRING("false"), STRING("$.k1")}, Null()},
+ {{STRING("100"), STRING("$.k1")}, Null()}, //int8
+ {{STRING("10000"), STRING("$.k1")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$.k1")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$.k1")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$.k1")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$.k1")}, Null()}, // string
+ {{STRING("{}"), STRING("$.k1")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$.k1")}, STRING("v31")}, // object
+ {{STRING("[]"), STRING("$.k1")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$.k1")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$.k1")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$.k1")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$.k1")},
+ Null()}, // complex array
+ };
+
+ st = check_function<DataTypeString, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract array
+ data_set = {
+ {{STRING("null"), STRING("$[0]")}, Null()},
+ {{STRING("true"), STRING("$[0]")}, Null()},
+ {{STRING("false"), STRING("$[0]")}, Null()},
+ {{STRING("100"), STRING("$[0]")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[0]")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[0]")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[0]")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[0]")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[0]")}, Null()}, // string
+ {{STRING("{}"), STRING("$[0]")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[0]")}, Null()}, // object
+ {{STRING("[]"), STRING("$[0]")}, Null()}, // empty array
+ {{STRING("null"), STRING("$[1]")}, Null()},
+ {{STRING("true"), STRING("$[1]")}, Null()},
+ {{STRING("false"), STRING("$[1]")}, Null()},
+ {{STRING("100"), STRING("$[1]")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[1]")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[1]")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[1]")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[1]")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[1]")}, Null()}, // string
+ {{STRING("{}"), STRING("$[1]")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[1]")}, Null()}, // object
+ {{STRING("[]"), STRING("$[1]")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$[0]")}, Null()}, // int array
+ {{STRING("[123, 456]"), STRING("$[1]")}, Null()}, // int array
+ {{STRING("[123, 456]"), STRING("$[2]")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$[0]")}, STRING("abc")}, // string array
+ {{STRING(R"(["abc", "def"])"), STRING("$[1]")}, STRING("def")}, // string array
+ {{STRING(R"(["abc", "def"])"), STRING("$[2]")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[0]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[1]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[2]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[3]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[4]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[5]")},
+ STRING("abc")}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[6]")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[1]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[2]")},
+ STRING("a")}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[3]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[4]")},
+ Null()}, // complex array
+ };
+
+ st = check_function<DataTypeString, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract $[0].k1
+ data_set = {
+ {{STRING("null"), STRING("$[0].k1")}, Null()},
+ {{STRING("true"), STRING("$[0].k1")}, Null()},
+ {{STRING("false"), STRING("$[0].k1")}, Null()},
+ {{STRING("100"), STRING("$[0].k1")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[0].k1")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[0].k1")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[0].k1")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[0].k1")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[0].k1")}, Null()}, // string
+ {{STRING("{}"), STRING("$[0].k1")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[0].k1")}, Null()}, // object
+ {{STRING("[]"), STRING("$[0].k1")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$[0].k1")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$[0].k1")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[0].k1")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0].k1")},
+ STRING("v41")}, // complex array
+ };
+
+ st = check_function<DataTypeString, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+}
+
+TEST(FunctionJsonbTEST, JsonbExtractIntTest) {
+ std::string func_name = "jsonb_extract_int";
+ InputTypeSet input_types = {TypeIndex::JSONB, TypeIndex::String};
+
+ // jsonb_extract root
+ DataSet data_set = {
+ {{STRING("null"), STRING("$")}, Null()},
+ {{STRING("true"), STRING("$")}, Null()},
+ {{STRING("false"), STRING("$")}, Null()},
+ {{STRING("100"), STRING("$")}, INT(100)}, //int8
+ {{STRING("10000"), STRING("$")}, INT(10000)}, // int16
+ {{STRING("1000000000"), STRING("$")}, INT(1000000000)}, // int32
+ {{STRING("1152921504606846976"), STRING("$")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$")}, Null()}, // string
+ {{STRING("{}"), STRING("$")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$")}, Null()}, // object
+ {{STRING("[]"), STRING("$")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$")},
+ Null()}, // complex array
+ };
+
+ auto st = check_function<DataTypeInt32, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract obejct
+ data_set = {
+ {{STRING("null"), STRING("$.k1")}, Null()},
+ {{STRING("true"), STRING("$.k1")}, Null()},
+ {{STRING("false"), STRING("$.k1")}, Null()},
+ {{STRING("100"), STRING("$.k1")}, Null()}, //int8
+ {{STRING("10000"), STRING("$.k1")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$.k1")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$.k1")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$.k1")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$.k1")}, Null()}, // string
+ {{STRING("{}"), STRING("$.k1")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$.k1")}, Null()}, // object
+ {{STRING("[]"), STRING("$.k1")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$.k1")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$.k1")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$.k1")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$.k1")},
+ Null()}, // complex array
+ };
+
+ st = check_function<DataTypeInt32, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract array
+ data_set = {
+ {{STRING("null"), STRING("$[0]")}, Null()},
+ {{STRING("true"), STRING("$[0]")}, Null()},
+ {{STRING("false"), STRING("$[0]")}, Null()},
+ {{STRING("100"), STRING("$[0]")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[0]")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[0]")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[0]")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[0]")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[0]")}, Null()}, // string
+ {{STRING("{}"), STRING("$[0]")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[0]")}, Null()}, // object
+ {{STRING("[]"), STRING("$[0]")}, Null()}, // empty array
+ {{STRING("null"), STRING("$[1]")}, Null()},
+ {{STRING("true"), STRING("$[1]")}, Null()},
+ {{STRING("false"), STRING("$[1]")}, Null()},
+ {{STRING("100"), STRING("$[1]")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[1]")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[1]")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[1]")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[1]")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[1]")}, Null()}, // string
+ {{STRING("{}"), STRING("$[1]")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[1]")}, Null()}, // object
+ {{STRING("[]"), STRING("$[1]")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$[0]")}, INT(123)}, // int array
+ {{STRING("[123, 456]"), STRING("$[1]")}, INT(456)}, // int array
+ {{STRING("[123, 456]"), STRING("$[2]")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$[0]")}, Null()}, // string array
+ {{STRING(R"(["abc", "def"])"), STRING("$[1]")}, Null()}, // string array
+ {{STRING(R"(["abc", "def"])"), STRING("$[2]")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[0]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[1]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[2]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[3]")},
+ INT(100)}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[4]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[5]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[6]")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[1]")},
+ INT(1)}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[2]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[3]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[4]")},
+ Null()}, // complex array
+ };
+
+ st = check_function<DataTypeInt32, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract $[0].k1
+ data_set = {
+ {{STRING("null"), STRING("$[0].k1")}, Null()},
+ {{STRING("true"), STRING("$[0].k1")}, Null()},
+ {{STRING("false"), STRING("$[0].k1")}, Null()},
+ {{STRING("100"), STRING("$[0].k1")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[0].k1")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[0].k1")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[0].k1")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[0].k1")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[0].k1")}, Null()}, // string
+ {{STRING("{}"), STRING("$[0].k1")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[0].k1")}, Null()}, // object
+ {{STRING("[]"), STRING("$[0].k1")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$[0].k1")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$[0].k1")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[0].k1")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0].k1")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0].k2")},
+ INT(400)}, // complex array
+ };
+
+ st = check_function<DataTypeInt32, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+}
+
+TEST(FunctionJsonbTEST, JsonbExtractBigIntTest) {
+ std::string func_name = "jsonb_extract_bigint";
+ InputTypeSet input_types = {TypeIndex::JSONB, TypeIndex::String};
+
+ // jsonb_extract root
+ DataSet data_set = {
+ {{STRING("null"), STRING("$")}, Null()},
+ {{STRING("true"), STRING("$")}, Null()},
+ {{STRING("false"), STRING("$")}, Null()},
+ {{STRING("100"), STRING("$")}, BIGINT(100)}, //int8
+ {{STRING("10000"), STRING("$")}, BIGINT(10000)}, // int16
+ {{STRING("1000000000"), STRING("$")}, BIGINT(1000000000)}, // int32
+ {{STRING("1152921504606846976"), STRING("$")}, BIGINT(1152921504606846976)}, // int64
+ {{STRING("6.18"), STRING("$")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$")}, Null()}, // string
+ {{STRING("{}"), STRING("$")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$")}, Null()}, // object
+ {{STRING("[]"), STRING("$")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$")},
+ Null()}, // complex array
+ };
+
+ auto st = check_function<DataTypeInt64, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract obejct
+ data_set = {
+ {{STRING("null"), STRING("$.k1")}, Null()},
+ {{STRING("true"), STRING("$.k1")}, Null()},
+ {{STRING("false"), STRING("$.k1")}, Null()},
+ {{STRING("100"), STRING("$.k1")}, Null()}, //int8
+ {{STRING("10000"), STRING("$.k1")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$.k1")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$.k1")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$.k1")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$.k1")}, Null()}, // string
+ {{STRING("{}"), STRING("$.k1")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$.k1")}, Null()}, // object
+ {{STRING("[]"), STRING("$.k1")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$.k1")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$.k1")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$.k1")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$.k1")},
+ Null()}, // complex array
+ };
+
+ st = check_function<DataTypeInt64, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract array
+ data_set = {
+ {{STRING("null"), STRING("$[0]")}, Null()},
+ {{STRING("true"), STRING("$[0]")}, Null()},
+ {{STRING("false"), STRING("$[0]")}, Null()},
+ {{STRING("100"), STRING("$[0]")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[0]")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[0]")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[0]")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[0]")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[0]")}, Null()}, // string
+ {{STRING("{}"), STRING("$[0]")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[0]")}, Null()}, // object
+ {{STRING("[]"), STRING("$[0]")}, Null()}, // empty array
+ {{STRING("null"), STRING("$[1]")}, Null()},
+ {{STRING("true"), STRING("$[1]")}, Null()},
+ {{STRING("false"), STRING("$[1]")}, Null()},
+ {{STRING("100"), STRING("$[1]")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[1]")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[1]")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[1]")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[1]")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[1]")}, Null()}, // string
+ {{STRING("{}"), STRING("$[1]")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[1]")}, Null()}, // object
+ {{STRING("[]"), STRING("$[1]")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$[0]")}, BIGINT(123)}, // int array
+ {{STRING("[123, 456]"), STRING("$[1]")}, BIGINT(456)}, // int array
+ {{STRING("[123, 456]"), STRING("$[2]")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$[0]")}, Null()}, // string array
+ {{STRING(R"(["abc", "def"])"), STRING("$[1]")}, Null()}, // string array
+ {{STRING(R"(["abc", "def"])"), STRING("$[2]")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[0]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[1]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[2]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[3]")},
+ BIGINT(100)}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[4]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[5]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[6]")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[1]")},
+ BIGINT(1)}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[2]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[3]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[4]")},
+ Null()}, // complex array
+ };
+
+ st = check_function<DataTypeInt64, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract $[0].k1
+ data_set = {
+ {{STRING("null"), STRING("$[0].k1")}, Null()},
+ {{STRING("true"), STRING("$[0].k1")}, Null()},
+ {{STRING("false"), STRING("$[0].k1")}, Null()},
+ {{STRING("100"), STRING("$[0].k1")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[0].k1")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[0].k1")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[0].k1")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[0].k1")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[0].k1")}, Null()}, // string
+ {{STRING("{}"), STRING("$[0].k1")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[0].k1")}, Null()}, // object
+ {{STRING("[]"), STRING("$[0].k1")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$[0].k1")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$[0].k1")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[0].k1")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0].k1")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0].k2")},
+ BIGINT(400)}, // complex array
+ };
+
+ st = check_function<DataTypeInt64, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+}
+
+TEST(FunctionJsonbTEST, JsonbExtractDoubleTest) {
+ std::string func_name = "jsonb_extract_double";
+ InputTypeSet input_types = {TypeIndex::JSONB, TypeIndex::String};
+
+ // jsonb_extract root
+ DataSet data_set = {
+ {{STRING("null"), STRING("$")}, Null()},
+ {{STRING("true"), STRING("$")}, Null()},
+ {{STRING("false"), STRING("$")}, Null()},
+ {{STRING("100"), STRING("$")}, DOUBLE(100)}, //int8
+ {{STRING("10000"), STRING("$")}, DOUBLE(10000)}, // int16
+ {{STRING("1000000000"), STRING("$")}, DOUBLE(1000000000)}, // int32
+ {{STRING("1152921504606846976"), STRING("$")}, DOUBLE(1152921504606846976)}, // int64
+ {{STRING("6.18"), STRING("$")}, DOUBLE(6.18)}, // double
+ {{STRING(R"("abcd")"), STRING("$")}, Null()}, // string
+ {{STRING("{}"), STRING("$")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$")}, Null()}, // object
+ {{STRING("[]"), STRING("$")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$")},
+ Null()}, // complex array
+ };
+
+ auto st = check_function<DataTypeFloat64, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract obejct
+ data_set = {
+ {{STRING("null"), STRING("$.k1")}, Null()},
+ {{STRING("true"), STRING("$.k1")}, Null()},
+ {{STRING("false"), STRING("$.k1")}, Null()},
+ {{STRING("100"), STRING("$.k1")}, Null()}, //int8
+ {{STRING("10000"), STRING("$.k1")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$.k1")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$.k1")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$.k1")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$.k1")}, Null()}, // string
+ {{STRING("{}"), STRING("$.k1")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$.k1")}, Null()}, // object
+ {{STRING("[]"), STRING("$.k1")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$.k1")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$.k1")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$.k1")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$.k1")},
+ Null()}, // complex array
+ };
+
+ st = check_function<DataTypeFloat64, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract array
+ data_set = {
+ {{STRING("null"), STRING("$[0]")}, Null()},
+ {{STRING("true"), STRING("$[0]")}, Null()},
+ {{STRING("false"), STRING("$[0]")}, Null()},
+ {{STRING("100"), STRING("$[0]")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[0]")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[0]")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[0]")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[0]")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[0]")}, Null()}, // string
+ {{STRING("{}"), STRING("$[0]")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[0]")}, Null()}, // object
+ {{STRING("[]"), STRING("$[0]")}, Null()}, // empty array
+ {{STRING("null"), STRING("$[1]")}, Null()},
+ {{STRING("true"), STRING("$[1]")}, Null()},
+ {{STRING("false"), STRING("$[1]")}, Null()},
+ {{STRING("100"), STRING("$[1]")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[1]")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[1]")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[1]")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[1]")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[1]")}, Null()}, // string
+ {{STRING("{}"), STRING("$[1]")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[1]")}, Null()}, // object
+ {{STRING("[]"), STRING("$[1]")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$[0]")}, DOUBLE(123)}, // int array
+ {{STRING("[123, 456]"), STRING("$[1]")}, DOUBLE(456)}, // int array
+ {{STRING("[123, 456]"), STRING("$[2]")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$[0]")}, Null()}, // string array
+ {{STRING(R"(["abc", "def"])"), STRING("$[1]")}, Null()}, // string array
+ {{STRING(R"(["abc", "def"])"), STRING("$[2]")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[0]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[1]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[2]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[3]")},
+ DOUBLE(100)}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[4]")},
+ DOUBLE(6.18)}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[5]")},
+ Null()}, // multi type array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[6]")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[1]")},
+ DOUBLE(1)}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[2]")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[3]")},
+ DOUBLE(3.14)}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[4]")},
+ Null()}, // complex array
+ };
+
+ st = check_function<DataTypeFloat64, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+
+ // jsonb_extract $[0].k1
+ data_set = {
+ {{STRING("null"), STRING("$[0].k1")}, Null()},
+ {{STRING("true"), STRING("$[0].k1")}, Null()},
+ {{STRING("false"), STRING("$[0].k1")}, Null()},
+ {{STRING("100"), STRING("$[0].k1")}, Null()}, //int8
+ {{STRING("10000"), STRING("$[0].k1")}, Null()}, // int16
+ {{STRING("1000000000"), STRING("$[0].k1")}, Null()}, // int32
+ {{STRING("1152921504606846976"), STRING("$[0].k1")}, Null()}, // int64
+ {{STRING("6.18"), STRING("$[0].k1")}, Null()}, // double
+ {{STRING(R"("abcd")"), STRING("$[0].k1")}, Null()}, // string
+ {{STRING("{}"), STRING("$[0].k1")}, Null()}, // empty object
+ {{STRING(R"({"k1":"v31", "k2": 300})"), STRING("$[0].k1")}, Null()}, // object
+ {{STRING("[]"), STRING("$[0].k1")}, Null()}, // empty array
+ {{STRING("[123, 456]"), STRING("$[0].k1")}, Null()}, // int array
+ {{STRING(R"(["abc", "def"])"), STRING("$[0].k1")}, Null()}, // string array
+ {{STRING(R"([null, true, false, 100, 6.18, "abc"])"), STRING("$[0].k1")},
+ Null()}, // multi type array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0].k1")},
+ Null()}, // complex array
+ {{STRING(R"([{"k1":"v41", "k2": 400}, 1, "a", 3.14])"), STRING("$[0].k2")},
+ DOUBLE(400)}, // complex array
+ };
+
+ st = check_function<DataTypeFloat64, true>(func_name, input_types, data_set);
+ EXPECT_EQ(Status::OK(), st);
+}
+
} // namespace doris::vectorized
diff --git a/be/test/vec/function/function_test_util.cpp b/be/test/vec/function/function_test_util.cpp
index 3cc25ccd95..92febd0640 100644
--- a/be/test/vec/function/function_test_util.cpp
+++ b/be/test/vec/function/function_test_util.cpp
@@ -17,6 +17,7 @@
#include "vec/function/function_test_util.h"
+#include "runtime/jsonb_value.h"
#include "vec/data_types/data_type_array.h"
#include "vec/data_types/data_type_bitmap.h"
#include "vec/data_types/data_type_decimal.h"
@@ -66,6 +67,10 @@ size_t type_index_to_data_type(const std::vector<std::any>& input_types, size_t
desc.type = doris_udf::FunctionContext::TYPE_STRING;
type = std::make_shared<DataTypeString>();
return 1;
+ case TypeIndex::JSONB:
+ desc.type = doris_udf::FunctionContext::TYPE_JSONB;
+ type = std::make_shared<DataTypeJsonb>();
+ return 1;
case TypeIndex::BitMap:
desc.type = doris_udf::FunctionContext::TYPE_OBJECT;
type = std::make_shared<DataTypeBitMap>();
@@ -177,6 +182,10 @@ bool insert_cell(MutableColumnPtr& column, DataTypePtr type_ptr, const std::any&
if (type.is_string()) {
auto str = std::any_cast<ut_type::STRING>(cell);
column->insert_data(str.c_str(), str.size());
+ } else if (type.is_json()) {
+ auto str = std::any_cast<ut_type::STRING>(cell);
+ JsonBinaryValue jsonb_val(str.c_str(), str.size());
+ column->insert_data(jsonb_val.value(), jsonb_val.size());
} else if (type.idx == TypeIndex::BitMap) {
BitmapValue* bitmap = std::any_cast<BitmapValue*>(cell);
column->insert_data((char*)bitmap, sizeof(BitmapValue));
diff --git a/be/test/vec/function/function_test_util.h b/be/test/vec/function/function_test_util.h
index 1d4d56f029..5d652d9b6c 100644
--- a/be/test/vec/function/function_test_util.h
+++ b/be/test/vec/function/function_test_util.h
@@ -163,7 +163,7 @@ void check_vec_table_function(TableFunction* fn, const InputTypeSet& input_types
// A DataSet with a constant column can only have one row of data
template <typename ReturnType, bool nullable = false>
Status check_function(const std::string& func_name, const InputTypeSet& input_types,
- const DataSet& data_set) {
+ const DataSet& data_set, bool expect_fail = false) {
// 1.0 create data type
ut_type::UTDataTypeDescs descs;
EXPECT_TRUE(parse_ut_data_type(input_types, descs));
@@ -234,16 +234,20 @@ Status check_function(const std::string& func_name, const InputTypeSet& input_ty
FunctionUtils fn_utils(fn_ctx_return, arg_types, 0);
auto* fn_ctx = fn_utils.get_fn_ctx();
fn_ctx->impl()->set_constant_cols(constant_cols);
- RETURN_IF_ERROR(func->prepare(fn_ctx, FunctionContext::FRAGMENT_LOCAL));
- RETURN_IF_ERROR(func->prepare(fn_ctx, FunctionContext::THREAD_LOCAL));
+ func->prepare(fn_ctx, FunctionContext::FRAGMENT_LOCAL);
+ func->prepare(fn_ctx, FunctionContext::THREAD_LOCAL);
block.insert({nullptr, return_type, "result"});
auto result = block.columns() - 1;
- RETURN_IF_ERROR(func->execute(fn_ctx, block, arguments, result, row_size));
+ if (expect_fail) {
+ RETURN_IF_ERROR(func->execute(fn_ctx, block, arguments, result, row_size));
+ } else {
+ func->execute(fn_ctx, block, arguments, result, row_size);
+ }
- RETURN_IF_ERROR(func->close(fn_ctx, FunctionContext::THREAD_LOCAL));
- RETURN_IF_ERROR(func->close(fn_ctx, FunctionContext::FRAGMENT_LOCAL));
+ func->close(fn_ctx, FunctionContext::THREAD_LOCAL);
+ func->close(fn_ctx, FunctionContext::FRAGMENT_LOCAL);
// 3. check the result of function
ColumnPtr column = block.get_columns()[result];
@@ -256,13 +260,13 @@ Status check_function(const std::string& func_name, const InputTypeSet& input_ty
auto s = column->get_data_at(i);
if (expect_data.size() == 0) {
// zero size result means invalid
- EXPECT_EQ(0, s.size) << " invalid result size should be 0 for row " << i;
+ EXPECT_EQ(0, s.size) << " invalid result size should be 0 at row " << i;
} else {
// convert jsonb binary value to json string to compare with expected json text
JsonbToJson to_json;
doris::JsonbValue* val =
doris::JsonbDocument::createDocument(s.data, s.size)->getValue();
- EXPECT_EQ(to_json.jsonb_to_string(val), expect_data) << " for row " << i;
+ EXPECT_EQ(to_json.jsonb_to_string(val), expect_data) << " at row " << i;
}
} else {
Field field;
@@ -273,20 +277,20 @@ Status check_function(const std::string& func_name, const InputTypeSet& input_ty
if constexpr (std::is_same_v<ReturnType, DataTypeDecimal<Decimal128>>) {
const auto& column_data = field.get<DecimalField<Decimal128>>().get_value();
- EXPECT_EQ(expect_data.value, column_data.value);
+ EXPECT_EQ(expect_data.value, column_data.value) << " at row " << i;
} else if constexpr (std::is_same_v<ReturnType, DataTypeFloat32>) {
const auto& column_data = field.get<DataTypeFloat64::FieldType>();
- EXPECT_EQ(expect_data, column_data);
+ EXPECT_EQ(expect_data, column_data) << " at row " << i;
} else {
const auto& column_data = field.get<typename ReturnType::FieldType>();
- EXPECT_EQ(expect_data, column_data);
+ EXPECT_EQ(expect_data, column_data) << " at row " << i;
}
}
};
if constexpr (nullable) {
bool is_null = data_set[i].second.type() == typeid(Null);
- EXPECT_EQ(is_null, column->is_null_at(i));
+ EXPECT_EQ(is_null, column->is_null_at(i)) << " at row " << i;
if (!is_null) check_column_data();
} else {
check_column_data();
diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py
index b97dbacd68..f1bb4faf86 100755
--- a/gensrc/script/doris_builtins_functions.py
+++ b/gensrc/script/doris_builtins_functions.py
@@ -2298,6 +2298,62 @@ visible_functions = [
'fake_symble_for_no_vec', '', '',
'vec', ''],
+ [['jsonb_exists_path'], 'BOOLEAN', ['JSONB', 'VARCHAR'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', ''],
+ [['jsonb_exists_path'], 'BOOLEAN', ['JSONB', 'STRING'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', ''],
+ [['jsonb_type'], 'STRING', ['JSONB', 'STRING'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_type'], 'STRING', ['JSONB', 'STRING'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+
+ [['jsonb_extract'], 'JSONB', ['JSONB', 'VARCHAR'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract'], 'JSONB', ['JSONB', 'STRING'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_isnull'], 'BOOLEAN', ['JSONB', 'VARCHAR'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_isnull'], 'BOOLEAN', ['JSONB', 'STRING'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_bool'], 'BOOLEAN', ['JSONB', 'VARCHAR'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_bool'], 'BOOLEAN', ['JSONB', 'STRING'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_int'], 'INT', ['JSONB', 'VARCHAR'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_int'], 'INT', ['JSONB', 'STRING'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_bigint'], 'BIGINT', ['JSONB', 'VARCHAR'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_bigint'], 'BIGINT', ['JSONB', 'STRING'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_double'], 'DOUBLE', ['JSONB', 'VARCHAR'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_double'], 'DOUBLE', ['JSONB', 'STRING'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_string'], 'STRING', ['JSONB', 'VARCHAR'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+ [['jsonb_extract_string'], 'STRING', ['JSONB', 'STRING'],
+ 'fake_symble_for_no_vec', '', '',
+ 'vec', 'ALWAYS_NULLABLE'],
+
# Json functions
[['get_json_int'], 'INT', ['VARCHAR', 'VARCHAR'],
'_ZN5doris13JsonFunctions12get_json_intEPN9doris_udf15FunctionContextERKNS1_9StringValES6_',
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org