diff --git a/openerp/addons/base/tests/test_expression.py b/openerp/addons/base/tests/test_expression.py index 4f533a5e170..9c0cd01cb5a 100644 --- a/openerp/addons/base/tests/test_expression.py +++ b/openerp/addons/base/tests/test_expression.py @@ -439,5 +439,18 @@ class test_expression(common.TransactionCase): partner_parent_id_col._auto_join = False state_country_id_col._auto_join = False + def test_translate_search(self): + Country = self.registry('res.country') + be = self.ref('base.be') + domains = [ + [('name', '=', 'Belgium')], + [('name', 'ilike', 'Belgi')], + [('name', 'in', ['Belgium', 'Care Bears'])], + ] + + for domain in domains: + ids = Country.search(self.cr, self.uid, domain) + self.assertListEqual([be], ids) + if __name__ == '__main__': unittest2.main() diff --git a/openerp/osv/expression.py b/openerp/osv/expression.py index 648a8447292..4330ba60527 100644 --- a/openerp/osv/expression.py +++ b/openerp/osv/expression.py @@ -1019,6 +1019,7 @@ class expression(object): push(create_substitution_leaf(leaf, (left, operator, right), working_model)) elif field.translate and right: + field = left need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike') sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator) if need_wildcard: @@ -1030,33 +1031,40 @@ class expression(object): sql_operator = sql_operator[4:] if sql_operator[:3] == 'not' else '=' inselect_operator = 'not inselect' - subselect = '( SELECT res_id' \ - ' FROM ir_translation' \ - ' WHERE name = %s' \ - ' AND lang = %s' \ - ' AND type = %s' - instr = ' %s' - #Covering in,not in operators with operands (%s,%s) ,etc. - if sql_operator == 'in': - instr = ','.join(['%s'] * len(right)) - subselect += ' AND value ' + sql_operator + ' ' + " (" + instr + ")" \ - ') UNION (' \ - ' SELECT id' \ - ' FROM "' + working_model._table + '"' \ - ' WHERE "' + left + '" ' + sql_operator + ' ' + " (" + instr + "))" - else: - subselect += ' AND value ' + sql_operator + instr + \ - ') UNION (' \ - ' SELECT id' \ - ' FROM "' + working_model._table + '"' \ - ' WHERE "' + left + '" ' + sql_operator + instr + ")" + trans_left = 'value' + left = '"%s"' % (left,) + instr = '%s' - params = [working_model._name + ',' + left, - context.get('lang', False) or 'en_US', - 'model', - right, - right, - ] + if self.has_unaccent and sql_operator.endswith('like'): + assert isinstance(right, basestring) + trans_left = 'unaccent(value)' + left = 'unaccent("%s")' % (left,) + instr = 'unaccent(%s)' + elif sql_operator == 'in': + # params will be flatten by to_sql() => expand the placeholders + instr = '(%s)' % ', '.join(['%s'] * len(right)) + + subselect = """(SELECT res_id + FROM ir_translation + WHERE name = %s + AND lang = %s + AND type = %s + AND {trans_left} {operator} {right} + ) UNION ( + SELECT id + FROM "{table}" + WHERE {left} {operator} {right} + ) + """.format(trans_left=trans_left, operator=sql_operator, + right=instr, table=working_model._table, left=left) + + params = ( + working_model._name + ',' + field, + context.get('lang') or 'en_US', + 'model', + right, + right, + ) push(create_substitution_leaf(leaf, ('id', inselect_operator, (subselect, params)), working_model)) else: @@ -1177,7 +1185,7 @@ class expression(object): if left in model._columns: format = need_wildcard and '%s' or model._columns[left]._symbol_set[0] - if self.has_unaccent and sql_operator in ('ilike', 'not ilike'): + if self.has_unaccent and sql_operator.endswith('like'): query = '(unaccent(%s."%s") %s unaccent(%s))' % (table_alias, left, sql_operator, format) else: query = '(%s."%s" %s %s)' % (table_alias, left, sql_operator, format) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index d5d0ee0fa30..f60e83726c4 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -648,7 +648,10 @@ class one2many(_column): else: cr.execute('update '+_table+' set '+self._fields_id+'=null where id=%s', (act[1],)) elif act[0] == 4: - cr.execute("select 1 from {0} where id=%s and {1}=%s".format(_table, self._fields_id), (act[1], id)) + # table of the field (parent_model in case of inherit) + field_model = self._fields_id in obj.pool[self._obj]._columns and self._obj or obj.pool[self._obj]._all_columns[self._fields_id].parent_model + field_table = obj.pool[field_model]._table + cr.execute("select 1 from {0} where id=%s and {1}=%s".format(field_table, self._fields_id), (act[1], id)) if not cr.fetchone(): # Must use write() to recompute parent_store structure if needed and check access rules obj.write(cr, user, [act[1]], {self._fields_id:id}, context=context or {})