Merge "Add some helper methods to deal with sqlite migrations"
This commit is contained in:
commit
e5b6c3b4f8
105
gertty/dbsupport.py
Normal file
105
gertty/dbsupport.py
Normal file
@ -0,0 +1,105 @@
|
||||
# Copyright 2014 Mirantis Inc.
|
||||
# Copyright 2014 OpenStack Foundation
|
||||
#
|
||||
# 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 six
|
||||
import uuid
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def sqlite_alter_columns(table_name, column_defs):
|
||||
"""Implement alter columns for SQLite.
|
||||
|
||||
The ALTER COLUMN command isn't supported by SQLite specification.
|
||||
Instead of calling ALTER COLUMN it uses the following workaround:
|
||||
|
||||
* create temp table '{table_name}_{rand_uuid}', with some column
|
||||
defs replaced;
|
||||
* copy all data to the temp table;
|
||||
* drop old table;
|
||||
* rename temp table to the old table name.
|
||||
"""
|
||||
connection = op.get_bind()
|
||||
meta = sqlalchemy.MetaData(bind=connection)
|
||||
meta.reflect()
|
||||
|
||||
changed_columns = {}
|
||||
indexes = []
|
||||
for col in column_defs:
|
||||
# If we are to have an index on the column, don't create it
|
||||
# immediately, instead, add it to a list of indexes to create
|
||||
# after the table rename.
|
||||
if col.index:
|
||||
indexes.append(('ix_%s_%s' % (table_name, col.name),
|
||||
table_name,
|
||||
[col.name],
|
||||
col.unique))
|
||||
col.unique = False
|
||||
col.index = False
|
||||
changed_columns[col.name] = col
|
||||
|
||||
# construct lists of all columns and their names
|
||||
old_columns = []
|
||||
new_columns = []
|
||||
column_names = []
|
||||
for column in meta.tables[table_name].columns:
|
||||
column_names.append(column.name)
|
||||
old_columns.append(column)
|
||||
if column.name in changed_columns.keys():
|
||||
new_columns.append(changed_columns[column.name])
|
||||
else:
|
||||
col_copy = column.copy()
|
||||
new_columns.append(col_copy)
|
||||
|
||||
for key in meta.tables[table_name].foreign_keys:
|
||||
constraint = key.constraint
|
||||
con_copy = constraint.copy()
|
||||
new_columns.append(con_copy)
|
||||
|
||||
for index in meta.tables[table_name].indexes:
|
||||
# If this is a single column index for a changed column, don't
|
||||
# copy it because we may already be creating a new version of
|
||||
# it (or removing it).
|
||||
idx_columns = [col.name for col in index.columns]
|
||||
if len(idx_columns)==1 and idx_columns[0] in changed_columns.keys():
|
||||
continue
|
||||
# Otherwise, recreate the index.
|
||||
indexes.append((index.name,
|
||||
table_name,
|
||||
[col.name for col in index.columns],
|
||||
index.unique))
|
||||
|
||||
# create temp table
|
||||
tmp_table_name = "%s_%s" % (table_name, six.text_type(uuid.uuid4()))
|
||||
op.create_table(tmp_table_name, *new_columns)
|
||||
meta.reflect()
|
||||
|
||||
try:
|
||||
# copy data from the old table to the temp one
|
||||
sql_select = sqlalchemy.sql.select(old_columns)
|
||||
connection.execute(sqlalchemy.sql.insert(meta.tables[tmp_table_name])
|
||||
.from_select(column_names, sql_select))
|
||||
except Exception:
|
||||
op.drop_table(tmp_table_name)
|
||||
raise
|
||||
|
||||
# drop the old table and rename temp table to the old table name
|
||||
op.drop_table(table_name)
|
||||
op.rename_table(tmp_table_name, table_name)
|
||||
|
||||
# (re-)create indexes
|
||||
for index in indexes:
|
||||
op.create_index(op.f(index[0]), index[1], index[2], unique=index[3])
|
Loading…
x
Reference in New Issue
Block a user