Skip to content

Commit 404a071

Browse files
committed
[FIX] util/orm: don't mark inherited field manual for custom
During the upgrade process, inherited fields were incorrectly marked as `manual`, whereas they should retain their original `base` state. like Fields created through Studio or `ir.model.fields` are expected to have `state = manual`, while inherited fields are set up by the ORM with `state = base` [1]. Marking inherited fields as `manual` makes the ORM treat them as independently created fields, which can trigger unnecessary computations, e.g for non-stored fields and `Many2many` fields related to `ir.attachment`. This change ensures that: * inherited fields retain `state = base` * only fields explicitly `ir.model.fields` are marked as `manual` or custom module field should mark as `manual` * field setup remains consistent with the ORM behavior This prevents inherited fields from being treated as independent fields and avoids unwanted computations during mock crawl. [1]: https://github.com/odoo/odoo/blob/d58f4ed332af35f6de26a93f07adf05368731e20/odoo/orm/model_classes.py#L493-L508 ``` ('account.product_product_menu_sellable', 122, 'Accounting > Customers > Products', 254): Traceback (most recent call last): File "/tmp/tmpqgivh7_j/migrations/base/tests/test_mock_crawl.py", line 335, in crawl_menu self.mock_action(action_vals) File "/tmp/tmpqgivh7_j/migrations/base/tests/test_mock_crawl.py", line 348, in mock_action return self.mock_act_window(action) File "/tmp/tmpqgivh7_j/migrations/base/tests/test_mock_crawl.py", line 432, in mock_act_window views = get_views( File "/home/odoo/src/odoo/19.0/addons/mail/models/mail_thread.py", line 471, in get_views res = super().get_views(views, options) File "/home/odoo/src/enterprise/19.0/web_studio/models/models.py", line 10, in get_views result = super().get_views(views, options=options) File "/home/odoo/src/enterprise/19.0/web_studio/models/ir_ui_view.py", line 52, in get_views return super().get_views(views, options) File "/home/odoo/src/odoo/19.0/odoo/addons/base/models/ir_ui_view.py", line 2946, in get_views result['models'][model] = {"fields": self.env[model].fields_get( File "/home/odoo/src/enterprise/19.0/web_studio/models/ir_model.py", line 76, in fields_get return super().fields_get(allfields, attributes=attributes) File "/home/odoo/src/enterprise/19.0/ai_fields/models/models.py", line 47, in fields_get res = super().fields_get(allfields, attributes) File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 3361, in fields_get description = field.get_description(self.env, attributes=attributes) File "/home/odoo/src/odoo/19.0/odoo/orm/fields.py", line 884, in get_description value = value(env) File "/home/odoo/src/odoo/19.0/odoo/orm/fields.py", line 937, in _description_groupable model._read_group_groupby(model._table, groupby, query) File "/home/odoo/src/odoo/19.0/addons/mail/models/mail_activity_mixin.py", line 257, in _read_group_groupby return super()._read_group_groupby(alias, groupby_spec, query) File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 2064, in _read_group_groupby coquery = comodel._search(codomain, bypass_access=field.bypass_search_access) File "/home/odoo/src/odoo/19.0/odoo/addons/base/models/ir_attachment.py", line 677, in _search records = self.sudo().with_context(active_test=False).search_fetch( File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 1418, in search_fetch return self._fetch_query(query, fields_to_fetch) File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 3917, in _fetch_query rows = self.env.execute_query(query.select(*sql_terms)) File "/home/odoo/src/odoo/19.0/odoo/orm/environments.py", line 534, in execute_query self.cr.execute(query) File "/home/odoo/src/odoo/19.0/odoo/tests/test_cursor.py", line 79, in execute return self._cursor.execute(*args, **kwargs) File "/home/odoo/src/odoo/19.0/odoo/sql_db.py", line 433, in execute self._obj.execute(query, params) psycopg2.DatabaseError: out of memory for query result ``` upg-4179716 opw-6101425
1 parent 3c8babe commit 404a071

1 file changed

Lines changed: 40 additions & 22 deletions

File tree

src/util/orm.py

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
from itertools import chain
1717
from textwrap import dedent
1818

19+
from psycopg2 import sql
20+
1921
try:
2022
from unittest.mock import patch
2123
except ImportError:
@@ -663,34 +665,50 @@ def custom_module_field_as_manual(env, rollback=True, do_flush=False):
663665
# if the field was not correctly removed from the database during past upgrades, the field remains in the database.
664666
reserved_words = ["env"]
665667
ignores = {"ir.actions.server": ["condition"], "ir.ui.view": ["page"]}
668+
669+
cte = ""
670+
include = ""
671+
if version_gte("17.0"):
672+
cte = """
673+
WITH delegated_fields AS (
674+
SELECT array_agg(f.id) AS ids
675+
FROM ir_model_fields f
676+
JOIN ir_model m
677+
ON m.id = f.model_id
678+
AND m.model = %(model)s
679+
JOIN ir_model_inherit i
680+
ON i.model_id = m.id
681+
AND i.parent_field_id IS NOT NULL
682+
JOIN ir_model_fields lf
683+
ON lf.id = i.parent_field_id
684+
WHERE f.related = lf.name || '.' || f.name
685+
)
686+
"""
687+
include = "AND id NOT IN (SELECT unnest(ids) FROM delegated_fields)"
688+
689+
query = format_query(
690+
env.cr,
691+
"""
692+
{cte}
693+
UPDATE ir_model_fields
694+
SET state = 'manual'
695+
WHERE state = 'base'
696+
AND model = %(model)s
697+
AND name NOT IN %(fields)s
698+
{include}
699+
RETURNING id
700+
""",
701+
cte=sql.SQL(cte),
702+
include=sql.SQL(include),
703+
)
666704
for model in models:
667705
model_fields = tuple(list(env.registry[model]._fields) + reserved_words + ignores.get(model, []))
668-
env.cr.execute(
669-
"""
670-
UPDATE ir_model_fields
671-
SET state = 'manual'
672-
WHERE state = 'base'
673-
AND model = %s
674-
AND name not in %s
675-
RETURNING id
676-
""",
677-
[model, model_fields],
678-
)
706+
env.cr.execute(query, {"model": model, "fields": model_fields})
679707
updated_field_ids += [r[0] for r in env.cr.fetchall()]
680708

681709
# 2.2 Convert fields of custom models, models that were just converted to `manual` models in the previous step.
682710
for model in custom_models:
683-
env.cr.execute(
684-
"""
685-
UPDATE ir_model_fields
686-
SET state = 'manual'
687-
WHERE state = 'base'
688-
AND model = %s
689-
AND name not in %s
690-
RETURNING id
691-
""",
692-
(model, tuple(reserved_words)),
693-
)
711+
env.cr.execute(query, {"model": model, "fields": model_fields})
694712
updated_field_ids += [r[0] for r in env.cr.fetchall()]
695713

696714
# 2.3 Temporarily disable rules that come from custom modules

0 commit comments

Comments
 (0)