diff options
author | Jenkins <jenkins@review.openstack.org> | 2015-04-10 13:58:09 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2015-04-10 13:58:09 +0000 |
commit | ebb3f0e2b5abd473d14404d43b0f0c32c2a4d5e2 (patch) | |
tree | 0a0e5f08c4b09e2e9433badf5c202eca58fe4a3c | |
parent | 9c852c63cd153aaa820d9bf5ebda7b5b7e1265c3 (diff) | |
parent | f94046bf20b315e151d668b55d737ae41414e421 (diff) | |
download | oslo-db-ebb3f0e2b5abd473d14404d43b0f0c32c2a4d5e2.tar.gz |
Merge "exc_filters: support for ForeignKey error on delete"
-rw-r--r-- | oslo_db/sqlalchemy/exc_filters.py | 6 | ||||
-rw-r--r-- | oslo_db/tests/sqlalchemy/test_exc_filters.py | 79 |
2 files changed, 80 insertions, 5 deletions
diff --git a/oslo_db/sqlalchemy/exc_filters.py b/oslo_db/sqlalchemy/exc_filters.py index 605b8a5..af8d992 100644 --- a/oslo_db/sqlalchemy/exc_filters.py +++ b/oslo_db/sqlalchemy/exc_filters.py @@ -191,12 +191,12 @@ def _sqlite_dupe_key_error(integrity_error, match, engine_name, is_disconnect): r"(?i).*foreign key constraint failed") @filters("postgresql", sqla_exc.IntegrityError, r".*on table \"(?P<table>[^\"]+)\" violates " - "foreign key constraint \"(?P<constraint>[^\"]+)\"\s*\n" + "foreign key constraint \"(?P<constraint>[^\"]+)\".*\n" "DETAIL: Key \((?P<key>.+)\)=\(.+\) " - "is not present in table " + "is (not present in|still referenced from) table " "\"(?P<key_table>[^\"]+)\".") @filters("mysql", sqla_exc.IntegrityError, - r".* u?'Cannot add or update a child row: " + r".* u?'Cannot (add|delete) or update a (child|parent) row: " 'a foreign key constraint fails \([`"].+[`"]\.[`"](?P<table>.+)[`"], ' 'CONSTRAINT [`"](?P<constraint>.+)[`"] FOREIGN KEY ' '\([`"](?P<key>.+)[`"]\) REFERENCES [`"](?P<key_table>.+)[`"] ') diff --git a/oslo_db/tests/sqlalchemy/test_exc_filters.py b/oslo_db/tests/sqlalchemy/test_exc_filters.py index 3f4f277..dc5de84 100644 --- a/oslo_db/tests/sqlalchemy/test_exc_filters.py +++ b/oslo_db/tests/sqlalchemy/test_exc_filters.py @@ -233,14 +233,14 @@ class TestReferenceErrorSQLite(_SQLAExceptionMatcher, test_base.DbTestCase): meta = sqla.MetaData(bind=self.engine) - table_1 = sqla.Table( + self.table_1 = sqla.Table( "resource_foo", meta, sqla.Column("id", sqla.Integer, primary_key=True), sqla.Column("foo", sqla.Integer), mysql_engine='InnoDB', mysql_charset='utf8', ) - table_1.create() + self.table_1.create() self.table_2 = sqla.Table( "resource_entity", meta, @@ -274,6 +274,30 @@ class TestReferenceErrorSQLite(_SQLAExceptionMatcher, test_base.DbTestCase): self.assertIsNone(matched.key) self.assertIsNone(matched.key_table) + def test_raise_delete(self): + self.engine.execute("PRAGMA foreign_keys = ON;") + + with self.engine.connect() as conn: + conn.execute(self.table_1.insert({"id": 1234, "foo": 42})) + conn.execute(self.table_2.insert({"id": 4321, "foo_id": 1234})) + matched = self.assertRaises( + exception.DBReferenceError, + self.engine.execute, + self.table_1.delete() + ) + self.assertInnerException( + matched, + "IntegrityError", + "foreign key constraint failed", + "DELETE FROM resource_foo", + (), + ) + + self.assertIsNone(matched.table) + self.assertIsNone(matched.constraint) + self.assertIsNone(matched.key) + self.assertIsNone(matched.key_table) + class TestReferenceErrorPostgreSQL(TestReferenceErrorSQLite, test_base.PostgreSQLOpportunisticTestCase): @@ -300,6 +324,31 @@ class TestReferenceErrorPostgreSQL(TestReferenceErrorSQLite, self.assertEqual("foo_id", matched.key) self.assertEqual("resource_foo", matched.key_table) + def test_raise_delete(self): + with self.engine.connect() as conn: + conn.execute(self.table_1.insert({"id": 1234, "foo": 42})) + conn.execute(self.table_2.insert({"id": 4321, "foo_id": 1234})) + matched = self.assertRaises( + exception.DBReferenceError, + self.engine.execute, + self.table_1.delete() + ) + self.assertInnerException( + matched, + "IntegrityError", + "update or delete on table \"resource_foo\" violates foreign key " + "constraint \"foo_fkey\" on table \"resource_entity\"\n" + "DETAIL: Key (id)=(1234) is still referenced from " + "table \"resource_entity\".\n", + "DELETE FROM resource_foo", + {}, + ) + + self.assertEqual("resource_foo", matched.table) + self.assertEqual("foo_fkey", matched.constraint) + self.assertEqual("id", matched.key) + self.assertEqual("resource_entity", matched.key_table) + class TestReferenceErrorMySQL(TestReferenceErrorSQLite, test_base.MySQLOpportunisticTestCase): @@ -353,6 +402,32 @@ class TestReferenceErrorMySQL(TestReferenceErrorSQLite, self.assertEqual("foo_id", matched.key) self.assertEqual("resource_foo", matched.key_table) + def test_raise_delete(self): + with self.engine.connect() as conn: + conn.execute(self.table_1.insert({"id": 1234, "foo": 42})) + conn.execute(self.table_2.insert({"id": 4321, "foo_id": 1234})) + matched = self.assertRaises( + exception.DBReferenceError, + self.engine.execute, + self.table_1.delete() + ) + self.assertInnerException( + matched, + "IntegrityError", + "(1451, 'cannot delete or update a parent row: a foreign key " + "constraint fails (`{0}`.`resource_entity`, " + "constraint `foo_fkey` " + "foreign key (`foo_id`) references " + "`resource_foo` (`id`))')".format(self.engine.url.database), + "DELETE FROM resource_foo", + (), + ) + + self.assertEqual("resource_entity", matched.table) + self.assertEqual("foo_fkey", matched.constraint) + self.assertEqual("foo_id", matched.key) + self.assertEqual("resource_foo", matched.key_table) + class TestConstraint(TestsExceptionFilter): def test_postgresql(self): |