Skip to content

Commit

Permalink
Explicit foreign key indexes.
Browse files Browse the repository at this point in the history
Overview:
MySQL requires indexes on foreign keys. Such an index is created on the
referencing table automatically if it does not exist.

Motivation:
MySQL names foreign keys indexes differently dependent from itself
version. Implicit fk indexes is MySQL specific behavior, so it should be
ignored during comparision. We plan to use Alembic to compare models and
migrations I0758c7e09d1d46ce870c3f94f76c2a177955e143. Alembic doesn't support
5.5 naming convention. So we need consistent index name for all MySQL versions
to be easily ignored.

Solution:
A new migration script renames incorrectly named fk indexes on MySQL.

Reproduction:
Stop execution when foregn keys will be initialized. See schema with
your MySQL shell client. With 5.5, indexes which was not named
explicitly, will have a name such as <tablename>_<columnname>_fk, with 5.1 it
will be <columnname>.

Change-Id: I01ba0c8856afbda59394395ac319bf83a55ee2be
Partial-Bug: #1292591
  • Loading branch information
Ilya Pekelny committed Apr 24, 2014
1 parent e954942 commit ba6705a
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
@@ -0,0 +1,49 @@
# Copyright 2014 Mirantis.inc
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import sqlalchemy as sa


def upgrade(migrate_engine):

if migrate_engine.name == 'mysql':
meta = sa.MetaData(bind=migrate_engine)
endpoint = sa.Table('endpoint', meta, autoload=True)

# NOTE(i159): MySQL requires indexes on referencing columns, and those
# indexes create automatically. That those indexes will have different
# names, depending on version of MySQL used. We shoud make this naming
# consistent, by reverting index name to a consistent condition.
if any(i for i in endpoint.indexes if
i.columns.keys() == ['service_id'] and i.name != 'service_id'):
# NOTE(i159): by this action will be made re-creation of an index
# with the new name. This can be considered as renaming under the
# MySQL rules.
sa.Index('service_id', endpoint.c.service_id).create()

user_group_membership = sa.Table('user_group_membership',
meta, autoload=True)

if any(i for i in user_group_membership.indexes if
i.columns.keys() == ['group_id'] and i.name != 'group_id'):
sa.Index('group_id', user_group_membership.c.group_id).create()


def downgrade(migrate_engine):
# NOTE(i159): index exists only in MySQL schemas, and got an inconsistent
# name only when MySQL 5.5 renamed it after re-creation
# (during migrations). So we just fixed inconsistency, there is no
# necessity to revert it.
pass
@@ -0,0 +1,42 @@
# Copyright 2014 Mirantis.inc
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import sqlalchemy as sa


def upgrade(migrate_engine):

if migrate_engine.name == 'mysql':
meta = sa.MetaData(bind=migrate_engine)
table = sa.Table('access_token', meta, autoload=True)

# NOTE(i159): MySQL requires indexes on referencing columns, and those
# indexes create automatically. That those indexes will have different
# names, depending on version of MySQL used. We shoud make this naming
# consistent, by reverting index name to a consistent condition.
if any(i for i in table.indexes if i.columns.keys() == ['consumer_id']
and i.name != 'consumer_id'):
# NOTE(i159): by this action will be made re-creation of an index
# with the new name. This can be considered as renaming under the
# MySQL rules.
sa.Index('consumer_id', table.c.consumer_id).create()


def downgrade(migrate_engine):
# NOTE(i159): index exists only in MySQL schemas, and got an inconsistent
# name only when MySQL 5.5 renamed it after re-creation
# (during migrations). So we just fixed inconsistency, there is no
# necessity to revert it.
pass

0 comments on commit ba6705a

Please sign in to comment.