@@ -9335,23 +9335,26 @@ def _parent_keys(parent_query, cols):
93359335 return sub
93369336
93379337
9338+ def _join_parent_keys (query , parent_query , pairs ):
9339+ # The parent query can repeat a key (it may carry its own joins), and a
9340+ # duplicated key would multiply every row of query. Dedupe the keys
9341+ # rather than the query, which is bigger and may carry its own DISTINCT.
9342+ keys = list (dict .fromkeys ([key for _ , key in pairs ]))
9343+ sub = _parent_keys (parent_query , keys ).order_by ().distinct ()
9344+ on = reduce (operator .or_ , [col == getattr (sub .c , key .column_name )
9345+ for col , key in pairs ])
9346+ query = query .join (sub , on = on )
9347+ if len (pairs ) > 1 :
9348+ # Several fks OR'd together can match one row to two distinct keys,
9349+ # which deduping the keys cannot prevent.
9350+ query = query .distinct ()
9351+ return query
9352+
9353+
93389354def _relate (query , parent_query , pairs , strategy ):
93399355 # Pairs are (column on query, the column it matches on parent_query).
93409356 if strategy == PREFETCH_TYPE .JOIN :
9341- # Distinct the key subquery, not the child query. Deduping the
9342- # keys prevents join fan-out without clobbering a child DISTINCT.
9343- # Inherited ordering is dropped, a key set has none and postgres
9344- # rejects DISTINCT ordered by an unprojected column.
9345- keys = list (dict .fromkeys ([key for _ , key in pairs ]))
9346- sub = _parent_keys (parent_query , keys ).order_by ().distinct ()
9347- on = reduce (operator .or_ , [col == getattr (sub .c , key .column_name )
9348- for col , key in pairs ])
9349- query = query .join (sub , on = on )
9350- if len (pairs ) > 1 :
9351- # An OR join over several fks can match a child row to more
9352- # than one key row, dedupe the children as well.
9353- query = query .distinct ()
9354- return query
9357+ return _join_parent_keys (query , parent_query , pairs )
93559358 expr = reduce (operator .or_ , [col << _parent_keys (parent_query , (key ,))
93569359 for col , key in pairs ])
93579360 return query .where (expr )
0 commit comments