summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/context.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2021-06-22 13:27:18 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2021-06-22 17:25:37 -0400
commit2cf8c5868cb83185001755d86aa0f79e0318b53f (patch)
tree7eadd810494b7d888f0522e38b7fdbabd349a032 /lib/sqlalchemy/orm/context.py
parent2f100a7d4bb143e1f8674a388d8d305be3051bd6 (diff)
downloadsqlalchemy-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.py23
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 (