.. 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
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`
+
(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
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,
)
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)
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)
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'),
])