This is an automated email from the ASF dual-hosted git repository.
yiguolei 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 a73b6e81042 [feature](function) support
sort_json_object_keys/normalize_json_numbers_to_double function (#56576)
a73b6e81042 is described below
commit a73b6e810422a26bf1b61a85f953e7f08928c138
Author: Mryange <[email protected]>
AuthorDate: Sun Oct 12 14:40:01 2025 +0800
[feature](function) support
sort_json_object_keys/normalize_json_numbers_to_double function (#56576)
### What problem does this PR solve?
https://github.com/apache/doris-website/pull/2927
```sql
mysql> select sort_json_object_keys(cast('{"b":123,"b":456,"a":789}' as
json));
+------------------------------------------------------------------+
| sort_json_object_keys(cast('{"b":123,"b":456,"a":789}' as json)) |
+------------------------------------------------------------------+
| {"a":789,"b":123} |
+------------------------------------------------------------------+
mysql> select cast('{"abc": 18446744073709551616}' as json) ,
normalize_json_numbers_to_double(cast('{"abc": 18446744073709551616}' as json));
+-----------------------------------------------+---------------------------------------------------------------------------------+
| cast('{"abc": 18446744073709551616}' as json) |
normalize_json_numbers_to_double(cast('{"abc": 18446744073709551616}' as json))
|
+-----------------------------------------------+---------------------------------------------------------------------------------+
| {"abc":18446744073709551616} |
{"abc":1.8446744073709552e+19}
|
+-----------------------------------------------+---------------------------------------------------------------------------------+
```
### Release note
None
### Check List (For Author)
- Test <!-- At least one of them must be included. -->
- [ ] Regression test
- [ ] Unit Test
- [ ] Manual test (add detailed scripts or steps below)
- [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
- [ ] Previous test can cover this change.
- [ ] No code files have been changed.
- [ ] Other reason <!-- Add your reason? -->
- Behavior changed:
- [ ] No.
- [ ] Yes. <!-- Explain the behavior change -->
- Does this need documentation?
- [ ] No.
- [ ] Yes. <!-- Add document PR link here. eg:
https://github.com/apache/doris-website/pull/1214 -->
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR
should merge into -->
---
be/src/vec/functions/function_jsonb_transform.cpp | 188 +++++++++++++++++++++
be/src/vec/functions/simple_function_factory.h | 2 +
.../doris/catalog/BuiltinScalarFunctions.java | 6 +
.../scalar/NormalizeJsonNumbersToDouble.java | 72 ++++++++
.../functions/scalar/SortJsonbObjectKeys.java | 72 ++++++++
.../expressions/visitor/ScalarFunctionVisitor.java | 10 ++
.../test_json_normalize_json_numbers_to_double.out | 46 +++++
.../jsonb_p0/test_json_sort_json_object_keys.out | 37 ++++
...st_json_normalize_json_numbers_to_double.groovy | 113 +++++++++++++
.../test_json_sort_json_object_keys.groovy | 100 +++++++++++
10 files changed, 646 insertions(+)
diff --git a/be/src/vec/functions/function_jsonb_transform.cpp
b/be/src/vec/functions/function_jsonb_transform.cpp
new file mode 100644
index 00000000000..17ef600c48a
--- /dev/null
+++ b/be/src/vec/functions/function_jsonb_transform.cpp
@@ -0,0 +1,188 @@
+// 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.
+
+#include <vector>
+
+#include "runtime/primitive_type.h"
+#include "util/jsonb_document.h"
+#include "util/jsonb_document_cast.h"
+#include "util/jsonb_writer.h"
+#include "vec/data_types/data_type_jsonb.h"
+#include "vec/functions/simple_function_factory.h"
+
+namespace doris::vectorized {
+
+// Sort the keys of the JSON object and deduplicate the repeated keys, keeping
the first one
+void sort_json_object_keys(JsonbWriter& jsonb_writer, const JsonbValue*
jsonb_value) {
+ if (jsonb_value->isObject()) {
+ std::vector<std::pair<StringRef, const JsonbValue*>> kvs;
+ const auto* obj_val = jsonb_value->unpack<ObjectVal>();
+ for (auto it = obj_val->begin(); it != obj_val->end(); ++it) {
+ kvs.emplace_back(StringRef(it->getKeyStr(), it->klen()),
it->value());
+ }
+ // sort by key
+ std::sort(kvs.begin(), kvs.end(),
+ [](const auto& left, const auto& right) { return left.first
< right.first; });
+ // unique by key
+ kvs.erase(std::unique(kvs.begin(), kvs.end(),
+ [](const auto& left, const auto& right) {
+ return left.first == right.first;
+ }),
+ kvs.end());
+ jsonb_writer.writeStartObject();
+ for (const auto& kv : kvs) {
+ jsonb_writer.writeKey(kv.first.data,
static_cast<uint8_t>(kv.first.size));
+ sort_json_object_keys(jsonb_writer, kv.second);
+ }
+ jsonb_writer.writeEndObject();
+ } else if (jsonb_value->isArray()) {
+ const auto* array_val = jsonb_value->unpack<ArrayVal>();
+ jsonb_writer.writeStartArray();
+ for (auto it = array_val->begin(); it != array_val->end(); ++it) {
+ sort_json_object_keys(jsonb_writer, &*it);
+ }
+ jsonb_writer.writeEndArray();
+ } else {
+ // scalar value
+ jsonb_writer.writeValue(jsonb_value);
+ }
+}
+
+// Convert all numeric types in JSON to double type
+void normalize_json_numbers_to_double(JsonbWriter& jsonb_writer, const
JsonbValue* jsonb_value) {
+ if (jsonb_value->isObject()) {
+ jsonb_writer.writeStartObject();
+ const auto* obj_val = jsonb_value->unpack<ObjectVal>();
+ for (auto it = obj_val->begin(); it != obj_val->end(); ++it) {
+ jsonb_writer.writeKey(it->getKeyStr(), it->klen());
+ normalize_json_numbers_to_double(jsonb_writer, it->value());
+ }
+ jsonb_writer.writeEndObject();
+ } else if (jsonb_value->isArray()) {
+ const auto* array_val = jsonb_value->unpack<ArrayVal>();
+ jsonb_writer.writeStartArray();
+ for (auto it = array_val->begin(); it != array_val->end(); ++it) {
+ normalize_json_numbers_to_double(jsonb_writer, &*it);
+ }
+ jsonb_writer.writeEndArray();
+ } else {
+ // scalar value
+ if (jsonb_value->isInt() || jsonb_value->isFloat() ||
jsonb_value->isDouble() ||
+ jsonb_value->isDecimal()) {
+ double to;
+ CastParameters params;
+ params.is_strict = false;
+ JsonbCast::cast_from_json_to_float(jsonb_value, to, params);
+ if (to == 0.0) {
+ // to avoid -0.0
+ to = 0.0;
+ } else if (std::isnan(to)) {
+ // to avoid -nan
+ to = std::numeric_limits<double>::quiet_NaN();
+ }
+ jsonb_writer.writeDouble(to);
+ } else {
+ jsonb_writer.writeValue(jsonb_value);
+ }
+ }
+}
+
+// Input jsonb, output jsonb
+template <typename Impl>
+class FunctionJsonbTransform : public IFunction {
+public:
+ static constexpr auto name = Impl::name;
+
+ static FunctionPtr create() { return
std::make_shared<FunctionJsonbTransform>(); }
+
+ String get_name() const override { return name; }
+
+ DataTypePtr get_return_type_impl(const DataTypes& arguments) const
override {
+ return std::make_shared<DataTypeJsonb>();
+ }
+
+ size_t get_number_of_arguments() const override { return 1; }
+
+ Status execute_impl(FunctionContext* context, Block& block, const
ColumnNumbers& arguments,
+ uint32_t result, size_t size) const override {
+ auto input_column = block.get_by_position(arguments[0]).column;
+ auto to_column = ColumnString::create();
+
+ const auto& input_jsonb_column = assert_cast<const
ColumnString&>(*input_column);
+
+ to_column->get_chars().reserve(input_jsonb_column.get_chars().size());
+
to_column->get_offsets().reserve(input_jsonb_column.get_offsets().size());
+
+ JsonbWriter writer;
+ for (size_t i = 0; i < size; ++i) {
+ StringRef val = input_jsonb_column.get_data_at(i);
+ JsonbDocument* doc = nullptr;
+ auto st = JsonbDocument::checkAndCreateDocument(val.data,
val.size, &doc);
+ if (!st.ok() || !doc || !doc->getValue()) [[unlikely]] {
+ // mayby be invalid jsonb, just insert default
+ // invalid jsonb value may be caused by the default null
processing
+ // insert empty string
+ to_column->insert_default();
+ continue;
+ }
+ JsonbValue* value = doc->getValue();
+ if (UNLIKELY(!value)) {
+ // mayby be invalid jsonb, just insert default
+ // invalid jsonb value may be caused by the default null
processing
+ // insert empty string
+ to_column->insert_default();
+ continue;
+ }
+
+ writer.reset();
+
+ Impl::transform(writer, value);
+
+ to_column->insert_data(writer.getOutput()->getBuffer(),
writer.getOutput()->getSize());
+ }
+ block.get_by_position(result).column = std::move(to_column);
+ return Status::OK();
+ }
+};
+
+struct SortJsonObjectKeys {
+ static constexpr auto name = "sort_json_object_keys";
+ static void transform(JsonbWriter& writer, const JsonbValue* value) {
+ sort_json_object_keys(writer, value);
+ }
+};
+
+struct NormalizeJsonNumbersToDouble {
+ static constexpr auto name = "normalize_json_numbers_to_double";
+ static void transform(JsonbWriter& writer, const JsonbValue* value) {
+ normalize_json_numbers_to_double(writer, value);
+ }
+};
+
+using FunctionSortJsonObjectKeys = FunctionJsonbTransform<SortJsonObjectKeys>;
+using FunctionNormalizeJsonNumbersToDouble =
FunctionJsonbTransform<NormalizeJsonNumbersToDouble>;
+
+void register_function_json_transform(SimpleFunctionFactory& factory) {
+ factory.register_function<FunctionSortJsonObjectKeys>();
+ factory.register_function<FunctionNormalizeJsonNumbersToDouble>();
+
+ factory.register_alias(FunctionSortJsonObjectKeys::name,
"sort_jsonb_object_keys");
+ factory.register_alias(FunctionNormalizeJsonNumbersToDouble::name,
+ "normalize_jsonb_numbers_to_double");
+}
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/functions/simple_function_factory.h
b/be/src/vec/functions/simple_function_factory.h
index 2b39d180204..7ff72bb60f9 100644
--- a/be/src/vec/functions/simple_function_factory.h
+++ b/be/src/vec/functions/simple_function_factory.h
@@ -76,6 +76,7 @@ void register_function_utility(SimpleFunctionFactory&
factory);
void register_function_json(SimpleFunctionFactory& factory);
void register_function_jsonb(SimpleFunctionFactory& factory);
void register_function_to_json(SimpleFunctionFactory& factory);
+void register_function_json_transform(SimpleFunctionFactory& factory);
void register_function_hash(SimpleFunctionFactory& factory);
void register_function_ifnull(SimpleFunctionFactory& factory);
void register_function_like(SimpleFunctionFactory& factory);
@@ -343,6 +344,7 @@ public:
register_function_score(instance);
register_function_binary(instance);
register_function_soundex(instance);
+ register_function_json_transform(instance);
#if defined(BE_TEST) && !defined(BE_BENCHMARK)
register_function_throw_exception(instance);
#endif
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 541d6e0a0d2..4c125b8f2f9 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
@@ -354,6 +354,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.NextDay;
import org.apache.doris.nereids.trees.expressions.functions.scalar.NgramSearch;
import org.apache.doris.nereids.trees.expressions.functions.scalar.NonNullable;
import org.apache.doris.nereids.trees.expressions.functions.scalar.NormalCdf;
+import
org.apache.doris.nereids.trees.expressions.functions.scalar.NormalizeJsonNumbersToDouble;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.NotNullOrEmpty;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Now;
import org.apache.doris.nereids.trees.expressions.functions.scalar.NullIf;
@@ -421,6 +422,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.Sm3;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Sm3sum;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Sm4Decrypt;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Sm4Encrypt;
+import
org.apache.doris.nereids.trees.expressions.functions.scalar.SortJsonbObjectKeys;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Soundex;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Space;
import org.apache.doris.nereids.trees.expressions.functions.scalar.SplitByChar;
@@ -858,6 +860,8 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(NextDay.class, "next_day"),
scalar(NonNullable.class, "non_nullable"),
scalar(NormalCdf.class, "normal_cdf"),
+ scalar(NormalizeJsonNumbersToDouble.class,
"normalize_json_numbers_to_double"),
+ scalar(NormalizeJsonNumbersToDouble.class,
"normalize_jsonb_numbers_to_double"),
scalar(NotNullOrEmpty.class, "not_null_or_empty"),
scalar(NgramSearch.class, "ngram_search"),
scalar(Now.class, "now", "current_timestamp", "localtime",
"localtimestamp"),
@@ -932,6 +936,8 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(Sm3sum.class, "sm3sum"),
scalar(Sm4Decrypt.class, "sm4_decrypt"),
scalar(Sm4Encrypt.class, "sm4_encrypt"),
+ scalar(SortJsonbObjectKeys.class, "sort_json_object_keys"),
+ scalar(SortJsonbObjectKeys.class, "sort_jsonb_object_keys"),
scalar(Soundex.class, "soundex"),
scalar(Space.class, "space"),
scalar(SplitByChar.class, "split_by_char"),
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/NormalizeJsonNumbersToDouble.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/NormalizeJsonNumbersToDouble.java
new file mode 100644
index 00000000000..1ed12f926a8
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/NormalizeJsonNumbersToDouble.java
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions.functions.scalar;
+
+import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.JsonType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'normalize_json_numbers_to_double'.
+ */
+public class NormalizeJsonNumbersToDouble extends ScalarFunction
+ implements UnaryExpression, ExplicitlyCastableSignature,
PropagateNullable {
+
+ public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(JsonType.INSTANCE).args(JsonType.INSTANCE));
+
+ /**
+ * constructor with 1 argument.
+ */
+ public NormalizeJsonNumbersToDouble(Expression arg0) {
+ super("normalize_json_numbers_to_double", arg0);
+ }
+
+ /** constructor for withChildren and reuse signature */
+ private NormalizeJsonNumbersToDouble(ScalarFunctionParams functionParams) {
+ super(functionParams);
+ }
+
+ /**
+ * withChildren.
+ */
+ @Override
+ public NormalizeJsonNumbersToDouble withChildren(List<Expression>
children) {
+ Preconditions.checkArgument(children.size() == 1);
+ return new NormalizeJsonNumbersToDouble(getFunctionParams(children));
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return SIGNATURES;
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitNormalizeJsonNumbersToDouble(this, context);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SortJsonbObjectKeys.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SortJsonbObjectKeys.java
new file mode 100644
index 00000000000..a964e0ca572
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SortJsonbObjectKeys.java
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions.functions.scalar;
+
+import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.JsonType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'sort_json_object_keys'.
+ */
+public class SortJsonbObjectKeys extends ScalarFunction
+ implements UnaryExpression, ExplicitlyCastableSignature,
PropagateNullable {
+
+ public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(JsonType.INSTANCE).args(JsonType.INSTANCE));
+
+ /**
+ * constructor with 1 argument.
+ */
+ public SortJsonbObjectKeys(Expression arg0) {
+ super("sort_json_object_keys", arg0);
+ }
+
+ /** constructor for withChildren and reuse signature */
+ private SortJsonbObjectKeys(ScalarFunctionParams functionParams) {
+ super(functionParams);
+ }
+
+ /**
+ * withChildren.
+ */
+ @Override
+ public SortJsonbObjectKeys withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() == 1);
+ return new SortJsonbObjectKeys(getFunctionParams(children));
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return SIGNATURES;
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitSortJsonbObjectKeys(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 f2a11017a71..d327bade315 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
@@ -357,6 +357,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.NextDay;
import org.apache.doris.nereids.trees.expressions.functions.scalar.NgramSearch;
import org.apache.doris.nereids.trees.expressions.functions.scalar.NonNullable;
import org.apache.doris.nereids.trees.expressions.functions.scalar.NormalCdf;
+import
org.apache.doris.nereids.trees.expressions.functions.scalar.NormalizeJsonNumbersToDouble;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.NotNullOrEmpty;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Now;
import org.apache.doris.nereids.trees.expressions.functions.scalar.NullIf;
@@ -421,6 +422,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.Sm3;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Sm3sum;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Sm4Decrypt;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Sm4Encrypt;
+import
org.apache.doris.nereids.trees.expressions.functions.scalar.SortJsonbObjectKeys;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Soundex;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Space;
import org.apache.doris.nereids.trees.expressions.functions.scalar.SplitByChar;
@@ -1597,6 +1599,10 @@ public interface ScalarFunctionVisitor<R, C> {
return visitScalarFunction(jsonbValid, context);
}
+ default R visitSortJsonbObjectKeys(SortJsonbObjectKeys sort, C context) {
+ return visitScalarFunction(sort, context);
+ }
+
default R visitL1Distance(L1Distance l1Distance, C context) {
return visitScalarFunction(l1Distance, context);
}
@@ -1785,6 +1791,10 @@ public interface ScalarFunctionVisitor<R, C> {
return visitScalarFunction(normalCdf, context);
}
+ default R visitNormalizeJsonNumbersToDouble(NormalizeJsonNumbersToDouble
func, C context) {
+ return visitScalarFunction(func, context);
+ }
+
default R visitNotNullOrEmpty(NotNullOrEmpty notNullOrEmpty, C context) {
return visitScalarFunction(notNullOrEmpty, context);
}
diff --git
a/regression-test/data/jsonb_p0/test_json_normalize_json_numbers_to_double.out
b/regression-test/data/jsonb_p0/test_json_normalize_json_numbers_to_double.out
new file mode 100644
index 00000000000..bfd85dc9599
--- /dev/null
+++
b/regression-test/data/jsonb_p0/test_json_normalize_json_numbers_to_double.out
@@ -0,0 +1,46 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !sql --
+{"b":1.2345678901234568e+18,"b":456,"a":789} {"b":123,"b":456,"a":789}
+
+-- !sql --
+[{"b":123,"b":456,"a":1.2345678901234568e+18},{"b":1.2133798178293133e+18},{"b":4.5612312312312314e+17},{"a":74124123132189}]
+
+-- !sql --
+nan
+
+-- !sql --
+0
+
+-- !sql --
+1231231322.23123
+
+-- !sql --
+1 {"b":123,"b":456,"a":789}
+2 {"d":123,"c":456,"b":789,"a":1011}
+3 {"x":123,"y":456,"z":789}
+4 [{"b":123,"b":456,"a":789},{"b":123},{"b":456},{"a":789}]
+5 \N
+6
{"Data":[{"a_1":"value1","B2":{"zZ":123,"A_1":"value2","b2":"should_sort_last","b2":"should_sort_first","__key__":[{"dupKey":"first","Dupkey":"second","dupKey":"third","1dupKey":"fourth"},{"mix_key":"foo","Mix_Key":"bar","mix_key":"baz"}]},"B2":"anotherB2","b2":"duplicateB2","A_1":"anotherA_1"},{"b2":[{"k":1,"K":2,"k":3},{"b2":"array_dup","B2":"array_B2"}],"randomKey_3":{"foo":"test","Foo":"TEST","foo":"again"}}],"meta_9":{"info":"example","Info":"EXAMPLE","info":"duplicate"}}
+
+-- !sql --
+1 {"b":123,"b":456,"a":789}
+2 {"d":123,"c":456,"b":789,"a":1011}
+3 {"x":123,"y":456,"z":789}
+4 [{"b":123,"b":456,"a":789},{"b":123},{"b":456},{"a":789}]
+5 \N
+6
{"Data":[{"a_1":"value1","B2":{"zZ":123,"A_1":"value2","b2":"should_sort_last","b2":"should_sort_first","__key__":[{"dupKey":"first","Dupkey":"second","dupKey":"third","1dupKey":"fourth"},{"mix_key":"foo","Mix_Key":"bar","mix_key":"baz"}]},"B2":"anotherB2","b2":"duplicateB2","A_1":"anotherA_1"},{"b2":[{"k":1,"K":2,"k":3},{"b2":"array_dup","B2":"array_B2"}],"randomKey_3":{"foo":"test","Foo":"TEST","foo":"again"}}],"meta_9":{"info":"example","Info":"EXAMPLE","info":"duplicate"}}
+
+-- !sql --
+1 {"b":123,"b":456,"a":789}
+2 {"d":123,"c":456,"b":789,"a":1011}
+3 {"x":123,"y":456,"z":789}
+4 [{"b":123,"b":456,"a":789},{"b":123},{"b":456},{"a":789}]
+6
{"Data":[{"a_1":"value1","B2":{"zZ":123,"A_1":"value2","b2":"should_sort_last","b2":"should_sort_first","__key__":[{"dupKey":"first","Dupkey":"second","dupKey":"third","1dupKey":"fourth"},{"mix_key":"foo","Mix_Key":"bar","mix_key":"baz"}]},"B2":"anotherB2","b2":"duplicateB2","A_1":"anotherA_1"},{"b2":[{"k":1,"K":2,"k":3},{"b2":"array_dup","B2":"array_B2"}],"randomKey_3":{"foo":"test","Foo":"TEST","foo":"again"}}],"meta_9":{"info":"example","Info":"EXAMPLE","info":"duplicate"}}
+
+-- !sql --
+1 {"b":123,"b":456,"a":789}
+2 {"d":123,"c":456,"b":789,"a":1011}
+3 {"x":123,"y":456,"z":789}
+4 [{"b":123,"b":456,"a":789},{"b":123},{"b":456},{"a":789}]
+6
{"Data":[{"a_1":"value1","B2":{"zZ":123,"A_1":"value2","b2":"should_sort_last","b2":"should_sort_first","__key__":[{"dupKey":"first","Dupkey":"second","dupKey":"third","1dupKey":"fourth"},{"mix_key":"foo","Mix_Key":"bar","mix_key":"baz"}]},"B2":"anotherB2","b2":"duplicateB2","A_1":"anotherA_1"},{"b2":[{"k":1,"K":2,"k":3},{"b2":"array_dup","B2":"array_B2"}],"randomKey_3":{"foo":"test","Foo":"TEST","foo":"again"}}],"meta_9":{"info":"example","Info":"EXAMPLE","info":"duplicate"}}
+
diff --git a/regression-test/data/jsonb_p0/test_json_sort_json_object_keys.out
b/regression-test/data/jsonb_p0/test_json_sort_json_object_keys.out
new file mode 100644
index 00000000000..c0ce45638fe
--- /dev/null
+++ b/regression-test/data/jsonb_p0/test_json_sort_json_object_keys.out
@@ -0,0 +1,37 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !sql --
+{"a":789,"b":123} {"a":789,"b":123}
+
+-- !sql --
+[{"a":789,"b":123},{"b":123},{"b":456},{"a":789}]
+
+-- !sql --
+1 {"a":789,"b":123}
+2 {"a":1011,"b":789,"c":456,"d":123}
+3 {"x":123,"y":456,"z":789}
+4 [{"a":789,"b":123},{"b":123},{"b":456},{"a":789}]
+5 \N
+6
{"Data":[{"A_1":"anotherA_1","B2":{"A_1":"value2","__key__":[{"1dupKey":"fourth","Dupkey":"second","dupKey":"first"},{"Mix_Key":"bar","mix_key":"foo"}],"b2":"should_sort_last","zZ":123},"a_1":"value1","b2":"duplicateB2"},{"b2":[{"K":2,"k":1},{"B2":"array_B2","b2":"array_dup"}],"randomKey_3":{"Foo":"TEST","foo":"test"}}],"meta_9":{"Info":"EXAMPLE","info":"example"}}
+
+-- !sql --
+1 {"a":789,"b":123}
+2 {"a":1011,"b":789,"c":456,"d":123}
+3 {"x":123,"y":456,"z":789}
+4 [{"a":789,"b":123},{"b":123},{"b":456},{"a":789}]
+5 \N
+6
{"Data":[{"A_1":"anotherA_1","B2":{"A_1":"value2","__key__":[{"1dupKey":"fourth","Dupkey":"second","dupKey":"first"},{"Mix_Key":"bar","mix_key":"foo"}],"b2":"should_sort_last","zZ":123},"a_1":"value1","b2":"duplicateB2"},{"b2":[{"K":2,"k":1},{"B2":"array_B2","b2":"array_dup"}],"randomKey_3":{"Foo":"TEST","foo":"test"}}],"meta_9":{"Info":"EXAMPLE","info":"example"}}
+
+-- !sql --
+1 {"a":789,"b":123}
+2 {"a":1011,"b":789,"c":456,"d":123}
+3 {"x":123,"y":456,"z":789}
+4 [{"a":789,"b":123},{"b":123},{"b":456},{"a":789}]
+6
{"Data":[{"A_1":"anotherA_1","B2":{"A_1":"value2","__key__":[{"1dupKey":"fourth","Dupkey":"second","dupKey":"first"},{"Mix_Key":"bar","mix_key":"foo"}],"b2":"should_sort_last","zZ":123},"a_1":"value1","b2":"duplicateB2"},{"b2":[{"K":2,"k":1},{"B2":"array_B2","b2":"array_dup"}],"randomKey_3":{"Foo":"TEST","foo":"test"}}],"meta_9":{"Info":"EXAMPLE","info":"example"}}
+
+-- !sql --
+1 {"a":789,"b":123}
+2 {"a":1011,"b":789,"c":456,"d":123}
+3 {"x":123,"y":456,"z":789}
+4 [{"a":789,"b":123},{"b":123},{"b":456},{"a":789}]
+6
{"Data":[{"A_1":"anotherA_1","B2":{"A_1":"value2","__key__":[{"1dupKey":"fourth","Dupkey":"second","dupKey":"first"},{"Mix_Key":"bar","mix_key":"foo"}],"b2":"should_sort_last","zZ":123},"a_1":"value1","b2":"duplicateB2"},{"b2":[{"K":2,"k":1},{"B2":"array_B2","b2":"array_dup"}],"randomKey_3":{"Foo":"TEST","foo":"test"}}],"meta_9":{"Info":"EXAMPLE","info":"example"}}
+
diff --git
a/regression-test/suites/jsonb_p0/test_json_normalize_json_numbers_to_double.groovy
b/regression-test/suites/jsonb_p0/test_json_normalize_json_numbers_to_double.groovy
new file mode 100644
index 00000000000..0736fb4a8c7
--- /dev/null
+++
b/regression-test/suites/jsonb_p0/test_json_normalize_json_numbers_to_double.groovy
@@ -0,0 +1,113 @@
+// 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.
+
+
+suite("test_json_normalize_json_numbers_to_double") {
+ qt_sql """
+ select
normalize_json_numbers_to_double(cast('{"b":1234567890123456789,"b":456,"a":789}'
as json)) ,
normalize_jsonb_numbers_to_double(cast('{"b":123,"b":456,"a":789}' as json));
+ """
+
+
+ qt_sql """
+ select
normalize_json_numbers_to_double(cast('[{"b":123,"b":456,"a":1234567890123456789.231231}
,{"b":1213379817829313213},{"b":456123123123123123},{"a":74124123132189} ]' as
json));
+ """
+
+
+ qt_sql """
+ select normalize_json_numbers_to_double(to_json(cast('nan' as
double)) );
+ """
+
+ qt_sql """
+ select normalize_json_numbers_to_double(to_json(cast('-0.0' as
double)) );
+ """
+
+ qt_sql """
+ select
normalize_json_numbers_to_double(to_json(cast('1231231322.23123' as Decimal)) );
+ """
+
+ sql "DROP TABLE IF EXISTS test_json_normalize_json_numbers_to_double_table"
+
+ sql """
+ CREATE TABLE IF NOT EXISTS
test_json_normalize_json_numbers_to_double_table (
+ id INT,
+ j JSON
+ )
+ DISTRIBUTED BY HASH(id) BUCKETS 3
+ PROPERTIES (
+ "replication_num" = "1"
+ )
+ """
+
+ sql """
+ INSERT INTO test_json_normalize_json_numbers_to_double_table VALUES
+ (1, '{"b":123,"b":456,"a":789}'),
+ (2, '{"d":123,"c":456,"b":789,"a":1011}'),
+ (3, '{"x":123,"y":456,"z":789}'),
+ (4, '[{"b":123,"b":456,"a":789} ,{"b":123},{"b":456},{"a":789}]'),
+ (5, null),
+ (6,
'{"Data":[{"a_1":"value1","B2":{"zZ":123,"A_1":"value2","b2":"should_sort_last","b2":"should_sort_first","__key__":[{"dupKey":"first","Dupkey":"second","dupKey":"third","1dupKey":"fourth"},{"mix_key":"foo","Mix_Key":"bar","mix_key":"baz"}]},"B2":"anotherB2","b2":"duplicateB2","A_1":"anotherA_1"},{"b2":[{"k":1,"K":2,"k":3},{"b2":"array_dup","B2":"array_B2"}],"randomKey_3":{"foo":"test","Foo":"TEST","foo":"again"}}],"meta_9":{"info":"example","Info":"EXAMPLE","info":"duplicate"}}')
+ """
+
+ qt_sql """
+ SELECT id, normalize_json_numbers_to_double(j) as sorted_json
+ FROM test_json_normalize_json_numbers_to_double_table
+ ORDER BY id
+ """
+
+ qt_sql """
+ SELECT id, normalize_jsonb_numbers_to_double(cast(j as jsonb)) as
sorted_jsonb
+ FROM test_json_normalize_json_numbers_to_double_table
+ ORDER BY id
+ """
+
+
+
+ sql "DROP TABLE IF EXISTS test_json_normalize_json_numbers_to_double_table"
+
+ sql """
+ CREATE TABLE IF NOT EXISTS
test_json_normalize_json_numbers_to_double_table (
+ id INT,
+ j JSON NOT NULL
+ )
+ DISTRIBUTED BY HASH(id) BUCKETS 3
+ PROPERTIES (
+ "replication_num" = "1"
+ )
+ """
+
+ sql """
+ INSERT INTO test_json_normalize_json_numbers_to_double_table VALUES
+ (1, '{"b":123,"b":456,"a":789}'),
+ (2, '{"d":123,"c":456,"b":789,"a":1011}'),
+ (3, '{"x":123,"y":456,"z":789}'),
+ (4, '[{"b":123,"b":456,"a":789} ,{"b":123},{"b":456},{"a":789}]'),
+ (6,
'{"Data":[{"a_1":"value1","B2":{"zZ":123,"A_1":"value2","b2":"should_sort_last","b2":"should_sort_first","__key__":[{"dupKey":"first","Dupkey":"second","dupKey":"third","1dupKey":"fourth"},{"mix_key":"foo","Mix_Key":"bar","mix_key":"baz"}]},"B2":"anotherB2","b2":"duplicateB2","A_1":"anotherA_1"},{"b2":[{"k":1,"K":2,"k":3},{"b2":"array_dup","B2":"array_B2"}],"randomKey_3":{"foo":"test","Foo":"TEST","foo":"again"}}],"meta_9":{"info":"example","Info":"EXAMPLE","info":"duplicate"}}')
+ """
+
+ qt_sql """
+ SELECT id, normalize_json_numbers_to_double(j) as sorted_json
+ FROM test_json_normalize_json_numbers_to_double_table
+ ORDER BY id
+ """
+
+ qt_sql """
+ SELECT id, normalize_jsonb_numbers_to_double(cast(j as jsonb)) as
sorted_jsonb
+ FROM test_json_normalize_json_numbers_to_double_table
+ ORDER BY id
+ """
+
+}
diff --git
a/regression-test/suites/jsonb_p0/test_json_sort_json_object_keys.groovy
b/regression-test/suites/jsonb_p0/test_json_sort_json_object_keys.groovy
new file mode 100644
index 00000000000..65f8f3f4b37
--- /dev/null
+++ b/regression-test/suites/jsonb_p0/test_json_sort_json_object_keys.groovy
@@ -0,0 +1,100 @@
+// 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.
+
+
+suite("test_json_sort_json_object_keys") {
+ qt_sql """
+ select sort_json_object_keys(cast('{"b":123,"b":456,"a":789}' as
json)) , sort_jsonb_object_keys(cast('{"b":123,"b":456,"a":789}' as json));
+ """
+
+
+ qt_sql """
+ select sort_json_object_keys(cast('[{"b":123,"b":456,"a":789}
,{"b":123},{"b":456},{"a":789} ]' as json));
+ """
+
+ sql "DROP TABLE IF EXISTS test_json_sort_json_object_keys_table"
+
+ sql """
+ CREATE TABLE IF NOT EXISTS test_json_sort_json_object_keys_table (
+ id INT,
+ j JSON
+ )
+ DISTRIBUTED BY HASH(id) BUCKETS 3
+ PROPERTIES (
+ "replication_num" = "1"
+ )
+ """
+
+ sql """
+ INSERT INTO test_json_sort_json_object_keys_table VALUES
+ (1, '{"b":123,"b":456,"a":789}'),
+ (2, '{"d":123,"c":456,"b":789,"a":1011}'),
+ (3, '{"x":123,"y":456,"z":789}'),
+ (4, '[{"b":123,"b":456,"a":789} ,{"b":123},{"b":456},{"a":789}]'),
+ (5, null),
+ (6,
'{"Data":[{"a_1":"value1","B2":{"zZ":123,"A_1":"value2","b2":"should_sort_last","b2":"should_sort_first","__key__":[{"dupKey":"first","Dupkey":"second","dupKey":"third","1dupKey":"fourth"},{"mix_key":"foo","Mix_Key":"bar","mix_key":"baz"}]},"B2":"anotherB2","b2":"duplicateB2","A_1":"anotherA_1"},{"b2":[{"k":1,"K":2,"k":3},{"b2":"array_dup","B2":"array_B2"}],"randomKey_3":{"foo":"test","Foo":"TEST","foo":"again"}}],"meta_9":{"info":"example","Info":"EXAMPLE","info":"duplicate"}}')
+ """
+
+ qt_sql """
+ SELECT id, sort_json_object_keys(j) as sorted_json
+ FROM test_json_sort_json_object_keys_table
+ ORDER BY id
+ """
+
+ qt_sql """
+ SELECT id, sort_jsonb_object_keys(cast(j as jsonb)) as sorted_jsonb
+ FROM test_json_sort_json_object_keys_table
+ ORDER BY id
+ """
+
+
+
+ sql "DROP TABLE IF EXISTS test_json_sort_json_object_keys_table"
+
+ sql """
+ CREATE TABLE IF NOT EXISTS test_json_sort_json_object_keys_table (
+ id INT,
+ j JSON NOT NULL
+ )
+ DISTRIBUTED BY HASH(id) BUCKETS 3
+ PROPERTIES (
+ "replication_num" = "1"
+ )
+ """
+
+ sql """
+ INSERT INTO test_json_sort_json_object_keys_table VALUES
+ (1, '{"b":123,"b":456,"a":789}'),
+ (2, '{"d":123,"c":456,"b":789,"a":1011}'),
+ (3, '{"x":123,"y":456,"z":789}'),
+ (4, '[{"b":123,"b":456,"a":789} ,{"b":123},{"b":456},{"a":789}]'),
+ (6,
'{"Data":[{"a_1":"value1","B2":{"zZ":123,"A_1":"value2","b2":"should_sort_last","b2":"should_sort_first","__key__":[{"dupKey":"first","Dupkey":"second","dupKey":"third","1dupKey":"fourth"},{"mix_key":"foo","Mix_Key":"bar","mix_key":"baz"}]},"B2":"anotherB2","b2":"duplicateB2","A_1":"anotherA_1"},{"b2":[{"k":1,"K":2,"k":3},{"b2":"array_dup","B2":"array_B2"}],"randomKey_3":{"foo":"test","Foo":"TEST","foo":"again"}}],"meta_9":{"info":"example","Info":"EXAMPLE","info":"duplicate"}}')
+ """
+
+ qt_sql """
+ SELECT id, sort_json_object_keys(j) as sorted_json
+ FROM test_json_sort_json_object_keys_table
+ ORDER BY id
+ """
+
+ qt_sql """
+ SELECT id, sort_jsonb_object_keys(cast(j as jsonb)) as sorted_jsonb
+ FROM test_json_sort_json_object_keys_table
+ ORDER BY id
+ """
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]