@Override
  public String check(int fieldId, Value value) throws DriverException {
    // In order to build pk indexes
    initializeEdition();
    // Check special case of auto-increment not-null fields
    Type type = getMetadata().getFieldType(fieldId);
    boolean autoIncrement = type.getBooleanConstraint(Constraint.AUTO_INCREMENT);
    if (autoIncrement && type.getBooleanConstraint(Constraint.NOT_NULL) && value.isNull()) {
      return null;
    }
    int fieldType = type.getTypeCode();
    // Test geometry types.
    if (TypeFactory.isVectorial(type.getTypeCode())) {
      int valueType = value.getType();

      if (!checkGeometry(valueType, fieldType)) {
        return "Can't put a "
            + TypeFactory.getTypeName(valueType)
            + " in a "
            + TypeFactory.getTypeName(fieldType)
            + " column.";
      }
    }
    // Cast value
    Value val = castValue(type, value);
    int broadType = TypeFactory.getBroaderType(fieldType, val.getType());
    if (val.getType() != broadType
        && val.getType() != Type.NULL
        && !checkGeometry(val.getType(), fieldType)
        && fieldType != Type.STRING) {
      return "Can't cast a "
          + TypeFactory.getTypeName(value.getType())
          + " to a "
          + TypeFactory.getTypeName(fieldType);
    }

    // Check constraints
    String fieldName = getMetadata().getFieldName(fieldId);
    String error = type.check(value);
    if (error != null) {
      return "Value at field " + getFieldName(fieldId) + " is not valid:" + error;
    }

    // Check uniqueness
    if (type.getBooleanConstraint(Constraint.UNIQUE) || type.getBooleanConstraint(Constraint.PK)) {
      // We assume a geometry field can't have unique constraint
      IndexQuery iq = new DefaultAlphaQuery(fieldName, value);
      Iterator<Integer> it = queryIndex(iq);
      while (it.hasNext()) {
        if (getFieldValue(it.next(), fieldId).equals(value).getAsBoolean()) {
          return fieldName + " column doesn't admit duplicates: " + value;
        }
      }
    }

    return null;
  }
 @Override
 public void setFieldName(int index, String name) throws DriverException {
   initializeEdition();
   SetFieldNameCommand command = new SetFieldNameCommand(this, index, name);
   cs.put(command);
 }
 @Override
 public void removeField(int index) throws DriverException {
   initializeEdition();
   DelFieldCommand command = new DelFieldCommand(this, index);
   cs.put(command);
 }
 @Override
 public void addField(String name, Type type) throws DriverException {
   initializeEdition();
   AddFieldCommand command = new AddFieldCommand(this, name, type);
   cs.put(command);
 }
 @Override
 public void insertFilledRowAt(long rowIndex, Value[] values) throws DriverException {
   initializeEdition();
   InsertAtCommand command = new InsertAtCommand((int) rowIndex, this, values);
   cs.put(command);
 }
 @Override
 public void setFieldValue(long row, int fieldId, Value value) throws DriverException {
   initializeEdition();
   ModifyCommand command = new ModifyCommand((int) row, this, value, fieldId);
   cs.put(command);
 }
 @Override
 public void deleteRow(long rowId) throws DriverException {
   initializeEdition();
   DeleteCommand command = new DeleteCommand((int) rowId, this);
   cs.put(command);
 }