diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-02-05 13:38:28 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-02-05 13:54:37 -0500 |
commit | bc9221bf781adfffdddf12860d4eed7650457a0a (patch) | |
tree | 83992d60fb056610cd29660a71a0284b74150785 /lib/sqlalchemy/sql/compiler.py | |
parent | ac1228a87290aca4aa64cec27e640817be932feb (diff) | |
download | sqlalchemy-bc9221bf781adfffdddf12860d4eed7650457a0a.tar.gz |
Track a second from_linter for lateral subqueries
Fixed bug where the "cartesian product" assertion was not correctly
accommodating for joins between tables that relied upon the use of LATERAL
to connect from a subquery to another subquery in the enclosing context.
Additionally, enabled from_linting for the base assert_compile(),
however it remains off by default; to enable by default we would
have to make sure it isn't set for DDL compiles and there's also
a lot of tests that would also need to turn it off, so leaving
this off for expediency.
Fixes: #5924
Change-Id: I22604baf572f8c4d96befcc610b3dcb79c13fc4a
Diffstat (limited to 'lib/sqlalchemy/sql/compiler.py')
-rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 42 |
1 files changed, 37 insertions, 5 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 696b38e64..f22e8614b 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -1996,14 +1996,24 @@ class SQLCompiler(Compiled): override_operator=None, eager_grouping=False, from_linter=None, + lateral_from_linter=None, **kw ): if from_linter and operators.is_comparison(binary.operator): - from_linter.edges.update( - itertools.product( - binary.left._from_objects, binary.right._from_objects + if lateral_from_linter is not None: + enclosing_lateral = kw["enclosing_lateral"] + lateral_from_linter.edges.update( + itertools.product( + binary.left._from_objects + [enclosing_lateral], + binary.right._from_objects + [enclosing_lateral], + ) + ) + else: + from_linter.edges.update( + itertools.product( + binary.left._from_objects, binary.right._from_objects + ) ) - ) # don't allow "? = ?" to render if ( @@ -2027,7 +2037,11 @@ class SQLCompiler(Compiled): ) else: return self._generate_generic_binary( - binary, opstring, from_linter=from_linter, **kw + binary, + opstring, + from_linter=from_linter, + lateral_from_linter=lateral_from_linter, + **kw ) def visit_function_as_comparison_op_binary(self, element, operator, **kw): @@ -2570,6 +2584,24 @@ class SQLCompiler(Compiled): from_linter=None, **kwargs ): + + if lateral: + if "enclosing_lateral" not in kwargs: + # if lateral is set and enclosing_lateral is not + # present, we assume we are being called directly + # from visit_lateral() and we need to set enclosing_lateral. + assert alias._is_lateral + kwargs["enclosing_lateral"] = alias + + # for lateral objects, we track a second from_linter that is... + # lateral! to the level above us. + if ( + from_linter + and "lateral_from_linter" not in kwargs + and "enclosing_lateral" in kwargs + ): + kwargs["lateral_from_linter"] = from_linter + if enclosing_alias is not None and enclosing_alias.element is alias: inner = alias.element._compiler_dispatch( self, |