Plain is headed towards 1.0! Subscribe for development updates →

   1"""
   2Create SQL statements for QuerySets.
   3
   4The code in here encapsulates all of the SQL construction so that QuerySets
   5themselves do not have to (and could be backed by things other than SQL
   6databases). The abstraction barrier only works one way: this module has to know
   7all about the internals of models in order to get the information it needs.
   8"""
   9
  10from __future__ import annotations
  11
  12import copy
  13import difflib
  14import functools
  15import sys
  16from collections import Counter, namedtuple
  17from collections.abc import Iterable, Iterator, Mapping
  18from collections.abc import Iterator as TypingIterator
  19from functools import cached_property
  20from itertools import chain, count, product
  21from string import ascii_uppercase
  22from typing import TYPE_CHECKING, Any, Literal, TypeVar, overload
  23
  24if TYPE_CHECKING:
  25    from typing import Self
  26
  27from plain.models.aggregates import Count
  28from plain.models.constants import LOOKUP_SEP
  29from plain.models.db import NotSupportedError, db_connection
  30from plain.models.exceptions import FieldDoesNotExist, FieldError
  31from plain.models.expressions import (
  32    BaseExpression,
  33    Col,
  34    Exists,
  35    F,
  36    OuterRef,
  37    Ref,
  38    ResolvedOuterRef,
  39    Value,
  40)
  41from plain.models.fields import Field
  42from plain.models.fields.related_lookups import MultiColSource
  43from plain.models.lookups import Lookup
  44from plain.models.query_utils import (
  45    PathInfo,
  46    Q,
  47    check_rel_lookup_compatibility,
  48    refs_expression,
  49)
  50from plain.models.sql.constants import INNER, LOUTER, ORDER_DIR, SINGLE
  51from plain.models.sql.datastructures import BaseTable, Empty, Join, MultiJoin
  52from plain.models.sql.where import AND, OR, ExtraWhere, NothingNode, WhereNode
  53from plain.utils.regex_helper import _lazy_re_compile
  54from plain.utils.tree import Node
  55
  56if TYPE_CHECKING:
  57    from plain.models import Model
  58    from plain.models.backends.base.base import BaseDatabaseWrapper
  59    from plain.models.meta import Meta
  60    from plain.models.sql.compiler import SQLCompiler
  61
  62
  63__all__ = ["Query", "RawQuery"]
  64
  65# Quotation marks ('"`[]), whitespace characters, semicolons, or inline
  66# SQL comments are forbidden in column aliases.
  67FORBIDDEN_ALIAS_PATTERN = _lazy_re_compile(r"['`\"\]\[;\s]|--|/\*|\*/")
  68
  69# Inspired from
  70# https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
  71EXPLAIN_OPTIONS_PATTERN = _lazy_re_compile(r"[\w\-]+")
  72
  73
  74def get_field_names_from_opts(meta: Meta | None) -> set[str]:
  75    if meta is None:
  76        return set()
  77    return set(
  78        chain.from_iterable(
  79            (f.name, f.attname) if f.concrete else (f.name,) for f in meta.get_fields()
  80        )
  81    )
  82
  83
  84def get_children_from_q(q: Q) -> TypingIterator[tuple[str, Any]]:
  85    for child in q.children:
  86        if isinstance(child, Node):
  87            yield from get_children_from_q(child)
  88        else:
  89            yield child
  90
  91
  92JoinInfo = namedtuple(
  93    "JoinInfo",
  94    ("final_field", "targets", "meta", "joins", "path", "transform_function"),
  95)
  96
  97
  98class RawQuery:
  99    """A single raw SQL query."""
 100
 101    def __init__(self, sql: str, params: tuple[Any, ...] | dict[str, Any] = ()):
 102        self.params = params
 103        self.sql = sql
 104        self.cursor: Any = None
 105
 106        # Mirror some properties of a normal query so that
 107        # the compiler can be used to process results.
 108        self.low_mark, self.high_mark = 0, None  # Used for offset/limit
 109        self.extra_select = {}
 110        self.annotation_select = {}
 111
 112    def chain(self) -> RawQuery:
 113        return self.clone()
 114
 115    def clone(self) -> RawQuery:
 116        return RawQuery(self.sql, params=self.params)
 117
 118    def get_columns(self) -> list[str]:
 119        if self.cursor is None:
 120            self._execute_query()
 121        converter = db_connection.introspection.identifier_converter
 122        return [
 123            converter(column_model_meta[0])
 124            for column_model_meta in self.cursor.description
 125        ]
 126
 127    def __iter__(self) -> TypingIterator[Any]:
 128        # Always execute a new query for a new iterator.
 129        # This could be optimized with a cache at the expense of RAM.
 130        self._execute_query()
 131        if not db_connection.features.can_use_chunked_reads:
 132            # If the database can't use chunked reads we need to make sure we
 133            # evaluate the entire query up front.
 134            result = list(self.cursor)
 135        else:
 136            result = self.cursor
 137        return iter(result)
 138
 139    def __repr__(self) -> str:
 140        return f"<{self.__class__.__name__}: {self}>"
 141
 142    @property
 143    def params_type(self) -> type[dict] | type[tuple] | None:
 144        if self.params is None:
 145            return None
 146        return dict if isinstance(self.params, Mapping) else tuple
 147
 148    def __str__(self) -> str:
 149        if self.params_type is None:
 150            return self.sql
 151        return self.sql % self.params_type(self.params)
 152
 153    def _execute_query(self) -> None:
 154        # Adapt parameters to the database, as much as possible considering
 155        # that the target type isn't known. See #17755.
 156        params_type = self.params_type
 157        adapter = db_connection.ops.adapt_unknown_value
 158        if params_type is tuple:
 159            params = tuple(adapter(val) for val in self.params)
 160        elif params_type is dict:
 161            params = {key: adapter(val) for key, val in self.params.items()}  # type: ignore[union-attr]
 162        elif params_type is None:
 163            params = None
 164        else:
 165            raise RuntimeError(f"Unexpected params type: {params_type}")
 166
 167        self.cursor = db_connection.cursor()
 168        self.cursor.execute(self.sql, params)
 169
 170
 171ExplainInfo = namedtuple("ExplainInfo", ("format", "options"))
 172
 173QueryType = TypeVar("QueryType", bound="Query")
 174
 175
 176class Query(BaseExpression):
 177    """A single SQL query."""
 178
 179    alias_prefix = "T"
 180    empty_result_set_value = None
 181    subq_aliases = frozenset([alias_prefix])
 182
 183    compiler = "SQLCompiler"
 184
 185    base_table_class = BaseTable
 186    join_class = Join
 187
 188    default_cols = True
 189    default_ordering = True
 190    standard_ordering = True
 191
 192    filter_is_sticky = False
 193    subquery = False
 194
 195    # SQL-related attributes.
 196    # Select and related select clauses are expressions to use in the SELECT
 197    # clause of the query. The select is used for cases where we want to set up
 198    # the select clause to contain other than default fields (values(),
 199    # subqueries...). Note that annotations go to annotations dictionary.
 200    select = ()
 201    # The group_by attribute can have one of the following forms:
 202    #  - None: no group by at all in the query
 203    #  - A tuple of expressions: group by (at least) those expressions.
 204    #    String refs are also allowed for now.
 205    #  - True: group by all select fields of the model
 206    # See compiler.get_group_by() for details.
 207    group_by = None
 208    order_by = ()
 209    low_mark = 0  # Used for offset/limit.
 210    high_mark = None  # Used for offset/limit.
 211    distinct = False
 212    distinct_fields = ()
 213    select_for_update = False
 214    select_for_update_nowait = False
 215    select_for_update_skip_locked = False
 216    select_for_update_of = ()
 217    select_for_no_key_update = False
 218    select_related: bool | dict[str, Any] = False
 219    has_select_fields = False
 220    # Arbitrary limit for select_related to prevents infinite recursion.
 221    max_depth = 5
 222    # Holds the selects defined by a call to values() or values_list()
 223    # excluding annotation_select and extra_select.
 224    values_select = ()
 225
 226    # SQL annotation-related attributes.
 227    annotation_select_mask = None
 228    _annotation_select_cache = None
 229
 230    # Set combination attributes.
 231    combinator = None
 232    combinator_all = False
 233    combined_queries = ()
 234
 235    # These are for extensions. The contents are more or less appended verbatim
 236    # to the appropriate clause.
 237    extra_select_mask = None
 238    _extra_select_cache = None
 239
 240    extra_tables = ()
 241    extra_order_by = ()
 242
 243    # A tuple that is a set of model field names and either True, if these are
 244    # the fields to defer, or False if these are the only fields to load.
 245    deferred_loading = (frozenset(), True)
 246
 247    explain_info = None
 248
 249    def __init__(self, model: type[Model], alias_cols: bool = True):
 250        self.model = model
 251        self.alias_refcount = {}
 252        # alias_map is the most important data structure regarding joins.
 253        # It's used for recording which joins exist in the query and what
 254        # types they are. The key is the alias of the joined table (possibly
 255        # the table name) and the value is a Join-like object (see
 256        # sql.datastructures.Join for more information).
 257        self.alias_map = {}
 258        # Whether to provide alias to columns during reference resolving.
 259        self.alias_cols = alias_cols
 260        # Sometimes the query contains references to aliases in outer queries (as
 261        # a result of split_exclude). Correct alias quoting needs to know these
 262        # aliases too.
 263        # Map external tables to whether they are aliased.
 264        self.external_aliases = {}
 265        self.table_map = {}  # Maps table names to list of aliases.
 266        self.used_aliases = set()
 267
 268        self.where = WhereNode()
 269        # Maps alias -> Annotation Expression.
 270        self.annotations = {}
 271        # These are for extensions. The contents are more or less appended
 272        # verbatim to the appropriate clause.
 273        self.extra = {}  # Maps col_alias -> (col_sql, params).
 274
 275        self._filtered_relations = {}
 276
 277    @property
 278    def output_field(self) -> Field | None:  # type: ignore[return]
 279        if len(self.select) == 1:
 280            select = self.select[0]
 281            return getattr(select, "target", None) or select.field
 282        elif len(self.annotation_select) == 1:
 283            return next(iter(self.annotation_select.values())).output_field
 284
 285    @cached_property
 286    def base_table(self) -> str | None:
 287        for alias in self.alias_map:
 288            return alias
 289
 290    def __str__(self) -> str:
 291        """
 292        Return the query as a string of SQL with the parameter values
 293        substituted in (use sql_with_params() to see the unsubstituted string).
 294
 295        Parameter values won't necessarily be quoted correctly, since that is
 296        done by the database interface at execution time.
 297        """
 298        sql, params = self.sql_with_params()
 299        return sql % params
 300
 301    def sql_with_params(self) -> tuple[str, tuple[Any, ...]]:
 302        """
 303        Return the query as an SQL string and the parameters that will be
 304        substituted into the query.
 305        """
 306        return self.get_compiler().as_sql()
 307
 308    def __deepcopy__(self, memo: dict[int, Any]) -> Self:
 309        """Limit the amount of work when a Query is deepcopied."""
 310        result = self.clone()
 311        memo[id(self)] = result
 312        return result
 313
 314    def get_compiler(self, *, elide_empty: bool = True) -> Any:
 315        return db_connection.ops.compiler(self.compiler)(
 316            self, db_connection, elide_empty
 317        )
 318
 319    def get_model_meta(self) -> Meta:
 320        """
 321        Return the Meta instance (the model._model_meta) from which to start
 322        processing. Normally, this is self.model._model_meta, but it can be changed
 323        by subclasses.
 324        """
 325        return self.model._model_meta
 326
 327    def clone(self) -> Self:
 328        """
 329        Return a copy of the current Query. A lightweight alternative to
 330        deepcopy().
 331        """
 332        obj = Empty()  # type: ignore[misc]
 333        obj.__class__ = self.__class__  # type: ignore[misc]
 334        # Copy references to everything.
 335        obj.__dict__ = self.__dict__.copy()  # type: ignore[attr-defined]
 336        # Clone attributes that can't use shallow copy.
 337        obj.alias_refcount = self.alias_refcount.copy()  # type: ignore[attr-defined]
 338        obj.alias_map = self.alias_map.copy()  # type: ignore[attr-defined]
 339        obj.external_aliases = self.external_aliases.copy()  # type: ignore[attr-defined]
 340        obj.table_map = self.table_map.copy()  # type: ignore[attr-defined]
 341        obj.where = self.where.clone()  # type: ignore[attr-defined]
 342        obj.annotations = self.annotations.copy()  # type: ignore[attr-defined]
 343        if self.annotation_select_mask is not None:
 344            obj.annotation_select_mask = self.annotation_select_mask.copy()  # type: ignore[attr-defined]
 345        if self.combined_queries:
 346            obj.combined_queries = tuple(  # type: ignore[attr-defined]
 347                [query.clone() for query in self.combined_queries]
 348            )
 349        # _annotation_select_cache cannot be copied, as doing so breaks the
 350        # (necessary) state in which both annotations and
 351        # _annotation_select_cache point to the same underlying objects.
 352        # It will get re-populated in the cloned queryset the next time it's
 353        # used.
 354        obj._annotation_select_cache = None  # type: ignore[attr-defined]
 355        obj.extra = self.extra.copy()  # type: ignore[attr-defined]
 356        if self.extra_select_mask is not None:
 357            obj.extra_select_mask = self.extra_select_mask.copy()  # type: ignore[attr-defined]
 358        if self._extra_select_cache is not None:
 359            obj._extra_select_cache = self._extra_select_cache.copy()  # type: ignore[attr-defined]
 360        if self.select_related is not False:
 361            # Use deepcopy because select_related stores fields in nested
 362            # dicts.
 363            obj.select_related = copy.deepcopy(obj.select_related)  # type: ignore[attr-defined]
 364        if "subq_aliases" in self.__dict__:
 365            obj.subq_aliases = self.subq_aliases.copy()  # type: ignore[attr-defined]
 366        obj.used_aliases = self.used_aliases.copy()  # type: ignore[attr-defined]
 367        obj._filtered_relations = self._filtered_relations.copy()  # type: ignore[attr-defined]
 368        # Clear the cached_property, if it exists.
 369        obj.__dict__.pop("base_table", None)
 370        return obj  # type: ignore[return-value]
 371
 372    @overload
 373    def chain(self, klass: None = None) -> Self: ...
 374
 375    @overload
 376    def chain(self, klass: type[QueryType]) -> QueryType: ...
 377
 378    def chain(self, klass: type[Query] | None = None) -> Query:
 379        """
 380        Return a copy of the current Query that's ready for another operation.
 381        The klass argument changes the type of the Query, e.g. UpdateQuery.
 382        """
 383        obj = self.clone()
 384        if klass and obj.__class__ != klass:
 385            obj.__class__ = klass  # type: ignore[misc]
 386        if not obj.filter_is_sticky:
 387            obj.used_aliases = set()  # type: ignore[attr-defined]
 388        obj.filter_is_sticky = False
 389        if hasattr(obj, "_setup_query"):
 390            obj._setup_query()  # type: ignore[attr-defined]
 391        return obj  # type: ignore[return-value]
 392
 393    def relabeled_clone(self, change_map: dict[str, str]) -> Self:
 394        clone = self.clone()
 395        clone.change_aliases(change_map)
 396        return clone
 397
 398    def _get_col(self, target: Any, field: Field, alias: str | None) -> Col:
 399        if not self.alias_cols:
 400            alias = None
 401        return target.get_col(alias, field)
 402
 403    def get_aggregation(self, aggregate_exprs: dict[str, Any]) -> dict[str, Any]:
 404        """
 405        Return the dictionary with the values of the existing aggregations.
 406        """
 407        if not aggregate_exprs:
 408            return {}
 409        aggregates = {}
 410        for alias, aggregate_expr in aggregate_exprs.items():
 411            self.check_alias(alias)
 412            aggregate = aggregate_expr.resolve_expression(
 413                self, allow_joins=True, reuse=None, summarize=True
 414            )
 415            if not aggregate.contains_aggregate:
 416                raise TypeError(f"{alias} is not an aggregate expression")
 417            aggregates[alias] = aggregate
 418        # Existing usage of aggregation can be determined by the presence of
 419        # selected aggregates but also by filters against aliased aggregates.
 420        _, having, qualify = self.where.split_having_qualify()
 421        has_existing_aggregation = (
 422            any(
 423                getattr(annotation, "contains_aggregate", True)
 424                for annotation in self.annotations.values()
 425            )
 426            or having
 427        )
 428        # Decide if we need to use a subquery.
 429        #
 430        # Existing aggregations would cause incorrect results as
 431        # get_aggregation() must produce just one result and thus must not use
 432        # GROUP BY.
 433        #
 434        # If the query has limit or distinct, or uses set operations, then
 435        # those operations must be done in a subquery so that the query
 436        # aggregates on the limit and/or distinct results instead of applying
 437        # the distinct and limit after the aggregation.
 438        if (
 439            isinstance(self.group_by, tuple)
 440            or self.is_sliced
 441            or has_existing_aggregation
 442            or qualify
 443            or self.distinct
 444            or self.combinator
 445        ):
 446            from plain.models.sql.subqueries import AggregateQuery
 447
 448            inner_query = self.clone()
 449            inner_query.subquery = True
 450            outer_query = AggregateQuery(self.model, inner_query)
 451            inner_query.select_for_update = False
 452            inner_query.select_related = False
 453            inner_query.set_annotation_mask(self.annotation_select)
 454            # Queries with distinct_fields need ordering and when a limit is
 455            # applied we must take the slice from the ordered query. Otherwise
 456            # no need for ordering.
 457            inner_query.clear_ordering(force=False)
 458            if not inner_query.distinct:
 459                # If the inner query uses default select and it has some
 460                # aggregate annotations, then we must make sure the inner
 461                # query is grouped by the main model's primary key. However,
 462                # clearing the select clause can alter results if distinct is
 463                # used.
 464                if inner_query.default_cols and has_existing_aggregation:
 465                    inner_query.group_by = (
 466                        self.model._model_meta.get_field("id").get_col(
 467                            inner_query.get_initial_alias()
 468                        ),
 469                    )
 470                inner_query.default_cols = False
 471                if not qualify:
 472                    # Mask existing annotations that are not referenced by
 473                    # aggregates to be pushed to the outer query unless
 474                    # filtering against window functions is involved as it
 475                    # requires complex realising.
 476                    annotation_mask = set()
 477                    for aggregate in aggregates.values():
 478                        annotation_mask |= aggregate.get_refs()
 479                    inner_query.set_annotation_mask(annotation_mask)
 480
 481            # Add aggregates to the outer AggregateQuery. This requires making
 482            # sure all columns referenced by the aggregates are selected in the
 483            # inner query. It is achieved by retrieving all column references
 484            # by the aggregates, explicitly selecting them in the inner query,
 485            # and making sure the aggregates are repointed to them.
 486            col_refs = {}
 487            for alias, aggregate in aggregates.items():
 488                replacements = {}
 489                for col in self._gen_cols([aggregate], resolve_refs=False):
 490                    if not (col_ref := col_refs.get(col)):
 491                        index = len(col_refs) + 1
 492                        col_alias = f"__col{index}"
 493                        col_ref = Ref(col_alias, col)
 494                        col_refs[col] = col_ref
 495                        inner_query.annotations[col_alias] = col
 496                        inner_query.append_annotation_mask([col_alias])
 497                    replacements[col] = col_ref
 498                outer_query.annotations[alias] = aggregate.replace_expressions(
 499                    replacements
 500                )
 501            if (
 502                inner_query.select == ()
 503                and not inner_query.default_cols
 504                and not inner_query.annotation_select_mask
 505            ):
 506                # In case of Model.objects[0:3].count(), there would be no
 507                # field selected in the inner query, yet we must use a subquery.
 508                # So, make sure at least one field is selected.
 509                inner_query.select = (
 510                    self.model._model_meta.get_field("id").get_col(
 511                        inner_query.get_initial_alias()
 512                    ),
 513                )
 514        else:
 515            outer_query = self
 516            self.select = ()
 517            self.default_cols = False
 518            self.extra = {}
 519            if self.annotations:
 520                # Inline reference to existing annotations and mask them as
 521                # they are unnecessary given only the summarized aggregations
 522                # are requested.
 523                replacements = {
 524                    Ref(alias, annotation): annotation
 525                    for alias, annotation in self.annotations.items()
 526                }
 527                self.annotations = {
 528                    alias: aggregate.replace_expressions(replacements)
 529                    for alias, aggregate in aggregates.items()
 530                }
 531            else:
 532                self.annotations = aggregates
 533            self.set_annotation_mask(aggregates)
 534
 535        empty_set_result = [
 536            expression.empty_result_set_value
 537            for expression in outer_query.annotation_select.values()
 538        ]
 539        elide_empty = not any(result is NotImplemented for result in empty_set_result)
 540        outer_query.clear_ordering(force=True)
 541        outer_query.clear_limits()
 542        outer_query.select_for_update = False
 543        outer_query.select_related = False
 544        compiler = outer_query.get_compiler(elide_empty=elide_empty)
 545        result = compiler.execute_sql(SINGLE)
 546        if result is None:
 547            result = empty_set_result
 548        else:
 549            converters = compiler.get_converters(outer_query.annotation_select.values())
 550            result = next(compiler.apply_converters((result,), converters))
 551
 552        return dict(zip(outer_query.annotation_select, result))
 553
 554    def get_count(self) -> int:
 555        """
 556        Perform a COUNT() query using the current filter constraints.
 557        """
 558        obj = self.clone()
 559        return obj.get_aggregation({"__count": Count("*")})["__count"]
 560
 561    def has_filters(self) -> bool:
 562        return bool(self.where)
 563
 564    def exists(self, limit: bool = True) -> Self:
 565        q = self.clone()
 566        if not (q.distinct and q.is_sliced):
 567            if q.group_by is True:
 568                q.add_fields(
 569                    (f.attname for f in self.model._model_meta.concrete_fields), False
 570                )
 571                # Disable GROUP BY aliases to avoid orphaning references to the
 572                # SELECT clause which is about to be cleared.
 573                q.set_group_by(allow_aliases=False)
 574            q.clear_select_clause()
 575        if q.combined_queries and q.combinator == "union":
 576            q.combined_queries = tuple(
 577                combined_query.exists(limit=False)
 578                for combined_query in q.combined_queries
 579            )
 580        q.clear_ordering(force=True)
 581        if limit:
 582            q.set_limits(high=1)
 583        q.add_annotation(Value(1), "a")
 584        return q
 585
 586    def has_results(self) -> bool:
 587        q = self.exists()
 588        compiler = q.get_compiler()
 589        return compiler.has_results()
 590
 591    def explain(self, format: str | None = None, **options: Any) -> str:
 592        q = self.clone()
 593        for option_name in options:
 594            if (
 595                not EXPLAIN_OPTIONS_PATTERN.fullmatch(option_name)
 596                or "--" in option_name
 597            ):
 598                raise ValueError(f"Invalid option name: {option_name!r}.")
 599        q.explain_info = ExplainInfo(format, options)
 600        compiler = q.get_compiler()
 601        return "\n".join(compiler.explain_query())
 602
 603    def combine(self, rhs: Query, connector: str) -> None:
 604        """
 605        Merge the 'rhs' query into the current one (with any 'rhs' effects
 606        being applied *after* (that is, "to the right of") anything in the
 607        current query. 'rhs' is not modified during a call to this function.
 608
 609        The 'connector' parameter describes how to connect filters from the
 610        'rhs' query.
 611        """
 612        if self.model != rhs.model:
 613            raise TypeError("Cannot combine queries on two different base models.")
 614        if self.is_sliced:
 615            raise TypeError("Cannot combine queries once a slice has been taken.")
 616        if self.distinct != rhs.distinct:
 617            raise TypeError("Cannot combine a unique query with a non-unique query.")
 618        if self.distinct_fields != rhs.distinct_fields:
 619            raise TypeError("Cannot combine queries with different distinct fields.")
 620
 621        # If lhs and rhs shares the same alias prefix, it is possible to have
 622        # conflicting alias changes like T4 -> T5, T5 -> T6, which might end up
 623        # as T4 -> T6 while combining two querysets. To prevent this, change an
 624        # alias prefix of the rhs and update current aliases accordingly,
 625        # except if the alias is the base table since it must be present in the
 626        # query on both sides.
 627        initial_alias = self.get_initial_alias()
 628        assert initial_alias is not None
 629        rhs.bump_prefix(self, exclude={initial_alias})
 630
 631        # Work out how to relabel the rhs aliases, if necessary.
 632        change_map = {}
 633        conjunction = connector == AND
 634
 635        # Determine which existing joins can be reused. When combining the
 636        # query with AND we must recreate all joins for m2m filters. When
 637        # combining with OR we can reuse joins. The reason is that in AND
 638        # case a single row can't fulfill a condition like:
 639        #     revrel__col=1 & revrel__col=2
 640        # But, there might be two different related rows matching this
 641        # condition. In OR case a single True is enough, so single row is
 642        # enough, too.
 643        #
 644        # Note that we will be creating duplicate joins for non-m2m joins in
 645        # the AND case. The results will be correct but this creates too many
 646        # joins. This is something that could be fixed later on.
 647        reuse = set() if conjunction else set(self.alias_map)
 648        joinpromoter = JoinPromoter(connector, 2, False)
 649        joinpromoter.add_votes(
 650            j for j in self.alias_map if self.alias_map[j].join_type == INNER
 651        )
 652        rhs_votes = set()
 653        # Now, add the joins from rhs query into the new query (skipping base
 654        # table).
 655        rhs_tables = list(rhs.alias_map)[1:]
 656        for alias in rhs_tables:
 657            join = rhs.alias_map[alias]
 658            # If the left side of the join was already relabeled, use the
 659            # updated alias.
 660            join = join.relabeled_clone(change_map)
 661            new_alias = self.join(join, reuse=reuse)
 662            if join.join_type == INNER:
 663                rhs_votes.add(new_alias)
 664            # We can't reuse the same join again in the query. If we have two
 665            # distinct joins for the same connection in rhs query, then the
 666            # combined query must have two joins, too.
 667            reuse.discard(new_alias)
 668            if alias != new_alias:
 669                change_map[alias] = new_alias
 670            if not rhs.alias_refcount[alias]:
 671                # The alias was unused in the rhs query. Unref it so that it
 672                # will be unused in the new query, too. We have to add and
 673                # unref the alias so that join promotion has information of
 674                # the join type for the unused alias.
 675                self.unref_alias(new_alias)
 676        joinpromoter.add_votes(rhs_votes)
 677        joinpromoter.update_join_types(self)
 678
 679        # Combine subqueries aliases to ensure aliases relabelling properly
 680        # handle subqueries when combining where and select clauses.
 681        self.subq_aliases |= rhs.subq_aliases
 682
 683        # Now relabel a copy of the rhs where-clause and add it to the current
 684        # one.
 685        w = rhs.where.clone()
 686        w.relabel_aliases(change_map)
 687        self.where.add(w, connector)
 688
 689        # Selection columns and extra extensions are those provided by 'rhs'.
 690        if rhs.select:
 691            self.set_select([col.relabeled_clone(change_map) for col in rhs.select])
 692        else:
 693            self.select = ()
 694
 695        if connector == OR:
 696            # It would be nice to be able to handle this, but the queries don't
 697            # really make sense (or return consistent value sets). Not worth
 698            # the extra complexity when you can write a real query instead.
 699            if self.extra and rhs.extra:
 700                raise ValueError(
 701                    "When merging querysets using 'or', you cannot have "
 702                    "extra(select=...) on both sides."
 703                )
 704        self.extra.update(rhs.extra)
 705        extra_select_mask = set()
 706        if self.extra_select_mask is not None:
 707            extra_select_mask.update(self.extra_select_mask)
 708        if rhs.extra_select_mask is not None:
 709            extra_select_mask.update(rhs.extra_select_mask)
 710        if extra_select_mask:
 711            self.set_extra_mask(extra_select_mask)
 712        self.extra_tables += rhs.extra_tables
 713
 714        # Ordering uses the 'rhs' ordering, unless it has none, in which case
 715        # the current ordering is used.
 716        self.order_by = rhs.order_by or self.order_by
 717        self.extra_order_by = rhs.extra_order_by or self.extra_order_by
 718
 719    def _get_defer_select_mask(
 720        self,
 721        meta: Meta,
 722        mask: dict[str, Any],
 723        select_mask: dict[Any, Any] | None = None,
 724    ) -> dict[Any, Any]:
 725        if select_mask is None:
 726            select_mask = {}
 727        select_mask[meta.get_field("id")] = {}
 728        # All concrete fields that are not part of the defer mask must be
 729        # loaded. If a relational field is encountered it gets added to the
 730        # mask for it be considered if `select_related` and the cycle continues
 731        # by recursively calling this function.
 732        for field in meta.concrete_fields:
 733            field_mask = mask.pop(field.name, None)
 734            if field_mask is None:
 735                select_mask.setdefault(field, {})
 736            elif field_mask:
 737                if not field.is_relation:
 738                    raise FieldError(next(iter(field_mask)))
 739                field_select_mask = select_mask.setdefault(field, {})
 740                related_model = field.remote_field.model
 741                self._get_defer_select_mask(
 742                    related_model._model_meta, field_mask, field_select_mask
 743                )
 744        # Remaining defer entries must be references to reverse relationships.
 745        # The following code is expected to raise FieldError if it encounters
 746        # a malformed defer entry.
 747        for field_name, field_mask in mask.items():
 748            if filtered_relation := self._filtered_relations.get(field_name):
 749                relation = meta.get_field(filtered_relation.relation_name)
 750                field_select_mask = select_mask.setdefault((field_name, relation), {})
 751                field = relation.field
 752            else:
 753                field = meta.get_field(field_name).field
 754                field_select_mask = select_mask.setdefault(field, {})
 755            related_model = field.model
 756            self._get_defer_select_mask(
 757                related_model._model_meta, field_mask, field_select_mask
 758            )
 759        return select_mask
 760
 761    def _get_only_select_mask(
 762        self,
 763        meta: Meta,
 764        mask: dict[str, Any],
 765        select_mask: dict[Any, Any] | None = None,
 766    ) -> dict[Any, Any]:
 767        if select_mask is None:
 768            select_mask = {}
 769        select_mask[meta.get_field("id")] = {}
 770        # Only include fields mentioned in the mask.
 771        for field_name, field_mask in mask.items():
 772            field = meta.get_field(field_name)
 773            field_select_mask = select_mask.setdefault(field, {})
 774            if field_mask:
 775                if not field.is_relation:
 776                    raise FieldError(next(iter(field_mask)))
 777                related_model = field.remote_field.model
 778                self._get_only_select_mask(
 779                    related_model._model_meta, field_mask, field_select_mask
 780                )
 781        return select_mask
 782
 783    def get_select_mask(self) -> dict[Any, Any]:
 784        """
 785        Convert the self.deferred_loading data structure to an alternate data
 786        structure, describing the field that *will* be loaded. This is used to
 787        compute the columns to select from the database and also by the
 788        QuerySet class to work out which fields are being initialized on each
 789        model. Models that have all their fields included aren't mentioned in
 790        the result, only those that have field restrictions in place.
 791        """
 792        field_names, defer = self.deferred_loading
 793        if not field_names:
 794            return {}
 795        mask = {}
 796        for field_name in field_names:
 797            part_mask = mask
 798            for part in field_name.split(LOOKUP_SEP):
 799                part_mask = part_mask.setdefault(part, {})
 800        meta = self.get_model_meta()
 801        if defer:
 802            return self._get_defer_select_mask(meta, mask)
 803        return self._get_only_select_mask(meta, mask)
 804
 805    def table_alias(
 806        self, table_name: str, create: bool = False, filtered_relation: Any = None
 807    ) -> tuple[str, bool]:
 808        """
 809        Return a table alias for the given table_name and whether this is a
 810        new alias or not.
 811
 812        If 'create' is true, a new alias is always created. Otherwise, the
 813        most recently created alias for the table (if one exists) is reused.
 814        """
 815        alias_list = self.table_map.get(table_name)
 816        if not create and alias_list:
 817            alias = alias_list[0]
 818            self.alias_refcount[alias] += 1
 819            return alias, False
 820
 821        # Create a new alias for this table.
 822        if alias_list:
 823            alias = "%s%d" % (self.alias_prefix, len(self.alias_map) + 1)  # noqa: UP031
 824            alias_list.append(alias)
 825        else:
 826            # The first occurrence of a table uses the table name directly.
 827            alias = (
 828                filtered_relation.alias if filtered_relation is not None else table_name
 829            )
 830            self.table_map[table_name] = [alias]
 831        self.alias_refcount[alias] = 1
 832        return alias, True
 833
 834    def ref_alias(self, alias: str) -> None:
 835        """Increases the reference count for this alias."""
 836        self.alias_refcount[alias] += 1
 837
 838    def unref_alias(self, alias: str, amount: int = 1) -> None:
 839        """Decreases the reference count for this alias."""
 840        self.alias_refcount[alias] -= amount
 841
 842    def promote_joins(self, aliases: set[str] | list[str]) -> None:
 843        """
 844        Promote recursively the join type of given aliases and its children to
 845        an outer join. If 'unconditional' is False, only promote the join if
 846        it is nullable or the parent join is an outer join.
 847
 848        The children promotion is done to avoid join chains that contain a LOUTER
 849        b INNER c. So, if we have currently a INNER b INNER c and a->b is promoted,
 850        then we must also promote b->c automatically, or otherwise the promotion
 851        of a->b doesn't actually change anything in the query results.
 852        """
 853        aliases = list(aliases)
 854        while aliases:
 855            alias = aliases.pop(0)
 856            if self.alias_map[alias].join_type is None:
 857                # This is the base table (first FROM entry) - this table
 858                # isn't really joined at all in the query, so we should not
 859                # alter its join type.
 860                continue
 861            # Only the first alias (skipped above) should have None join_type
 862            assert self.alias_map[alias].join_type is not None
 863            parent_alias = self.alias_map[alias].parent_alias
 864            parent_louter = (
 865                parent_alias and self.alias_map[parent_alias].join_type == LOUTER
 866            )
 867            already_louter = self.alias_map[alias].join_type == LOUTER
 868            if (self.alias_map[alias].nullable or parent_louter) and not already_louter:
 869                self.alias_map[alias] = self.alias_map[alias].promote()
 870                # Join type of 'alias' changed, so re-examine all aliases that
 871                # refer to this one.
 872                aliases.extend(
 873                    join
 874                    for join in self.alias_map
 875                    if self.alias_map[join].parent_alias == alias
 876                    and join not in aliases
 877                )
 878
 879    def demote_joins(self, aliases: set[str] | list[str]) -> None:
 880        """
 881        Change join type from LOUTER to INNER for all joins in aliases.
 882
 883        Similarly to promote_joins(), this method must ensure no join chains
 884        containing first an outer, then an inner join are generated. If we
 885        are demoting b->c join in chain a LOUTER b LOUTER c then we must
 886        demote a->b automatically, or otherwise the demotion of b->c doesn't
 887        actually change anything in the query results. .
 888        """
 889        aliases = list(aliases)
 890        while aliases:
 891            alias = aliases.pop(0)
 892            if self.alias_map[alias].join_type == LOUTER:
 893                self.alias_map[alias] = self.alias_map[alias].demote()
 894                parent_alias = self.alias_map[alias].parent_alias
 895                if self.alias_map[parent_alias].join_type == INNER:
 896                    aliases.append(parent_alias)
 897
 898    def reset_refcounts(self, to_counts: dict[str, int]) -> None:
 899        """
 900        Reset reference counts for aliases so that they match the value passed
 901        in `to_counts`.
 902        """
 903        for alias, cur_refcount in self.alias_refcount.copy().items():
 904            unref_amount = cur_refcount - to_counts.get(alias, 0)
 905            self.unref_alias(alias, unref_amount)
 906
 907    def change_aliases(self, change_map: dict[str, str]) -> None:
 908        """
 909        Change the aliases in change_map (which maps old-alias -> new-alias),
 910        relabelling any references to them in select columns and the where
 911        clause.
 912        """
 913        # If keys and values of change_map were to intersect, an alias might be
 914        # updated twice (e.g. T4 -> T5, T5 -> T6, so also T4 -> T6) depending
 915        # on their order in change_map.
 916        assert set(change_map).isdisjoint(change_map.values())
 917
 918        # 1. Update references in "select" (normal columns plus aliases),
 919        # "group by" and "where".
 920        self.where.relabel_aliases(change_map)
 921        if isinstance(self.group_by, tuple):
 922            self.group_by = tuple(
 923                [col.relabeled_clone(change_map) for col in self.group_by]
 924            )
 925        self.select = tuple([col.relabeled_clone(change_map) for col in self.select])
 926        self.annotations = self.annotations and {
 927            key: col.relabeled_clone(change_map)
 928            for key, col in self.annotations.items()
 929        }
 930
 931        # 2. Rename the alias in the internal table/alias datastructures.
 932        for old_alias, new_alias in change_map.items():
 933            if old_alias not in self.alias_map:
 934                continue
 935            alias_data = self.alias_map[old_alias].relabeled_clone(change_map)
 936            self.alias_map[new_alias] = alias_data
 937            self.alias_refcount[new_alias] = self.alias_refcount[old_alias]
 938            del self.alias_refcount[old_alias]
 939            del self.alias_map[old_alias]
 940
 941            table_aliases = self.table_map[alias_data.table_name]
 942            for pos, alias in enumerate(table_aliases):
 943                if alias == old_alias:
 944                    table_aliases[pos] = new_alias
 945                    break
 946        self.external_aliases = {
 947            # Table is aliased or it's being changed and thus is aliased.
 948            change_map.get(alias, alias): (aliased or alias in change_map)
 949            for alias, aliased in self.external_aliases.items()
 950        }
 951
 952    def bump_prefix(
 953        self, other_query: Query, exclude: set[str] | dict[str, str] | None = None
 954    ) -> None:
 955        """
 956        Change the alias prefix to the next letter in the alphabet in a way
 957        that the other query's aliases and this query's aliases will not
 958        conflict. Even tables that previously had no alias will get an alias
 959        after this call. To prevent changing aliases use the exclude parameter.
 960        """
 961
 962        def prefix_gen() -> TypingIterator[str]:
 963            """
 964            Generate a sequence of characters in alphabetical order:
 965                -> 'A', 'B', 'C', ...
 966
 967            When the alphabet is finished, the sequence will continue with the
 968            Cartesian product:
 969                -> 'AA', 'AB', 'AC', ...
 970            """
 971            alphabet = ascii_uppercase
 972            prefix = chr(ord(self.alias_prefix) + 1)
 973            yield prefix
 974            for n in count(1):
 975                seq = alphabet[alphabet.index(prefix) :] if prefix else alphabet
 976                for s in product(seq, repeat=n):
 977                    yield "".join(s)
 978                prefix = None
 979
 980        if self.alias_prefix != other_query.alias_prefix:
 981            # No clashes between self and outer query should be possible.
 982            return
 983
 984        # Explicitly avoid infinite loop. The constant divider is based on how
 985        # much depth recursive subquery references add to the stack. This value
 986        # might need to be adjusted when adding or removing function calls from
 987        # the code path in charge of performing these operations.
 988        local_recursion_limit = sys.getrecursionlimit() // 16
 989        for pos, prefix in enumerate(prefix_gen()):
 990            if prefix not in self.subq_aliases:
 991                self.alias_prefix = prefix
 992                break
 993            if pos > local_recursion_limit:
 994                raise RecursionError(
 995                    "Maximum recursion depth exceeded: too many subqueries."
 996                )
 997        self.subq_aliases = self.subq_aliases.union([self.alias_prefix])
 998        other_query.subq_aliases = other_query.subq_aliases.union(self.subq_aliases)
 999        if exclude is None:
1000            exclude = {}
1001        self.change_aliases(
1002            {
1003                alias: "%s%d" % (self.alias_prefix, pos)  # noqa: UP031
1004                for pos, alias in enumerate(self.alias_map)
1005                if alias not in exclude
1006            }
1007        )
1008
1009    def get_initial_alias(self) -> str | None:
1010        """
1011        Return the first alias for this query, after increasing its reference
1012        count.
1013        """
1014        if self.alias_map:
1015            alias = self.base_table
1016            self.ref_alias(alias)
1017        elif self.model:
1018            alias = self.join(
1019                self.base_table_class(self.model.model_options.db_table, None)
1020            )
1021        else:
1022            alias = None
1023        return alias
1024
1025    def count_active_tables(self) -> int:
1026        """
1027        Return the number of tables in this query with a non-zero reference
1028        count. After execution, the reference counts are zeroed, so tables
1029        added in compiler will not be seen by this method.
1030        """
1031        return len([1 for count in self.alias_refcount.values() if count])
1032
1033    def join(
1034        self,
1035        join: BaseTable | Join,
1036        reuse: set[str] | None = None,
1037        reuse_with_filtered_relation: bool = False,
1038    ) -> str:
1039        """
1040        Return an alias for the 'join', either reusing an existing alias for
1041        that join or creating a new one. 'join' is either a base_table_class or
1042        join_class.
1043
1044        The 'reuse' parameter can be either None which means all joins are
1045        reusable, or it can be a set containing the aliases that can be reused.
1046
1047        The 'reuse_with_filtered_relation' parameter is used when computing
1048        FilteredRelation instances.
1049
1050        A join is always created as LOUTER if the lhs alias is LOUTER to make
1051        sure chains like t1 LOUTER t2 INNER t3 aren't generated. All new
1052        joins are created as LOUTER if the join is nullable.
1053        """
1054        if reuse_with_filtered_relation and reuse:
1055            reuse_aliases = [
1056                a for a, j in self.alias_map.items() if a in reuse and j.equals(join)
1057            ]
1058        else:
1059            reuse_aliases = [
1060                a
1061                for a, j in self.alias_map.items()
1062                if (reuse is None or a in reuse) and j == join
1063            ]
1064        if reuse_aliases:
1065            if join.table_alias in reuse_aliases:
1066                reuse_alias = join.table_alias
1067            else:
1068                # Reuse the most recent alias of the joined table
1069                # (a many-to-many relation may be joined multiple times).
1070                reuse_alias = reuse_aliases[-1]
1071            self.ref_alias(reuse_alias)
1072            return reuse_alias
1073
1074        # No reuse is possible, so we need a new alias.
1075        alias, _ = self.table_alias(
1076            join.table_name, create=True, filtered_relation=join.filtered_relation
1077        )
1078        if join.join_type:
1079            if self.alias_map[join.parent_alias].join_type == LOUTER or join.nullable:  # type: ignore[attr-defined]
1080                join_type = LOUTER
1081            else:
1082                join_type = INNER
1083            join.join_type = join_type
1084        join.table_alias = alias
1085        self.alias_map[alias] = join
1086        return alias
1087
1088    def check_alias(self, alias: str) -> None:
1089        if FORBIDDEN_ALIAS_PATTERN.search(alias):
1090            raise ValueError(
1091                "Column aliases cannot contain whitespace characters, quotation marks, "
1092                "semicolons, or SQL comments."
1093            )
1094
1095    def add_annotation(
1096        self, annotation: BaseExpression, alias: str, select: bool = True
1097    ) -> None:
1098        """Add a single annotation expression to the Query."""
1099        self.check_alias(alias)
1100        annotation = annotation.resolve_expression(self, allow_joins=True, reuse=None)
1101        if select:
1102            self.append_annotation_mask([alias])
1103        else:
1104            self.set_annotation_mask(set(self.annotation_select).difference({alias}))
1105        self.annotations[alias] = annotation
1106
1107    def resolve_expression(self, query: Query, *args: Any, **kwargs: Any) -> Self:
1108        clone = self.clone()
1109        # Subqueries need to use a different set of aliases than the outer query.
1110        clone.bump_prefix(query)
1111        clone.subquery = True
1112        clone.where.resolve_expression(query, *args, **kwargs)
1113        # Resolve combined queries.
1114        if clone.combinator:
1115            clone.combined_queries = tuple(
1116                [
1117                    combined_query.resolve_expression(query, *args, **kwargs)
1118                    for combined_query in clone.combined_queries
1119                ]
1120            )
1121        for key, value in clone.annotations.items():
1122            resolved = value.resolve_expression(query, *args, **kwargs)
1123            if hasattr(resolved, "external_aliases"):
1124                resolved.external_aliases.update(clone.external_aliases)
1125            clone.annotations[key] = resolved
1126        # Outer query's aliases are considered external.
1127        for alias, table in query.alias_map.items():
1128            clone.external_aliases[alias] = (
1129                isinstance(table, Join)
1130                and table.join_field.related_model.model_options.db_table != alias
1131            ) or (
1132                isinstance(table, BaseTable) and table.table_name != table.table_alias
1133            )
1134        return clone
1135
1136    def get_external_cols(self) -> list[Col]:
1137        exprs = chain(self.annotations.values(), self.where.children)
1138        return [
1139            col
1140            for col in self._gen_cols(exprs, include_external=True)
1141            if col.alias in self.external_aliases
1142        ]
1143
1144    def get_group_by_cols(
1145        self, wrapper: BaseExpression | None = None
1146    ) -> list[Col] | list[BaseExpression]:
1147        # If wrapper is referenced by an alias for an explicit GROUP BY through
1148        # values() a reference to this expression and not the self must be
1149        # returned to ensure external column references are not grouped against
1150        # as well.
1151        external_cols = self.get_external_cols()
1152        if any(col.possibly_multivalued for col in external_cols):
1153            return [wrapper or self]
1154        return external_cols
1155
1156    def as_sql(
1157        self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
1158    ) -> tuple[str, tuple[Any, ...]]:
1159        # Some backends (e.g. Oracle) raise an error when a subquery contains
1160        # unnecessary ORDER BY clause.
1161        if (
1162            self.subquery
1163            and not db_connection.features.ignores_unnecessary_order_by_in_subqueries
1164        ):
1165            self.clear_ordering(force=False)
1166            for query in self.combined_queries:
1167                query.clear_ordering(force=False)
1168        sql, params = self.get_compiler().as_sql()
1169        if self.subquery:
1170            sql = f"({sql})"
1171        return sql, params
1172
1173    def resolve_lookup_value(
1174        self, value: Any, can_reuse: set[str] | None, allow_joins: bool
1175    ) -> Any:
1176        if hasattr(value, "resolve_expression"):
1177            value = value.resolve_expression(
1178                self,
1179                reuse=can_reuse,
1180                allow_joins=allow_joins,
1181            )
1182        elif isinstance(value, list | tuple):
1183            # The items of the iterable may be expressions and therefore need
1184            # to be resolved independently.
1185            values = (
1186                self.resolve_lookup_value(sub_value, can_reuse, allow_joins)
1187                for sub_value in value
1188            )
1189            type_ = type(value)
1190            if hasattr(type_, "_make"):  # namedtuple
1191                return type_(*values)
1192            return type_(values)
1193        return value
1194
1195    def solve_lookup_type(
1196        self, lookup: str, summarize: bool = False
1197    ) -> tuple[
1198        list[str] | tuple[str, ...], tuple[str, ...], BaseExpression | Literal[False]
1199    ]:
1200        """
1201        Solve the lookup type from the lookup (e.g.: 'foobar__id__icontains').
1202        """
1203        lookup_splitted = lookup.split(LOOKUP_SEP)
1204        if self.annotations:
1205            annotation, expression_lookups = refs_expression(
1206                lookup_splitted, self.annotations
1207            )
1208            if annotation:
1209                expression = self.annotations[annotation]
1210                if summarize:
1211                    expression = Ref(annotation, expression)
1212                return expression_lookups, (), expression
1213        _, field, _, lookup_parts = self.names_to_path(
1214            lookup_splitted, self.get_model_meta()
1215        )
1216        field_parts = lookup_splitted[0 : len(lookup_splitted) - len(lookup_parts)]
1217        if len(lookup_parts) > 1 and not field_parts:
1218            raise FieldError(
1219                f'Invalid lookup "{lookup}" for model {self.get_model_meta().model.__name__}".'
1220            )
1221        return lookup_parts, field_parts, False  # type: ignore[return-value]
1222
1223    def check_query_object_type(self, value: Any, meta: Meta, field: Field) -> None:
1224        """
1225        Check whether the object passed while querying is of the correct type.
1226        If not, raise a ValueError specifying the wrong object.
1227        """
1228        if hasattr(value, "_model_meta"):
1229            if not check_rel_lookup_compatibility(value._model_meta.model, meta, field):
1230                raise ValueError(
1231                    f'Cannot query "{value}": Must be "{meta.model.model_options.object_name}" instance.'
1232                )
1233
1234    def check_related_objects(self, field: Field, value: Any, meta: Meta) -> None:
1235        """Check the type of object passed to query relations."""
1236        if field.is_relation:
1237            # Check that the field and the queryset use the same model in a
1238            # query like .filter(author=Author.query.all()). For example, the
1239            # meta would be Author's (from the author field) and value.model
1240            # would be Author.query.all() queryset's .model (Author also).
1241            # The field is the related field on the lhs side.
1242            if (
1243                isinstance(value, Query)
1244                and not value.has_select_fields
1245                and not check_rel_lookup_compatibility(value.model, meta, field)
1246            ):
1247                raise ValueError(
1248                    f'Cannot use QuerySet for "{value.model.model_options.object_name}": Use a QuerySet for "{meta.model.model_options.object_name}".'
1249                )
1250            elif hasattr(value, "_model_meta"):
1251                self.check_query_object_type(value, meta, field)
1252            elif hasattr(value, "__iter__"):
1253                for v in value:
1254                    self.check_query_object_type(v, meta, field)
1255
1256    def check_filterable(self, expression: Any) -> None:
1257        """Raise an error if expression cannot be used in a WHERE clause."""
1258        if hasattr(expression, "resolve_expression") and not getattr(
1259            expression, "filterable", True
1260        ):
1261            raise NotSupportedError(
1262                expression.__class__.__name__ + " is disallowed in the filter clause."
1263            )
1264        if hasattr(expression, "get_source_expressions"):
1265            for expr in expression.get_source_expressions():
1266                self.check_filterable(expr)
1267
1268    def build_lookup(
1269        self, lookups: list[str], lhs: BaseExpression | MultiColSource, rhs: Any
1270    ) -> Lookup | None:
1271        """
1272        Try to extract transforms and lookup from given lhs.
1273
1274        The lhs value is something that works like SQLExpression.
1275        The rhs value is what the lookup is going to compare against.
1276        The lookups is a list of names to extract using get_lookup()
1277        and get_transform().
1278        """
1279        # __exact is the default lookup if one isn't given.
1280        *transforms, lookup_name = lookups or ["exact"]
1281        for name in transforms:
1282            lhs = self.try_transform(lhs, name)
1283        # First try get_lookup() so that the lookup takes precedence if the lhs
1284        # supports both transform and lookup for the name.
1285        lookup_class = lhs.get_lookup(lookup_name)
1286        if not lookup_class:
1287            # A lookup wasn't found. Try to interpret the name as a transform
1288            # and do an Exact lookup against it.
1289            lhs = self.try_transform(lhs, lookup_name)
1290            lookup_name = "exact"
1291            lookup_class = lhs.get_lookup(lookup_name)
1292            if not lookup_class:
1293                return
1294
1295        lookup = lookup_class(lhs, rhs)
1296        # Interpret '__exact=None' as the sql 'is NULL'; otherwise, reject all
1297        # uses of None as a query value unless the lookup supports it.
1298        if lookup.rhs is None and not lookup.can_use_none_as_rhs:
1299            if lookup_name not in ("exact", "iexact"):
1300                raise ValueError("Cannot use None as a query value")
1301            return lhs.get_lookup("isnull")(lhs, True)  # type: ignore[return-value]
1302
1303        return lookup
1304
1305    def try_transform(
1306        self, lhs: BaseExpression | MultiColSource, name: str
1307    ) -> BaseExpression | MultiColSource:
1308        """
1309        Helper method for build_lookup(). Try to fetch and initialize
1310        a transform for name parameter from lhs.
1311        """
1312        transform_class = lhs.get_transform(name)  # type: ignore[union-attr]
1313        if transform_class:
1314            return transform_class(lhs)
1315        else:
1316            output_field = lhs.output_field.__class__
1317            suggested_lookups = difflib.get_close_matches(
1318                name, output_field.get_lookups()
1319            )
1320            if suggested_lookups:
1321                suggestion = ", perhaps you meant {}?".format(
1322                    " or ".join(suggested_lookups)
1323                )
1324            else:
1325                suggestion = "."
1326            raise FieldError(
1327                f"Unsupported lookup '{name}' for {output_field.__name__} or join on the field not "
1328                f"permitted{suggestion}"
1329            )
1330
1331    def build_filter(
1332        self,
1333        filter_expr: tuple[str, Any] | Q | BaseExpression,
1334        branch_negated: bool = False,
1335        current_negated: bool = False,
1336        can_reuse: set[str] | None = None,
1337        allow_joins: bool = True,
1338        split_subq: bool = True,
1339        reuse_with_filtered_relation: bool = False,
1340        check_filterable: bool = True,
1341        summarize: bool = False,
1342    ) -> tuple[WhereNode, set[str] | tuple[()]]:
1343        """
1344        Build a WhereNode for a single filter clause but don't add it
1345        to this Query. Query.add_q() will then add this filter to the where
1346        Node.
1347
1348        The 'branch_negated' tells us if the current branch contains any
1349        negations. This will be used to determine if subqueries are needed.
1350
1351        The 'current_negated' is used to determine if the current filter is
1352        negated or not and this will be used to determine if IS NULL filtering
1353        is needed.
1354
1355        The difference between current_negated and branch_negated is that
1356        branch_negated is set on first negation, but current_negated is
1357        flipped for each negation.
1358
1359        Note that add_filter will not do any negating itself, that is done
1360        upper in the code by add_q().
1361
1362        The 'can_reuse' is a set of reusable joins for multijoins.
1363
1364        If 'reuse_with_filtered_relation' is True, then only joins in can_reuse
1365        will be reused.
1366
1367        The method will create a filter clause that can be added to the current
1368        query. However, if the filter isn't added to the query then the caller
1369        is responsible for unreffing the joins used.
1370        """
1371        if isinstance(filter_expr, dict):
1372            raise FieldError("Cannot parse keyword query as dict")
1373        if isinstance(filter_expr, Q):
1374            return self._add_q(
1375                filter_expr,
1376                branch_negated=branch_negated,
1377                current_negated=current_negated,
1378                used_aliases=can_reuse,
1379                allow_joins=allow_joins,
1380                split_subq=split_subq,
1381                check_filterable=check_filterable,
1382                summarize=summarize,
1383            )
1384        if hasattr(filter_expr, "resolve_expression"):
1385            if not getattr(filter_expr, "conditional", False):
1386                raise TypeError("Cannot filter against a non-conditional expression.")
1387            condition = filter_expr.resolve_expression(
1388                self, allow_joins=allow_joins, summarize=summarize
1389            )  # type: ignore[attr-defined]
1390            if not isinstance(condition, Lookup):
1391                condition = self.build_lookup(["exact"], condition, True)
1392            return WhereNode([condition], connector=AND), []  # type: ignore[return-value]
1393        arg, value = filter_expr
1394        if not arg:
1395            raise FieldError(f"Cannot parse keyword query {arg!r}")
1396        lookups, parts, reffed_expression = self.solve_lookup_type(arg, summarize)
1397
1398        if check_filterable:
1399            self.check_filterable(reffed_expression)
1400
1401        if not allow_joins and len(parts) > 1:
1402            raise FieldError("Joined field references are not permitted in this query")
1403
1404        pre_joins = self.alias_refcount.copy()
1405        value = self.resolve_lookup_value(value, can_reuse, allow_joins)
1406        used_joins = {
1407            k for k, v in self.alias_refcount.items() if v > pre_joins.get(k, 0)
1408        }
1409
1410        if check_filterable:
1411            self.check_filterable(value)
1412
1413        if reffed_expression:
1414            condition = self.build_lookup(list(lookups), reffed_expression, value)
1415            return WhereNode([condition], connector=AND), []  # type: ignore[return-value]
1416
1417        meta = self.get_model_meta()
1418        alias = self.get_initial_alias()
1419        assert alias is not None
1420        allow_many = not branch_negated or not split_subq
1421
1422        try:
1423            join_info = self.setup_joins(
1424                list(parts),
1425                meta,
1426                alias,
1427                can_reuse=can_reuse,
1428                allow_many=allow_many,
1429                reuse_with_filtered_relation=reuse_with_filtered_relation,
1430            )
1431
1432            # Prevent iterator from being consumed by check_related_objects()
1433            if isinstance(value, Iterator):
1434                value = list(value)
1435            self.check_related_objects(join_info.final_field, value, join_info.meta)
1436
1437            # split_exclude() needs to know which joins were generated for the
1438            # lookup parts
1439            self._lookup_joins = join_info.joins
1440        except MultiJoin as e:
1441            return self.split_exclude(
1442                filter_expr,
1443                can_reuse or set(),
1444                e.names_with_path,  # type: ignore[invalid-argument-type]
1445            )
1446
1447        # Update used_joins before trimming since they are reused to determine
1448        # which joins could be later promoted to INNER.
1449        used_joins.update(join_info.joins)
1450        targets, alias, join_list = self.trim_joins(
1451            join_info.targets, join_info.joins, join_info.path
1452        )
1453        if can_reuse is not None:
1454            can_reuse.update(join_list)
1455
1456        if join_info.final_field.is_relation:
1457            if len(targets) == 1:
1458                col = self._get_col(targets[0], join_info.final_field, alias)
1459            else:
1460                col = MultiColSource(
1461                    alias, targets, join_info.targets, join_info.final_field
1462                )
1463        else:
1464            col = self._get_col(targets[0], join_info.final_field, alias)
1465
1466        condition = self.build_lookup(list(lookups), col, value)
1467        assert condition is not None
1468        lookup_type = condition.lookup_name
1469        clause = WhereNode([condition], connector=AND)
1470
1471        require_outer = (
1472            lookup_type == "isnull" and condition.rhs is True and not current_negated
1473        )
1474        if (
1475            current_negated
1476            and (lookup_type != "isnull" or condition.rhs is False)
1477            and condition.rhs is not None
1478        ):
1479            require_outer = True
1480            if lookup_type != "isnull":
1481                # The condition added here will be SQL like this:
1482                # NOT (col IS NOT NULL), where the first NOT is added in
1483                # upper layers of code. The reason for addition is that if col
1484                # is null, then col != someval will result in SQL "unknown"
1485                # which isn't the same as in Python. The Python None handling
1486                # is wanted, and it can be gotten by
1487                # (col IS NULL OR col != someval)
1488                #   <=>
1489                # NOT (col IS NOT NULL AND col = someval).
1490                if (
1491                    self.is_nullable(targets[0])
1492                    or self.alias_map[join_list[-1]].join_type == LOUTER
1493                ):
1494                    lookup_class = targets[0].get_lookup("isnull")
1495                    assert lookup_class is not None
1496                    col = self._get_col(targets[0], join_info.targets[0], alias)
1497                    clause.add(lookup_class(col, False), AND)
1498                # If someval is a nullable column, someval IS NOT NULL is
1499                # added.
1500                if isinstance(value, Col) and self.is_nullable(value.target):
1501                    lookup_class = value.target.get_lookup("isnull")
1502                    assert lookup_class is not None
1503                    clause.add(lookup_class(value, False), AND)
1504        return clause, used_joins if not require_outer else ()
1505
1506    def add_filter(self, filter_lhs: str, filter_rhs: Any) -> None:
1507        self.add_q(Q((filter_lhs, filter_rhs)))
1508
1509    def add_q(self, q_object: Q) -> None:  # type: ignore[unsupported-operator]
1510        """
1511        A preprocessor for the internal _add_q(). Responsible for doing final
1512        join promotion.
1513        """
1514        # For join promotion this case is doing an AND for the added q_object
1515        # and existing conditions. So, any existing inner join forces the join
1516        # type to remain inner. Existing outer joins can however be demoted.
1517        # (Consider case where rel_a is LOUTER and rel_a__col=1 is added - if
1518        # rel_a doesn't produce any rows, then the whole condition must fail.
1519        # So, demotion is OK.
1520        existing_inner = {
1521            a for a in self.alias_map if self.alias_map[a].join_type == INNER
1522        }
1523        clause, _ = self._add_q(q_object, self.used_aliases)
1524        if clause:
1525            self.where.add(clause, AND)
1526        self.demote_joins(existing_inner)
1527
1528    def build_where(
1529        self, filter_expr: tuple[str, Any] | Q | BaseExpression
1530    ) -> WhereNode:
1531        return self.build_filter(filter_expr, allow_joins=False)[0]
1532
1533    def clear_where(self) -> None:
1534        self.where = WhereNode()
1535
1536    def _add_q(
1537        self,
1538        q_object: Q,
1539        used_aliases: set[str] | None,
1540        branch_negated: bool = False,
1541        current_negated: bool = False,
1542        allow_joins: bool = True,
1543        split_subq: bool = True,
1544        check_filterable: bool = True,
1545        summarize: bool = False,
1546    ) -> tuple[WhereNode, set[str] | tuple[()]]:  # type: ignore[unsupported-operator]
1547        """Add a Q-object to the current filter."""
1548        connector = q_object.connector
1549        current_negated ^= q_object.negated
1550        branch_negated = branch_negated or q_object.negated
1551        target_clause = WhereNode(connector=connector, negated=q_object.negated)
1552        joinpromoter = JoinPromoter(
1553            q_object.connector, len(q_object.children), current_negated
1554        )
1555        for child in q_object.children:
1556            child_clause, needed_inner = self.build_filter(
1557                child,
1558                can_reuse=used_aliases,
1559                branch_negated=branch_negated,
1560                current_negated=current_negated,
1561                allow_joins=allow_joins,
1562                split_subq=split_subq,
1563                check_filterable=check_filterable,
1564                summarize=summarize,
1565            )
1566            joinpromoter.add_votes(needed_inner)
1567            if child_clause:
1568                target_clause.add(child_clause, connector)
1569        needed_inner = joinpromoter.update_join_types(self)
1570        return target_clause, needed_inner
1571
1572    def build_filtered_relation_q(
1573        self,
1574        q_object: Q,
1575        reuse: set[str],
1576        branch_negated: bool = False,
1577        current_negated: bool = False,
1578    ) -> WhereNode:  # type: ignore[unsupported-operator]
1579        """Add a FilteredRelation object to the current filter."""
1580        connector = q_object.connector
1581        current_negated ^= q_object.negated
1582        branch_negated = branch_negated or q_object.negated
1583        target_clause = WhereNode(connector=connector, negated=q_object.negated)
1584        for child in q_object.children:
1585            if isinstance(child, Node):
1586                child_clause = self.build_filtered_relation_q(
1587                    child,
1588                    reuse=reuse,
1589                    branch_negated=branch_negated,
1590                    current_negated=current_negated,
1591                )
1592            else:
1593                child_clause, _ = self.build_filter(
1594                    child,
1595                    can_reuse=reuse,
1596                    branch_negated=branch_negated,
1597                    current_negated=current_negated,
1598                    allow_joins=True,
1599                    split_subq=False,
1600                    reuse_with_filtered_relation=True,
1601                )
1602            target_clause.add(child_clause, connector)
1603        return target_clause
1604
1605    def add_filtered_relation(self, filtered_relation: Any, alias: str) -> None:
1606        filtered_relation.alias = alias
1607        lookups = dict(get_children_from_q(filtered_relation.condition))
1608        relation_lookup_parts, relation_field_parts, _ = self.solve_lookup_type(
1609            filtered_relation.relation_name
1610        )
1611        if relation_lookup_parts:
1612            raise ValueError(
1613                "FilteredRelation's relation_name cannot contain lookups "
1614                f"(got {filtered_relation.relation_name!r})."
1615            )
1616        for lookup in chain(lookups):
1617            lookup_parts, lookup_field_parts, _ = self.solve_lookup_type(lookup)
1618            shift = 2 if not lookup_parts else 1
1619            lookup_field_path = lookup_field_parts[:-shift]
1620            for idx, lookup_field_part in enumerate(lookup_field_path):
1621                if len(relation_field_parts) > idx:
1622                    if relation_field_parts[idx] != lookup_field_part:
1623                        raise ValueError(
1624                            "FilteredRelation's condition doesn't support "
1625                            f"relations outside the {filtered_relation.relation_name!r} (got {lookup!r})."
1626                        )
1627                else:
1628                    raise ValueError(
1629                        "FilteredRelation's condition doesn't support nested "
1630                        f"relations deeper than the relation_name (got {lookup!r} for "
1631                        f"{filtered_relation.relation_name!r})."
1632                    )
1633        self._filtered_relations[filtered_relation.alias] = filtered_relation
1634
1635    def names_to_path(
1636        self,
1637        names: list[str],
1638        meta: Meta,
1639        allow_many: bool = True,
1640        fail_on_missing: bool = False,
1641    ) -> tuple[list[Any], Field, tuple[Field, ...], list[str]]:
1642        """
1643        Walk the list of names and turns them into PathInfo tuples. A single
1644        name in 'names' can generate multiple PathInfos (m2m, for example).
1645
1646        'names' is the path of names to travel, 'meta' is the Meta we
1647        start the name resolving from, 'allow_many' is as for setup_joins().
1648        If fail_on_missing is set to True, then a name that can't be resolved
1649        will generate a FieldError.
1650
1651        Return a list of PathInfo tuples. In addition return the final field
1652        (the last used join field) and target (which is a field guaranteed to
1653        contain the same value as the final field). Finally, return those names
1654        that weren't found (which are likely transforms and the final lookup).
1655        """
1656        path, names_with_path = [], []
1657        for pos, name in enumerate(names):
1658            cur_names_with_path = (name, [])
1659
1660            field = None
1661            filtered_relation = None
1662            try:
1663                if meta is None:
1664                    raise FieldDoesNotExist
1665                field = meta.get_field(name)
1666            except FieldDoesNotExist:
1667                if name in self.annotation_select:
1668                    field = self.annotation_select[name].output_field
1669                elif name in self._filtered_relations and pos == 0:
1670                    filtered_relation = self._filtered_relations[name]
1671                    if LOOKUP_SEP in filtered_relation.relation_name:
1672                        parts = filtered_relation.relation_name.split(LOOKUP_SEP)
1673                        filtered_relation_path, field, _, _ = self.names_to_path(
1674                            parts,
1675                            meta,
1676                            allow_many,
1677                            fail_on_missing,
1678                        )
1679                        path.extend(filtered_relation_path[:-1])
1680                    else:
1681                        field = meta.get_field(filtered_relation.relation_name)  # type: ignore[attr-defined]
1682            if field is not None:
1683                # Fields that contain one-to-many relations with a generic
1684                # model (like a GenericForeignKey) cannot generate reverse
1685                # relations and therefore cannot be used for reverse querying.
1686                if field.is_relation and not field.related_model:
1687                    raise FieldError(
1688                        f"Field {name!r} does not generate an automatic reverse "
1689                        "relation and therefore cannot be used for reverse "
1690                        "querying. If it is a GenericForeignKey, consider "
1691                        "adding a GenericRelation."
1692                    )
1693            else:
1694                # We didn't find the current field, so move position back
1695                # one step.
1696                pos -= 1
1697                if pos == -1 or fail_on_missing:
1698                    available = sorted(
1699                        [
1700                            *get_field_names_from_opts(meta),
1701                            *self.annotation_select,
1702                            *self._filtered_relations,
1703                        ]
1704                    )
1705                    raise FieldError(
1706                        "Cannot resolve keyword '{}' into field. "
1707                        "Choices are: {}".format(name, ", ".join(available))
1708                    )
1709                break
1710
1711            if hasattr(field, "path_infos"):
1712                pathinfos: list[PathInfo]
1713                if filtered_relation:
1714                    pathinfos = field.get_path_info(filtered_relation)  # type: ignore[attr-defined]
1715                else:
1716                    pathinfos = field.path_infos  # type: ignore[attr-defined]
1717                if not allow_many:
1718                    for inner_pos, p in enumerate(pathinfos):
1719                        if p.m2m:
1720                            cur_names_with_path[1].extend(pathinfos[0 : inner_pos + 1])
1721                            names_with_path.append(cur_names_with_path)
1722                            raise MultiJoin(pos + 1, names_with_path)
1723                last = pathinfos[-1]
1724                path.extend(pathinfos)
1725                final_field = last.join_field
1726                meta = last.to_meta
1727                targets = last.target_fields
1728                cur_names_with_path[1].extend(pathinfos)
1729                names_with_path.append(cur_names_with_path)
1730            else:
1731                # Local non-relational field.
1732                final_field = field
1733                targets = (field,)
1734                if fail_on_missing and pos + 1 != len(names):
1735                    raise FieldError(
1736                        f"Cannot resolve keyword {names[pos + 1]!r} into field. Join on '{name}'"
1737                        " not permitted."
1738                    )
1739                break
1740        return path, final_field, targets, names[pos + 1 :]
1741
1742    def setup_joins(
1743        self,
1744        names: list[str],
1745        meta: Meta,
1746        alias: str,
1747        can_reuse: set[str] | None = None,
1748        allow_many: bool = True,
1749        reuse_with_filtered_relation: bool = False,
1750    ) -> JoinInfo:
1751        """
1752        Compute the necessary table joins for the passage through the fields
1753        given in 'names'. 'meta' is the Meta for the current model
1754        (which gives the table we are starting from), 'alias' is the alias for
1755        the table to start the joining from.
1756
1757        The 'can_reuse' defines the reverse foreign key joins we can reuse. It
1758        can be None in which case all joins are reusable or a set of aliases
1759        that can be reused. Note that non-reverse foreign keys are always
1760        reusable when using setup_joins().
1761
1762        The 'reuse_with_filtered_relation' can be used to force 'can_reuse'
1763        parameter and force the relation on the given connections.
1764
1765        If 'allow_many' is False, then any reverse foreign key seen will
1766        generate a MultiJoin exception.
1767
1768        Return the final field involved in the joins, the target field (used
1769        for any 'where' constraint), the final 'opts' value, the joins, the
1770        field path traveled to generate the joins, and a transform function
1771        that takes a field and alias and is equivalent to `field.get_col(alias)`
1772        in the simple case but wraps field transforms if they were included in
1773        names.
1774
1775        The target field is the field containing the concrete value. Final
1776        field can be something different, for example foreign key pointing to
1777        that value. Final field is needed for example in some value
1778        conversions (convert 'obj' in fk__id=obj to pk val using the foreign
1779        key field for example).
1780        """
1781        joins = [alias]
1782        # The transform can't be applied yet, as joins must be trimmed later.
1783        # To avoid making every caller of this method look up transforms
1784        # directly, compute transforms here and create a partial that converts
1785        # fields to the appropriate wrapped version.
1786
1787        def final_transformer(field: Field, alias: str | None) -> Col:
1788            if not self.alias_cols:
1789                alias = None
1790            return field.get_col(alias)  # type: ignore[arg-type]
1791
1792        # Try resolving all the names as fields first. If there's an error,
1793        # treat trailing names as lookups until a field can be resolved.
1794        last_field_exception = None
1795        for pivot in range(len(names), 0, -1):
1796            try:
1797                path, final_field, targets, rest = self.names_to_path(
1798                    names[:pivot],
1799                    meta,
1800                    allow_many,
1801                    fail_on_missing=True,
1802                )
1803            except FieldError as exc:
1804                if pivot == 1:
1805                    # The first item cannot be a lookup, so it's safe
1806                    # to raise the field error here.
1807                    raise
1808                else:
1809                    last_field_exception = exc
1810            else:
1811                # The transforms are the remaining items that couldn't be
1812                # resolved into fields.
1813                transforms = names[pivot:]
1814                break
1815        for name in transforms:
1816
1817            def transform(
1818                field: Field, alias: str | None, *, name: str, previous: Any
1819            ) -> BaseExpression | MultiColSource:
1820                try:
1821                    wrapped = previous(field, alias)
1822                    return self.try_transform(wrapped, name)
1823                except FieldError:
1824                    # FieldError is raised if the transform doesn't exist.
1825                    if isinstance(final_field, Field) and last_field_exception:
1826                        raise last_field_exception
1827                    else:
1828                        raise
1829
1830            final_transformer = functools.partial(  # type: ignore[misc]
1831                transform, name=name, previous=final_transformer
1832            )
1833            final_transformer.has_transforms = True  # type: ignore[attr-defined]
1834        # Then, add the path to the query's joins. Note that we can't trim
1835        # joins at this stage - we will need the information about join type
1836        # of the trimmed joins.
1837        for join in path:
1838            if join.filtered_relation:
1839                filtered_relation = join.filtered_relation.clone()
1840                table_alias = filtered_relation.alias
1841            else:
1842                filtered_relation = None
1843                table_alias = None
1844            meta = join.to_meta
1845            if join.direct:
1846                nullable = self.is_nullable(join.join_field)
1847            else:
1848                nullable = True
1849            connection = self.join_class(
1850                meta.model.model_options.db_table,
1851                alias,
1852                table_alias,
1853                INNER,
1854                join.join_field,
1855                nullable,
1856                filtered_relation=filtered_relation,
1857            )
1858            reuse = can_reuse if join.m2m or reuse_with_filtered_relation else None
1859            alias = self.join(
1860                connection,
1861                reuse=reuse,
1862                reuse_with_filtered_relation=reuse_with_filtered_relation,
1863            )
1864            joins.append(alias)
1865            if filtered_relation:
1866                filtered_relation.path = joins[:]
1867        return JoinInfo(final_field, targets, meta, joins, path, final_transformer)
1868
1869    def trim_joins(
1870        self, targets: tuple[Field, ...], joins: list[str], path: list[Any]
1871    ) -> tuple[tuple[Field, ...], str, list[str]]:
1872        """
1873        The 'target' parameter is the final field being joined to, 'joins'
1874        is the full list of join aliases. The 'path' contain the PathInfos
1875        used to create the joins.
1876
1877        Return the final target field and table alias and the new active
1878        joins.
1879
1880        Always trim any direct join if the target column is already in the
1881        previous table. Can't trim reverse joins as it's unknown if there's
1882        anything on the other side of the join.
1883        """
1884        joins = joins[:]
1885        for pos, info in enumerate(reversed(path)):
1886            if len(joins) == 1 or not info.direct:
1887                break
1888            if info.filtered_relation:
1889                break
1890            join_targets = {t.column for t in info.join_field.foreign_related_fields}
1891            cur_targets = {t.column for t in targets}
1892            if not cur_targets.issubset(join_targets):
1893                break
1894            targets_dict = {
1895                r[1].column: r[0]
1896                for r in info.join_field.related_fields
1897                if r[1].column in cur_targets
1898            }
1899            targets = tuple(targets_dict[t.column] for t in targets)
1900            self.unref_alias(joins.pop())
1901        return targets, joins[-1], joins
1902
1903    @classmethod
1904    def _gen_cols(
1905        cls,
1906        exprs: Iterable[Any],
1907        include_external: bool = False,
1908        resolve_refs: bool = True,
1909    ) -> TypingIterator[Col]:
1910        for expr in exprs:
1911            if isinstance(expr, Col):
1912                yield expr
1913            elif include_external and callable(
1914                getattr(expr, "get_external_cols", None)
1915            ):
1916                yield from expr.get_external_cols()
1917            elif hasattr(expr, "get_source_expressions"):
1918                if not resolve_refs and isinstance(expr, Ref):
1919                    continue
1920                yield from cls._gen_cols(
1921                    expr.get_source_expressions(),
1922                    include_external=include_external,
1923                    resolve_refs=resolve_refs,
1924                )
1925
1926    @classmethod
1927    def _gen_col_aliases(cls, exprs: Iterable[Any]) -> TypingIterator[str]:
1928        yield from (expr.alias for expr in cls._gen_cols(exprs))
1929
1930    def resolve_ref(
1931        self,
1932        name: str,
1933        allow_joins: bool = True,
1934        reuse: set[str] | None = None,
1935        summarize: bool = False,
1936    ) -> BaseExpression | MultiColSource:
1937        annotation = self.annotations.get(name)
1938        if annotation is not None:
1939            if not allow_joins:
1940                for alias in self._gen_col_aliases([annotation]):
1941                    if isinstance(self.alias_map[alias], Join):
1942                        raise FieldError(
1943                            "Joined field references are not permitted in this query"
1944                        )
1945            if summarize:
1946                # Summarize currently means we are doing an aggregate() query
1947                # which is executed as a wrapped subquery if any of the
1948                # aggregate() elements reference an existing annotation. In
1949                # that case we need to return a Ref to the subquery's annotation.
1950                if name not in self.annotation_select:
1951                    raise FieldError(
1952                        f"Cannot aggregate over the '{name}' alias. Use annotate() "
1953                        "to promote it."
1954                    )
1955                return Ref(name, self.annotation_select[name])
1956            else:
1957                return annotation
1958        else:
1959            field_list = name.split(LOOKUP_SEP)
1960            annotation = self.annotations.get(field_list[0])
1961            if annotation is not None:
1962                for transform in field_list[1:]:
1963                    annotation = self.try_transform(annotation, transform)
1964                return annotation
1965            initial_alias = self.get_initial_alias()
1966            assert initial_alias is not None
1967            join_info = self.setup_joins(
1968                field_list,
1969                self.get_model_meta(),
1970                initial_alias,
1971                can_reuse=reuse,
1972            )
1973            targets, final_alias, join_list = self.trim_joins(
1974                join_info.targets, join_info.joins, join_info.path
1975            )
1976            if not allow_joins and len(join_list) > 1:
1977                raise FieldError(
1978                    "Joined field references are not permitted in this query"
1979                )
1980            if len(targets) > 1:
1981                raise FieldError(
1982                    "Referencing multicolumn fields with F() objects isn't supported"
1983                )
1984            # Verify that the last lookup in name is a field or a transform:
1985            # transform_function() raises FieldError if not.
1986            transform = join_info.transform_function(targets[0], final_alias)
1987            if reuse is not None:
1988                reuse.update(join_list)
1989            return transform
1990
1991    def split_exclude(
1992        self,
1993        filter_expr: tuple[str, Any],
1994        can_reuse: set[str],
1995        names_with_path: list[tuple[str, list[Any]]],
1996    ) -> tuple[WhereNode, set[str] | tuple[()]]:
1997        """
1998        When doing an exclude against any kind of N-to-many relation, we need
1999        to use a subquery. This method constructs the nested query, given the
2000        original exclude filter (filter_expr) and the portion up to the first
2001        N-to-many relation field.
2002
2003        For example, if the origin filter is ~Q(child__name='foo'), filter_expr
2004        is ('child__name', 'foo') and can_reuse is a set of joins usable for
2005        filters in the original query.
2006
2007        We will turn this into equivalent of:
2008            WHERE NOT EXISTS(
2009                SELECT 1
2010                FROM child
2011                WHERE name = 'foo' AND child.parent_id = parent.id
2012                LIMIT 1
2013            )
2014        """
2015        # Generate the inner query.
2016        query = self.__class__(self.model)
2017        query._filtered_relations = self._filtered_relations
2018        filter_lhs, filter_rhs = filter_expr
2019        if isinstance(filter_rhs, OuterRef):
2020            filter_rhs = OuterRef(filter_rhs)
2021        elif isinstance(filter_rhs, F):
2022            filter_rhs = OuterRef(filter_rhs.name)
2023        query.add_filter(filter_lhs, filter_rhs)
2024        query.clear_ordering(force=True)
2025        # Try to have as simple as possible subquery -> trim leading joins from
2026        # the subquery.
2027        trimmed_prefix, contains_louter = query.trim_start(names_with_path)
2028
2029        col = query.select[0]
2030        select_field = col.target
2031        alias = col.alias
2032        if alias in can_reuse:
2033            id_field = select_field.model._model_meta.get_field("id")
2034            # Need to add a restriction so that outer query's filters are in effect for
2035            # the subquery, too.
2036            query.bump_prefix(self)
2037            lookup_class = select_field.get_lookup("exact")
2038            # Note that the query.select[0].alias is different from alias
2039            # due to bump_prefix above.
2040            lookup = lookup_class(
2041                id_field.get_col(query.select[0].alias), id_field.get_col(alias)
2042            )
2043            query.where.add(lookup, AND)
2044            query.external_aliases[alias] = True
2045
2046        lookup_class = select_field.get_lookup("exact")
2047        lookup = lookup_class(col, ResolvedOuterRef(trimmed_prefix))
2048        query.where.add(lookup, AND)
2049        condition, needed_inner = self.build_filter(Exists(query))
2050
2051        if contains_louter:
2052            or_null_condition, _ = self.build_filter(
2053                (f"{trimmed_prefix}__isnull", True),
2054                current_negated=True,
2055                branch_negated=True,
2056                can_reuse=can_reuse,
2057            )
2058            condition.add(or_null_condition, OR)
2059            # Note that the end result will be:
2060            # (outercol NOT IN innerq AND outercol IS NOT NULL) OR outercol IS NULL.
2061            # This might look crazy but due to how IN works, this seems to be
2062            # correct. If the IS NOT NULL check is removed then outercol NOT
2063            # IN will return UNKNOWN. If the IS NULL check is removed, then if
2064            # outercol IS NULL we will not match the row.
2065        return condition, needed_inner
2066
2067    def set_empty(self) -> None:
2068        self.where.add(NothingNode(), AND)
2069        for query in self.combined_queries:
2070            query.set_empty()
2071
2072    def is_empty(self) -> bool:
2073        return any(isinstance(c, NothingNode) for c in self.where.children)
2074
2075    def set_limits(self, low: int | None = None, high: int | None = None) -> None:
2076        """
2077        Adjust the limits on the rows retrieved. Use low/high to set these,
2078        as it makes it more Pythonic to read and write. When the SQL query is
2079        created, convert them to the appropriate offset and limit values.
2080
2081        Apply any limits passed in here to the existing constraints. Add low
2082        to the current low value and clamp both to any existing high value.
2083        """
2084        if high is not None:
2085            if self.high_mark is not None:
2086                self.high_mark = min(self.high_mark, self.low_mark + high)
2087            else:
2088                self.high_mark = self.low_mark + high
2089        if low is not None:
2090            if self.high_mark is not None:
2091                self.low_mark = min(self.high_mark, self.low_mark + low)
2092            else:
2093                self.low_mark = self.low_mark + low
2094
2095        if self.low_mark == self.high_mark:
2096            self.set_empty()
2097
2098    def clear_limits(self) -> None:
2099        """Clear any existing limits."""
2100        self.low_mark, self.high_mark = 0, None
2101
2102    @property
2103    def is_sliced(self) -> bool:
2104        return self.low_mark != 0 or self.high_mark is not None
2105
2106    def has_limit_one(self) -> bool:
2107        return self.high_mark is not None and (self.high_mark - self.low_mark) == 1
2108
2109    def can_filter(self) -> bool:
2110        """
2111        Return True if adding filters to this instance is still possible.
2112
2113        Typically, this means no limits or offsets have been put on the results.
2114        """
2115        return not self.is_sliced
2116
2117    def clear_select_clause(self) -> None:
2118        """Remove all fields from SELECT clause."""
2119        self.select = ()
2120        self.default_cols = False
2121        self.select_related = False
2122        self.set_extra_mask(())
2123        self.set_annotation_mask(())
2124
2125    def clear_select_fields(self) -> None:
2126        """
2127        Clear the list of fields to select (but not extra_select columns).
2128        Some queryset types completely replace any existing list of select
2129        columns.
2130        """
2131        self.select = ()
2132        self.values_select = ()
2133
2134    def add_select_col(self, col: Col, name: str) -> None:
2135        self.select += (col,)
2136        self.values_select += (name,)
2137
2138    def set_select(self, cols: list[Col] | tuple[Col, ...]) -> None:
2139        self.default_cols = False
2140        self.select = tuple(cols)
2141
2142    def add_distinct_fields(self, *field_names: str) -> None:
2143        """
2144        Add and resolve the given fields to the query's "distinct on" clause.
2145        """
2146        self.distinct_fields = field_names
2147        self.distinct = True
2148
2149    def add_fields(
2150        self, field_names: list[str] | TypingIterator[str], allow_m2m: bool = True
2151    ) -> None:
2152        """
2153        Add the given (model) fields to the select set. Add the field names in
2154        the order specified.
2155        """
2156        alias = self.get_initial_alias()
2157        assert alias is not None
2158        meta = self.get_model_meta()
2159
2160        try:
2161            cols = []
2162            for name in field_names:
2163                # Join promotion note - we must not remove any rows here, so
2164                # if there is no existing joins, use outer join.
2165                join_info = self.setup_joins(
2166                    name.split(LOOKUP_SEP), meta, alias, allow_many=allow_m2m
2167                )
2168                targets, final_alias, joins = self.trim_joins(
2169                    join_info.targets,
2170                    join_info.joins,
2171                    join_info.path,
2172                )
2173                for target in targets:
2174                    cols.append(join_info.transform_function(target, final_alias))
2175            if cols:
2176                self.set_select(cols)
2177        except MultiJoin:
2178            raise FieldError(f"Invalid field name: '{name}'")
2179        except FieldError:
2180            if LOOKUP_SEP in name:
2181                # For lookups spanning over relationships, show the error
2182                # from the model on which the lookup failed.
2183                raise
2184            elif name in self.annotations:
2185                raise FieldError(
2186                    f"Cannot select the '{name}' alias. Use annotate() to promote it."
2187                )
2188            else:
2189                names = sorted(
2190                    [
2191                        *get_field_names_from_opts(meta),
2192                        *self.extra,
2193                        *self.annotation_select,
2194                        *self._filtered_relations,
2195                    ]
2196                )
2197                raise FieldError(
2198                    "Cannot resolve keyword {!r} into field. Choices are: {}".format(
2199                        name, ", ".join(names)
2200                    )
2201                )
2202
2203    def add_ordering(self, *ordering: str | BaseExpression) -> None:
2204        """
2205        Add items from the 'ordering' sequence to the query's "order by"
2206        clause. These items are either field names (not column names) --
2207        possibly with a direction prefix ('-' or '?') -- or OrderBy
2208        expressions.
2209
2210        If 'ordering' is empty, clear all ordering from the query.
2211        """
2212        errors = []
2213        for item in ordering:
2214            if isinstance(item, str):
2215                if item == "?":
2216                    continue
2217                item = item.removeprefix("-")
2218                if item in self.annotations:
2219                    continue
2220                if self.extra and item in self.extra:
2221                    continue
2222                # names_to_path() validates the lookup. A descriptive
2223                # FieldError will be raise if it's not.
2224                self.names_to_path(item.split(LOOKUP_SEP), self.model._model_meta)
2225            elif not hasattr(item, "resolve_expression"):
2226                errors.append(item)
2227            if getattr(item, "contains_aggregate", False):
2228                raise FieldError(
2229                    "Using an aggregate in order_by() without also including "
2230                    f"it in annotate() is not allowed: {item}"
2231                )
2232        if errors:
2233            raise FieldError(f"Invalid order_by arguments: {errors}")
2234        if ordering:
2235            self.order_by += ordering
2236        else:
2237            self.default_ordering = False
2238
2239    def clear_ordering(self, force: bool = False, clear_default: bool = True) -> None:
2240        """
2241        Remove any ordering settings if the current query allows it without
2242        side effects, set 'force' to True to clear the ordering regardless.
2243        If 'clear_default' is True, there will be no ordering in the resulting
2244        query (not even the model's default).
2245        """
2246        if not force and (
2247            self.is_sliced or self.distinct_fields or self.select_for_update
2248        ):
2249            return
2250        self.order_by = ()
2251        self.extra_order_by = ()
2252        if clear_default:
2253            self.default_ordering = False
2254
2255    def set_group_by(self, allow_aliases: bool = True) -> None:
2256        """
2257        Expand the GROUP BY clause required by the query.
2258
2259        This will usually be the set of all non-aggregate fields in the
2260        return data. If the database backend supports grouping by the
2261        primary key, and the query would be equivalent, the optimization
2262        will be made automatically.
2263        """
2264        if allow_aliases and self.values_select:
2265            # If grouping by aliases is allowed assign selected value aliases
2266            # by moving them to annotations.
2267            group_by_annotations = {}
2268            values_select = {}
2269            for alias, expr in zip(self.values_select, self.select):
2270                if isinstance(expr, Col):
2271                    values_select[alias] = expr
2272                else:
2273                    group_by_annotations[alias] = expr
2274            self.annotations = {**group_by_annotations, **self.annotations}
2275            self.append_annotation_mask(group_by_annotations)
2276            self.select = tuple(values_select.values())
2277            self.values_select = tuple(values_select)
2278        group_by = list(self.select)
2279        for alias, annotation in self.annotation_select.items():
2280            if not (group_by_cols := annotation.get_group_by_cols()):
2281                continue
2282            if allow_aliases and not annotation.contains_aggregate:
2283                group_by.append(Ref(alias, annotation))
2284            else:
2285                group_by.extend(group_by_cols)
2286        self.group_by = tuple(group_by)
2287
2288    def add_select_related(self, fields: list[str]) -> None:
2289        """
2290        Set up the select_related data structure so that we only select
2291        certain related models (as opposed to all models, when
2292        self.select_related=True).
2293        """
2294        if isinstance(self.select_related, bool):
2295            field_dict: dict[str, Any] = {}
2296        else:
2297            field_dict = self.select_related
2298        for field in fields:
2299            d = field_dict
2300            for part in field.split(LOOKUP_SEP):
2301                d = d.setdefault(part, {})
2302        self.select_related = field_dict
2303
2304    def add_extra(
2305        self,
2306        select: dict[str, str],
2307        select_params: list[Any] | None,
2308        where: list[str],
2309        params: list[Any],
2310        tables: list[str],
2311        order_by: tuple[str, ...],
2312    ) -> None:
2313        """
2314        Add data to the various extra_* attributes for user-created additions
2315        to the query.
2316        """
2317        if select:
2318            # We need to pair any placeholder markers in the 'select'
2319            # dictionary with their parameters in 'select_params' so that
2320            # subsequent updates to the select dictionary also adjust the
2321            # parameters appropriately.
2322            select_pairs = {}
2323            if select_params:
2324                param_iter = iter(select_params)
2325            else:
2326                param_iter = iter([])
2327            for name, entry in select.items():
2328                self.check_alias(name)
2329                entry = str(entry)
2330                entry_params = []
2331                pos = entry.find("%s")
2332                while pos != -1:
2333                    if pos == 0 or entry[pos - 1] != "%":
2334                        entry_params.append(next(param_iter))
2335                    pos = entry.find("%s", pos + 2)
2336                select_pairs[name] = (entry, entry_params)
2337            self.extra.update(select_pairs)
2338        if where or params:
2339            self.where.add(ExtraWhere(where, params), AND)
2340        if tables:
2341            self.extra_tables += tuple(tables)
2342        if order_by:
2343            self.extra_order_by = order_by
2344
2345    def clear_deferred_loading(self) -> None:
2346        """Remove any fields from the deferred loading set."""
2347        self.deferred_loading = (frozenset(), True)
2348
2349    def add_deferred_loading(self, field_names: frozenset[str]) -> None:
2350        """
2351        Add the given list of model field names to the set of fields to
2352        exclude from loading from the database when automatic column selection
2353        is done. Add the new field names to any existing field names that
2354        are deferred (or removed from any existing field names that are marked
2355        as the only ones for immediate loading).
2356        """
2357        # Fields on related models are stored in the literal double-underscore
2358        # format, so that we can use a set datastructure. We do the foo__bar
2359        # splitting and handling when computing the SQL column names (as part of
2360        # get_columns()).
2361        existing, defer = self.deferred_loading
2362        existing_set = set(existing)
2363        if defer:
2364            # Add to existing deferred names.
2365            self.deferred_loading = frozenset(existing_set.union(field_names)), True
2366        else:
2367            # Remove names from the set of any existing "immediate load" names.
2368            if new_existing := existing_set.difference(field_names):
2369                self.deferred_loading = frozenset(new_existing), False
2370            else:
2371                self.clear_deferred_loading()
2372                if new_only := set(field_names).difference(existing_set):
2373                    self.deferred_loading = frozenset(new_only), True
2374
2375    def add_immediate_loading(self, field_names: list[str] | set[str]) -> None:
2376        """
2377        Add the given list of model field names to the set of fields to
2378        retrieve when the SQL is executed ("immediate loading" fields). The
2379        field names replace any existing immediate loading field names. If
2380        there are field names already specified for deferred loading, remove
2381        those names from the new field_names before storing the new names
2382        for immediate loading. (That is, immediate loading overrides any
2383        existing immediate values, but respects existing deferrals.)
2384        """
2385        existing, defer = self.deferred_loading
2386        field_names_set = set(field_names)
2387
2388        if defer:
2389            # Remove any existing deferred names from the current set before
2390            # setting the new names.
2391            self.deferred_loading = (
2392                frozenset(field_names_set.difference(existing)),
2393                False,
2394            )
2395        else:
2396            # Replace any existing "immediate load" field names.
2397            self.deferred_loading = frozenset(field_names_set), False
2398
2399    def set_annotation_mask(
2400        self,
2401        names: set[str]
2402        | frozenset[str]
2403        | list[str]
2404        | tuple[str, ...]
2405        | dict[str, Any]
2406        | None,
2407    ) -> None:  # type: ignore[misc]
2408        """Set the mask of annotations that will be returned by the SELECT."""
2409        if names is None:
2410            self.annotation_select_mask = None
2411        else:
2412            self.annotation_select_mask = set(names)
2413        self._annotation_select_cache = None
2414
2415    def append_annotation_mask(self, names: list[str] | dict[str, Any]) -> None:
2416        if self.annotation_select_mask is not None:
2417            self.set_annotation_mask(self.annotation_select_mask.union(names))
2418
2419    def set_extra_mask(
2420        self, names: set[str] | list[str] | tuple[str, ...] | None
2421    ) -> None:
2422        """
2423        Set the mask of extra select items that will be returned by SELECT.
2424        Don't remove them from the Query since they might be used later.
2425        """
2426        if names is None:
2427            self.extra_select_mask = None
2428        else:
2429            self.extra_select_mask = set(names)
2430        self._extra_select_cache = None
2431
2432    def set_values(self, fields: list[str]) -> None:
2433        self.select_related = False
2434        self.clear_deferred_loading()
2435        self.clear_select_fields()
2436        self.has_select_fields = True
2437
2438        if fields:
2439            field_names = []
2440            extra_names = []
2441            annotation_names = []
2442            if not self.extra and not self.annotations:
2443                # Shortcut - if there are no extra or annotations, then
2444                # the values() clause must be just field names.
2445                field_names = list(fields)
2446            else:
2447                self.default_cols = False
2448                for f in fields:
2449                    if f in self.extra_select:
2450                        extra_names.append(f)
2451                    elif f in self.annotation_select:
2452                        annotation_names.append(f)
2453                    else:
2454                        field_names.append(f)
2455            self.set_extra_mask(extra_names)
2456            self.set_annotation_mask(annotation_names)
2457            selected = frozenset(field_names + extra_names + annotation_names)
2458        else:
2459            field_names = [f.attname for f in self.model._model_meta.concrete_fields]
2460            selected = frozenset(field_names)
2461        # Selected annotations must be known before setting the GROUP BY
2462        # clause.
2463        if self.group_by is True:
2464            self.add_fields(
2465                (f.attname for f in self.model._model_meta.concrete_fields), False
2466            )
2467            # Disable GROUP BY aliases to avoid orphaning references to the
2468            # SELECT clause which is about to be cleared.
2469            self.set_group_by(allow_aliases=False)
2470            self.clear_select_fields()
2471        elif self.group_by:
2472            # Resolve GROUP BY annotation references if they are not part of
2473            # the selected fields anymore.
2474            group_by = []
2475            for expr in self.group_by:
2476                if isinstance(expr, Ref) and expr.refs not in selected:
2477                    expr = self.annotations[expr.refs]
2478                group_by.append(expr)
2479            self.group_by = tuple(group_by)
2480
2481        self.values_select = tuple(field_names)
2482        self.add_fields(field_names, True)
2483
2484    @property
2485    def annotation_select(self) -> dict[str, BaseExpression]:
2486        """
2487        Return the dictionary of aggregate columns that are not masked and
2488        should be used in the SELECT clause. Cache this result for performance.
2489        """
2490        if self._annotation_select_cache is not None:
2491            return self._annotation_select_cache
2492        elif not self.annotations:
2493            return {}
2494        elif self.annotation_select_mask is not None:
2495            self._annotation_select_cache = {
2496                k: v
2497                for k, v in self.annotations.items()
2498                if k in self.annotation_select_mask
2499            }
2500            return self._annotation_select_cache
2501        else:
2502            return self.annotations
2503
2504    @property
2505    def extra_select(self) -> dict[str, tuple[str, list[Any]]]:
2506        if self._extra_select_cache is not None:
2507            return self._extra_select_cache
2508        if not self.extra:
2509            return {}
2510        elif self.extra_select_mask is not None:
2511            self._extra_select_cache = {
2512                k: v for k, v in self.extra.items() if k in self.extra_select_mask
2513            }
2514            return self._extra_select_cache
2515        else:
2516            return self.extra
2517
2518    def trim_start(
2519        self, names_with_path: list[tuple[str, list[Any]]]
2520    ) -> tuple[str, bool]:
2521        """
2522        Trim joins from the start of the join path. The candidates for trim
2523        are the PathInfos in names_with_path structure that are m2m joins.
2524
2525        Also set the select column so the start matches the join.
2526
2527        This method is meant to be used for generating the subquery joins &
2528        cols in split_exclude().
2529
2530        Return a lookup usable for doing outerq.filter(lookup=self) and a
2531        boolean indicating if the joins in the prefix contain a LEFT OUTER join.
2532        _"""
2533        all_paths = []
2534        for _, paths in names_with_path:
2535            all_paths.extend(paths)
2536        contains_louter = False
2537        # Trim and operate only on tables that were generated for
2538        # the lookup part of the query. That is, avoid trimming
2539        # joins generated for F() expressions.
2540        lookup_tables = [
2541            t for t in self.alias_map if t in self._lookup_joins or t == self.base_table
2542        ]
2543        for trimmed_paths, path in enumerate(all_paths):
2544            if path.m2m:
2545                break
2546            if self.alias_map[lookup_tables[trimmed_paths + 1]].join_type == LOUTER:
2547                contains_louter = True
2548            alias = lookup_tables[trimmed_paths]
2549            self.unref_alias(alias)
2550        # The path.join_field is a Rel, lets get the other side's field
2551        join_field = path.join_field.field
2552        # Build the filter prefix.
2553        paths_in_prefix = trimmed_paths
2554        trimmed_prefix = []
2555        for name, path in names_with_path:
2556            if paths_in_prefix - len(path) < 0:
2557                break
2558            trimmed_prefix.append(name)
2559            paths_in_prefix -= len(path)
2560        trimmed_prefix.append(join_field.foreign_related_fields[0].name)
2561        trimmed_prefix = LOOKUP_SEP.join(trimmed_prefix)
2562        # Lets still see if we can trim the first join from the inner query
2563        # (that is, self). We can't do this for:
2564        # - LEFT JOINs because we would miss those rows that have nothing on
2565        #   the outer side,
2566        # - INNER JOINs from filtered relations because we would miss their
2567        #   filters.
2568        first_join = self.alias_map[lookup_tables[trimmed_paths + 1]]
2569        if first_join.join_type != LOUTER and not first_join.filtered_relation:
2570            select_fields = [r[0] for r in join_field.related_fields]
2571            select_alias = lookup_tables[trimmed_paths + 1]
2572            self.unref_alias(lookup_tables[trimmed_paths])
2573            extra_restriction = join_field.get_extra_restriction(
2574                None, lookup_tables[trimmed_paths + 1]
2575            )
2576            if extra_restriction:
2577                self.where.add(extra_restriction, AND)
2578        else:
2579            # TODO: It might be possible to trim more joins from the start of the
2580            # inner query if it happens to have a longer join chain containing the
2581            # values in select_fields. Lets punt this one for now.
2582            select_fields = [r[1] for r in join_field.related_fields]
2583            select_alias = lookup_tables[trimmed_paths]
2584        # The found starting point is likely a join_class instead of a
2585        # base_table_class reference. But the first entry in the query's FROM
2586        # clause must not be a JOIN.
2587        for table in self.alias_map:
2588            if self.alias_refcount[table] > 0:
2589                self.alias_map[table] = self.base_table_class(
2590                    self.alias_map[table].table_name,
2591                    table,
2592                )
2593                break
2594        self.set_select([f.get_col(select_alias) for f in select_fields])
2595        return trimmed_prefix, contains_louter
2596
2597    def is_nullable(self, field: Field) -> bool:
2598        """Check if the given field should be treated as nullable."""
2599        # QuerySet does not have knowledge of which connection is going to be
2600        # used. For the single-database setup we always reference the default
2601        # connection here.
2602        return field.allow_null
2603
2604
2605def get_order_dir(field: str, default: str = "ASC") -> tuple[str, str]:
2606    """
2607    Return the field name and direction for an order specification. For
2608    example, '-foo' is returned as ('foo', 'DESC').
2609
2610    The 'default' param is used to indicate which way no prefix (or a '+'
2611    prefix) should sort. The '-' prefix always sorts the opposite way.
2612    """
2613    dirn = ORDER_DIR[default]
2614    if field[0] == "-":
2615        return field[1:], dirn[1]
2616    return field, dirn[0]
2617
2618
2619class JoinPromoter:
2620    """
2621    A class to abstract away join promotion problems for complex filter
2622    conditions.
2623    """
2624
2625    def __init__(self, connector: str, num_children: int, negated: bool):
2626        self.connector = connector
2627        self.negated = negated
2628        if self.negated:
2629            if connector == AND:
2630                self.effective_connector = OR
2631            else:
2632                self.effective_connector = AND
2633        else:
2634            self.effective_connector = self.connector
2635        self.num_children = num_children
2636        # Maps of table alias to how many times it is seen as required for
2637        # inner and/or outer joins.
2638        self.votes = Counter()
2639
2640    def __repr__(self) -> str:
2641        return (
2642            f"{self.__class__.__qualname__}(connector={self.connector!r}, "
2643            f"num_children={self.num_children!r}, negated={self.negated!r})"
2644        )
2645
2646    def add_votes(self, votes: Any) -> None:
2647        """
2648        Add single vote per item to self.votes. Parameter can be any
2649        iterable.
2650        """
2651        self.votes.update(votes)
2652
2653    def update_join_types(self, query: Query) -> set[str]:
2654        """
2655        Change join types so that the generated query is as efficient as
2656        possible, but still correct. So, change as many joins as possible
2657        to INNER, but don't make OUTER joins INNER if that could remove
2658        results from the query.
2659        """
2660        to_promote = set()
2661        to_demote = set()
2662        # The effective_connector is used so that NOT (a AND b) is treated
2663        # similarly to (a OR b) for join promotion.
2664        for table, votes in self.votes.items():
2665            # We must use outer joins in OR case when the join isn't contained
2666            # in all of the joins. Otherwise the INNER JOIN itself could remove
2667            # valid results. Consider the case where a model with rel_a and
2668            # rel_b relations is queried with rel_a__col=1 | rel_b__col=2. Now,
2669            # if rel_a join doesn't produce any results is null (for example
2670            # reverse foreign key or null value in direct foreign key), and
2671            # there is a matching row in rel_b with col=2, then an INNER join
2672            # to rel_a would remove a valid match from the query. So, we need
2673            # to promote any existing INNER to LOUTER (it is possible this
2674            # promotion in turn will be demoted later on).
2675            if self.effective_connector == OR and votes < self.num_children:
2676                to_promote.add(table)
2677            # If connector is AND and there is a filter that can match only
2678            # when there is a joinable row, then use INNER. For example, in
2679            # rel_a__col=1 & rel_b__col=2, if either of the rels produce NULL
2680            # as join output, then the col=1 or col=2 can't match (as
2681            # NULL=anything is always false).
2682            # For the OR case, if all children voted for a join to be inner,
2683            # then we can use INNER for the join. For example:
2684            #     (rel_a__col__icontains=Alex | rel_a__col__icontains=Russell)
2685            # then if rel_a doesn't produce any rows, the whole condition
2686            # can't match. Hence we can safely use INNER join.
2687            if self.effective_connector == AND or (
2688                self.effective_connector == OR and votes == self.num_children
2689            ):
2690                to_demote.add(table)
2691            # Finally, what happens in cases where we have:
2692            #    (rel_a__col=1|rel_b__col=2) & rel_a__col__gte=0
2693            # Now, we first generate the OR clause, and promote joins for it
2694            # in the first if branch above. Both rel_a and rel_b are promoted
2695            # to LOUTER joins. After that we do the AND case. The OR case
2696            # voted no inner joins but the rel_a__col__gte=0 votes inner join
2697            # for rel_a. We demote it back to INNER join (in AND case a single
2698            # vote is enough). The demotion is OK, if rel_a doesn't produce
2699            # rows, then the rel_a__col__gte=0 clause can't be true, and thus
2700            # the whole clause must be false. So, it is safe to use INNER
2701            # join.
2702            # Note that in this example we could just as well have the __gte
2703            # clause and the OR clause swapped. Or we could replace the __gte
2704            # clause with an OR clause containing rel_a__col=1|rel_a__col=2,
2705            # and again we could safely demote to INNER.
2706        query.promote_joins(to_promote)
2707        query.demote_joins(to_demote)
2708        return to_demote