private void findSubQueries()

in core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java [2049:2156]


  private void findSubQueries(
      Blackboard bb,
      SqlNode node,
      RelOptUtil.Logic logic,
      boolean registerOnlyScalarSubQueries) {
    // If node is structurally identical to one of the group-by,
    // then it is not a sub-query; it is a reference.
    if (bb.agg != null && bb.agg.lookupGroupExpr(node) != -1) {
      return;
    }
    final SqlKind kind = node.getKind();
    switch (kind) {
    case EXISTS:
    case UNIQUE:
    case SELECT:
    case MULTISET_QUERY_CONSTRUCTOR:
    case MULTISET_VALUE_CONSTRUCTOR:
    case ARRAY_QUERY_CONSTRUCTOR:
    case MAP_QUERY_CONSTRUCTOR:
    case CURSOR:
    case SET_SEMANTICS_TABLE:
    case SCALAR_QUERY:
      if (!registerOnlyScalarSubQueries
          || (kind == SqlKind.SCALAR_QUERY)) {
        bb.registerSubQuery(node, RelOptUtil.Logic.TRUE_FALSE);
      }
      return;
    case IN:
      break;
    case NOT_IN:
    case NOT:
      logic = logic.negate();
      break;
    default:
      break;
    }
    if (node instanceof SqlCall) {
      switch (kind) {
      // Do no change logic for AND, IN and NOT IN expressions;
      // but do change logic for OR, NOT and others;
      // EXISTS was handled already.
      case AND:
      case IN:
      case NOT_IN:
        break;
      default:
        logic = RelOptUtil.Logic.TRUE_FALSE_UNKNOWN;
        break;
      }
      for (SqlNode operand : ((SqlCall) node).getOperandList()) {
        if (operand != null) {
          // In the case of an IN expression, locate scalar
          // sub-queries so we can convert them to constants
          findSubQueries(bb, operand, logic,
              kind == SqlKind.IN || kind == SqlKind.NOT_IN
                  || kind == SqlKind.SOME || kind == SqlKind.ALL
                  || registerOnlyScalarSubQueries);
        }
      }
    } else if (node instanceof SqlNodeList) {
      for (SqlNode child : (SqlNodeList) node) {
        findSubQueries(bb, child, logic,
            kind == SqlKind.IN || kind == SqlKind.NOT_IN
                || kind == SqlKind.SOME || kind == SqlKind.ALL
                || registerOnlyScalarSubQueries);
      }
    }

    // Now that we've located any scalar sub-queries inside the IN
    // expression, register the IN expression itself.  We need to
    // register the scalar sub-queries first so they can be converted
    // before the IN expression is converted.
    switch (kind) {
    case IN:
    case NOT_IN:
    case SOME:
    case ALL:
      switch (logic) {
      case TRUE_FALSE_UNKNOWN:
        RelDataType type = validator().getValidatedNodeTypeIfKnown(node);
        if (type == null) {
          // The node might not be validated if we still don't know type of the node.
          // Therefore return directly.
          return;
        } else {
          break;
        }
      case UNKNOWN_AS_FALSE:
        logic = RelOptUtil.Logic.TRUE;
        break;
      default:
        break;
      }
      if (node instanceof SqlBasicCall
          && ((SqlCall) node).getOperator() instanceof SqlQuantifyOperator
          && ((SqlQuantifyOperator) ((SqlCall) node).getOperator())
              .tryDeriveTypeForCollection(bb.getValidator(), bb.scope,
                  (SqlCall) node) != null) {
        findSubQueries(bb, ((SqlCall) node).operand(0), logic, registerOnlyScalarSubQueries);
        findSubQueries(bb, ((SqlCall) node).operand(1), logic, registerOnlyScalarSubQueries);
        break;
      }
      bb.registerSubQuery(node, logic);
      break;
    default:
      break;
    }
  }