Rémy Voet (ryv) fde7727dd8 [FIX] core: fix recursion error from unlink
On a model X, where there is a field related x_related
(related= 'y_id.y_translate') towards a translate field y_translate
on Model Y.
When you unlink at least 1001 records of X
(r1, r2, ... , r1000, r1001) (cr.MAX_IN + 1), you get a traceback
(`RecursionError: maximum recursion depth exceeded in comparison`).

The stack looks like:

File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 3609, in unlink
  self.env.flush_all()
File "/home/odoo/Documents/dev/odoo/odoo/api.py", line 732, in flush_all
  self._recompute_all()
File "/home/odoo/Documents/dev/odoo/odoo/api.py", line 728, in _recompute_all
  self[field.model_name]._recompute_field(field)
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 6179, in _recompute_field
  field.recompute(records)
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 1348, in recompute
  self.compute_value(record)
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 1368, in compute_value
  records._compute_field_value(self)
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 4209, in _compute_field_value
  fields.determine(field.compute, self)
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 100, in determine
  return needle(records, *args)
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 689, in _compute_related
  values = [first(value[name]) for value in values]
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 689, in <listcomp>
  values = [first(value[name]) for value in values]
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 5874, in __getitem__
  return self._fields[key].__get__(self, type(self))
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 2771, in __get__
  return super().__get__(records, owner)
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 1186, in __get__
  recs._fetch_field(self)
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 3162, in _fetch_field
  self._read(fnames)
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 3214, in _read
  self.flush_recordset(translated_field_names)
...

-> Extra info:
translated_field_names = ['x_related']
`self = X(r1001, r1, r2, ..., r999)`

...
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 5585, in flush_recordset
  self._recompute_recordset(fnames)
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 6162, in _recompute_recordset
  self._recompute_field(field, self._ids)
...

-> Long recursion starts here but first records to be recomputed will be r1, then r2, then r3, ...
But the maximum recursion depth error will be triggered earlier at the
end of the recursion, because the stack limit in Python is 1000
by default.
...
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 6179, in _recompute_field
    field.recompute(records)
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 1348, in recompute
  self.compute_value(record)
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 1368, in compute_value
  records._compute_field_value(self)
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 4209, in _compute_field_value
  fields.determine(field.compute, self)
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 100, in determine
  return needle(records, *args)
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 689, in _compute_related
  values = [first(value[name]) for value in values]
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 689, in <listcomp>
  values = [first(value[name]) for value in values]
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 5874, in __getitem__
  return self._fields[key].__get__(self, type(self))
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 2771, in __get__
  return super().__get__(records, owner)
File "/home/odoo/Documents/dev/odoo/odoo/fields.py", line 1186, in __get__
  recs._fetch_field(self)
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 3162, in _fetch_field
  self._read(fnames)
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 3214, in _read
  self.flush_recordset(translated_field_names)
...

------ Extra info:
translated_field_names = ['x_related']
`self = X(r1, r2, ... , r999)`
...

Since 9c3b9a4926, the `x_related` is
flagged to be recomputed at the end of the delete
loop of `unlink`, but it shouldn't be, because records are deleted now.
The problem is in these lines:
```python
with self.env.protecting(self._fields.values(), records):
    self.modified(self._fields, before=True)
```
The `records` are only a part of `self` (batch of 1000), so the
`protecting` call only protects the current batch and not `self`.
Then, the second batch (here with only one record), will flag to recompute
`x_related` of the first batch records. Then, later on, the `flush_all`
will generate the recursion error trying to resolve
these `to_recompute`.

To fix it, only move the modified call (+ protecting) before
the batch loop and executes it on `self`.

This issue shouldn't exist in master, because having a
related translate field triggers a warning (`Translated stored related
field (<field_name>) will not be computed correctly in all languages`).
Also `https://github.com/odoo/odoo/pull/100472` fixes the issue in
master, but it generates one SQL request by record, which isn't great.
Then in master, we should forward this commit (but test will be remove
because it generates the warning message).

closes odoo/odoo#119471

X-original-commit: 78450cae5900e267de439e4988b314aa644e76bd
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Rémy Voet <ryv@odoo.com>
2023-04-24 23:48:55 +02:00
2023-04-13 17:57:45 +02:00
…
…
2023-01-03 13:16:02 +01:00

Build Status Tech Doc Help Nightly Builds

Odoo

Odoo is a suite of web based open source business apps.

The main Odoo Apps include an Open Source CRM, Website Builder, eCommerce, Warehouse Management, Project Management, Billing & Accounting, Point of Sale, Human Resources, Marketing, Manufacturing, ...

Odoo Apps can be used as stand-alone applications, but they also integrate seamlessly so you get a full-featured Open Source ERP when you install several Apps.

Getting started with Odoo

For a standard installation please follow the Setup instructions from the documentation.

To learn the software, we recommend the Odoo eLearning, or Scale-up, the business game. Developers can start with the developer tutorials

S
Description
No description provided
Readme LGPL-3.0
3.4 GiB
Languages
Python 49.6%
JavaScript 47.8%
SCSS 2%
CSS 0.3%
HTML 0.2%