From 2e2adb3935bcbf9dc6e100c4ba9a8e1b4bf3a4e6 Mon Sep 17 00:00:00 2001 From: Mike Fedosin Date: Wed, 16 Dec 2015 17:05:45 +0300 Subject: [PATCH] Fix model sync for SQLite This code fixes the situation when several models are mismatched for SQLite because of type inconsistencies between Integer and BigInteger in sqlalchemy. Change-Id: I52b3a0158db8e3dc48f19509d1f9f80420ee40ea Closes-bug: #1526804 Closes-bug: #1526675 --- glance/db/sqlalchemy/api.py | 4 ++++ glance/db/sqlalchemy/models.py | 10 ++-------- glance/db/sqlalchemy/models_artifacts.py | 9 ++++++--- glance/tests/unit/test_migrations.py | 23 +++++++++++++++++++++++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/glance/db/sqlalchemy/api.py b/glance/db/sqlalchemy/api.py index dde26fd77e..2092dcf11c 100644 --- a/glance/db/sqlalchemy/api.py +++ b/glance/db/sqlalchemy/api.py @@ -303,6 +303,10 @@ def _get_default_column_value(column_type): 'integer': 0, 'string': '' } + + if isinstance(column_type, sa_sql.type_api.Variant): + return _get_default_column_value(column_type.impl) + return type_schema[column_type.__visit_name__] diff --git a/glance/db/sqlalchemy/models.py b/glance/db/sqlalchemy/models.py index 1d3526fd68..bf953de098 100644 --- a/glance/db/sqlalchemy/models.py +++ b/glance/db/sqlalchemy/models.py @@ -26,7 +26,6 @@ from sqlalchemy import BigInteger from sqlalchemy import Boolean from sqlalchemy import Column from sqlalchemy import DateTime -from sqlalchemy.ext.compiler import compiles from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import ForeignKey from sqlalchemy import Index @@ -44,11 +43,6 @@ from glance.common import timeutils BASE = declarative_base() -@compiles(BigInteger, 'sqlite') -def compile_big_int_sqlite(type_, compiler, **kw): - return 'INTEGER' - - class JSONEncodedDict(TypeDecorator): """Represents an immutable structure as a json-encoded string""" @@ -131,8 +125,8 @@ class Image(BASE, GlanceBase): name = Column(String(255)) disk_format = Column(String(20)) container_format = Column(String(20)) - size = Column(BigInteger) - virtual_size = Column(BigInteger) + size = Column(BigInteger().with_variant(Integer, "sqlite")) + virtual_size = Column(BigInteger().with_variant(Integer, "sqlite")) status = Column(String(30), nullable=False) is_public = Column(Boolean, nullable=False, default=False) checksum = Column(String(32)) diff --git a/glance/db/sqlalchemy/models_artifacts.py b/glance/db/sqlalchemy/models_artifacts.py index 4b1ed4b745..191be44390 100644 --- a/glance/db/sqlalchemy/models_artifacts.py +++ b/glance/db/sqlalchemy/models_artifacts.py @@ -109,13 +109,15 @@ class Artifact(BASE, ArtifactBase): default=lambda: str(uuid.uuid4())) name = Column(String(255), nullable=False) type_name = Column(String(255), nullable=False) - type_version_prefix = Column(BigInteger, nullable=False) + type_version_prefix = Column(BigInteger().with_variant(Integer, "sqlite"), + nullable=False) type_version_suffix = Column(String(255)) type_version_meta = Column(String(255)) type_version = composite(semver_db.DBVersion, type_version_prefix, type_version_suffix, type_version_meta, comparator_factory=semver_db.VersionComparator) - version_prefix = Column(BigInteger, nullable=False) + version_prefix = Column(BigInteger().with_variant(Integer, "sqlite"), + nullable=False) version_suffix = Column(String(255)) version_meta = Column(String(255)) version = composite(semver_db.DBVersion, version_prefix, @@ -294,7 +296,8 @@ class ArtifactBlob(BASE, ArtifactBase): nullable=False) name = Column(String(255), nullable=False) item_key = Column(String(329)) - size = Column(BigInteger(), nullable=False) + size = Column(BigInteger().with_variant(Integer, "sqlite"), + nullable=False) checksum = Column(String(32)) position = Column(Integer) artifact = relationship(Artifact, diff --git a/glance/tests/unit/test_migrations.py b/glance/tests/unit/test_migrations.py index d20241dc48..6bee2bf4dd 100644 --- a/glance/tests/unit/test_migrations.py +++ b/glance/tests/unit/test_migrations.py @@ -42,6 +42,7 @@ from oslo_utils import uuidutils from six.moves import range import sqlalchemy from sqlalchemy import inspect +import sqlalchemy.types as types from glance.common import crypt from glance.common import exception @@ -1887,6 +1888,28 @@ class ModelsMigrationSyncMixin(object): def db_sync(self, engine): migration.db_sync(engine=engine) + # TODO(akamyshikova): remove this method as soon as comparison with Variant + # will be implemented in oslo.db or alembic + def compare_type(self, ctxt, insp_col, meta_col, insp_type, meta_type): + if isinstance(meta_type, types.Variant): + meta_orig_type = meta_col.type + insp_orig_type = insp_col.type + meta_col.type = meta_type.impl + insp_col.type = meta_type.impl + + try: + return self.compare_type(ctxt, insp_col, meta_col, insp_type, + meta_type.impl) + finally: + meta_col.type = meta_orig_type + insp_col.type = insp_orig_type + else: + ret = super(ModelsMigrationSyncMixin, self).compare_type( + ctxt, insp_col, meta_col, insp_type, meta_type) + if ret is not None: + return ret + return ctxt.impl.compare_type(insp_col, meta_col) + def include_object(self, object_, name, type_, reflected, compare_to): if name in ['migrate_version'] and type_ == 'table': return False