/**
   * This helper method handles the case when a tuple is being removed from the table, before the
   * row has actually been removed from the table. All indexes on the table are updated to remove
   * the row.
   *
   * @param tblFileInfo details of the table being updated
   * @param ptup the tuple about to be removed from the table
   */
  private void removeRowFromIndexes(TableInfo tblFileInfo, PageTuple ptup) {

    logger.debug(
        "Removing tuple " + ptup + " from indexes for table " + tblFileInfo.getTableName());

    // Iterate over the indexes in the table.
    TableSchema schema = tblFileInfo.getSchema();
    for (ColumnRefs indexDef : schema.getIndexes().values()) {
      TupleLiteral idxTup =
          IndexUtils.makeSearchKeyValue(indexDef, ptup, /* findExactTuple */ true);

      logger.debug("Removing tuple " + idxTup + " from index " + indexDef.getIndexName());

      try {
        IndexInfo indexInfo = indexManager.openIndex(tblFileInfo, indexDef.getIndexName());

        TupleFile tupleFile = indexInfo.getTupleFile();

        PageTuple idxPageTup = IndexUtils.findTupleInIndex(idxTup, tupleFile);
        if (idxPageTup == null) {
          throw new IllegalStateException(
              "Can't find tuple in " + "index corresponding to table's tuple.");
        }

        tupleFile.deleteTuple(idxPageTup);
      } catch (IOException e) {
        throw new EventDispatchException(
            "Couldn't update index "
                + indexDef.getIndexName()
                + " for table "
                + tblFileInfo.getTableName());
      }
    }
  }
  /**
   * This helper method handles the case when a tuple is being added to the table, after the row has
   * already been added to the table. All indexes on the table are updated to include the new row.
   *
   * @param tblFileInfo details of the table being updated
   * @param ptup the new tuple that was inserted into the table
   */
  private void addRowToIndexes(TableInfo tblFileInfo, PageTuple ptup) {
    logger.debug("Adding tuple " + ptup + " to indexes for table " + tblFileInfo.getTableName());

    // Iterate over the indexes in the table.
    TableSchema schema = tblFileInfo.getSchema();
    for (ColumnRefs indexDef : schema.getIndexes().values()) {
      TupleLiteral idxTup;
      try {
        IndexInfo indexInfo = indexManager.openIndex(tblFileInfo, indexDef.getIndexName());

        TupleFile tupleFile = indexInfo.getTupleFile();

        TableConstraintType constraintType = indexDef.getConstraintType();
        if (constraintType != null && constraintType.isUnique()) {
          // Check if the index already has a tuple with this value.
          idxTup = IndexUtils.makeSearchKeyValue(indexDef, ptup, /* findExactTuple */ false);

          if (IndexUtils.findTupleInIndex(idxTup, tupleFile) != null) {
            // Adding this row would violate the unique index.
            throw new IllegalStateException(
                "Unique index " + "already contains a tuple with this value.");
          }
        }

        idxTup = IndexUtils.makeSearchKeyValue(indexDef, ptup, /* findExactTuple */ true);

        logger.debug("Adding tuple " + idxTup + " to index " + indexDef.getIndexName());

        tupleFile.addTuple(idxTup);
      } catch (IOException e) {
        throw new EventDispatchException(
            "Couldn't update index "
                + indexDef.getIndexName()
                + " for table "
                + tblFileInfo.getTableName(),
            e);
      }
    }
  }