/**
   * This function prepares the from-clause for use by the planner to generate an actual execution
   * plan from the clause. This includes several important tasks:
   *
   * <ul>
   *   <li>The schema of the from-clause's output is determined.
   *   <li>If the from-clause is a join, and the join specifies <tt>NATURAL</tt>, <tt>USING (col,
   *       ...)</tt>, or an <tt>ON</tt> clause, the join condition is determined
   * </ul>
   *
   * <p>Since a from-clause can be a SQL subquery or a join expression, it should be evident that
   * the method will recursively prepare its children as well.
   *
   * <p><b>This method really shouldn't be called directly.</b> Instead, the enclosing {@link
   * SelectClause} will calls this method when the clause's {@link SelectClause#computeSchema}
   * method is invoked.
   *
   * @return the schema of the from-clause's output
   * @throws IOException if a table's schema cannot be loaded, or some other IO issue occurs.
   */
  public Schema prepare() throws IOException {

    Schema result = null;

    switch (clauseType) {
      case BASE_TABLE:
        logger.debug("Preparing BASE_TABLE from-clause.");

        TableFileInfo tblFileInfo = StorageManager.getInstance().openTable(tableName);
        result = tblFileInfo.getSchema();

        if (aliasName != null) {
          // Make a copy of the result schema and change the table names.
          result = new Schema(result);
          result.setTableName(aliasName);
        }

        break;

      case SELECT_SUBQUERY:
        logger.debug("Preparing SELECT_SUBQUERY from-clause.");

        result = derivedTable.computeSchema();

        assert aliasName != null;

        // Make a copy of the result schema and change the table names.
        result = new Schema(result);
        result.setTableName(aliasName);

        break;

      case JOIN_EXPR:
        logger.debug("Preparing JOIN_EXPR from-clause.  Condition type = " + condType);

        result = new Schema();

        Schema leftSchema = leftChild.prepare();
        Schema rightSchema = rightChild.prepare();

        // Depending on the join type, we might eliminate duplicate column
        // names.
        if (condType == JoinConditionType.NATURAL_JOIN) {
          // Make sure that each side of the join doesn't have any
          // duplicate column names.  (A schema can have columns with the
          // same name, but from different table names.  This is not
          // allowed for natural joins.)
          if (leftSchema.hasMultipleColumnsWithSameName()) {
            throw new SchemaNameException(
                "Natural join error:  "
                    + "left child table has multiple columns with same "
                    + "column name");
          }
          if (rightSchema.hasMultipleColumnsWithSameName()) {
            throw new SchemaNameException(
                "Natural join error:  "
                    + "right child table has multiple columns with same "
                    + "column name");
          }

          Set<String> commonCols = leftSchema.getCommonColumnNames(rightSchema);
          if (commonCols.isEmpty()) {
            // TODO:  According to the SQL99 standard, this shouldn't
            //        generate an error.
            throw new SchemaNameException(
                "Natural join error:  " + "child tables share no common column names!");
          }

          buildJoinSchema("Natural join", leftSchema, rightSchema, commonCols, result);
        } else if (condType == JoinConditionType.JOIN_USING) {
          LinkedHashSet<String> commonCols = new LinkedHashSet<String>();
          for (String name : joinUsingNames) {
            if (!commonCols.add(name)) {
              throw new SchemaNameException(
                  "Column name " + name + " was specified multiple times in USING clause");
            }
          }

          buildJoinSchema("Join USING", leftSchema, rightSchema, commonCols, result);
        } else {
          // This join condition-type doesn't alter the result schema.
          // Just lump together the result schemas.
          result.append(leftSchema);
          result.append(rightSchema);

          preparedJoinExpr = joinOnExpr;
        }
    }

    // Don't need to do any schema validation in this function, since all the
    // validation takes place in the SELECT clause schema-computation code.

    preparedSchema = result;
    return result;
  }
 /**
  * Initialize the tuple-remover object with the details it needs to delete tuples from the
  * specified table.
  *
  * @param tblFileInfo details of the table that will be modified
  */
 public TupleRemover(TableFileInfo tblFileInfo) {
   this.tblFileInfo = tblFileInfo;
   this.tableMgr = tblFileInfo.getTableManager();
   this.eventDispatch = EventDispatcher.getInstance();
 }