[FIX] base: don't recompute while performing the bulk of the unlink
If a record is deleted *and* has property fields, the deletion of the property fields will trigger the various recomputes before the record itself has actually been deleted, and thus stuff which depend(ed) on that record will be recomputed under the assumption that the record still exists, which probably will not work. Under the assumption that the same issue would occur when deleting more than one batch of records (unlinking the data, values or attachment would also trigger a recompute before the proper end of the function and could lead to incoherence, e.g. some of the records being deleted being visible to recomputes), lift the entire effective body of the unlink into a norecompute context, to ensure that only the very final recompute (from the top-level unlink) is actually triggered. opw-807036
This commit is contained in:
committed by
Nicolas Martinelli
parent
a583a56324
commit
fc55d649d6
+40
-39
@@ -3388,53 +3388,54 @@ class BaseModel(object):
|
||||
raise UserError(_('Unable to delete this document because it is used as a default property'))
|
||||
|
||||
# Delete the records' properties.
|
||||
self.env['ir.property'].search([('res_id', 'in', refs)]).unlink()
|
||||
with self.env.norecompute():
|
||||
self.env['ir.property'].search([('res_id', 'in', refs)]).unlink()
|
||||
|
||||
self.delete_workflow()
|
||||
self.delete_workflow()
|
||||
|
||||
self.check_access_rule('unlink')
|
||||
self.check_access_rule('unlink')
|
||||
|
||||
cr = self._cr
|
||||
Data = self.env['ir.model.data'].sudo().with_context({})
|
||||
Values = self.env['ir.values']
|
||||
Attachment = self.env['ir.attachment']
|
||||
cr = self._cr
|
||||
Data = self.env['ir.model.data'].sudo().with_context({})
|
||||
Values = self.env['ir.values']
|
||||
Attachment = self.env['ir.attachment']
|
||||
|
||||
for sub_ids in cr.split_for_in_conditions(self.ids):
|
||||
query = "DELETE FROM %s WHERE id IN %%s" % self._table
|
||||
cr.execute(query, (sub_ids,))
|
||||
for sub_ids in cr.split_for_in_conditions(self.ids):
|
||||
query = "DELETE FROM %s WHERE id IN %%s" % self._table
|
||||
cr.execute(query, (sub_ids,))
|
||||
|
||||
# Removing the ir_model_data reference if the record being deleted
|
||||
# is a record created by xml/csv file, as these are not connected
|
||||
# with real database foreign keys, and would be dangling references.
|
||||
#
|
||||
# Note: the following steps are performed as superuser to avoid
|
||||
# access rights restrictions, and with no context to avoid possible
|
||||
# side-effects during admin calls.
|
||||
data = Data.search([('model', '=', self._name), ('res_id', 'in', sub_ids)])
|
||||
if data:
|
||||
data.unlink()
|
||||
# Removing the ir_model_data reference if the record being deleted
|
||||
# is a record created by xml/csv file, as these are not connected
|
||||
# with real database foreign keys, and would be dangling references.
|
||||
#
|
||||
# Note: the following steps are performed as superuser to avoid
|
||||
# access rights restrictions, and with no context to avoid possible
|
||||
# side-effects during admin calls.
|
||||
data = Data.search([('model', '=', self._name), ('res_id', 'in', sub_ids)])
|
||||
if data:
|
||||
data.unlink()
|
||||
|
||||
# For the same reason, remove the relevant records in ir_values
|
||||
refs = ['%s,%s' % (self._name, i) for i in sub_ids]
|
||||
values = Values.search(['|', ('value', 'in', refs),
|
||||
'&', ('model', '=', self._name),
|
||||
('res_id', 'in', sub_ids)])
|
||||
if values:
|
||||
values.unlink()
|
||||
# For the same reason, remove the relevant records in ir_values
|
||||
refs = ['%s,%s' % (self._name, i) for i in sub_ids]
|
||||
values = Values.search(['|', ('value', 'in', refs),
|
||||
'&', ('model', '=', self._name),
|
||||
('res_id', 'in', sub_ids)])
|
||||
if values:
|
||||
values.unlink()
|
||||
|
||||
# For the same reason, remove the relevant records in ir_attachment
|
||||
# (the search is performed with sql as the search method of
|
||||
# ir_attachment is overridden to hide attachments of deleted
|
||||
# records)
|
||||
query = 'SELECT id FROM ir_attachment WHERE res_model=%s AND res_id IN %s'
|
||||
cr.execute(query, (self._name, sub_ids))
|
||||
attachments = Attachment.browse([row[0] for row in cr.fetchall()])
|
||||
if attachments:
|
||||
attachments.unlink()
|
||||
# For the same reason, remove the relevant records in ir_attachment
|
||||
# (the search is performed with sql as the search method of
|
||||
# ir_attachment is overridden to hide attachments of deleted
|
||||
# records)
|
||||
query = 'SELECT id FROM ir_attachment WHERE res_model=%s AND res_id IN %s'
|
||||
cr.execute(query, (self._name, sub_ids))
|
||||
attachments = Attachment.browse([row[0] for row in cr.fetchall()])
|
||||
if attachments:
|
||||
attachments.unlink()
|
||||
|
||||
# invalidate the *whole* cache, since the orm does not handle all
|
||||
# changes made in the database, like cascading delete!
|
||||
self.invalidate_cache()
|
||||
# invalidate the *whole* cache, since the orm does not handle all
|
||||
# changes made in the database, like cascading delete!
|
||||
self.invalidate_cache()
|
||||
|
||||
# recompute new-style fields
|
||||
if self.env.recompute and self._context.get('recompute', True):
|
||||
|
||||
Reference in New Issue
Block a user