1104 """ |
1104 """ |
1105 # begin by inserting eid/type/source/extid into the entities table |
1105 # begin by inserting eid/type/source/extid into the entities table |
1106 hook.CleanupNewEidsCacheOp.get_instance(session).add_data(entity.eid) |
1106 hook.CleanupNewEidsCacheOp.get_instance(session).add_data(entity.eid) |
1107 self.system_source.add_info(session, entity, source, extid, complete) |
1107 self.system_source.add_info(session, entity, source, extid, complete) |
1108 |
1108 |
1109 def delete_info(self, session, entity, sourceuri, extid, scleanup=None): |
1109 def delete_info(self, session, entity, sourceuri, scleanup=None): |
1110 """called by external source when some entity known by the system source |
1110 """called by external source when some entity known by the system source |
1111 has been deleted in the external source |
1111 has been deleted in the external source |
1112 """ |
1112 """ |
1113 # mark eid as being deleted in session info and setup cache update |
1113 # mark eid as being deleted in session info and setup cache update |
1114 # operation |
1114 # operation |
1115 hook.CleanupDeletedEidsCacheOp.get_instance(session).add_data(entity.eid) |
1115 hook.CleanupDeletedEidsCacheOp.get_instance(session).add_data(entity.eid) |
1116 self._delete_info(session, entity, sourceuri, extid, scleanup) |
1116 self._delete_info(session, entity, sourceuri, scleanup) |
1117 |
1117 |
1118 def _delete_info(self, session, entity, sourceuri, extid, scleanup=None): |
1118 def _delete_info(self, session, entity, sourceuri, scleanup=None): |
1119 """delete system information on deletion of an entity: |
1119 """delete system information on deletion of an entity: |
|
1120 |
1120 * delete all remaining relations from/to this entity |
1121 * delete all remaining relations from/to this entity |
|
1122 |
1121 * call delete info on the system source which will transfer record from |
1123 * call delete info on the system source which will transfer record from |
1122 the entities table to the deleted_entities table |
1124 the entities table to the deleted_entities table |
|
1125 |
|
1126 When scleanup is specified, it's expected to be the source's eid, in |
|
1127 which case we'll specify the target's relation source so that this |
|
1128 source is ignored. E.g. we want to delete relations stored locally, as |
|
1129 the deletion information comes from the external source, it's its |
|
1130 responsability to have cleaned-up its own relations. |
1123 """ |
1131 """ |
1124 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
1132 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
|
1133 if scleanup is not None: |
|
1134 source = self.sources_by_eid[scleanup] |
1125 # delete remaining relations: if user can delete the entity, he can |
1135 # delete remaining relations: if user can delete the entity, he can |
1126 # delete all its relations without security checking |
1136 # delete all its relations without security checking |
1127 with security_enabled(session, read=False, write=False): |
1137 with security_enabled(session, read=False, write=False): |
1128 eid = entity.eid |
1138 eid = entity.eid |
1129 for rschema, _, role in entity.e_schema.relation_definitions(): |
1139 for rschema, _, role in entity.e_schema.relation_definitions(): |
1135 # deleted and so hooks are correctly called |
1145 # deleted and so hooks are correctly called |
1136 rql = 'DELETE X %s Y WHERE X eid %%(x)s' % rtype |
1146 rql = 'DELETE X %s Y WHERE X eid %%(x)s' % rtype |
1137 else: |
1147 else: |
1138 rql = 'DELETE Y %s X WHERE X eid %%(x)s' % rtype |
1148 rql = 'DELETE Y %s X WHERE X eid %%(x)s' % rtype |
1139 if scleanup is not None: |
1149 if scleanup is not None: |
|
1150 # if the relation can't be crossed, nothing to cleanup (we |
|
1151 # would get a BadRQLQuery from the multi-sources planner). |
|
1152 # This may still leave some junk if the mapping has changed |
|
1153 # at some point, but one can still run db-check to catch |
|
1154 # those |
|
1155 if not source in self.can_cross_relation(rtype): |
|
1156 continue |
1140 # source cleaning: only delete relations stored locally |
1157 # source cleaning: only delete relations stored locally |
1141 # (here, scleanup |
1158 # (here, scleanup |
1142 rql += ', NOT (Y cw_source S, S eid %(seid)s)' |
1159 rql += ', NOT (Y cw_source S, S eid %(seid)s)' |
1143 try: |
1160 try: |
1144 session.execute(rql, {'x': eid, 'seid': scleanup}, |
1161 session.execute(rql, {'x': eid, 'seid': scleanup}, |
1145 build_descr=False) |
1162 build_descr=False) |
1146 except Exception: |
1163 except Exception: |
|
1164 if self.config.mode == 'test': |
|
1165 raise |
1147 self.exception('error while cascading delete for entity %s ' |
1166 self.exception('error while cascading delete for entity %s ' |
1148 'from %s. RQL: %s', entity, sourceuri, rql) |
1167 'from %s. RQL: %s', entity, sourceuri, rql) |
1149 self.system_source.delete_info_multi(session, [entity], sourceuri) |
1168 self.system_source.delete_info_multi(session, [entity], sourceuri) |
1150 |
1169 |
1151 def _delete_info_multi(self, session, entities, sourceuri, scleanup=None): |
1170 def _delete_info_multi(self, session, entities, sourceuri, scleanup=None): |
1152 """same as _delete_info but accepts a list of entities with |
1171 """same as _delete_info but accepts a list of entities with |
1153 the same etype and belinging to the same source. |
1172 the same etype and belinging to the same source. |
1154 """ |
1173 """ |
1155 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
1174 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
|
1175 if scleanup is not None: |
|
1176 source = self.sources_by_eid[scleanup] |
1156 # delete remaining relations: if user can delete the entity, he can |
1177 # delete remaining relations: if user can delete the entity, he can |
1157 # delete all its relations without security checking |
1178 # delete all its relations without security checking |
1158 with security_enabled(session, read=False, write=False): |
1179 with security_enabled(session, read=False, write=False): |
1159 eids = [_e.eid for _e in entities] |
1180 eids = [_e.eid for _e in entities] |
1160 in_eids = ','.join((str(eid) for eid in eids)) |
1181 in_eids = ','.join((str(eid) for eid in eids)) |
1167 # deleted and so hooks are correctly called |
1188 # deleted and so hooks are correctly called |
1168 rql = 'DELETE X %s Y WHERE X eid IN (%s)' % (rtype, in_eids) |
1189 rql = 'DELETE X %s Y WHERE X eid IN (%s)' % (rtype, in_eids) |
1169 else: |
1190 else: |
1170 rql = 'DELETE Y %s X WHERE X eid IN (%s)' % (rtype, in_eids) |
1191 rql = 'DELETE Y %s X WHERE X eid IN (%s)' % (rtype, in_eids) |
1171 if scleanup is not None: |
1192 if scleanup is not None: |
|
1193 # if the relation can't be crossed, nothing to cleanup (we |
|
1194 # would get a BadRQLQuery from the multi-sources planner). |
|
1195 # This may still leave some junk if the mapping has changed |
|
1196 # at some point, but one can still run db-check to catch |
|
1197 # those |
|
1198 if not source in self.can_cross_relation(rtype): |
|
1199 continue |
1172 # source cleaning: only delete relations stored locally |
1200 # source cleaning: only delete relations stored locally |
1173 rql += ', NOT (Y cw_source S, S eid %(seid)s)' |
1201 rql += ', NOT (Y cw_source S, S eid %(seid)s)' |
1174 try: |
1202 try: |
1175 session.execute(rql, {'seid': scleanup}, build_descr=False) |
1203 session.execute(rql, {'seid': scleanup}, build_descr=False) |
1176 except Exception: |
1204 except Exception: |
|
1205 if self.config.mode == 'test': |
|
1206 raise |
1177 self.exception('error while cascading delete for entity %s ' |
1207 self.exception('error while cascading delete for entity %s ' |
1178 'from %s. RQL: %s', entities, sourceuri, rql) |
1208 'from %s. RQL: %s', entities, sourceuri, rql) |
1179 self.system_source.delete_info_multi(session, entities, sourceuri) |
1209 self.system_source.delete_info_multi(session, entities, sourceuri) |
1180 |
1210 |
1181 def locate_relation_source(self, session, subject, rtype, object): |
1211 def locate_relation_source(self, session, subject, rtype, object): |