]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Normalize Oracle reflected FK constraint name
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 13 Mar 2017 15:20:53 +0000 (11:20 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 13 Mar 2017 23:31:30 +0000 (19:31 -0400)
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
doc/build/changelog/changelog_12.rst
doc/build/changelog/migration_12.rst
lib/sqlalchemy/dialects/oracle/base.py
lib/sqlalchemy/testing/suite/test_reflection.py
test/requirements.py

index 009f5b9745c062ce2d55a4efc48341a8e0abe9bd..83df9167f929dd8dbc6728bd632fa9c1d8b61ded 100644 (file)
 
 .. 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
index 204652264a45512271dd05ac54c563ee5ac59a32..0950482287acea0effa399ab686dfde0e62783e4 100644 (file)
@@ -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`
+
index 7c23e9cd48c3b60f0d38dae15e1409269b69ac89..39bc5e1d3119a0f6408b0d795c179ad020bf9c2e 100644 (file)
@@ -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
index ed6a33b6d44b0fe8cab0bcd3a458d221e99f146d..572cc4a0a6187275565d5db2d5981b31fcb69053 100644 (file)
@@ -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)
index b1f965029d935aa743fe9af2a2de4c69e32a6801..16b1305bf7e75c4af06dacae6378dc1be40fa058 100644 (file)
@@ -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'),
             ])