@@ -234,7 +234,7 @@ def explode_query(cr, query, alias=None, num_buckets=8, prefix=None):
234234 return [cr .mogrify (query , [num_buckets , index ]).decode () for index in range (num_buckets )]
235235
236236
237- def explode_query_range (cr , query , table , alias = None , bucket_size = 10000 , prefix = None ):
237+ def explode_query_range (cr , query , table , alias = None , bucket_size = 10000 , prefix = None , format = True ):
238238 """
239239 Explode a query to multiple queries that can be executed in parallel.
240240
@@ -297,16 +297,27 @@ def explode_query_range(cr, query, table, alias=None, bucket_size=10000, prefix=
297297 # Still, since the query may only be valid if there is no split, we force the usage of `prefix` in the query to
298298 # validate its correctness and avoid scripts that pass the CI but fail in production.
299299 parallel_filter = "{alias}.id IS NOT NULL" .format (alias = alias )
300- return [query .replace ("{parallel_filter}" , parallel_filter )]
300+ return [
301+ (
302+ query .format (parallel_filter = parallel_filter )
303+ if format
304+ else query .replace ("{parallel_filter}" , parallel_filter )
305+ )
306+ ]
301307
302308 parallel_filter = "{alias}.id BETWEEN %(lower-bound)s AND %(upper-bound)s" .format (alias = alias )
303- query = query .replace ("%" , "%%" ).replace ("{parallel_filter}" , parallel_filter )
309+
310+ query = query .replace ("%" , "%%" )
311+ query = (
312+ query .format (parallel_filter = parallel_filter ) if format else query .replace ("{parallel_filter}" , parallel_filter )
313+ )
314+
304315 return [
305316 cr .mogrify (query , {"lower-bound" : ids [i ], "upper-bound" : ids [i + 1 ] - 1 }).decode () for i in range (len (ids ) - 1 )
306317 ]
307318
308319
309- def explode_execute (cr , query , table , alias = None , bucket_size = 10000 , logger = _logger ):
320+ def explode_execute (cr , query , table , alias = None , bucket_size = 10000 , format = True , logger = _logger ):
310321 """
311322 Execute a query in parallel.
312323
@@ -336,6 +347,8 @@ def explode_execute(cr, query, table, alias=None, bucket_size=10000, logger=_log
336347 :param str table: name of the *main* table of the query, used to split the processing
337348 :param str alias: alias used for the main table in the query
338349 :param int bucket_size: size of the buckets of ids to split the processing
350+ :param bool format: Whether to use `.format` (instead of `.replace`) to inject the parallel filter.
351+ Setting it to `False` can prevent issues with hard-coded curly braces.
339352 :param logger: logger used to report the progress
340353 :type logger: :class:`logging.Logger`
341354 :return: the sum of `cr.rowcount` for each query run
@@ -349,7 +362,7 @@ def explode_execute(cr, query, table, alias=None, bucket_size=10000, logger=_log
349362 """
350363 return parallel_execute (
351364 cr ,
352- explode_query_range (cr , query , table , alias = alias , bucket_size = bucket_size ),
365+ explode_query_range (cr , query , table , alias = alias , bucket_size = bucket_size , format = format ),
353366 logger = logger ,
354367 )
355368
0 commit comments