Unique constraint violation is wrapped by IntegrityError in SqlAlchemy.
SqlAlchemy doesn't unify errors from different DBs so we must do this in nova.
Also in some tables (for example instance_types) there are more than one unique
constraint. This means we should get names of columns, which values violate
unique constraint, from error message.
Unique constraint violations messages are different for different DB backedns:
1) sqlite:
1 column - (IntegrityError) column c1 is not unique
N columns - (IntegrityError) column c1, c2, ..., N are not unique
2) postgres:
1 column - (IntegrityError) duplicate key value violates unique
constraint "users_c1_key"
N columns - (IntegrityError) duplicate key value violates unique
constraint "name_of_our_constraint"
3) mysql:
1 column - (IntegrityError) (1062, "Duplicate entry 'value_of_c1' for key
'c1'")
N columns - (IntegrityError) (1062, "Duplicate entry 'values joined
with -' for key 'name_of_our_constraint'")
There is no information about table and columns in `N columns` messages for
mysql and postgres. So we should make name convention for UniqueConstraints
name: "uniq_c1_x_c2_x_c3" means that columns c1, c2, c3 are in
UniqueConstraint.
Also there is another way to get columns name from unique constraint:
1) Get table name.
2) Load table = Table(table_name, meta, autoload=True).
3) Find unique constraint that is in table.constraints by name.
4) Get columns names from unique constraint object.
But I think that it is a bad approach because:
1) We must do table autoload in exception handling
2) There is no easy way to get table name in wrap_db_error() method.
Remove Duplicate exception handling from models.save() method.
Add new DBDuplicateEntry exception to exceptions module.
Add new wrapper in sqlalchemy get_session() for handling Integrity Error.
blueprint db-unique-keys
Change-Id: Ic8fd8e0613f10d06c1d7d90f76a436099e8bfef2