[hooks/syncschema] only call "ALTER TABLE" once when changing a size constraint

Until now we would:

  • remove the old size constraint from the in-memory schema
  • call update_rdef_column which removes the size restriction from the column's type
  • add the new constraint object
  • call update_rdef_column which adds the size restriction back

This breaks on SQL Server when the column is involved in an index (e.g. as part of a multi-column unique constraint), because in the intermediate stage the column's type is "nvarchar(max)", which is not indexable.

Of course we must still detect the case where a size constraint is really dropped and update the db schema accordingly.

Closes #5557633.

authorAurelien Campeas <aurelien.campeas@pythonian.fr>
changeset80236876ee4d
branchdefault
phasepublic
hiddenno
parent revision#743ed2b13a6f [syncschema] only add to the `synchronized` set if all possible updates have been done
child revision#22f330f829ae [hooks/syncschema] make sure CWUniqueTogetherConstraintDelOp happens before CWConstraintDelOp
files modified by this revision
hooks/syncschema.py
# HG changeset patch
# User Aurelien Campeas <aurelien.campeas@pythonian.fr>
# Date 1443013233 -7200
# Wed Sep 23 15:00:33 2015 +0200
# Node ID 80236876ee4dd09d8a04a6909335b978f2ec0bfa
# Parent 743ed2b13a6f83122ba2713e0b881d5c606cd01a
[hooks/syncschema] only call "ALTER TABLE" once when changing a size constraint

Until now we would:

- remove the old size constraint from the in-memory schema
- call update_rdef_column which removes the size restriction from the
column's type
- add the new constraint object
- call update_rdef_column which adds the size restriction back

This breaks on SQL Server when the column is involved in an index (e.g.
as part of a multi-column unique constraint), because in the
intermediate stage the column's type is "nvarchar(max)", which is not
indexable.

Of course we must still detect the case where a size constraint is
really dropped and update the db schema accordingly.

Closes #5557633.

diff --git a/hooks/syncschema.py b/hooks/syncschema.py
@@ -659,10 +659,20 @@
1          # then update database: alter the physical schema on size/unique
2          # constraint changes
3          syssource = cnx.repo.system_source
4          cstrtype = self.oldcstr.type()
5          if cstrtype == 'SizeConstraint':
6 +            # if the size constraint is being replaced with a new max size, we'll
7 +            # call update_rdef_column in CWConstraintAddOp, skip it here
8 +            for cstr in cnx.transaction_data.get('newsizecstr', ()):
9 +                rdefentity = cstr.reverse_constrained_by[0]
10 +                cstrrdef = cnx.vreg.schema.schema_by_eid(rdefentity.eid)
11 +                if cstrrdef == rdef:
12 +                    return
13 +
14 +            # we found that the size constraint for this rdef is really gone,
15 +            # not just replaced by another
16              syssource.update_rdef_column(cnx, rdef)
17              self.size_cstr_changed = True
18          elif cstrtype == 'UniqueConstraint':
19              syssource.update_rdef_unique(cnx, rdef)
20              self.unique_changed = True
@@ -1112,10 +1122,15 @@
21      __regid__ = 'syncaddcwconstraint'
22      __select__ = SyncSchemaHook.__select__ & is_instance('CWConstraint')
23      events = ('after_add_entity', 'after_update_entity')
24 
25      def __call__(self):
26 +        if self.entity.cstrtype[0].name == 'SizeConstraint':
27 +            txdata = self._cw.transaction_data
28 +            if 'newsizecstr' not in txdata:
29 +                txdata['newsizecstr'] = set()
30 +            txdata['newsizecstr'].add(self.entity)
31          CWConstraintAddOp(self._cw, entity=self.entity)
32 
33 
34  class AfterAddConstrainedByHook(SyncSchemaHook):
35      __regid__ = 'syncaddconstrainedby'