changeset 822db4b23ad1 in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset&node=822db4b23ad1
description:
        Recompute path if part of the old path has already been updated

        This happens when multiple parent are modified at the same time.
        In such case the new path previously computed is no more correct.

        issue11266
        review368141002
diffstat:

 trytond/model/modelsql.py  |  31 +++++++++++++++++++++----------
 trytond/tests/test_tree.py |  17 +++++++++++++++++
 2 files changed, 38 insertions(+), 10 deletions(-)

diffs (75 lines):

diff -r 5d979ddb683c -r 822db4b23ad1 trytond/model/modelsql.py
--- a/trytond/model/modelsql.py Mon Feb 21 00:52:10 2022 +0100
+++ b/trytond/model/modelsql.py Tue Feb 22 22:57:03 2022 +0100
@@ -1640,6 +1640,24 @@
         update = transaction.connection.cursor()
         table = cls.__table__()
         parent = cls.__table__()
+
+        def update_path(query, column, sub_ids):
+            updated = set()
+            query.where = reduce_ids(table.id, sub_ids)
+            cursor.execute(*query)
+            for old_path, new_path in cursor:
+                if old_path == new_path:
+                    continue
+                if any(old_path.startswith(p) for p in updated):
+                    return False
+                update.execute(*table.update(
+                        [column],
+                        [Concat(new_path,
+                                Substring(table.path, len(old_path) + 1))],
+                        where=table.path.like(old_path + '%')))
+                updated.add(old_path)
+            return True
+
         for field_name, ids in zip(field_names, list_ids):
             field = cls._fields[field_name]
             parent_column = Column(table, field_name)
@@ -1652,16 +1670,9 @@
                     Concat(Concat(
                             Coalesce(parent_path_column, ''), table.id), '/')))
             for sub_ids in grouped_slice(ids):
-                query.where = reduce_ids(table.id, sub_ids)
-                cursor.execute(*query)
-                for old_path, new_path in cursor:
-                    if old_path == new_path:
-                        continue
-                    update.execute(*table.update(
-                            [path_column],
-                            [Concat(new_path,
-                                    Substring(table.path, len(old_path) + 1))],
-                            where=table.path.like(old_path + '%')))
+                sub_ids = list(sub_ids)
+                while not update_path(query, path_column, sub_ids):
+                    pass
 
     @classmethod
     def _update_mptt(cls, field_names, list_ids, values=None):
diff -r 5d979ddb683c -r 822db4b23ad1 trytond/tests/test_tree.py
--- a/trytond/tests/test_tree.py        Mon Feb 21 00:52:10 2022 +0100
+++ b/trytond/tests/test_tree.py        Tue Feb 22 22:57:03 2022 +0100
@@ -140,6 +140,23 @@
         Model.delete(records)
         self.check_tree()
 
+    @with_transaction()
+    def test_write_multiple_parents(self):
+        "Test write multiple parents"
+        pool = Pool()
+        Model = pool.get(self.model_name)
+
+        record1 = Model(name="Root")
+        record1.save()
+        record2 = Model(name="Child", parent=record1)
+        record2.save()
+        record3 = Model(name="Grand Child", parent=record2)
+        record3.save()
+        self.check_tree()
+
+        Model.write([record2, record3], {'parent': None})
+        self.check_tree()
+
     def rebuild(self):
         raise NotImplementedError
 

Reply via email to