From: Mike Bayer Date: Mon, 13 Mar 2017 15:20:53 +0000 (-0400) Subject: Normalize Oracle reflected FK constraint name X-Git-Tag: rel_1_2_0b1~159 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6b0e12fd6f50a75750daf71ddff4bf32565fdf86;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Normalize Oracle reflected FK constraint name Oracle reflection now "normalizes" the name given to a foreign key constraint, that is, returns it as all lower case for a case insensitive name. This was already the behavior for indexes and primary key constraints as well as all table and column names. This will allow Alembic autogenerate scripts to compare and render foreign key constraint names correctly when initially specified as case insensitive. Change-Id: Ibb34ec6ce7cb244d1c4ae9d44ce2d37d37227e69 Fixes: #3276 --- diff --git a/doc/build/changelog/changelog_12.rst b/doc/build/changelog/changelog_12.rst index 009f5b9745..83df9167f9 100644 --- a/doc/build/changelog/changelog_12.rst +++ b/doc/build/changelog/changelog_12.rst @@ -12,3 +12,20 @@ .. changelog:: :version: 1.2.0b1 + + + .. change:: 3276 + :tags: bug, oracle + :tickets: 3276 + + Oracle reflection now "normalizes" the name given to a foreign key + constraint, that is, returns it as all lower case for a case + insensitive name. This was already the behavior for indexes + and primary key constraints as well as all table and column names. + This will allow Alembic autogenerate scripts to compare and render + foreign key constraint names correctly when initially specified + as case insensitive. + + .. seealso:: + + :ref:`change_3276` \ No newline at end of file diff --git a/doc/build/changelog/migration_12.rst b/doc/build/changelog/migration_12.rst index 204652264a..0950482287 100644 --- a/doc/build/changelog/migration_12.rst +++ b/doc/build/changelog/migration_12.rst @@ -55,3 +55,36 @@ Dialect Improvements and Changes - SQLite Dialect Improvements and Changes - Oracle ============================================= +.. _change_3276: + +Oracle foreign key constraint names are now "name normalized" +------------------------------------------------------------- + +The names of foreign key constraints as delivered to a +:class:`.ForeignKeyConstraint` object during table reflection as well as +within the :meth:`.Inspector.get_foreign_keys` method will now be +"name normalized", that is, expressed as lower case for a case insensitive +name, rather than the raw UPPERCASE format that Oracle uses:: + + >>> insp.get_indexes("addresses") + [{'unique': False, 'column_names': [u'user_id'], + 'name': u'address_idx', 'dialect_options': {}}] + + >>> insp.get_pk_constraint("addresses") + {'name': u'pk_cons', 'constrained_columns': [u'id']} + + >>> insp.get_foreign_keys("addresses") + [{'referred_table': u'users', 'referred_columns': [u'id'], + 'referred_schema': None, 'name': u'user_id_fk', + 'constrained_columns': [u'user_id']}] + +Previously, the foreign keys result would look like:: + + [{'referred_table': u'users', 'referred_columns': [u'id'], + 'referred_schema': None, 'name': 'USER_ID_FK', + 'constrained_columns': [u'user_id']}] + +Where the above could create problems particularly with Alembic autogenerate. + +:ticket:`3276` + diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py index 7c23e9cd48..39bc5e1d31 100644 --- a/lib/sqlalchemy/dialects/oracle/base.py +++ b/lib/sqlalchemy/dialects/oracle/base.py @@ -1530,6 +1530,8 @@ class OracleDialect(default.DefaultDialect): (cons_name, cons_type, local_column, remote_table, remote_column, remote_owner) = \ row[0:2] + tuple([self.normalize_name(x) for x in row[2:6]]) + cons_name = self.normalize_name(cons_name) + if cons_type == 'R': if remote_table is None: # ticket 363 diff --git a/lib/sqlalchemy/testing/suite/test_reflection.py b/lib/sqlalchemy/testing/suite/test_reflection.py index ed6a33b6d4..572cc4a0a6 100644 --- a/lib/sqlalchemy/testing/suite/test_reflection.py +++ b/lib/sqlalchemy/testing/suite/test_reflection.py @@ -70,7 +70,8 @@ class ComponentReflectionTest(fixtures.TablesTest): Column('test2', sa.Float(5), nullable=False), Column('parent_user_id', sa.Integer, sa.ForeignKey('%susers.user_id' % - schema_prefix)), + schema_prefix, + name='user_id_fk')), schema=schema, test_needs_fk=True, ) @@ -444,7 +445,7 @@ class ComponentReflectionTest(fixtures.TablesTest): fkey1 = users_fkeys[0] with testing.requires.named_constraints.fail_if(): - self.assert_(fkey1['name'] is not None) + eq_(fkey1['name'], "user_id_fk") eq_(fkey1['referred_schema'], expected_schema) eq_(fkey1['referred_table'], users.name) @@ -457,7 +458,7 @@ class ComponentReflectionTest(fixtures.TablesTest): schema=schema) fkey1 = addr_fkeys[0] - with testing.requires.named_constraints.fail_if(): + with testing.requires.implicitly_named_constraints.fail_if(): self.assert_(fkey1['name'] is not None) eq_(fkey1['referred_schema'], expected_schema) diff --git a/test/requirements.py b/test/requirements.py index b1f965029d..16b1305bf7 100644 --- a/test/requirements.py +++ b/test/requirements.py @@ -59,6 +59,12 @@ class DefaultRequirements(SuiteRequirements): def named_constraints(self): """target database must support names for constraints.""" + return exclusions.open() + + @property + def implicitly_named_constraints(self): + """target database must apply names to unnamed constraints.""" + return skip_if([ no_support('sqlite', 'not supported by database'), ])