summaryrefslogtreecommitdiff
path: root/odoo/osv
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2020-06-17 12:18:24 +0000
committerRaphael Collet <rco@odoo.com>2020-08-18 13:02:41 +0000
commit89963e0eddbf36d687799acb6ed1e8486cc178e7 (patch)
treebd2290f9a06428e0d102b59f088dbe66c508213a /odoo/osv
parent1a0feab95d7f555aa1786f9f696ac3fef5dbd042 (diff)
[IMP] core: inline SELECT many2one as subquery for one2many fields
This avoids the standalone query with a SELECT DISTINCT, which is costly to execute, and enables potential optimizations in the query execution.
Diffstat (limited to 'odoo/osv')
-rw-r--r--odoo/osv/expression.py36
1 files changed, 9 insertions, 27 deletions
diff --git a/odoo/osv/expression.py b/odoo/osv/expression.py
index 14d38dedbba..3b5d509df61 100644
--- a/odoo/osv/expression.py
+++ b/odoo/osv/expression.py
@@ -447,24 +447,6 @@ def check_leaf(element, internal=False):
# SQL utils
# --------------------------------------------------
-def select_from_where(cr, select_field, from_table, where_field, where_ids, where_operator):
- # todo: merge into parent query as sub-query
- res = []
- if where_ids:
- if where_operator in ['<', '>', '>=', '<=']:
- cr.execute('SELECT DISTINCT "%s" FROM "%s" WHERE "%s" %s %%s' % \
- (select_field, from_table, where_field, where_operator),
- (where_ids[0],)) # TODO shouldn't this be min/max(where_ids) ?
- res = [r[0] for r in cr.fetchall()]
- else: # TODO where_operator is supposed to be 'in'? It is called with child_of...
- for i in range(0, len(where_ids), cr.IN_MAX):
- subids = where_ids[i:i + cr.IN_MAX]
- cr.execute('SELECT DISTINCT "%s" FROM "%s" WHERE "%s" IN %%s' % \
- (select_field, from_table, where_field), (tuple(subids),))
- res.extend([r[0] for r in cr.fetchall()])
- return res
-
-
def get_unaccent_wrapper(cr):
if odoo.registry(cr.dbname).has_unaccent:
return lambda x: "unaccent(%s)" % (x,)
@@ -816,18 +798,18 @@ class expression(object):
if ids2 and inverse_is_int and domain:
ids2 = comodel.search([('id', 'in', ids2)] + domain, order='id').ids
- # determine ids1 in model related to ids2
- if not ids2:
- ids1 = []
- elif comodel._fields[field.inverse_name].store:
- ids1 = select_from_where(cr, field.inverse_name, comodel._table, 'id', ids2, operator)
+ if ids2 and comodel._fields[field.inverse_name].store:
+ op1 = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect'
+ subquery = 'SELECT "%s" FROM "%s" WHERE "id" IN %%s' % (field.inverse_name, comodel._table)
+ subparams = [tuple(ids2)]
+ push(('id', op1, (subquery, subparams)), model, alias, internal=True)
else:
+ # determine ids1 in model related to ids2
recs = comodel.browse(ids2).sudo().with_context(prefetch_fields=False)
ids1 = unwrap_inverse(recs.mapped(field.inverse_name))
-
- # rewrite condition in terms of ids1
- op1 = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
- push(('id', op1, ids1), model, alias)
+ # rewrite condition in terms of ids1
+ op1 = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
+ push(('id', op1, ids1), model, alias)
else:
if comodel._fields[field.inverse_name].store and not (inverse_is_int and domain):