From 64b95a01d05422886cfe557dce0f3be93cfe97d8 Mon Sep 17 00:00:00 2001 From: Adrian Torres Date: Tue, 24 Nov 2020 09:46:45 +0000 Subject: [PATCH] [FIX] base: do not prefetch fields to be uninstalled During the uninstall step of the registry, we perform a commit right after the uninstallation of all module data, this commit is performed right before the creation of a new registry, this means that said commit will call `flush_env` and thus `recompute` on an environment that is based on a stale Registry (memory and database are unsynchronized). This means that during this specific moment, there's a chance that the recompute function may have to fetch some fields it depends on to perform its computations if said fields are not in cache, this in turn means that it will try to prefetch fields that are potentially no longer in the database, making the registry crash and preventing the uninstall. This is what happened with multiple if not all `payment_*` modules, the main module `payment` depends on a `ir.module.module` record, most notably the `color` field of the `payment.acquirer` model which depends on the `state` field which in turn depends on the `ir.module.module.state` field. This meant that uninstalling a module such as `payment_paypal` triggered a recompute of `payment.acquirer.color` during uninstall, and to perform that computation we need several `payment.acquirer` fields to be fetched from cache or the database. If in cache, the uninstall would go through without a hitch, if not in cache, we would fetch the required fields from the database but we'd also attempt to prefetch the fields introduced by `payment_paypal` that had just been deleted from the database! To avoid this, the `_module_uninstall_data` method of `ir.model.data` will henceforth guarantee that `ir.model.fields` that are to-be-deleted will have their prefetch set to False, meaning only existing fields will be fetched from the database during the uninstall of extending modules. Fixes #60424 opw-2372598 closes odoo/odoo#62247 X-original-commit: 7bffd2df0d5d7eff841cdf7ba7cb6ea84a5c5c49 Signed-off-by: Raphael Collet (rco) Co-authored-by: Raphael Collet --- odoo/addons/base/models/ir_model.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/odoo/addons/base/models/ir_model.py b/odoo/addons/base/models/ir_model.py index 0eafd4e6cfe..1b5ea5e7794 100644 --- a/odoo/addons/base/models/ir_model.py +++ b/odoo/addons/base/models/ir_model.py @@ -2059,6 +2059,16 @@ class IrModelData(models.Model): else: records_items.append((data.model, data.res_id)) + # avoid prefetching fields that are going to be deleted: during uninstall, it is + # possible to perform a recompute (via flush_env) after the database columns have been + # deleted but before the new registry has been created, meaning the recompute will + # be executed on a stale registry, and if some of the data for executing the compute + # methods is not in cache it will be fetched, and fields that exist in the registry but not + # in the database will be prefetched, this will of course fail and prevent the uninstall. + for ir_field in self.env['ir.model.fields'].browse(field_ids): + field = self.pool[ir_field.model]._fields[ir_field.name] + field.prefetch = False + # to collect external ids of records that cannot be deleted undeletable_ids = []