172
168
sqlite.SQLiteConstraintGenerator)
175
def db_sync(abs_path, version=None, init_version=0):
171
def db_sync(engine, abs_path, version=None, init_version=0, sanity_check=True):
176
172
"""Upgrade or downgrade a database.
178
174
Function runs the upgrade() or downgrade() functions in change scripts.
176
:param engine: SQLAlchemy engine instance for a given database
180
177
:param abs_path: Absolute path to migrate repository.
181
178
:param version: Database will upgrade/downgrade until this version.
182
179
If None - database will update to the latest
183
180
available version.
184
181
:param init_version: Initial database version
182
:param sanity_check: Require schema sanity checking for all tables
186
185
if version is not None:
188
187
version = int(version)
190
189
raise exception.DbMigrationError(
191
190
message=_("version should be an integer"))
193
current_version = db_version(abs_path, init_version)
192
current_version = db_version(engine, abs_path, init_version)
194
193
repository = _find_migrate_repo(abs_path)
195
_db_schema_sanity_check()
195
_db_schema_sanity_check(engine)
196
196
if version is None or version > current_version:
197
return versioning_api.upgrade(get_engine(), repository, version)
197
return versioning_api.upgrade(engine, repository, version)
199
return versioning_api.downgrade(get_engine(), repository,
199
return versioning_api.downgrade(engine, repository,
203
def _db_schema_sanity_check():
204
engine = get_engine()
203
def _db_schema_sanity_check(engine):
204
"""Ensure all database tables were created with required parameters.
206
:param engine: SQLAlchemy engine instance for a given database
205
210
if engine.name == 'mysql':
206
211
onlyutf8_sql = ('SELECT TABLE_NAME,TABLE_COLLATION '
207
212
'from information_schema.TABLES '
208
213
'where TABLE_SCHEMA=%s and '
209
214
'TABLE_COLLATION NOT LIKE "%%utf8%%"')
211
table_names = [res[0] for res in engine.execute(onlyutf8_sql,
212
engine.url.database)]
216
# NOTE(morganfainberg): exclude the sqlalchemy-migrate and alembic
217
# versioning tables from the tables we need to verify utf8 status on.
218
# Non-standard table names are not supported.
219
EXCLUDED_TABLES = ['migrate_version', 'alembic_version']
221
table_names = [res[0] for res in
222
engine.execute(onlyutf8_sql, engine.url.database) if
223
res[0].lower() not in EXCLUDED_TABLES]
213
225
if len(table_names) > 0:
214
226
raise ValueError(_('Tables "%s" have non utf8 collation, '
215
227
'please make sure all tables are CHARSET=utf8'
216
228
) % ','.join(table_names))
219
def db_version(abs_path, init_version):
231
def db_version(engine, abs_path, init_version):
220
232
"""Show the current version of the repository.
234
:param engine: SQLAlchemy engine instance for a given database
222
235
:param abs_path: Absolute path to migrate repository
223
236
:param version: Initial database version
225
238
repository = _find_migrate_repo(abs_path)
227
return versioning_api.db_version(get_engine(), repository)
240
return versioning_api.db_version(engine, repository)
228
241
except versioning_exceptions.DatabaseNotControlledError:
229
242
meta = sqlalchemy.MetaData()
230
engine = get_engine()
231
243
meta.reflect(bind=engine)
232
244
tables = meta.tables
233
245
if len(tables) == 0 or 'alembic_version' in tables:
234
db_version_control(abs_path, init_version)
235
return versioning_api.db_version(get_engine(), repository)
246
db_version_control(engine, abs_path, version=init_version)
247
return versioning_api.db_version(engine, repository)
237
249
raise exception.DbMigrationError(
244
def db_version_control(abs_path, version=None):
256
def db_version_control(engine, abs_path, version=None):
245
257
"""Mark a database as under this repository's version control.
247
259
Once a database is under version control, schema changes should
248
260
only be done via change scripts in this repository.
262
:param engine: SQLAlchemy engine instance for a given database
250
263
:param abs_path: Absolute path to migrate repository
251
264
:param version: Initial database version
253
266
repository = _find_migrate_repo(abs_path)
254
versioning_api.version_control(get_engine(), repository, version)
267
versioning_api.version_control(engine, repository, version)