/**
   * Determines if a filter condition is a simple one and returns the parameters corresponding to
   * the simple filters.
   *
   * @param calcRel original CalcRel
   * @param filterExprs filter expression being analyzed
   * @param filterList returns the list of filter ordinals in the simple expression
   * @param literals returns the list of literals to be used in the simple comparisons
   * @param op returns the operator to be used in the simple comparison
   * @return true if the filter condition is simple
   */
  private boolean isConditionSimple(
      CalcRel calcRel,
      RexNode filterExprs,
      List<Integer> filterList,
      List<RexLiteral> literals,
      List<CompOperatorEnum> op) {
    SargFactory sargFactory = new SargFactory(calcRel.getCluster().getRexBuilder());
    SargRexAnalyzer rexAnalyzer = sargFactory.newRexAnalyzer(true);
    List<SargBinding> sargBindingList = rexAnalyzer.analyzeAll(filterExprs);

    // Currently, it's all or nothing.  So, if there are filters rejected
    // by the analyzer, we can't process a subset using the reshape
    // exec stream
    if (rexAnalyzer.getNonSargFilterRexNode() != null) {
      return false;
    }

    List<RexInputRef> filterCols = new ArrayList<RexInputRef>();
    List<RexNode> filterOperands = new ArrayList<RexNode>();
    if (FennelRelUtil.extractSimplePredicates(sargBindingList, filterCols, filterOperands, op)) {
      for (RexInputRef filterCol : filterCols) {
        filterList.add(filterCol.getIndex());
      }
      for (RexNode operand : filterOperands) {
        literals.add((RexLiteral) operand);
      }
      return true;
    } else {
      return false;
    }
  }
 /**
  * Constructs a FarragoReentrantSubquery.
  *
  * @param subq the subquery to evaluate
  * @param parentConverter sqlToRelConverter associated with the parent query
  * @param isExists whether the subquery is part of an EXISTS expression
  * @param isExplain whether the subquery is part of an EXPLAIN PLAN statement
  * @param results the resulting evaluated expressions
  */
 FarragoReentrantSubquery(
     SqlCall subq,
     SqlToRelConverter parentConverter,
     boolean isExists,
     boolean isExplain,
     List<RexNode> results) {
   super(
       FennelRelUtil.getPreparingStmt(parentConverter.getCluster()).getRootStmtContext(),
       parentConverter.getRexBuilder(),
       results);
   FarragoSessionStmtContext rootContext = getRootStmtContext();
   if (rootContext != null) {
     rootContext.setSaveFirstTxnCsn();
   }
   if (!isExists) {
     assert subq.getKind() == SqlKind.SCALAR_QUERY;
   }
   this.subq = subq;
   this.parentConverter = parentConverter;
   this.isExists = isExists;
   this.isExplain = isExplain;
 }
  protected void executeImpl() throws Exception {
    SqlCall call = (SqlCall) subq;
    SqlSelect select = (SqlSelect) call.getOperands()[0];

    // Convert the SqlNode tree to a RelNode tree; we need to do this
    // here so the RelNode tree is associated with the new preparing
    // stmt.
    FarragoPreparingStmt preparingStmt = (FarragoPreparingStmt) getPreparingStmt();
    SqlValidator validator = preparingStmt.getSqlValidator();
    SqlToRelConverter sqlConverter = preparingStmt.getSqlToRelConverter(validator, preparingStmt);
    preparingStmt.setParentStmt(FennelRelUtil.getPreparingStmt(parentConverter.getCluster()));

    // Add to the new converter any subqueries that have already been
    // converted by the parent so we can avoid re-executing them
    sqlConverter.addConvertedNonCorrSubqs(parentConverter.getMapConvertedNonCorrSubqs());
    RelNode plan = sqlConverter.convertQuery(select, true, true);

    // The subquery cannot have dynamic parameters
    if (sqlConverter.getDynamicParamCount() > 0) {
      failed = true;
      return;
    }

    List<RexNode> exprs = new ArrayList<RexNode>();
    RelDataType resultType = null;

    if (!isExists) {
      // Non-EXISTS subqueries need to be converted to single-value
      // subqueries
      plan = sqlConverter.convertToSingleValueSubq(select, plan);

      // Create a dummy expression to store the type of the result.
      // When setting the type, derive the type based on what a
      // scalar subquery should return and create the type from the
      // type factory of the parent query.
      resultType = call.getOperator().deriveType(validator, validator.getFromScope(select), call);
      resultType = rexBuilder.getTypeFactory().copyType(resultType);
      exprs.add(rexBuilder.makeInputRef(resultType, 0));
    }

    plan = sqlConverter.decorrelate(select, plan);

    // If the subquery is part of an EXPLAIN PLAN statement, don't
    // execute the subquery, but instead just return a dynamic parameter
    // as a placeholder for the subquery result.  Otherwise, execute
    // the query to produce the constant expression.  Cast the expression
    // as needed so the type matches the expected result type.
    RexNode constExpr;
    if (isExplain) {
      if (isExists) {
        resultType = rexBuilder.getTypeFactory().createSqlType(SqlTypeName.BOOLEAN);
      }
      constExpr =
          rexBuilder.makeDynamicParam(
              resultType, parentConverter.getDynamicParamCountInExplain(true));
      results.add(constExpr);
    } else {
      executePlan(plan, exprs, isExists, false);
      if (!failed && !isExists) {
        constExpr = results.get(0);
        if (constExpr.getType() != resultType) {
          constExpr = rexBuilder.makeCast(resultType, constExpr);
          results.set(0, constExpr);
        }
      }
    }
  }