[IMP] expression.py: added support of _auto_join in parse. The purpose is to add join clauses to queries instead of replacing many2one or one2many fields by id in ... equivalent leafs. This should lessen the number of executed queries, as well as the time required for some queries like mailboxes queries. Updated the generation of full table aliases when generating SQL, to avoid having a table having it own name as alias.

bzr revid: tde@openerp.com-20121128095042-x5rzgwydv0g9uy0m
This commit is contained in:
Thibault Delavallée 2012-11-28 10:50:42 +01:00
parent 0544565a57
commit ac587f68fe
1 changed files with 45 additions and 2 deletions

View File

@ -403,7 +403,11 @@ class expression(object):
def _get_full_alias(self, alias):
if not self._get_table_from_alias(alias):
return False
return '%s as %s' % (self._get_table_from_alias(alias)._table, alias)
table_name = self._get_table_from_alias(alias)._table
if table_name == alias:
return '"%s"' % alias
else:
return '"%s" as %s' % (table_name, alias)
def _add_table_alias(self, alias, table):
if not self._has_table_alias(alias):
@ -414,7 +418,7 @@ class expression(object):
def get_tables(self):
""" Returns the list of tables for SQL queries, like select from ... """
return ['"%s"' % item for item in self.table_aliases]
return [self._get_full_alias(item) for item in self.table_aliases]
def parse(self, cr, uid, exp, table, context):
""" Transform the leaves of the expression
@ -540,6 +544,7 @@ class expression(object):
# - get relational table that exists for relational fields
# - prepare the alias for tables, that can be the table name if only one-level
# - if domain is a path (ex: ('partner_id.name', '=', 'foo')):
# TDE TO ADD: once fully implemented, explain auto_join
# replace all the expression by a normalized equivalent domain
# - find the related ids: partner_id.name='foo' -> res_partner.search(('name', '=', 'foo')))
# - many2one: leaf becomes directly ('partner_id', 'in', 'partner_ids')
@ -555,6 +560,44 @@ class expression(object):
relational_table = table.pool.get(field._obj)
alias = working_table._table
while len(field_path) > 1 and field._auto_join:
if not field._type in ['many2one', 'one2many']:
raise '_auto_join attribute on something else than a many2one or one2many is currently not implemented... crashing'
previous_alias = alias
alias = alias + '__' + field_path[0]
if not self._get_table_from_alias(alias):
self._add_table_alias(alias, relational_table)
if field._type == 'many2one':
self.joins.append('%s."%s"=%s."%s"' % (alias, 'id', previous_alias, field_path[0]))
elif field._type == 'one2many':
self.joins.append('%s."%s"=%s."%s"' % (alias, field._fields_id, previous_alias, 'id'))
self.exp[i] = (alias + '.' + field_path[1], self.exp[i][1], self.exp[i][2])
# udpate working variables
field_path = field_path[1].split('.', 1)
working_table = relational_table
field = working_table._columns.get(field_path[0])
if not field:
if left == 'id' and operator == 'child_of':
ids2 = to_ids(right, table)
dom = child_of_domain(left, ids2, working_table)
self.exp = self.exp[:i] + dom + self.exp[i + 1:]
else:
# field could not be found in model columns, it's probably invalid, unless
# it's one of the _log_access special fields
# TODO: make these fields explicitly available in self.columns instead!
if field_path[0] not in MAGIC_COLUMNS:
raise ValueError("Invalid field %r in domain expression %r" % (left, exp))
break
# moved on top
relational_table = table.pool.get(field._obj)
if not field:
continue
if len(field_path) > 1:
if field._type == 'many2one':
right = relational_table.search(cr, uid, [(field_path[1], operator, right)], context=context)