diff --git a/be/src/util/jsonb_document.h b/be/src/util/jsonb_document.h index 657438fefee0d00..8ed8503675c9b35 100644 --- a/be/src/util/jsonb_document.h +++ b/be/src/util/jsonb_document.h @@ -549,6 +549,9 @@ class JsonbValue { //Get the number of jsonbvalue elements int length() const; + //Get the depth of jsonbvalue + int depth() const; + //Whether to include the jsonbvalue rhs bool contains(JsonbValue* rhs) const; @@ -1264,6 +1267,56 @@ inline int JsonbValue::length() const { } } +inline int JsonbValue::depth() const { + switch (type_) { + case JsonbType::T_Int8: + case JsonbType::T_Int16: + case JsonbType::T_Int32: + case JsonbType::T_Int64: + case JsonbType::T_Double: + case JsonbType::T_Float: + case JsonbType::T_Int128: + case JsonbType::T_String: + case JsonbType::T_Binary: + case JsonbType::T_Null: + case JsonbType::T_True: + case JsonbType::T_False: { + return 1; + } + case JsonbType::T_Object: { + int depth = 1; + int numElem = ((ObjectVal*)this)->numElem(); + if (numElem == 0) return depth; + + JsonbKeyValue* first_key = ((ObjectVal*)this)->getJsonbKeyValue(0); + JsonbValue* first_value = + ((ObjectVal*)this)->find(first_key->getKeyStr(), first_key->klen()); + int max_depth = depth + first_value->depth(); + + for (int i = 1; i < numElem; ++i) { + JsonbKeyValue* key = ((ObjectVal*)this)->getJsonbKeyValue(i); + JsonbValue* value = ((ObjectVal*)this)->find(key->getKeyStr(), key->klen()); + int current_depth = depth + value->depth(); + if (current_depth > max_depth) max_depth = current_depth; + } + return max_depth; + } + case JsonbType::T_Array: { + int depth = 1; + int numElem = ((ArrayVal*)this)->numElem(); + if (numElem == 0) return depth; + int max_depth = depth + ((ArrayVal*)this)->get(0)->depth(); + for (int i = 1; i < numElem; ++i) { + int current_depth = depth + ((ArrayVal*)this)->get(i)->depth(); + if (current_depth > max_depth) max_depth = current_depth; + } + return max_depth; + } + default: + return 0; + } +} + inline bool JsonbValue::contains(JsonbValue* rhs) const { switch (type_) { case JsonbType::T_Int8: diff --git a/be/src/vec/functions/function_jsonb.cpp b/be/src/vec/functions/function_jsonb.cpp index a7d43aca4f1f92d..cab4d20ff4a3251 100644 --- a/be/src/vec/functions/function_jsonb.cpp +++ b/be/src/vec/functions/function_jsonb.cpp @@ -1288,6 +1288,56 @@ struct JsonbContainsAndPathImpl { } }; +class FunctionJsonbDepth : public IFunction { +public: + static constexpr auto name = "json_depth"; + String get_name() const override { return name; } + static FunctionPtr create() { return std::make_shared(); } + + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + return make_nullable(std::make_shared()); + } + + size_t get_number_of_arguments() const override { return 1; } + + bool use_default_implementation_for_nulls() const override { return false; } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + size_t result, size_t input_rows_count) override { + DCHECK_GE(arguments.size(), 1); + auto jsonb_data_column = block.get_by_position(arguments[0]).column; + + auto null_map = ColumnUInt8::create(input_rows_count, 0); + auto return_type = block.get_data_type(result); + MutableColumnPtr res = return_type->create_column(); + + //if(jsonb_data_column->) + + for (size_t i = 0; i < input_rows_count; ++i) { + if (jsonb_data_column->is_null_at(i)) { + null_map->get_data()[i] = 1; + res->insert_data(nullptr, 0); + continue; + } + + auto jsonb_value = jsonb_data_column->get_data_at(i); + // doc is NOT necessary to be deleted since JsonbDocument will not allocate memory + JsonbDocument* doc = JsonbDocument::createDocument(jsonb_value.data, jsonb_value.size); + JsonbValue* value = doc->getValue(); + if (UNLIKELY(jsonb_value.size == 0 || !value)) { + null_map->get_data()[i] = 1; + res->insert_data(nullptr, 0); + continue; + } + auto depth = value->depth(); + res->insert_data(const_cast((char*)&depth), 0); + } + block.replace_by_position(result, + ColumnNullable::create(std::move(res), std::move(null_map))); + return Status::OK(); + } +}; + void register_function_jsonb(SimpleFunctionFactory& factory) { factory.register_function(FunctionJsonbParse::name); factory.register_alias(FunctionJsonbParse::name, FunctionJsonbParse::alias); @@ -1353,6 +1403,7 @@ void register_function_jsonb(SimpleFunctionFactory& factory) { factory.register_function>(); factory.register_function>(); factory.register_function>(); + factory.register_function(); } } // namespace doris::vectorized diff --git a/docs/en/docs/sql-manual/sql-functions/json-functions/json-depth.md b/docs/en/docs/sql-manual/sql-functions/json-functions/json-depth.md new file mode 100644 index 000000000000000..261c2d3014a32bb --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/json-functions/json-depth.md @@ -0,0 +1,94 @@ +--- +{ +"title": "JSON_DEPTH", +"language": "en" +} +--- + + + +## json_depth +### description +#### Syntax + +`INT json_depth(JSON json_str)` + +returns the maximum depth of a JSON document. + +JSON_DEPTH() calculates depth according to the following rules: + +* The depth of an empty array, or an empty object, or a scalar is 1. +* The depth of an nonempty array containing only elements of depth 1 is 2. +* The depth of an nonempty object containing only member values of depth 1 is 2. +* return NULL if the argument is NULL. + +### example + +``` +mysql> select JSON_DEPTH('[]'); ++------------------+ +| json_depth('[]') | ++------------------+ +| 1 | ++------------------+ +1 row in set (0.07 sec) + +mysql> select JSON_DEPTH('1'); ++-----------------+ +| json_depth('1') | ++-----------------+ +| 1 | ++-----------------+ +1 row in set (0.09 sec) + +mysql> select JSON_DEPTH('[1, 2]'); ++----------------------+ +| json_depth('[1, 2]') | ++----------------------+ +| 2 | ++----------------------+ +1 row in set (0.05 sec) + +mysql> select JSON_DEPTH('[1, [2, 3]]'); ++---------------------------+ +| json_depth('[1, [2, 3]]') | ++---------------------------+ +| 3 | ++---------------------------+ +1 row in set (0.05 sec) + +mysql> select JSON_DEPTH('{"x": {"y": 1}}'); ++-------------------------------+ +| json_depth('{"x": {"y": 1}}') | ++-------------------------------+ +| 3 | ++-------------------------------+ +1 row in set (0.06 sec) + +mysql> select JSON_DEPTH(NULL); ++------------------+ +| json_depth(NULL) | ++------------------+ +| NULL | ++------------------+ +1 row in set (0.08 sec) +``` +### keywords +json,json_depth diff --git a/docs/sidebars.json b/docs/sidebars.json index 0caf967961af3a7..25f91955a590337 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -639,6 +639,7 @@ "sql-manual/sql-functions/json-functions/json-valid", "sql-manual/sql-functions/json-functions/json-contains", "sql-manual/sql-functions/json-functions/json-length", + "sql-manual/sql-functions/json-functions/json-depth", "sql-manual/sql-functions/json-functions/get-json-double", "sql-manual/sql-functions/json-functions/get-json-int", "sql-manual/sql-functions/json-functions/get-json-bigint", diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/json-functions/json-depth.md b/docs/zh-CN/docs/sql-manual/sql-functions/json-functions/json-depth.md new file mode 100644 index 000000000000000..0df31391ed05d80 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/json-functions/json-depth.md @@ -0,0 +1,94 @@ +--- +{ +"title": "JSON_DEPTH", +"language": "zh-CN" +} +--- + + + +## json_depth +### description +#### Syntax + +`INT json_depth(JSON json_str)` + +返回 JSON 文档的最大深度。 + +JSON_DEPTH()根据以下规则计算深度: + +* 空数组、空对象或标量的深度为 1。 +* 仅包含深度为 1 的元素的非空数组的深度为2。 +* 仅包含深度为 1 的成员值的非空对象的深度为2。 +* NULL如果参数为 ,则该函数将返回NULL。 + +### example + +``` +mysql> select JSON_DEPTH('[]'); ++------------------+ +| json_depth('[]') | ++------------------+ +| 1 | ++------------------+ +1 row in set (0.07 sec) + +mysql> select JSON_DEPTH('1'); ++-----------------+ +| json_depth('1') | ++-----------------+ +| 1 | ++-----------------+ +1 row in set (0.09 sec) + +mysql> select JSON_DEPTH('[1, 2]'); ++----------------------+ +| json_depth('[1, 2]') | ++----------------------+ +| 2 | ++----------------------+ +1 row in set (0.05 sec) + +mysql> select JSON_DEPTH('[1, [2, 3]]'); ++---------------------------+ +| json_depth('[1, [2, 3]]') | ++---------------------------+ +| 3 | ++---------------------------+ +1 row in set (0.05 sec) + +mysql> select JSON_DEPTH('{"x": {"y": 1}}'); ++-------------------------------+ +| json_depth('{"x": {"y": 1}}') | ++-------------------------------+ +| 3 | ++-------------------------------+ +1 row in set (0.06 sec) + +mysql> select JSON_DEPTH(NULL); ++------------------+ +| json_depth(NULL) | ++------------------+ +| NULL | ++------------------+ +1 row in set (0.08 sec) +``` +### keywords +json,json_depth diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java index e73281e8098c3fe..a45e553ef2c835e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java @@ -181,6 +181,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Instr; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonArray; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonContains; +import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonDepth; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonExtract; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonInsert; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonLength; @@ -292,6 +293,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.RoundBankers; import org.apache.doris.nereids.trees.expressions.functions.scalar.Rpad; import org.apache.doris.nereids.trees.expressions.functions.scalar.Rtrim; +import org.apache.doris.nereids.trees.expressions.functions.scalar.RunningDifference; import org.apache.doris.nereids.trees.expressions.functions.scalar.SecToTime; import org.apache.doris.nereids.trees.expressions.functions.scalar.Second; import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondCeil; @@ -564,9 +566,6 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(JsonQuote.class, "json_quote"), scalar(JsonUnQuote.class, "json_unquote"), scalar(JsonExtract.class, "json_extract"), - scalar(JsonInsert.class, "json_insert"), - scalar(JsonReplace.class, "json_replace"), - scalar(JsonSet.class, "json_set"), scalar(JsonbExistsPath.class, "json_exists_path"), scalar(JsonbExistsPath.class, "jsonb_exists_path"), scalar(JsonbExtract.class, "jsonb_extract"), @@ -611,7 +610,7 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(JsonbType.class, "json_type"), scalar(JsonbType.class, "jsonb_type"), scalar(JsonLength.class, "json_length"), - scalar(JsonContains.class, "json_contains"), + scalar(JsonContains.class, "json_conatins"), scalar(LastDay.class, "last_day"), scalar(Least.class, "least"), scalar(Left.class, "left"), @@ -691,6 +690,7 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(RoundBankers.class, "round_bankers"), scalar(Rpad.class, "rpad"), scalar(Rtrim.class, "rtrim"), + scalar(RunningDifference.class, "running_difference"), scalar(Second.class, "second"), scalar(SecondCeil.class, "second_ceil"), scalar(SecondFloor.class, "second_floor"), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/JsonDepth.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/JsonDepth.java new file mode 100644 index 000000000000000..399de9a45ffca1f --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/JsonDepth.java @@ -0,0 +1,69 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.trees.expressions.functions.scalar; + +import org.apache.doris.catalog.FunctionSignature; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable; +import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression; +import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; +import org.apache.doris.nereids.types.IntegerType; +import org.apache.doris.nereids.types.JsonType; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * ScalarFunction 'json_depth'. This class is generated by GenerateFunction. + */ +public class JsonDepth extends ScalarFunction + implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable { + + public static final List SIGNATURES = ImmutableList.of( + FunctionSignature.ret(IntegerType.INSTANCE).args(JsonType.INSTANCE) + ); + + /** + * constructor with 1 arguments. + */ + public JsonDepth(Expression arg0) { + super("json_depth", arg0); + } + + /** + * withChildren. + */ + @Override + public JsonDepth withChildren(List children) { + Preconditions.checkArgument(children.size() == 1); + return new JsonDepth(children.get(0)); + } + + @Override + public List getSignatures() { + return SIGNATURES; + } + + @Override + public R accept(ExpressionVisitor visitor, C context) { + return visitor.visitJsonDepth(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java index 111116af0eb4e5f..8d3c07a6bc8afe2 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java @@ -179,6 +179,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Instr; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonArray; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonContains; +import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonDepth; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonExtract; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonInsert; import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonLength; @@ -1172,6 +1173,10 @@ default R visitJsonLength(JsonLength jsonLength, C context) { return visitScalarFunction(jsonLength, context); } + default R visitJsonDepth(JsonDepth jsonDepth, C context) { + return visitScalarFunction(jsonDepth, context); + } + default R visitJsonContains(JsonContains jsonContains, C context) { return visitScalarFunction(jsonContains, context); } diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py index 8cbb924c3583292..3c6496749e1c4f1 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -1771,6 +1771,7 @@ [['json_contains'], 'BOOLEAN', ['JSONB', 'JSONB'], 'ALWAYS_NULLABLE'], [['json_contains'], 'BOOLEAN', ['JSONB', 'JSONB', 'VARCHAR'], 'ALWAYS_NULLABLE'], [['json_contains'], 'BOOLEAN', ['JSONB', 'JSONB', 'STRING'], 'ALWAYS_NULLABLE'], + [['json_depth'], 'INT', ['JSONB'], 'ALWAYS_NULLABLE'], # Json functions [['get_json_int'], 'INT', ['VARCHAR', 'VARCHAR'], 'ALWAYS_NULLABLE'], diff --git a/regression-test/data/jsonb_p0/test_jsonb_load_and_function.out b/regression-test/data/jsonb_p0/test_jsonb_load_and_function.out index 29cb48477a787b3..dc934846cef5de4 100644 --- a/regression-test/data/jsonb_p0/test_jsonb_load_and_function.out +++ b/regression-test/data/jsonb_p0/test_jsonb_load_and_function.out @@ -7723,3 +7723,65 @@ true 30 -9223372036854775808 false 31 18446744073709551615 false +-- !sql_json_depth -- +\N + +-- !sql_json_depth -- +1 + +-- !sql_json_depth -- +1 + +-- !sql_json_depth -- +1 + +-- !sql_json_depth -- +1 + +-- !sql_json_depth -- +1 + +-- !sql_json_depth -- +2 + +-- !sql_json_depth -- +3 + +-- !sql_json_depth -- +3 + +-- !sql_json_depth -- +3 + +-- !sql_json_depth -- +2 + +-- !sql_json_depth -- +3 + +-- !sql_json_depth -- +1 \N \N +2 null 1 +3 true 1 +4 false 1 +5 100 1 +6 10000 1 +7 1000000000 1 +8 1152921504606846976 1 +9 6.18 1 +10 "abcd" 1 +11 {} 1 +12 {"k1":"v31","k2":300} 2 +13 [] 1 +14 [123,456] 2 +15 ["abc","def"] 2 +16 [null,true,false,100,6.18,"abc"] 2 +17 [{"k1":"v41","k2":400},1,"a",3.14] 3 +18 {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]} 4 +26 \N \N +27 {"k1":"v1","k2":200} 2 +28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} 3 +29 12524337771678448270 1 +30 -9223372036854775808 1 +31 18446744073709551615 1 + diff --git a/regression-test/data/jsonb_p0/test_jsonb_load_unique_key_and_function.out b/regression-test/data/jsonb_p0/test_jsonb_load_unique_key_and_function.out index eca0a75867aba9d..a94bd4663670974 100644 --- a/regression-test/data/jsonb_p0/test_jsonb_load_unique_key_and_function.out +++ b/regression-test/data/jsonb_p0/test_jsonb_load_unique_key_and_function.out @@ -6105,3 +6105,62 @@ true 27 {"k1":"v1","k2":200} false 28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} false +-- !sql_json_depth -- +\N + +-- !sql_json_depth -- +1 + +-- !sql_json_depth -- +1 + +-- !sql_json_depth -- +1 + +-- !sql_json_depth -- +1 + +-- !sql_json_depth -- +1 + +-- !sql_json_depth -- +2 + +-- !sql_json_depth -- +3 + +-- !sql_json_depth -- +3 + +-- !sql_json_depth -- +3 + +-- !sql_json_depth -- +2 + +-- !sql_json_depth -- +3 + +-- !sql_json_depth -- +1 \N \N +2 null 1 +3 true 1 +4 false 1 +5 100 1 +6 10000 1 +7 1000000000 1 +8 1152921504606846976 1 +9 6.18 1 +10 "abcd" 1 +11 {} 1 +12 {"k1":"v31","k2":300} 2 +13 [] 1 +14 [123,456] 2 +15 ["abc","def"] 2 +16 [null,true,false,100,6.18,"abc"] 2 +17 [{"k1":"v41","k2":400},1,"a",3.14] 3 +18 {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]} 4 +26 \N \N +27 {"k1":"v1","k2":200} 2 +28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} 3 + diff --git a/regression-test/suites/jsonb_p0/test_jsonb_load_and_function.groovy b/regression-test/suites/jsonb_p0/test_jsonb_load_and_function.groovy index 524b89ae6a33b7c..75554d0c777c988 100644 --- a/regression-test/suites/jsonb_p0/test_jsonb_load_and_function.groovy +++ b/regression-test/suites/jsonb_p0/test_jsonb_load_and_function.groovy @@ -569,4 +569,18 @@ suite("test_jsonb_load_and_function", "p0") { qt_select_json_contains """SELECT id, j, json_contains(j, cast('{"k2":300}' as json)) FROM ${testTable} ORDER BY id""" qt_select_json_contains """SELECT id, j, json_contains(j, cast('{"k1":"v41","k2":400}' as json), '\$.a1') FROM ${testTable} ORDER BY id""" qt_select_json_contains """SELECT id, j, json_contains(j, cast('[123,456]' as json)) FROM ${testTable} ORDER BY id""" + + qt_sql_json_depth """SELECT json_depth(NULL)""" + qt_sql_json_depth """SELECT json_depth('true')""" + qt_sql_json_depth """SELECT json_depth('null')""" + qt_sql_json_depth """SELECT json_depth('"abc"')""" + qt_sql_json_depth """SELECT json_depth('[]')""" + qt_sql_json_depth """SELECT json_depth('{}')""" + qt_sql_json_depth """SELECT json_depth('[1, 2]')""" + qt_sql_json_depth """SELECT json_depth('[1, {"x": 2}]')""" + qt_sql_json_depth """SELECT json_depth('{"x": 1, "y": [1, 2]}')""" + qt_sql_json_depth """SELECT json_depth('[1, [2, 3]]')""" + qt_sql_json_depth """SELECT json_depth('{"x": 1}')""" + qt_sql_json_depth """SELECT json_depth('{"x": {"y": 1}}')""" + qt_sql_json_depth """SELECT id, j, json_depth(j) FROM ${testTable} ORDER BY id""" } diff --git a/regression-test/suites/jsonb_p0/test_jsonb_load_unique_key_and_function.groovy b/regression-test/suites/jsonb_p0/test_jsonb_load_unique_key_and_function.groovy index 526ddf4710e557a..154c0512d4784ab 100644 --- a/regression-test/suites/jsonb_p0/test_jsonb_load_unique_key_and_function.groovy +++ b/regression-test/suites/jsonb_p0/test_jsonb_load_unique_key_and_function.groovy @@ -512,4 +512,18 @@ suite("test_jsonb_unique_load_and_function", "p0") { qt_select_json_contains """SELECT id, j, json_contains(j, cast('{"k2":300}' as json)) FROM ${testTable} ORDER BY id""" qt_select_json_contains """SELECT id, j, json_contains(j, cast('{"k1":"v41","k2":400}' as json), '\$.a1') FROM ${testTable} ORDER BY id""" qt_select_json_contains """SELECT id, j, json_contains(j, cast('[123,456]' as json)) FROM ${testTable} ORDER BY id""" + + qt_sql_json_depth """SELECT json_depth(NULL)""" + qt_sql_json_depth """SELECT json_depth('true')""" + qt_sql_json_depth """SELECT json_depth('null')""" + qt_sql_json_depth """SELECT json_depth('"abc"')""" + qt_sql_json_depth """SELECT json_depth('[]')""" + qt_sql_json_depth """SELECT json_depth('{}')""" + qt_sql_json_depth """SELECT json_depth('[1, 2]')""" + qt_sql_json_depth """SELECT json_depth('[1, {"x": 2}]')""" + qt_sql_json_depth """SELECT json_depth('{"x": 1, "y": [1, 2]}')""" + qt_sql_json_depth """SELECT json_depth('[1, [2, 3]]')""" + qt_sql_json_depth """SELECT json_depth('{"x": 1}')""" + qt_sql_json_depth """SELECT json_depth('{"x": {"y": 1}}')""" + qt_sql_json_depth """SELECT id, j, json_depth(j) FROM ${testTable} ORDER BY id""" }