server/schemahooks.py
changeset 2019 399a930e10ef
parent 2011 758ccc0a9d16
child 2056 57d287a2132a
equal deleted inserted replaced
2018:5abd684d5b9d 2019:399a930e10ef
    12 """
    12 """
    13 __docformat__ = "restructuredtext en"
    13 __docformat__ = "restructuredtext en"
    14 
    14 
    15 from yams.schema import BASE_TYPES
    15 from yams.schema import BASE_TYPES
    16 from yams.buildobjs import EntityType, RelationType, RelationDefinition
    16 from yams.buildobjs import EntityType, RelationType, RelationDefinition
    17 from yams.schema2sql import eschema2sql, rschema2sql, _type_from_constraints
    17 from yams.schema2sql import eschema2sql, rschema2sql, type_from_constraints
    18 
    18 
    19 from cubicweb import ValidationError, RepositoryError
    19 from cubicweb import ValidationError, RepositoryError
    20 from cubicweb.server import schemaserial as ss
    20 from cubicweb.server import schemaserial as ss
    21 from cubicweb.server.sqlutils import SQL_PREFIX
    21 from cubicweb.server.sqlutils import SQL_PREFIX
    22 from cubicweb.server.pool import Operation, SingleLastOperation, PreCommitOperation
    22 from cubicweb.server.pool import Operation, SingleLastOperation, PreCommitOperation
   391                                   fulltextindexed=entity.fulltextindexed,
   391                                   fulltextindexed=entity.fulltextindexed,
   392                                   internationalizable=entity.internationalizable,
   392                                   internationalizable=entity.internationalizable,
   393                                   constraints=constraints,
   393                                   constraints=constraints,
   394                                   eid=entity.eid)
   394                                   eid=entity.eid)
   395         sysource = session.pool.source('system')
   395         sysource = session.pool.source('system')
   396         attrtype = _type_from_constraints(sysource.dbhelper, rdef.object,
   396         attrtype = type_from_constraints(sysource.dbhelper, rdef.object,
   397                                           constraints)
   397                                          constraints)
   398         # XXX should be moved somehow into lgc.adbh: sqlite doesn't support to
   398         # XXX should be moved somehow into lgc.adbh: sqlite doesn't support to
   399         # add a new column with UNIQUE, it should be added after the ALTER TABLE
   399         # add a new column with UNIQUE, it should be added after the ALTER TABLE
   400         # using ADD INDEX
   400         # using ADD INDEX
   401         if sysource.dbdriver == 'sqlite' and 'UNIQUE' in attrtype:
   401         if sysource.dbdriver == 'sqlite' and 'UNIQUE' in attrtype:
   402             extra_unique_index = True
   402             extra_unique_index = True
   421                 sysource.create_index(session, table, column,
   421                 sysource.create_index(session, table, column,
   422                                       unique=extra_unique_index)
   422                                       unique=extra_unique_index)
   423             except Exception, ex:
   423             except Exception, ex:
   424                 self.error('error while creating index for %s.%s: %s',
   424                 self.error('error while creating index for %s.%s: %s',
   425                            table, column, ex)
   425                            table, column, ex)
   426         # postgres doesn't implement, so do it in two times
       
   427         # ALTER TABLE %s ADD COLUMN %s %s SET DEFAULT %s
       
   428         if default is not None:
       
   429             if isinstance(default, unicode):
       
   430                 default = default.encode(sysource.encoding)
       
   431             try:
       
   432                 session.system_sql('ALTER TABLE %s ALTER COLUMN %s SET DEFAULT '
       
   433                                    '%%(default)s' % (table, column),
       
   434                                    {'default': default})
       
   435             except Exception, ex:
       
   436                 # not supported by sqlite for instance
       
   437                 self.error('error while altering table %s: %s', table, ex)
       
   438             session.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column),
       
   439                                {'default': default})
       
   440         AddErdefOp(session, rdef)
   426         AddErdefOp(session, rdef)
   441 
   427 
   442 def after_add_efrdef(session, entity):
   428 def after_add_efrdef(session, entity):
   443     AddCWAttributePreCommitOp(session, entity=entity)
   429     AddCWAttributePreCommitOp(session, entity=entity)
   444 
   430 
   565 class UpdateRelationDefOp(SchemaOperation):
   551 class UpdateRelationDefOp(SchemaOperation):
   566     """actually update some properties of a relation definition"""
   552     """actually update some properties of a relation definition"""
   567     rschema = values = None # make pylint happy
   553     rschema = values = None # make pylint happy
   568 
   554 
   569     def precommit_event(self):
   555     def precommit_event(self):
       
   556         etype = self.kobj[0]
       
   557         table = SQL_PREFIX + etype
       
   558         column = SQL_PREFIX + self.rschema.type
   570         if 'indexed' in self.values:
   559         if 'indexed' in self.values:
   571             sysource = self.session.pool.source('system')
   560             sysource = self.session.pool.source('system')
   572             etype, rtype = self.kobj[0], self.rschema.type
       
   573             table = SQL_PREFIX + etype
       
   574             column = SQL_PREFIX + rtype
       
   575             if self.values['indexed']:
   561             if self.values['indexed']:
   576                 sysource.create_index(self.session, table, column)
   562                 sysource.create_index(self.session, table, column)
   577             else:
   563             else:
   578                 sysource.drop_index(self.session, table, column)
   564                 sysource.drop_index(self.session, table, column)
   579         if 'cardinality' in self.values and self.rschema.is_final():
   565         if 'cardinality' in self.values and self.rschema.is_final():
   580             if self.session.pool.source('system').dbdriver == 'sqlite':
   566             adbh = self.session.pool.source('system').dbhelper
       
   567             if not adbh.alter_column_support:
   581                 # not supported (and NOT NULL not set by yams in that case, so
   568                 # not supported (and NOT NULL not set by yams in that case, so
   582                 # no worry)
   569                 # no worry)
   583                 return
   570                 return
   584             sqlexec = self.session.system_sql
   571             atype = self.rschema.objects(etype)[0]
   585             etype, rtype = self.kobj[0], self.rschema.type
   572             constraints = self.rschema.rproperty(etype, atype, 'constraints')
   586             if self.values['cardinality'][0] == '1':
   573             coltype = type_from_constraints(adbh, atype, constraints,
   587                 cmd = 'SET'
   574                                             creating=False)
   588             else:
   575             sql = adbh.sql_set_null_allowed(table, column, coltype,
   589                 cmd = 'DROP'
   576                                             self.values['cardinality'][0] != '1')
   590             sqlexec('ALTER TABLE %s ALTER COLUMN %s %s NOT NULL' % (
   577             self.session.system_sql(sql)
   591                 SQL_PREFIX + etype, SQL_PREFIX + rtype, cmd))
       
   592 
   578 
   593     def commit_event(self):
   579     def commit_event(self):
   594         # structure should be clean, not need to remove entity's relations
   580         # structure should be clean, not need to remove entity's relations
   595         # at this point
   581         # at this point
   596         self.rschema._rproperties[self.kobj].update(self.values)
   582         self.rschema._rproperties[self.kobj].update(self.values)
   724         table = SQL_PREFIX + str(subjtype)
   710         table = SQL_PREFIX + str(subjtype)
   725         column = SQL_PREFIX + str(rtype)
   711         column = SQL_PREFIX + str(rtype)
   726         # alter the physical schema on size constraint changes
   712         # alter the physical schema on size constraint changes
   727         if self._cstr.type() == 'SizeConstraint' and (
   713         if self._cstr.type() == 'SizeConstraint' and (
   728             self.cstr is None or self.cstr.max != self._cstr.max):
   714             self.cstr is None or self.cstr.max != self._cstr.max):
       
   715             adbh = self.session.pool.source('system').dbhelper
       
   716             card = rtype.rproperty(subjtype, objtype, 'cardinality')
       
   717             coltype = type_from_constraints(adbh, objtype, [self._cstr],
       
   718                                             creating=False)
       
   719             sql = adbh.sql_change_col_type(table, column, coltype, card != '1')
   729             try:
   720             try:
   730                 session.system_sql('ALTER TABLE %s ALTER COLUMN %s TYPE VARCHAR(%s)'
   721                 session.system_sql(sql)
   731                                    % (table, column, self._cstr.max))
       
   732                 self.info('altered column %s of table %s: now VARCHAR(%s)',
   722                 self.info('altered column %s of table %s: now VARCHAR(%s)',
   733                           column, table, self._cstr.max)
   723                           column, table, self._cstr.max)
   734             except Exception, ex:
   724             except Exception, ex:
   735                 # not supported by sqlite for instance
   725                 # not supported by sqlite for instance
   736                 self.error('error while altering table %s: %s', table, ex)
   726                 self.error('error while altering table %s: %s', table, ex)
   739                 self.session, table, column, unique=True)
   729                 self.session, table, column, unique=True)
   740 
   730 
   741     def commit_event(self):
   731     def commit_event(self):
   742         if self.cancelled:
   732         if self.cancelled:
   743             return
   733             return
   744         # in-place removing
   734         # in-place modification
   745         if not self.cstr is None:
   735         if not self.cstr is None:
   746             self.constraints.remove(self.cstr)
   736             self.constraints.remove(self.cstr)
   747         self.constraints.append(self._cstr)
   737         self.constraints.append(self._cstr)
   748 
   738 
   749 
   739