17 package org.apache.calcite.rel.externalize;
19 import com.fasterxml.jackson.databind.type.TypeFactory;
20 import com.google.common.collect.ImmutableList;
23 import org.apache.calcite.avatica.AvaticaUtils;
24 import org.apache.calcite.avatica.util.TimeUnitRange;
25 import org.apache.calcite.plan.RelOptCluster;
26 import org.apache.calcite.plan.RelTraitSet;
27 import org.apache.calcite.rel.RelCollation;
28 import org.apache.calcite.rel.RelCollationImpl;
29 import org.apache.calcite.rel.RelCollations;
30 import org.apache.calcite.rel.RelDistribution;
31 import org.apache.calcite.rel.RelDistributions;
32 import org.apache.calcite.rel.RelFieldCollation;
33 import org.apache.calcite.rel.RelInput;
34 import org.apache.calcite.rel.RelNode;
35 import org.apache.calcite.rel.core.AggregateCall;
36 import org.apache.calcite.rel.core.CorrelationId;
37 import org.apache.calcite.rel.core.TableModify.Operation;
38 import org.apache.calcite.rel.type.RelDataType;
39 import org.apache.calcite.rel.type.RelDataTypeFactory;
40 import org.apache.calcite.rel.type.RelDataTypeField;
41 import org.apache.calcite.rex.RexBuilder;
42 import org.apache.calcite.rex.RexCall;
43 import org.apache.calcite.rex.RexCorrelVariable;
44 import org.apache.calcite.rex.RexFieldAccess;
45 import org.apache.calcite.rex.RexFieldCollation;
46 import org.apache.calcite.rex.RexInputRef;
47 import org.apache.calcite.rex.RexLiteral;
48 import org.apache.calcite.rex.RexNode;
49 import org.apache.calcite.rex.RexOver;
50 import org.apache.calcite.rex.RexSubQuery;
51 import org.apache.calcite.rex.RexWindow;
52 import org.apache.calcite.rex.RexWindowBound;
54 import org.apache.calcite.sql.SqlAggFunction;
55 import org.apache.calcite.sql.SqlFunction;
56 import org.apache.calcite.sql.SqlIdentifier;
57 import org.apache.calcite.sql.SqlKind;
59 import org.apache.calcite.sql.SqlOperatorTable;
60 import org.apache.calcite.sql.SqlSyntax;
61 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
62 import org.apache.calcite.sql.fun.SqlTrimFunction;
63 import org.apache.calcite.sql.type.SqlTypeName;
64 import org.apache.calcite.util.ImmutableBitSet;
65 import org.apache.calcite.util.JsonBuilder;
66 import org.apache.calcite.util.Util;
68 import java.lang.reflect.Constructor;
69 import java.lang.reflect.InvocationTargetException;
70 import java.math.BigDecimal;
71 import java.util.ArrayList;
72 import java.util.HashMap;
73 import java.util.List;
82 new HashMap<String, Constructor>();
85 public static final List<String>
PACKAGES = ImmutableList.of(
"org.apache.calcite.rel.",
86 "org.apache.calcite.rel.core.",
87 "org.apache.calcite.rel.logical.",
88 "org.apache.calcite.adapter.jdbc.",
89 "org.apache.calcite.adapter.enumerable.",
90 "org.apache.calcite.adapter.jdbc.JdbcRules$");
96 public RelNode
create(Map<String, Object> map) {
97 String
type = (String) map.get(
"type");
100 return (RelNode) constructor.newInstance(map);
101 }
catch (InstantiationException e) {
102 throw new RuntimeException(
"while invoking constructor for type '" + type +
"'", e);
103 }
catch (IllegalAccessException e) {
104 throw new RuntimeException(
"while invoking constructor for type '" + type +
"'", e);
105 }
catch (InvocationTargetException e) {
106 throw new RuntimeException(
"while invoking constructor for type '" + type +
"'", e);
107 }
catch (ClassCastException e) {
108 throw new RuntimeException(
"while invoking constructor for type '" + type +
"'", e);
113 Constructor constructor = constructorMap.get(
type);
114 if (constructor == null) {
118 constructor = clazz.getConstructor(RelInput.class);
119 }
catch (NoSuchMethodException e) {
120 throw new RuntimeException(
121 "class does not have required constructor, " + clazz +
"(RelInput)");
123 constructorMap.put(
type, constructor);
133 if (!type.contains(
".")) {
136 return Class.forName(package_ +
type);
137 }
catch (ClassNotFoundException e) {
143 return Class.forName(
type);
144 }
catch (ClassNotFoundException e) {
145 throw new RuntimeException(
"unknown type " + type);
153 final String canonicalName = class_.getName();
155 if (canonicalName.startsWith(package_)) {
156 String remaining = canonicalName.substring(package_.length());
157 if (remaining.indexOf(
'.') < 0 && remaining.indexOf(
'$') < 0) {
162 return canonicalName;
165 public Object
toJson(RelCollationImpl node) {
166 final List<Object> list =
new ArrayList<Object>();
167 for (RelFieldCollation fieldCollation : node.getFieldCollations()) {
168 final Map<String, Object> map = jsonBuilder.map();
169 map.put(
"field", fieldCollation.getFieldIndex());
170 map.put(
"direction", fieldCollation.getDirection().
name());
171 map.put(
"nulls", fieldCollation.nullDirection.name());
177 public Object
toJson(RexFieldCollation node) {
178 final Map<String, Object> map = jsonBuilder.map();
179 map.put(
"field",
toJson(node.left));
180 map.put(
"direction", node.getDirection().
name());
181 map.put(
"nulls", node.getNullDirection().
name());
185 public RelCollation
toCollation(List<Map<String, Object>> jsonFieldCollations) {
186 final List<RelFieldCollation> fieldCollations =
new ArrayList<RelFieldCollation>();
187 for (Map<String, Object> map : jsonFieldCollations) {
190 return RelCollations.of(fieldCollations);
195 final RelFieldCollation.Direction direction = Util.enumVal(
196 RelFieldCollation.Direction.class, (String) map.get(
"direction"));
197 final RelFieldCollation.NullDirection nullDirection = Util.enumVal(
198 RelFieldCollation.NullDirection.class, (String) map.get(
"nulls"));
199 return new RelFieldCollation(field, direction, nullDirection);
203 return RelDistributions.ANY;
206 public RelDataType
toType(RelDataTypeFactory typeFactory, Object o) {
207 if (o instanceof List) {
208 @SuppressWarnings(
"unchecked")
209 final List<Map<String, Object>> jsonList = (List<Map<String, Object>>) o;
210 final RelDataTypeFactory.Builder builder = typeFactory.builder();
211 for (Map<String, Object> jsonMap : jsonList) {
212 builder.add((String) jsonMap.get(
"name"),
toType(typeFactory, jsonMap));
214 return builder.build();
216 final Map<String, Object> map = (Map<String, Object>) o;
217 final SqlTypeName sqlTypeName =
218 Util.enumVal(SqlTypeName.class, (String) map.get(
"type"));
221 final RelDataType
type;
222 if (precision == null) {
223 type = typeFactory.createSqlType(sqlTypeName);
224 }
else if (scale == null) {
225 type = typeFactory.createSqlType(sqlTypeName, precision);
227 type = typeFactory.createSqlType(sqlTypeName, precision, scale);
229 final boolean nullable = (Boolean) map.get(
"nullable");
230 return typeFactory.createTypeWithNullability(
type, nullable);
234 public Object
toJson(AggregateCall node) {
235 final Map<String, Object> map = jsonBuilder.map();
236 map.put(
"agg",
toJson(node.getAggregation()));
237 map.put(
"type",
toJson(node.getType()));
238 map.put(
"distinct", node.isDistinct());
239 map.put(
"operands", node.getArgList());
244 if (value == null || value instanceof Number || value instanceof String
245 || value instanceof Boolean) {
247 }
else if (value instanceof RexNode) {
248 return toJson((RexNode) value);
249 }
else if (value instanceof CorrelationId) {
250 return toJson((CorrelationId) value);
251 }
else if (value instanceof List) {
252 final List<Object> list = jsonBuilder.list();
253 for (Object o : (List) value) {
257 }
else if (value instanceof ImmutableBitSet) {
258 final List<Object> list = jsonBuilder.list();
259 for (
Integer integer : (ImmutableBitSet) value) {
260 list.add(
toJson(integer));
263 }
else if (value instanceof AggregateCall) {
264 return toJson((AggregateCall) value);
265 }
else if (value instanceof RelCollationImpl) {
266 return toJson((RelCollationImpl) value);
267 }
else if (value instanceof RexFieldCollation) {
268 return toJson((RexFieldCollation) value);
269 }
else if (value instanceof RelDataType) {
270 return toJson((RelDataType) value);
271 }
else if (value instanceof RelDataTypeField) {
272 return toJson((RelDataTypeField) value);
273 }
else if (value instanceof
JoinType) {
274 return value.toString();
275 }
else if (value instanceof Operation) {
276 return value.toString();
278 throw new UnsupportedOperationException(
"type not serializable: " + value
279 +
" (type " + value.getClass().getCanonicalName() +
")");
283 private Object
toJson(RelDataType node) {
284 if (node.isStruct()) {
285 final List<Object> list = jsonBuilder.list();
286 for (RelDataTypeField
field : node.getFieldList()) {
291 final Map<String, Object> map = jsonBuilder.map();
292 map.put(
"type", node.getSqlTypeName().
name());
293 map.put(
"nullable", node.isNullable());
294 if (node.getSqlTypeName().allowsPrec()) {
295 map.put(
"precision", node.getPrecision());
297 if (node.getSqlTypeName().allowsScale()) {
298 map.put(
"scale", node.getScale());
304 private Object
toJson(RelDataTypeField node) {
305 final Map<String, Object> map = (Map<String, Object>)
toJson(node.getType());
306 map.put(
"name", node.getName());
310 private Object
toJson(CorrelationId node) {
314 private Object
toJson(
final RexWindowBound window_bound) {
315 final Map<String, Object> map = jsonBuilder.map();
316 map.put(
"unbounded",
toJson(window_bound.isUnbounded()));
317 map.put(
"preceding",
toJson(window_bound.isPreceding()));
318 map.put(
"following",
toJson(window_bound.isFollowing()));
319 map.put(
"is_current_row",
toJson(window_bound.isCurrentRow()));
321 window_bound.getOffset() != null ?
toJson(window_bound.getOffset()) : null);
322 map.put(
"order_key",
toJson(window_bound.getOrderKey()));
327 final Map<String, Object> map;
328 switch (node.getKind()) {
330 map = jsonBuilder.map();
331 final RexFieldAccess fieldAccess = (RexFieldAccess) node;
332 map.put(
"field", fieldAccess.getField().getName());
333 map.put(
"expr",
toJson(fieldAccess.getReferenceExpr()));
336 final RexLiteral literal = (RexLiteral) node;
337 final Object value2 = literal.getValue2();
338 map = jsonBuilder.map();
339 if (value2 instanceof TimeUnitRange || value2 instanceof SqlTrimFunction.Flag) {
340 map.put(
"literal", value2.toString());
342 map.put(
"literal", value2);
344 map.put(
"type", literal.getTypeName().
name());
345 map.put(
"target_type", literal.getType().getSqlTypeName().toString());
346 final Object value = literal.getValue();
347 if (value instanceof BigDecimal) {
348 map.put(
"scale", ((BigDecimal) value).scale());
349 map.put(
"precision", ((BigDecimal) value).precision());
351 map.put(
"scale", literal.getType().getScale());
352 map.put(
"precision", literal.getType().getPrecision());
354 map.put(
"type_scale", literal.getType().getScale());
355 map.put(
"type_precision", literal.getType().getPrecision());
358 map = jsonBuilder.map();
359 map.put(
"input", ((RexInputRef) node).getIndex());
361 case CORREL_VARIABLE:
362 map = jsonBuilder.map();
363 map.put(
"correl", ((RexCorrelVariable) node).getName());
364 map.put(
"type",
toJson(node.getType()));
367 if (node instanceof RexCall) {
368 final RexCall call = (RexCall) node;
369 map = jsonBuilder.map();
370 map.put(
"op",
toJson(call.getOperator()));
371 final List<Object> list = jsonBuilder.list();
372 for (RexNode operand : call.getOperands()) {
373 list.add(
toJson(operand));
375 map.put(
"operands", list);
376 map.put(
"type",
toJson(node.getType()));
377 if (node instanceof RexSubQuery) {
379 ((RexSubQuery) node).rel.explain(subqueryWriter);
380 map.put(
"subquery", subqueryWriter.asJsonMap());
382 if (node instanceof RexOver) {
383 final RexWindow window = ((RexOver) node).getWindow();
384 final List<Object> partitionKeyList = jsonBuilder.list();
385 for (
final RexNode partitionKey : window.partitionKeys) {
386 partitionKeyList.add(
toJson(partitionKey));
388 map.put(
"partition_keys", partitionKeyList);
389 final List<Object> orderKeyList = jsonBuilder.list();
390 for (
final RexFieldCollation orderKey : window.orderKeys) {
391 orderKeyList.add(
toJson(orderKey));
393 map.put(
"order_keys", orderKeyList);
394 RexWindowBound
lower_bound = window.getLowerBound();
395 RexWindowBound
upper_bound = window.getUpperBound();
396 map.put(
"lower_bound",
toJson(lower_bound));
397 map.put(
"upper_bound",
toJson(upper_bound));
398 map.put(
"is_rows",
toJson(window.isRows()));
400 if (call.getOperator() instanceof SqlFunction) {
401 switch (((SqlFunction) call.getOperator()).getFunctionType()) {
402 case USER_DEFINED_CONSTRUCTOR:
403 case USER_DEFINED_FUNCTION:
404 case USER_DEFINED_PROCEDURE:
405 case USER_DEFINED_SPECIFIC_FUNCTION:
406 map.put(
"class", call.getOperator().getClass().getName());
411 throw new UnsupportedOperationException(
"unknown rex " + node);
415 RexNode
toRex(RelInput relInput, Object o) {
416 final RelOptCluster cluster = relInput.getCluster();
417 final RexBuilder rexBuilder = cluster.getRexBuilder();
420 }
else if (o instanceof Map) {
422 final String op = (String) map.get(
"op");
424 final List operands = (List) map.get(
"operands");
425 final Object jsonType = map.get(
"type");
427 final List<RexNode> rexOperands =
toRexList(relInput, operands);
429 if (jsonType != null) {
430 type =
toType(cluster.getTypeFactory(), jsonType);
432 type = rexBuilder.deriveReturnType(
operator, rexOperands);
434 return rexBuilder.makeCall(
type,
operator, rexOperands);
438 List<RelNode> inputNodes = relInput.getInputs();
440 for (RelNode inputNode : inputNodes) {
441 final RelDataType rowType = inputNode.getRowType();
442 if (i < rowType.getFieldCount()) {
443 final RelDataTypeField
field = rowType.getFieldList().
get(i);
444 return rexBuilder.makeInputRef(field.getType(), input);
446 i -= rowType.getFieldCount();
448 throw new RuntimeException(
"input field " + input +
" is out of range");
450 final String
field = (String) map.get(
"field");
452 final Object jsonExpr = map.get(
"expr");
453 final RexNode expr =
toRex(relInput, jsonExpr);
454 return rexBuilder.makeFieldAccess(expr,
field,
true);
456 final String correl = (String) map.get(
"correl");
457 if (correl != null) {
458 final Object jsonType = map.get(
"type");
459 RelDataType
type =
toType(cluster.getTypeFactory(), jsonType);
460 return rexBuilder.makeCorrel(
type,
new CorrelationId(correl));
462 if (map.containsKey(
"literal")) {
463 final Object literal = map.get(
"literal");
464 final SqlTypeName sqlTypeName =
465 Util.enumVal(SqlTypeName.class, (String) map.get(
"type"));
466 if (literal == null) {
467 return rexBuilder.makeNullLiteral(
468 cluster.getTypeFactory().createSqlType(sqlTypeName));
473 if (literal instanceof Number) {
474 final SqlTypeName targetTypeName =
475 Util.enumVal(SqlTypeName.class, (String) map.get(
"target_type"));
476 final long scale = ((Number) map.get(
"scale")).longValue();
477 final long precision = ((Number) map.get(
"precision")).longValue();
478 final long typeScale = ((Number) map.get(
"type_scale")).longValue();
479 final long typePrecision = ((Number) map.get(
"type_precision")).longValue();
480 RelDataTypeFactory typeFactory = cluster.getTypeFactory();
483 BigDecimal.valueOf(((Number) literal).longValue(), (
int) scale);
485 if (typeScale != 0 && typeScale != -2147483648) {
486 return rexBuilder.makeLiteral(value,
487 typeFactory.createSqlType(
488 SqlTypeName.DECIMAL, (int) typePrecision, (
int) typeScale),
491 return rexBuilder.makeLiteral(
492 value, typeFactory.createSqlType(targetTypeName),
false);
495 return toRex(relInput, literal);
498 throw new UnsupportedOperationException(
"cannot convert to rex " + o);
499 }
else if (o instanceof Boolean) {
500 return rexBuilder.makeLiteral((Boolean) o);
501 }
else if (o instanceof String) {
502 return rexBuilder.makeLiteral((String) o);
503 }
else if (o instanceof Number) {
504 final Number number = (Number) o;
505 if (number instanceof
Double || number instanceof
Float) {
506 return rexBuilder.makeApproxLiteral(BigDecimal.valueOf(number.doubleValue()));
508 return rexBuilder.makeExactLiteral(BigDecimal.valueOf(number.longValue()));
511 throw new UnsupportedOperationException(
"cannot convert to rex " + o);
515 private List<RexNode>
toRexList(RelInput relInput, List operands) {
516 final List<RexNode> list =
new ArrayList<RexNode>();
517 for (Object operand : operands) {
518 list.add(
toRex(relInput, operand));
524 return toOp(op,
new HashMap<>());
532 operatorTable.addUDF(null);
533 final List<SqlOperator> operatorList = operatorTable.getOperatorList();
535 if (
operator.getName().equals(op)) {
539 String class_ = (String) map.get(
"class");
540 if (class_ != null) {
542 return (
SqlOperator) Class.forName(class_).newInstance();
543 }
catch (InstantiationException e) {
544 throw new RuntimeException(e);
545 }
catch (IllegalAccessException e) {
546 throw new RuntimeException(e);
547 }
catch (ClassNotFoundException e) {
548 throw new RuntimeException(e);
551 throw new RuntimeException(
"Operator " + op +
" does not supported");
557 String syntax =
"FUNCTION";
558 SqlKind sqlKind = SqlKind.valueOf(kind);
559 SqlSyntax sqlSyntax = SqlSyntax.valueOf(syntax);
562 operatorTable.addUDF(null);
563 final List<SqlOperator> operators = operatorTable.getOperatorList();
564 List<String> names =
new ArrayList<>();
566 names.add(operator.toString());
567 if (
operator.getName().equals(name)) {
571 throw new RuntimeException(
"Aggregation function with name " + name
572 +
" not found, search in " + names.toString());
576 return (SqlAggFunction)
toOp(agg);
580 return (SqlAggFunction)
toOp(relInput, agg);
585 return operator.getName();
DEVICE auto upper_bound(ARGS &&...args)
RelCollation toCollation(List< Map< String, Object >> jsonFieldCollations)
static final List< String > PACKAGES
Object toJson(RelDataTypeField node)
List< RexNode > toRexList(RelInput relInput, List operands)
Constructor getConstructor(String type)
Object toJson(RelDataType node)
final Map< String, Constructor > constructorMap
Class typeNameToClass(String type)
SqlOperator toOp(String op, Map< String, Object > map)
Object toJson(RelCollationImpl node)
SqlAggFunction toAggregation(RelInput relInput, String agg)
RelDistribution toDistribution(Object o)
Object toJson(RexFieldCollation node)
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
String classToTypeName(Class<?extends RelNode > class_)
SqlOperator toOp(RelInput relInput, String name)
SqlAggFunction toAggregation(String agg)
HeavyDBRelJson(JsonBuilder jsonBuilder)
RexNode toRex(RelInput relInput, Object o)
RelDataType toType(RelDataTypeFactory typeFactory, Object o)
RelFieldCollation toFieldCollation(Map< String, Object > map)
DEVICE auto lower_bound(ARGS &&...args)
Object toJson(Object value)
RelNode create(Map< String, Object > map)
Object toJson(CorrelationId node)
final JsonBuilder jsonBuilder
Object toJson(RexNode node)
SqlOperator toOp(String op)
Object toJson(AggregateCall node)
String toJson(SqlOperator operator)
Object toJson(final RexWindowBound window_bound)