# HG changeset patch # User Daniele Nicolodi # Date 1318443886 -7200 # Node ID 9cccafa2c7539d978eab753b947ba1076d93bd87 # Parent 40fa8f9097769206c49601b65dcdeca245c27190 Tweak upgrade procedure to make it work on btlab databases. diff -r 40fa8f909776 -r 9cccafa2c753 src/ltpdarepo/upgrade.py --- a/src/ltpdarepo/upgrade.py Tue Oct 11 19:16:20 2011 +0200 +++ b/src/ltpdarepo/upgrade.py Wed Oct 12 20:24:46 2011 +0200 @@ -3,53 +3,71 @@ import MySQLdb as mysql +from ltpdarepo import SCHEMA from .config import HOSTNAME, DATABASE, USERNAME, PASSWORD # upgrade steps register -steps = [] +steps = {} def register(r0, r1, func=None): # register upgrade functions if func == None: return partial(register, r0, r1) - steps.append((r0, r1, func)) + steps[r0] = (r0, r1, func) return func -def upgrade(fromrev=None): +def upgrade(force=None): """run database schema upgrade steps""" + logger = logging.getLogger(__name__) conn = mysql.connect(host=HOSTNAME, db=DATABASE, user=USERNAME, passwd=PASSWORD, charset='utf8') curs = conn.cursor() - logger = logging.getLogger(__name__) # current schema version curs.execute("""SELECT value+0 FROM options WHERE name='version'""") - schema = curs.fetchone()[0] - - if fromrev is not None: - logger.info("force upgrade from v%s", schema) - schema = fromrev + current = curs.fetchone()[0] + logger.info("current database shema v%s", current) - # filter applicable upgrade steps - todo = filter(lambda x: x[0] >= schema, steps) + # allow to force upgrade from specific version + if force is not None: + current = force + logger.info("force upgrade from schema v%s", current) - # iter upgrade steps - for fromr, tor, step in sorted(todo): + while current != SCHEMA: + # next upgrade step + step = steps.get(current, None) + if step is None: + raise ValueError("no upgrade path from database shema v%s" % current) + fromr, tor, func = step # run upgrade step logger.info("upgrading database schema from v%s to v%s", fromr, tor) - step(conn) + func(conn) - # update schema version + # update current schema version + current = tor curs.execute("""UPDATE options SET value=%s - WHERE name='version'""", str(tor)) + WHERE name='version'""", str(current)) conn.commit() conn.close() +@register(2.3, 2.4) +def upgrade_23_24(conn): + curs = conn.cursor() + + # no idea why this table is here + curs.execute("DROP TABLE IF EXISTS bobjs") + + # unused so far and in the wrong incarnation + curs.execute("DROP TABLE IF EXISTS queries") + + conn.commit() + + @register(2.4, 2.5) def upgrade_24_to_25(conn): curs = conn.cursor() @@ -106,11 +124,19 @@ # crerate "queries" table curs.execute("""CREATE TABLE IF NOT EXISTS queries ( - id INT NOT NULL AUTO_INCREMENT, - title TEXT NOT NULL, - db TEXT NOT NULL, - query TEXT NOT NULL, - PRIMARY KEY (id)) CHARSET=utf8""") + id INT NOT NULL AUTO_INCREMENT, + title TEXT NOT NULL, + db TEXT NOT NULL, + query TEXT NOT NULL, + PRIMARY KEY (id)) CHARSET=utf8""") + + # add 'version' field to 'available_dbs' table if not already there + curs.execute("DESCRIBE available_dbs") + fields = [row[0] for row in curs.fetchall()] + if 'version' not in fields: + curs.execute("""ALTER TABLE available_dbs + ADD COLUMN version INT DEFAULT 1 + COMMENT 'database layout version'""") conn.commit() @@ -129,12 +155,21 @@ databases = [row[0] for row in curs.fetchall()] for db in databases: try: - # perform the big bad database schema upgrade - logger.info(" upgrading database %s", db) curs.execute("USE `%s`" % db) - _transmogrify(conn) + # detect dabases with hybrid schema version + curs.execute("DESCRIBE objmeta") + fields = [row[0] for row in curs.fetchall()] + if 'id' not in fields: + # perform schema upgrade from hybrid schema version + logger.info(" upgrading hybrid database %s", db) + hybrid(conn) + else: + # perform schema upgrade + logger.info(" upgrading database %s", db) + transmogrify(conn) except Exception: import traceback + logger.info(" FAILED!") traceback.print_exc() else: # update version information @@ -145,7 +180,7 @@ curs.execute("USE `%s`" % current) -def _transmogrify(conn): +def transmogrify(conn): """the big bad database schema upgrade""" logger = logging.getLogger(__name__) @@ -232,6 +267,7 @@ if table in ('collections', 'objs', 'transactions', 'users'): continue # add primary key + logger.info(" add primary key to table %s", table) curs.execute("ALTER TABLE %s ADD PRIMARY KEY (obj_id)" % table) # add foreign keys logger.info(" add foreign key to table %s", table) @@ -240,6 +276,50 @@ conn.commit() +def hybrid(conn): + """big bad database schema upgrade for hybrid tables""" + + logger = logging.getLogger(__name__) + curs = conn.cursor() + + # upgrade "xxir" tables + for table in ('mfir', 'miir'): + curs.execute("DESCRIBE %s" % table) + fields = [row[0] for row in curs.fetchall()] + if 'id' not in fields: + continue + # drop 'id' column + logger.info(" fix table %s", table) + curs.execute("ALTER TABLE %s MODIFY obj_id INT(11) UNSIGNED NOT NULL" % table) + curs.execute("ALTER TABLE %s DROP COLUMN id" % table) + + # upgrade "cdata" table + curs.execute("DESCRIBE cdata") + fields = [row[0] for row in curs.fetchall()] + if 'xunits' in fields: + logger.info(" fix table cdata") + curs.execute("ALTER TABLE cdata DROP COLUMN xunits") + + # for all tables + curs.execute("SHOW TABLES") + tables = [t[0] for t in curs.fetchall()] + for table in tables: + # except "objs", "collections" and "transactions" + if table in ('collections', 'objs', 'transactions', 'users'): + continue + # add primary key + curs.execute("DESCRIBE %s obj_id" % table) + row = curs.fetchone() + if row[3] != 'PRI': + logger.info(" add primary key to table %s", table) + curs.execute("ALTER TABLE %s ADD PRIMARY KEY (obj_id)" % table) + # add foreign keys + logger.info(" add foreign key to table %s", table) + curs.execute("""ALTER TABLE %s ADD FOREIGN KEY (obj_id) + REFERENCES objs(id) ON DELETE CASCADE""" % table) + conn.commit() + + @register(2.7, 2.8) def upgrade_27_to_28(conn): curs = conn.cursor()