public RexNode convertExpression()

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");
        }