/**
   * Creates projection list for scan. If the projection contains expressions, then the input
   * references from those expressions are extracted and that list of references becomes the
   * projection list.
   *
   * @param origScan row scan underneath the project
   * @param projRel ProjectRel that we will be creating the projection for
   * @param projectedColumns returns a list of the projected column ordinals, if it is possible to
   *     project
   * @param preserveExprCondition condition that identifies special expressions that should be
   *     preserved in the projection
   * @param defaultExpr expression to be used in the projection if no fields or special columns are
   *     selected
   * @param newProjList returns a new projection RelNode corresponding to a projection that now
   *     references a rowscan that is projecting the input references that were extracted from the
   *     original projection expressions; if the original expression didn't contain expressions,
   *     then this list is returned empty
   * @return true if columns in projection list from the scan need to be renamed
   */
  public boolean createProjectionList(
      FennelRel origScan,
      ProjectRel projRel,
      List<Integer> projectedColumns,
      PushProjector.ExprCondition preserveExprCondition,
      RexNode defaultExpr,
      List<ProjectRel> newProjList) {
    // REVIEW:  what about AnonFields?
    int n = projRel.getChildExps().length;
    RelDataType rowType = origScan.getRowType();
    RelDataType projType = projRel.getRowType();
    RelDataTypeField[] projFields = projType.getFields();
    List<Integer> tempProjList = new ArrayList<Integer>();
    boolean needRename = false;
    for (int i = 0; i < n; ++i) {
      RexNode exp = projRel.getChildExps()[i];
      List<String> origFieldName = new ArrayList<String>();
      Integer projIndex = mapProjCol(exp, origFieldName, rowType);
      if (projIndex == null) {
        // there are expressions in the projection; we need to extract
        // all input references and any special expressions from the
        // projection
        PushProjector pushProject =
            new PushProjector(projRel, null, origScan, preserveExprCondition);
        ProjectRel newProject = pushProject.convertProject(defaultExpr);
        if (newProject == null) {
          // can't do any further projection
          return false;
        }
        newProjList.add(newProject);

        // using the input references we just extracted, it should now
        // be possible to create a projection for the row scan
        needRename =
            createProjectionList(
                origScan,
                (ProjectRel) newProject.getChild(),
                projectedColumns,
                preserveExprCondition,
                defaultExpr,
                newProjList);
        assert (projectedColumns.size() > 0);
        return needRename;
      }
      String projFieldName = projFields[i].getName();
      if (!projFieldName.equals(origFieldName.get(0))) {
        needRename = true;
      }
      tempProjList.add(projIndex);
    }

    // now that we've determined it is possible to project, add the
    // ordinals to the return list
    projectedColumns.addAll(tempProjList);
    return needRename;
  }
 protected Integer mapFieldRef(RexNode exp, List<String> origFieldName, RelDataType rowType) {
   RexInputRef fieldAccess = (RexInputRef) exp;
   origFieldName.add(rowType.getFields()[fieldAccess.getIndex()].getName());
   return fieldAccess.getIndex();
 }
  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);
        }
      }
    }
  }