Skip to content

Commit

Permalink
Simplify and unify table creation for MySQL and PostgreSQL
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Jul 9, 2019
1 parent 0bbfa0e commit cc922d5
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 341 deletions.
30 changes: 16 additions & 14 deletions src/relstorage/adapters/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,37 @@

def query_property(base_name,
extension='',
formatted=False):
formatted=False,
property_suffix='_queries',
lazy_suffix='_query'):
"""
Defines a property that adapts to preserving or dropping history.
To use, define a property ending in `_queries` that is a
two-tuple, where the preserving query comes first and the dropping
query comes second. This indirection lets subclasses override
these queries.
To use, define a property ending in ``_queries``
*property_suffix*) that is a two-tuple, where the preserving query
comes first and the dropping query comes second. This indirection
lets subclasses override these queries.
Then define a property, passing the base name (without _queries)
to this function.
Then define a property, passing the base name (without
``_queries``) to this function.
The correct query will be lazily picked at runtime. The instance
must have the ``keep_history`` attribute.
If the chosen query is an exception instance or class, it will be raised
instead of returned. This allows defining a query that is only
supported in one of the two modes. Usually, this exception should be
:class:`ZODB.POSException.Unsupported`.
If the chosen query is an exception instance or class, it will be
raised instead of returned. This allows defining a query that is
only supported in one of the two modes. Usually, this exception
should be :class:`ZODB.POSException.Unsupported`.
:keyword str extension: This string will be appended to whatever
query is chosen before it is formatted and before it is returned.
:keyword bool formatted: If True (*not* the default), then the
chosen query will be formatted using the
``self.runner.script_vars``.
``self.runner.script_vars``.
"""

def prop(inst):
queries = getattr(inst, base_name + '_queries')
queries = getattr(inst, base_name + property_suffix)
query = queries[0] if inst.keep_history else queries[1]
if isinstance(query, Exception) or (
isinstance(query, type)
Expand All @@ -68,7 +70,7 @@ def prop(inst):

prop.__doc__ = "Query for " + base_name

return Lazy(prop, base_name + '_query')
return Lazy(prop, base_name + lazy_suffix)

formatted_query_property = partial(query_property, formatted=True)

Expand Down
159 changes: 7 additions & 152 deletions src/relstorage/adapters/mysql/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@
class MySQLSchemaInstaller(AbstractSchemaInstaller):

database_type = 'mysql'
COLTYPE_BINARY_STRING = 'BLOB'
TRANSACTIONAL_TABLE_SUFFIX = 'ENGINE = InnoDB'
COLTYPE_MD5 = 'CHAR(32) CHARACTER SET ascii'
COLTYPE_STATE = 'LONGBLOB'
COLTYPE_BLOB_CHUNK = 'LONGBLOB'


# The names of tables that in the past were explicitly declared as
# MyISAM but which should now be InnoDB to work with transactions.
# TODO: Add a migration check for this.
# TODO: Add a migration check and fix this.
tables_that_used_to_be_myisam_should_be_innodb = (
# new_oid, # (This needs to be done, but we're not quite there yet)
'object_ref',
Expand Down Expand Up @@ -69,9 +75,6 @@ def check_compatibility(self, cursor, tables):
def _create_pack_lock(self, cursor):
return

COLTYPE_BINARY_STRING = 'BLOB'
TRANSACTIONAL_TABLE_SUFFIX = 'ENGINE = InnoDB'

# As usual, MySQL has a quirky implementation of this feature and we
# have to re-specify *everything* about the column. MySQL 8 supports the
# simple 'RENAME ... TO ...' syntax that everyone else does.
Expand All @@ -89,154 +92,6 @@ def _create_new_oid(self, cursor):
"""
self.runner.run_script(cursor, stmt)


def _create_object_state(self, cursor):
if self.keep_history:
stmt = """
CREATE TABLE object_state (
zoid BIGINT NOT NULL,
tid BIGINT NOT NULL REFERENCES transaction,
PRIMARY KEY (zoid, tid),
CHECK (tid > 0),
prev_tid BIGINT NOT NULL REFERENCES transaction,
md5 CHAR(32) CHARACTER SET ascii,
state_size BIGINT NOT NULL,
state LONGBLOB
) ENGINE = InnoDB;
CREATE INDEX object_state_tid ON object_state (tid);
CREATE INDEX object_state_prev_tid ON object_state (prev_tid);
"""
else:
stmt = """
CREATE TABLE object_state (
zoid BIGINT NOT NULL PRIMARY KEY,
tid BIGINT NOT NULL,
CHECK (tid > 0),
state_size BIGINT NOT NULL,
state LONGBLOB
) ENGINE = InnoDB;
CREATE INDEX object_state_tid ON object_state (tid);
"""

self.runner.run_script(cursor, stmt)

def _create_blob_chunk(self, cursor):
if self.keep_history:
stmt = """
CREATE TABLE blob_chunk (
zoid BIGINT NOT NULL,
tid BIGINT NOT NULL,
chunk_num BIGINT NOT NULL,
PRIMARY KEY (zoid, tid, chunk_num),
chunk LONGBLOB NOT NULL
) ENGINE = InnoDB;
CREATE INDEX blob_chunk_lookup ON blob_chunk (zoid, tid);
ALTER TABLE blob_chunk ADD CONSTRAINT blob_chunk_fk
FOREIGN KEY (zoid, tid)
REFERENCES object_state (zoid, tid)
ON DELETE CASCADE;
"""
else:
stmt = """
CREATE TABLE blob_chunk (
zoid BIGINT NOT NULL,
chunk_num BIGINT NOT NULL,
PRIMARY KEY (zoid, chunk_num),
tid BIGINT NOT NULL,
chunk LONGBLOB NOT NULL
) ENGINE = InnoDB;
CREATE INDEX blob_chunk_lookup ON blob_chunk (zoid);
ALTER TABLE blob_chunk ADD CONSTRAINT blob_chunk_fk
FOREIGN KEY (zoid)
REFERENCES object_state (zoid)
ON DELETE CASCADE;
"""

self.runner.run_script(cursor, stmt)

def _create_current_object(self, cursor):
if self.keep_history:
stmt = """
CREATE TABLE current_object (
zoid BIGINT NOT NULL PRIMARY KEY,
tid BIGINT NOT NULL,
FOREIGN KEY (zoid, tid)
REFERENCES object_state (zoid, tid)
) ENGINE = InnoDB;
CREATE INDEX current_object_tid ON current_object (tid);
"""
self.runner.run_script(cursor, stmt)

def _create_object_ref(self, cursor):
if self.keep_history:
stmt = """
CREATE TABLE object_ref (
zoid BIGINT NOT NULL,
tid BIGINT NOT NULL,
to_zoid BIGINT NOT NULL,
PRIMARY KEY (tid, zoid, to_zoid)
) ENGINE = InnoDB;
"""
else:
stmt = """
CREATE TABLE object_ref (
zoid BIGINT NOT NULL,
to_zoid BIGINT NOT NULL,
tid BIGINT NOT NULL,
PRIMARY KEY (zoid, to_zoid)
) ENGINE = InnoDB;
"""

self.runner.run_script(cursor, stmt)

def _create_object_refs_added(self, cursor):
if self.keep_history:
stmt = """
CREATE TABLE object_refs_added (
tid BIGINT NOT NULL PRIMARY KEY
) ENGINE = InnoDB;
"""
else:
stmt = """
CREATE TABLE object_refs_added (
zoid BIGINT NOT NULL PRIMARY KEY,
tid BIGINT NOT NULL
) ENGINE = InnoDB;
"""
self.runner.run_script(cursor, stmt)

def _create_pack_object(self, cursor):
stmt = """
CREATE TABLE pack_object (
zoid BIGINT NOT NULL PRIMARY KEY,
keep BOOLEAN NOT NULL,
keep_tid BIGINT NOT NULL,
visited BOOLEAN NOT NULL DEFAULT FALSE
) ENGINE = InnoDB;
CREATE INDEX pack_object_keep_zoid ON pack_object (keep, zoid);
"""
self.runner.run_script(cursor, stmt)

def _create_pack_state(self, cursor):
if self.keep_history:
stmt = """
CREATE TABLE pack_state (
tid BIGINT NOT NULL,
zoid BIGINT NOT NULL,
PRIMARY KEY (tid, zoid)
) ENGINE = InnoDB;
"""
self.runner.run_script(cursor, stmt)

def _create_pack_state_tid(self, cursor):
if self.keep_history:
stmt = """
CREATE TABLE pack_state_tid (
tid BIGINT NOT NULL PRIMARY KEY
) ENGINE = InnoDB;
"""
self.runner.run_script(cursor, stmt)

# Temp tables are created in a session-by-session basis
def _create_temp_store(self, _cursor):
return
Expand Down

0 comments on commit cc922d5

Please sign in to comment.