1# orm/context.py 
    2# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 
    3# <see AUTHORS file> 
    4# 
    5# This module is part of SQLAlchemy and is released under 
    6# the MIT License: https://www.opensource.org/licenses/mit-license.php 
    7# mypy: ignore-errors 
    8 
    9from __future__ import annotations 
    10 
    11import collections 
    12import itertools 
    13from typing import Any 
    14from typing import cast 
    15from typing import Dict 
    16from typing import Iterable 
    17from typing import List 
    18from typing import Optional 
    19from typing import Set 
    20from typing import Tuple 
    21from typing import Type 
    22from typing import TYPE_CHECKING 
    23from typing import TypeVar 
    24from typing import Union 
    25 
    26from . import attributes 
    27from . import interfaces 
    28from . import loading 
    29from .base import _is_aliased_class 
    30from .interfaces import ORMColumnDescription 
    31from .interfaces import ORMColumnsClauseRole 
    32from .path_registry import PathRegistry 
    33from .util import _entity_corresponds_to 
    34from .util import _ORMJoin 
    35from .util import _TraceAdaptRole 
    36from .util import AliasedClass 
    37from .util import Bundle 
    38from .util import ORMAdapter 
    39from .util import ORMStatementAdapter 
    40from .. import exc as sa_exc 
    41from .. import future 
    42from .. import inspect 
    43from .. import sql 
    44from .. import util 
    45from ..sql import coercions 
    46from ..sql import expression 
    47from ..sql import roles 
    48from ..sql import util as sql_util 
    49from ..sql import visitors 
    50from ..sql._typing import is_dml 
    51from ..sql._typing import is_insert_update 
    52from ..sql._typing import is_select_base 
    53from ..sql.base import _select_iterables 
    54from ..sql.base import CacheableOptions 
    55from ..sql.base import CompileState 
    56from ..sql.base import Executable 
    57from ..sql.base import Generative 
    58from ..sql.base import Options 
    59from ..sql.dml import UpdateBase 
    60from ..sql.elements import GroupedElement 
    61from ..sql.elements import TextClause 
    62from ..sql.selectable import CompoundSelectState 
    63from ..sql.selectable import LABEL_STYLE_DISAMBIGUATE_ONLY 
    64from ..sql.selectable import LABEL_STYLE_NONE 
    65from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL 
    66from ..sql.selectable import Select 
    67from ..sql.selectable import SelectLabelStyle 
    68from ..sql.selectable import SelectState 
    69from ..sql.selectable import TypedReturnsRows 
    70from ..sql.visitors import InternalTraversal 
    71from ..util.typing import TupleAny 
    72from ..util.typing import TypeVarTuple 
    73from ..util.typing import Unpack 
    74 
    75 
    76if TYPE_CHECKING: 
    77    from ._typing import _InternalEntityType 
    78    from ._typing import OrmExecuteOptionsParameter 
    79    from .loading import _PostLoad 
    80    from .mapper import Mapper 
    81    from .query import Query 
    82    from .session import _BindArguments 
    83    from .session import Session 
    84    from ..engine import Result 
    85    from ..engine.interfaces import _CoreSingleExecuteParams 
    86    from ..sql._typing import _ColumnsClauseArgument 
    87    from ..sql.compiler import SQLCompiler 
    88    from ..sql.dml import _DMLTableElement 
    89    from ..sql.elements import ColumnElement 
    90    from ..sql.selectable import _JoinTargetElement 
    91    from ..sql.selectable import _LabelConventionCallable 
    92    from ..sql.selectable import _SetupJoinsElement 
    93    from ..sql.selectable import ExecutableReturnsRows 
    94    from ..sql.selectable import SelectBase 
    95    from ..sql.type_api import TypeEngine 
    96 
    97_T = TypeVar("_T", bound=Any) 
    98_Ts = TypeVarTuple("_Ts") 
    99_path_registry = PathRegistry.root 
    100 
    101_EMPTY_DICT = util.immutabledict() 
    102 
    103 
    104LABEL_STYLE_LEGACY_ORM = SelectLabelStyle.LABEL_STYLE_LEGACY_ORM 
    105 
    106 
    107class QueryContext: 
    108    __slots__ = ( 
    109        "top_level_context", 
    110        "compile_state", 
    111        "query", 
    112        "user_passed_query", 
    113        "params", 
    114        "load_options", 
    115        "bind_arguments", 
    116        "execution_options", 
    117        "session", 
    118        "autoflush", 
    119        "populate_existing", 
    120        "invoke_all_eagers", 
    121        "version_check", 
    122        "refresh_state", 
    123        "create_eager_joins", 
    124        "propagated_loader_options", 
    125        "attributes", 
    126        "runid", 
    127        "partials", 
    128        "post_load_paths", 
    129        "identity_token", 
    130        "yield_per", 
    131        "loaders_require_buffering", 
    132        "loaders_require_uniquing", 
    133    ) 
    134 
    135    runid: int 
    136    post_load_paths: Dict[PathRegistry, _PostLoad] 
    137    compile_state: _ORMCompileState 
    138 
    139    class default_load_options(Options): 
    140        _only_return_tuples = False 
    141        _populate_existing = False 
    142        _version_check = False 
    143        _invoke_all_eagers = True 
    144        _autoflush = True 
    145        _identity_token = None 
    146        _yield_per = None 
    147        _refresh_state = None 
    148        _lazy_loaded_from = None 
    149        _legacy_uniquing = False 
    150        _sa_top_level_orm_context = None 
    151        _is_user_refresh = False 
    152 
    153    def __init__( 
    154        self, 
    155        compile_state: CompileState, 
    156        statement: Union[ 
    157            Select[Unpack[TupleAny]], 
    158            FromStatement[Unpack[TupleAny]], 
    159            UpdateBase, 
    160        ], 
    161        user_passed_query: Union[ 
    162            Select[Unpack[TupleAny]], 
    163            FromStatement[Unpack[TupleAny]], 
    164            UpdateBase, 
    165        ], 
    166        params: _CoreSingleExecuteParams, 
    167        session: Session, 
    168        load_options: Union[ 
    169            Type[QueryContext.default_load_options], 
    170            QueryContext.default_load_options, 
    171        ], 
    172        execution_options: Optional[OrmExecuteOptionsParameter] = None, 
    173        bind_arguments: Optional[_BindArguments] = None, 
    174    ): 
    175        self.load_options = load_options 
    176        self.execution_options = execution_options or _EMPTY_DICT 
    177        self.bind_arguments = bind_arguments or _EMPTY_DICT 
    178        self.compile_state = compile_state 
    179        self.query = statement 
    180 
    181        # the query that the end user passed to Session.execute() or similar. 
    182        # this is usually the same as .query, except in the bulk_persistence 
    183        # routines where a separate FromStatement is manufactured in the 
    184        # compile stage; this allows differentiation in that case. 
    185        self.user_passed_query = user_passed_query 
    186 
    187        self.session = session 
    188        self.loaders_require_buffering = False 
    189        self.loaders_require_uniquing = False 
    190        self.params = params 
    191        self.top_level_context = load_options._sa_top_level_orm_context 
    192 
    193        cached_options = compile_state.select_statement._with_options 
    194        uncached_options = user_passed_query._with_options 
    195 
    196        # see issue #7447 , #8399 for some background 
    197        # propagated loader options will be present on loaded InstanceState 
    198        # objects under state.load_options and are typically used by 
    199        # LazyLoader to apply options to the SELECT statement it emits. 
    200        # For compile state options (i.e. loader strategy options), these 
    201        # need to line up with the ".load_path" attribute which in 
    202        # loader.py is pulled from context.compile_state.current_path. 
    203        # so, this means these options have to be the ones from the 
    204        # *cached* statement that's travelling with compile_state, not the 
    205        # *current* statement which won't match up for an ad-hoc 
    206        # AliasedClass 
    207        self.propagated_loader_options = tuple( 
    208            opt._adapt_cached_option_to_uncached_option(self, uncached_opt) 
    209            for opt, uncached_opt in zip(cached_options, uncached_options) 
    210            if opt.propagate_to_loaders 
    211        ) 
    212 
    213        self.attributes = dict(compile_state.attributes) 
    214 
    215        self.autoflush = load_options._autoflush 
    216        self.populate_existing = load_options._populate_existing 
    217        self.invoke_all_eagers = load_options._invoke_all_eagers 
    218        self.version_check = load_options._version_check 
    219        self.refresh_state = load_options._refresh_state 
    220        self.yield_per = load_options._yield_per 
    221        self.identity_token = load_options._identity_token 
    222 
    223    def _get_top_level_context(self) -> QueryContext: 
    224        return self.top_level_context or self 
    225 
    226 
    227_orm_load_exec_options = util.immutabledict( 
    228    {"_result_disable_adapt_to_context": True} 
    229) 
    230 
    231 
    232class _AbstractORMCompileState(CompileState): 
    233    is_dml_returning = False 
    234 
    235    def _init_global_attributes( 
    236        self, statement, compiler, *, toplevel, process_criteria_for_toplevel 
    237    ): 
    238        self.attributes = {} 
    239 
    240        if compiler is None: 
    241            # this is the legacy / testing only ORM _compile_state() use case. 
    242            # there is no need to apply criteria options for this. 
    243            self.global_attributes = {} 
    244            assert toplevel 
    245            return 
    246        else: 
    247            self.global_attributes = ga = compiler._global_attributes 
    248 
    249        if toplevel: 
    250            ga["toplevel_orm"] = True 
    251 
    252            if process_criteria_for_toplevel: 
    253                for opt in statement._with_options: 
    254                    if opt._is_criteria_option: 
    255                        opt.process_compile_state(self) 
    256 
    257            return 
    258        elif ga.get("toplevel_orm", False): 
    259            return 
    260 
    261        stack_0 = compiler.stack[0] 
    262 
    263        try: 
    264            toplevel_stmt = stack_0["selectable"] 
    265        except KeyError: 
    266            pass 
    267        else: 
    268            for opt in toplevel_stmt._with_options: 
    269                if opt._is_compile_state and opt._is_criteria_option: 
    270                    opt.process_compile_state(self) 
    271 
    272        ga["toplevel_orm"] = True 
    273 
    274    @classmethod 
    275    def create_for_statement( 
    276        cls, 
    277        statement: Executable, 
    278        compiler: SQLCompiler, 
    279        **kw: Any, 
    280    ) -> CompileState: 
    281        """Create a context for a statement given a :class:`.Compiler`. 
    282 
    283        This method is always invoked in the context of SQLCompiler.process(). 
    284 
    285        For a Select object, this would be invoked from 
    286        SQLCompiler.visit_select(). For the special FromStatement object used 
    287        by Query to indicate "Query.from_statement()", this is called by 
    288        FromStatement._compiler_dispatch() that would be called by 
    289        SQLCompiler.process(). 
    290        """ 
    291        return super().create_for_statement(statement, compiler, **kw) 
    292 
    293    @classmethod 
    294    def orm_pre_session_exec( 
    295        cls, 
    296        session, 
    297        statement, 
    298        params, 
    299        execution_options, 
    300        bind_arguments, 
    301        is_pre_event, 
    302    ): 
    303        raise NotImplementedError() 
    304 
    305    @classmethod 
    306    def orm_execute_statement( 
    307        cls, 
    308        session, 
    309        statement, 
    310        params, 
    311        execution_options, 
    312        bind_arguments, 
    313        conn, 
    314    ) -> Result: 
    315        result = conn.execute( 
    316            statement, params or {}, execution_options=execution_options 
    317        ) 
    318        return cls.orm_setup_cursor_result( 
    319            session, 
    320            statement, 
    321            params, 
    322            execution_options, 
    323            bind_arguments, 
    324            result, 
    325        ) 
    326 
    327    @classmethod 
    328    def orm_setup_cursor_result( 
    329        cls, 
    330        session, 
    331        statement, 
    332        params, 
    333        execution_options, 
    334        bind_arguments, 
    335        result, 
    336    ): 
    337        raise NotImplementedError() 
    338 
    339 
    340class _AutoflushOnlyORMCompileState(_AbstractORMCompileState): 
    341    """ORM compile state that is a passthrough, except for autoflush.""" 
    342 
    343    @classmethod 
    344    def orm_pre_session_exec( 
    345        cls, 
    346        session, 
    347        statement, 
    348        params, 
    349        execution_options, 
    350        bind_arguments, 
    351        is_pre_event, 
    352    ): 
    353        # consume result-level load_options.  These may have been set up 
    354        # in an ORMExecuteState hook 
    355        ( 
    356            load_options, 
    357            execution_options, 
    358        ) = QueryContext.default_load_options.from_execution_options( 
    359            "_sa_orm_load_options", 
    360            { 
    361                "autoflush", 
    362            }, 
    363            execution_options, 
    364            statement._execution_options, 
    365        ) 
    366 
    367        if not is_pre_event and load_options._autoflush: 
    368            session._autoflush() 
    369 
    370        return statement, execution_options 
    371 
    372    @classmethod 
    373    def orm_setup_cursor_result( 
    374        cls, 
    375        session, 
    376        statement, 
    377        params, 
    378        execution_options, 
    379        bind_arguments, 
    380        result, 
    381    ): 
    382        return result 
    383 
    384 
    385class _ORMCompileState(_AbstractORMCompileState): 
    386    class default_compile_options(CacheableOptions): 
    387        _cache_key_traversal = [ 
    388            ("_use_legacy_query_style", InternalTraversal.dp_boolean), 
    389            ("_for_statement", InternalTraversal.dp_boolean), 
    390            ("_bake_ok", InternalTraversal.dp_boolean), 
    391            ("_current_path", InternalTraversal.dp_has_cache_key), 
    392            ("_enable_single_crit", InternalTraversal.dp_boolean), 
    393            ("_enable_eagerloads", InternalTraversal.dp_boolean), 
    394            ("_only_load_props", InternalTraversal.dp_plain_obj), 
    395            ("_set_base_alias", InternalTraversal.dp_boolean), 
    396            ("_for_refresh_state", InternalTraversal.dp_boolean), 
    397            ("_render_for_subquery", InternalTraversal.dp_boolean), 
    398            ("_is_star", InternalTraversal.dp_boolean), 
    399        ] 
    400 
    401        # set to True by default from Query._statement_20(), to indicate 
    402        # the rendered query should look like a legacy ORM query.  right 
    403        # now this basically indicates we should use tablename_columnname 
    404        # style labels.    Generally indicates the statement originated 
    405        # from a Query object. 
    406        _use_legacy_query_style = False 
    407 
    408        # set *only* when we are coming from the Query.statement 
    409        # accessor, or a Query-level equivalent such as 
    410        # query.subquery().  this supersedes "toplevel". 
    411        _for_statement = False 
    412 
    413        _bake_ok = True 
    414        _current_path = _path_registry 
    415        _enable_single_crit = True 
    416        _enable_eagerloads = True 
    417        _only_load_props = None 
    418        _set_base_alias = False 
    419        _for_refresh_state = False 
    420        _render_for_subquery = False 
    421        _is_star = False 
    422 
    423    attributes: Dict[Any, Any] 
    424    global_attributes: Dict[Any, Any] 
    425 
    426    statement: Union[ 
    427        Select[Unpack[TupleAny]], FromStatement[Unpack[TupleAny]], UpdateBase 
    428    ] 
    429    select_statement: Union[ 
    430        Select[Unpack[TupleAny]], FromStatement[Unpack[TupleAny]] 
    431    ] 
    432    _entities: List[_QueryEntity] 
    433    _polymorphic_adapters: Dict[_InternalEntityType, ORMAdapter] 
    434    compile_options: Union[ 
    435        Type[default_compile_options], default_compile_options 
    436    ] 
    437    _primary_entity: Optional[_QueryEntity] 
    438    use_legacy_query_style: bool 
    439    _label_convention: _LabelConventionCallable 
    440    primary_columns: List[ColumnElement[Any]] 
    441    secondary_columns: List[ColumnElement[Any]] 
    442    dedupe_columns: Set[ColumnElement[Any]] 
    443    create_eager_joins: List[ 
    444        # TODO: this structure is set up by JoinedLoader 
    445        TupleAny 
    446    ] 
    447    current_path: PathRegistry = _path_registry 
    448    _has_mapper_entities = False 
    449 
    450    def __init__(self, *arg, **kw): 
    451        raise NotImplementedError() 
    452 
    453    @classmethod 
    454    def create_for_statement( 
    455        cls, 
    456        statement: Executable, 
    457        compiler: SQLCompiler, 
    458        **kw: Any, 
    459    ) -> _ORMCompileState: 
    460        return cls._create_orm_context( 
    461            cast("Union[Select, FromStatement]", statement), 
    462            toplevel=not compiler.stack, 
    463            compiler=compiler, 
    464            **kw, 
    465        ) 
    466 
    467    @classmethod 
    468    def _create_orm_context( 
    469        cls, 
    470        statement: Union[Select, FromStatement], 
    471        *, 
    472        toplevel: bool, 
    473        compiler: Optional[SQLCompiler], 
    474        **kw: Any, 
    475    ) -> _ORMCompileState: 
    476        raise NotImplementedError() 
    477 
    478    def _append_dedupe_col_collection(self, obj, col_collection): 
    479        dedupe = self.dedupe_columns 
    480        if obj not in dedupe: 
    481            dedupe.add(obj) 
    482            col_collection.append(obj) 
    483 
    484    @classmethod 
    485    def _column_naming_convention( 
    486        cls, label_style: SelectLabelStyle, legacy: bool 
    487    ) -> _LabelConventionCallable: 
    488        if legacy: 
    489 
    490            def name(col, col_name=None): 
    491                if col_name: 
    492                    return col_name 
    493                else: 
    494                    return getattr(col, "key") 
    495 
    496            return name 
    497        else: 
    498            return SelectState._column_naming_convention(label_style) 
    499 
    500    @classmethod 
    501    def get_column_descriptions(cls, statement): 
    502        return _column_descriptions(statement) 
    503 
    504    @classmethod 
    505    def orm_pre_session_exec( 
    506        cls, 
    507        session, 
    508        statement, 
    509        params, 
    510        execution_options, 
    511        bind_arguments, 
    512        is_pre_event, 
    513    ): 
    514        # consume result-level load_options.  These may have been set up 
    515        # in an ORMExecuteState hook 
    516        ( 
    517            load_options, 
    518            execution_options, 
    519        ) = QueryContext.default_load_options.from_execution_options( 
    520            "_sa_orm_load_options", 
    521            { 
    522                "populate_existing", 
    523                "autoflush", 
    524                "yield_per", 
    525                "identity_token", 
    526                "sa_top_level_orm_context", 
    527            }, 
    528            execution_options, 
    529            statement._execution_options, 
    530        ) 
    531 
    532        # default execution options for ORM results: 
    533        # 1. _result_disable_adapt_to_context=True 
    534        #    this will disable the ResultSetMetadata._adapt_to_context() 
    535        #    step which we don't need, as we have result processors cached 
    536        #    against the original SELECT statement before caching. 
    537 
    538        if "sa_top_level_orm_context" in execution_options: 
    539            ctx = execution_options["sa_top_level_orm_context"] 
    540            execution_options = ctx.query._execution_options.merge_with( 
    541                ctx.execution_options, execution_options 
    542            ) 
    543 
    544        if not execution_options: 
    545            execution_options = _orm_load_exec_options 
    546        else: 
    547            execution_options = execution_options.union(_orm_load_exec_options) 
    548 
    549        # would have been placed here by legacy Query only 
    550        if load_options._yield_per: 
    551            execution_options = execution_options.union( 
    552                {"yield_per": load_options._yield_per} 
    553            ) 
    554 
    555        if ( 
    556            getattr(statement._compile_options, "_current_path", None) 
    557            and len(statement._compile_options._current_path) > 10 
    558            and execution_options.get("compiled_cache", True) is not None 
    559        ): 
    560            execution_options: util.immutabledict[str, Any] = ( 
    561                execution_options.union( 
    562                    { 
    563                        "compiled_cache": None, 
    564                        "_cache_disable_reason": "excess depth for " 
    565                        "ORM loader options", 
    566                    } 
    567                ) 
    568            ) 
    569 
    570        bind_arguments["clause"] = statement 
    571 
    572        # new in 1.4 - the coercions system is leveraged to allow the 
    573        # "subject" mapper of a statement be propagated to the top 
    574        # as the statement is built.   "subject" mapper is the generally 
    575        # standard object used as an identifier for multi-database schemes. 
    576 
    577        # we are here based on the fact that _propagate_attrs contains 
    578        # "compile_state_plugin": "orm".   The "plugin_subject" 
    579        # needs to be present as well. 
    580 
    581        try: 
    582            plugin_subject = statement._propagate_attrs["plugin_subject"] 
    583        except KeyError: 
    584            assert False, "statement had 'orm' plugin but no plugin_subject" 
    585        else: 
    586            if plugin_subject: 
    587                bind_arguments["mapper"] = plugin_subject.mapper 
    588 
    589        if not is_pre_event and load_options._autoflush: 
    590            session._autoflush() 
    591 
    592        return statement, execution_options 
    593 
    594    @classmethod 
    595    def orm_setup_cursor_result( 
    596        cls, 
    597        session, 
    598        statement, 
    599        params, 
    600        execution_options, 
    601        bind_arguments, 
    602        result, 
    603    ): 
    604        execution_context = result.context 
    605        compile_state = execution_context.compiled.compile_state 
    606 
    607        # cover edge case where ORM entities used in legacy select 
    608        # were passed to session.execute: 
    609        # session.execute(legacy_select([User.id, User.name])) 
    610        # see test_query->test_legacy_tuple_old_select 
    611 
    612        load_options = execution_options.get( 
    613            "_sa_orm_load_options", QueryContext.default_load_options 
    614        ) 
    615 
    616        if compile_state.compile_options._is_star: 
    617            return result 
    618 
    619        querycontext = QueryContext( 
    620            compile_state, 
    621            statement, 
    622            statement, 
    623            params, 
    624            session, 
    625            load_options, 
    626            execution_options, 
    627            bind_arguments, 
    628        ) 
    629        return loading.instances(result, querycontext) 
    630 
    631    @property 
    632    def _lead_mapper_entities(self): 
    633        """return all _MapperEntity objects in the lead entities collection. 
    634 
    635        Does **not** include entities that have been replaced by 
    636        with_entities(), with_only_columns() 
    637 
    638        """ 
    639        return [ 
    640            ent for ent in self._entities if isinstance(ent, _MapperEntity) 
    641        ] 
    642 
    643    def _create_with_polymorphic_adapter(self, ext_info, selectable): 
    644        """given MapperEntity or ORMColumnEntity, setup polymorphic loading 
    645        if called for by the Mapper. 
    646 
    647        As of #8168 in 2.0.0rc1, polymorphic adapters, which greatly increase 
    648        the complexity of the query creation process, are not used at all 
    649        except in the quasi-legacy cases of with_polymorphic referring to an 
    650        alias and/or subquery. This would apply to concrete polymorphic 
    651        loading, and joined inheritance where a subquery is 
    652        passed to with_polymorphic (which is completely unnecessary in modern 
    653        use). 
    654 
    655        TODO: What is a "quasi-legacy" case?   Do we need this method with 
    656        2.0 style select() queries or not?   Why is with_polymorphic referring 
    657        to an alias or subquery "legacy" ? 
    658 
    659        """ 
    660        if ( 
    661            not ext_info.is_aliased_class 
    662            and ext_info.mapper.persist_selectable 
    663            not in self._polymorphic_adapters 
    664        ): 
    665            for mp in ext_info.mapper.iterate_to_root(): 
    666                self._mapper_loads_polymorphically_with( 
    667                    mp, 
    668                    ORMAdapter( 
    669                        _TraceAdaptRole.WITH_POLYMORPHIC_ADAPTER, 
    670                        mp, 
    671                        equivalents=mp._equivalent_columns, 
    672                        selectable=selectable, 
    673                    ), 
    674                ) 
    675 
    676    def _mapper_loads_polymorphically_with(self, mapper, adapter): 
    677        for m2 in mapper._with_polymorphic_mappers or [mapper]: 
    678            self._polymorphic_adapters[m2] = adapter 
    679 
    680            for m in m2.iterate_to_root(): 
    681                self._polymorphic_adapters[m.local_table] = adapter 
    682 
    683    @classmethod 
    684    def _create_entities_collection(cls, query, legacy): 
    685        raise NotImplementedError( 
    686            "this method only works for ORMSelectCompileState" 
    687        ) 
    688 
    689 
    690class _DMLReturningColFilter: 
    691    """a base for an adapter used for the DML RETURNING cases 
    692 
    693    Has a subset of the interface used by 
    694    :class:`.ORMAdapter` and is used for :class:`._QueryEntity` 
    695    instances to set up their columns as used in RETURNING for a 
    696    DML statement. 
    697 
    698    """ 
    699 
    700    __slots__ = ("mapper", "columns", "__weakref__") 
    701 
    702    def __init__(self, target_mapper, immediate_dml_mapper): 
    703        if ( 
    704            immediate_dml_mapper is not None 
    705            and target_mapper.local_table 
    706            is not immediate_dml_mapper.local_table 
    707        ): 
    708            # joined inh, or in theory other kinds of multi-table mappings 
    709            self.mapper = immediate_dml_mapper 
    710        else: 
    711            # single inh, normal mappings, etc. 
    712            self.mapper = target_mapper 
    713        self.columns = self.columns = util.WeakPopulateDict( 
    714            self.adapt_check_present  # type: ignore 
    715        ) 
    716 
    717    def __call__(self, col, as_filter): 
    718        for cc in sql_util._find_columns(col): 
    719            c2 = self.adapt_check_present(cc) 
    720            if c2 is not None: 
    721                return col 
    722        else: 
    723            return None 
    724 
    725    def adapt_check_present(self, col): 
    726        raise NotImplementedError() 
    727 
    728 
    729class _DMLBulkInsertReturningColFilter(_DMLReturningColFilter): 
    730    """an adapter used for the DML RETURNING case specifically 
    731    for ORM bulk insert (or any hypothetical DML that is splitting out a class 
    732    hierarchy among multiple DML statements....ORM bulk insert is the only 
    733    example right now) 
    734 
    735    its main job is to limit the columns in a RETURNING to only a specific 
    736    mapped table in a hierarchy. 
    737 
    738    """ 
    739 
    740    def adapt_check_present(self, col): 
    741        mapper = self.mapper 
    742        prop = mapper._columntoproperty.get(col, None) 
    743        if prop is None: 
    744            return None 
    745        return mapper.local_table.c.corresponding_column(col) 
    746 
    747 
    748class _DMLUpdateDeleteReturningColFilter(_DMLReturningColFilter): 
    749    """an adapter used for the DML RETURNING case specifically 
    750    for ORM enabled UPDATE/DELETE 
    751 
    752    its main job is to limit the columns in a RETURNING to include 
    753    only direct persisted columns from the immediate selectable, not 
    754    expressions like column_property(), or to also allow columns from other 
    755    mappers for the UPDATE..FROM use case. 
    756 
    757    """ 
    758 
    759    def adapt_check_present(self, col): 
    760        mapper = self.mapper 
    761        prop = mapper._columntoproperty.get(col, None) 
    762        if prop is not None: 
    763            # if the col is from the immediate mapper, only return a persisted 
    764            # column, not any kind of column_property expression 
    765            return mapper.persist_selectable.c.corresponding_column(col) 
    766 
    767        # if the col is from some other mapper, just return it, assume the 
    768        # user knows what they are doing 
    769        return col 
    770 
    771 
    772@sql.base.CompileState.plugin_for("orm", "orm_from_statement") 
    773class _ORMFromStatementCompileState(_ORMCompileState): 
    774    _from_obj_alias = None 
    775    _has_mapper_entities = False 
    776 
    777    statement_container: FromStatement 
    778    requested_statement: Union[SelectBase, TextClause, UpdateBase] 
    779    dml_table: Optional[_DMLTableElement] = None 
    780 
    781    _has_orm_entities = False 
    782    multi_row_eager_loaders = False 
    783    eager_adding_joins = False 
    784    compound_eager_adapter = None 
    785 
    786    extra_criteria_entities = _EMPTY_DICT 
    787    eager_joins = _EMPTY_DICT 
    788 
    789    @classmethod 
    790    def _create_orm_context( 
    791        cls, 
    792        statement: Union[Select, FromStatement], 
    793        *, 
    794        toplevel: bool, 
    795        compiler: Optional[SQLCompiler], 
    796        **kw: Any, 
    797    ) -> _ORMFromStatementCompileState: 
    798        statement_container = statement 
    799 
    800        assert isinstance(statement_container, FromStatement) 
    801 
    802        if compiler is not None and compiler.stack: 
    803            raise sa_exc.CompileError( 
    804                "The ORM FromStatement construct only supports being " 
    805                "invoked as the topmost statement, as it is only intended to " 
    806                "define how result rows should be returned." 
    807            ) 
    808 
    809        self = cls.__new__(cls) 
    810        self._primary_entity = None 
    811 
    812        self.use_legacy_query_style = ( 
    813            statement_container._compile_options._use_legacy_query_style 
    814        ) 
    815        self.statement_container = self.select_statement = statement_container 
    816        self.requested_statement = statement = statement_container.element 
    817 
    818        if statement.is_dml: 
    819            self.dml_table = statement.table 
    820            self.is_dml_returning = True 
    821 
    822        self._entities = [] 
    823        self._polymorphic_adapters = {} 
    824 
    825        self.compile_options = statement_container._compile_options 
    826 
    827        if ( 
    828            self.use_legacy_query_style 
    829            and isinstance(statement, expression.SelectBase) 
    830            and not statement._is_textual 
    831            and not statement.is_dml 
    832            and statement._label_style is LABEL_STYLE_NONE 
    833        ): 
    834            self.statement = statement.set_label_style( 
    835                LABEL_STYLE_TABLENAME_PLUS_COL 
    836            ) 
    837        else: 
    838            self.statement = statement 
    839 
    840        self._label_convention = self._column_naming_convention( 
    841            ( 
    842                statement._label_style 
    843                if not statement._is_textual and not statement.is_dml 
    844                else LABEL_STYLE_NONE 
    845            ), 
    846            self.use_legacy_query_style, 
    847        ) 
    848 
    849        _QueryEntity.to_compile_state( 
    850            self, 
    851            statement_container._raw_columns, 
    852            self._entities, 
    853            is_current_entities=True, 
    854        ) 
    855 
    856        self.current_path = statement_container._compile_options._current_path 
    857 
    858        self._init_global_attributes( 
    859            statement_container, 
    860            compiler, 
    861            process_criteria_for_toplevel=False, 
    862            toplevel=True, 
    863        ) 
    864 
    865        if statement_container._with_options: 
    866            for opt in statement_container._with_options: 
    867                if opt._is_compile_state: 
    868                    opt.process_compile_state(self) 
    869 
    870        if statement_container._compile_state_funcs: 
    871            for fn, key in statement_container._compile_state_funcs: 
    872                fn(self) 
    873 
    874        self.primary_columns = [] 
    875        self.secondary_columns = [] 
    876        self.dedupe_columns = set() 
    877        self.create_eager_joins = [] 
    878        self._fallback_from_clauses = [] 
    879 
    880        self.order_by = None 
    881 
    882        if isinstance(self.statement, expression.TextClause): 
    883            # TextClause has no "column" objects at all.  for this case, 
    884            # we generate columns from our _QueryEntity objects, then 
    885            # flip on all the "please match no matter what" parameters. 
    886            self.extra_criteria_entities = {} 
    887 
    888            for entity in self._entities: 
    889                entity.setup_compile_state(self) 
    890 
    891            compiler._ordered_columns = compiler._textual_ordered_columns = ( 
    892                False 
    893            ) 
    894 
    895            # enable looser result column matching.  this is shown to be 
    896            # needed by test_query.py::TextTest 
    897            compiler._loose_column_name_matching = True 
    898 
    899            for c in self.primary_columns: 
    900                compiler.process( 
    901                    c, 
    902                    within_columns_clause=True, 
    903                    add_to_result_map=compiler._add_to_result_map, 
    904                ) 
    905        else: 
    906            # for everyone else, Select, Insert, Update, TextualSelect, they 
    907            # have column objects already.  After much 
    908            # experimentation here, the best approach seems to be, use 
    909            # those columns completely, don't interfere with the compiler 
    910            # at all; just in ORM land, use an adapter to convert from 
    911            # our ORM columns to whatever columns are in the statement, 
    912            # before we look in the result row. Adapt on names 
    913            # to accept cases such as issue #9217, however also allow 
    914            # this to be overridden for cases such as #9273. 
    915            self._from_obj_alias = ORMStatementAdapter( 
    916                _TraceAdaptRole.ADAPT_FROM_STATEMENT, 
    917                self.statement, 
    918                adapt_on_names=statement_container._adapt_on_names, 
    919            ) 
    920 
    921        return self 
    922 
    923    def _adapt_col_list(self, cols, current_adapter): 
    924        return cols 
    925 
    926    def _get_current_adapter(self): 
    927        return None 
    928 
    929    def setup_dml_returning_compile_state(self, dml_mapper): 
    930        """used by BulkORMInsert, Update, Delete to set up a handler 
    931        for RETURNING to return ORM objects and expressions 
    932 
    933        """ 
    934        target_mapper = self.statement._propagate_attrs.get( 
    935            "plugin_subject", None 
    936        ) 
    937 
    938        if self.statement.is_insert: 
    939            adapter = _DMLBulkInsertReturningColFilter( 
    940                target_mapper, dml_mapper 
    941            ) 
    942        elif self.statement.is_update or self.statement.is_delete: 
    943            adapter = _DMLUpdateDeleteReturningColFilter( 
    944                target_mapper, dml_mapper 
    945            ) 
    946        else: 
    947            adapter = None 
    948 
    949        if self.compile_options._is_star and (len(self._entities) != 1): 
    950            raise sa_exc.CompileError( 
    951                "Can't generate ORM query that includes multiple expressions " 
    952                "at the same time as '*'; query for '*' alone if present" 
    953            ) 
    954 
    955        for entity in self._entities: 
    956            entity.setup_dml_returning_compile_state(self, adapter) 
    957 
    958 
    959class FromStatement(GroupedElement, Generative, TypedReturnsRows[Unpack[_Ts]]): 
    960    """Core construct that represents a load of ORM objects from various 
    961    :class:`.ReturnsRows` and other classes including: 
    962 
    963    :class:`.Select`, :class:`.TextClause`, :class:`.TextualSelect`, 
    964    :class:`.CompoundSelect`, :class`.Insert`, :class:`.Update`, 
    965    and in theory, :class:`.Delete`. 
    966 
    967    """ 
    968 
    969    __visit_name__ = "orm_from_statement" 
    970 
    971    _compile_options = _ORMFromStatementCompileState.default_compile_options 
    972 
    973    _compile_state_factory = _ORMFromStatementCompileState.create_for_statement 
    974 
    975    _for_update_arg = None 
    976 
    977    element: Union[ExecutableReturnsRows, TextClause] 
    978 
    979    _adapt_on_names: bool 
    980 
    981    _traverse_internals = [ 
    982        ("_raw_columns", InternalTraversal.dp_clauseelement_list), 
    983        ("element", InternalTraversal.dp_clauseelement), 
    984    ] + Executable._executable_traverse_internals 
    985 
    986    _cache_key_traversal = _traverse_internals + [ 
    987        ("_compile_options", InternalTraversal.dp_has_cache_key) 
    988    ] 
    989 
    990    is_from_statement = True 
    991 
    992    def __init__( 
    993        self, 
    994        entities: Iterable[_ColumnsClauseArgument[Any]], 
    995        element: Union[ExecutableReturnsRows, TextClause], 
    996        _adapt_on_names: bool = True, 
    997    ): 
    998        self._raw_columns = [ 
    999            coercions.expect( 
    1000                roles.ColumnsClauseRole, 
    1001                ent, 
    1002                apply_propagate_attrs=self, 
    1003                post_inspect=True, 
    1004            ) 
    1005            for ent in util.to_list(entities) 
    1006        ] 
    1007        self.element = element 
    1008        self.is_dml = element.is_dml 
    1009        self.is_select = element.is_select 
    1010        self.is_delete = element.is_delete 
    1011        self.is_insert = element.is_insert 
    1012        self.is_update = element.is_update 
    1013        self._label_style = ( 
    1014            element._label_style if is_select_base(element) else None 
    1015        ) 
    1016        self._adapt_on_names = _adapt_on_names 
    1017 
    1018    def _compiler_dispatch(self, compiler, **kw): 
    1019        """provide a fixed _compiler_dispatch method. 
    1020 
    1021        This is roughly similar to using the sqlalchemy.ext.compiler 
    1022        ``@compiles`` extension. 
    1023 
    1024        """ 
    1025 
    1026        compile_state = self._compile_state_factory(self, compiler, **kw) 
    1027 
    1028        toplevel = not compiler.stack 
    1029 
    1030        if toplevel: 
    1031            compiler.compile_state = compile_state 
    1032 
    1033        return compiler.process(compile_state.statement, **kw) 
    1034 
    1035    @property 
    1036    def column_descriptions(self): 
    1037        """Return a :term:`plugin-enabled` 'column descriptions' structure 
    1038        referring to the columns which are SELECTed by this statement. 
    1039 
    1040        See the section :ref:`queryguide_inspection` for an overview 
    1041        of this feature. 
    1042 
    1043        .. seealso:: 
    1044 
    1045            :ref:`queryguide_inspection` - ORM background 
    1046 
    1047        """ 
    1048        meth = cast( 
    1049            _ORMSelectCompileState, SelectState.get_plugin_class(self) 
    1050        ).get_column_descriptions 
    1051        return meth(self) 
    1052 
    1053    def _ensure_disambiguated_names(self): 
    1054        return self 
    1055 
    1056    def get_children(self, **kw): 
    1057        yield from itertools.chain.from_iterable( 
    1058            element._from_objects for element in self._raw_columns 
    1059        ) 
    1060        yield from super().get_children(**kw) 
    1061 
    1062    @property 
    1063    def _all_selected_columns(self): 
    1064        return self.element._all_selected_columns 
    1065 
    1066    @property 
    1067    def _return_defaults(self): 
    1068        return self.element._return_defaults if is_dml(self.element) else None 
    1069 
    1070    @property 
    1071    def _returning(self): 
    1072        return self.element._returning if is_dml(self.element) else None 
    1073 
    1074    @property 
    1075    def _inline(self): 
    1076        return self.element._inline if is_insert_update(self.element) else None 
    1077 
    1078 
    1079@sql.base.CompileState.plugin_for("orm", "compound_select") 
    1080class _CompoundSelectCompileState( 
    1081    _AutoflushOnlyORMCompileState, CompoundSelectState 
    1082): 
    1083    pass 
    1084 
    1085 
    1086@sql.base.CompileState.plugin_for("orm", "select") 
    1087class _ORMSelectCompileState(_ORMCompileState, SelectState): 
    1088    _already_joined_edges = () 
    1089 
    1090    _memoized_entities = _EMPTY_DICT 
    1091 
    1092    _from_obj_alias = None 
    1093    _has_mapper_entities = False 
    1094 
    1095    _has_orm_entities = False 
    1096    multi_row_eager_loaders = False 
    1097    eager_adding_joins = False 
    1098    compound_eager_adapter = None 
    1099 
    1100    correlate = None 
    1101    correlate_except = None 
    1102    _where_criteria = () 
    1103    _having_criteria = () 
    1104 
    1105    @classmethod 
    1106    def _create_orm_context( 
    1107        cls, 
    1108        statement: Union[Select, FromStatement], 
    1109        *, 
    1110        toplevel: bool, 
    1111        compiler: Optional[SQLCompiler], 
    1112        **kw: Any, 
    1113    ) -> _ORMSelectCompileState: 
    1114 
    1115        self = cls.__new__(cls) 
    1116 
    1117        select_statement = statement 
    1118 
    1119        # if we are a select() that was never a legacy Query, we won't 
    1120        # have ORM level compile options. 
    1121        statement._compile_options = cls.default_compile_options.safe_merge( 
    1122            statement._compile_options 
    1123        ) 
    1124 
    1125        if select_statement._execution_options: 
    1126            # execution options should not impact the compilation of a 
    1127            # query, and at the moment subqueryloader is putting some things 
    1128            # in here that we explicitly don't want stuck in a cache. 
    1129            self.select_statement = select_statement._clone() 
    1130            self.select_statement._execution_options = util.immutabledict() 
    1131        else: 
    1132            self.select_statement = select_statement 
    1133 
    1134        # indicates this select() came from Query.statement 
    1135        self.for_statement = select_statement._compile_options._for_statement 
    1136 
    1137        # generally if we are from Query or directly from a select() 
    1138        self.use_legacy_query_style = ( 
    1139            select_statement._compile_options._use_legacy_query_style 
    1140        ) 
    1141 
    1142        self._entities = [] 
    1143        self._primary_entity = None 
    1144        self._polymorphic_adapters = {} 
    1145 
    1146        self.compile_options = select_statement._compile_options 
    1147 
    1148        if not toplevel: 
    1149            # for subqueries, turn off eagerloads and set 
    1150            # "render_for_subquery". 
    1151            self.compile_options += { 
    1152                "_enable_eagerloads": False, 
    1153                "_render_for_subquery": True, 
    1154            } 
    1155 
    1156        # determine label style.   we can make different decisions here. 
    1157        # at the moment, trying to see if we can always use DISAMBIGUATE_ONLY 
    1158        # rather than LABEL_STYLE_NONE, and if we can use disambiguate style 
    1159        # for new style ORM selects too. 
    1160        if ( 
    1161            self.use_legacy_query_style 
    1162            and self.select_statement._label_style is LABEL_STYLE_LEGACY_ORM 
    1163        ): 
    1164            if not self.for_statement: 
    1165                self.label_style = LABEL_STYLE_TABLENAME_PLUS_COL 
    1166            else: 
    1167                self.label_style = LABEL_STYLE_DISAMBIGUATE_ONLY 
    1168        else: 
    1169            self.label_style = self.select_statement._label_style 
    1170 
    1171        if select_statement._memoized_select_entities: 
    1172            self._memoized_entities = { 
    1173                memoized_entities: _QueryEntity.to_compile_state( 
    1174                    self, 
    1175                    memoized_entities._raw_columns, 
    1176                    [], 
    1177                    is_current_entities=False, 
    1178                ) 
    1179                for memoized_entities in ( 
    1180                    select_statement._memoized_select_entities 
    1181                ) 
    1182            } 
    1183 
    1184        # label_convention is stateful and will yield deduping keys if it 
    1185        # sees the same key twice.  therefore it's important that it is not 
    1186        # invoked for the above "memoized" entities that aren't actually 
    1187        # in the columns clause 
    1188        self._label_convention = self._column_naming_convention( 
    1189            statement._label_style, self.use_legacy_query_style 
    1190        ) 
    1191 
    1192        _QueryEntity.to_compile_state( 
    1193            self, 
    1194            select_statement._raw_columns, 
    1195            self._entities, 
    1196            is_current_entities=True, 
    1197        ) 
    1198 
    1199        self.current_path = select_statement._compile_options._current_path 
    1200 
    1201        self.eager_order_by = () 
    1202 
    1203        self._init_global_attributes( 
    1204            select_statement, 
    1205            compiler, 
    1206            toplevel=toplevel, 
    1207            process_criteria_for_toplevel=False, 
    1208        ) 
    1209 
    1210        if toplevel and ( 
    1211            select_statement._with_options 
    1212            or select_statement._memoized_select_entities 
    1213        ): 
    1214            for ( 
    1215                memoized_entities 
    1216            ) in select_statement._memoized_select_entities: 
    1217                for opt in memoized_entities._with_options: 
    1218                    if opt._is_compile_state: 
    1219                        opt.process_compile_state_replaced_entities( 
    1220                            self, 
    1221                            [ 
    1222                                ent 
    1223                                for ent in self._memoized_entities[ 
    1224                                    memoized_entities 
    1225                                ] 
    1226                                if isinstance(ent, _MapperEntity) 
    1227                            ], 
    1228                        ) 
    1229 
    1230            for opt in self.select_statement._with_options: 
    1231                if opt._is_compile_state: 
    1232                    opt.process_compile_state(self) 
    1233 
    1234        # uncomment to print out the context.attributes structure 
    1235        # after it's been set up above 
    1236        # self._dump_option_struct() 
    1237 
    1238        if select_statement._compile_state_funcs: 
    1239            for fn, key in select_statement._compile_state_funcs: 
    1240                fn(self) 
    1241 
    1242        self.primary_columns = [] 
    1243        self.secondary_columns = [] 
    1244        self.dedupe_columns = set() 
    1245        self.eager_joins = {} 
    1246        self.extra_criteria_entities = {} 
    1247        self.create_eager_joins = [] 
    1248        self._fallback_from_clauses = [] 
    1249 
    1250        # normalize the FROM clauses early by themselves, as this makes 
    1251        # it an easier job when we need to assemble a JOIN onto these, 
    1252        # for select.join() as well as joinedload().   As of 1.4 there are now 
    1253        # potentially more complex sets of FROM objects here as the use 
    1254        # of lambda statements for lazyload, load_on_pk etc. uses more 
    1255        # cloning of the select() construct.  See #6495 
    1256        self.from_clauses = self._normalize_froms( 
    1257            info.selectable for info in select_statement._from_obj 
    1258        ) 
    1259 
    1260        # this is a fairly arbitrary break into a second method, 
    1261        # so it might be nicer to break up create_for_statement() 
    1262        # and _setup_for_generate into three or four logical sections 
    1263        self._setup_for_generate() 
    1264 
    1265        SelectState.__init__(self, self.statement, compiler, **kw) 
    1266        return self 
    1267 
    1268    def _dump_option_struct(self): 
    1269        print("\n---------------------------------------------------\n") 
    1270        print(f"current path: {self.current_path}") 
    1271        for key in self.attributes: 
    1272            if isinstance(key, tuple) and key[0] == "loader": 
    1273                print(f"\nLoader:           {PathRegistry.coerce(key[1])}") 
    1274                print(f"    {self.attributes[key]}") 
    1275                print(f"    {self.attributes[key].__dict__}") 
    1276            elif isinstance(key, tuple) and key[0] == "path_with_polymorphic": 
    1277                print(f"\nWith Polymorphic: {PathRegistry.coerce(key[1])}") 
    1278                print(f"    {self.attributes[key]}") 
    1279 
    1280    def _setup_for_generate(self): 
    1281        query = self.select_statement 
    1282 
    1283        self.statement = None 
    1284        self._join_entities = () 
    1285 
    1286        if self.compile_options._set_base_alias: 
    1287            # legacy Query only 
    1288            self._set_select_from_alias() 
    1289 
    1290        for memoized_entities in query._memoized_select_entities: 
    1291            if memoized_entities._setup_joins: 
    1292                self._join( 
    1293                    memoized_entities._setup_joins, 
    1294                    self._memoized_entities[memoized_entities], 
    1295                ) 
    1296 
    1297        if query._setup_joins: 
    1298            self._join(query._setup_joins, self._entities) 
    1299 
    1300        current_adapter = self._get_current_adapter() 
    1301 
    1302        if query._where_criteria: 
    1303            self._where_criteria = query._where_criteria 
    1304 
    1305            if current_adapter: 
    1306                self._where_criteria = tuple( 
    1307                    current_adapter(crit, True) 
    1308                    for crit in self._where_criteria 
    1309                ) 
    1310 
    1311        # TODO: some complexity with order_by here was due to mapper.order_by. 
    1312        # now that this is removed we can hopefully make order_by / 
    1313        # group_by act identically to how they are in Core select. 
    1314        self.order_by = ( 
    1315            self._adapt_col_list(query._order_by_clauses, current_adapter) 
    1316            if current_adapter and query._order_by_clauses not in (None, False) 
    1317            else query._order_by_clauses 
    1318        ) 
    1319 
    1320        if query._having_criteria: 
    1321            self._having_criteria = tuple( 
    1322                current_adapter(crit, True) if current_adapter else crit 
    1323                for crit in query._having_criteria 
    1324            ) 
    1325 
    1326        self.group_by = ( 
    1327            self._adapt_col_list( 
    1328                util.flatten_iterator(query._group_by_clauses), current_adapter 
    1329            ) 
    1330            if current_adapter and query._group_by_clauses not in (None, False) 
    1331            else query._group_by_clauses or None 
    1332        ) 
    1333 
    1334        if self.eager_order_by: 
    1335            adapter = self.from_clauses[0]._target_adapter 
    1336            self.eager_order_by = adapter.copy_and_process(self.eager_order_by) 
    1337 
    1338        if query._distinct_on: 
    1339            self.distinct_on = self._adapt_col_list( 
    1340                query._distinct_on, current_adapter 
    1341            ) 
    1342        else: 
    1343            self.distinct_on = () 
    1344 
    1345        self.distinct = query._distinct 
    1346 
    1347        self.syntax_extensions = { 
    1348            key: current_adapter(value, True) if current_adapter else value 
    1349            for key, value in query._get_syntax_extensions_as_dict().items() 
    1350        } 
    1351 
    1352        if query._correlate: 
    1353            # ORM mapped entities that are mapped to joins can be passed 
    1354            # to .correlate, so here they are broken into their component 
    1355            # tables. 
    1356            self.correlate = tuple( 
    1357                util.flatten_iterator( 
    1358                    sql_util.surface_selectables(s) if s is not None else None 
    1359                    for s in query._correlate 
    1360                ) 
    1361            ) 
    1362        elif query._correlate_except is not None: 
    1363            self.correlate_except = tuple( 
    1364                util.flatten_iterator( 
    1365                    sql_util.surface_selectables(s) if s is not None else None 
    1366                    for s in query._correlate_except 
    1367                ) 
    1368            ) 
    1369        elif not query._auto_correlate: 
    1370            self.correlate = (None,) 
    1371 
    1372        # PART II 
    1373 
    1374        self._for_update_arg = query._for_update_arg 
    1375 
    1376        if self.compile_options._is_star and (len(self._entities) != 1): 
    1377            raise sa_exc.CompileError( 
    1378                "Can't generate ORM query that includes multiple expressions " 
    1379                "at the same time as '*'; query for '*' alone if present" 
    1380            ) 
    1381        for entity in self._entities: 
    1382            entity.setup_compile_state(self) 
    1383 
    1384        for rec in self.create_eager_joins: 
    1385            strategy = rec[0] 
    1386            strategy(self, *rec[1:]) 
    1387 
    1388        # else "load from discrete FROMs" mode, 
    1389        # i.e. when each _MappedEntity has its own FROM 
    1390 
    1391        if self.compile_options._enable_single_crit: 
    1392            self._adjust_for_extra_criteria() 
    1393 
    1394        if not self.primary_columns: 
    1395            if self.compile_options._only_load_props: 
    1396                assert False, "no columns were included in _only_load_props" 
    1397 
    1398            raise sa_exc.InvalidRequestError( 
    1399                "Query contains no columns with which to SELECT from." 
    1400            ) 
    1401 
    1402        if not self.from_clauses: 
    1403            self.from_clauses = list(self._fallback_from_clauses) 
    1404 
    1405        if self.order_by is False: 
    1406            self.order_by = None 
    1407 
    1408        if self._should_nest_selectable: 
    1409            self.statement = self._compound_eager_statement() 
    1410        else: 
    1411            self.statement = self._simple_statement() 
    1412 
    1413        if self.for_statement: 
    1414            ezero = self._mapper_zero() 
    1415            if ezero is not None: 
    1416                # TODO: this goes away once we get rid of the deep entity 
    1417                # thing 
    1418                self.statement = self.statement._annotate( 
    1419                    {"deepentity": ezero} 
    1420                ) 
    1421 
    1422    @classmethod 
    1423    def _create_entities_collection(cls, query, legacy): 
    1424        """Creates a partial ORMSelectCompileState that includes 
    1425        the full collection of _MapperEntity and other _QueryEntity objects. 
    1426 
    1427        Supports a few remaining use cases that are pre-compilation 
    1428        but still need to gather some of the column  / adaption information. 
    1429 
    1430        """ 
    1431        self = cls.__new__(cls) 
    1432 
    1433        self._entities = [] 
    1434        self._primary_entity = None 
    1435        self._polymorphic_adapters = {} 
    1436 
    1437        self._label_convention = self._column_naming_convention( 
    1438            query._label_style, legacy 
    1439        ) 
    1440 
    1441        # entities will also set up polymorphic adapters for mappers 
    1442        # that have with_polymorphic configured 
    1443        _QueryEntity.to_compile_state( 
    1444            self, query._raw_columns, self._entities, is_current_entities=True 
    1445        ) 
    1446        return self 
    1447 
    1448    @classmethod 
    1449    def determine_last_joined_entity(cls, statement): 
    1450        setup_joins = statement._setup_joins 
    1451 
    1452        return _determine_last_joined_entity(setup_joins, None) 
    1453 
    1454    @classmethod 
    1455    def all_selected_columns(cls, statement): 
    1456        for element in statement._raw_columns: 
    1457            if ( 
    1458                element.is_selectable 
    1459                and "entity_namespace" in element._annotations 
    1460            ): 
    1461                ens = element._annotations["entity_namespace"] 
    1462                if not ens.is_mapper and not ens.is_aliased_class: 
    1463                    yield from _select_iterables([element]) 
    1464                else: 
    1465                    yield from _select_iterables(ens._all_column_expressions) 
    1466            else: 
    1467                yield from _select_iterables([element]) 
    1468 
    1469    @classmethod 
    1470    def get_columns_clause_froms(cls, statement): 
    1471        return cls._normalize_froms( 
    1472            itertools.chain.from_iterable( 
    1473                ( 
    1474                    element._from_objects 
    1475                    if "parententity" not in element._annotations 
    1476                    else [ 
    1477                        element._annotations[ 
    1478                            "parententity" 
    1479                        ].__clause_element__() 
    1480                    ] 
    1481                ) 
    1482                for element in statement._raw_columns 
    1483            ) 
    1484        ) 
    1485 
    1486    @classmethod 
    1487    def from_statement(cls, statement, from_statement): 
    1488        from_statement = coercions.expect( 
    1489            roles.ReturnsRowsRole, 
    1490            from_statement, 
    1491            apply_propagate_attrs=statement, 
    1492        ) 
    1493 
    1494        stmt = FromStatement(statement._raw_columns, from_statement) 
    1495 
    1496        stmt.__dict__.update( 
    1497            _with_options=statement._with_options, 
    1498            _compile_state_funcs=statement._compile_state_funcs, 
    1499            _execution_options=statement._execution_options, 
    1500            _propagate_attrs=statement._propagate_attrs, 
    1501        ) 
    1502        return stmt 
    1503 
    1504    def _set_select_from_alias(self): 
    1505        """used only for legacy Query cases""" 
    1506 
    1507        query = self.select_statement  # query 
    1508 
    1509        assert self.compile_options._set_base_alias 
    1510        assert len(query._from_obj) == 1 
    1511 
    1512        adapter = self._get_select_from_alias_from_obj(query._from_obj[0]) 
    1513        if adapter: 
    1514            self.compile_options += {"_enable_single_crit": False} 
    1515            self._from_obj_alias = adapter 
    1516 
    1517    def _get_select_from_alias_from_obj(self, from_obj): 
    1518        """used only for legacy Query cases""" 
    1519 
    1520        info = from_obj 
    1521 
    1522        if "parententity" in info._annotations: 
    1523            info = info._annotations["parententity"] 
    1524 
    1525        if hasattr(info, "mapper"): 
    1526            if not info.is_aliased_class: 
    1527                raise sa_exc.ArgumentError( 
    1528                    "A selectable (FromClause) instance is " 
    1529                    "expected when the base alias is being set." 
    1530                ) 
    1531            else: 
    1532                return info._adapter 
    1533 
    1534        elif isinstance(info.selectable, sql.selectable.AliasedReturnsRows): 
    1535            equivs = self._all_equivs() 
    1536            assert info is info.selectable 
    1537            return ORMStatementAdapter( 
    1538                _TraceAdaptRole.LEGACY_SELECT_FROM_ALIAS, 
    1539                info.selectable, 
    1540                equivalents=equivs, 
    1541            ) 
    1542        else: 
    1543            return None 
    1544 
    1545    def _mapper_zero(self): 
    1546        """return the Mapper associated with the first QueryEntity.""" 
    1547        return self._entities[0].mapper 
    1548 
    1549    def _entity_zero(self): 
    1550        """Return the 'entity' (mapper or AliasedClass) associated 
    1551        with the first QueryEntity, or alternatively the 'select from' 
    1552        entity if specified.""" 
    1553 
    1554        for ent in self.from_clauses: 
    1555            if "parententity" in ent._annotations: 
    1556                return ent._annotations["parententity"] 
    1557        for qent in self._entities: 
    1558            if qent.entity_zero: 
    1559                return qent.entity_zero 
    1560 
    1561        return None 
    1562 
    1563    def _only_full_mapper_zero(self, methname): 
    1564        if self._entities != [self._primary_entity]: 
    1565            raise sa_exc.InvalidRequestError( 
    1566                "%s() can only be used against " 
    1567                "a single mapped class." % methname 
    1568            ) 
    1569        return self._primary_entity.entity_zero 
    1570 
    1571    def _only_entity_zero(self, rationale=None): 
    1572        if len(self._entities) > 1: 
    1573            raise sa_exc.InvalidRequestError( 
    1574                rationale 
    1575                or "This operation requires a Query " 
    1576                "against a single mapper." 
    1577            ) 
    1578        return self._entity_zero() 
    1579 
    1580    def _all_equivs(self): 
    1581        equivs = {} 
    1582 
    1583        for memoized_entities in self._memoized_entities.values(): 
    1584            for ent in [ 
    1585                ent 
    1586                for ent in memoized_entities 
    1587                if isinstance(ent, _MapperEntity) 
    1588            ]: 
    1589                equivs.update(ent.mapper._equivalent_columns) 
    1590 
    1591        for ent in [ 
    1592            ent for ent in self._entities if isinstance(ent, _MapperEntity) 
    1593        ]: 
    1594            equivs.update(ent.mapper._equivalent_columns) 
    1595        return equivs 
    1596 
    1597    def _compound_eager_statement(self): 
    1598        # for eager joins present and LIMIT/OFFSET/DISTINCT, 
    1599        # wrap the query inside a select, 
    1600        # then append eager joins onto that 
    1601 
    1602        if self.order_by: 
    1603            # the default coercion for ORDER BY is now the OrderByRole, 
    1604            # which adds an additional post coercion to ByOfRole in that 
    1605            # elements are converted into label references.  For the 
    1606            # eager load / subquery wrapping case, we need to un-coerce 
    1607            # the original expressions outside of the label references 
    1608            # in order to have them render. 
    1609            unwrapped_order_by = [ 
    1610                ( 
    1611                    elem.element 
    1612                    if isinstance(elem, sql.elements._label_reference) 
    1613                    else elem 
    1614                ) 
    1615                for elem in self.order_by 
    1616            ] 
    1617 
    1618            order_by_col_expr = sql_util.expand_column_list_from_order_by( 
    1619                self.primary_columns, unwrapped_order_by 
    1620            ) 
    1621        else: 
    1622            order_by_col_expr = [] 
    1623            unwrapped_order_by = None 
    1624 
    1625        # put FOR UPDATE on the inner query, where MySQL will honor it, 
    1626        # as well as if it has an OF so PostgreSQL can use it. 
    1627        inner = self._select_statement( 
    1628            self.primary_columns 
    1629            + [c for c in order_by_col_expr if c not in self.dedupe_columns], 
    1630            self.from_clauses, 
    1631            self._where_criteria, 
    1632            self._having_criteria, 
    1633            self.label_style, 
    1634            self.order_by, 
    1635            for_update=self._for_update_arg, 
    1636            hints=self.select_statement._hints, 
    1637            statement_hints=self.select_statement._statement_hints, 
    1638            correlate=self.correlate, 
    1639            correlate_except=self.correlate_except, 
    1640            **self._select_args, 
    1641        ) 
    1642 
    1643        inner = inner.alias() 
    1644 
    1645        equivs = self._all_equivs() 
    1646 
    1647        self.compound_eager_adapter = ORMStatementAdapter( 
    1648            _TraceAdaptRole.COMPOUND_EAGER_STATEMENT, inner, equivalents=equivs 
    1649        ) 
    1650 
    1651        statement = future.select( 
    1652            *([inner] + self.secondary_columns)  # use_labels=self.labels 
    1653        ) 
    1654        statement._label_style = self.label_style 
    1655 
    1656        # Oracle Database however does not allow FOR UPDATE on the subquery, 
    1657        # and the Oracle Database dialects ignore it, plus for PostgreSQL, 
    1658        # MySQL we expect that all elements of the row are locked, so also put 
    1659        # it on the outside (except in the case of PG when OF is used) 
    1660        if ( 
    1661            self._for_update_arg is not None 
    1662            and self._for_update_arg.of is None 
    1663        ): 
    1664            statement._for_update_arg = self._for_update_arg 
    1665 
    1666        from_clause = inner 
    1667        for eager_join in self.eager_joins.values(): 
    1668            # EagerLoader places a 'stop_on' attribute on the join, 
    1669            # giving us a marker as to where the "splice point" of 
    1670            # the join should be 
    1671            from_clause = sql_util.splice_joins( 
    1672                from_clause, eager_join, eager_join.stop_on 
    1673            ) 
    1674 
    1675        statement.select_from.non_generative(statement, from_clause) 
    1676 
    1677        if unwrapped_order_by: 
    1678            statement.order_by.non_generative( 
    1679                statement, 
    1680                *self.compound_eager_adapter.copy_and_process( 
    1681                    unwrapped_order_by 
    1682                ), 
    1683            ) 
    1684 
    1685        statement.order_by.non_generative(statement, *self.eager_order_by) 
    1686        return statement 
    1687 
    1688    def _simple_statement(self): 
    1689        statement = self._select_statement( 
    1690            self.primary_columns + self.secondary_columns, 
    1691            tuple(self.from_clauses) + tuple(self.eager_joins.values()), 
    1692            self._where_criteria, 
    1693            self._having_criteria, 
    1694            self.label_style, 
    1695            self.order_by, 
    1696            for_update=self._for_update_arg, 
    1697            hints=self.select_statement._hints, 
    1698            statement_hints=self.select_statement._statement_hints, 
    1699            correlate=self.correlate, 
    1700            correlate_except=self.correlate_except, 
    1701            **self._select_args, 
    1702        ) 
    1703 
    1704        if self.eager_order_by: 
    1705            statement.order_by.non_generative(statement, *self.eager_order_by) 
    1706        return statement 
    1707 
    1708    def _select_statement( 
    1709        self, 
    1710        raw_columns, 
    1711        from_obj, 
    1712        where_criteria, 
    1713        having_criteria, 
    1714        label_style, 
    1715        order_by, 
    1716        for_update, 
    1717        hints, 
    1718        statement_hints, 
    1719        correlate, 
    1720        correlate_except, 
    1721        limit_clause, 
    1722        offset_clause, 
    1723        fetch_clause, 
    1724        fetch_clause_options, 
    1725        distinct, 
    1726        distinct_on, 
    1727        prefixes, 
    1728        suffixes, 
    1729        group_by, 
    1730        independent_ctes, 
    1731        independent_ctes_opts, 
    1732        syntax_extensions, 
    1733    ): 
    1734        statement = Select._create_raw_select( 
    1735            _raw_columns=raw_columns, 
    1736            _from_obj=from_obj, 
    1737            _label_style=label_style, 
    1738        ) 
    1739 
    1740        if where_criteria: 
    1741            statement._where_criteria = where_criteria 
    1742        if having_criteria: 
    1743            statement._having_criteria = having_criteria 
    1744 
    1745        if order_by: 
    1746            statement._order_by_clauses += tuple(order_by) 
    1747 
    1748        if distinct_on: 
    1749            statement._distinct = True 
    1750            statement._distinct_on = distinct_on 
    1751        elif distinct: 
    1752            statement._distinct = True 
    1753 
    1754        if group_by: 
    1755            statement._group_by_clauses += tuple(group_by) 
    1756 
    1757        statement._limit_clause = limit_clause 
    1758        statement._offset_clause = offset_clause 
    1759        statement._fetch_clause = fetch_clause 
    1760        statement._fetch_clause_options = fetch_clause_options 
    1761        statement._independent_ctes = independent_ctes 
    1762        statement._independent_ctes_opts = independent_ctes_opts 
    1763        if syntax_extensions: 
    1764            statement._set_syntax_extensions(**syntax_extensions) 
    1765 
    1766        if prefixes: 
    1767            statement._prefixes = prefixes 
    1768 
    1769        if suffixes: 
    1770            statement._suffixes = suffixes 
    1771 
    1772        statement._for_update_arg = for_update 
    1773 
    1774        if hints: 
    1775            statement._hints = hints 
    1776        if statement_hints: 
    1777            statement._statement_hints = statement_hints 
    1778 
    1779        if correlate: 
    1780            statement.correlate.non_generative(statement, *correlate) 
    1781 
    1782        if correlate_except is not None: 
    1783            statement.correlate_except.non_generative( 
    1784                statement, *correlate_except 
    1785            ) 
    1786 
    1787        return statement 
    1788 
    1789    def _adapt_polymorphic_element(self, element): 
    1790        if "parententity" in element._annotations: 
    1791            search = element._annotations["parententity"] 
    1792            alias = self._polymorphic_adapters.get(search, None) 
    1793            if alias: 
    1794                return alias.adapt_clause(element) 
    1795 
    1796        if isinstance(element, expression.FromClause): 
    1797            search = element 
    1798        elif hasattr(element, "table"): 
    1799            search = element.table 
    1800        else: 
    1801            return None 
    1802 
    1803        alias = self._polymorphic_adapters.get(search, None) 
    1804        if alias: 
    1805            return alias.adapt_clause(element) 
    1806 
    1807    def _adapt_col_list(self, cols, current_adapter): 
    1808        if current_adapter: 
    1809            return [current_adapter(o, True) for o in cols] 
    1810        else: 
    1811            return cols 
    1812 
    1813    def _get_current_adapter(self): 
    1814        adapters = [] 
    1815 
    1816        if self._from_obj_alias: 
    1817            # used for legacy going forward for query set_ops, e.g. 
    1818            # union(), union_all(), etc. 
    1819            # 1.4 and previously, also used for from_self(), 
    1820            # select_entity_from() 
    1821            # 
    1822            # for the "from obj" alias, apply extra rule to the 
    1823            # 'ORM only' check, if this query were generated from a 
    1824            # subquery of itself, i.e. _from_selectable(), apply adaption 
    1825            # to all SQL constructs. 
    1826            adapters.append( 
    1827                self._from_obj_alias.replace, 
    1828            ) 
    1829 
    1830        # this was *hopefully* the only adapter we were going to need 
    1831        # going forward...however, we unfortunately need _from_obj_alias 
    1832        # for query.union(), which we can't drop 
    1833        if self._polymorphic_adapters: 
    1834            adapters.append(self._adapt_polymorphic_element) 
    1835 
    1836        if not adapters: 
    1837            return None 
    1838 
    1839        def _adapt_clause(clause, as_filter): 
    1840            # do we adapt all expression elements or only those 
    1841            # tagged as 'ORM' constructs ? 
    1842 
    1843            def replace(elem): 
    1844                for adapter in adapters: 
    1845                    e = adapter(elem) 
    1846                    if e is not None: 
    1847                        return e 
    1848 
    1849            return visitors.replacement_traverse(clause, {}, replace) 
    1850 
    1851        return _adapt_clause 
    1852 
    1853    def _join(self, args, entities_collection): 
    1854        for right, onclause, from_, flags in args: 
    1855            isouter = flags["isouter"] 
    1856            full = flags["full"] 
    1857 
    1858            right = inspect(right) 
    1859            if onclause is not None: 
    1860                onclause = inspect(onclause) 
    1861 
    1862            if isinstance(right, interfaces.PropComparator): 
    1863                if onclause is not None: 
    1864                    raise sa_exc.InvalidRequestError( 
    1865                        "No 'on clause' argument may be passed when joining " 
    1866                        "to a relationship path as a target" 
    1867                    ) 
    1868 
    1869                onclause = right 
    1870                right = None 
    1871            elif "parententity" in right._annotations: 
    1872                right = right._annotations["parententity"] 
    1873 
    1874            if onclause is None: 
    1875                if not right.is_selectable and not hasattr(right, "mapper"): 
    1876                    raise sa_exc.ArgumentError( 
    1877                        "Expected mapped entity or " 
    1878                        "selectable/table as join target" 
    1879                    ) 
    1880 
    1881            if isinstance(onclause, interfaces.PropComparator): 
    1882                # descriptor/property given (or determined); this tells us 
    1883                # explicitly what the expected "left" side of the join is. 
    1884 
    1885                of_type = getattr(onclause, "_of_type", None) 
    1886 
    1887                if right is None: 
    1888                    if of_type: 
    1889                        right = of_type 
    1890                    else: 
    1891                        right = onclause.property 
    1892 
    1893                        try: 
    1894                            right = right.entity 
    1895                        except AttributeError as err: 
    1896                            raise sa_exc.ArgumentError( 
    1897                                "Join target %s does not refer to a " 
    1898                                "mapped entity" % right 
    1899                            ) from err 
    1900 
    1901                left = onclause._parententity 
    1902 
    1903                prop = onclause.property 
    1904                if not isinstance(onclause, attributes.QueryableAttribute): 
    1905                    onclause = prop 
    1906 
    1907                # check for this path already present.  don't render in that 
    1908                # case. 
    1909                if (left, right, prop.key) in self._already_joined_edges: 
    1910                    continue 
    1911 
    1912                if from_ is not None: 
    1913                    if ( 
    1914                        from_ is not left 
    1915                        and from_._annotations.get("parententity", None) 
    1916                        is not left 
    1917                    ): 
    1918                        raise sa_exc.InvalidRequestError( 
    1919                            "explicit from clause %s does not match left side " 
    1920                            "of relationship attribute %s" 
    1921                            % ( 
    1922                                from_._annotations.get("parententity", from_), 
    1923                                onclause, 
    1924                            ) 
    1925                        ) 
    1926            elif from_ is not None: 
    1927                prop = None 
    1928                left = from_ 
    1929            else: 
    1930                # no descriptor/property given; we will need to figure out 
    1931                # what the effective "left" side is 
    1932                prop = left = None 
    1933 
    1934            # figure out the final "left" and "right" sides and create an 
    1935            # ORMJoin to add to our _from_obj tuple 
    1936            self._join_left_to_right( 
    1937                entities_collection, 
    1938                left, 
    1939                right, 
    1940                onclause, 
    1941                prop, 
    1942                isouter, 
    1943                full, 
    1944            ) 
    1945 
    1946    def _join_left_to_right( 
    1947        self, 
    1948        entities_collection, 
    1949        left, 
    1950        right, 
    1951        onclause, 
    1952        prop, 
    1953        outerjoin, 
    1954        full, 
    1955    ): 
    1956        """given raw "left", "right", "onclause" parameters consumed from 
    1957        a particular key within _join(), add a real ORMJoin object to 
    1958        our _from_obj list (or augment an existing one) 
    1959 
    1960        """ 
    1961 
    1962        explicit_left = left 
    1963        if left is None: 
    1964            # left not given (e.g. no relationship object/name specified) 
    1965            # figure out the best "left" side based on our existing froms / 
    1966            # entities 
    1967            assert prop is None 
    1968            ( 
    1969                left, 
    1970                replace_from_obj_index, 
    1971                use_entity_index, 
    1972            ) = self._join_determine_implicit_left_side( 
    1973                entities_collection, left, right, onclause 
    1974            ) 
    1975        else: 
    1976            # left is given via a relationship/name, or as explicit left side. 
    1977            # Determine where in our 
    1978            # "froms" list it should be spliced/appended as well as what 
    1979            # existing entity it corresponds to. 
    1980            ( 
    1981                replace_from_obj_index, 
    1982                use_entity_index, 
    1983            ) = self._join_place_explicit_left_side(entities_collection, left) 
    1984 
    1985        if left is right: 
    1986            raise sa_exc.InvalidRequestError( 
    1987                "Can't construct a join from %s to %s, they " 
    1988                "are the same entity" % (left, right) 
    1989            ) 
    1990 
    1991        # the right side as given often needs to be adapted.  additionally 
    1992        # a lot of things can be wrong with it.  handle all that and 
    1993        # get back the new effective "right" side 
    1994        r_info, right, onclause = self._join_check_and_adapt_right_side( 
    1995            left, right, onclause, prop 
    1996        ) 
    1997 
    1998        if not r_info.is_selectable: 
    1999            extra_criteria = self._get_extra_criteria(r_info) 
    2000        else: 
    2001            extra_criteria = () 
    2002 
    2003        if replace_from_obj_index is not None: 
    2004            # splice into an existing element in the 
    2005            # self._from_obj list 
    2006            left_clause = self.from_clauses[replace_from_obj_index] 
    2007 
    2008            if explicit_left is not None and onclause is None: 
    2009                onclause = _ORMJoin._join_condition(explicit_left, right) 
    2010 
    2011            self.from_clauses = ( 
    2012                self.from_clauses[:replace_from_obj_index] 
    2013                + [ 
    2014                    _ORMJoin( 
    2015                        left_clause, 
    2016                        right, 
    2017                        onclause, 
    2018                        isouter=outerjoin, 
    2019                        full=full, 
    2020                        _extra_criteria=extra_criteria, 
    2021                    ) 
    2022                ] 
    2023                + self.from_clauses[replace_from_obj_index + 1 :] 
    2024            ) 
    2025        else: 
    2026            # add a new element to the self._from_obj list 
    2027            if use_entity_index is not None: 
    2028                # make use of _MapperEntity selectable, which is usually 
    2029                # entity_zero.selectable, but if with_polymorphic() were used 
    2030                # might be distinct 
    2031                assert isinstance( 
    2032                    entities_collection[use_entity_index], _MapperEntity 
    2033                ) 
    2034                left_clause = entities_collection[use_entity_index].selectable 
    2035            else: 
    2036                left_clause = left 
    2037 
    2038            self.from_clauses = self.from_clauses + [ 
    2039                _ORMJoin( 
    2040                    left_clause, 
    2041                    r_info, 
    2042                    onclause, 
    2043                    isouter=outerjoin, 
    2044                    full=full, 
    2045                    _extra_criteria=extra_criteria, 
    2046                ) 
    2047            ] 
    2048 
    2049    def _join_determine_implicit_left_side( 
    2050        self, entities_collection, left, right, onclause 
    2051    ): 
    2052        """When join conditions don't express the left side explicitly, 
    2053        determine if an existing FROM or entity in this query 
    2054        can serve as the left hand side. 
    2055 
    2056        """ 
    2057 
    2058        # when we are here, it means join() was called without an ORM- 
    2059        # specific way of telling us what the "left" side is, e.g.: 
    2060        # 
    2061        # join(RightEntity) 
    2062        # 
    2063        # or 
    2064        # 
    2065        # join(RightEntity, RightEntity.foo == LeftEntity.bar) 
    2066        # 
    2067 
    2068        r_info = inspect(right) 
    2069 
    2070        replace_from_obj_index = use_entity_index = None 
    2071 
    2072        if self.from_clauses: 
    2073            # we have a list of FROMs already.  So by definition this 
    2074            # join has to connect to one of those FROMs. 
    2075 
    2076            indexes = sql_util.find_left_clause_to_join_from( 
    2077                self.from_clauses, r_info.selectable, onclause 
    2078            ) 
    2079 
    2080            if len(indexes) == 1: 
    2081                replace_from_obj_index = indexes[0] 
    2082                left = self.from_clauses[replace_from_obj_index] 
    2083            elif len(indexes) > 1: 
    2084                raise sa_exc.InvalidRequestError( 
    2085                    "Can't determine which FROM clause to join " 
    2086                    "from, there are multiple FROMS which can " 
    2087                    "join to this entity. Please use the .select_from() " 
    2088                    "method to establish an explicit left side, as well as " 
    2089                    "providing an explicit ON clause if not present already " 
    2090                    "to help resolve the ambiguity." 
    2091                ) 
    2092            else: 
    2093                raise sa_exc.InvalidRequestError( 
    2094                    "Don't know how to join to %r. " 
    2095                    "Please use the .select_from() " 
    2096                    "method to establish an explicit left side, as well as " 
    2097                    "providing an explicit ON clause if not present already " 
    2098                    "to help resolve the ambiguity." % (right,) 
    2099                ) 
    2100 
    2101        elif entities_collection: 
    2102            # we have no explicit FROMs, so the implicit left has to 
    2103            # come from our list of entities. 
    2104 
    2105            potential = {} 
    2106            for entity_index, ent in enumerate(entities_collection): 
    2107                entity = ent.entity_zero_or_selectable 
    2108                if entity is None: 
    2109                    continue 
    2110                ent_info = inspect(entity) 
    2111                if ent_info is r_info:  # left and right are the same, skip 
    2112                    continue 
    2113 
    2114                # by using a dictionary with the selectables as keys this 
    2115                # de-duplicates those selectables as occurs when the query is 
    2116                # against a series of columns from the same selectable 
    2117                if isinstance(ent, _MapperEntity): 
    2118                    potential[ent.selectable] = (entity_index, entity) 
    2119                else: 
    2120                    potential[ent_info.selectable] = (None, entity) 
    2121 
    2122            all_clauses = list(potential.keys()) 
    2123            indexes = sql_util.find_left_clause_to_join_from( 
    2124                all_clauses, r_info.selectable, onclause 
    2125            ) 
    2126 
    2127            if len(indexes) == 1: 
    2128                use_entity_index, left = potential[all_clauses[indexes[0]]] 
    2129            elif len(indexes) > 1: 
    2130                raise sa_exc.InvalidRequestError( 
    2131                    "Can't determine which FROM clause to join " 
    2132                    "from, there are multiple FROMS which can " 
    2133                    "join to this entity. Please use the .select_from() " 
    2134                    "method to establish an explicit left side, as well as " 
    2135                    "providing an explicit ON clause if not present already " 
    2136                    "to help resolve the ambiguity." 
    2137                ) 
    2138            else: 
    2139                raise sa_exc.InvalidRequestError( 
    2140                    "Don't know how to join to %r. " 
    2141                    "Please use the .select_from() " 
    2142                    "method to establish an explicit left side, as well as " 
    2143                    "providing an explicit ON clause if not present already " 
    2144                    "to help resolve the ambiguity." % (right,) 
    2145                ) 
    2146        else: 
    2147            raise sa_exc.InvalidRequestError( 
    2148                "No entities to join from; please use " 
    2149                "select_from() to establish the left " 
    2150                "entity/selectable of this join" 
    2151            ) 
    2152 
    2153        return left, replace_from_obj_index, use_entity_index 
    2154 
    2155    def _join_place_explicit_left_side(self, entities_collection, left): 
    2156        """When join conditions express a left side explicitly, determine 
    2157        where in our existing list of FROM clauses we should join towards, 
    2158        or if we need to make a new join, and if so is it from one of our 
    2159        existing entities. 
    2160 
    2161        """ 
    2162 
    2163        # when we are here, it means join() was called with an indicator 
    2164        # as to an exact left side, which means a path to a 
    2165        # Relationship was given, e.g.: 
    2166        # 
    2167        # join(RightEntity, LeftEntity.right) 
    2168        # 
    2169        # or 
    2170        # 
    2171        # join(LeftEntity.right) 
    2172        # 
    2173        # as well as string forms: 
    2174        # 
    2175        # join(RightEntity, "right") 
    2176        # 
    2177        # etc. 
    2178        # 
    2179 
    2180        replace_from_obj_index = use_entity_index = None 
    2181 
    2182        l_info = inspect(left) 
    2183        if self.from_clauses: 
    2184            indexes = sql_util.find_left_clause_that_matches_given( 
    2185                self.from_clauses, l_info.selectable 
    2186            ) 
    2187 
    2188            if len(indexes) > 1: 
    2189                raise sa_exc.InvalidRequestError( 
    2190                    "Can't identify which entity in which to assign the " 
    2191                    "left side of this join.   Please use a more specific " 
    2192                    "ON clause." 
    2193                ) 
    2194 
    2195            # have an index, means the left side is already present in 
    2196            # an existing FROM in the self._from_obj tuple 
    2197            if indexes: 
    2198                replace_from_obj_index = indexes[0] 
    2199 
    2200            # no index, means we need to add a new element to the 
    2201            # self._from_obj tuple 
    2202 
    2203        # no from element present, so we will have to add to the 
    2204        # self._from_obj tuple.  Determine if this left side matches up 
    2205        # with existing mapper entities, in which case we want to apply the 
    2206        # aliasing / adaptation rules present on that entity if any 
    2207        if ( 
    2208            replace_from_obj_index is None 
    2209            and entities_collection 
    2210            and hasattr(l_info, "mapper") 
    2211        ): 
    2212            for idx, ent in enumerate(entities_collection): 
    2213                # TODO: should we be checking for multiple mapper entities 
    2214                # matching? 
    2215                if isinstance(ent, _MapperEntity) and ent.corresponds_to(left): 
    2216                    use_entity_index = idx 
    2217                    break 
    2218 
    2219        return replace_from_obj_index, use_entity_index 
    2220 
    2221    def _join_check_and_adapt_right_side(self, left, right, onclause, prop): 
    2222        """transform the "right" side of the join as well as the onclause 
    2223        according to polymorphic mapping translations, aliasing on the query 
    2224        or on the join, special cases where the right and left side have 
    2225        overlapping tables. 
    2226 
    2227        """ 
    2228 
    2229        l_info = inspect(left) 
    2230        r_info = inspect(right) 
    2231 
    2232        overlap = False 
    2233 
    2234        right_mapper = getattr(r_info, "mapper", None) 
    2235        # if the target is a joined inheritance mapping, 
    2236        # be more liberal about auto-aliasing. 
    2237        if right_mapper and ( 
    2238            right_mapper.with_polymorphic 
    2239            or isinstance(right_mapper.persist_selectable, expression.Join) 
    2240        ): 
    2241            for from_obj in self.from_clauses or [l_info.selectable]: 
    2242                if sql_util.selectables_overlap( 
    2243                    l_info.selectable, from_obj 
    2244                ) and sql_util.selectables_overlap( 
    2245                    from_obj, r_info.selectable 
    2246                ): 
    2247                    overlap = True 
    2248                    break 
    2249 
    2250        if overlap and l_info.selectable is r_info.selectable: 
    2251            raise sa_exc.InvalidRequestError( 
    2252                "Can't join table/selectable '%s' to itself" 
    2253                % l_info.selectable 
    2254            ) 
    2255 
    2256        right_mapper, right_selectable, right_is_aliased = ( 
    2257            getattr(r_info, "mapper", None), 
    2258            r_info.selectable, 
    2259            getattr(r_info, "is_aliased_class", False), 
    2260        ) 
    2261 
    2262        if ( 
    2263            right_mapper 
    2264            and prop 
    2265            and not right_mapper.common_parent(prop.mapper) 
    2266        ): 
    2267            raise sa_exc.InvalidRequestError( 
    2268                "Join target %s does not correspond to " 
    2269                "the right side of join condition %s" % (right, onclause) 
    2270            ) 
    2271 
    2272        # _join_entities is used as a hint for single-table inheritance 
    2273        # purposes at the moment 
    2274        if hasattr(r_info, "mapper"): 
    2275            self._join_entities += (r_info,) 
    2276 
    2277        need_adapter = False 
    2278 
    2279        # test for joining to an unmapped selectable as the target 
    2280        if r_info.is_clause_element: 
    2281            if prop: 
    2282                right_mapper = prop.mapper 
    2283 
    2284            if right_selectable._is_lateral: 
    2285                # orm_only is disabled to suit the case where we have to 
    2286                # adapt an explicit correlate(Entity) - the select() loses 
    2287                # the ORM-ness in this case right now, ideally it would not 
    2288                current_adapter = self._get_current_adapter() 
    2289                if current_adapter is not None: 
    2290                    # TODO: we had orm_only=False here before, removing 
    2291                    # it didn't break things.   if we identify the rationale, 
    2292                    # may need to apply "_orm_only" annotation here. 
    2293                    right = current_adapter(right, True) 
    2294 
    2295            elif prop: 
    2296                # joining to selectable with a mapper property given 
    2297                # as the ON clause 
    2298 
    2299                if not right_selectable.is_derived_from( 
    2300                    right_mapper.persist_selectable 
    2301                ): 
    2302                    raise sa_exc.InvalidRequestError( 
    2303                        "Selectable '%s' is not derived from '%s'" 
    2304                        % ( 
    2305                            right_selectable.description, 
    2306                            right_mapper.persist_selectable.description, 
    2307                        ) 
    2308                    ) 
    2309 
    2310                # if the destination selectable is a plain select(), 
    2311                # turn it into an alias(). 
    2312                if isinstance(right_selectable, expression.SelectBase): 
    2313                    right_selectable = coercions.expect( 
    2314                        roles.FromClauseRole, right_selectable 
    2315                    ) 
    2316                    need_adapter = True 
    2317 
    2318                # make the right hand side target into an ORM entity 
    2319                right = AliasedClass(right_mapper, right_selectable) 
    2320 
    2321                util.warn_deprecated( 
    2322                    "An alias is being generated automatically against " 
    2323                    "joined entity %s for raw clauseelement, which is " 
    2324                    "deprecated and will be removed in a later release. " 
    2325                    "Use the aliased() " 
    2326                    "construct explicitly, see the linked example." 
    2327                    % right_mapper, 
    2328                    "1.4", 
    2329                    code="xaj1", 
    2330                ) 
    2331 
    2332        # test for overlap: 
    2333        # orm/inheritance/relationships.py 
    2334        # SelfReferentialM2MTest 
    2335        aliased_entity = right_mapper and not right_is_aliased and overlap 
    2336 
    2337        if not need_adapter and aliased_entity: 
    2338            # there are a few places in the ORM that automatic aliasing 
    2339            # is still desirable, and can't be automatic with a Core 
    2340            # only approach.  For illustrations of "overlaps" see 
    2341            # test/orm/inheritance/test_relationships.py.  There are also 
    2342            # general overlap cases with many-to-many tables where automatic 
    2343            # aliasing is desirable. 
    2344            right = AliasedClass(right, flat=True) 
    2345            need_adapter = True 
    2346 
    2347            util.warn( 
    2348                "An alias is being generated automatically against " 
    2349                "joined entity %s due to overlapping tables.  This is a " 
    2350                "legacy pattern which may be " 
    2351                "deprecated in a later release.  Use the " 
    2352                "aliased(<entity>, flat=True) " 
    2353                "construct explicitly, see the linked example." % right_mapper, 
    2354                code="xaj2", 
    2355            ) 
    2356 
    2357        if need_adapter: 
    2358            # if need_adapter is True, we are in a deprecated case and 
    2359            # a warning has been emitted. 
    2360            assert right_mapper 
    2361 
    2362            adapter = ORMAdapter( 
    2363                _TraceAdaptRole.DEPRECATED_JOIN_ADAPT_RIGHT_SIDE, 
    2364                inspect(right), 
    2365                equivalents=right_mapper._equivalent_columns, 
    2366            ) 
    2367 
    2368            # if an alias() on the right side was generated, 
    2369            # which is intended to wrap a the right side in a subquery, 
    2370            # ensure that columns retrieved from this target in the result 
    2371            # set are also adapted. 
    2372            self._mapper_loads_polymorphically_with(right_mapper, adapter) 
    2373        elif ( 
    2374            not r_info.is_clause_element 
    2375            and not right_is_aliased 
    2376            and right_mapper._has_aliased_polymorphic_fromclause 
    2377        ): 
    2378            # for the case where the target mapper has a with_polymorphic 
    2379            # set up, ensure an adapter is set up for criteria that works 
    2380            # against this mapper.  Previously, this logic used to 
    2381            # use the "create_aliases or aliased_entity" case to generate 
    2382            # an aliased() object, but this creates an alias that isn't 
    2383            # strictly necessary. 
    2384            # see test/orm/test_core_compilation.py 
    2385            # ::RelNaturalAliasedJoinsTest::test_straight 
    2386            # and similar 
    2387            self._mapper_loads_polymorphically_with( 
    2388                right_mapper, 
    2389                ORMAdapter( 
    2390                    _TraceAdaptRole.WITH_POLYMORPHIC_ADAPTER_RIGHT_JOIN, 
    2391                    right_mapper, 
    2392                    selectable=right_mapper.selectable, 
    2393                    equivalents=right_mapper._equivalent_columns, 
    2394                ), 
    2395            ) 
    2396        # if the onclause is a ClauseElement, adapt it with any 
    2397        # adapters that are in place right now 
    2398        if isinstance(onclause, expression.ClauseElement): 
    2399            current_adapter = self._get_current_adapter() 
    2400            if current_adapter: 
    2401                onclause = current_adapter(onclause, True) 
    2402 
    2403        # if joining on a MapperProperty path, 
    2404        # track the path to prevent redundant joins 
    2405        if prop: 
    2406            self._already_joined_edges += ((left, right, prop.key),) 
    2407 
    2408        return inspect(right), right, onclause 
    2409 
    2410    @property 
    2411    def _select_args(self): 
    2412        return { 
    2413            "limit_clause": self.select_statement._limit_clause, 
    2414            "offset_clause": self.select_statement._offset_clause, 
    2415            "distinct": self.distinct, 
    2416            "distinct_on": self.distinct_on, 
    2417            "prefixes": self.select_statement._prefixes, 
    2418            "suffixes": self.select_statement._suffixes, 
    2419            "group_by": self.group_by or None, 
    2420            "fetch_clause": self.select_statement._fetch_clause, 
    2421            "fetch_clause_options": ( 
    2422                self.select_statement._fetch_clause_options 
    2423            ), 
    2424            "independent_ctes": self.select_statement._independent_ctes, 
    2425            "independent_ctes_opts": ( 
    2426                self.select_statement._independent_ctes_opts 
    2427            ), 
    2428            "syntax_extensions": self.syntax_extensions, 
    2429        } 
    2430 
    2431    @property 
    2432    def _should_nest_selectable(self): 
    2433        kwargs = self._select_args 
    2434 
    2435        if not self.eager_adding_joins: 
    2436            return False 
    2437 
    2438        return ( 
    2439            ( 
    2440                kwargs.get("limit_clause") is not None 
    2441                and self.multi_row_eager_loaders 
    2442            ) 
    2443            or ( 
    2444                kwargs.get("offset_clause") is not None 
    2445                and self.multi_row_eager_loaders 
    2446            ) 
    2447            or kwargs.get("distinct", False) 
    2448            or kwargs.get("distinct_on", ()) 
    2449            or kwargs.get("group_by", False) 
    2450        ) 
    2451 
    2452    def _get_extra_criteria(self, ext_info): 
    2453        if ( 
    2454            "additional_entity_criteria", 
    2455            ext_info.mapper, 
    2456        ) in self.global_attributes: 
    2457            return tuple( 
    2458                ae._resolve_where_criteria(ext_info) 
    2459                for ae in self.global_attributes[ 
    2460                    ("additional_entity_criteria", ext_info.mapper) 
    2461                ] 
    2462                if (ae.include_aliases or ae.entity is ext_info) 
    2463                and ae._should_include(self) 
    2464            ) 
    2465        else: 
    2466            return () 
    2467 
    2468    def _adjust_for_extra_criteria(self): 
    2469        """Apply extra criteria filtering. 
    2470 
    2471        For all distinct single-table-inheritance mappers represented in 
    2472        the columns clause of this query, as well as the "select from entity", 
    2473        add criterion to the WHERE 
    2474        clause of the given QueryContext such that only the appropriate 
    2475        subtypes are selected from the total results. 
    2476 
    2477        Additionally, add WHERE criteria originating from LoaderCriteriaOptions 
    2478        associated with the global context. 
    2479 
    2480        """ 
    2481 
    2482        for fromclause in self.from_clauses: 
    2483            ext_info = fromclause._annotations.get("parententity", None) 
    2484 
    2485            if ( 
    2486                ext_info 
    2487                and ( 
    2488                    ext_info.mapper._single_table_criterion is not None 
    2489                    or ("additional_entity_criteria", ext_info.mapper) 
    2490                    in self.global_attributes 
    2491                ) 
    2492                and ext_info not in self.extra_criteria_entities 
    2493            ): 
    2494                self.extra_criteria_entities[ext_info] = ( 
    2495                    ext_info, 
    2496                    ext_info._adapter if ext_info.is_aliased_class else None, 
    2497                ) 
    2498 
    2499        _where_criteria_to_add = () 
    2500 
    2501        merged_single_crit = collections.defaultdict( 
    2502            lambda: (util.OrderedSet(), set()) 
    2503        ) 
    2504 
    2505        for ext_info, adapter in util.OrderedSet( 
    2506            self.extra_criteria_entities.values() 
    2507        ): 
    2508            if ext_info in self._join_entities: 
    2509                continue 
    2510 
    2511            # assemble single table inheritance criteria. 
    2512            if ( 
    2513                ext_info.is_aliased_class 
    2514                and ext_info._base_alias()._is_with_polymorphic 
    2515            ): 
    2516                # for a with_polymorphic(), we always include the full 
    2517                # hierarchy from what's given as the base class for the wpoly. 
    2518                # this is new in 2.1 for #12395 so that it matches the behavior 
    2519                # of joined inheritance. 
    2520                hierarchy_root = ext_info._base_alias() 
    2521            else: 
    2522                hierarchy_root = ext_info 
    2523 
    2524            single_crit_component = ( 
    2525                hierarchy_root.mapper._single_table_criteria_component 
    2526            ) 
    2527 
    2528            if single_crit_component is not None: 
    2529                polymorphic_on, criteria = single_crit_component 
    2530 
    2531                polymorphic_on = polymorphic_on._annotate( 
    2532                    { 
    2533                        "parententity": hierarchy_root, 
    2534                        "parentmapper": hierarchy_root.mapper, 
    2535                    } 
    2536                ) 
    2537 
    2538                list_of_single_crits, adapters = merged_single_crit[ 
    2539                    (hierarchy_root, polymorphic_on) 
    2540                ] 
    2541                list_of_single_crits.update(criteria) 
    2542                if adapter: 
    2543                    adapters.add(adapter) 
    2544 
    2545            # assemble "additional entity criteria", which come from 
    2546            # with_loader_criteria() options 
    2547            if not self.compile_options._for_refresh_state: 
    2548                additional_entity_criteria = self._get_extra_criteria(ext_info) 
    2549                _where_criteria_to_add += tuple( 
    2550                    adapter.traverse(crit) if adapter else crit 
    2551                    for crit in additional_entity_criteria 
    2552                ) 
    2553 
    2554        # merge together single table inheritance criteria keyed to 
    2555        # top-level mapper / aliasedinsp (which may be a with_polymorphic()) 
    2556        for (ext_info, polymorphic_on), ( 
    2557            merged_crit, 
    2558            adapters, 
    2559        ) in merged_single_crit.items(): 
    2560            new_crit = polymorphic_on.in_(merged_crit) 
    2561            for adapter in adapters: 
    2562                new_crit = adapter.traverse(new_crit) 
    2563            _where_criteria_to_add += (new_crit,) 
    2564 
    2565        current_adapter = self._get_current_adapter() 
    2566        if current_adapter: 
    2567            # finally run all the criteria through the "main" adapter, if we 
    2568            # have one, and concatenate to final WHERE criteria 
    2569            for crit in _where_criteria_to_add: 
    2570                crit = current_adapter(crit, False) 
    2571                self._where_criteria += (crit,) 
    2572        else: 
    2573            # else just concatenate our criteria to the final WHERE criteria 
    2574            self._where_criteria += _where_criteria_to_add 
    2575 
    2576 
    2577def _column_descriptions( 
    2578    query_or_select_stmt: Union[Query, Select, FromStatement], 
    2579    compile_state: Optional[_ORMSelectCompileState] = None, 
    2580    legacy: bool = False, 
    2581) -> List[ORMColumnDescription]: 
    2582    if compile_state is None: 
    2583        compile_state = _ORMSelectCompileState._create_entities_collection( 
    2584            query_or_select_stmt, legacy=legacy 
    2585        ) 
    2586    ctx = compile_state 
    2587    d = [ 
    2588        { 
    2589            "name": ent._label_name, 
    2590            "type": ent.type, 
    2591            "aliased": getattr(insp_ent, "is_aliased_class", False), 
    2592            "expr": ent.expr, 
    2593            "entity": ( 
    2594                getattr(insp_ent, "entity", None) 
    2595                if ent.entity_zero is not None 
    2596                and not insp_ent.is_clause_element 
    2597                else None 
    2598            ), 
    2599        } 
    2600        for ent, insp_ent in [ 
    2601            (_ent, _ent.entity_zero) for _ent in ctx._entities 
    2602        ] 
    2603    ] 
    2604    return d 
    2605 
    2606 
    2607def _legacy_filter_by_entity_zero( 
    2608    query_or_augmented_select: Union[Query[Any], Select[Unpack[TupleAny]]], 
    2609) -> Optional[_InternalEntityType[Any]]: 
    2610    self = query_or_augmented_select 
    2611    if self._setup_joins: 
    2612        _last_joined_entity = self._last_joined_entity 
    2613        if _last_joined_entity is not None: 
    2614            return _last_joined_entity 
    2615 
    2616    if self._from_obj and "parententity" in self._from_obj[0]._annotations: 
    2617        return self._from_obj[0]._annotations["parententity"] 
    2618 
    2619    return _entity_from_pre_ent_zero(self) 
    2620 
    2621 
    2622def _entity_from_pre_ent_zero( 
    2623    query_or_augmented_select: Union[Query[Any], Select[Unpack[TupleAny]]], 
    2624) -> Optional[_InternalEntityType[Any]]: 
    2625    self = query_or_augmented_select 
    2626    if not self._raw_columns: 
    2627        return None 
    2628 
    2629    ent = self._raw_columns[0] 
    2630 
    2631    if "parententity" in ent._annotations: 
    2632        return ent._annotations["parententity"] 
    2633    elif isinstance(ent, ORMColumnsClauseRole): 
    2634        return ent.entity 
    2635    elif "bundle" in ent._annotations: 
    2636        return ent._annotations["bundle"] 
    2637    else: 
    2638        return ent 
    2639 
    2640 
    2641def _determine_last_joined_entity( 
    2642    setup_joins: Tuple[_SetupJoinsElement, ...], 
    2643    entity_zero: Optional[_InternalEntityType[Any]] = None, 
    2644) -> Optional[Union[_InternalEntityType[Any], _JoinTargetElement]]: 
    2645    if not setup_joins: 
    2646        return None 
    2647 
    2648    (target, onclause, from_, flags) = setup_joins[-1] 
    2649 
    2650    if isinstance( 
    2651        target, 
    2652        attributes.QueryableAttribute, 
    2653    ): 
    2654        return target.entity 
    2655    else: 
    2656        return target 
    2657 
    2658 
    2659class _QueryEntity: 
    2660    """represent an entity column returned within a Query result.""" 
    2661 
    2662    __slots__ = () 
    2663 
    2664    supports_single_entity: bool 
    2665 
    2666    _non_hashable_value = False 
    2667    _null_column_type = False 
    2668    use_id_for_hash = False 
    2669 
    2670    _label_name: Optional[str] 
    2671    type: Union[Type[Any], TypeEngine[Any]] 
    2672    expr: Union[_InternalEntityType, ColumnElement[Any]] 
    2673    entity_zero: Optional[_InternalEntityType] 
    2674 
    2675    def setup_compile_state(self, compile_state: _ORMCompileState) -> None: 
    2676        raise NotImplementedError() 
    2677 
    2678    def setup_dml_returning_compile_state( 
    2679        self, 
    2680        compile_state: _ORMCompileState, 
    2681        adapter: Optional[_DMLReturningColFilter], 
    2682    ) -> None: 
    2683        raise NotImplementedError() 
    2684 
    2685    def row_processor(self, context, result): 
    2686        raise NotImplementedError() 
    2687 
    2688    @classmethod 
    2689    def to_compile_state( 
    2690        cls, compile_state, entities, entities_collection, is_current_entities 
    2691    ): 
    2692        for idx, entity in enumerate(entities): 
    2693            if entity._is_lambda_element: 
    2694                if entity._is_sequence: 
    2695                    cls.to_compile_state( 
    2696                        compile_state, 
    2697                        entity._resolved, 
    2698                        entities_collection, 
    2699                        is_current_entities, 
    2700                    ) 
    2701                    continue 
    2702                else: 
    2703                    entity = entity._resolved 
    2704 
    2705            if entity.is_clause_element: 
    2706                if entity.is_selectable: 
    2707                    if "parententity" in entity._annotations: 
    2708                        _MapperEntity( 
    2709                            compile_state, 
    2710                            entity, 
    2711                            entities_collection, 
    2712                            is_current_entities, 
    2713                        ) 
    2714                    else: 
    2715                        _ColumnEntity._for_columns( 
    2716                            compile_state, 
    2717                            entity._select_iterable, 
    2718                            entities_collection, 
    2719                            idx, 
    2720                            is_current_entities, 
    2721                        ) 
    2722                else: 
    2723                    if entity._annotations.get("bundle", False): 
    2724                        _BundleEntity( 
    2725                            compile_state, 
    2726                            entity, 
    2727                            entities_collection, 
    2728                            is_current_entities, 
    2729                        ) 
    2730                    elif entity._is_clause_list: 
    2731                        # this is legacy only - test_composites.py 
    2732                        # test_query_cols_legacy 
    2733                        _ColumnEntity._for_columns( 
    2734                            compile_state, 
    2735                            entity._select_iterable, 
    2736                            entities_collection, 
    2737                            idx, 
    2738                            is_current_entities, 
    2739                        ) 
    2740                    else: 
    2741                        _ColumnEntity._for_columns( 
    2742                            compile_state, 
    2743                            [entity], 
    2744                            entities_collection, 
    2745                            idx, 
    2746                            is_current_entities, 
    2747                        ) 
    2748            elif entity.is_bundle: 
    2749                _BundleEntity(compile_state, entity, entities_collection) 
    2750 
    2751        return entities_collection 
    2752 
    2753 
    2754class _MapperEntity(_QueryEntity): 
    2755    """mapper/class/AliasedClass entity""" 
    2756 
    2757    __slots__ = ( 
    2758        "expr", 
    2759        "mapper", 
    2760        "entity_zero", 
    2761        "is_aliased_class", 
    2762        "path", 
    2763        "_extra_entities", 
    2764        "_label_name", 
    2765        "_with_polymorphic_mappers", 
    2766        "selectable", 
    2767        "_polymorphic_discriminator", 
    2768    ) 
    2769 
    2770    expr: _InternalEntityType 
    2771    mapper: Mapper[Any] 
    2772    entity_zero: _InternalEntityType 
    2773    is_aliased_class: bool 
    2774    path: PathRegistry 
    2775    _label_name: str 
    2776 
    2777    def __init__( 
    2778        self, compile_state, entity, entities_collection, is_current_entities 
    2779    ): 
    2780        entities_collection.append(self) 
    2781        if is_current_entities: 
    2782            if compile_state._primary_entity is None: 
    2783                compile_state._primary_entity = self 
    2784            compile_state._has_mapper_entities = True 
    2785            compile_state._has_orm_entities = True 
    2786 
    2787        entity = entity._annotations["parententity"] 
    2788        entity._post_inspect 
    2789        ext_info = self.entity_zero = entity 
    2790        entity = ext_info.entity 
    2791 
    2792        self.expr = entity 
    2793        self.mapper = mapper = ext_info.mapper 
    2794 
    2795        self._extra_entities = (self.expr,) 
    2796 
    2797        if ext_info.is_aliased_class: 
    2798            self._label_name = ext_info.name 
    2799        else: 
    2800            self._label_name = mapper.class_.__name__ 
    2801 
    2802        self.is_aliased_class = ext_info.is_aliased_class 
    2803        self.path = ext_info._path_registry 
    2804 
    2805        self.selectable = ext_info.selectable 
    2806        self._with_polymorphic_mappers = ext_info.with_polymorphic_mappers 
    2807        self._polymorphic_discriminator = ext_info.polymorphic_on 
    2808 
    2809        if mapper._should_select_with_poly_adapter: 
    2810            compile_state._create_with_polymorphic_adapter( 
    2811                ext_info, self.selectable 
    2812            ) 
    2813 
    2814    supports_single_entity = True 
    2815 
    2816    _non_hashable_value = True 
    2817    use_id_for_hash = True 
    2818 
    2819    @property 
    2820    def type(self): 
    2821        return self.mapper.class_ 
    2822 
    2823    @property 
    2824    def entity_zero_or_selectable(self): 
    2825        return self.entity_zero 
    2826 
    2827    def corresponds_to(self, entity): 
    2828        return _entity_corresponds_to(self.entity_zero, entity) 
    2829 
    2830    def _get_entity_clauses(self, compile_state): 
    2831        adapter = None 
    2832 
    2833        if not self.is_aliased_class: 
    2834            if compile_state._polymorphic_adapters: 
    2835                adapter = compile_state._polymorphic_adapters.get( 
    2836                    self.mapper, None 
    2837                ) 
    2838        else: 
    2839            adapter = self.entity_zero._adapter 
    2840 
    2841        if adapter: 
    2842            if compile_state._from_obj_alias: 
    2843                ret = adapter.wrap(compile_state._from_obj_alias) 
    2844            else: 
    2845                ret = adapter 
    2846        else: 
    2847            ret = compile_state._from_obj_alias 
    2848 
    2849        return ret 
    2850 
    2851    def row_processor(self, context, result): 
    2852        compile_state = context.compile_state 
    2853        adapter = self._get_entity_clauses(compile_state) 
    2854 
    2855        if compile_state.compound_eager_adapter and adapter: 
    2856            adapter = adapter.wrap(compile_state.compound_eager_adapter) 
    2857        elif not adapter: 
    2858            adapter = compile_state.compound_eager_adapter 
    2859 
    2860        if compile_state._primary_entity is self: 
    2861            only_load_props = compile_state.compile_options._only_load_props 
    2862            refresh_state = context.refresh_state 
    2863        else: 
    2864            only_load_props = refresh_state = None 
    2865 
    2866        _instance = loading._instance_processor( 
    2867            self, 
    2868            self.mapper, 
    2869            context, 
    2870            result, 
    2871            self.path, 
    2872            adapter, 
    2873            only_load_props=only_load_props, 
    2874            refresh_state=refresh_state, 
    2875            polymorphic_discriminator=self._polymorphic_discriminator, 
    2876        ) 
    2877 
    2878        return _instance, self._label_name, self._extra_entities 
    2879 
    2880    def setup_dml_returning_compile_state( 
    2881        self, 
    2882        compile_state: _ORMCompileState, 
    2883        adapter: Optional[_DMLReturningColFilter], 
    2884    ) -> None: 
    2885        loading._setup_entity_query( 
    2886            compile_state, 
    2887            self.mapper, 
    2888            self, 
    2889            self.path, 
    2890            adapter, 
    2891            compile_state.primary_columns, 
    2892            with_polymorphic=self._with_polymorphic_mappers, 
    2893            only_load_props=compile_state.compile_options._only_load_props, 
    2894            polymorphic_discriminator=self._polymorphic_discriminator, 
    2895        ) 
    2896 
    2897    def setup_compile_state(self, compile_state): 
    2898        adapter = self._get_entity_clauses(compile_state) 
    2899 
    2900        single_table_crit = self.mapper._single_table_criterion 
    2901        if ( 
    2902            single_table_crit is not None 
    2903            or ("additional_entity_criteria", self.mapper) 
    2904            in compile_state.global_attributes 
    2905        ): 
    2906            ext_info = self.entity_zero 
    2907            compile_state.extra_criteria_entities[ext_info] = ( 
    2908                ext_info, 
    2909                ext_info._adapter if ext_info.is_aliased_class else None, 
    2910            ) 
    2911 
    2912        loading._setup_entity_query( 
    2913            compile_state, 
    2914            self.mapper, 
    2915            self, 
    2916            self.path, 
    2917            adapter, 
    2918            compile_state.primary_columns, 
    2919            with_polymorphic=self._with_polymorphic_mappers, 
    2920            only_load_props=compile_state.compile_options._only_load_props, 
    2921            polymorphic_discriminator=self._polymorphic_discriminator, 
    2922        ) 
    2923        compile_state._fallback_from_clauses.append(self.selectable) 
    2924 
    2925 
    2926class _BundleEntity(_QueryEntity): 
    2927    _extra_entities = () 
    2928 
    2929    __slots__ = ( 
    2930        "bundle", 
    2931        "expr", 
    2932        "type", 
    2933        "_label_name", 
    2934        "_entities", 
    2935        "supports_single_entity", 
    2936    ) 
    2937 
    2938    _entities: List[_QueryEntity] 
    2939    bundle: Bundle 
    2940    type: Type[Any] 
    2941    _label_name: str 
    2942    supports_single_entity: bool 
    2943    expr: Bundle 
    2944 
    2945    def __init__( 
    2946        self, 
    2947        compile_state, 
    2948        expr, 
    2949        entities_collection, 
    2950        is_current_entities, 
    2951        setup_entities=True, 
    2952        parent_bundle=None, 
    2953    ): 
    2954        compile_state._has_orm_entities = True 
    2955 
    2956        expr = expr._annotations["bundle"] 
    2957        if parent_bundle: 
    2958            parent_bundle._entities.append(self) 
    2959        else: 
    2960            entities_collection.append(self) 
    2961 
    2962        if isinstance( 
    2963            expr, (attributes.QueryableAttribute, interfaces.PropComparator) 
    2964        ): 
    2965            bundle = expr.__clause_element__() 
    2966        else: 
    2967            bundle = expr 
    2968 
    2969        self.bundle = self.expr = bundle 
    2970        self.type = type(bundle) 
    2971        self._label_name = bundle.name 
    2972        self._entities = [] 
    2973 
    2974        if setup_entities: 
    2975            for expr in bundle.exprs: 
    2976                if "bundle" in expr._annotations: 
    2977                    _BundleEntity( 
    2978                        compile_state, 
    2979                        expr, 
    2980                        entities_collection, 
    2981                        is_current_entities, 
    2982                        parent_bundle=self, 
    2983                    ) 
    2984                elif isinstance(expr, Bundle): 
    2985                    _BundleEntity( 
    2986                        compile_state, 
    2987                        expr, 
    2988                        entities_collection, 
    2989                        is_current_entities, 
    2990                        parent_bundle=self, 
    2991                    ) 
    2992                else: 
    2993                    _ORMColumnEntity._for_columns( 
    2994                        compile_state, 
    2995                        [expr], 
    2996                        entities_collection, 
    2997                        None, 
    2998                        is_current_entities, 
    2999                        parent_bundle=self, 
    3000                    ) 
    3001 
    3002        self.supports_single_entity = self.bundle.single_entity 
    3003 
    3004    @property 
    3005    def mapper(self): 
    3006        ezero = self.entity_zero 
    3007        if ezero is not None: 
    3008            return ezero.mapper 
    3009        else: 
    3010            return None 
    3011 
    3012    @property 
    3013    def entity_zero(self): 
    3014        for ent in self._entities: 
    3015            ezero = ent.entity_zero 
    3016            if ezero is not None: 
    3017                return ezero 
    3018        else: 
    3019            return None 
    3020 
    3021    def corresponds_to(self, entity): 
    3022        # TODO: we might be able to implement this but for now 
    3023        # we are working around it 
    3024        return False 
    3025 
    3026    @property 
    3027    def entity_zero_or_selectable(self): 
    3028        for ent in self._entities: 
    3029            ezero = ent.entity_zero_or_selectable 
    3030            if ezero is not None: 
    3031                return ezero 
    3032        else: 
    3033            return None 
    3034 
    3035    def setup_compile_state(self, compile_state): 
    3036        for ent in self._entities: 
    3037            ent.setup_compile_state(compile_state) 
    3038 
    3039    def setup_dml_returning_compile_state( 
    3040        self, 
    3041        compile_state: _ORMCompileState, 
    3042        adapter: Optional[_DMLReturningColFilter], 
    3043    ) -> None: 
    3044        return self.setup_compile_state(compile_state) 
    3045 
    3046    def row_processor(self, context, result): 
    3047        procs, labels, extra = zip( 
    3048            *[ent.row_processor(context, result) for ent in self._entities] 
    3049        ) 
    3050 
    3051        proc = self.bundle.create_row_processor(context.query, procs, labels) 
    3052 
    3053        return proc, self._label_name, self._extra_entities 
    3054 
    3055 
    3056class _ColumnEntity(_QueryEntity): 
    3057    __slots__ = ( 
    3058        "_fetch_column", 
    3059        "_row_processor", 
    3060        "raw_column_index", 
    3061        "translate_raw_column", 
    3062    ) 
    3063 
    3064    @classmethod 
    3065    def _for_columns( 
    3066        cls, 
    3067        compile_state, 
    3068        columns, 
    3069        entities_collection, 
    3070        raw_column_index, 
    3071        is_current_entities, 
    3072        parent_bundle=None, 
    3073    ): 
    3074        for column in columns: 
    3075            annotations = column._annotations 
    3076            if "parententity" in annotations: 
    3077                _entity = annotations["parententity"] 
    3078            else: 
    3079                _entity = sql_util.extract_first_column_annotation( 
    3080                    column, "parententity" 
    3081                ) 
    3082 
    3083            if _entity: 
    3084                if "identity_token" in column._annotations: 
    3085                    _IdentityTokenEntity( 
    3086                        compile_state, 
    3087                        column, 
    3088                        entities_collection, 
    3089                        _entity, 
    3090                        raw_column_index, 
    3091                        is_current_entities, 
    3092                        parent_bundle=parent_bundle, 
    3093                    ) 
    3094                else: 
    3095                    _ORMColumnEntity( 
    3096                        compile_state, 
    3097                        column, 
    3098                        entities_collection, 
    3099                        _entity, 
    3100                        raw_column_index, 
    3101                        is_current_entities, 
    3102                        parent_bundle=parent_bundle, 
    3103                    ) 
    3104            else: 
    3105                _RawColumnEntity( 
    3106                    compile_state, 
    3107                    column, 
    3108                    entities_collection, 
    3109                    raw_column_index, 
    3110                    is_current_entities, 
    3111                    parent_bundle=parent_bundle, 
    3112                ) 
    3113 
    3114    @property 
    3115    def type(self): 
    3116        return self.column.type 
    3117 
    3118    @property 
    3119    def _non_hashable_value(self): 
    3120        return not self.column.type.hashable 
    3121 
    3122    @property 
    3123    def _null_column_type(self): 
    3124        return self.column.type._isnull 
    3125 
    3126    def row_processor(self, context, result): 
    3127        compile_state = context.compile_state 
    3128 
    3129        # the resulting callable is entirely cacheable so just return 
    3130        # it if we already made one 
    3131        if self._row_processor is not None: 
    3132            getter, label_name, extra_entities = self._row_processor 
    3133            if self.translate_raw_column: 
    3134                extra_entities += ( 
    3135                    context.query._raw_columns[self.raw_column_index], 
    3136                ) 
    3137 
    3138            return getter, label_name, extra_entities 
    3139 
    3140        # retrieve the column that would have been set up in 
    3141        # setup_compile_state, to avoid doing redundant work 
    3142        if self._fetch_column is not None: 
    3143            column = self._fetch_column 
    3144        else: 
    3145            # fetch_column will be None when we are doing a from_statement 
    3146            # and setup_compile_state may not have been called. 
    3147            column = self.column 
    3148 
    3149            # previously, the RawColumnEntity didn't look for from_obj_alias 
    3150            # however I can't think of a case where we would be here and 
    3151            # we'd want to ignore it if this is the from_statement use case. 
    3152            # it's not really a use case to have raw columns + from_statement 
    3153            if compile_state._from_obj_alias: 
    3154                column = compile_state._from_obj_alias.columns[column] 
    3155 
    3156            if column._annotations: 
    3157                # annotated columns perform more slowly in compiler and 
    3158                # result due to the __eq__() method, so use deannotated 
    3159                column = column._deannotate() 
    3160 
    3161        if compile_state.compound_eager_adapter: 
    3162            column = compile_state.compound_eager_adapter.columns[column] 
    3163 
    3164        getter = result._getter(column) 
    3165        ret = getter, self._label_name, self._extra_entities 
    3166        self._row_processor = ret 
    3167 
    3168        if self.translate_raw_column: 
    3169            extra_entities = self._extra_entities + ( 
    3170                context.query._raw_columns[self.raw_column_index], 
    3171            ) 
    3172            return getter, self._label_name, extra_entities 
    3173        else: 
    3174            return ret 
    3175 
    3176 
    3177class _RawColumnEntity(_ColumnEntity): 
    3178    entity_zero = None 
    3179    mapper = None 
    3180    supports_single_entity = False 
    3181 
    3182    __slots__ = ( 
    3183        "expr", 
    3184        "column", 
    3185        "_label_name", 
    3186        "entity_zero_or_selectable", 
    3187        "_extra_entities", 
    3188    ) 
    3189 
    3190    def __init__( 
    3191        self, 
    3192        compile_state, 
    3193        column, 
    3194        entities_collection, 
    3195        raw_column_index, 
    3196        is_current_entities, 
    3197        parent_bundle=None, 
    3198    ): 
    3199        self.expr = column 
    3200        self.raw_column_index = raw_column_index 
    3201        self.translate_raw_column = raw_column_index is not None 
    3202 
    3203        if column._is_star: 
    3204            compile_state.compile_options += {"_is_star": True} 
    3205 
    3206        if not is_current_entities or column._is_text_clause: 
    3207            self._label_name = None 
    3208        else: 
    3209            if parent_bundle: 
    3210                self._label_name = column._proxy_key 
    3211            else: 
    3212                self._label_name = compile_state._label_convention(column) 
    3213 
    3214        if parent_bundle: 
    3215            parent_bundle._entities.append(self) 
    3216        else: 
    3217            entities_collection.append(self) 
    3218 
    3219        self.column = column 
    3220        self.entity_zero_or_selectable = ( 
    3221            self.column._from_objects[0] if self.column._from_objects else None 
    3222        ) 
    3223        self._extra_entities = (self.expr, self.column) 
    3224        self._fetch_column = self._row_processor = None 
    3225 
    3226    def corresponds_to(self, entity): 
    3227        return False 
    3228 
    3229    def setup_dml_returning_compile_state( 
    3230        self, 
    3231        compile_state: _ORMCompileState, 
    3232        adapter: Optional[_DMLReturningColFilter], 
    3233    ) -> None: 
    3234        return self.setup_compile_state(compile_state) 
    3235 
    3236    def setup_compile_state(self, compile_state): 
    3237        current_adapter = compile_state._get_current_adapter() 
    3238        if current_adapter: 
    3239            column = current_adapter(self.column, False) 
    3240            if column is None: 
    3241                return 
    3242        else: 
    3243            column = self.column 
    3244 
    3245        if column._annotations: 
    3246            # annotated columns perform more slowly in compiler and 
    3247            # result due to the __eq__() method, so use deannotated 
    3248            column = column._deannotate() 
    3249 
    3250        compile_state.dedupe_columns.add(column) 
    3251        compile_state.primary_columns.append(column) 
    3252        self._fetch_column = column 
    3253 
    3254 
    3255class _ORMColumnEntity(_ColumnEntity): 
    3256    """Column/expression based entity.""" 
    3257 
    3258    supports_single_entity = False 
    3259 
    3260    __slots__ = ( 
    3261        "expr", 
    3262        "mapper", 
    3263        "column", 
    3264        "_label_name", 
    3265        "entity_zero_or_selectable", 
    3266        "entity_zero", 
    3267        "_extra_entities", 
    3268    ) 
    3269 
    3270    def __init__( 
    3271        self, 
    3272        compile_state, 
    3273        column, 
    3274        entities_collection, 
    3275        parententity, 
    3276        raw_column_index, 
    3277        is_current_entities, 
    3278        parent_bundle=None, 
    3279    ): 
    3280        annotations = column._annotations 
    3281 
    3282        _entity = parententity 
    3283 
    3284        # an AliasedClass won't have proxy_key in the annotations for 
    3285        # a column if it was acquired using the class' adapter directly, 
    3286        # such as using AliasedInsp._adapt_element().  this occurs 
    3287        # within internal loaders. 
    3288 
    3289        orm_key = annotations.get("proxy_key", None) 
    3290        proxy_owner = annotations.get("proxy_owner", _entity) 
    3291        if orm_key: 
    3292            self.expr = getattr(proxy_owner.entity, orm_key) 
    3293            self.translate_raw_column = False 
    3294        else: 
    3295            # if orm_key is not present, that means this is an ad-hoc 
    3296            # SQL ColumnElement, like a CASE() or other expression. 
    3297            # include this column position from the invoked statement 
    3298            # in the ORM-level ResultSetMetaData on each execute, so that 
    3299            # it can be targeted by identity after caching 
    3300            self.expr = column 
    3301            self.translate_raw_column = raw_column_index is not None 
    3302 
    3303        self.raw_column_index = raw_column_index 
    3304 
    3305        if is_current_entities: 
    3306            if parent_bundle: 
    3307                self._label_name = orm_key if orm_key else column._proxy_key 
    3308            else: 
    3309                self._label_name = compile_state._label_convention( 
    3310                    column, col_name=orm_key 
    3311                ) 
    3312        else: 
    3313            self._label_name = None 
    3314 
    3315        _entity._post_inspect 
    3316        self.entity_zero = self.entity_zero_or_selectable = ezero = _entity 
    3317        self.mapper = mapper = _entity.mapper 
    3318 
    3319        if parent_bundle: 
    3320            parent_bundle._entities.append(self) 
    3321        else: 
    3322            entities_collection.append(self) 
    3323 
    3324        compile_state._has_orm_entities = True 
    3325 
    3326        self.column = column 
    3327 
    3328        self._fetch_column = self._row_processor = None 
    3329 
    3330        self._extra_entities = (self.expr, self.column) 
    3331 
    3332        if mapper._should_select_with_poly_adapter: 
    3333            compile_state._create_with_polymorphic_adapter( 
    3334                ezero, ezero.selectable 
    3335            ) 
    3336 
    3337    def corresponds_to(self, entity): 
    3338        if _is_aliased_class(entity): 
    3339            # TODO: polymorphic subclasses ? 
    3340            return entity is self.entity_zero 
    3341        else: 
    3342            return not _is_aliased_class( 
    3343                self.entity_zero 
    3344            ) and entity.common_parent(self.entity_zero) 
    3345 
    3346    def setup_dml_returning_compile_state( 
    3347        self, 
    3348        compile_state: _ORMCompileState, 
    3349        adapter: Optional[_DMLReturningColFilter], 
    3350    ) -> None: 
    3351 
    3352        self._fetch_column = column = self.column 
    3353        if adapter: 
    3354            column = adapter(column, False) 
    3355 
    3356        if column is not None: 
    3357            compile_state.dedupe_columns.add(column) 
    3358            compile_state.primary_columns.append(column) 
    3359 
    3360    def setup_compile_state(self, compile_state): 
    3361        current_adapter = compile_state._get_current_adapter() 
    3362        if current_adapter: 
    3363            column = current_adapter(self.column, False) 
    3364            if column is None: 
    3365                assert compile_state.is_dml_returning 
    3366                self._fetch_column = self.column 
    3367                return 
    3368        else: 
    3369            column = self.column 
    3370 
    3371        ezero = self.entity_zero 
    3372 
    3373        single_table_crit = self.mapper._single_table_criterion 
    3374        if ( 
    3375            single_table_crit is not None 
    3376            or ("additional_entity_criteria", self.mapper) 
    3377            in compile_state.global_attributes 
    3378        ): 
    3379            compile_state.extra_criteria_entities[ezero] = ( 
    3380                ezero, 
    3381                ezero._adapter if ezero.is_aliased_class else None, 
    3382            ) 
    3383 
    3384        if column._annotations and not column._expression_label: 
    3385            # annotated columns perform more slowly in compiler and 
    3386            # result due to the __eq__() method, so use deannotated 
    3387            column = column._deannotate() 
    3388 
    3389        # use entity_zero as the from if we have it. this is necessary 
    3390        # for polymorphic scenarios where our FROM is based on ORM entity, 
    3391        # not the FROM of the column.  but also, don't use it if our column 
    3392        # doesn't actually have any FROMs that line up, such as when its 
    3393        # a scalar subquery. 
    3394        if set(self.column._from_objects).intersection( 
    3395            ezero.selectable._from_objects 
    3396        ): 
    3397            compile_state._fallback_from_clauses.append(ezero.selectable) 
    3398 
    3399        compile_state.dedupe_columns.add(column) 
    3400        compile_state.primary_columns.append(column) 
    3401        self._fetch_column = column 
    3402 
    3403 
    3404class _IdentityTokenEntity(_ORMColumnEntity): 
    3405    translate_raw_column = False 
    3406 
    3407    def setup_compile_state(self, compile_state): 
    3408        pass 
    3409 
    3410    def row_processor(self, context, result): 
    3411        def getter(row): 
    3412            return context.load_options._identity_token 
    3413 
    3414        return getter, self._label_name, self._extra_entities