diff --git a/trytond/trytond/model/modelsql.py b/trytond/trytond/model/modelsql.py index a17cddc628..8be0144667 100644 --- a/trytond/trytond/model/modelsql.py +++ b/trytond/trytond/model/modelsql.py @@ -3,7 +3,7 @@ import datetime from collections import defaultdict from functools import wraps -from itertools import groupby, islice, product, repeat +from itertools import groupby, product, repeat from sql import ( Asc, Column, Desc, Expression, Literal, Null, NullsFirst, NullsLast, Table, @@ -1809,7 +1809,7 @@ class ModelSQL(ModelStorage): raise AccessError(msg, '\n'.join(ctx_msg)) @classmethod - def __search_query(cls, domain, count, query, order): + def __search_query(cls, domain, count, query, order, prefetch): pool = Pool() Rule = pool.get('ir.rule') @@ -1868,7 +1868,8 @@ class ModelSQL(ModelStorage): expression &= domain_exp main_table, _ = tables[None] columns = cls.__searched_columns( - tables, eager=not count and not query) + tables, + eager=not count and not query and prefetch) o_idx = 0 for oexpr, otype in order: @@ -1940,6 +1941,8 @@ class ModelSQL(ModelStorage): query=False): transaction = Transaction() connection = transaction.connection + context = transaction.context + prefetch = context.get('_search_prefetch', True) super().search( domain, offset=offset, limit=limit, order=order, count=count) @@ -1952,7 +1955,7 @@ class ModelSQL(ModelStorage): order.append(('id', None)) tables, expression, union_orderings = cls.__search_query( - domain, count, query, order) + domain, count, query, order, prefetch) main_table, _ = tables[None] if count: @@ -1986,7 +1989,7 @@ class ModelSQL(ModelStorage): if query: columns = [main_table.id.as_('id')] else: - columns = cls.__searched_columns(tables, eager=True) + columns = cls.__searched_columns(tables, eager=prefetch) if union_orderings: columns = [ Column(main_table, c.output_name).as_(c.output_name) @@ -2003,31 +2006,39 @@ class ModelSQL(ModelStorage): if query: return select - cursor = connection.cursor(row_factory=backend.dict_row) + if prefetch: + row_factory = backend.dict_row + else: + row_factory = backend.scalar_row + cursor = connection.cursor(row_factory=row_factory) cursor.execute(*select) - rows = list(cursor) - cache = transaction.get_cache() - delete_records = transaction.delete_records[cls.__name__] + if prefetch: + cache = transaction.get_cache() + delete_records = transaction.delete_records[cls.__name__] - keys = None - for data in islice(rows, 0, cache.size_limit): - if data['id'] in delete_records: - continue - if keys is None: - keys = list(data.keys()) - for k in keys[:]: - if k in ('_timestamp', '_datetime', '__id'): + no_cache = None + ids = [] + for i, data in enumerate(cursor): + ids.append(data['id']) + if i < cache.size_limit: + if data['id'] in delete_records: continue - field = cls._fields[k] - if not getattr(field, 'datetime_field', None): - keys.remove(k) - continue - for k in keys: - del data[k] - cache[cls.__name__][data['id']]._update(data) + if no_cache is None: + no_cache = list(data.keys()) + for k in no_cache[:]: + if k in ('_timestamp', '_datetime', '__id'): + continue + field = cls._fields[k] + if not getattr(field, 'datetime_field', None): + no_cache.remove(k) + for k in no_cache: + del data[k] + cache[cls.__name__][data['id']]._update(data) + else: + ids = cursor - return cls.browse([x['id'] for x in rows]) + return cls.browse(ids) @classmethod def search_domain(cls, domain, active_test=None, tables=None): diff --git a/trytond/trytond/model/modelstorage.py b/trytond/trytond/model/modelstorage.py index 3bc6be796f..661e515db5 100644 --- a/trytond/trytond/model/modelstorage.py +++ b/trytond/trytond/model/modelstorage.py @@ -98,6 +98,14 @@ def is_leaf(expression): and expression[1] in OPERATORS) # TODO remove OPERATORS test +class _search_RPC(RPC): + def convert(self, obj, *args, **kwargs): + args, kwargs, context, timestamp = super().convert( + obj, *args, **kwargs) + context['_search_prefetch'] = False + return args, kwargs, context, timestamp + + class ModelStorage(Model): """ Define a model with storage capability in Tryton. @@ -164,7 +172,7 @@ class ModelStorage(Model): 0: request_records_limit, }, result=lambda r: list(map(int, r))), - 'search': RPC( + 'search': _search_RPC( result=lambda r: list(map(int, r)), size_limits={ 2: request_records_limit,