Skip to content

Commit

Permalink
Checking existence of index before dropping
Browse files Browse the repository at this point in the history
Migrations modifying indexes drop and recreate the index.
If an index does not exist dropping would fail the migration.
As part of this fix, checking if index exists before dropping it.

Fixes bug 1243553

Change-Id: Ic75744bdccfbc516d36a9711ad6997fd86c7a722
  • Loading branch information
maheshp committed Nov 6, 2013
1 parent 8cea914 commit aadc7b8
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 8 deletions.
26 changes: 18 additions & 8 deletions nova/db/sqlalchemy/utils.py
Expand Up @@ -551,6 +551,14 @@ def is_deleted_column_constraint(constraint):
execute()


def _index_exists(migrate_engine, table_name, index_name):
inspector = reflection.Inspector.from_engine(migrate_engine)
indexes = inspector.get_indexes(table_name)
index_names = [index['name'] for index in indexes]

return index_name in index_names


def _add_index(migrate_engine, table, index_name, idx_columns):
index = Index(
index_name, *[getattr(table.c, col) for col in idx_columns]
Expand All @@ -559,18 +567,20 @@ def _add_index(migrate_engine, table, index_name, idx_columns):


def _drop_index(migrate_engine, table, index_name, idx_columns):
index = Index(
index_name, *[getattr(table.c, col) for col in idx_columns]
)
index.drop()
if _index_exists(migrate_engine, table.name, index_name):
index = Index(
index_name, *[getattr(table.c, col) for col in idx_columns]
)
index.drop()


def _change_index_columns(migrate_engine, table, index_name,
new_columns, old_columns):
Index(
index_name,
*[getattr(table.c, col) for col in old_columns]
).drop(migrate_engine)
if _index_exists(migrate_engine, table.name, index_name):
Index(
index_name,
*[getattr(table.c, col) for col in old_columns]
).drop(migrate_engine)

Index(
index_name,
Expand Down
74 changes: 74 additions & 0 deletions nova/tests/db/test_sqlalchemy_utils.py
@@ -0,0 +1,74 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4

# 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 mock

from nova.db.sqlalchemy import utils
from nova import test


class SqlAlchemyUtilsTestCase(test.NoDBTestCase):
"""Test case for sqlaclchemy utils methods."""

def test_modify_indexes_checks_index_before_dropping_in_postgresql(self):
data = {"table_name": (('index2', ('old_column'),
('new_column')),)}
migrate_engine = mock.Mock()
migrate_engine.name = 'postgresql'

with mock.patch('nova.db.sqlalchemy.utils.reflection.Inspector'
'.from_engine') as inspector:
inspector.return_value.get_indexes.return_value = [
{'name': "index1"}]
with mock.patch('nova.db.sqlalchemy.utils.Index') as index:
index.return_value = mock.Mock()
utils.modify_indexes(migrate_engine, data, False)

self.assertFalse(index.called)
self.assertFalse(index.return_value.drop.called)

def test_modify_indexes_checks_index_before_dropping_in_mysql(self):
data = {"table_name": (('index2', ('old_column'),
('new_column')),)}
migrate_engine = mock.Mock()
migrate_engine.name = 'mysql'

with mock.patch('nova.db.sqlalchemy.utils.reflection.Inspector'
'.from_engine') as inspector:
inspector.return_value.get_indexes.return_value = [
{'name': "index1"}]
with mock.patch('nova.db.sqlalchemy.utils.Index') as index:
with mock.patch('nova.db.sqlalchemy.utils.Table') as Table:
index.return_value = mock.Mock()
utils.modify_indexes(migrate_engine, data, False)

self.assertFalse(index.return_value.drop.called)

def test_modify_indexes(self):
data = {"table_name": (('index2', ('old_column'),
('new_column')),)}
migrate_engine = mock.Mock()
migrate_engine.name = 'mysql'

with mock.patch('nova.db.sqlalchemy.utils.reflection.Inspector'
'.from_engine') as inspector:
inspector.return_value.get_indexes.return_value = [
{'name': "index2"}]
with mock.patch('nova.db.sqlalchemy.utils.Index') as index:
with mock.patch('nova.db.sqlalchemy.utils.Table') as Table:
index.return_value = mock.Mock()
utils.modify_indexes(migrate_engine, data, True)

self.assertTrue(index.return_value.drop.called)
self.assertTrue(index.return_value.create.called)

0 comments on commit aadc7b8

Please sign in to comment.