# HG changeset patch # User Sylvain Thénault # Date 1466438400 -7200 # Node ID ebe75d73acddc3b66fa30bc2e4c9f4d2428864a6 # Parent 5a857bba1b794210703029f2d46d214d975ac6f6 [schema sync] Rename index when an entity type is renamed So we may still find them later using their expected name, and avoid collisions. Closes #13822045 diff -r 5a857bba1b79 -r ebe75d73acdd cubicweb/hooks/syncschema.py --- a/cubicweb/hooks/syncschema.py Fri Jun 17 13:26:13 2016 +0200 +++ b/cubicweb/hooks/syncschema.py Mon Jun 20 18:00:00 2016 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -31,6 +31,7 @@ from hashlib import md5 from yams.schema import BASE_TYPES, BadSchemaDefinition, RelationDefinitionSchema +from yams.constraints import UniqueConstraint from yams import buildobjs as ybo, convert_default_value from logilab.common.decorators import clear_cache @@ -41,6 +42,7 @@ CONSTRAINTS, UNIQUE_CONSTRAINTS, ETYPE_NAME_MAP) from cubicweb.server import hook, schemaserial as ss, schema2sql as y2sql from cubicweb.server.sqlutils import SQL_PREFIX +from cubicweb.server.schema2sql import unique_index_name from cubicweb.hooks.synccomputed import RecomputeAttributeOperation # core entity and relation types which can't be removed @@ -291,19 +293,47 @@ oldname = newname = None # make pylint happy def rename(self, oldname, newname): - self.cnx.vreg.schema.rename_entity_type(oldname, newname) + cnx = self.cnx + source = cnx.repo.system_source + dbhelper = source.dbhelper # we need sql to operate physical changes on the system database - sqlexec = self.cnx.system_sql - dbhelper = self.cnx.repo.system_source.dbhelper - sql = dbhelper.sql_rename_table(SQL_PREFIX+oldname, - SQL_PREFIX+newname) + sqlexec = cnx.system_sql + cnx.vreg.schema.rename_entity_type(oldname, newname) + old_table = SQL_PREFIX + oldname + new_table = SQL_PREFIX + newname + eschema = cnx.vreg.schema.eschema(newname) + # drop old indexes before the renaming + for rschema in eschema.subject_relations(): + if rschema.inlined or (rschema.final and eschema.rdef(rschema.type).indexed): + source.drop_index(cnx, old_table, SQL_PREFIX + rschema.type) + if rschema.final and any(isinstance(cstr, UniqueConstraint) + for cstr in eschema.rdef(rschema.type).constraints): + source.drop_index(cnx, old_table, SQL_PREFIX + rschema.type, unique=True) + sql = dbhelper.sql_rename_table(old_table, new_table) sqlexec(sql) self.info('renamed table %s to %s', oldname, newname) sqlexec('UPDATE entities SET type=%(newname)s WHERE type=%(oldname)s', {'newname': newname, 'oldname': oldname}) - for eid, (etype, extid, auri) in self.cnx.repo._type_source_cache.items(): + for eid, (etype, extid, auri) in cnx.repo._type_source_cache.items(): if etype == oldname: - self.cnx.repo._type_source_cache[eid] = (newname, extid, auri) + cnx.repo._type_source_cache[eid] = (newname, extid, auri) + # recreate the indexes + for rschema in eschema.subject_relations(): + if rschema.inlined or (rschema.final and eschema.rdef(rschema.type).indexed): + source.create_index(cnx, new_table, SQL_PREFIX + rschema.type) + if rschema.final and any(isinstance(cstr, UniqueConstraint) + for cstr in eschema.rdef(rschema.type).constraints): + source.create_index(cnx, new_table, SQL_PREFIX + rschema.type, unique=True) + for attrs in eschema._unique_together or (): + columns = ['%s%s' % (SQL_PREFIX, attr) for attr in attrs] + old_index_name = unique_index_name(oldname, columns) + for sql in dbhelper.sqls_drop_multicol_unique_index( + new_table, columns, old_index_name): + sqlexec(sql) + new_index_name = unique_index_name(newname, columns) + for sql in dbhelper.sqls_create_multicol_unique_index( + new_table, columns, new_index_name): + sqlexec(sql) # XXX transaction records def precommit_event(self): diff -r 5a857bba1b79 -r ebe75d73acdd cubicweb/server/schema2sql.py --- a/cubicweb/server/schema2sql.py Fri Jun 17 13:26:13 2016 +0200 +++ b/cubicweb/server/schema2sql.py Mon Jun 20 18:00:00 2016 +0200 @@ -111,8 +111,10 @@ def unique_index_name(eschema, columns): + # keep giving eschema instead of table name for bw compat + table = text_type(eschema) # unique_index_name is used as name of CWUniqueConstraint, hence it should be unicode - return text_type(build_index_name(eschema.type, columns, 'unique_')) + return text_type(build_index_name(table, columns, 'unique_')) def iter_unique_index_names(eschema): diff -r 5a857bba1b79 -r ebe75d73acdd cubicweb/server/test/data-migractions/migratedapp/schema.py --- a/cubicweb/server/test/data-migractions/migratedapp/schema.py Fri Jun 17 13:26:13 2016 +0200 +++ b/cubicweb/server/test/data-migractions/migratedapp/schema.py Mon Jun 20 18:00:00 2016 +0200 @@ -205,7 +205,7 @@ # New class New(EntityType): - new_name = String() + new_name = String(indexed=True, unique=True) # New class same_as(RelationDefinition): diff -r 5a857bba1b79 -r ebe75d73acdd cubicweb/server/test/data-migractions/schema.py --- a/cubicweb/server/test/data-migractions/schema.py Fri Jun 17 13:26:13 2016 +0200 +++ b/cubicweb/server/test/data-migractions/schema.py Mon Jun 20 18:00:00 2016 +0200 @@ -162,7 +162,7 @@ 'read' : ('managers', 'users', 'guests'), 'add' : ('managers', 'users', 'guests'), 'update' : () - }) + }, indexed=True, unique=True) class connait(RelationType): diff -r 5a857bba1b79 -r ebe75d73acdd cubicweb/server/test/unittest_migractions.py --- a/cubicweb/server/test/unittest_migractions.py Fri Jun 17 13:26:13 2016 +0200 +++ b/cubicweb/server/test/unittest_migractions.py Mon Jun 20 18:00:00 2016 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -35,6 +35,7 @@ from cubicweb.server.sqlutils import SQL_PREFIX from cubicweb.server.migractions import ServerMigrationHelper from cubicweb.server.sources import storages +from cubicweb.server.schema2sql import build_index_name import cubicweb.devtools @@ -340,7 +341,18 @@ entity = mh.create_entity('Old', name=u'old') self.repo.type_and_source_from_eid(entity.eid, entity._cw) mh.cmd_rename_entity_type('Old', 'New') + dbh = self.repo.system_source.dbhelper + indices = set(dbh.list_indices(cnx.cnxset.cu, 'cw_New')) + self.assertNotIn(build_index_name('cw_Old', ['cw_name']), indices) + self.assertIn(build_index_name('cw_New', ['cw_name']), indices) mh.cmd_rename_attribute('New', 'name', 'new_name') + indices = set(dbh.list_indices(cnx.cnxset.cu, 'cw_New')) + # check 'indexed' index + self.assertNotIn(build_index_name('cw_New', ['cw_name'], 'idx_'), indices) + self.assertIn(build_index_name('cw_New', ['cw_new_name'], 'idx_'), indices) + # check 'unique' index + self.assertNotIn(build_index_name('cw_New', ['cw_name'], 'key_'), indices) + self.assertIn(build_index_name('cw_New', ['cw_new_name'], 'key_'), indices) def test_add_drop_relation_type(self): with self.mh() as (cnx, mh):