in flink-table/flink-table-planner/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java [5424:5612]
public RexNode convertExpression(SqlNode expr) {
// If we're in aggregation mode and this is an expression in the
// GROUP BY clause, return a reference to the field.
AggConverter agg = this.agg;
if (agg != null) {
final SqlNode expandedGroupExpr = validator().expand(expr, scope());
final int ref = agg.lookupGroupExpr(expandedGroupExpr);
if (ref >= 0) {
return rexBuilder.makeInputRef(root(), ref);
}
if (expr instanceof SqlCall) {
final RexNode rex = agg.lookupAggregates((SqlCall) expr);
if (rex != null) {
return rex;
}
}
}
// Allow the derived class chance to override the standard
// behavior for special kinds of expressions.
RexNode rex = convertExtendedExpression(expr, this);
if (rex != null) {
return rex;
}
// Sub-queries and OVER expressions are not like ordinary
// expressions.
final SqlKind kind = expr.getKind();
final SubQuery subQuery;
if (!config.isExpand()) {
final SqlCall call;
final SqlNode query;
final RelRoot root;
switch (kind) {
case IN:
case NOT_IN:
case SOME:
case ALL:
call = (SqlCall) expr;
query = call.operand(1);
if (!(query instanceof SqlNodeList)) {
root = convertQueryRecursive(query, false, null);
final SqlNode operand = call.operand(0);
List<SqlNode> nodes;
switch (operand.getKind()) {
case ROW:
nodes = ((SqlCall) operand).getOperandList();
break;
default:
nodes = ImmutableList.of(operand);
}
final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
for (SqlNode node : nodes) {
builder.add(convertExpression(node));
}
final ImmutableList<RexNode> list = builder.build();
switch (kind) {
case IN:
return RexSubQuery.in(root.rel, list);
case NOT_IN:
return rexBuilder.makeCall(
SqlStdOperatorTable.NOT,
RexSubQuery.in(root.rel, list));
case SOME:
return RexSubQuery.some(
root.rel,
list,
(SqlQuantifyOperator) call.getOperator());
case ALL:
return rexBuilder.makeCall(
SqlStdOperatorTable.NOT,
RexSubQuery.some(
root.rel,
list,
negate(
(SqlQuantifyOperator)
call.getOperator())));
default:
throw new AssertionError(kind);
}
}
break;
case EXISTS:
call = (SqlCall) expr;
query = Iterables.getOnlyElement(call.getOperandList());
root = convertQueryRecursive(query, false, null);
RelNode rel = root.rel;
while (rel instanceof Project
|| rel instanceof Sort
&& ((Sort) rel).fetch == null
&& ((Sort) rel).offset == null) {
rel = ((SingleRel) rel).getInput();
}
return RexSubQuery.exists(rel);
case UNIQUE:
call = (SqlCall) expr;
query = Iterables.getOnlyElement(call.getOperandList());
root = convertQueryRecursive(query, false, null);
return RexSubQuery.unique(root.rel);
case SCALAR_QUERY:
call = (SqlCall) expr;
query = Iterables.getOnlyElement(call.getOperandList());
root = convertQueryRecursive(query, false, null);
return RexSubQuery.scalar(root.rel);
case ARRAY_QUERY_CONSTRUCTOR:
call = (SqlCall) expr;
query = Iterables.getOnlyElement(call.getOperandList());
root = convertQueryRecursive(query, false, null);
return RexSubQuery.array(root.rel);
case MAP_QUERY_CONSTRUCTOR:
call = (SqlCall) expr;
query = Iterables.getOnlyElement(call.getOperandList());
root = convertQueryRecursive(query, false, null);
return RexSubQuery.map(root.rel);
case MULTISET_QUERY_CONSTRUCTOR:
call = (SqlCall) expr;
query = Iterables.getOnlyElement(call.getOperandList());
root = convertQueryRecursive(query, false, null);
return RexSubQuery.multiset(root.rel);
default:
break;
}
}
switch (kind) {
case SOME:
case ALL:
case UNIQUE:
if (config.isExpand()) {
throw new RuntimeException(kind + " is only supported if expand = false");
}
// fall through
case CURSOR:
case IN:
case NOT_IN:
subQuery = requireNonNull(getSubQuery(expr, null));
rex = requireNonNull(subQuery.expr);
return StandardConvertletTable.castToValidatedType(
expr, rex, validator(), rexBuilder);
case SELECT:
case EXISTS:
case SCALAR_QUERY:
case ARRAY_QUERY_CONSTRUCTOR:
case MAP_QUERY_CONSTRUCTOR:
case MULTISET_QUERY_CONSTRUCTOR:
subQuery = getSubQuery(expr, null);
assert subQuery != null;
rex = subQuery.expr;
assert rex != null : "rex != null";
if (((kind == SqlKind.SCALAR_QUERY) || (kind == SqlKind.EXISTS))
&& isConvertedSubq(rex)) {
// scalar sub-query or EXISTS has been converted to a
// constant
return rex;
}
// The indicator column is the last field of the sub-query.
RexNode fieldAccess =
rexBuilder.makeFieldAccess(rex, rex.getType().getFieldCount() - 1);
// The indicator column will be nullable if it comes from
// the null-generating side of the join. For EXISTS, add an
// "IS TRUE" check so that the result is "BOOLEAN NOT NULL".
if (fieldAccess.getType().isNullable() && kind == SqlKind.EXISTS) {
fieldAccess =
rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, fieldAccess);
}
return fieldAccess;
case OVER:
return convertOver(this, expr);
default:
// fall through
}
// Apply standard conversions.
rex = expr.accept(this);
return requireNonNull(rex, "rex");
}