This is an automated email from the ASF dual-hosted git repository. hongze pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push: new 5101703 [CALCITE-2791] Add the JSON_TYPE function (xuqianjin) 5101703 is described below commit 5101703c3bb7e051766f9dc932534a0a7acba0c5 Author: xuqianjin <x1q...@163.com> AuthorDate: Sat Feb 23 00:44:49 2019 +0800 [CALCITE-2791] Add the JSON_TYPE function (xuqianjin) Close apache/calcite#1013 --- babel/src/main/codegen/config.fmpp | 1 + core/src/main/codegen/config.fmpp | 1 + core/src/main/codegen/templates/Parser.jj | 19 ++++++ .../calcite/adapter/enumerable/RexImpTable.java | 2 + .../apache/calcite/runtime/CalciteResource.java | 3 + .../org/apache/calcite/runtime/SqlFunctions.java | 36 +++++++++++ .../calcite/sql/fun/SqlJsonTypeFunction.java | 69 ++++++++++++++++++++++ .../calcite/sql/fun/SqlStdOperatorTable.java | 2 + .../org/apache/calcite/util/BuiltInMethod.java | 1 + .../calcite/runtime/CalciteResource.properties | 1 + core/src/test/codegen/config.fmpp | 1 + .../calcite/rel/rel2sql/RelToSqlConverterTest.java | 8 +++ .../apache/calcite/sql/parser/SqlParserTest.java | 10 ++++ .../calcite/sql/test/SqlOperatorBaseTest.java | 24 ++++++++ .../java/org/apache/calcite/test/JdbcTest.java | 12 ++++ .../apache/calcite/test/SqlJsonFunctionsTest.java | 23 +++++++- .../org/apache/calcite/test/SqlValidatorTest.java | 8 +++ server/src/main/codegen/config.fmpp | 1 + site/_docs/reference.md | 24 ++++++++ 19 files changed, 245 insertions(+), 1 deletion(-) diff --git a/babel/src/main/codegen/config.fmpp b/babel/src/main/codegen/config.fmpp index 2fa6061..f8f4a0b 100644 --- a/babel/src/main/codegen/config.fmpp +++ b/babel/src/main/codegen/config.fmpp @@ -139,6 +139,7 @@ data: { "ISOLATION" "JAVA" "JSON" + "JSON_TYPE" "K" "KEY" "KEY_MEMBER" diff --git a/core/src/main/codegen/config.fmpp b/core/src/main/codegen/config.fmpp index d7d5066..4021ab1 100644 --- a/core/src/main/codegen/config.fmpp +++ b/core/src/main/codegen/config.fmpp @@ -159,6 +159,7 @@ data: { "ISOLATION" "JAVA" "JSON" + "JSON_TYPE" "K" "KEY" "KEY_MEMBER" diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj index 6cecc56..a546495 100644 --- a/core/src/main/codegen/templates/Parser.jj +++ b/core/src/main/codegen/templates/Parser.jj @@ -4827,6 +4827,8 @@ SqlNode BuiltinFunctionCall() : | node = JsonObjectFunctionCall() { return node; } | + node = JsonTypeFunctionCall() { return node; } + | node = JsonObjectAggFunctionCall() { return node; } | node = JsonArrayFunctionCall() { return node; } @@ -5246,6 +5248,22 @@ SqlCall JsonObjectFunctionCall() : } } +SqlCall JsonTypeFunctionCall() : +{ + final SqlNode[] args = new SqlNode[1]; + SqlNode e; + final Span span; +} +{ + <JSON_TYPE> { span = span(); } + <LPAREN> e = JsonValueExpression(true) { + args[0] = e; + } + <RPAREN> { + return SqlStdOperatorTable.JSON_TYPE.createCall(span.end(this), args); + } +} + SqlCall JsonObjectAggFunctionCall() : { final SqlNode[] args = new SqlNode[2]; @@ -6274,6 +6292,7 @@ SqlPostfixOperator PostfixRowOperator() : | < JSON_EXISTS: "JSON_EXISTS" > | < JSON_VALUE: "JSON_VALUE" > | < JSON_OBJECT: "JSON_OBJECT"> +| < JSON_TYPE: "JSON_TYPE"> | < JSON_OBJECTAGG: "JSON_OBJECTAGG"> | < JSON_QUERY: "JSON_QUERY" > | < K: "K" > diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java index 910bebe..6059d5e 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java @@ -167,6 +167,7 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.JSON_OBJECT; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.JSON_OBJECTAGG; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.JSON_QUERY; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.JSON_STRUCTURED_VALUE_EXPRESSION; +import static org.apache.calcite.sql.fun.SqlStdOperatorTable.JSON_TYPE; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.JSON_VALUE_ANY; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.JSON_VALUE_EXPRESSION; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LAG; @@ -450,6 +451,7 @@ public class RexImpTable { defineMethod(JSON_VALUE_ANY, BuiltInMethod.JSON_VALUE_ANY.method, NullPolicy.NONE); defineMethod(JSON_QUERY, BuiltInMethod.JSON_QUERY.method, NullPolicy.NONE); defineMethod(JSON_OBJECT, BuiltInMethod.JSON_OBJECT.method, NullPolicy.NONE); + defineMethod(JSON_TYPE, BuiltInMethod.JSON_TYPE.method, NullPolicy.NONE); aggMap.put(JSON_OBJECTAGG, JsonObjectAggImplementor .supplierFor(BuiltInMethod.JSON_OBJECTAGG_ADD.method)); diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java index 4142f67..6ae9bea 100644 --- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java +++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java @@ -852,6 +852,9 @@ public interface CalciteResource { @BaseMessage("While executing SQL [{0}] on JDBC sub-schema") ExInst<RuntimeException> exceptionWhilePerformingQueryOnJdbcSubSchema(String sql); + + @BaseMessage("Unknown JSON type in JSON_TYPE function, and the object is: ''{0}''") + ExInst<CalciteException> unknownObjectOfJsonType(String value); } // End CalciteResource.java diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java index bb1b335..6f17efd 100644 --- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java +++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java @@ -2676,6 +2676,42 @@ public class SqlFunctions { } } + public static String jsonType(Object o) { + final String result; + try { + if (o instanceof Integer) { + result = "INTEGER"; + } else if (o instanceof String) { + result = "STRING"; + } else if (o instanceof Float) { + result = "FLOAT"; + } else if (o instanceof Double) { + result = "DOUBLE"; + } else if (o instanceof Long) { + result = "LONG"; + } else if (o instanceof Boolean) { + result = "BOOLEAN"; + } else if (o instanceof Date) { + result = "DATE"; + } else if (o instanceof Map) { + result = "OBJECT"; + } else if (o instanceof Collection) { + result = "ARRAY"; + } else if (o == null) { + result = "NULL"; + } else { + result = "unknown"; + } + if (result.equals("unknown")) { + throw RESOURCE.unknownObjectOfJsonType(o.toString()).ex(); + } else { + return result; + } + } catch (Exception ex) { + throw RESOURCE.unknownObjectOfJsonType(o.toString()).ex(); + } + } + public static boolean isJsonValue(String input) { try { dejsonize(input); diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonTypeFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonTypeFunction.java new file mode 100644 index 0000000..8ab3125 --- /dev/null +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonTypeFunction.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.calcite.sql.fun; + +import org.apache.calcite.sql.SqlCall; +import org.apache.calcite.sql.SqlFunction; +import org.apache.calcite.sql.SqlFunctionCategory; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.sql.SqlLiteral; +import org.apache.calcite.sql.SqlNode; +import org.apache.calcite.sql.SqlOperandCountRange; +import org.apache.calcite.sql.SqlWriter; +import org.apache.calcite.sql.parser.SqlParserPos; +import org.apache.calcite.sql.type.OperandTypes; +import org.apache.calcite.sql.type.ReturnTypes; +import org.apache.calcite.sql.type.SqlOperandCountRanges; +import org.apache.calcite.sql.type.SqlOperandTypeChecker; +import org.apache.calcite.sql.type.SqlTypeName; +import org.apache.calcite.sql.validate.SqlValidator; + + +/** + * The <code>JSON_TYPE</code> function. + */ +public class SqlJsonTypeFunction extends SqlFunction { + public SqlJsonTypeFunction() { + super("JSON_TYPE", + SqlKind.OTHER_FUNCTION, + ReturnTypes.explicit(SqlTypeName.VARCHAR, 20), + null, + OperandTypes.ANY, + SqlFunctionCategory.SYSTEM); + } + + @Override public SqlOperandCountRange getOperandCountRange() { + return SqlOperandCountRanges.of(1); + } + + @Override protected void checkOperandCount(SqlValidator validator, + SqlOperandTypeChecker argType, SqlCall call) { + assert call.operandCount() == 1; + } + + @Override public SqlCall createCall(SqlLiteral functionQualifier, + SqlParserPos pos, SqlNode... operands) { + return super.createCall(functionQualifier, pos, operands); + } + + @Override public void unparse(SqlWriter writer, SqlCall call, int leftPrec, + int rightPrec) { + super.unparse(writer, call, 0, 0); + } +} + +// End SqlJsonTypeFunction.java diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java index 7ca82ec..3990012 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java @@ -1303,6 +1303,8 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable { public static final SqlFunction JSON_OBJECT = new SqlJsonObjectFunction(); + public static final SqlFunction JSON_TYPE = new SqlJsonTypeFunction(); + public static final SqlJsonObjectAggAggFunction JSON_OBJECTAGG = new SqlJsonObjectAggAggFunction("JSON_OBJECTAGG", SqlJsonConstructorNullClause.NULL_ON_NULL); diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java index 97b47dc..5e2c06f 100644 --- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java +++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java @@ -282,6 +282,7 @@ public enum BuiltInMethod { SqlJsonQueryEmptyOrErrorBehavior.class), JSON_OBJECT(SqlFunctions.class, "jsonObject", SqlJsonConstructorNullClause.class), + JSON_TYPE(SqlFunctions.class, "jsonType", Object.class), JSON_OBJECTAGG_ADD(SqlFunctions.class, "jsonObjectAggAdd", Map.class, String.class, Object.class, SqlJsonConstructorNullClause.class), JSON_ARRAY(SqlFunctions.class, "jsonArray", diff --git a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties index a717d16..9202536 100644 --- a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties +++ b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties @@ -277,4 +277,5 @@ IllegalErrorBehaviorInJsonQueryFunc=Illegal error behavior ''{0}'' specified in NullKeyOfJsonObjectNotAllowed=Null key of JSON object is not allowed QueryExecutionTimeoutReached=Timeout of ''{0}'' ms for query execution is reached. Query execution started at ''{1}'' ExceptionWhilePerformingQueryOnJdbcSubSchema = While executing SQL [{0}] on JDBC sub-schema +UnknownObjectOfJsonType=Unknown JSON type in JSON_TYPE function, and the object is: ''{0}'' # End CalciteResource.properties diff --git a/core/src/test/codegen/config.fmpp b/core/src/test/codegen/config.fmpp index db3518b..991914e 100644 --- a/core/src/test/codegen/config.fmpp +++ b/core/src/test/codegen/config.fmpp @@ -143,6 +143,7 @@ data: { "ISOLATION" "JAVA" "JSON" + "JSON_TYPE" "K" "KEY" "KEY_MEMBER" diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java index 0932f37..4a9e20b 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java @@ -3054,6 +3054,14 @@ public class RelToSqlConverterTest { sql(query).withSpark().ok(expected); } + @Test public void testJsonType() { + String query = "select json_type(\"product_name\") from \"product\""; + final String expected = "SELECT " + + "JSON_TYPE(\"product_name\" FORMAT JSON)\n" + + "FROM \"foodmart\".\"product\""; + sql(query).ok(expected); + } + /** Fluid interface to run tests. */ static class Sql { private final SchemaPlus schema; diff --git a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java index 421cca5..83d4b8d 100644 --- a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java +++ b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java @@ -8379,6 +8379,16 @@ public class SqlParserTest { + "FORMAT JSON NULL ON NULL)"); } + @Test public void testJsonType() { + checkExp("json_type('11.56')", "JSON_TYPE('11.56' FORMAT JSON)"); + checkExp("json_type('{}')", "JSON_TYPE('{}' FORMAT JSON)"); + checkExp("json_type(null)", "JSON_TYPE(NULL FORMAT JSON)"); + checkExp("json_type('[\"foo\",null]')", + "JSON_TYPE('[\"foo\",null]' FORMAT JSON)"); + checkExp("json_type('{\"foo\": \"100\"}')", + "JSON_TYPE('{\"foo\": \"100\"}' FORMAT JSON)"); + } + @Test public void testJsonObjectAgg() { checkExp("json_objectagg(k_column: v_column)", "JSON_OBJECTAGG(KEY `K_COLUMN` VALUE `V_COLUMN` NULL ON NULL)"); diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java index dbba71c..46b78f1 100644 --- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java +++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java @@ -4473,6 +4473,30 @@ public abstract class SqlOperatorBaseTest { "{\"foo\":{\"foo\":\"bar\"}}", "VARCHAR(2000) NOT NULL"); } + @Test public void testJsonType() { + tester.setFor(SqlStdOperatorTable.JSON_TYPE); + tester.checkString("json_type('\"1\"')", + "STRING", "VARCHAR(20) NOT NULL"); + tester.checkString("json_type('1')", + "INTEGER", "VARCHAR(20) NOT NULL"); + tester.checkString("json_type('11.45')", + "DOUBLE", "VARCHAR(20) NOT NULL"); + tester.checkString("json_type('true')", + "BOOLEAN", "VARCHAR(20) NOT NULL"); + tester.checkString("json_type('null')", + "NULL", "VARCHAR(20) NOT NULL"); + tester.checkString("json_type(cast(null as varchar(1)))", + "NULL", "VARCHAR(20) NOT NULL"); + tester.checkString("json_type('{\"a\": [10, true]}')", + "OBJECT", "VARCHAR(20) NOT NULL"); + tester.checkString("json_type('{}')", + "OBJECT", "VARCHAR(20) NOT NULL"); + tester.checkString("json_type('[10, true]')", + "ARRAY", "VARCHAR(20) NOT NULL"); + tester.checkString("json_type('\"2019-01-27 21:24:00\"')", + "STRING", "VARCHAR(20) NOT NULL"); + } + @Test public void testJsonObjectAgg() { checkAggType(tester, "json_objectagg('foo': 'bar')", "VARCHAR(2000) NOT NULL"); tester.checkFails("^json_objectagg(100: 'bar')^", diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java index 01ad5d5..3674078 100644 --- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java +++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java @@ -6748,6 +6748,18 @@ public class JdbcTest { .returns("EXPR$0=[250, 500, 1000]\n"); } + @Ignore + @Test public void testJsonType() { + CalciteAssert.that() + .query("SELECT JSON_TYPE(v) AS c1\n" + + ",JSON_TYPE(JSON_VALUE(v, 'lax $.b' ERROR ON ERROR)) AS c2\n" + + ",JSON_TYPE(JSON_VALUE(v, 'strict $.a[0]' ERROR ON ERROR)) AS c3\n" + + ",JSON_TYPE(JSON_VALUE(v, 'strict $.a[1]' ERROR ON ERROR)) AS c4\n" + + "FROM (VALUES ('{\"a\": [10, true],\"b\": \"[10, true]\"}')) AS t(v)\n" + + "limit 10") + .returns("C1=OBJECT; C2=ARRAY; C3=INTEGER; C4=BOOLEAN\n"); + } + /** * Test case for * <a href="https://issues.apache.org/jira/browse/CALCITE-2609">[CALCITE-2609] diff --git a/core/src/test/java/org/apache/calcite/test/SqlJsonFunctionsTest.java b/core/src/test/java/org/apache/calcite/test/SqlJsonFunctionsTest.java index 3f3c57d..311f2c8 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlJsonFunctionsTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlJsonFunctionsTest.java @@ -65,6 +65,7 @@ public class SqlJsonFunctionsTest { public static final String INVOC_DESC_JSONIZE = "jsonize"; public static final String INVOC_DESC_DEJSONIZE = "dejsonize"; public static final String INVOC_DESC_JSON_OBJECT = "jsonObject"; + public static final String INVOC_DESC_JSON_TYPE = "jsonType"; public static final String INVOC_DESC_JSON_OBJECT_AGG_ADD = "jsonObjectAggAdd"; public static final String INVOC_DESC_JSON_ARRAY = "jsonArray"; @@ -476,6 +477,17 @@ public class SqlJsonFunctionsTest { } @Test + public void testJsonType() { + assertJsonType(is("OBJECT"), "{}"); + assertJsonType(is("ARRAY"), + "[\"foo\",null]"); + assertJsonType(is("NULL"), "null"); + assertJsonType(is("BOOLEAN"), "false"); + assertJsonType(is("INTEGER"), "12"); + assertJsonType(is("DOUBLE"), "11.22"); + } + + @Test public void testJsonObjectAggAdd() { Map<String, Object> map = new HashMap<>(); Map<String, Object> expected = new HashMap<>(); @@ -637,7 +649,7 @@ public class SqlJsonFunctionsTest { private void assertDejsonize(String input, Matcher<Object> matcher) { assertThat(invocationDesc(INVOC_DESC_DEJSONIZE, input), - SqlFunctions.dejsonize(input), + SqlFunctions.dejsonize(input), matcher); } @@ -656,6 +668,15 @@ public class SqlJsonFunctionsTest { matcher); } + private void assertJsonType(Matcher<? super String> matcher, + String input) { + assertThat( + invocationDesc(INVOC_DESC_JSON_TYPE, input), + SqlFunctions.jsonType( + SqlFunctions.dejsonize(input)), + matcher); + } + private void assertJsonObjectAggAdd(Map map, String k, Object v, SqlJsonConstructorNullClause nullClause, Matcher<? super Map> matcher) { diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java index 9c55b1f..882ab4b 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java @@ -10769,6 +10769,14 @@ public class SqlValidatorTest extends SqlValidatorTestCase { "(?s).*Expected a character type*"); } + @Test public void testJsonType() { + check("select json_type(ename) from emp"); + checkExp("json_type('{\"foo\":\"bar\"}')"); + checkExpType("json_type('{\"foo\":\"bar\"}')", "VARCHAR(20) NOT NULL"); + checkFails("select json_type(^1^) from emp", + "(.*)JSON_VALUE_EXPRESSION(.*)"); + } + @Test public void testJsonObjectAgg() { check("select json_objectagg(ename: empno) from emp"); checkFails("select ^json_objectagg(empno: ename)^ from emp", diff --git a/server/src/main/codegen/config.fmpp b/server/src/main/codegen/config.fmpp index 30c3031..d4d7243 100644 --- a/server/src/main/codegen/config.fmpp +++ b/server/src/main/codegen/config.fmpp @@ -151,6 +151,7 @@ data: { "ISOLATION" "JAVA" "JSON" + "JSON_TYPE" "K" "KEY" "KEY_MEMBER" diff --git a/site/_docs/reference.md b/site/_docs/reference.md index 3e0b78f..d429ac3 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -567,6 +567,7 @@ JSON, **JSON_OBJECT**, **JSON_OBJECTAGG**, **JSON_QUERY**, +JSON_TYPE, **JSON_VALUE**, K, KEY, @@ -1994,6 +1995,29 @@ Note: | value IS JSON ARRAY | Whether *value* is a json array, *value* is in character string type | value IS NOT JSON ARRAY | Whether *value* is not a json array, *value* is in character string type +#### MySQL Specific Operators + +| Operator syntax | Description +|:------------------------------------------------- |:----------- +| JSON_TYPE(value) | Returns a string indicating the type of a JSON **value**. This can be an object, an array, or a scalar type + +Example SQL: + +```SQL +SELECT JSON_TYPE(v) AS c1 +,JSON_TYPE(JSON_VALUE(v, 'lax $.b' ERROR ON ERROR)) AS c2 +,JSON_TYPE(JSON_VALUE(v, 'strict $.a[0]' ERROR ON ERROR)) AS c3 +,JSON_TYPE(JSON_VALUE(v, 'strict $.a[1]' ERROR ON ERROR)) AS c4 +FROM (VALUES ('{"a": [10, true],"b": "[10, true]"}')) AS t(v) +LIMIT 10; +``` + +Result: + +| c1 | c2 | c3 | c4 | +| ------ | ----- | ------- | ------- | +| OBJECT | ARRAY | INTEGER | BOOLEAN | + ## User-defined functions Calcite is extensible. You can define each kind of function using user code.