driver=config.sources()['system']['db-driver']ifnot(driver=='postgres'ordriver.startswith('sqlserver')):importsysprint>>sys.stderr,'This migration is not supported for backends other than sqlserver or postgres (yet).'sys.exit(1)add_relation_definition('CWAttribute','add_permission','CWGroup')add_relation_definition('CWAttribute','add_permission','RQLExpression')# a bad defaultval in 3.13.8 schema was fixed in 3.13.9, but the migration was missedrql('SET ATTR defaultval NULL WHERE ATTR from_entity E, E name "CWSource", ATTR relation_type T, T name "in_synchronization"')# the migration gets confused when we change rdefs out from under it. So# explicitly remove this size constraint so it doesn't stick around and break# things later.rdefeid=schema['defaultval'].rdefs.values()[0].eidrql('DELETE CWConstraint C WHERE C cstrtype T, T name "SizeConstraint", R constrained_by C, R eid %(eid)s',{'eid':rdefeid})sync_schema_props_perms('defaultval')defconvert_defaultval(cwattr,default):fromdecimalimportDecimalimportyamsfromcubicwebimportBinaryifdefaultisNone:returnifisinstance(default,Binary):# partially migrated instance, try to be idempotentreturndefaultatype=cwattr.to_entity[0].nameifatype=='Boolean':# boolean attributes with default=False were stored as ''assertdefaultin('True','False',''),repr(default)default=default=='True'elifatypein('Int','BigInt'):default=int(default)elifatype=='Float':default=float(default)elifatype=='Decimal':default=Decimal(default)elifatypein('Date','Datetime','TZDatetime','Time'):try:# handle NOW and TODAY, keep them stored as stringsyams.KEYWORD_MAP[atype][default.upper()]default=default.upper()exceptKeyError:# otherwise get an actual date or datetimedefault=yams.DATE_FACTORY_MAP[atype](default)else:assertatype=='String',atypedefault=unicode(default)returnBinary.zpickle(default)dbh=repo.system_source.dbhelpersql('ALTER TABLE cw_cwattribute ADD new_defaultval %s'%dbh.TYPE_MAPPING['Bytes'])forcwattrinrql('CWAttribute X').entities():olddefault=cwattr.defaultvalifolddefaultisnotNone:req="UPDATE cw_cwattribute SET new_defaultval = %(val)s WHERE cw_eid = %(eid)s"args={'val':dbh.binary_value(convert_defaultval(cwattr,olddefault).getvalue()),'eid':cwattr.eid}sql(req,args,ask_confirm=False)sql('ALTER TABLE cw_cwattribute DROP COLUMN cw_defaultval')ifdriver=='postgres':sql('ALTER TABLE cw_cwattribute RENAME COLUMN new_defaultval TO cw_defaultval')else:# sqlserversql("sp_rename 'cw_cwattribute.new_defaultval', 'cw_defaultval', 'COLUMN'")# Set object type to "Bytes" for CWAttribute's "defaultval" attributerql('SET X to_entity B WHERE X is CWAttribute, X from_entity Y, Y name "CWAttribute", ''X relation_type Z, Z name "defaultval", B name "Bytes", NOT X to_entity B')oldrdef=schema['CWAttribute'].rdef('defaultval')importyams.buildobjsasybonewrdef=ybo.RelationDefinition('CWAttribute','defaultval','Bytes')newrdef.eid=oldrdef.eidschema.add_relation_def(newrdef)schema.del_relation_def('CWAttribute','defaultval','String')commit()sync_schema_props_perms('defaultval')forrschemainschema.relations():ifrschema.symmetric:subjects=set(repr(e.type)foreinrschema.subjects())objects=set(repr(e.type)foreinrschema.objects())assertsubjects==objectsmartians=set(str(eid)foreid,insql('SELECT eid_to FROM %s_relation, entities WHERE eid_to = eid AND type NOT IN (%s)'%(rschema.type,','.join(subjects))))martians|=set(str(eid)foreid,insql('SELECT eid_from FROM %s_relation, entities WHERE eid_from = eid AND type NOT IN (%s)'%(rschema.type,','.join(subjects))))ifmartians:martians=','.join(martians)print'deleting broken relations %s for eids %s'%(rschema.type,martians)sql('DELETE FROM %s_relation WHERE eid_from IN (%s) OR eid_to IN (%s)'%(rschema.type,martians,martians))withsession.deny_all_hooks_but():rql('SET X %(r)s Y WHERE Y %(r)s X, NOT X %(r)s Y'%{'r':rschema.type})commit()# multi columns unique constraints regenerationfromcubicweb.serverimportschemaserial# syncschema hooks would try to remove indices but# 1) we already do that below# 2) the hook expects the CWUniqueTogetherConstraint.name attribute that hasn't# yet been addedwithsession.allow_all_hooks_but('syncschema'):rql('DELETE CWUniqueTogetherConstraint C')commit()add_attribute('CWUniqueTogetherConstraint','name')# low-level wipe code for postgres & sqlserver, plain sql ...ifdriver=='postgres':forindexname,insql('select indexname from pg_indexes'):ifindexname.startswith('unique_'):print'dropping index',indexnamesql('DROP INDEX %s'%indexname)commit()elifdriver.startswith('sqlserver'):forviewname,insql('select name from sys.views'):ifviewname.startswith('utv_'):print'dropping view (index should be cascade-deleted)',viewnamesql('DROP VIEW %s'%viewname)commit()# recreate the constraints, hook will lead to low-level recreationforeschemainsorted(schema.entities()):ifeschema._unique_together:rql_args=schemaserial.uniquetogether2rqls(eschema)forrql,argsinrql_args:args['x']=eschema.eidsession.execute(rql,args)commit()# all attributes perms have to be refreshed ...forrschemainschema.relations():ifrschema.final:ifrschema.typeinfsschema:sync_schema_props_perms(rschema.type,syncprops=False,ask_confirm=False)else:print'WARNING: attribute %s missing from fs schema'%rschema.type