]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Hoist loop-invariant set intersection in _get_display_froms
authorsebastianbreguel <breguelsebastian@gmail.com>
Sun, 31 May 2026 20:12:19 +0000 (16:12 -0400)
committersqla-tester <sqla-tester@sqlalchemy.org>
Sun, 31 May 2026 20:12:19 +0000 (16:12 -0400)
Fixes #13336.

`SelectState._get_display_froms` recomputed a loop-invariant `_cloned_intersection(...)` once per FROM element in each of the three correlation comprehensions, making each branch O(N²) in the number of FROM elements. This hoists the call so it runs once, which is O(N).

`_cloned_intersection` / `_cloned_difference` are pure and return a set, and neither argument changes during the comprehension, so the result is identical. A function-level benchmark asserts `old == new` at every N (full numbers in #13336), and `test/sql/` plus the ORM compilation/query tests pass: 7442 passed, 359 skipped. Net -14 lines.

Per the issue discussion, no changelog entry is included.

### Checklist

This pull request is:

- [x] A short code fix
  - Issue with a runnable demonstration: #13336
  - Behavior-preserving (no logic change), so it is covered by the existing `test/sql/` and ORM compilation/query suites rather than adding new tests.

Closes: #13337
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13337
Pull-request-sha: beba43e77a773a4d9e9d55cc39c7c85ecda6293e

Change-Id: I95b02ffa66ef709c16bf5275924ec03244c19ecb

lib/sqlalchemy/sql/selectable.py

index cc29ebdbec7a0395e99fc3e256ea3af811474c56..6b07bbf9b20c50d7ea991f98aa4f54f23f5f5294 100644 (file)
@@ -5082,42 +5082,28 @@ class SelectState(util.MemoizedSlots, CompileState):
         if self.statement._correlate:
             to_correlate = self.statement._correlate
             if to_correlate:
-                froms = [
-                    f
-                    for f in froms
-                    if f
-                    not in _cloned_intersection(
-                        _cloned_intersection(
-                            froms, explicit_correlate_froms or ()
-                        ),
-                        to_correlate,
-                    )
-                ]
-
-        if self.statement._correlate_except is not None:
-            froms = [
-                f
-                for f in froms
-                if f
-                not in _cloned_difference(
+                to_remove = _cloned_intersection(
                     _cloned_intersection(
                         froms, explicit_correlate_froms or ()
                     ),
-                    self.statement._correlate_except,
+                    to_correlate,
                 )
-            ]
+                froms = [f for f in froms if f not in to_remove]
+
+        if self.statement._correlate_except is not None:
+            to_remove = _cloned_difference(
+                _cloned_intersection(froms, explicit_correlate_froms or ()),
+                self.statement._correlate_except,
+            )
+            froms = [f for f in froms if f not in to_remove]
 
         if (
             self.statement._auto_correlate
             and implicit_correlate_froms
             and len(froms) > 1
         ):
-            froms = [
-                f
-                for f in froms
-                if f
-                not in _cloned_intersection(froms, implicit_correlate_froms)
-            ]
+            to_remove = _cloned_intersection(froms, implicit_correlate_froms)
+            froms = [f for f in froms if f not in to_remove]
 
             if not len(froms):
                 raise exc.InvalidRequestError(