58 return cw.transaction_data['groupmap'] |
58 return cw.transaction_data['groupmap'] |
59 except KeyError: |
59 except KeyError: |
60 cw.transaction_data['groupmap'] = gmap = ss.group_mapping(cw) |
60 cw.transaction_data['groupmap'] = gmap = ss.group_mapping(cw) |
61 return gmap |
61 return gmap |
62 |
62 |
63 def add_inline_relation_column(session, etype, rtype): |
63 def add_inline_relation_column(cnx, etype, rtype): |
64 """add necessary column and index for an inlined relation""" |
64 """add necessary column and index for an inlined relation""" |
65 attrkey = '%s.%s' % (etype, rtype) |
65 attrkey = '%s.%s' % (etype, rtype) |
66 createdattrs = session.transaction_data.setdefault('createdattrs', set()) |
66 createdattrs = cnx.transaction_data.setdefault('createdattrs', set()) |
67 if attrkey in createdattrs: |
67 if attrkey in createdattrs: |
68 return |
68 return |
69 createdattrs.add(attrkey) |
69 createdattrs.add(attrkey) |
70 table = SQL_PREFIX + etype |
70 table = SQL_PREFIX + etype |
71 column = SQL_PREFIX + rtype |
71 column = SQL_PREFIX + rtype |
72 try: |
72 try: |
73 session.system_sql(str('ALTER TABLE %s ADD %s integer' |
73 cnx.system_sql(str('ALTER TABLE %s ADD %s integer' |
74 % (table, column)), rollback_on_failure=False) |
74 % (table, column)), rollback_on_failure=False) |
75 session.info('added column %s to table %s', column, table) |
75 cnx.info('added column %s to table %s', column, table) |
76 except Exception: |
76 except Exception: |
77 # silent exception here, if this error has not been raised because the |
77 # silent exception here, if this error has not been raised because the |
78 # column already exists, index creation will fail anyway |
78 # column already exists, index creation will fail anyway |
79 session.exception('error while adding column %s to table %s', |
79 cnx.exception('error while adding column %s to table %s', |
80 table, column) |
80 table, column) |
81 # create index before alter table which may expectingly fail during test |
81 # create index before alter table which may expectingly fail during test |
82 # (sqlite) while index creation should never fail (test for index existence |
82 # (sqlite) while index creation should never fail (test for index existence |
83 # is done by the dbhelper) |
83 # is done by the dbhelper) |
84 session.repo.system_source.create_index(session, table, column) |
84 cnx.repo.system_source.create_index(cnx, table, column) |
85 session.info('added index on %s(%s)', table, column) |
85 cnx.info('added index on %s(%s)', table, column) |
86 |
86 |
87 |
87 |
88 def insert_rdef_on_subclasses(session, eschema, rschema, rdefdef, props): |
88 def insert_rdef_on_subclasses(cnx, eschema, rschema, rdefdef, props): |
89 # XXX 'infered': True/False, not clear actually |
89 # XXX 'infered': True/False, not clear actually |
90 props.update({'constraints': rdefdef.constraints, |
90 props.update({'constraints': rdefdef.constraints, |
91 'description': rdefdef.description, |
91 'description': rdefdef.description, |
92 'cardinality': rdefdef.cardinality, |
92 'cardinality': rdefdef.cardinality, |
93 'permissions': rdefdef.get_permissions(), |
93 'permissions': rdefdef.get_permissions(), |
94 'order': rdefdef.order, |
94 'order': rdefdef.order, |
95 'infered': False, 'eid': None |
95 'infered': False, 'eid': None |
96 }) |
96 }) |
97 cstrtypemap = ss.cstrtype_mapping(session) |
97 cstrtypemap = ss.cstrtype_mapping(cnx) |
98 groupmap = group_mapping(session) |
98 groupmap = group_mapping(cnx) |
99 object = rschema.schema.eschema(rdefdef.object) |
99 object = rschema.schema.eschema(rdefdef.object) |
100 for specialization in eschema.specialized_by(False): |
100 for specialization in eschema.specialized_by(False): |
101 if (specialization, rdefdef.object) in rschema.rdefs: |
101 if (specialization, rdefdef.object) in rschema.rdefs: |
102 continue |
102 continue |
103 sperdef = RelationDefinitionSchema(specialization, rschema, |
103 sperdef = RelationDefinitionSchema(specialization, rschema, |
104 object, None, values=props) |
104 object, None, values=props) |
105 ss.execschemarql(session.execute, sperdef, |
105 ss.execschemarql(cnx.execute, sperdef, |
106 ss.rdef2rql(sperdef, cstrtypemap, groupmap)) |
106 ss.rdef2rql(sperdef, cstrtypemap, groupmap)) |
107 |
107 |
108 |
108 |
109 def check_valid_changes(session, entity, ro_attrs=('name', 'final')): |
109 def check_valid_changes(cnx, entity, ro_attrs=('name', 'final')): |
110 errors = {} |
110 errors = {} |
111 # don't use getattr(entity, attr), we would get the modified value if any |
111 # don't use getattr(entity, attr), we would get the modified value if any |
112 for attr in entity.cw_edited: |
112 for attr in entity.cw_edited: |
113 if attr in ro_attrs: |
113 if attr in ro_attrs: |
114 origval, newval = entity.cw_edited.oldnewvalue(attr) |
114 origval, newval = entity.cw_edited.oldnewvalue(attr) |
135 |
135 |
136 class DropTable(hook.Operation): |
136 class DropTable(hook.Operation): |
137 """actually remove a database from the instance's schema""" |
137 """actually remove a database from the instance's schema""" |
138 table = None # make pylint happy |
138 table = None # make pylint happy |
139 def precommit_event(self): |
139 def precommit_event(self): |
140 dropped = self.session.transaction_data.setdefault('droppedtables', |
140 dropped = self.cnx.transaction_data.setdefault('droppedtables', |
141 set()) |
141 set()) |
142 if self.table in dropped: |
142 if self.table in dropped: |
143 return # already processed |
143 return # already processed |
144 dropped.add(self.table) |
144 dropped.add(self.table) |
145 self.session.system_sql('DROP TABLE %s' % self.table) |
145 self.cnx.system_sql('DROP TABLE %s' % self.table) |
146 self.info('dropped table %s', self.table) |
146 self.info('dropped table %s', self.table) |
147 |
147 |
148 # XXX revertprecommit_event |
148 # XXX revertprecommit_event |
149 |
149 |
150 |
150 |
151 class DropRelationTable(DropTable): |
151 class DropRelationTable(DropTable): |
152 def __init__(self, session, rtype): |
152 def __init__(self, cnx, rtype): |
153 super(DropRelationTable, self).__init__( |
153 super(DropRelationTable, self).__init__( |
154 session, table='%s_relation' % rtype) |
154 cnx, table='%s_relation' % rtype) |
155 session.transaction_data.setdefault('pendingrtypes', set()).add(rtype) |
155 cnx.transaction_data.setdefault('pendingrtypes', set()).add(rtype) |
156 |
156 |
157 |
157 |
158 class DropColumn(hook.Operation): |
158 class DropColumn(hook.Operation): |
159 """actually remove the attribut's column from entity table in the system |
159 """actually remove the attribut's column from entity table in the system |
160 database |
160 database |
161 """ |
161 """ |
162 table = column = None # make pylint happy |
162 table = column = None # make pylint happy |
163 def precommit_event(self): |
163 def precommit_event(self): |
164 session, table, column = self.session, self.table, self.column |
164 cnx, table, column = self.cnx, self.table, self.column |
165 source = session.repo.system_source |
165 source = cnx.repo.system_source |
166 # drop index if any |
166 # drop index if any |
167 source.drop_index(session, table, column) |
167 source.drop_index(cnx, table, column) |
168 if source.dbhelper.alter_column_support: |
168 if source.dbhelper.alter_column_support: |
169 session.system_sql('ALTER TABLE %s DROP COLUMN %s' |
169 cnx.system_sql('ALTER TABLE %s DROP COLUMN %s' |
170 % (table, column), rollback_on_failure=False) |
170 % (table, column), rollback_on_failure=False) |
171 self.info('dropped column %s from table %s', column, table) |
171 self.info('dropped column %s from table %s', column, table) |
172 else: |
172 else: |
173 # not supported by sqlite for instance |
173 # not supported by sqlite for instance |
174 self.error('dropping column not supported by the backend, handle ' |
174 self.error('dropping column not supported by the backend, handle ' |
185 special operation which should be called once and after all other schema |
185 special operation which should be called once and after all other schema |
186 operations. It will trigger internal structures rebuilding to consider |
186 operations. It will trigger internal structures rebuilding to consider |
187 schema changes. |
187 schema changes. |
188 """ |
188 """ |
189 |
189 |
190 def __init__(self, session): |
190 def __init__(self, cnx): |
191 hook.SingleLastOperation.__init__(self, session) |
191 hook.SingleLastOperation.__init__(self, cnx) |
192 |
192 |
193 def precommit_event(self): |
193 def precommit_event(self): |
194 for eschema in self.session.repo.schema.entities(): |
194 for eschema in self.cnx.repo.schema.entities(): |
195 if not eschema.final: |
195 if not eschema.final: |
196 clear_cache(eschema, 'ordered_relations') |
196 clear_cache(eschema, 'ordered_relations') |
197 |
197 |
198 def postcommit_event(self): |
198 def postcommit_event(self): |
199 rebuildinfered = self.session.get_shared_data('rebuild-infered', True) |
199 rebuildinfered = self.cnx.get_shared_data('rebuild-infered', True) |
200 repo = self.session.repo |
200 repo = self.cnx.repo |
201 # commit event should not raise error, while set_schema has chances to |
201 # commit event should not raise error, while set_schema has chances to |
202 # do so because it triggers full vreg reloading |
202 # do so because it triggers full vreg reloading |
203 try: |
203 try: |
204 if rebuildinfered: |
204 if rebuildinfered: |
205 repo.schema.rebuild_infered_relations() |
205 repo.schema.rebuild_infered_relations() |
206 # trigger vreg reload |
206 # trigger vreg reload |
207 repo.set_schema(repo.schema) |
207 repo.set_schema(repo.schema) |
208 # CWUser class might have changed, update current session users |
208 # CWUser class might have changed, update current session users |
209 cwuser_cls = self.session.vreg['etypes'].etype_class('CWUser') |
209 cwuser_cls = self.cnx.vreg['etypes'].etype_class('CWUser') |
210 for session in repo._sessions.itervalues(): |
210 for session in repo._sessions.itervalues(): |
211 session.user.__class__ = cwuser_cls |
211 session.user.__class__ = cwuser_cls |
212 except Exception: |
212 except Exception: |
213 self.critical('error while setting schema', exc_info=True) |
213 self.critical('error while setting schema', exc_info=True) |
214 |
214 |
235 * add <meta rtype> relation by creating the necessary CWRelation entity |
235 * add <meta rtype> relation by creating the necessary CWRelation entity |
236 """ |
236 """ |
237 entity = None # make pylint happy |
237 entity = None # make pylint happy |
238 |
238 |
239 def precommit_event(self): |
239 def precommit_event(self): |
240 session = self.session |
240 cnx = self.cnx |
241 entity = self.entity |
241 entity = self.entity |
242 schema = session.vreg.schema |
242 schema = cnx.vreg.schema |
243 etype = ybo.EntityType(eid=entity.eid, name=entity.name, |
243 etype = ybo.EntityType(eid=entity.eid, name=entity.name, |
244 description=entity.description) |
244 description=entity.description) |
245 eschema = schema.add_entity_type(etype) |
245 eschema = schema.add_entity_type(etype) |
246 # create the necessary table |
246 # create the necessary table |
247 tablesql = y2sql.eschema2sql(session.repo.system_source.dbhelper, |
247 tablesql = y2sql.eschema2sql(cnx.repo.system_source.dbhelper, |
248 eschema, prefix=SQL_PREFIX) |
248 eschema, prefix=SQL_PREFIX) |
249 for sql in tablesql.split(';'): |
249 for sql in tablesql.split(';'): |
250 if sql.strip(): |
250 if sql.strip(): |
251 session.system_sql(sql) |
251 cnx.system_sql(sql) |
252 # add meta relations |
252 # add meta relations |
253 gmap = group_mapping(session) |
253 gmap = group_mapping(cnx) |
254 cmap = ss.cstrtype_mapping(session) |
254 cmap = ss.cstrtype_mapping(cnx) |
255 for rtype in (META_RTYPES - VIRTUAL_RTYPES): |
255 for rtype in (META_RTYPES - VIRTUAL_RTYPES): |
256 try: |
256 try: |
257 rschema = schema[rtype] |
257 rschema = schema[rtype] |
258 except KeyError: |
258 except KeyError: |
259 self.critical('rtype %s was not handled at cwetype creation time', rtype) |
259 self.critical('rtype %s was not handled at cwetype creation time', rtype) |
268 except KeyError: |
268 except KeyError: |
269 # this combo does not exist because this is not a universal META_RTYPE |
269 # this combo does not exist because this is not a universal META_RTYPE |
270 continue |
270 continue |
271 rdef.subject = _MockEntity(eid=entity.eid) |
271 rdef.subject = _MockEntity(eid=entity.eid) |
272 mock = _MockEntity(eid=None) |
272 mock = _MockEntity(eid=None) |
273 ss.execschemarql(session.execute, mock, ss.rdef2rql(rdef, cmap, gmap)) |
273 ss.execschemarql(cnx.execute, mock, ss.rdef2rql(rdef, cmap, gmap)) |
274 |
274 |
275 def revertprecommit_event(self): |
275 def revertprecommit_event(self): |
276 # revert changes on in memory schema |
276 # revert changes on in memory schema |
277 self.session.vreg.schema.del_entity_type(self.entity.name) |
277 self.cnx.vreg.schema.del_entity_type(self.entity.name) |
278 # revert changes on database |
278 # revert changes on database |
279 self.session.system_sql('DROP TABLE %s%s' % (SQL_PREFIX, self.entity.name)) |
279 self.cnx.system_sql('DROP TABLE %s%s' % (SQL_PREFIX, self.entity.name)) |
280 |
280 |
281 |
281 |
282 class CWETypeRenameOp(MemSchemaOperation): |
282 class CWETypeRenameOp(MemSchemaOperation): |
283 """this operation updates physical storage accordingly""" |
283 """this operation updates physical storage accordingly""" |
284 oldname = newname = None # make pylint happy |
284 oldname = newname = None # make pylint happy |
285 |
285 |
286 def rename(self, oldname, newname): |
286 def rename(self, oldname, newname): |
287 self.session.vreg.schema.rename_entity_type(oldname, newname) |
287 self.cnx.vreg.schema.rename_entity_type(oldname, newname) |
288 # we need sql to operate physical changes on the system database |
288 # we need sql to operate physical changes on the system database |
289 sqlexec = self.session.system_sql |
289 sqlexec = self.cnx.system_sql |
290 dbhelper = self.session.repo.system_source.dbhelper |
290 dbhelper = self.cnx.repo.system_source.dbhelper |
291 sql = dbhelper.sql_rename_table(SQL_PREFIX+oldname, |
291 sql = dbhelper.sql_rename_table(SQL_PREFIX+oldname, |
292 SQL_PREFIX+newname) |
292 SQL_PREFIX+newname) |
293 sqlexec(sql) |
293 sqlexec(sql) |
294 self.info('renamed table %s to %s', oldname, newname) |
294 self.info('renamed table %s to %s', oldname, newname) |
295 sqlexec('UPDATE entities SET type=%(newname)s WHERE type=%(oldname)s', |
295 sqlexec('UPDATE entities SET type=%(newname)s WHERE type=%(oldname)s', |
296 {'newname': newname, 'oldname': oldname}) |
296 {'newname': newname, 'oldname': oldname}) |
297 for eid, (etype, extid, auri) in self.session.repo._type_source_cache.items(): |
297 for eid, (etype, extid, auri) in self.cnx.repo._type_source_cache.items(): |
298 if etype == oldname: |
298 if etype == oldname: |
299 self.session.repo._type_source_cache[eid] = (newname, extid, auri) |
299 self.cnx.repo._type_source_cache[eid] = (newname, extid, auri) |
300 # XXX transaction records |
300 # XXX transaction records |
301 |
301 |
302 def precommit_event(self): |
302 def precommit_event(self): |
303 self.rename(self.oldname, self.newname) |
303 self.rename(self.oldname, self.newname) |
304 |
304 |
330 inlined = self.values['inlined'] |
330 inlined = self.values['inlined'] |
331 # check in-lining is possible when inlined |
331 # check in-lining is possible when inlined |
332 if inlined: |
332 if inlined: |
333 self.entity.check_inlined_allowed() |
333 self.entity.check_inlined_allowed() |
334 # inlined changed, make necessary physical changes! |
334 # inlined changed, make necessary physical changes! |
335 sqlexec = self.session.system_sql |
335 sqlexec = self.cnx.system_sql |
336 rtype = rschema.type |
336 rtype = rschema.type |
337 eidcolumn = SQL_PREFIX + 'eid' |
337 eidcolumn = SQL_PREFIX + 'eid' |
338 if not inlined: |
338 if not inlined: |
339 # need to create the relation if it has not been already done by |
339 # need to create the relation if it has not been already done by |
340 # another event of the same transaction |
340 # another event of the same transaction |
341 if not rschema.type in session.transaction_data.get('createdtables', ()): |
341 if not rschema.type in cnx.transaction_data.get('createdtables', ()): |
342 tablesql = y2sql.rschema2sql(rschema) |
342 tablesql = y2sql.rschema2sql(rschema) |
343 # create the necessary table |
343 # create the necessary table |
344 for sql in tablesql.split(';'): |
344 for sql in tablesql.split(';'): |
345 if sql.strip(): |
345 if sql.strip(): |
346 sqlexec(sql) |
346 sqlexec(sql) |
347 session.transaction_data.setdefault('createdtables', []).append( |
347 cnx.transaction_data.setdefault('createdtables', []).append( |
348 rschema.type) |
348 rschema.type) |
349 # copy existant data |
349 # copy existant data |
350 column = SQL_PREFIX + rtype |
350 column = SQL_PREFIX + rtype |
351 for etype in rschema.subjects(): |
351 for etype in rschema.subjects(): |
352 table = SQL_PREFIX + str(etype) |
352 table = SQL_PREFIX + str(etype) |
353 sqlexec('INSERT INTO %s_relation SELECT %s, %s FROM %s WHERE NOT %s IS NULL' |
353 sqlexec('INSERT INTO %s_relation SELECT %s, %s FROM %s WHERE NOT %s IS NULL' |
354 % (rtype, eidcolumn, column, table, column)) |
354 % (rtype, eidcolumn, column, table, column)) |
355 # drop existant columns |
355 # drop existant columns |
356 #if session.repo.system_source.dbhelper.alter_column_support: |
356 #if cnx.repo.system_source.dbhelper.alter_column_support: |
357 for etype in rschema.subjects(): |
357 for etype in rschema.subjects(): |
358 DropColumn(session, table=SQL_PREFIX + str(etype), |
358 DropColumn(cnx, table=SQL_PREFIX + str(etype), |
359 column=SQL_PREFIX + rtype) |
359 column=SQL_PREFIX + rtype) |
360 else: |
360 else: |
361 for etype in rschema.subjects(): |
361 for etype in rschema.subjects(): |
362 try: |
362 try: |
363 add_inline_relation_column(session, str(etype), rtype) |
363 add_inline_relation_column(cnx, str(etype), rtype) |
364 except Exception as ex: |
364 except Exception as ex: |
365 # the column probably already exists. this occurs when the |
365 # the column probably already exists. this occurs when the |
366 # entity's type has just been added or if the column has not |
366 # entity's type has just been added or if the column has not |
367 # been previously dropped (eg sqlite) |
367 # been previously dropped (eg sqlite) |
368 self.error('error while altering table %s: %s', etype, ex) |
368 self.error('error while altering table %s: %s', etype, ex) |
405 entity = self.entity |
405 entity = self.entity |
406 fromentity = entity.stype |
406 fromentity = entity.stype |
407 rdefdef = self.rdefdef = ybo.RelationDefinition( |
407 rdefdef = self.rdefdef = ybo.RelationDefinition( |
408 str(fromentity.name), entity.rtype.name, str(entity.otype.name), |
408 str(fromentity.name), entity.rtype.name, str(entity.otype.name), |
409 description=entity.description, cardinality=entity.cardinality, |
409 description=entity.description, cardinality=entity.cardinality, |
410 constraints=get_constraints(self.session, entity), |
410 constraints=get_constraints(self.cnx, entity), |
411 order=entity.ordernum, eid=entity.eid, **kwargs) |
411 order=entity.ordernum, eid=entity.eid, **kwargs) |
412 self.session.vreg.schema.add_relation_def(rdefdef) |
412 self.cnx.vreg.schema.add_relation_def(rdefdef) |
413 self.session.execute('SET X ordernum Y+1 ' |
413 self.cnx.execute('SET X ordernum Y+1 ' |
414 'WHERE X from_entity SE, SE eid %(se)s, X ordernum Y, ' |
414 'WHERE X from_entity SE, SE eid %(se)s, X ordernum Y, ' |
415 'X ordernum >= %(order)s, NOT X eid %(x)s', |
415 'X ordernum >= %(order)s, NOT X eid %(x)s', |
416 {'x': entity.eid, 'se': fromentity.eid, |
416 {'x': entity.eid, 'se': fromentity.eid, |
417 'order': entity.ordernum or 0}) |
417 'order': entity.ordernum or 0}) |
418 return rdefdef |
418 return rdefdef |
419 |
419 |
420 def precommit_event(self): |
420 def precommit_event(self): |
421 session = self.session |
421 cnx = self.cnx |
422 entity = self.entity |
422 entity = self.entity |
423 # entity.defaultval is a Binary or None, but we need a correctly typed |
423 # entity.defaultval is a Binary or None, but we need a correctly typed |
424 # value |
424 # value |
425 default = entity.defaultval |
425 default = entity.defaultval |
426 if default is not None: |
426 if default is not None: |
446 # added some str() wrapping query since some backend (eg psycopg) don't |
446 # added some str() wrapping query since some backend (eg psycopg) don't |
447 # allow unicode queries |
447 # allow unicode queries |
448 table = SQL_PREFIX + rdefdef.subject |
448 table = SQL_PREFIX + rdefdef.subject |
449 column = SQL_PREFIX + rdefdef.name |
449 column = SQL_PREFIX + rdefdef.name |
450 try: |
450 try: |
451 session.system_sql(str('ALTER TABLE %s ADD %s %s' |
451 cnx.system_sql(str('ALTER TABLE %s ADD %s %s' |
452 % (table, column, attrtype)), |
452 % (table, column, attrtype)), |
453 rollback_on_failure=False) |
453 rollback_on_failure=False) |
454 self.info('added column %s to table %s', table, column) |
454 self.info('added column %s to table %s', table, column) |
455 except Exception as ex: |
455 except Exception as ex: |
456 # the column probably already exists. this occurs when |
456 # the column probably already exists. this occurs when |
457 # the entity's type has just been added or if the column |
457 # the entity's type has just been added or if the column |
458 # has not been previously dropped |
458 # has not been previously dropped |
459 self.error('error while altering table %s: %s', table, ex) |
459 self.error('error while altering table %s: %s', table, ex) |
460 if extra_unique_index or entity.indexed: |
460 if extra_unique_index or entity.indexed: |
461 try: |
461 try: |
462 syssource.create_index(session, table, column, |
462 syssource.create_index(cnx, table, column, |
463 unique=extra_unique_index) |
463 unique=extra_unique_index) |
464 except Exception as ex: |
464 except Exception as ex: |
465 self.error('error while creating index for %s.%s: %s', |
465 self.error('error while creating index for %s.%s: %s', |
466 table, column, ex) |
466 table, column, ex) |
467 # final relations are not infered, propagate |
467 # final relations are not infered, propagate |
468 schema = session.vreg.schema |
468 schema = cnx.vreg.schema |
469 try: |
469 try: |
470 eschema = schema.eschema(rdefdef.subject) |
470 eschema = schema.eschema(rdefdef.subject) |
471 except KeyError: |
471 except KeyError: |
472 return # entity type currently being added |
472 return # entity type currently being added |
473 # propagate attribute to children classes |
473 # propagate attribute to children classes |
474 rschema = schema.rschema(rdefdef.name) |
474 rschema = schema.rschema(rdefdef.name) |
475 # if relation type has been inserted in the same transaction, its final |
475 # if relation type has been inserted in the same transaction, its final |
476 # attribute is still set to False, so we've to ensure it's False |
476 # attribute is still set to False, so we've to ensure it's False |
477 rschema.final = True |
477 rschema.final = True |
478 insert_rdef_on_subclasses(session, eschema, rschema, rdefdef, props) |
478 insert_rdef_on_subclasses(cnx, eschema, rschema, rdefdef, props) |
479 # update existing entities with the default value of newly added attribute |
479 # update existing entities with the default value of newly added attribute |
480 if default is not None: |
480 if default is not None: |
481 default = convert_default_value(self.rdefdef, default) |
481 default = convert_default_value(self.rdefdef, default) |
482 session.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column), |
482 cnx.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column), |
483 {'default': default}) |
483 {'default': default}) |
484 |
484 |
485 def revertprecommit_event(self): |
485 def revertprecommit_event(self): |
486 # revert changes on in memory schema |
486 # revert changes on in memory schema |
487 if getattr(self, 'rdefdef', None) is None: |
487 if getattr(self, 'rdefdef', None) is None: |
488 return |
488 return |
489 self.session.vreg.schema.del_relation_def( |
489 self.cnx.vreg.schema.del_relation_def( |
490 self.rdefdef.subject, self.rdefdef.name, self.rdefdef.object) |
490 self.rdefdef.subject, self.rdefdef.name, self.rdefdef.object) |
491 # XXX revert changes on database |
491 # XXX revert changes on database |
492 |
492 |
493 |
493 |
494 class CWRelationAddOp(CWAttributeAddOp): |
494 class CWRelationAddOp(CWAttributeAddOp): |
503 constraints are handled by specific hooks |
503 constraints are handled by specific hooks |
504 """ |
504 """ |
505 entity = None # make pylint happy |
505 entity = None # make pylint happy |
506 |
506 |
507 def precommit_event(self): |
507 def precommit_event(self): |
508 session = self.session |
508 cnx = self.cnx |
509 entity = self.entity |
509 entity = self.entity |
510 # update the in-memory schema first |
510 # update the in-memory schema first |
511 rdefdef = self.init_rdef(composite=entity.composite) |
511 rdefdef = self.init_rdef(composite=entity.composite) |
512 # then make necessary changes to the system source database |
512 # then make necessary changes to the system source database |
513 schema = session.vreg.schema |
513 schema = cnx.vreg.schema |
514 rtype = rdefdef.name |
514 rtype = rdefdef.name |
515 rschema = schema.rschema(rtype) |
515 rschema = schema.rschema(rtype) |
516 # this have to be done before permissions setting |
516 # this have to be done before permissions setting |
517 if rschema.inlined: |
517 if rschema.inlined: |
518 # need to add a column if the relation is inlined and if this is the |
518 # need to add a column if the relation is inlined and if this is the |
519 # first occurence of "Subject relation Something" whatever Something |
519 # first occurence of "Subject relation Something" whatever Something |
520 if len(rschema.objects(rdefdef.subject)) == 1: |
520 if len(rschema.objects(rdefdef.subject)) == 1: |
521 add_inline_relation_column(session, rdefdef.subject, rtype) |
521 add_inline_relation_column(cnx, rdefdef.subject, rtype) |
522 eschema = schema[rdefdef.subject] |
522 eschema = schema[rdefdef.subject] |
523 insert_rdef_on_subclasses(session, eschema, rschema, rdefdef, |
523 insert_rdef_on_subclasses(cnx, eschema, rschema, rdefdef, |
524 {'composite': entity.composite}) |
524 {'composite': entity.composite}) |
525 else: |
525 else: |
526 if rschema.symmetric: |
526 if rschema.symmetric: |
527 # for symmetric relations, rdefs will store relation definitions |
527 # for symmetric relations, rdefs will store relation definitions |
528 # in both ways (i.e. (subj -> obj) and (obj -> subj)) |
528 # in both ways (i.e. (subj -> obj) and (obj -> subj)) |
531 relation_already_defined = len(rschema.rdefs) > 1 |
531 relation_already_defined = len(rschema.rdefs) > 1 |
532 # need to create the relation if no relation definition in the |
532 # need to create the relation if no relation definition in the |
533 # schema and if it has not been added during other event of the same |
533 # schema and if it has not been added during other event of the same |
534 # transaction |
534 # transaction |
535 if not (relation_already_defined or |
535 if not (relation_already_defined or |
536 rtype in session.transaction_data.get('createdtables', ())): |
536 rtype in cnx.transaction_data.get('createdtables', ())): |
537 rschema = schema.rschema(rtype) |
537 rschema = schema.rschema(rtype) |
538 # create the necessary table |
538 # create the necessary table |
539 for sql in y2sql.rschema2sql(rschema).split(';'): |
539 for sql in y2sql.rschema2sql(rschema).split(';'): |
540 if sql.strip(): |
540 if sql.strip(): |
541 session.system_sql(sql) |
541 cnx.system_sql(sql) |
542 session.transaction_data.setdefault('createdtables', []).append( |
542 cnx.transaction_data.setdefault('createdtables', []).append( |
543 rtype) |
543 rtype) |
544 |
544 |
545 # XXX revertprecommit_event |
545 # XXX revertprecommit_event |
546 |
546 |
547 |
547 |
548 class RDefDelOp(MemSchemaOperation): |
548 class RDefDelOp(MemSchemaOperation): |
549 """an actual relation has been removed""" |
549 """an actual relation has been removed""" |
550 rdef = None # make pylint happy |
550 rdef = None # make pylint happy |
551 |
551 |
552 def precommit_event(self): |
552 def precommit_event(self): |
553 session = self.session |
553 cnx = self.cnx |
554 rdef = self.rdef |
554 rdef = self.rdef |
555 rschema = rdef.rtype |
555 rschema = rdef.rtype |
556 # make necessary changes to the system source database first |
556 # make necessary changes to the system source database first |
557 rdeftype = rschema.final and 'CWAttribute' or 'CWRelation' |
557 rdeftype = rschema.final and 'CWAttribute' or 'CWRelation' |
558 execute = session.execute |
558 execute = cnx.execute |
559 rset = execute('Any COUNT(X) WHERE X is %s, X relation_type R,' |
559 rset = execute('Any COUNT(X) WHERE X is %s, X relation_type R,' |
560 'R eid %%(x)s' % rdeftype, {'x': rschema.eid}) |
560 'R eid %%(x)s' % rdeftype, {'x': rschema.eid}) |
561 lastrel = rset[0][0] == 0 |
561 lastrel = rset[0][0] == 0 |
562 # we have to update physical schema systematically for final and inlined |
562 # we have to update physical schema systematically for final and inlined |
563 # relations, but only if it's the last instance for this relation type |
563 # relations, but only if it's the last instance for this relation type |
565 if (rschema.final or rschema.inlined): |
565 if (rschema.final or rschema.inlined): |
566 rset = execute('Any COUNT(X) WHERE X is %s, X relation_type R, ' |
566 rset = execute('Any COUNT(X) WHERE X is %s, X relation_type R, ' |
567 'R eid %%(r)s, X from_entity E, E eid %%(e)s' |
567 'R eid %%(r)s, X from_entity E, E eid %%(e)s' |
568 % rdeftype, |
568 % rdeftype, |
569 {'r': rschema.eid, 'e': rdef.subject.eid}) |
569 {'r': rschema.eid, 'e': rdef.subject.eid}) |
570 if rset[0][0] == 0 and not session.deleted_in_transaction(rdef.subject.eid): |
570 if rset[0][0] == 0 and not cnx.deleted_in_transaction(rdef.subject.eid): |
571 ptypes = session.transaction_data.setdefault('pendingrtypes', set()) |
571 ptypes = cnx.transaction_data.setdefault('pendingrtypes', set()) |
572 ptypes.add(rschema.type) |
572 ptypes.add(rschema.type) |
573 DropColumn(session, table=SQL_PREFIX + str(rdef.subject), |
573 DropColumn(cnx, table=SQL_PREFIX + str(rdef.subject), |
574 column=SQL_PREFIX + str(rschema)) |
574 column=SQL_PREFIX + str(rschema)) |
575 elif lastrel: |
575 elif lastrel: |
576 DropRelationTable(session, str(rschema)) |
576 DropRelationTable(cnx, str(rschema)) |
577 # then update the in-memory schema |
577 # then update the in-memory schema |
578 if rdef.subject not in ETYPE_NAME_MAP and rdef.object not in ETYPE_NAME_MAP: |
578 if rdef.subject not in ETYPE_NAME_MAP and rdef.object not in ETYPE_NAME_MAP: |
579 rschema.del_relation_def(rdef.subject, rdef.object) |
579 rschema.del_relation_def(rdef.subject, rdef.object) |
580 # if this is the last relation definition of this type, drop associated |
580 # if this is the last relation definition of this type, drop associated |
581 # relation type |
581 # relation type |
582 if lastrel and not session.deleted_in_transaction(rschema.eid): |
582 if lastrel and not cnx.deleted_in_transaction(rschema.eid): |
583 execute('DELETE CWRType X WHERE X eid %(x)s', {'x': rschema.eid}) |
583 execute('DELETE CWRType X WHERE X eid %(x)s', {'x': rschema.eid}) |
584 |
584 |
585 def revertprecommit_event(self): |
585 def revertprecommit_event(self): |
586 # revert changes on in memory schema |
586 # revert changes on in memory schema |
587 # |
587 # |
588 # Note: add_relation_def takes a RelationDefinition, not a |
588 # Note: add_relation_def takes a RelationDefinition, not a |
589 # RelationDefinitionSchema, needs to fake it |
589 # RelationDefinitionSchema, needs to fake it |
590 rdef = self.rdef |
590 rdef = self.rdef |
591 rdef.name = str(rdef.rtype) |
591 rdef.name = str(rdef.rtype) |
592 if rdef.subject not in ETYPE_NAME_MAP and rdef.object not in ETYPE_NAME_MAP: |
592 if rdef.subject not in ETYPE_NAME_MAP and rdef.object not in ETYPE_NAME_MAP: |
593 self.session.vreg.schema.add_relation_def(rdef) |
593 self.cnx.vreg.schema.add_relation_def(rdef) |
594 |
594 |
595 |
595 |
596 |
596 |
597 class RDefUpdateOp(MemSchemaOperation): |
597 class RDefUpdateOp(MemSchemaOperation): |
598 """actually update some properties of a relation definition""" |
598 """actually update some properties of a relation definition""" |
599 rschema = rdefkey = values = None # make pylint happy |
599 rschema = rdefkey = values = None # make pylint happy |
600 rdef = oldvalues = None |
600 rdef = oldvalues = None |
601 indexed_changed = null_allowed_changed = False |
601 indexed_changed = null_allowed_changed = False |
602 |
602 |
603 def precommit_event(self): |
603 def precommit_event(self): |
604 session = self.session |
604 cnx = self.cnx |
605 rdef = self.rdef = self.rschema.rdefs[self.rdefkey] |
605 rdef = self.rdef = self.rschema.rdefs[self.rdefkey] |
606 # update the in-memory schema first |
606 # update the in-memory schema first |
607 self.oldvalues = dict( (attr, getattr(rdef, attr)) for attr in self.values) |
607 self.oldvalues = dict( (attr, getattr(rdef, attr)) for attr in self.values) |
608 rdef.update(self.values) |
608 rdef.update(self.values) |
609 # then make necessary changes to the system source database |
609 # then make necessary changes to the system source database |
610 syssource = session.repo.system_source |
610 syssource = cnx.repo.system_source |
611 if 'indexed' in self.values: |
611 if 'indexed' in self.values: |
612 syssource.update_rdef_indexed(session, rdef) |
612 syssource.update_rdef_indexed(cnx, rdef) |
613 self.indexed_changed = True |
613 self.indexed_changed = True |
614 if 'cardinality' in self.values and (rdef.rtype.final or |
614 if 'cardinality' in self.values and (rdef.rtype.final or |
615 rdef.rtype.inlined) \ |
615 rdef.rtype.inlined) \ |
616 and self.values['cardinality'][0] != self.oldvalues['cardinality'][0]: |
616 and self.values['cardinality'][0] != self.oldvalues['cardinality'][0]: |
617 syssource.update_rdef_null_allowed(self.session, rdef) |
617 syssource.update_rdef_null_allowed(self.cnx, rdef) |
618 self.null_allowed_changed = True |
618 self.null_allowed_changed = True |
619 if 'fulltextindexed' in self.values: |
619 if 'fulltextindexed' in self.values: |
620 UpdateFTIndexOp.get_instance(session).add_data(rdef.subject) |
620 UpdateFTIndexOp.get_instance(cnx).add_data(rdef.subject) |
621 |
621 |
622 def revertprecommit_event(self): |
622 def revertprecommit_event(self): |
623 if self.rdef is None: |
623 if self.rdef is None: |
624 return |
624 return |
625 # revert changes on in memory schema |
625 # revert changes on in memory schema |
626 self.rdef.update(self.oldvalues) |
626 self.rdef.update(self.oldvalues) |
627 # revert changes on database |
627 # revert changes on database |
628 syssource = self.session.repo.system_source |
628 syssource = self.cnx.repo.system_source |
629 if self.indexed_changed: |
629 if self.indexed_changed: |
630 syssource.update_rdef_indexed(self.session, self.rdef) |
630 syssource.update_rdef_indexed(self.cnx, self.rdef) |
631 if self.null_allowed_changed: |
631 if self.null_allowed_changed: |
632 syssource.update_rdef_null_allowed(self.session, self.rdef) |
632 syssource.update_rdef_null_allowed(self.cnx, self.rdef) |
633 |
633 |
634 |
634 |
635 def _set_modifiable_constraints(rdef): |
635 def _set_modifiable_constraints(rdef): |
636 # for proper in-place modification of in-memory schema: if rdef.constraints |
636 # for proper in-place modification of in-memory schema: if rdef.constraints |
637 # is already a list, reuse it (we're updating multiple constraints of the |
637 # is already a list, reuse it (we're updating multiple constraints of the |
644 """actually remove a constraint of a relation definition""" |
644 """actually remove a constraint of a relation definition""" |
645 rdef = oldcstr = newcstr = None # make pylint happy |
645 rdef = oldcstr = newcstr = None # make pylint happy |
646 size_cstr_changed = unique_changed = False |
646 size_cstr_changed = unique_changed = False |
647 |
647 |
648 def precommit_event(self): |
648 def precommit_event(self): |
649 session = self.session |
649 cnx = self.cnx |
650 rdef = self.rdef |
650 rdef = self.rdef |
651 # in-place modification of in-memory schema first |
651 # in-place modification of in-memory schema first |
652 _set_modifiable_constraints(rdef) |
652 _set_modifiable_constraints(rdef) |
653 rdef.constraints.remove(self.oldcstr) |
653 rdef.constraints.remove(self.oldcstr) |
654 # then update database: alter the physical schema on size/unique |
654 # then update database: alter the physical schema on size/unique |
655 # constraint changes |
655 # constraint changes |
656 syssource = session.repo.system_source |
656 syssource = cnx.repo.system_source |
657 cstrtype = self.oldcstr.type() |
657 cstrtype = self.oldcstr.type() |
658 if cstrtype == 'SizeConstraint': |
658 if cstrtype == 'SizeConstraint': |
659 syssource.update_rdef_column(session, rdef) |
659 syssource.update_rdef_column(cnx, rdef) |
660 self.size_cstr_changed = True |
660 self.size_cstr_changed = True |
661 elif cstrtype == 'UniqueConstraint': |
661 elif cstrtype == 'UniqueConstraint': |
662 syssource.update_rdef_unique(session, rdef) |
662 syssource.update_rdef_unique(cnx, rdef) |
663 self.unique_changed = True |
663 self.unique_changed = True |
664 |
664 |
665 def revertprecommit_event(self): |
665 def revertprecommit_event(self): |
666 # revert changes on in memory schema |
666 # revert changes on in memory schema |
667 if self.newcstr is not None: |
667 if self.newcstr is not None: |
668 self.rdef.constraints.remove(self.newcstr) |
668 self.rdef.constraints.remove(self.newcstr) |
669 if self.oldcstr is not None: |
669 if self.oldcstr is not None: |
670 self.rdef.constraints.append(self.oldcstr) |
670 self.rdef.constraints.append(self.oldcstr) |
671 # revert changes on database |
671 # revert changes on database |
672 syssource = self.session.repo.system_source |
672 syssource = self.cnx.repo.system_source |
673 if self.size_cstr_changed: |
673 if self.size_cstr_changed: |
674 syssource.update_rdef_column(self.session, self.rdef) |
674 syssource.update_rdef_column(self.cnx, self.rdef) |
675 if self.unique_changed: |
675 if self.unique_changed: |
676 syssource.update_rdef_unique(self.session, self.rdef) |
676 syssource.update_rdef_unique(self.cnx, self.rdef) |
677 |
677 |
678 |
678 |
679 class CWConstraintAddOp(CWConstraintDelOp): |
679 class CWConstraintAddOp(CWConstraintDelOp): |
680 """actually update constraint of a relation definition""" |
680 """actually update constraint of a relation definition""" |
681 entity = None # make pylint happy |
681 entity = None # make pylint happy |
682 |
682 |
683 def precommit_event(self): |
683 def precommit_event(self): |
684 session = self.session |
684 cnx = self.cnx |
685 rdefentity = self.entity.reverse_constrained_by[0] |
685 rdefentity = self.entity.reverse_constrained_by[0] |
686 # when the relation is added in the same transaction, the constraint |
686 # when the relation is added in the same transaction, the constraint |
687 # object is created by the operation adding the attribute or relation, |
687 # object is created by the operation adding the attribute or relation, |
688 # so there is nothing to do here |
688 # so there is nothing to do here |
689 if session.added_in_transaction(rdefentity.eid): |
689 if cnx.added_in_transaction(rdefentity.eid): |
690 return |
690 return |
691 rdef = self.rdef = session.vreg.schema.schema_by_eid(rdefentity.eid) |
691 rdef = self.rdef = cnx.vreg.schema.schema_by_eid(rdefentity.eid) |
692 cstrtype = self.entity.type |
692 cstrtype = self.entity.type |
693 oldcstr = self.oldcstr = rdef.constraint_by_type(cstrtype) |
693 oldcstr = self.oldcstr = rdef.constraint_by_type(cstrtype) |
694 newcstr = self.newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value) |
694 newcstr = self.newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value) |
695 # in-place modification of in-memory schema first |
695 # in-place modification of in-memory schema first |
696 _set_modifiable_constraints(rdef) |
696 _set_modifiable_constraints(rdef) |
698 if oldcstr is not None: |
698 if oldcstr is not None: |
699 rdef.constraints.remove(oldcstr) |
699 rdef.constraints.remove(oldcstr) |
700 rdef.constraints.append(newcstr) |
700 rdef.constraints.append(newcstr) |
701 # then update database: alter the physical schema on size/unique |
701 # then update database: alter the physical schema on size/unique |
702 # constraint changes |
702 # constraint changes |
703 syssource = session.repo.system_source |
703 syssource = cnx.repo.system_source |
704 if cstrtype == 'SizeConstraint' and (oldcstr is None or |
704 if cstrtype == 'SizeConstraint' and (oldcstr is None or |
705 oldcstr.max != newcstr.max): |
705 oldcstr.max != newcstr.max): |
706 syssource.update_rdef_column(session, rdef) |
706 syssource.update_rdef_column(cnx, rdef) |
707 self.size_cstr_changed = True |
707 self.size_cstr_changed = True |
708 elif cstrtype == 'UniqueConstraint' and oldcstr is None: |
708 elif cstrtype == 'UniqueConstraint' and oldcstr is None: |
709 syssource.update_rdef_unique(session, rdef) |
709 syssource.update_rdef_unique(cnx, rdef) |
710 self.unique_changed = True |
710 self.unique_changed = True |
711 |
711 |
712 |
712 |
713 class CWUniqueTogetherConstraintAddOp(MemSchemaOperation): |
713 class CWUniqueTogetherConstraintAddOp(MemSchemaOperation): |
714 entity = None # make pylint happy |
714 entity = None # make pylint happy |
715 |
715 |
716 def precommit_event(self): |
716 def precommit_event(self): |
717 session = self.session |
717 cnx = self.cnx |
718 prefix = SQL_PREFIX |
718 prefix = SQL_PREFIX |
719 entity = self.entity |
719 entity = self.entity |
720 table = '%s%s' % (prefix, entity.constraint_of[0].name) |
720 table = '%s%s' % (prefix, entity.constraint_of[0].name) |
721 cols = ['%s%s' % (prefix, r.name) for r in entity.relations] |
721 cols = ['%s%s' % (prefix, r.name) for r in entity.relations] |
722 dbhelper = session.repo.system_source.dbhelper |
722 dbhelper = cnx.repo.system_source.dbhelper |
723 sqls = dbhelper.sqls_create_multicol_unique_index(table, cols, entity.name) |
723 sqls = dbhelper.sqls_create_multicol_unique_index(table, cols, entity.name) |
724 for sql in sqls: |
724 for sql in sqls: |
725 session.system_sql(sql) |
725 cnx.system_sql(sql) |
726 |
726 |
727 def postcommit_event(self): |
727 def postcommit_event(self): |
728 entity = self.entity |
728 entity = self.entity |
729 eschema = self.session.vreg.schema.schema_by_eid(entity.constraint_of[0].eid) |
729 eschema = self.cnx.vreg.schema.schema_by_eid(entity.constraint_of[0].eid) |
730 attrs = [r.name for r in entity.relations] |
730 attrs = [r.name for r in entity.relations] |
731 eschema._unique_together.append(attrs) |
731 eschema._unique_together.append(attrs) |
732 |
732 |
733 |
733 |
734 class CWUniqueTogetherConstraintDelOp(MemSchemaOperation): |
734 class CWUniqueTogetherConstraintDelOp(MemSchemaOperation): |
735 entity = cstrname = None # for pylint |
735 entity = cstrname = None # for pylint |
736 cols = () # for pylint |
736 cols = () # for pylint |
737 |
737 |
738 def precommit_event(self): |
738 def precommit_event(self): |
739 session = self.session |
739 cnx = self.cnx |
740 prefix = SQL_PREFIX |
740 prefix = SQL_PREFIX |
741 table = '%s%s' % (prefix, self.entity.type) |
741 table = '%s%s' % (prefix, self.entity.type) |
742 dbhelper = session.repo.system_source.dbhelper |
742 dbhelper = cnx.repo.system_source.dbhelper |
743 cols = ['%s%s' % (prefix, c) for c in self.cols] |
743 cols = ['%s%s' % (prefix, c) for c in self.cols] |
744 sqls = dbhelper.sqls_drop_multicol_unique_index(table, cols, self.cstrname) |
744 sqls = dbhelper.sqls_drop_multicol_unique_index(table, cols, self.cstrname) |
745 for sql in sqls: |
745 for sql in sqls: |
746 session.system_sql(sql) |
746 cnx.system_sql(sql) |
747 |
747 |
748 def postcommit_event(self): |
748 def postcommit_event(self): |
749 eschema = self.session.vreg.schema.schema_by_eid(self.entity.eid) |
749 eschema = self.cnx.vreg.schema.schema_by_eid(self.entity.eid) |
750 cols = set(self.cols) |
750 cols = set(self.cols) |
751 unique_together = [ut for ut in eschema._unique_together |
751 unique_together = [ut for ut in eschema._unique_together |
752 if set(ut) != cols] |
752 if set(ut) != cols] |
753 eschema._unique_together = unique_together |
753 eschema._unique_together = unique_together |
754 |
754 |
759 """actually remove the entity type from the instance's schema""" |
759 """actually remove the entity type from the instance's schema""" |
760 etype = None # make pylint happy |
760 etype = None # make pylint happy |
761 |
761 |
762 def postcommit_event(self): |
762 def postcommit_event(self): |
763 # del_entity_type also removes entity's relations |
763 # del_entity_type also removes entity's relations |
764 self.session.vreg.schema.del_entity_type(self.etype) |
764 self.cnx.vreg.schema.del_entity_type(self.etype) |
765 |
765 |
766 |
766 |
767 class MemSchemaCWRTypeAdd(MemSchemaOperation): |
767 class MemSchemaCWRTypeAdd(MemSchemaOperation): |
768 """actually add the relation type to the instance's schema""" |
768 """actually add the relation type to the instance's schema""" |
769 rtypedef = None # make pylint happy |
769 rtypedef = None # make pylint happy |
770 |
770 |
771 def precommit_event(self): |
771 def precommit_event(self): |
772 self.session.vreg.schema.add_relation_type(self.rtypedef) |
772 self.cnx.vreg.schema.add_relation_type(self.rtypedef) |
773 |
773 |
774 def revertprecommit_event(self): |
774 def revertprecommit_event(self): |
775 self.session.vreg.schema.del_relation_type(self.rtypedef.name) |
775 self.cnx.vreg.schema.del_relation_type(self.rtypedef.name) |
776 |
776 |
777 |
777 |
778 class MemSchemaCWRTypeDel(MemSchemaOperation): |
778 class MemSchemaCWRTypeDel(MemSchemaOperation): |
779 """actually remove the relation type from the instance's schema""" |
779 """actually remove the relation type from the instance's schema""" |
780 rtype = None # make pylint happy |
780 rtype = None # make pylint happy |
781 |
781 |
782 def postcommit_event(self): |
782 def postcommit_event(self): |
783 try: |
783 try: |
784 self.session.vreg.schema.del_relation_type(self.rtype) |
784 self.cnx.vreg.schema.del_relation_type(self.rtype) |
785 except KeyError: |
785 except KeyError: |
786 # s/o entity type have already been deleted |
786 # s/o entity type have already been deleted |
787 pass |
787 pass |
788 |
788 |
789 |
789 |
1024 __regid__ = 'syncdelrelationtype' |
1024 __regid__ = 'syncdelrelationtype' |
1025 __select__ = SyncSchemaHook.__select__ & hook.match_rtype('relation_type') |
1025 __select__ = SyncSchemaHook.__select__ & hook.match_rtype('relation_type') |
1026 events = ('after_delete_relation',) |
1026 events = ('after_delete_relation',) |
1027 |
1027 |
1028 def __call__(self): |
1028 def __call__(self): |
1029 session = self._cw |
1029 cnx = self._cw |
1030 try: |
1030 try: |
1031 rdef = session.vreg.schema.schema_by_eid(self.eidfrom) |
1031 rdef = cnx.vreg.schema.schema_by_eid(self.eidfrom) |
1032 except KeyError: |
1032 except KeyError: |
1033 self.critical('cant get schema rdef associated to %s', self.eidfrom) |
1033 self.critical('cant get schema rdef associated to %s', self.eidfrom) |
1034 return |
1034 return |
1035 subjschema, rschema, objschema = rdef.as_triple() |
1035 subjschema, rschema, objschema = rdef.as_triple() |
1036 pendingrdefs = session.transaction_data.setdefault('pendingrdefs', set()) |
1036 pendingrdefs = cnx.transaction_data.setdefault('pendingrdefs', set()) |
1037 # first delete existing relation if necessary |
1037 # first delete existing relation if necessary |
1038 if rschema.final: |
1038 if rschema.final: |
1039 rdeftype = 'CWAttribute' |
1039 rdeftype = 'CWAttribute' |
1040 pendingrdefs.add((subjschema, rschema)) |
1040 pendingrdefs.add((subjschema, rschema)) |
1041 else: |
1041 else: |
1042 rdeftype = 'CWRelation' |
1042 rdeftype = 'CWRelation' |
1043 pendingrdefs.add((subjschema, rschema, objschema)) |
1043 pendingrdefs.add((subjschema, rschema, objschema)) |
1044 if not (session.deleted_in_transaction(subjschema.eid) or |
1044 if not (cnx.deleted_in_transaction(subjschema.eid) or |
1045 session.deleted_in_transaction(objschema.eid)): |
1045 cnx.deleted_in_transaction(objschema.eid)): |
1046 session.execute('DELETE X %s Y WHERE X is %s, Y is %s' |
1046 cnx.execute('DELETE X %s Y WHERE X is %s, Y is %s' |
1047 % (rschema, subjschema, objschema)) |
1047 % (rschema, subjschema, objschema)) |
1048 RDefDelOp(session, rdef=rdef) |
1048 RDefDelOp(cnx, rdef=rdef) |
1049 |
1049 |
1050 |
1050 |
1051 # CWAttribute / CWRelation hooks ############################################### |
1051 # CWAttribute / CWRelation hooks ############################################### |
1052 |
1052 |
1053 class AfterAddCWAttributeHook(SyncSchemaHook): |
1053 class AfterAddCWAttributeHook(SyncSchemaHook): |
1217 We wait after the commit to as the schema in memory is only updated after |
1217 We wait after the commit to as the schema in memory is only updated after |
1218 the commit. |
1218 the commit. |
1219 """ |
1219 """ |
1220 |
1220 |
1221 def postcommit_event(self): |
1221 def postcommit_event(self): |
1222 session = self.session |
1222 cnx = self.cnx |
1223 source = session.repo.system_source |
1223 source = cnx.repo.system_source |
1224 schema = session.repo.vreg.schema |
1224 schema = cnx.repo.vreg.schema |
1225 to_reindex = self.get_data() |
1225 to_reindex = self.get_data() |
1226 self.info('%i etypes need full text indexed reindexation', |
1226 self.info('%i etypes need full text indexed reindexation', |
1227 len(to_reindex)) |
1227 len(to_reindex)) |
1228 for etype in to_reindex: |
1228 for etype in to_reindex: |
1229 rset = session.execute('Any X WHERE X is %s' % etype) |
1229 rset = cnx.execute('Any X WHERE X is %s' % etype) |
1230 self.info('Reindexing full text index for %i entity of type %s', |
1230 self.info('Reindexing full text index for %i entity of type %s', |
1231 len(rset), etype) |
1231 len(rset), etype) |
1232 still_fti = list(schema[etype].indexable_attributes()) |
1232 still_fti = list(schema[etype].indexable_attributes()) |
1233 for entity in rset.entities(): |
1233 for entity in rset.entities(): |
1234 source.fti_unindex_entities(session, [entity]) |
1234 source.fti_unindex_entities(cnx, [entity]) |
1235 for container in entity.cw_adapt_to('IFTIndexable').fti_containers(): |
1235 for container in entity.cw_adapt_to('IFTIndexable').fti_containers(): |
1236 if still_fti or container is not entity: |
1236 if still_fti or container is not entity: |
1237 source.fti_unindex_entities(session, [container]) |
1237 source.fti_unindex_entities(cnx, [container]) |
1238 source.fti_index_entities(session, [container]) |
1238 source.fti_index_entities(cnx, [container]) |
1239 if to_reindex: |
1239 if to_reindex: |
1240 # Transaction has already been committed |
1240 # Transaction has already been committed |
1241 session.cnxset.commit() |
1241 cnx.cnxset.commit() |
1242 |
1242 |
1243 |
1243 |
1244 |
1244 |
1245 |
1245 |
1246 # specializes synchronization hooks ############################################ |
1246 # specializes synchronization hooks ############################################ |