Thibault Delavallée (OpenERP) has proposed merging 
lp:~openerp-dev/openobject-server/trunk-join-speedup-tde into 
lp:openobject-server.

Requested reviews:
  OpenERP Core Team (openerp)

For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-join-speedup-tde/+merge/136438

Perform auto-join and needaction speed update

fields: added the _auto_join option
expression.py
- added management of _auto_join in parsing of domains
-- 
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-join-speedup-tde/+merge/136438
Your team OpenERP R&D Team is subscribed to branch 
lp:~openerp-dev/openobject-server/trunk-join-speedup-tde.
=== modified file 'openerp/addons/base/ir/ir_needaction.py'
--- openerp/addons/base/ir/ir_needaction.py	2012-09-04 10:32:42 +0000
+++ openerp/addons/base/ir/ir_needaction.py	2012-11-27 15:08:08 +0000
@@ -21,6 +21,7 @@
 
 from osv import osv
 
+
 class ir_needaction_mixin(osv.AbstractModel):
     '''Mixin class for objects using the need action feature.
 
@@ -60,4 +61,4 @@
         dom = self._needaction_domain_get(cr, uid, context=context)
         if not dom:
             return 0
-        return self.search(cr, uid, (domain or []) +dom, context=context, count=True)
+        return self.search(cr, uid, (domain or []) + dom, limit=100, context=context, count=True)

=== modified file 'openerp/addons/base/ir/ir_ui_menu.py'
--- openerp/addons/base/ir/ir_ui_menu.py	2012-10-29 10:46:36 +0000
+++ openerp/addons/base/ir/ir_ui_menu.py	2012-11-27 15:08:08 +0000
@@ -249,7 +249,7 @@
         icon_image = False
         if icon_path:
             try:
-                icon_file = tools.file_open(icon_path,'rb')
+                icon_file = tools.file_open(icon_path, 'rb')
                 icon_image = base64.encodestring(icon_file.read())
             finally:
                 icon_file.close()
@@ -265,17 +265,26 @@
 
         return res
 
-    def _get_needaction(self, cr, uid, ids, field_names, args, context=None):
+    def _get_needaction_enabled(self, cr, uid, ids, field_names, args, context=None):
+        res = dict.fromkeys(ids, False)
+        for menu in self.browse(cr, uid, ids, context=context):
+            if menu.action and menu.action.type in ('ir.actions.act_window', 'ir.actions.client') and menu.action.res_model:
+                obj = self.pool.get(menu.action.res_model)
+                if obj and obj._needaction:
+                    res[menu.id] = True
+        return res
+
+    def get_needaction_data(self, cr, uid, ids, context=None):
         res = {}
         for menu in self.browse(cr, uid, ids, context=context):
             res[menu.id] = {
                 'needaction_enabled': False,
                 'needaction_counter': False,
             }
-            if menu.action and menu.action.type in ('ir.actions.act_window','ir.actions.client') and menu.action.res_model:
+            if menu.action and menu.action.type in ('ir.actions.act_window', 'ir.actions.client') and menu.action.res_model:
                 obj = self.pool.get(menu.action.res_model)
                 if obj and obj._needaction:
-                    if menu.action.type=='ir.actions.act_window':
+                    if menu.action.type == 'ir.actions.act_window':
                         dom = menu.action.domain and eval(menu.action.domain, {'uid': uid}) or []
                     else:
                         dom = eval(menu.action.params_store or '{}', {'uid': uid}).get('domain')
@@ -286,7 +295,7 @@
     _columns = {
         'name': fields.char('Menu', size=64, required=True, translate=True),
         'sequence': fields.integer('Sequence'),
-        'child_id' : fields.one2many('ir.ui.menu', 'parent_id','Child IDs'),
+        'child_id': fields.one2many('ir.ui.menu', 'parent_id', 'Child IDs'),
         'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True),
         'groups_id': fields.many2many('res.groups', 'ir_ui_menu_group_rel',
             'menu_id', 'gid', 'Groups', help="If you have groups, the visibility of this menu will be based on these groups. "\
@@ -296,11 +305,13 @@
         'icon': fields.selection(tools.icons, 'Icon', size=64),
         'icon_pict': fields.function(_get_icon_pict, type='char', size=32),
         'web_icon': fields.char('Web Icon File', size=128),
-        'web_icon_hover':fields.char('Web Icon File (hover)', size=128),
+        'web_icon_hover': fields.char('Web Icon File (hover)', size=128),
         'web_icon_data': fields.function(_get_image_icon, string='Web Icon Image', type='binary', readonly=True, store=True, multi='icon'),
-        'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'),
-        'needaction_enabled': fields.function(_get_needaction, string='Target model uses the need action mechanism', type='boolean', help='If the menu entry action is an act_window action, and if this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.', multi='_get_needaction'),
-        'needaction_counter': fields.function(_get_needaction, string='Number of actions the user has to perform', type='integer', help='If the target model uses the need action mechanism, this field gives the number of actions the current user has to perform.', multi='_get_needaction'),
+        'web_icon_hover_data': fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', readonly=True, store=True, multi='icon'),
+        'needaction_enabled': fields.function(_get_needaction_enabled,
+            type='boolean', store=True,
+            string='Target model uses the need action mechanism',
+            help='If the menu entry action is an act_window action, and if this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false.'),
         'action': fields.function(_action, fnct_inv=_action_inv,
             type='reference', string='Action',
             selection=[

=== modified file 'openerp/osv/expression.py'
--- openerp/osv/expression.py	2012-10-18 12:47:50 +0000
+++ openerp/osv/expression.py	2012-11-27 15:08:08 +0000
@@ -362,11 +362,24 @@
     """
 
     def __init__(self, cr, uid, exp, table, context):
+        """ Initialize expression object and automatically parse the expression
+            right after initialization.
+
+            :param exp: expression (using domain ('foo', '=', 'bar' format))
+            :param table: root table object
+
+            :attr dict leaf_to_table: used to store the table to use for the
+                sql generation, according to the domain leaf.
+                structure: { [leaf index]: table object }
+            :attr set table_aliases: set of aliases.
+            :attr list joins: list of join conditions, such as (res_country_state."id" = res_partner."state_id")
+            :attr root_table: root table, set by parse()
+        """
         self.has_unaccent = openerp.modules.registry.RegistryManager.get(cr.dbname).has_unaccent
-        self.__field_tables = {}  # used to store the table to use for the sql generation. key = index of the leaf
-        self.__all_tables = set()
-        self.__joins = []
-        self.__main_table = None # 'root' table. set by parse()
+        self.leaf_to_table = {}
+        self.table_aliases = set()
+        self.joins = []
+        self.root_table = None
         # assign self.__exp with the normalized, parsed domain.
         self.parse(cr, uid, distribute_not(normalize(exp)), table, context)
 
@@ -378,8 +391,8 @@
     def parse(self, cr, uid, exp, table, context):
         """ transform the leaves of the expression """
         self.__exp = exp
-        self.__main_table = table
-        self.__all_tables.add(table)
+        self.root_table = table
+        self.table_aliases.add(table)
 
         def child_of_domain(left, ids, left_model, parent=None, prefix=''):
             """Returns a domain implementing the child_of operator for [(left,child_of,ids)],
@@ -419,7 +432,7 @@
             return list(value)
 
         i = -1
-        while i + 1<len(self.__exp):
+        while i + 1 < len(self.__exp):
             i += 1
             e = self.__exp[i]
             if is_operator(e) or e == TRUE_LEAF or e == FALSE_LEAF:
@@ -434,7 +447,7 @@
             self.__exp[i] = e
             left, operator, right = e
 
-            working_table = table # The table containing the field (the name provided in the left operand)
+            working_table = table  # The table containing the field (the name provided in the left operand)
             field_path = left.split('.', 1)
 
             # If the field is _inherits'd, search for the working_table,
@@ -444,12 +457,12 @@
                 while True:
                     field = working_table._columns.get(field_path[0])
                     if field:
-                        self.__field_tables[i] = working_table
+                        self.leaf_to_table[i] = working_table
                         break
                     next_table = working_table.pool.get(working_table._inherit_fields[field_path[0]][0])
-                    if next_table not in self.__all_tables:
-                        self.__joins.append('%s."%s"=%s."%s"' % (next_table._table, 'id', working_table._table, working_table._inherits[next_table._name]))
-                        self.__all_tables.add(next_table)
+                    if next_table not in self.table_aliases:
+                        self.joins.append('%s."%s"=%s."%s"' % (next_table._table, 'id', working_table._table, working_table._inherits[next_table._name]))
+                        self.table_aliases.add(next_table)
                     working_table = next_table
             # Or (try to) directly extract the field.
             else:
@@ -459,7 +472,7 @@
                 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:]
+                    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
@@ -476,7 +489,7 @@
                 # Making search easier when there is a left operand as field.o2m or field.m2m
                 if field._type in ['many2many', 'one2many']:
                     right = field_obj.search(cr, uid, [(field_path[1], operator, right)], context=context)
-                    right1 = table.search(cr, uid, [(field_path[0],'in', right)], context=dict(context, active_test=False))
+                    right1 = table.search(cr, uid, [(field_path[0], 'in', right)], context=dict(context, active_test=False))
                     self.__exp[i] = ('id', 'in', right1)
 
                 if not isinstance(field, fields.property):
@@ -516,7 +529,7 @@
                         dom = child_of_domain(left, ids2, field_obj, prefix=field._obj)
                     else:
                         dom = child_of_domain('id', ids2, working_table, parent=left)
-                    self.__exp = self.__exp[:i] + dom + self.__exp[i+1:]
+                    self.__exp = self.__exp[:i] + dom + self.__exp[i + 1:]
 
                 else:
                     call_null = True
@@ -532,7 +545,7 @@
                             else:
                                 ids2 = right
                         if not ids2:
-                            if operator in ['like','ilike','in','=']:
+                            if operator in ['like', 'ilike', 'in', '=']:
                                 #no result found with given search criteria
                                 call_null = False
                                 self.__exp[i] = FALSE_LEAF
@@ -573,12 +586,12 @@
                             else:
                                 res_ids = right
                         if not res_ids:
-                            if operator in ['like','ilike','in','=']:
+                            if operator in ['like', 'ilike', 'in', '=']:
                                 #no result found with given search criteria
                                 call_null_m2m = False
                                 self.__exp[i] = FALSE_LEAF
                             else:
-                                operator = 'in' # operator changed because ids are directly related to main object
+                                operator = 'in'  # operator changed because ids are directly related to main object
                         else:
                             call_null_m2m = False
                             m2m_op = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
@@ -595,7 +608,7 @@
                         dom = child_of_domain(left, ids2, field_obj, prefix=field._obj)
                     else:
                         dom = child_of_domain('id', ids2, working_table, parent=left)
-                    self.__exp = self.__exp[:i] + dom + self.__exp[i+1:]
+                    self.__exp = self.__exp[:i] + dom + self.__exp[i + 1:]
                 else:
                     def _get_expression(field_obj, cr, uid, left, right, operator, context=None):
                         if context is None:
@@ -603,24 +616,24 @@
                         c = context.copy()
                         c['active_test'] = False
                         #Special treatment to ill-formed domains
-                        operator = ( operator in ['<','>','<=','>='] ) and 'in' or operator
+                        operator = (operator in ['<', '>', '<=', '>=']) and 'in' or operator
 
-                        dict_op = {'not in':'!=','in':'=','=':'in','!=':'not in'}
+                        dict_op = {'not in': '!=', 'in': '=', '=': 'in', '!=': 'not in'}
                         if isinstance(right, tuple):
                             right = list(right)
-                        if (not isinstance(right, list)) and operator in ['not in','in']:
+                        if (not isinstance(right, list)) and operator in ['not in', 'in']:
                             operator = dict_op[operator]
-                        elif isinstance(right, list) and operator in ['!=','=']: #for domain (FIELD,'=',['value1','value2'])
+                        elif isinstance(right, list) and operator in ['!=', '=']:  # for domain (FIELD,'=',['value1','value2'])
                             operator = dict_op[operator]
                         res_ids = [x[0] for x in field_obj.name_search(cr, uid, right, [], operator, limit=None, context=c)]
                         if operator in NEGATIVE_TERM_OPERATORS:
-                            res_ids.append(False) # TODO this should not be appended if False was in 'right'
+                            res_ids.append(False)  # TODO this should not be appended if False was in 'right'
                         return (left, 'in', res_ids)
                     # resolve string-based m2o criterion into IDs
                     if isinstance(right, basestring) or \
-                            right and isinstance(right, (tuple,list)) and all(isinstance(item, basestring) for item in right):
+                            right and isinstance(right, (tuple, list)) and all(isinstance(item, basestring) for item in right):
                         self.__exp[i] = _get_expression(field_obj, cr, uid, left, right, operator, context=context)
-                    else: 
+                    else:
                         # right == [] or right == False and all other cases are handled by __leaf_to_sql()
                         pass
 
@@ -640,7 +653,7 @@
 
                 if field.translate:
                     need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike')
-                    sql_operator = {'=like':'like','=ilike':'ilike'}.get(operator,operator)
+                    sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator)
                     if need_wildcard:
                         right = '%%%s%%' % right
 
@@ -651,13 +664,13 @@
                              '     AND type = %s'
                     instr = ' %s'
                     #Covering in,not in operators with operands (%s,%s) ,etc.
-                    if sql_operator in ['in','not in']:
+                    if sql_operator in ['in', 'not in']:
                         instr = ','.join(['%s'] * len(right))
-                        subselect += '     AND value ' + sql_operator +  ' ' +" (" + instr + ")"   \
+                        subselect += '     AND value ' + sql_operator + ' ' + " (" + instr + ")"   \
                              ') UNION ('                \
                              '  SELECT id'              \
                              '    FROM "' + working_table._table + '"'       \
-                             '   WHERE "' + left + '" ' + sql_operator + ' ' +" (" + instr + "))"
+                             '   WHERE "' + left + '" ' + sql_operator + ' ' + " (" + instr + "))"
                     else:
                         subselect += '     AND value ' + sql_operator + instr +   \
                              ') UNION ('                \
@@ -729,11 +742,11 @@
                 elif not check_nulls and operator == 'not in':
                     query = '(%s OR %s."%s" IS NULL)' % (query, table._table, left)
                 elif check_nulls and operator == 'not in':
-                    query = '(%s AND %s."%s" IS NOT NULL)' % (query, table._table, left) # needed only for TRUE.
-            else: # Must not happen
+                    query = '(%s AND %s."%s" IS NOT NULL)' % (query, table._table, left)  # needed only for TRUE.
+            else:  # Must not happen
                 raise ValueError("Invalid domain term %r" % (leaf,))
 
-        elif right == False and (left in table._columns) and table._columns[left]._type=="boolean" and (operator == '='):
+        elif right == False and (left in table._columns) and table._columns[left]._type == "boolean" and (operator == '='):
             query = '(%s."%s" IS NULL or %s."%s" = false )' % (table._table, left, table._table, left)
             params = []
 
@@ -741,7 +754,7 @@
             query = '%s."%s" IS NULL ' % (table._table, left)
             params = []
 
-        elif right == False and (left in table._columns) and table._columns[left]._type=="boolean" and (operator == '!='):
+        elif right == False and (left in table._columns) and table._columns[left]._type == "boolean" and (operator == '!='):
             query = '(%s."%s" IS NOT NULL and %s."%s" != false)' % (table._table, left, table._table, left)
             params = []
 
@@ -764,7 +777,7 @@
 
         else:
             need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike')
-            sql_operator = {'=like':'like','=ilike':'ilike'}.get(operator,operator)
+            sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator)
 
             if left in table._columns:
                 format = need_wildcard and '%s' or table._columns[left]._symbol_set[0]
@@ -775,7 +788,7 @@
             elif left in MAGIC_COLUMNS:
                     query = "(%s.\"%s\" %s %%s)" % (table._table, left, sql_operator)
                     params = right
-            else: # Must not happen
+            else:  # Must not happen
                 raise ValueError("Invalid field %r in domain term %r" % (left, leaf))
 
             add_null = False
@@ -798,14 +811,13 @@
             params = [params]
         return (query, params)
 
-
     def to_sql(self):
         stack = []
         params = []
         # Process the domain from right to left, using a stack, to generate a SQL expression.
         for i, e in reverse_enumerate(self.__exp):
             if is_leaf(e, internal=True):
-                table = self.__field_tables.get(i, self.__main_table)
+                table = self.leaf_to_table.get(i, self.root_table)
                 q, p = self.__leaf_to_sql(e, table)
                 params.insert(0, p)
                 stack.append(q)
@@ -819,13 +831,12 @@
 
         assert len(stack) == 1
         query = stack[0]
-        joins = ' AND '.join(self.__joins)
+        joins = ' AND '.join(self.joins)
         if joins:
             query = '(%s) AND %s' % (joins, query)
         return (query, flatten(params))
 
     def get_tables(self):
-        return ['"%s"' % t._table for t in self.__all_tables]
+        return ['"%s"' % t._table for t in self.table_aliases]
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-

_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help   : https://help.launchpad.net/ListHelp

Reply via email to