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 |