details: https://code.tryton.org/tryton/commit/e29d66bccb77
branch: default
user: Cédric Krier <[email protected]>
date: Fri Jun 05 10:10:01 2026 +0200
description:
Do not prefetch columns when searching for RPC
Closes #14802
diffstat:
trytond/trytond/model/modelsql.py | 61 ++++++++++++++++++++--------------
trytond/trytond/model/modelstorage.py | 10 +++++-
2 files changed, 45 insertions(+), 26 deletions(-)
diffs (145 lines):
diff -r e1657467e49c -r e29d66bccb77 trytond/trytond/model/modelsql.py
--- a/trytond/trytond/model/modelsql.py Thu Jun 04 23:41:21 2026 +0200
+++ b/trytond/trytond/model/modelsql.py Fri Jun 05 10:10:01 2026 +0200
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 -r e1657467e49c -r e29d66bccb77 trytond/trytond/model/modelstorage.py
--- a/trytond/trytond/model/modelstorage.py Thu Jun 04 23:41:21 2026 +0200
+++ b/trytond/trytond/model/modelstorage.py Fri Jun 05 10:10:01 2026 +0200
@@ -98,6 +98,14 @@
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 @@
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,