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