Handle ibm_db_sa DBDuplicateEntry integrity errors
This patch adds duplicate entry integrity error handling for the ibm_db_sa driver to the common sqlalchemy db session. Closes-Bug: #1227321 Part of nova blueprint: db2-database Change-Id: I2f0d3d660373e4f647615f121fed0da9442f8cd2
This commit is contained in:
parent
0f24d82afc
commit
8dccc7bbb6
|
@ -332,11 +332,20 @@ class SqliteForeignKeysListener(PoolListener):
|
|||
# 'c1'")
|
||||
# N columns - (IntegrityError) (1062, "Duplicate entry 'values joined
|
||||
# with -' for key 'name_of_our_constraint'")
|
||||
#
|
||||
# ibm_db_sa:
|
||||
# N columns - (IntegrityError) SQL0803N One or more values in the INSERT
|
||||
# statement, UPDATE statement, or foreign key update caused by a
|
||||
# DELETE statement are not valid because the primary key, unique
|
||||
# constraint or unique index identified by "2" constrains table
|
||||
# "NOVA.KEY_PAIRS" from having duplicate values for the index
|
||||
# key.
|
||||
_DUP_KEY_RE_DB = {
|
||||
"sqlite": (re.compile(r"^.*columns?([^)]+)(is|are)\s+not\s+unique$"),
|
||||
re.compile(r"^.*UNIQUE\s+constraint\s+failed:\s+(.+)$")),
|
||||
"postgresql": (re.compile(r"^.*duplicate\s+key.*\"([^\"]+)\"\s*\n.*$"),),
|
||||
"mysql": (re.compile(r"^.*\(1062,.*'([^\']+)'\"\)$"),)
|
||||
"mysql": (re.compile(r"^.*\(1062,.*'([^\']+)'\"\)$"),),
|
||||
"ibm_db_sa": (re.compile(r"^.*SQL0803N.*$"),),
|
||||
}
|
||||
|
||||
|
||||
|
@ -358,7 +367,7 @@ def _raise_if_duplicate_entry_error(integrity_error, engine_name):
|
|||
return [columns]
|
||||
return columns[len(uniqbase):].split("0")[1:]
|
||||
|
||||
if engine_name not in ["mysql", "sqlite", "postgresql"]:
|
||||
if engine_name not in ["ibm_db_sa", "mysql", "sqlite", "postgresql"]:
|
||||
return
|
||||
|
||||
# FIXME(johannes): The usage of the .message attribute has been
|
||||
|
@ -373,7 +382,12 @@ def _raise_if_duplicate_entry_error(integrity_error, engine_name):
|
|||
else:
|
||||
return
|
||||
|
||||
columns = match.group(1)
|
||||
# NOTE(mriedem): The ibm_db_sa integrity error message doesn't provide the
|
||||
# columns so we have to omit that from the DBDuplicateEntry error.
|
||||
columns = ''
|
||||
|
||||
if engine_name != 'ibm_db_sa':
|
||||
columns = match.group(1)
|
||||
|
||||
if engine_name == "sqlite":
|
||||
columns = [c.split('.')[-1] for c in columns.strip().split(", ")]
|
||||
|
|
|
@ -22,6 +22,7 @@ import mock
|
|||
import sqlalchemy
|
||||
from sqlalchemy import Column, MetaData, Table, UniqueConstraint
|
||||
from sqlalchemy import DateTime, Integer, String
|
||||
from sqlalchemy import exc as sqla_exc
|
||||
from sqlalchemy.exc import DataError
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
|
@ -84,6 +85,40 @@ class SessionErrorWrapperTestCase(test_base.DbTestCase):
|
|||
self.assertRaises(db_exc.DBDuplicateEntry,
|
||||
method, {'foo': 20})
|
||||
|
||||
def test_ibm_db_sa_raise_if_duplicate_entry_error_duplicate(self):
|
||||
# Tests that the session._raise_if_duplicate_entry_error method
|
||||
# translates the duplicate entry integrity error for the DB2 engine.
|
||||
statement = ('INSERT INTO key_pairs (created_at, updated_at, '
|
||||
'deleted_at, deleted, name, user_id, fingerprint) VALUES '
|
||||
'(?, ?, ?, ?, ?, ?, ?)')
|
||||
params = ['20130918001123627099', None, None, 0, 'keypair-23474772',
|
||||
'974a7c9ffde6419f9811fcf94a917f47',
|
||||
'7d:2c:58:7f:97:66:14:3f:27:c7:09:3c:26:95:66:4d']
|
||||
orig = sqla_exc.SQLAlchemyError(
|
||||
'SQL0803N One or more values in the INSERT statement, UPDATE '
|
||||
'statement, or foreign key update caused by a DELETE statement are'
|
||||
' not valid because the primary key, unique constraint or unique '
|
||||
'index identified by "2" constrains table "NOVA.KEY_PAIRS" from '
|
||||
'having duplicate values for the index key.')
|
||||
integrity_error = sqla_exc.IntegrityError(statement, params, orig)
|
||||
self.assertRaises(db_exc.DBDuplicateEntry,
|
||||
session._raise_if_duplicate_entry_error,
|
||||
integrity_error, 'ibm_db_sa')
|
||||
|
||||
def test_ibm_db_sa_raise_if_duplicate_entry_error_no_match(self):
|
||||
# Tests that the session._raise_if_duplicate_entry_error method
|
||||
# does not raise a DBDuplicateEntry exception when it's not a matching
|
||||
# integrity error.
|
||||
statement = ('ALTER TABLE instance_types ADD CONSTRAINT '
|
||||
'uniq_name_x_deleted UNIQUE (name, deleted)')
|
||||
params = None
|
||||
orig = sqla_exc.SQLAlchemyError(
|
||||
'SQL0542N The column named "NAME" cannot be a column of a '
|
||||
'primary key or unique key constraint because it can contain null '
|
||||
'values.')
|
||||
integrity_error = sqla_exc.IntegrityError(statement, params, orig)
|
||||
session._raise_if_duplicate_entry_error(integrity_error, 'ibm_db_sa')
|
||||
|
||||
|
||||
_REGEXP_TABLE_NAME = _TABLE_NAME + "regexp"
|
||||
|
||||
|
|
Loading…
Reference in New Issue