19 |
19 |
20 - synchronize the living schema object with the persistent schema |
20 - synchronize the living schema object with the persistent schema |
21 - perform physical update on the source when necessary |
21 - perform physical update on the source when necessary |
22 |
22 |
23 checking for schema consistency is done in hooks.py |
23 checking for schema consistency is done in hooks.py |
24 |
|
25 """ |
24 """ |
|
25 |
26 __docformat__ = "restructuredtext en" |
26 __docformat__ = "restructuredtext en" |
27 |
27 |
28 from copy import copy |
28 from copy import copy |
29 from yams.schema import BASE_TYPES, RelationSchema, RelationDefinitionSchema |
29 from yams.schema import BASE_TYPES, RelationSchema, RelationDefinitionSchema |
30 from yams import buildobjs as ybo, schema2sql as y2sql |
30 from yams import buildobjs as ybo, schema2sql as y2sql |
82 def add_inline_relation_column(session, etype, rtype): |
82 def add_inline_relation_column(session, etype, rtype): |
83 """add necessary column and index for an inlined relation""" |
83 """add necessary column and index for an inlined relation""" |
84 table = SQL_PREFIX + etype |
84 table = SQL_PREFIX + etype |
85 column = SQL_PREFIX + rtype |
85 column = SQL_PREFIX + rtype |
86 try: |
86 try: |
87 session.system_sql(str('ALTER TABLE %s ADD COLUMN %s integer' |
87 session.system_sql(str('ALTER TABLE %s ADD %s integer' |
88 % (table, column)), rollback_on_failure=False) |
88 % (table, column)), rollback_on_failure=False) |
89 session.info('added column %s to table %s', column, table) |
89 session.info('added column %s to table %s', column, table) |
90 except: |
90 except: |
91 # silent exception here, if this error has not been raised because the |
91 # silent exception here, if this error has not been raised because the |
92 # column already exists, index creation will fail anyway |
92 # column already exists, index creation will fail anyway |
143 database |
143 database |
144 """ |
144 """ |
145 table = column = None # make pylint happy |
145 table = column = None # make pylint happy |
146 def precommit_event(self): |
146 def precommit_event(self): |
147 session, table, column = self.session, self.table, self.column |
147 session, table, column = self.session, self.table, self.column |
|
148 source = session.repo.system_source |
148 # drop index if any |
149 # drop index if any |
149 session.pool.source('system').drop_index(session, table, column) |
150 source.drop_index(session, table, column) |
150 try: |
151 if source.dbhelper.alter_column_support: |
151 session.system_sql('ALTER TABLE %s DROP COLUMN %s' |
152 session.system_sql('ALTER TABLE %s DROP COLUMN %s' |
152 % (table, column), rollback_on_failure=False) |
153 % (table, column), rollback_on_failure=False) |
153 self.info('dropped column %s from table %s', column, table) |
154 self.info('dropped column %s from table %s', column, table) |
154 except Exception, ex: |
155 else: |
155 # not supported by sqlite for instance |
156 # not supported by sqlite for instance |
156 self.error('error while altering table %s: %s', table, ex) |
157 self.error('dropping column not supported by the backend, handle ' |
|
158 'it yourself (%s.%s)', table, column) |
157 |
159 |
158 |
160 |
159 # base operations for in-memory schema synchronization ######################## |
161 # base operations for in-memory schema synchronization ######################## |
160 |
162 |
161 class MemSchemaNotifyChanges(hook.SingleLastOperation): |
163 class MemSchemaNotifyChanges(hook.SingleLastOperation): |
282 for etype in rschema.subjects(): |
284 for etype in rschema.subjects(): |
283 table = SQL_PREFIX + str(etype) |
285 table = SQL_PREFIX + str(etype) |
284 sqlexec('INSERT INTO %s_relation SELECT %s, %s FROM %s WHERE NOT %s IS NULL' |
286 sqlexec('INSERT INTO %s_relation SELECT %s, %s FROM %s WHERE NOT %s IS NULL' |
285 % (rtype, eidcolumn, column, table, column)) |
287 % (rtype, eidcolumn, column, table, column)) |
286 # drop existant columns |
288 # drop existant columns |
|
289 #if session.repo.system_source.dbhelper.alter_column_support: |
287 for etype in rschema.subjects(): |
290 for etype in rschema.subjects(): |
288 DropColumn(session, table=SQL_PREFIX + str(etype), |
291 DropColumn(session, table=SQL_PREFIX + str(etype), |
289 column=SQL_PREFIX + rtype) |
292 column=SQL_PREFIX + rtype) |
290 else: |
293 else: |
291 for etype in rschema.subjects(): |
294 for etype in rschema.subjects(): |
292 try: |
295 try: |
293 add_inline_relation_column(session, str(etype), rtype) |
296 add_inline_relation_column(session, str(etype), rtype) |
294 except Exception, ex: |
297 except Exception, ex: |
375 # added some str() wrapping query since some backend (eg psycopg) don't |
378 # added some str() wrapping query since some backend (eg psycopg) don't |
376 # allow unicode queries |
379 # allow unicode queries |
377 table = SQL_PREFIX + rdef.subject |
380 table = SQL_PREFIX + rdef.subject |
378 column = SQL_PREFIX + rdef.name |
381 column = SQL_PREFIX + rdef.name |
379 try: |
382 try: |
380 session.system_sql(str('ALTER TABLE %s ADD COLUMN %s %s' |
383 session.system_sql(str('ALTER TABLE %s ADD %s %s' |
381 % (table, column, attrtype)), |
384 % (table, column, attrtype)), |
382 rollback_on_failure=False) |
385 rollback_on_failure=False) |
383 self.info('added column %s to table %s', table, column) |
386 self.info('added column %s to table %s', table, column) |
384 except Exception, ex: |
387 except Exception, ex: |
385 # the column probably already exists. this occurs when |
388 # the column probably already exists. this occurs when |
550 coltype = y2sql.type_from_constraints(adbh, objtype, [newcstr], |
553 coltype = y2sql.type_from_constraints(adbh, objtype, [newcstr], |
551 creating=False) |
554 creating=False) |
552 sql = adbh.sql_change_col_type(table, column, coltype, card != '1') |
555 sql = adbh.sql_change_col_type(table, column, coltype, card != '1') |
553 try: |
556 try: |
554 session.system_sql(sql, rollback_on_failure=False) |
557 session.system_sql(sql, rollback_on_failure=False) |
555 self.info('altered column %s of table %s: now VARCHAR(%s)', |
558 self.info('altered column %s of table %s: now %s', |
556 column, table, newcstr.max) |
559 column, table, coltype) |
557 except Exception, ex: |
560 except Exception, ex: |
558 # not supported by sqlite for instance |
561 # not supported by sqlite for instance |
559 self.error('error while altering table %s: %s', table, ex) |
562 self.error('error while altering table %s: %s', table, ex) |
560 elif cstrtype == 'UniqueConstraint' and oldcstr is None: |
563 elif cstrtype == 'UniqueConstraint' and oldcstr is None: |
561 session.pool.source('system').create_index( |
564 session.pool.source('system').create_index( |
566 """actually remove a constraint of a relation definition""" |
569 """actually remove a constraint of a relation definition""" |
567 rtype = subjtype = None # make pylint happy |
570 rtype = subjtype = None # make pylint happy |
568 |
571 |
569 def precommit_event(self): |
572 def precommit_event(self): |
570 cstrtype = self.cstr.type() |
573 cstrtype = self.cstr.type() |
571 table = SQL_PREFIX + str(self.subjtype) |
574 table = SQL_PREFIX + str(self.rdef.subject) |
572 column = SQL_PREFIX + str(self.rtype) |
575 column = SQL_PREFIX + str(self.rdef.rtype) |
573 # alter the physical schema on size/unique constraint changes |
576 # alter the physical schema on size/unique constraint changes |
574 if cstrtype == 'SizeConstraint': |
577 if cstrtype == 'SizeConstraint': |
575 try: |
578 try: |
576 self.session.system_sql('ALTER TABLE %s ALTER COLUMN %s TYPE TEXT' |
579 adbh = self.session.pool.source('system').dbhelper |
577 % (table, column), |
580 coltype = y2sql.type_from_constraints(adbh, rdef.object, [], |
578 rollback_on_failure=False) |
581 creating=False) |
579 self.info('altered column %s of table %s: now TEXT', |
582 sql = adbh.sql_change_col_type(table, column, coltype, |
580 column, table) |
583 rdef.cardinality != '1') |
|
584 self.session.system_sql(sql, rollback_on_failure=False) |
|
585 self.info('altered column %s of table %s: now %s', |
|
586 column, table, coltype) |
581 except Exception, ex: |
587 except Exception, ex: |
582 # not supported by sqlite for instance |
588 # not supported by sqlite for instance |
583 self.error('error while altering table %s: %s', table, ex) |
589 self.error('error while altering table %s: %s', table, ex) |
584 elif cstrtype == 'UniqueConstraint': |
590 elif cstrtype == 'UniqueConstraint': |
585 self.session.pool.source('system').drop_index( |
591 self.session.pool.source('system').drop_index( |
1110 try: |
1116 try: |
1111 cstr = rdef.constraint_by_type(entity.type) |
1117 cstr = rdef.constraint_by_type(entity.type) |
1112 except IndexError: |
1118 except IndexError: |
1113 self._cw.critical('constraint type no more accessible') |
1119 self._cw.critical('constraint type no more accessible') |
1114 else: |
1120 else: |
1115 SourceDbCWConstraintDel(self._cw, cstr=cstr, |
1121 SourceDbCWConstraintDel(self._cw, rdef=rdef, cstr=cstr) |
1116 subjtype=rdef.subject, rtype=rdef.rtype) |
|
1117 MemSchemaCWConstraintDel(self._cw, rdef=rdef, cstr=cstr) |
1122 MemSchemaCWConstraintDel(self._cw, rdef=rdef, cstr=cstr) |
1118 |
1123 |
1119 |
1124 |
1120 # permissions synchronization hooks ############################################ |
1125 # permissions synchronization hooks ############################################ |
1121 |
1126 |