From f2a16187582ed697ffeea1522e4f0c745bf77016 Mon Sep 17 00:00:00 2001 From: Nans Lefebvre Date: Thu, 31 Oct 2019 10:01:03 +0000 Subject: [PATCH] [FIX] models: manage environment when loading records When testing the import of records, a flush should be done to check all databases constraints and fields computations. Moreover, in case an exception is raised within a savepoint, the environment should be cleaned up, to avoid tricky bugs (see below). We replace the manual handling of savepoints with the savepoint context manager, which already handles all of this. This code predates the context manager, so in a way it was archaic. When testing the import of records, the following could happen: "An unknown issue occurred during import (possibly lost connection, data limit exceeded or memory limits exceeded)." This would happen on project tasks; the fields 'working_hours_open', 'working_hours_close', 'working_days_open', 'working_days_close', all depend on the computation of _compute_elapsed. Because this is a test import, the records would raise a MissingError, and fields_to_compute would always contain 3 of the fields. The resulting is an infinite loop giving this error. opw 2092134 closes odoo/odoo#39682 X-original-commit: 1a315e87b05fcbdefcb3db6d8d4837f6cc3e835c Signed-off-by: Nans Lefebvre (len) Co-authored-by: Raphael Collet --- odoo/models.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/odoo/models.py b/odoo/models.py index 58bca634283..b9201de446b 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -859,6 +859,8 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): :type data: list(list(str)) :returns: {ids: list(int)|False, messages: [Message][, lastrow: int]} """ + self.flush() + # determine values of mode, current_module and noupdate mode = self._context.get('mode', 'init') current_module = self._context.get('module', '__import__') @@ -905,30 +907,27 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # try to create in batch try: - recs = self._load_records(data_list, mode == 'update') - ids.extend(recs.ids) - cr.execute('RELEASE SAVEPOINT model_load_save') + with cr.savepoint(): + recs = self._load_records(data_list, mode == 'update') + ids.extend(recs.ids) return except Exception: - cr.execute('ROLLBACK TO SAVEPOINT model_load_save') + pass # try again, this time record by record for rec_data in data_list: try: - cr.execute('SAVEPOINT model_load_save') - rec = self._load_records([rec_data], mode == 'update') - ids.append(rec.id) - cr.execute('RELEASE SAVEPOINT model_load_save') + with cr.savepoint(): + rec = self._load_records([rec_data], mode == 'update') + ids.append(rec.id) except psycopg2.Warning as e: info = rec_data['info'] messages.append(dict(info, type='warning', message=str(e))) - cr.execute('ROLLBACK TO SAVEPOINT model_load_save') except psycopg2.Error as e: info = rec_data['info'] messages.append(dict(info, type='error', **PGERROR_TO_OE[e.pgcode](self, fg, info, e))) # Failed to write, log to messages, rollback savepoint (to # avoid broken transaction) and keep going - cr.execute('ROLLBACK TO SAVEPOINT model_load_save') except Exception as e: _logger.exception("Error while loading record") info = rec_data['info'] @@ -937,7 +936,6 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): messages.append(dict(info, type='error', message=message, moreinfo=moreinfo)) # Failed for some reason, perhaps due to invalid data supplied, # rollback savepoint and keep going - cr.execute('ROLLBACK TO SAVEPOINT model_load_save') # make 'flush' available to the methods below, in the case where XMLID # resolution fails, for instance