diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-06-22 13:27:18 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-06-22 17:25:37 -0400 |
commit | 2cf8c5868cb83185001755d86aa0f79e0318b53f (patch) | |
tree | 7eadd810494b7d888f0522e38b7fdbabd349a032 /lib/sqlalchemy/orm/context.py | |
parent | 2f100a7d4bb143e1f8674a388d8d305be3051bd6 (diff) | |
download | sqlalchemy-2cf8c5868cb83185001755d86aa0f79e0318b53f.tar.gz |
Export deferred columns but not col props; fix CTE labeling
Refined the behavior of ORM subquery rendering with regards to deferred
columns and column properties to be more compatible with that of 1.3 while
also providing for 1.4's newer features. As a subquery in 1.4 does not make
use of loader options, including :func:`_orm.deferred`, a subquery that is
against an ORM entity with deferred attributes will now render those
deferred attributes that refer directly to mapped table columns, as these
are needed in the outer SELECT if that outer SELECT makes use of these
columns; however a deferred attribute that refers to a composed SQL
expression as we normally do with :func:`_orm.column_property` will not be
part of the subquery, as these can be selected explicitly if needed in the
subquery. If the entity is being SELECTed from this subquery, the column
expression can still render on "the outside" in terms of the derived
subquery columns. This produces essentially the same behavior as when
working with 1.3. However in this case the fix has to also make sure that
the ``.selected_columns`` collection of an ORM-enabled :func:`_sql.select`
also follows these rules, which in particular allows recursive CTEs to
render correctly in this scenario, which were previously failing to render
correctly due to this issue.
As part of this change the _exported_columns_iterator() method has been
removed and logic simplified to use ._all_selected_columns from any
SelectBase object where _exported_columns_iterator() was used before.
Additionally sets up UpdateBase to include ReturnsRows in its hierarchy;
the literal point of ReturnsRows was to be a common base for UpdateBase
and SelectBase so it was kind of weird it wasn't there.
Fixes: #6661
Fixed issue in CTE constructs mostly relevant to ORM use cases where a
recursive CTE against "anonymous" labels such as those seen in ORM
``column_property()`` mappings would render in the
``WITH RECURSIVE xyz(...)`` section as their raw internal label and not a
cleanly anonymized name.
Fixes: #6663
Change-Id: I26219d4d8e6c0915b641426e9885540f74fae4d2
Diffstat (limited to 'lib/sqlalchemy/orm/context.py')
-rw-r--r-- | lib/sqlalchemy/orm/context.py | 23 |
1 files changed, 7 insertions, 16 deletions
diff --git a/lib/sqlalchemy/orm/context.py b/lib/sqlalchemy/orm/context.py index 321eeada0..78026efb1 100644 --- a/lib/sqlalchemy/orm/context.py +++ b/lib/sqlalchemy/orm/context.py @@ -153,6 +153,7 @@ class ORMCompileState(CompileState): ("_only_load_props", InternalTraversal.dp_plain_obj), ("_set_base_alias", InternalTraversal.dp_boolean), ("_for_refresh_state", InternalTraversal.dp_boolean), + ("_render_for_subquery", InternalTraversal.dp_boolean), ] # set to True by default from Query._statement_20(), to indicate @@ -176,6 +177,7 @@ class ORMCompileState(CompileState): _only_load_props = None _set_base_alias = False _for_refresh_state = False + _render_for_subquery = False current_path = _path_registry @@ -530,9 +532,7 @@ class ORMSelectCompileState(ORMCompileState, SelectState): self.select_statement = select_statement # indicates this select() came from Query.statement - self.for_statement = ( - for_statement - ) = select_statement._compile_options._for_statement + self.for_statement = select_statement._compile_options._for_statement # generally if we are from Query or directly from a select() self.use_legacy_query_style = ( @@ -554,13 +554,12 @@ class ORMSelectCompileState(ORMCompileState, SelectState): self.compile_options = select_statement._compile_options - if not for_statement and not toplevel: - # for subqueries, turn off eagerloads. - # if "for_statement" mode is set, Query.subquery() - # would have set this flag to False already if that's what's - # desired + if not toplevel: + # for subqueries, turn off eagerloads and set + # "render_for_subquery". self.compile_options += { "_enable_eagerloads": False, + "_render_for_subquery": True, } # determine label style. we can make different decisions here. @@ -855,14 +854,6 @@ class ORMSelectCompileState(ORMCompileState, SelectState): return target @classmethod - def exported_columns_iterator(cls, statement): - return ( - elem - for elem in cls.all_selected_columns(statement) - if not elem._is_text_clause - ) - - @classmethod def all_selected_columns(cls, statement): for element in statement._raw_columns: if ( |