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 <[email protected]>
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.