misc/migration/3.21.0_Any.py
changeset 11057 0b59724cb3f2
parent 11052 058bb3dc685f
child 11058 23eb30449fe5
equal deleted inserted replaced
11052:058bb3dc685f 11057:0b59724cb3f2
     1 from __future__ import print_function
       
     2 
       
     3 from cubicweb.schema import PURE_VIRTUAL_RTYPES
       
     4 from cubicweb.server.schema2sql import rschema_has_table
       
     5 
       
     6 
       
     7 def add_foreign_keys():
       
     8     source = repo.system_source
       
     9     if not source.dbhelper.alter_column_support:
       
    10         return
       
    11     for rschema in schema.relations():
       
    12         if rschema.inlined:
       
    13             add_foreign_keys_inlined(rschema)
       
    14         elif rschema_has_table(rschema, skip_relations=PURE_VIRTUAL_RTYPES):
       
    15             add_foreign_keys_relation(rschema)
       
    16     for eschema in schema.entities():
       
    17         if eschema.final:
       
    18             continue
       
    19         add_foreign_key_etype(eschema)
       
    20 
       
    21 
       
    22 def add_foreign_keys_relation(rschema):
       
    23     args = {'r': rschema.type}
       
    24     count = sql('SELECT COUNT(*) FROM ('
       
    25                 '    SELECT eid_from FROM %(r)s_relation'
       
    26                 '  UNION'
       
    27                 '    SELECT eid_to FROM %(r)s_relation'
       
    28                 '  EXCEPT'
       
    29                 '    SELECT eid FROM entities) AS eids' % args,
       
    30                 ask_confirm=False)[0][0]
       
    31     if count:
       
    32         print('%s references %d unknown entities, deleting' % (rschema, count))
       
    33         sql('DELETE FROM %(r)s_relation '
       
    34             'WHERE eid_from IN (SELECT eid_from FROM %(r)s_relation EXCEPT SELECT eid FROM entities)' % args)
       
    35         sql('DELETE FROM %(r)s_relation '
       
    36             'WHERE eid_to IN (SELECT eid_to FROM %(r)s_relation EXCEPT SELECT eid FROM entities)' % args)
       
    37 
       
    38     args['from_fk'] = '%(r)s_relation_eid_from_fkey' % args
       
    39     args['to_fk'] = '%(r)s_relation_eid_to_fkey' % args
       
    40     args['table'] = '%(r)s_relation' % args
       
    41     if repo.system_source.dbdriver == 'postgres':
       
    42         sql('ALTER TABLE %(table)s DROP CONSTRAINT IF EXISTS %(from_fk)s' % args,
       
    43             ask_confirm=False)
       
    44         sql('ALTER TABLE %(table)s DROP CONSTRAINT IF EXISTS %(to_fk)s' % args,
       
    45             ask_confirm=False)
       
    46     elif repo.system_source.dbdriver.startswith('sqlserver'):
       
    47         sql("IF OBJECT_ID('%(from_fk)s', 'F') IS NOT NULL "
       
    48             "ALTER TABLE %(table)s DROP CONSTRAINT %(from_fk)s" % args,
       
    49             ask_confirm=False)
       
    50         sql("IF OBJECT_ID('%(to_fk)s', 'F') IS NOT NULL "
       
    51             "ALTER TABLE %(table)s DROP CONSTRAINT %(to_fk)s" % args,
       
    52             ask_confirm=False)
       
    53     sql('ALTER TABLE %(table)s ADD CONSTRAINT %(from_fk)s '
       
    54         'FOREIGN KEY (eid_from) REFERENCES entities (eid)' % args,
       
    55         ask_confirm=False)
       
    56     sql('ALTER TABLE %(table)s ADD CONSTRAINT %(to_fk)s '
       
    57         'FOREIGN KEY (eid_to) REFERENCES entities (eid)' % args,
       
    58         ask_confirm=False)
       
    59 
       
    60 
       
    61 def add_foreign_keys_inlined(rschema):
       
    62     for eschema in rschema.subjects():
       
    63         args = {'e': eschema.type, 'r': rschema.type}
       
    64         args['c'] = 'cw_%(e)s_cw_%(r)s_fkey' % args
       
    65 
       
    66         if eschema.rdef(rschema).cardinality[0] == '1':
       
    67             broken_eids = sql('SELECT cw_eid FROM cw_%(e)s WHERE cw_%(r)s IS NULL' % args,
       
    68                               ask_confirm=False)
       
    69             if broken_eids:
       
    70                 print('Required relation %(e)s.%(r)s missing' % args)
       
    71                 args['eids'] = ', '.join(str(eid) for eid, in broken_eids)
       
    72                 rql('DELETE %(e)s X WHERE X eid IN (%(eids)s)' % args)
       
    73             broken_eids = sql('SELECT cw_eid FROM cw_%(e)s WHERE cw_%(r)s IN (SELECT cw_%(r)s FROM cw_%(e)s '
       
    74                               'EXCEPT SELECT eid FROM entities)' % args,
       
    75                               ask_confirm=False)
       
    76             if broken_eids:
       
    77                 print('Required relation %(e)s.%(r)s references unknown objects, deleting subject entities' % args)
       
    78                 args['eids'] = ', '.join(str(eid) for eid, in broken_eids)
       
    79                 rql('DELETE %(e)s X WHERE X eid IN (%(eids)s)' % args)
       
    80         else:
       
    81             if sql('SELECT COUNT(*) FROM ('
       
    82                    '    SELECT cw_%(r)s FROM cw_%(e)s WHERE cw_%(r)s IS NOT NULL'
       
    83                    '  EXCEPT'
       
    84                    '    SELECT eid FROM entities) AS eids' % args,
       
    85                    ask_confirm=False)[0][0]:
       
    86                 print('%(e)s.%(r)s references unknown entities, deleting relation' % args)
       
    87                 sql('UPDATE cw_%(e)s SET cw_%(r)s = NULL WHERE cw_%(r)s IS NOT NULL AND cw_%(r)s IN '
       
    88                     '(SELECT cw_%(r)s FROM cw_%(e)s EXCEPT SELECT eid FROM entities)' % args)
       
    89 
       
    90         if repo.system_source.dbdriver == 'postgres':
       
    91             sql('ALTER TABLE cw_%(e)s DROP CONSTRAINT IF EXISTS %(c)s' % args,
       
    92                 ask_confirm=False)
       
    93         elif repo.system_source.dbdriver.startswith('sqlserver'):
       
    94             sql("IF OBJECT_ID('%(c)s', 'F') IS NOT NULL "
       
    95                 "ALTER TABLE cw_%(e)s DROP CONSTRAINT %(c)s" % args,
       
    96                 ask_confirm=False)
       
    97         sql('ALTER TABLE cw_%(e)s ADD CONSTRAINT %(c)s '
       
    98             'FOREIGN KEY (cw_%(r)s) references entities(eid)' % args,
       
    99             ask_confirm=False)
       
   100 
       
   101 
       
   102 def add_foreign_key_etype(eschema):
       
   103     args = {'e': eschema.type}
       
   104     if sql('SELECT COUNT(*) FROM ('
       
   105            '    SELECT cw_eid FROM cw_%(e)s'
       
   106            '  EXCEPT'
       
   107            '    SELECT eid FROM entities) AS eids' % args,
       
   108            ask_confirm=False)[0][0]:
       
   109         print('%(e)s has nonexistent entities, deleting' % args)
       
   110         sql('DELETE FROM cw_%(e)s WHERE cw_eid IN '
       
   111             '(SELECT cw_eid FROM cw_%(e)s EXCEPT SELECT eid FROM entities)' % args)
       
   112     args['c'] = 'cw_%(e)s_cw_eid_fkey' % args
       
   113     if repo.system_source.dbdriver == 'postgres':
       
   114         sql('ALTER TABLE cw_%(e)s DROP CONSTRAINT IF EXISTS %(c)s' % args,
       
   115             ask_confirm=False)
       
   116     elif repo.system_source.dbdriver.startswith('sqlserver'):
       
   117         sql("IF OBJECT_ID('%(c)s', 'F') IS NOT NULL "
       
   118             "ALTER TABLE cw_%(e)s DROP CONSTRAINT %(c)s" % args,
       
   119             ask_confirm=False)
       
   120     sql('ALTER TABLE cw_%(e)s ADD CONSTRAINT %(c)s '
       
   121         'FOREIGN KEY (cw_eid) REFERENCES entities (eid)' % args,
       
   122         ask_confirm=False)
       
   123 
       
   124 
       
   125 add_foreign_keys()
       
   126 
       
   127 cu = session.cnxset.cu
       
   128 helper = repo.system_source.dbhelper
       
   129 
       
   130 helper.drop_index(cu, 'entities', 'extid', False)
       
   131 # don't use create_index because it doesn't work for columns that may be NULL
       
   132 # on sqlserver
       
   133 for query in helper.sqls_create_multicol_unique_index('entities', ['extid']):
       
   134     cu.execute(query)
       
   135 
       
   136 if 'moved_entities' not in helper.list_tables(cu):
       
   137     sql('''
       
   138     CREATE TABLE moved_entities (
       
   139       eid INTEGER PRIMARY KEY NOT NULL,
       
   140       extid VARCHAR(256) UNIQUE
       
   141     )
       
   142     ''')
       
   143 
       
   144 moved_entities = sql('SELECT -eid, extid FROM entities WHERE eid < 0',
       
   145                      ask_confirm=False)
       
   146 if moved_entities:
       
   147     cu.executemany('INSERT INTO moved_entities (eid, extid) VALUES (%s, %s)',
       
   148                    moved_entities)
       
   149     sql('DELETE FROM entities WHERE eid < 0')
       
   150 
       
   151 commit()
       
   152 
       
   153 sync_schema_props_perms('CWEType')
       
   154 
       
   155 sync_schema_props_perms('cwuri')
       
   156 
       
   157 from cubicweb.server.schema2sql import check_constraint
       
   158 
       
   159 for cwconstraint in rql('Any C WHERE R constrained_by C').entities():
       
   160     cwrdef = cwconstraint.reverse_constrained_by[0]
       
   161     rdef = cwrdef.yams_schema()
       
   162     cstr = rdef.constraint_by_eid(cwconstraint.eid)
       
   163     if cstr.type() not in ('BoundaryConstraint', 'IntervalBoundConstraint', 'StaticVocabularyConstraint'):
       
   164         continue
       
   165     cstrname, check = check_constraint(rdef.subject, rdef.object, rdef.rtype.type,
       
   166             cstr, helper, prefix='cw_')
       
   167     args = {'e': rdef.subject.type, 'c': cstrname, 'v': check}
       
   168     if repo.system_source.dbdriver == 'postgres':
       
   169         sql('ALTER TABLE cw_%(e)s DROP CONSTRAINT IF EXISTS %(c)s' % args)
       
   170     elif repo.system_source.dbdriver.startswith('sqlserver'):
       
   171         sql("IF OBJECT_ID('%(c)s', 'C') IS NOT NULL "
       
   172             "ALTER TABLE cw_%(e)s DROP CONSTRAINT %(c)s" % args)
       
   173     sql('ALTER TABLE cw_%(e)s ADD CONSTRAINT %(c)s CHECK(%(v)s)' % args)
       
   174 commit()