[FIX] openerp/osv/fields: disable prefetching when reading inverse of one2many fields
authorRaphael Collet <rco@openerp.com>
Tue, 9 Sep 2014 13:23:52 +0000 (15:23 +0200)
committerRaphael Collet <rco@openerp.com>
Wed, 10 Sep 2014 07:41:36 +0000 (09:41 +0200)
This fixes issue #2146.  The inverse of a one2many field can be an inherited
field (_inherits).  In that case, we cannot read its value with a simple
database query.  Instead, we let the related field read it, but for performance
considerations we disable the prefetching of other fields.

openerp/models.py
openerp/osv/fields.py

index ef5c2bb..79a61a7 100644 (file)
@@ -3155,6 +3155,9 @@ class BaseModel(object):
         elif self.env.field_todo(field):
             # field must be recomputed, do not prefetch records to recompute
             records -= self.env.field_todo(field)
+        elif not self._context.get('prefetch_fields', True):
+            # do not prefetch other fields
+            pass
         elif self._columns[field.name]._prefetch:
             # here we can optimize: prefetch all classic and many2one fields
             fnames = set(fname
index f11ef97..37fe2b1 100644 (file)
@@ -671,29 +671,20 @@ class one2many(_column):
             context = dict(context or {})
             context.update(self._context)
 
+        # retrieve the records in the comodel
         comodel = obj.pool[self._obj].browse(cr, user, [], context)
         inverse = self._fields_id
         domain = self._domain(obj) if callable(self._domain) else self._domain
         domain = domain + [(inverse, 'in', ids)]
-
         records = comodel.search(domain, limit=self._limit)
-        record_ids = map(int, records)
-
-        res = dict((id, []) for id in ids)
-        if record_ids:
-            cr.execute('SELECT id, %(inverse)s \
-                       FROM %(rel)s \
-                       WHERE id in %%s ' % {
-                        'inverse': inverse,
-                        'rel': comodel._table,
-                    }, (tuple(record_ids),))
-            record_value_id = dict(cr.fetchall())
-            # match the result per id, preserving the order
-            for record in records:
-                key = record_value_id[record.id]
-                res[key].append(record.id)
 
-        return res
+        result = {id: [] for id in ids}
+        # read the inverse of records without prefetching other fields on them
+        for record in records.with_context(prefetch_fields=False):
+            # record[inverse] may be a record or an integer
+            result[int(record[inverse])].append(record.id)
+
+        return result
 
     def set(self, cr, obj, id, field, values, user=None, context=None):
         result = []