# HG changeset patch # User Julien Cristau # Date 1421415055 -3600 # Node ID 1443fe643a38f1969bf3237198718009a107a4ac # Parent aaabcb64f77f4998b0ee45ae9e7e155178b870eb [server] change order of entities table modification vs entity creation/deletion In order to have a foreign key referencing the entities table, the insertion into entities must happen first, and the deletion must happen last. For the deletion case, this means we need to: 1. delete all relations (cascade) 2. delete the entities themselves 3. delete the corresponding lines from the entities table This means the _delete_info{,_multi} methods can't keep doing 1 and 3. Thankfully the "public" delete_info method appears to be unused, so drop it. Related to #4846892. diff -r aaabcb64f77f -r 1443fe643a38 server/repository.py --- a/server/repository.py Thu Jan 15 17:06:16 2015 +0100 +++ b/server/repository.py Fri Jan 16 14:30:55 2015 +0100 @@ -1074,48 +1074,9 @@ hook.CleanupNewEidsCacheOp.get_instance(session).add_data(entity.eid) self.system_source.add_info(session, entity, source, extid) - def delete_info(self, session, entity, sourceuri): - """called by external source when some entity known by the system source - has been deleted in the external source - """ - # mark eid as being deleted in session info and setup cache update - # operation - hook.CleanupDeletedEidsCacheOp.get_instance(session).add_data(entity.eid) - self._delete_info(session, entity, sourceuri) - - def _delete_info(self, session, entity, sourceuri): - """delete system information on deletion of an entity: - - * delete all remaining relations from/to this entity - * call delete info on the system source - """ - pendingrtypes = session.transaction_data.get('pendingrtypes', ()) - # delete remaining relations: if user can delete the entity, he can - # delete all its relations without security checking - with session.security_enabled(read=False, write=False): - eid = entity.eid - for rschema, _, role in entity.e_schema.relation_definitions(): - rtype = rschema.type - if rtype in schema.VIRTUAL_RTYPES or rtype in pendingrtypes: - continue - if role == 'subject': - # don't skip inlined relation so they are regularly - # deleted and so hooks are correctly called - rql = 'DELETE X %s Y WHERE X eid %%(x)s' % rtype - else: - rql = 'DELETE Y %s X WHERE X eid %%(x)s' % rtype - try: - session.execute(rql, {'x': eid}, build_descr=False) - except Exception: - if self.config.mode == 'test': - raise - self.exception('error while cascading delete for entity %s ' - 'from %s. RQL: %s', entity, sourceuri, rql) - self.system_source.delete_info_multi(session, [entity]) - - def _delete_info_multi(self, session, entities): - """same as _delete_info but accepts a list of entities with - the same etype and belinging to the same source. + def _delete_cascade_multi(self, session, entities): + """same as _delete_cascade but accepts a list of entities with + the same etype and belonging to the same source. """ pendingrtypes = session.transaction_data.get('pendingrtypes', ()) # delete remaining relations: if user can delete the entity, he can @@ -1146,7 +1107,6 @@ raise self.exception('error while cascading delete for entity %s. RQL: %s', entities, rql) - self.system_source.delete_info_multi(session, entities) def init_entity_caches(self, cnx, entity, source): """add entity to connection entities cache and repo's extid cache. @@ -1184,13 +1144,13 @@ edited.set_defaults() if cnx.is_hook_category_activated('integrity'): edited.check(creation=True) + self.add_info(cnx, entity, source, extid) try: source.add_entity(cnx, entity) except UniqueTogetherError as exc: userhdlr = cnx.vreg['adapters'].select( 'IUserFriendlyError', cnx, entity=entity, exc=exc) userhdlr.raise_user_exception() - self.add_info(cnx, entity, source, extid) edited.saved = entity._cw_is_saved = True # trigger after_add_entity after after_add_relation self.hm.call_hooks('after_add_entity', cnx, entity=entity) @@ -1305,8 +1265,9 @@ if server.DEBUG & server.DBG_REPO: print 'DELETE entities', etype, [entity.eid for entity in entities] self.hm.call_hooks('before_delete_entity', cnx, entities=entities) - self._delete_info_multi(cnx, entities) + self._delete_cascade_multi(cnx, entities) source.delete_entities(cnx, entities) + source.delete_info_multi(cnx, entities) self.hm.call_hooks('after_delete_entity', cnx, entities=entities) # don't clear cache here, it is done in a hook on commit diff -r aaabcb64f77f -r 1443fe643a38 server/sources/native.py --- a/server/sources/native.py Thu Jan 15 17:06:16 2015 +0100 +++ b/server/sources/native.py Fri Jan 16 14:30:55 2015 +0100 @@ -1182,10 +1182,10 @@ self.repo.hm.call_hooks('before_add_entity', cnx, entity=entity) # restore the entity action.changes['cw_eid'] = eid + # restore record in entities (will update fti if needed) + self.add_info(cnx, entity, self, None) sql = self.sqlgen.insert(SQL_PREFIX + etype, action.changes) self.doexec(cnx, sql, action.changes) - # restore record in entities (will update fti if needed) - self.add_info(cnx, entity, self, None) self.repo.hm.call_hooks('after_add_entity', cnx, entity=entity) return errors diff -r aaabcb64f77f -r 1443fe643a38 server/test/unittest_repository.py --- a/server/test/unittest_repository.py Thu Jan 15 17:06:16 2015 +0100 +++ b/server/test/unittest_repository.py Fri Jan 16 14:30:55 2015 +0100 @@ -692,7 +692,8 @@ cu = cnx.system_sql('SELECT * FROM entities WHERE eid = -1') data = cu.fetchall() self.assertEqual(tuplify(data), [(-1, 'Personne', 'system', None)]) - self.repo.delete_info(cnx, entity, 'system') + self.repo._delete_cascade_multi(cnx, [entity]) + self.repo.system_source.delete_info_multi(cnx, [entity]) #self.repo.commit() cu = cnx.system_sql('SELECT * FROM entities WHERE eid = -1') data = cu.fetchall()