This is an automated email from the ASF dual-hosted git repository.
mmior 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 4954216 [CALCITE-3177]Ensure correct deserialization of relational
algebra.
4954216 is described below
commit 4954216c71a6262728ad6ed4792d4ac7b9ec7b71
Author: yanzhi <[email protected]>
AuthorDate: Thu Jul 25 10:03:43 2019 +0800
[CALCITE-3177]Ensure correct deserialization of relational algebra.
---
.../apache/calcite/rel/externalize/RelJson.java | 45 ++++++++----
.../calcite/rel/externalize/RelJsonReader.java | 4 +-
.../org/apache/calcite/plan/RelWriterTest.java | 80 +++++++++++++++++++---
3 files changed, 105 insertions(+), 24 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java
b/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java
index 169ecb0..c7fe76f 100644
--- a/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java
+++ b/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java
@@ -46,12 +46,15 @@ import org.apache.calcite.rex.RexWindow;
import org.apache.calcite.rex.RexWindowBound;
import org.apache.calcite.sql.SqlAggFunction;
import org.apache.calcite.sql.SqlFunction;
+import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.SqlSyntax;
import org.apache.calcite.sql.SqlWindow;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.validate.SqlNameMatchers;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.JsonBuilder;
import org.apache.calcite.util.Util;
@@ -434,15 +437,16 @@ public class RelJson {
return null;
} else if (o instanceof Map) {
Map map = (Map) o;
- final String op = (String) map.get("op");
+ final Map<String, Object> opMap = (Map) map.get("op");
final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
- if (op != null) {
+ if (opMap != null) {
+ final String op = (String) opMap.get("name");
final List operands = (List) map.get("operands");
final List<RexNode> rexOperands = toRexList(relInput, operands);
final Object jsonType = map.get("type");
final Map window = (Map) map.get("window");
if (window != null) {
- final SqlAggFunction operator = toAggregation(relInput, op, map);
+ final SqlAggFunction operator = toAggregation(relInput, op, opMap);
final RelDataType type = toType(typeFactory, jsonType);
final List<RexNode> partitionKeys = toRexList(relInput, (List)
window.get("partition"));
final List<RexFieldCollation> orderKeys =
@@ -469,7 +473,7 @@ public class RelJson {
ImmutableList.copyOf(orderKeys), lowerBound, upperBound,
physical,
true, false, distinct, false);
} else {
- final SqlOperator operator = toOp(relInput, op, map);
+ final SqlOperator operator = toOp(relInput, opMap);
final RelDataType type;
if (jsonType != null) {
type = toType(typeFactory, jsonType);
@@ -603,13 +607,22 @@ public class RelJson {
return list;
}
- SqlOperator toOp(RelInput relInput, String op, Map<String, Object> map) {
- // TODO: build a map, for more efficient lookup
- // TODO: look up based on SqlKind
- final List<SqlOperator> operatorList =
- SqlStdOperatorTable.instance().getOperatorList();
- for (SqlOperator operator : operatorList) {
- if (operator.getName().equals(op)) {
+ SqlOperator toOp(RelInput relInput, Map<String, Object> map) {
+ // in case different operator has the same kind, check with both name and
kind.
+ String name = map.get("name").toString();
+ String kind = map.get("kind").toString();
+ String syntax = map.get("syntax").toString();
+ SqlKind sqlKind = SqlKind.valueOf(kind);
+ SqlSyntax sqlSyntax = SqlSyntax.valueOf(syntax);
+ List<SqlOperator> operators = new ArrayList<>();
+ SqlStdOperatorTable.instance().lookupOperatorOverloads(
+ new SqlIdentifier(name, new SqlParserPos(0, 0)),
+ null,
+ sqlSyntax,
+ operators,
+ SqlNameMatchers.liberal());
+ for (SqlOperator operator: operators) {
+ if (operator.kind == sqlKind) {
return operator;
}
}
@@ -621,12 +634,16 @@ public class RelJson {
}
SqlAggFunction toAggregation(RelInput relInput, String agg, Map<String,
Object> map) {
- return (SqlAggFunction) toOp(relInput, agg, map);
+ return (SqlAggFunction) toOp(relInput, map);
}
- private String toJson(SqlOperator operator) {
+ private Map toJson(SqlOperator operator) {
// User-defined operators are not yet handled.
- return operator.getName();
+ Map map = jsonBuilder.map();
+ map.put("name", operator.getName());
+ map.put("kind", operator.kind.toString());
+ map.put("syntax", operator.getSyntax().toString());
+ return map;
}
}
diff --git
a/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
b/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
index b7d7e8a..e7a73a8 100644
--- a/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
+++ b/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
@@ -273,9 +273,9 @@ public class RelJsonReader {
}
private AggregateCall toAggCall(RelInput relInput, Map<String, Object>
jsonAggCall) {
- final String aggName = (String) jsonAggCall.get("agg");
+ final Map<String, Object> aggMap = (Map) jsonAggCall.get("agg");
final SqlAggFunction aggregation =
- relJson.toAggregation(relInput, aggName, jsonAggCall);
+ relJson.toAggregation(relInput, (String) aggMap.get("name"), aggMap);
final Boolean distinct = (Boolean) jsonAggCall.get("distinct");
@SuppressWarnings("unchecked")
final List<Integer> operands = (List<Integer>) jsonAggCall.get("operands");
diff --git a/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java
b/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java
index 4734413..0e74702 100644
--- a/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java
+++ b/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java
@@ -82,7 +82,11 @@ public class RelWriterTest {
+ " \"id\": \"1\",\n"
+ " \"relOp\": \"LogicalFilter\",\n"
+ " \"condition\": {\n"
- + " \"op\": \"=\",\n"
+ + " \"op\": {\n"
+ + " \"name\": \"=\",\n"
+ + " \"kind\": \"EQUALS\",\n"
+ + " \"syntax\": \"BINARY\"\n"
+ + " },\n"
+ " \"operands\": [\n"
+ " {\n"
+ " \"input\": 1,\n"
@@ -106,7 +110,11 @@ public class RelWriterTest {
+ " ],\n"
+ " \"aggs\": [\n"
+ " {\n"
- + " \"agg\": \"COUNT\",\n"
+ + " \"agg\": {\n"
+ + " \"name\": \"COUNT\",\n"
+ + " \"kind\": \"COUNT\",\n"
+ + " \"syntax\": \"FUNCTION_STAR\"\n"
+ + " },\n"
+ " \"type\": {\n"
+ " \"type\": \"BIGINT\",\n"
+ " \"nullable\": false\n"
@@ -117,7 +125,11 @@ public class RelWriterTest {
+ " ]\n"
+ " },\n"
+ " {\n"
- + " \"agg\": \"COUNT\",\n"
+ + " \"agg\": {\n"
+ + " \"name\": \"COUNT\",\n"
+ + " \"kind\": \"COUNT\",\n"
+ + " \"syntax\": \"FUNCTION_STAR\"\n"
+ + " },\n"
+ " \"type\": {\n"
+ " \"type\": \"BIGINT\",\n"
+ " \"nullable\": false\n"
@@ -145,7 +157,11 @@ public class RelWriterTest {
+ " \"id\": \"1\",\n"
+ " \"relOp\": \"LogicalFilter\",\n"
+ " \"condition\": {\n"
- + " \"op\": \"=\",\n"
+ + " \"op\": {"
+ + " \"name\": \"=\",\n"
+ + " \"kind\": \"EQUALS\",\n"
+ + " \"syntax\": \"BINARY\"\n"
+ + " },\n"
+ " \"operands\": [\n"
+ " {\n"
+ " \"input\": 1,\n"
@@ -166,7 +182,11 @@ public class RelWriterTest {
+ " ],\n"
+ " \"aggs\": [\n"
+ " {\n"
- + " \"agg\": \"COUNT\",\n"
+ + " \"agg\": {\n"
+ + " \"name\": \"COUNT\",\n"
+ + " \"kind\": \"COUNT\",\n"
+ + " \"syntax\": \"FUNCTION_STAR\"\n"
+ + " },\n"
+ " \"type\": {\n"
+ " \"type\": \"BIGINT\",\n"
+ " \"nullable\": false\n"
@@ -177,7 +197,11 @@ public class RelWriterTest {
+ " ]\n"
+ " },\n"
+ " {\n"
- + " \"agg\": \"COUNT\",\n"
+ + " \"agg\": {\n"
+ + " \"name\": \"COUNT\",\n"
+ + " \"kind\": \"COUNT\",\n"
+ + " \"syntax\": \"FUNCTION_STAR\"\n"
+ + " },\n"
+ " \"type\": {\n"
+ " \"type\": \"BIGINT\",\n"
+ " \"nullable\": false\n"
@@ -215,7 +239,11 @@ public class RelWriterTest {
+ " \"name\": \"$0\"\n"
+ " },\n"
+ " {\n"
- + " \"op\": \"COUNT\",\n"
+ + " \"op\": {\n"
+ + " \"name\": \"COUNT\",\n"
+ + " \"kind\": \"COUNT\",\n"
+ + " \"syntax\": \"FUNCTION_STAR\"\n"
+ + " },\n"
+ " \"operands\": [\n"
+ " {\n"
+ " \"input\": 0,\n"
@@ -253,7 +281,11 @@ public class RelWriterTest {
+ " }\n"
+ " },\n"
+ " {\n"
- + " \"op\": \"SUM\",\n"
+ + " \"op\": {\n"
+ + " \"name\": \"SUM\",\n"
+ + " \"kind\": \"SUM\",\n"
+ + " \"syntax\": \"FUNCTION\"\n"
+ + " },\n"
+ " \"operands\": [\n"
+ " {\n"
+ " \"input\": 0,\n"
@@ -517,6 +549,38 @@ public class RelWriterTest {
assertThat(s, isLinux(expected));
}
+ @Test public void testPlusOperator() {
+ final FrameworkConfig config = RelBuilderTest.config().build();
+ final RelBuilder builder = RelBuilder.create(config);
+ final RelNode rel = builder
+ .scan("EMP")
+ .project(
+ builder.call(SqlStdOperatorTable.PLUS,
+ builder.field("SAL"),
+ builder.literal(10)))
+ .build();
+ RelJsonWriter jsonWriter = new RelJsonWriter();
+ rel.explain(jsonWriter);
+ String relJson = jsonWriter.asString();
+ String s =
+ Frameworks.withPlanner((cluster, relOptSchema, rootSchema) -> {
+ final RelJsonReader reader = new RelJsonReader(
+ cluster, getSchema(rel), rootSchema);
+ RelNode node;
+ try {
+ node = reader.read(relJson);
+ } catch (IOException e) {
+ throw TestUtil.rethrow(e);
+ }
+ return RelOptUtil.dumpPlan("", node, SqlExplainFormat.TEXT,
+ SqlExplainLevel.EXPPLAN_ATTRIBUTES);
+ });
+ final String expected = ""
+ + "LogicalProject($f0=[+($5, 10)])\n"
+ + " LogicalTableScan(table=[[scott, EMP]])\n";
+ assertThat(s, isLinux(expected));
+ }
+
/** Returns the schema of a {@link org.apache.calcite.rel.core.TableScan}
* in this plan, or null if there are no scans. */
private RelOptSchema getSchema(RelNode rel) {