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;
  }
  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);
  }