misc/migration/3.18.0_Any.py
changeset 9402 2c48c091b6a2
parent 9395 96dba2efd16d
child 9406 38debfa8b536
child 9460 a2a0bc984863
equal deleted inserted replaced
9127:aff75b69db92 9402:2c48c091b6a2
       
     1 driver = config.sources()['system']['db-driver']
       
     2 if not (driver == 'postgres' or driver.startswith('sqlserver')):
       
     3     import sys
       
     4     print >>sys.stderr, 'This migration is not supported for backends other than sqlserver or postgres (yet).'
       
     5     sys.exit(1)
       
     6 
       
     7 sync_schema_props_perms('defaultval')
       
     8 
       
     9 def convert_defaultval(cwattr, default):
       
    10     from decimal import Decimal
       
    11     import yams
       
    12     from cubicweb import Binary
       
    13     if default is None:
       
    14         return
       
    15     atype = cwattr.to_entity[0].name
       
    16     if atype == 'Boolean':
       
    17         # boolean attributes with default=False were stored as ''
       
    18         assert default in ('True', 'False', ''), repr(default)
       
    19         default = default == 'True'
       
    20     elif atype in ('Int', 'BigInt'):
       
    21         default = int(default)
       
    22     elif atype == 'Float':
       
    23         default = float(default)
       
    24     elif atype == 'Decimal':
       
    25         default = Decimal(default)
       
    26     elif atype in ('Date', 'Datetime', 'TZDatetime', 'Time'):
       
    27         try:
       
    28             # handle NOW and TODAY, keep them stored as strings
       
    29             yams.KEYWORD_MAP[atype][default.upper()]
       
    30             default = default.upper()
       
    31         except KeyError:
       
    32             # otherwise get an actual date or datetime
       
    33             default = yams.DATE_FACTORY_MAP[atype](default)
       
    34     else:
       
    35         assert atype == 'String', atype
       
    36         default = unicode(default)
       
    37     return Binary.zpickle(default)
       
    38 
       
    39 dbh = repo.system_source.dbhelper
       
    40 
       
    41 
       
    42 sql('ALTER TABLE cw_cwattribute ADD new_defaultval %s' % dbh.TYPE_MAPPING['Bytes'])
       
    43 
       
    44 for cwattr in rql('CWAttribute X').entities():
       
    45     olddefault = cwattr.defaultval
       
    46     if olddefault is not None:
       
    47         req = "UPDATE cw_cwattribute SET new_defaultval = %(val)s WHERE cw_eid = %(eid)s"
       
    48         args = {'val': dbh.binary_value(convert_defaultval(cwattr, olddefault).getvalue()), 'eid': cwattr.eid}
       
    49         sql(req, args, ask_confirm=False)
       
    50 
       
    51 sql('ALTER TABLE cw_cwattribute DROP COLUMN cw_defaultval')
       
    52 if driver == 'postgres':
       
    53     sql('ALTER TABLE cw_cwattribute RENAME COLUMN new_defaultval TO cw_defaultval')
       
    54 else: # sqlserver
       
    55     sql("sp_rename 'cw_cwattribute.new_defaultval', 'cw_defaultval', 'COLUMN'")
       
    56 
       
    57 
       
    58 # Set object type to "Bytes" for CWAttribute's "defaultval" attribute
       
    59 rql('SET X to_entity B WHERE X is CWAttribute, X from_entity Y, Y name "CWAttribute", '
       
    60     'X relation_type Z, Z name "defaultval", B name "Bytes"')
       
    61 
       
    62 from yams import buildobjs as ybo
       
    63 schema.add_relation_def(ybo.RelationDefinition('CWAttribute', 'defaultval', 'Bytes'))
       
    64 schema.del_relation_def('CWAttribute', 'defaultval', 'String')
       
    65 
       
    66 commit()
       
    67 
       
    68 for rschema in schema.relations():
       
    69     if rschema.symmetric:
       
    70         subjects = set(repr(e.type) for e in rschema.subjects())
       
    71         objects = set(repr(e.type) for e in rschema.objects())
       
    72         assert subjects == objects
       
    73         martians = set(str(eid) for eid, in sql('SELECT eid_to FROM %s_relation, entities WHERE eid_to = eid AND type NOT IN (%s)' %
       
    74                                            (rschema.type, ','.join(subjects))))
       
    75         martians |= set(str(eid) for eid, in sql('SELECT eid_from FROM %s_relation, entities WHERE eid_from = eid AND type NOT IN (%s)' %
       
    76                                             (rschema.type, ','.join(subjects))))
       
    77         if martians:
       
    78             martians = ','.join(martians)
       
    79             print 'deleting broken relations %s for eids %s' % (rschema.type, martians)
       
    80             sql('DELETE FROM %s_relation WHERE eid_from IN (%s) OR eid_to IN (%s)' % (rschema.type, martians, martians))
       
    81         with session.deny_all_hooks_but():
       
    82             rql('SET X %(r)s Y WHERE Y %(r)s X, NOT X %(r)s Y' % {'r': rschema.type})
       
    83     commit()
       
    84 
       
    85 
       
    86 # multi columns unique constraints regeneration
       
    87 from cubicweb.server import schemaserial
       
    88 
       
    89 # syncschema hooks would try to remove indices but
       
    90 # 1) we already do that below
       
    91 # 2) the hook expects the CWUniqueTogetherConstraint.name attribute that hasn't
       
    92 #    yet been added
       
    93 with session.allow_all_hooks_but('syncschema'):
       
    94     rql('DELETE CWUniqueTogetherConstraint C')
       
    95 commit()
       
    96 
       
    97 add_attribute('CWUniqueTogetherConstraint', 'name')
       
    98 
       
    99 # low-level wipe code for postgres & sqlserver, plain sql ...
       
   100 if driver == 'postgres':
       
   101     for indexname, in sql('select indexname from pg_indexes'):
       
   102         if indexname.startswith('unique_'):
       
   103             print 'dropping index', indexname
       
   104             sql('DROP INDEX %s' % indexname)
       
   105     commit()
       
   106 elif driver.startswith('sqlserver'):
       
   107     for viewname, in sql('select name from sys.views'):
       
   108         if viewname.startswith('utv_'):
       
   109             print 'dropping view (index should be cascade-deleted)', viewname
       
   110             sql('DROP VIEW %s' % viewname)
       
   111     commit()
       
   112 
       
   113 # recreate the constraints, hook will lead to low-level recreation
       
   114 for eschema in sorted(schema.entities()):
       
   115     if eschema._unique_together:
       
   116         rql_args = schemaserial.uniquetogether2rqls(eschema)
       
   117         for rql, args in rql_args:
       
   118             args['x'] = eschema.eid
       
   119             session.execute(rql, args)
       
   120         commit()
       
   121 
       
   122 
       
   123 add_relation_definition('CWAttribute', 'add_permission', 'CWGroup')
       
   124 add_relation_definition('CWAttribute', 'add_permission', 'RQLExpression')
       
   125 
       
   126 # all attributes perms have to be refreshed ...
       
   127 for rschema in schema.relations():
       
   128     if relation.final:
       
   129         sync_schema_props_perms(rschema.type, syncprops=False)