@@ -41,6 +41,11 @@ class PilotAgentsDB(DB):
4141 "VO" ,
4242 }
4343
44+ # Number of values inserted into the in-memory temp tables per batch in
45+ # getPilotInfo. Keeping batches bounded avoids overflowing MEMORY tables
46+ # (ERROR 1114: The table is full) when querying large pilot reference lists.
47+ PILOT_INFO_BATCH_SIZE = 10000
48+
4449 def __init__ (self , parentLogger = None ):
4550 super ().__init__ ("PilotAgentsDB" , "WorkloadManagement/PilotAgentsDB" , parentLogger = parentLogger )
4651 self ._defaultLogger = self .log
@@ -286,23 +291,70 @@ def getPilotInfo(self, pilotRef=False, conn=False, paramNames=[], pilotID=False)
286291 return S_ERROR (f"Unknown column: { col } " )
287292
288293 cmd = f"SELECT { ', ' .join (parameters )} FROM PilotAgents" # nosec
289- condSQL = []
290- for key , value in [
291- ("PilotJobReference" , pilotRef ),
292- ("PilotID" , pilotID ),
293- ]:
294- resList = []
295- for v in value if isinstance (value , list ) else [value ] if value else []:
296- result = self ._escapeString (v )
297- if not result ["OK" ]:
298- return result
299- resList .append (result ["Value" ])
300- if resList :
301- condSQL .append (f"{ key } IN ({ ',' .join (resList )} )" )
302- if condSQL :
303- cmd = f"{ cmd } WHERE { ' AND ' .join (condSQL )} "
304-
305- result = self ._query (cmd , conn = conn )
294+ tempTables = []
295+ activeKeys = []
296+ result = None
297+ try :
298+ for key , value in [("PilotJobReference" , pilotRef ), ("PilotID" , pilotID )]:
299+ values = []
300+ for v in value if isinstance (value , list ) else [value ] if value else []:
301+ values .append (v )
302+ if not values :
303+ continue
304+ tableName = f"to_select_PilotAgents_{ key } "
305+ if key == "PilotID" :
306+ sqlCmd = (
307+ f"CREATE TEMPORARY TABLE { tableName } "
308+ f" (PilotID INT UNSIGNED NOT NULL, PRIMARY KEY (PilotID)) ENGINE=MEMORY;"
309+ )
310+ insertValues = [(int (v ),) for v in values ]
311+ else :
312+ sqlCmd = (
313+ f"CREATE TEMPORARY TABLE { tableName } "
314+ f" (PilotJobReference VARCHAR(255) NOT NULL, PRIMARY KEY (PilotJobReference)) ENGINE=MEMORY;"
315+ )
316+ insertValues = [(v ,) for v in values ]
317+ returnValueOrRaise (self ._update (sqlCmd , conn = conn ))
318+ tempTables .append (tableName )
319+ activeKeys .append ((key , tableName , insertValues ))
320+
321+ joinSQL = [f"JOIN { tn } USING ({ k } )" for k , tn , _ in activeKeys ]
322+ selectCmd = f"{ cmd } { ' ' .join (joinSQL )} " if joinSQL else cmd
323+
324+ if not activeKeys :
325+ # No conditions: plain SELECT over the whole table.
326+ result = self ._query (selectCmd , conn = conn )
327+ else :
328+ # Load every condition key fully except the last one, which is
329+ # processed batch by batch (truncating between batches) so the
330+ # in-memory temp table never holds all the rows at once. This
331+ # preserves the AND semantics: the union of the per-batch
332+ # results equals the full JOIN result.
333+ for key , tableName , insertValues in activeKeys [:- 1 ]:
334+ insertCmd = f"INSERT INTO { tableName } ({ key } ) VALUES ( %s )" # nosec: B608
335+ for i in range (0 , len (insertValues ), self .PILOT_INFO_BATCH_SIZE ):
336+ returnValueOrRaise (
337+ self ._updatemany (insertCmd , insertValues [i : i + self .PILOT_INFO_BATCH_SIZE ], conn = conn )
338+ )
339+ batchKey , batchTable , batchValues = activeKeys [- 1 ]
340+ insertCmd = f"INSERT INTO { batchTable } ({ batchKey } ) VALUES ( %s )" # nosec: B608
341+ resultRows = []
342+ for i in range (0 , len (batchValues ), self .PILOT_INFO_BATCH_SIZE ):
343+ returnValueOrRaise (self ._update (f"TRUNCATE TABLE { batchTable } " , conn = conn ))
344+ returnValueOrRaise (
345+ self ._updatemany (insertCmd , batchValues [i : i + self .PILOT_INFO_BATCH_SIZE ], conn = conn )
346+ )
347+ batchResult = self ._query (selectCmd , conn = conn )
348+ if not batchResult ["OK" ]:
349+ result = batchResult
350+ break
351+ resultRows .extend (batchResult ["Value" ])
352+ else :
353+ result = S_OK (resultRows )
354+ finally :
355+ for tableName in tempTables :
356+ sqlCmd = f"DROP TEMPORARY TABLE { tableName } "
357+ returnValueOrRaise (self ._update (sqlCmd , conn = conn ))
306358 if not result ["OK" ]:
307359 return result
308360 if not result ["Value" ]:
0 commit comments