From 650ad385ba691a730d7ef869d2372102d9f6e610 Mon Sep 17 00:00:00 2001 From: Svetlana Shturm Date: Mon, 19 Aug 2013 11:13:48 +0400 Subject: [PATCH] Fix migration with fkeys Creation of fkeys doesn't work in sqlite, so we should do these changes in another dialects. Fix bug 1204823. Also we can have a problem with data conflicted with declared ForeignKey. We should dump "bad" data to another place, upgrade and create FK. Downgrade method should restore dumped data. Change-Id: I33089d6f47dcde4cf716a3d303c8df23dd19cd07 --- .../versions/012_add_missing_foreign_keys.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/ceilometer/storage/sqlalchemy/migrate_repo/versions/012_add_missing_foreign_keys.py b/ceilometer/storage/sqlalchemy/migrate_repo/versions/012_add_missing_foreign_keys.py index f95faea5..beb3074a 100644 --- a/ceilometer/storage/sqlalchemy/migrate_repo/versions/012_add_missing_foreign_keys.py +++ b/ceilometer/storage/sqlalchemy/migrate_repo/versions/012_add_missing_foreign_keys.py @@ -15,6 +15,9 @@ from migrate import ForeignKeyConstraint from sqlalchemy import MetaData, Table +from sqlalchemy.sql.expression import select + +from ceilometer.openstack.common.db.sqlalchemy import utils TABLES = ['resource', 'sourceassoc', 'user', 'project', 'meter', 'source', 'alarm'] @@ -36,13 +39,28 @@ INDEXES = { def upgrade(migrate_engine): + if migrate_engine.name == 'sqlite': + return meta = MetaData(bind=migrate_engine) load_tables = dict((table_name, Table(table_name, meta, autoload=True)) for table_name in TABLES) for table_name, indexes in INDEXES.items(): table = load_tables[table_name] + + # Save data that conflicted with FK. + columns = [column.copy() for column in table.columns] + table_dump = Table('dump_' + table_name, meta, *columns) + table_dump.create() for column, ref_table_name, ref_column_name in indexes: ref_table = load_tables[ref_table_name] + subq = select([getattr(ref_table.c, ref_column_name)]) + sql = utils.InsertFromSelect(table_dump, table.select().where( + ~ getattr(table.c, column).in_(subq))) + sql_del = table.delete().where( + ~ getattr(table.c, column).in_(subq)) + migrate_engine.execute(sql) + migrate_engine.execute(sql_del) + params = {'columns': [table.c[column]], 'refcolumns': [ref_table.c[ref_column_name]]} if migrate_engine.name == 'mysql': @@ -52,6 +70,8 @@ def upgrade(migrate_engine): def downgrade(migrate_engine): + if migrate_engine.name == 'sqlite': + return meta = MetaData(bind=migrate_engine) load_tables = dict((table_name, Table(table_name, meta, autoload=True)) for table_name in TABLES) @@ -63,5 +83,13 @@ def downgrade(migrate_engine): 'refcolumns': [ref_table.c[ref_column_name]]} if migrate_engine.name == 'mysql': params['name'] = "_".join(('fk', table_name, column)) - fkey = ForeignKeyConstraint(**params) - fkey.drop() + with migrate_engine.begin(): + fkey = ForeignKeyConstraint(**params) + fkey.drop() + with migrate_engine.begin(): + # Restore data that had been dropped. + table_dump_name = 'dump_' + table_name + table_dump = Table(table_dump_name, meta, autoload=True) + sql = utils.InsertFromSelect(table, table_dump.select()) + migrate_engine.execute(sql) + table_dump.drop()