void doInsertAt(long rowIndex, Value[] values) throws DriverException {
    // Check value count
    int fc = getFieldCount();
    if (values.length != fc) {
      throw new IllegalArgumentException("Wrong number of values. Expected: " + fc);
    }

    // Convert value
    for (int i = 0; i < values.length; i++) {
      Type type = getMetadata().getFieldType(i);
      values[i] = castValue(type, values[i]);
    }

    // Check constraints
    for (int i = 0; i < values.length; i++) {
      // Check uniqueness
      checkConstraints(values[i], i);
    }

    // Perform modifications
    dirty = true;
    insertInIndex(values, (int) rowIndex);
    PhysicalRowAddress dir = internalBuffer.insertRow(null, values);
    rowsAddresses.add((int) rowIndex, dir);
    InsertEditionInfo iei = new InsertEditionInfo(dir);
    editionActions.add((int) rowIndex, iei);
    cachedScope = null;

    editionListenerSupport.callInsert(rowIndex, undoRedo);
  }
 @Override
 public void syncWithSource() throws DriverException {
   getDataSource().syncWithSource();
   indexEditionManager.cancel();
   freeResources();
   initialize();
   editionListenerSupport.callSync();
 }
  void undoInsertAt(long rowIndex) throws DriverException {
    deleteInIndex((int) rowIndex);
    rowsAddresses.remove((int) rowIndex);
    editionActions.remove((int) rowIndex);
    cachedScope = null;

    editionListenerSupport.callDeleteRow(rowIndex, true);
  }
  void undoDeleteRow(PhysicalRowAddress dir, long rowId, DeleteEditionInfo dei, EditionInfo ei)
      throws DriverException {
    rowsAddresses.add((int) rowId, dir);
    if (dei != null) {
      deletedPKs.remove(dei);
    }
    editionActions.add((int) rowId, ei);
    insertInIndex(getRow(rowId), (int) rowId);

    cachedScope = null;

    editionListenerSupport.callInsert(rowId, true);
  }
  ModifyCommand.ModifyInfo doSetFieldValue(long row, int fieldId, Value value)
      throws DriverException {
    // convert value
    Value val = value;
    if (val == null) {
      val = ValueFactory.createNullValue();
    }

    // write check
    checkConstraints(val, fieldId);

    // Do modification
    ModifyCommand.ModifyInfo ret;
    PhysicalRowAddress dir = rowsAddresses.get((int) row);
    dirty = true;
    setFieldValueInIndex((int) row, fieldId, getFieldValue(row, fieldId), val);
    if (dir instanceof OriginalRowAddress) {
      Value[] original = getOriginalRow(dir);
      Value previousValue = original[fieldId];
      original[fieldId] = val;
      PhysicalRowAddress newAddress = internalBuffer.insertRow(dir.getPK(), original);
      rowsAddresses.set((int) row, newAddress);
      UpdateEditionInfo info = new UpdateEditionInfo(dir.getPK(), rowsAddresses.get((int) row));
      EditionInfo ei = editionActions.set((int) row, info);
      ret =
          new ModifyCommand.ModifyInfo(
              (OriginalRowAddress) dir,
              ei,
              (InternalBufferRowAddress) newAddress,
              previousValue,
              row,
              fieldId);
    } else {
      Value previousValue = dir.getFieldValue(fieldId);
      ((InternalBufferRowAddress) dir).setFieldValue(fieldId, val);
      /*
       * We don't modify the EditionInfo because is an insertion that
       * already points to the internal buffer
       */
      ret =
          new ModifyCommand.ModifyInfo(
              null, null, (InternalBufferRowAddress) dir, previousValue, row, fieldId);
    }
    cachedScope = null;

    editionListenerSupport.callSetFieldValue(row, fieldId, undoRedo);

    return ret;
  }
  DeleteCommandInfo doDeleteRow(long rowId) throws DriverException {
    dirty = true;
    deleteInIndex((int) rowId);
    PhysicalRowAddress dir = rowsAddresses.remove((int) rowId);
    EditionInfo ei = editionActions.get((int) rowId);
    DeleteEditionInfo dei = null;
    if (ei instanceof OriginalEditionInfo) {
      dei = new DeleteEditionInfo(((OriginalEditionInfo) ei).getPK());
      deletedPKs.add(dei);
    }
    editionActions.remove((int) rowId);
    cachedScope = null;

    editionListenerSupport.callDeleteRow(rowId, undoRedo);

    return new DeleteCommand.DeleteCommandInfo(dir, rowId, dei, ei);
  }
  void undoSetFieldValue(
      OriginalRowAddress previousDir,
      EditionInfo previousInfo,
      InternalBufferRowAddress dir,
      Value previousValue,
      int fieldId,
      long row)
      throws DriverException {
    if (previousDir != null) {
      setFieldValueInIndex((int) row, fieldId, getFieldValue(row, fieldId), previousValue);
      rowsAddresses.set((int) row, previousDir);
      editionActions.set((int) row, previousInfo);
    } else {
      setFieldValueInIndex((int) row, fieldId, getFieldValue(row, fieldId), previousValue);
      dir.setFieldValue(fieldId, previousValue);
    }

    cachedScope = null;
    editionListenerSupport.callSetFieldValue(row, fieldId, true);
  }
 @Override
 public void commitDone(String name) throws DriverException {
   initialize();
   editionListenerSupport.callSync();
 }
 @Override
 public void setDispatchingMode(int dispatchingMode) {
   editionListenerSupport.setDispatchingMode(dispatchingMode);
 }
 @Override
 public int getDispatchingMode() {
   return editionListenerSupport.getDispatchingMode();
 }
 @Override
 public void removeEditionListener(EditionListener listener) {
   editionListenerSupport.removeEditionListener(listener);
 }
 @Override
 public void addEditionListener(EditionListener listener) {
   editionListenerSupport.addEditionListener(listener);
 }