public SqlNode toSql()

in core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java [658:855]


    public SqlNode toSql(@Nullable RexProgram program, RexNode rex) {
      rex = dialect.prepareUnparse(rex);
      final RexSubQuery subQuery;
      final SqlNode sqlSubQuery;
      final RexLiteral literal;
      switch (rex.getKind()) {
      case LOCAL_REF:
        final int index = ((RexLocalRef) rex).getIndex();
        return toSql(program, requireNonNull(program, "program").getExprList().get(index));

      case INPUT_REF:
        return field(((RexInputRef) rex).getIndex());

      case FIELD_ACCESS:
        final Deque<RexFieldAccess> accesses = new ArrayDeque<>();
        RexNode referencedExpr = rex;
        while (referencedExpr.getKind() == SqlKind.FIELD_ACCESS) {
          accesses.offerLast((RexFieldAccess) referencedExpr);
          referencedExpr = ((RexFieldAccess) referencedExpr).getReferenceExpr();
        }
        SqlIdentifier sqlIdentifier;
        switch (referencedExpr.getKind()) {
        case CORREL_VARIABLE:
          final RexCorrelVariable variable = (RexCorrelVariable) referencedExpr;
          final Context correlAliasContext = getAliasContext(variable);
          final RexFieldAccess lastAccess = requireNonNull(accesses.pollLast());
          SqlNode node  = correlAliasContext
              .field(lastAccess.getField().getIndex());
          if (node instanceof SqlDynamicParam) {
            return node;
          }
          sqlIdentifier = (SqlIdentifier) node;
          break;
        case ROW:
        case ITEM:
          final SqlNode expr = toSql(program, referencedExpr);
          sqlIdentifier = new SqlIdentifier(expr.toString(), POS);
          break;
        default:
          sqlIdentifier = (SqlIdentifier) toSql(program, referencedExpr);
        }

        int nameIndex = sqlIdentifier.names.size();
        RexFieldAccess access;
        while ((access = accesses.pollLast()) != null) {
          sqlIdentifier = sqlIdentifier.add(nameIndex++, access.getField().getName(), POS);
        }
        return sqlIdentifier;

      case PATTERN_INPUT_REF:
        final RexPatternFieldRef ref = (RexPatternFieldRef) rex;
        String pv = ref.getAlpha();
        SqlNode refNode = field(ref.getIndex());
        final SqlIdentifier id = (SqlIdentifier) refNode;
        if (id.names.size() > 1) {
          return id.setName(0, pv);
        } else {
          return new SqlIdentifier(ImmutableList.of(pv, id.names.get(0)), POS);
        }

      case LITERAL:
        return SqlImplementor.toSql(program, (RexLiteral) rex);

      case CASE:
        final RexCall caseCall = (RexCall) rex;
        final List<SqlNode> caseNodeList =
            toSql(program, caseCall.getOperands());
        final SqlNode valueNode;
        final List<SqlNode> whenList = Expressions.list();
        final List<SqlNode> thenList = Expressions.list();
        final SqlNode elseNode;
        if (caseNodeList.size() % 2 == 0) {
          // switched:
          //   "case x when v1 then t1 when v2 then t2 ... else e end"
          valueNode = caseNodeList.get(0);
          for (int i = 1; i < caseNodeList.size() - 1; i += 2) {
            whenList.add(caseNodeList.get(i));
            thenList.add(caseNodeList.get(i + 1));
          }
        } else {
          // other: "case when w1 then t1 when w2 then t2 ... else e end"
          valueNode = null;
          for (int i = 0; i < caseNodeList.size() - 1; i += 2) {
            whenList.add(caseNodeList.get(i));
            thenList.add(caseNodeList.get(i + 1));
          }
        }
        elseNode = caseNodeList.get(caseNodeList.size() - 1);

        if (caseCall.getType().getSqlTypeName() == SqlTypeName.BOOLEAN
            && !dialect.supportBooleanCaseWhen()) {
          // Transformed when expressions of boolean type in SqlCase
          // For example, given
          //     CASE WHEN x > 1 THEN y > 1 ELSE y < 10 END
          // Transformed:
          //     (CASE WHEN x > 1 THEN (CASE WHEN y > 1 THEN 1 ELSE 0 END)
          // ELSE (CASE WHEN y < 10 THEN 1 ELSE 0 END) END) = 1
          final List<SqlNode> thenList2 = thenList.stream()
              .map(
                  thenNode -> new SqlCase(POS, null, SqlNodeList.of(thenNode),
                      SqlNodeList.of(ONE), SqlNodeList.of(ZERO)))
              .collect(SqlNode.toList());
          final SqlNode elseNode2 =
              new SqlCase(POS, null, SqlNodeList.of(elseNode),
                  SqlNodeList.of(ONE), SqlNodeList.of(ZERO));

          final SqlCase sqlCase =
              new SqlCase(POS, valueNode,
                  new SqlNodeList(whenList, POS),
                  new SqlNodeList(thenList2, POS), elseNode2);
          return SqlStdOperatorTable.EQUALS.createCall(POS, sqlCase, ONE);
        }

        return new SqlCase(POS, valueNode, new SqlNodeList(whenList, POS),
            new SqlNodeList(thenList, POS), elseNode);

      case DYNAMIC_PARAM:
        final RexDynamicParam caseParam = (RexDynamicParam) rex;
        if (caseParam.getIndex() >= JdbcCorrelationDataContext.OFFSET) {
          throw new AssertionError("More than "
              + JdbcCorrelationDataContext.OFFSET
              + " dynamic parameters used in query");
        }
        return new SqlDynamicParam(caseParam.getIndex(), POS);

      case IN:
      case SOME:
      case ALL:
        subQuery = (RexSubQuery) rex;
        sqlSubQuery = implementor().visitRoot(subQuery.rel).asQueryOrValues();
        final List<RexNode> operands = subQuery.operands;
        SqlNode op0;
        if (operands.size() == 1) {
          op0 = toSql(program, operands.get(0));
        } else {
          final List<SqlNode> cols = toSql(program, operands);
          op0 = new SqlNodeList(cols, POS);
        }
        return subQuery.getOperator().createCall(POS, op0, sqlSubQuery);

      case SEARCH:
        final RexCall search = (RexCall) rex;
        if (search.operands.get(1).getKind() == SqlKind.LITERAL) {
          literal = (RexLiteral) search.operands.get(1);
          final Sarg sarg = castNonNull(literal.getValueAs(Sarg.class));
          //noinspection unchecked
          return toSql(program, search.operands.get(0), literal.getType(), sarg);
        }
        return toSql(program, RexUtil.expandSearch(RexBuilder.DEFAULT, program, search));

      case EXISTS:
      case UNIQUE:
      case SCALAR_QUERY:
        subQuery = (RexSubQuery) rex;
        sqlSubQuery =
            implementor().visitRoot(subQuery.rel).asQueryOrValues();
        return subQuery.getOperator().createCall(POS, sqlSubQuery);

      case NOT:
        RexNode operand = ((RexCall) rex).operands.get(0);
        final SqlNode node = toSql(program, operand);
        final SqlOperator inverseOperator = getInverseOperator(operand);
        if (inverseOperator != null) {
          switch (operand.getKind()) {
          case IN:
            assert operand instanceof RexSubQuery
                : "scalar IN is no longer allowed in RexCall: " + rex;
            break;
          default:
            break;
          }
          return inverseOperator.createCall(POS,
              ((SqlCall) node).getOperandList());
        } else {
          return SqlStdOperatorTable.NOT.createCall(POS, node);
        }

      case LAMBDA:
        final RexLambda lambda = (RexLambda) rex;
        final SqlNodeList parameters = new SqlNodeList(POS);
        for (RexLambdaRef parameter : lambda.getParameters()) {
          parameters.add(toSql(program, parameter));
        }
        final SqlNode expression = toSql(program, lambda.getExpression());
        return new SqlLambda(POS, parameters, expression);

      case LAMBDA_REF:
        final RexLambdaRef lambdaRef = (RexLambdaRef) rex;
        return new SqlIdentifier(lambdaRef.getName(), POS);

      default:
        if (rex instanceof RexOver) {
          return toSql(program, (RexOver) rex);
        }

        return callToSql(program, (RexCall) rex, false);
      }
    }