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 if (value.toString().contains(
"$cor")) {
279 throw new UnsupportedOperationException(
280 "Unable to decorrelate one of the correlated subqueries.");
282 throw new UnsupportedOperationException(
"type not serializable: " + value
283 +
" (type " + value.getClass().getCanonicalName() +
")");
287 private Object
toJson(RelDataType node) {
288 if (node.isStruct()) {
289 final List<Object> list = jsonBuilder.list();
290 for (RelDataTypeField
field : node.getFieldList()) {
295 final Map<String, Object> map = jsonBuilder.map();
296 map.put(
"type", node.getSqlTypeName().
name());
297 map.put(
"nullable", node.isNullable());
298 if (node.getSqlTypeName().allowsPrec()) {
299 map.put(
"precision", node.getPrecision());
301 if (node.getSqlTypeName().allowsScale()) {
302 map.put(
"scale", node.getScale());
308 private Object
toJson(RelDataTypeField node) {
309 final Map<String, Object> map = (Map<String, Object>)
toJson(node.getType());
310 map.put(
"name", node.getName());
314 private Object
toJson(CorrelationId node) {
318 private Object
toJson(
final RexWindowBound window_bound) {
319 final Map<String, Object> map = jsonBuilder.map();
320 map.put(
"unbounded",
toJson(window_bound.isUnbounded()));
321 map.put(
"preceding",
toJson(window_bound.isPreceding()));
322 map.put(
"following",
toJson(window_bound.isFollowing()));
323 map.put(
"is_current_row",
toJson(window_bound.isCurrentRow()));
325 window_bound.getOffset() != null ?
toJson(window_bound.getOffset()) : null);
326 map.put(
"order_key",
toJson(window_bound.getOrderKey()));
331 final Map<String, Object> map;
332 switch (node.getKind()) {
334 map = jsonBuilder.map();
335 final RexFieldAccess fieldAccess = (RexFieldAccess) node;
336 map.put(
"field", fieldAccess.getField().getName());
337 map.put(
"expr",
toJson(fieldAccess.getReferenceExpr()));
340 final RexLiteral literal = (RexLiteral) node;
341 final Object value2 = literal.getValue2();
342 map = jsonBuilder.map();
343 if (value2 instanceof TimeUnitRange || value2 instanceof SqlTrimFunction.Flag) {
344 map.put(
"literal", value2.toString());
346 map.put(
"literal", value2);
348 map.put(
"type", literal.getTypeName().
name());
349 map.put(
"target_type", literal.getType().getSqlTypeName().toString());
350 final Object value = literal.getValue();
351 if (value instanceof BigDecimal) {
352 map.put(
"scale", ((BigDecimal) value).scale());
353 map.put(
"precision", ((BigDecimal) value).precision());
355 map.put(
"scale", literal.getType().getScale());
356 map.put(
"precision", literal.getType().getPrecision());
358 map.put(
"type_scale", literal.getType().getScale());
359 map.put(
"type_precision", literal.getType().getPrecision());
362 map = jsonBuilder.map();
363 map.put(
"input", ((RexInputRef) node).getIndex());
365 case CORREL_VARIABLE:
366 map = jsonBuilder.map();
367 map.put(
"correl", ((RexCorrelVariable) node).getName());
368 map.put(
"type",
toJson(node.getType()));
371 if (node instanceof RexCall) {
372 final RexCall call = (RexCall) node;
373 map = jsonBuilder.map();
374 map.put(
"op",
toJson(call.getOperator()));
375 final List<Object> list = jsonBuilder.list();
376 for (RexNode operand : call.getOperands()) {
377 list.add(
toJson(operand));
379 map.put(
"operands", list);
380 map.put(
"type",
toJson(node.getType()));
381 if (node instanceof RexSubQuery) {
383 ((RexSubQuery) node).rel.explain(subqueryWriter);
384 map.put(
"subquery", subqueryWriter.asJsonMap());
386 if (node instanceof RexOver) {
387 final RexWindow window = ((RexOver) node).getWindow();
388 final List<Object> partitionKeyList = jsonBuilder.list();
389 for (
final RexNode partitionKey : window.partitionKeys) {
390 partitionKeyList.add(
toJson(partitionKey));
392 map.put(
"partition_keys", partitionKeyList);
393 final List<Object> orderKeyList = jsonBuilder.list();
394 for (
final RexFieldCollation orderKey : window.orderKeys) {
395 orderKeyList.add(
toJson(orderKey));
397 map.put(
"order_keys", orderKeyList);
398 RexWindowBound
lower_bound = window.getLowerBound();
399 RexWindowBound
upper_bound = window.getUpperBound();
400 map.put(
"lower_bound",
toJson(lower_bound));
401 map.put(
"upper_bound",
toJson(upper_bound));
402 map.put(
"is_rows",
toJson(window.isRows()));
404 if (call.getOperator() instanceof SqlFunction) {
405 switch (((SqlFunction) call.getOperator()).getFunctionType()) {
406 case USER_DEFINED_CONSTRUCTOR:
407 case USER_DEFINED_FUNCTION:
408 case USER_DEFINED_PROCEDURE:
409 case USER_DEFINED_SPECIFIC_FUNCTION:
410 map.put(
"class", call.getOperator().getClass().getName());
415 throw new UnsupportedOperationException(
"unknown rex " + node);
419 RexNode
toRex(RelInput relInput, Object o) {
420 final RelOptCluster cluster = relInput.getCluster();
421 final RexBuilder rexBuilder = cluster.getRexBuilder();
424 }
else if (o instanceof Map) {
426 final String op = (String) map.get(
"op");
428 final List operands = (List) map.get(
"operands");
429 final Object jsonType = map.get(
"type");
431 final List<RexNode> rexOperands =
toRexList(relInput, operands);
433 if (jsonType != null) {
434 type =
toType(cluster.getTypeFactory(), jsonType);
436 type = rexBuilder.deriveReturnType(
operator, rexOperands);
438 return rexBuilder.makeCall(
type,
operator, rexOperands);
442 List<RelNode> inputNodes = relInput.getInputs();
444 for (RelNode inputNode : inputNodes) {
445 final RelDataType rowType = inputNode.getRowType();
446 if (i < rowType.getFieldCount()) {
447 final RelDataTypeField
field = rowType.getFieldList().
get(i);
448 return rexBuilder.makeInputRef(field.getType(), input);
450 i -= rowType.getFieldCount();
452 throw new RuntimeException(
"input field " + input +
" is out of range");
454 final String
field = (String) map.get(
"field");
456 final Object jsonExpr = map.get(
"expr");
457 final RexNode expr =
toRex(relInput, jsonExpr);
458 return rexBuilder.makeFieldAccess(expr,
field,
true);
460 final String correl = (String) map.get(
"correl");
461 if (correl != null) {
462 final Object jsonType = map.get(
"type");
463 RelDataType
type =
toType(cluster.getTypeFactory(), jsonType);
464 return rexBuilder.makeCorrel(
type,
new CorrelationId(correl));
466 if (map.containsKey(
"literal")) {
467 final Object literal = map.get(
"literal");
468 final SqlTypeName sqlTypeName =
469 Util.enumVal(SqlTypeName.class, (String) map.get(
"type"));
470 if (literal == null) {
471 return rexBuilder.makeNullLiteral(
472 cluster.getTypeFactory().createSqlType(sqlTypeName));
477 if (literal instanceof Number) {
478 final SqlTypeName targetTypeName =
479 Util.enumVal(SqlTypeName.class, (String) map.get(
"target_type"));
480 final long scale = ((Number) map.get(
"scale")).longValue();
481 final long precision = ((Number) map.get(
"precision")).longValue();
482 final long typeScale = ((Number) map.get(
"type_scale")).longValue();
483 final long typePrecision = ((Number) map.get(
"type_precision")).longValue();
484 RelDataTypeFactory typeFactory = cluster.getTypeFactory();
487 BigDecimal.valueOf(((Number) literal).longValue(), (
int) scale);
489 if (typeScale != 0 && typeScale != -2147483648) {
490 return rexBuilder.makeLiteral(value,
491 typeFactory.createSqlType(
492 SqlTypeName.DECIMAL, (int) typePrecision, (
int) typeScale),
495 return rexBuilder.makeLiteral(
496 value, typeFactory.createSqlType(targetTypeName),
false);
499 return toRex(relInput, literal);
502 throw new UnsupportedOperationException(
"cannot convert to rex " + o);
503 }
else if (o instanceof Boolean) {
504 return rexBuilder.makeLiteral((Boolean) o);
505 }
else if (o instanceof String) {
506 return rexBuilder.makeLiteral((String) o);
507 }
else if (o instanceof Number) {
508 final Number number = (Number) o;
509 if (number instanceof
Double || number instanceof
Float) {
510 return rexBuilder.makeApproxLiteral(BigDecimal.valueOf(number.doubleValue()));
512 return rexBuilder.makeExactLiteral(BigDecimal.valueOf(number.longValue()));
515 throw new UnsupportedOperationException(
"cannot convert to rex " + o);
519 private List<RexNode>
toRexList(RelInput relInput, List operands) {
520 final List<RexNode> list =
new ArrayList<RexNode>();
521 for (Object operand : operands) {
522 list.add(
toRex(relInput, operand));
528 return toOp(op,
new HashMap<>());
536 operatorTable.addUDF(null);
537 final List<SqlOperator> operatorList = operatorTable.getOperatorList();
539 if (
operator.getName().equals(op)) {
543 String class_ = (String) map.get(
"class");
544 if (class_ != null) {
546 return (
SqlOperator) Class.forName(class_).newInstance();
547 }
catch (InstantiationException e) {
548 throw new RuntimeException(e);
549 }
catch (IllegalAccessException e) {
550 throw new RuntimeException(e);
551 }
catch (ClassNotFoundException e) {
552 throw new RuntimeException(e);
555 throw new RuntimeException(
"Operator " + op +
" does not supported");
561 String syntax =
"FUNCTION";
562 SqlKind sqlKind = SqlKind.valueOf(kind);
563 SqlSyntax sqlSyntax = SqlSyntax.valueOf(syntax);
566 operatorTable.addUDF(null);
567 final List<SqlOperator> operators = operatorTable.getOperatorList();
568 List<String> names =
new ArrayList<>();
570 names.add(operator.toString());
571 if (
operator.getName().equals(name)) {
575 throw new RuntimeException(
"Aggregation function with name " + name
576 +
" not found, search in " + names.toString());
580 return (SqlAggFunction)
toOp(agg);
584 return (SqlAggFunction)
toOp(relInput, agg);
589 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)