1# sql/elements.py
2# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
7# mypy: allow-untyped-defs, allow-untyped-calls
8
9"""Core SQL expression elements, including :class:`_expression.ClauseElement`,
10:class:`_expression.ColumnElement`, and derived classes.
11
12"""
13
14from __future__ import annotations
15
16from decimal import Decimal
17from enum import Enum
18import itertools
19import operator
20import re
21import typing
22from typing import AbstractSet
23from typing import Any
24from typing import Callable
25from typing import cast
26from typing import Dict
27from typing import FrozenSet
28from typing import Generic
29from typing import Iterable
30from typing import Iterator
31from typing import List
32from typing import Literal
33from typing import Mapping
34from typing import Optional
35from typing import overload
36from typing import ParamSpec
37from typing import Sequence
38from typing import Set
39from typing import Tuple as typing_Tuple
40from typing import Type
41from typing import TYPE_CHECKING
42from typing import TypeVar
43from typing import Union
44
45from . import coercions
46from . import operators
47from . import roles
48from . import traversals
49from . import type_api
50from ._typing import has_schema_attr
51from ._typing import is_named_from_clause
52from ._typing import is_quoted_name
53from ._typing import is_tuple_type
54from .annotation import Annotated
55from .annotation import SupportsWrappingAnnotations
56from .base import _clone
57from .base import _expand_cloned
58from .base import _generative
59from .base import _NoArg
60from .base import Executable
61from .base import Generative
62from .base import HasMemoized
63from .base import Immutable
64from .base import NO_ARG
65from .base import SingletonConstant
66from .cache_key import MemoizedHasCacheKey
67from .cache_key import NO_CACHE
68from .coercions import _document_text_coercion # noqa
69from .operators import ColumnOperators
70from .operators import OperatorClass
71from .traversals import HasCopyInternals
72from .visitors import cloned_traverse
73from .visitors import ExternallyTraversible
74from .visitors import InternalTraversal
75from .visitors import traverse
76from .visitors import Visitable
77from .. import exc
78from .. import inspection
79from .. import util
80from ..util import HasMemoized_ro_memoized_attribute
81from ..util import TypingOnly
82from ..util.typing import Self
83from ..util.typing import TupleAny
84from ..util.typing import Unpack
85
86
87if typing.TYPE_CHECKING:
88 from ._typing import _ByArgument
89 from ._typing import _ColumnExpressionArgument
90 from ._typing import _ColumnExpressionOrStrLabelArgument
91 from ._typing import _DMLOnlyColumnArgument
92 from ._typing import _HasDialect
93 from ._typing import _InfoType
94 from ._typing import _PropagateAttrsType
95 from ._typing import _TypeEngineArgument
96 from .base import _EntityNamespace
97 from .base import ColumnSet
98 from .cache_key import _CacheKeyTraversalType
99 from .cache_key import CacheKey
100 from .compiler import Compiled
101 from .compiler import SQLCompiler
102 from .functions import FunctionElement
103 from .operators import OperatorType
104 from .schema import Column
105 from .schema import DefaultGenerator
106 from .schema import FetchedValue
107 from .schema import ForeignKey
108 from .selectable import _SelectIterable
109 from .selectable import FromClause
110 from .selectable import NamedFromClause
111 from .selectable import TextualSelect
112 from .sqltypes import TupleType
113 from .type_api import TypeEngine
114 from .visitors import _CloneCallableType
115 from .visitors import _TraverseInternalsType
116 from .visitors import anon_map
117 from ..engine import Connection
118 from ..engine import Dialect
119 from ..engine.interfaces import _CoreMultiExecuteParams
120 from ..engine.interfaces import CacheStats
121 from ..engine.interfaces import CompiledCacheType
122 from ..engine.interfaces import CoreExecuteOptionsParameter
123 from ..engine.interfaces import SchemaTranslateMapType
124 from ..engine.result import Result
125
126
127_NUMERIC = Union[float, Decimal]
128_NUMBER = Union[float, int, Decimal]
129
130_T = TypeVar("_T", bound="Any")
131_T_co = TypeVar("_T_co", bound=Any, covariant=True)
132_OPT = TypeVar("_OPT", bound="Any")
133_NT = TypeVar("_NT", bound="_NUMERIC")
134
135_NMT = TypeVar("_NMT", bound="_NUMBER")
136
137
138@overload
139def literal(
140 value: Any,
141 type_: _TypeEngineArgument[_T],
142 literal_execute: bool = False,
143) -> BindParameter[_T]: ...
144
145
146@overload
147def literal(
148 value: _T,
149 type_: None = None,
150 literal_execute: bool = False,
151) -> BindParameter[_T]: ...
152
153
154@overload
155def literal(
156 value: Any,
157 type_: Optional[_TypeEngineArgument[Any]] = None,
158 literal_execute: bool = False,
159) -> BindParameter[Any]: ...
160
161
162def literal(
163 value: Any,
164 type_: Optional[_TypeEngineArgument[Any]] = None,
165 literal_execute: bool = False,
166) -> BindParameter[Any]:
167 r"""Return a literal clause, bound to a bind parameter.
168
169 Literal clauses are created automatically when non-
170 :class:`_expression.ClauseElement` objects (such as strings, ints, dates,
171 etc.) are
172 used in a comparison operation with a :class:`_expression.ColumnElement`
173 subclass,
174 such as a :class:`~sqlalchemy.schema.Column` object. Use this function
175 to force the generation of a literal clause, which will be created as a
176 :class:`BindParameter` with a bound value.
177
178 :param value: the value to be bound. Can be any Python object supported by
179 the underlying DB-API, or is translatable via the given type argument.
180
181 :param type\_: an optional :class:`~sqlalchemy.types.TypeEngine` which will
182 provide bind-parameter translation for this literal.
183
184 :param literal_execute: optional bool, when True, the SQL engine will
185 attempt to render the bound value directly in the SQL statement at
186 execution time rather than providing as a parameter value.
187
188 .. versionadded:: 2.0
189
190 """
191 return coercions.expect(
192 roles.LiteralValueRole,
193 value,
194 type_=type_,
195 literal_execute=literal_execute,
196 )
197
198
199def literal_column(
200 text: str, type_: Optional[_TypeEngineArgument[_T]] = None
201) -> ColumnClause[_T]:
202 r"""Produce a :class:`.ColumnClause` object that has the
203 :paramref:`_expression.column.is_literal` flag set to True.
204
205 :func:`_expression.literal_column` is similar to
206 :func:`_expression.column`, except that
207 it is more often used as a "standalone" column expression that renders
208 exactly as stated; while :func:`_expression.column`
209 stores a string name that
210 will be assumed to be part of a table and may be quoted as such,
211 :func:`_expression.literal_column` can be that,
212 or any other arbitrary column-oriented
213 expression.
214
215 :param text: the text of the expression; can be any SQL expression.
216 Quoting rules will not be applied. To specify a column-name expression
217 which should be subject to quoting rules, use the :func:`column`
218 function.
219
220 :param type\_: an optional :class:`~sqlalchemy.types.TypeEngine`
221 object which will
222 provide result-set translation and additional expression semantics for
223 this column. If left as ``None`` the type will be :class:`.NullType`.
224
225 .. seealso::
226
227 :func:`_expression.column`
228
229 :func:`_expression.text`
230
231 :ref:`tutorial_select_arbitrary_text`
232
233 """
234 return ColumnClause(text, type_=type_, is_literal=True)
235
236
237class CompilerElement(Visitable):
238 """base class for SQL elements that can be compiled to produce a
239 SQL string.
240
241 .. versionadded:: 2.0
242
243 """
244
245 __slots__ = ()
246 __visit_name__ = "compiler_element"
247
248 supports_execution = False
249
250 stringify_dialect = "default"
251
252 @util.preload_module("sqlalchemy.engine.default")
253 @util.preload_module("sqlalchemy.engine.url")
254 def compile(
255 self,
256 bind: Optional[_HasDialect] = None,
257 dialect: Optional[Dialect] = None,
258 **kw: Any,
259 ) -> Compiled:
260 """Compile this SQL expression.
261
262 The return value is a :class:`~.Compiled` object.
263 Calling ``str()`` or ``unicode()`` on the returned value will yield a
264 string representation of the result. The
265 :class:`~.Compiled` object also can return a
266 dictionary of bind parameter names and values
267 using the ``params`` accessor.
268
269 :param bind: An :class:`.Connection` or :class:`.Engine` which
270 can provide a :class:`.Dialect` in order to generate a
271 :class:`.Compiled` object. If the ``bind`` and
272 ``dialect`` parameters are both omitted, a default SQL compiler
273 is used.
274
275 :param column_keys: Used for INSERT and UPDATE statements, a list of
276 column names which should be present in the VALUES clause of the
277 compiled statement. If ``None``, all columns from the target table
278 object are rendered.
279
280 :param dialect: A :class:`.Dialect` instance which can generate
281 a :class:`.Compiled` object. This argument takes precedence over
282 the ``bind`` argument.
283
284 :param compile_kwargs: optional dictionary of additional parameters
285 that will be passed through to the compiler within all "visit"
286 methods. This allows any custom flag to be passed through to
287 a custom compilation construct, for example. It is also used
288 for the case of passing the ``literal_binds`` flag through::
289
290 from sqlalchemy.sql import table, column, select
291
292 t = table("t", column("x"))
293
294 s = select(t).where(t.c.x == 5)
295
296 print(s.compile(compile_kwargs={"literal_binds": True}))
297
298 .. seealso::
299
300 :ref:`faq_sql_expression_string`
301
302 """
303
304 if dialect is None:
305 if bind:
306 dialect = bind.dialect
307 elif self.stringify_dialect == "default":
308 dialect = self._default_dialect()
309 else:
310 url = util.preloaded.engine_url
311 dialect = url.URL.create(
312 self.stringify_dialect
313 ).get_dialect()()
314
315 return self._compiler(dialect, **kw)
316
317 def _default_dialect(self):
318 default = util.preloaded.engine_default
319 return default.StrCompileDialect()
320
321 def _compiler(self, dialect: Dialect, **kw: Any) -> Compiled:
322 """Return a compiler appropriate for this ClauseElement, given a
323 Dialect."""
324
325 if TYPE_CHECKING:
326 assert isinstance(self, ClauseElement)
327 return dialect.statement_compiler(dialect, self, **kw)
328
329 def __str__(self) -> str:
330 return str(self.compile())
331
332
333@inspection._self_inspects
334class ClauseElement(
335 SupportsWrappingAnnotations,
336 MemoizedHasCacheKey,
337 HasCopyInternals,
338 ExternallyTraversible,
339 CompilerElement,
340):
341 """Base class for elements of a programmatically constructed SQL
342 expression.
343
344 """
345
346 __visit_name__ = "clause"
347
348 if TYPE_CHECKING:
349
350 @util.memoized_property
351 def _propagate_attrs(self) -> _PropagateAttrsType:
352 """like annotations, however these propagate outwards liberally
353 as SQL constructs are built, and are set up at construction time.
354
355 """
356 ...
357
358 else:
359 _propagate_attrs = util.EMPTY_DICT
360
361 @util.ro_memoized_property
362 def description(self) -> Optional[str]:
363 return None
364
365 _is_clone_of: Optional[Self] = None
366
367 is_clause_element = True
368 is_selectable = False
369 is_dml = False
370 _is_column_element = False
371 _is_keyed_column_element = False
372 _is_table = False
373 _gen_static_annotations_cache_key = False
374 _is_textual = False
375 _is_from_clause = False
376 _is_returns_rows = False
377 _is_text_clause = False
378 _is_from_container = False
379 _is_select_container = False
380 _is_select_base = False
381 _is_select_statement = False
382 _is_bind_parameter = False
383 _is_clause_list = False
384 _is_lambda_element = False
385 _is_singleton_constant = False
386 _is_immutable = False
387 _is_star = False
388
389 @property
390 def _order_by_label_element(self) -> Optional[Label[Any]]:
391 return None
392
393 _cache_key_traversal: _CacheKeyTraversalType = None
394
395 negation_clause: ColumnElement[bool]
396
397 if typing.TYPE_CHECKING:
398
399 def get_children(
400 self, *, omit_attrs: typing_Tuple[str, ...] = ..., **kw: Any
401 ) -> Iterable[ClauseElement]: ...
402
403 @util.ro_non_memoized_property
404 def _from_objects(self) -> List[FromClause]:
405 return []
406
407 def _set_propagate_attrs(self, values: Mapping[str, Any]) -> Self:
408 # usually, self._propagate_attrs is empty here. one case where it's
409 # not is a subquery against ORM select, that is then pulled as a
410 # property of an aliased class. should all be good
411
412 # assert not self._propagate_attrs
413
414 self._propagate_attrs = util.immutabledict(values)
415 return self
416
417 def _default_compiler(self) -> SQLCompiler:
418 dialect = self._default_dialect()
419 return dialect.statement_compiler(dialect, self) # type: ignore
420
421 def _clone(self, **kw: Any) -> Self:
422 """Create a shallow copy of this ClauseElement.
423
424 This method may be used by a generative API. Its also used as
425 part of the "deep" copy afforded by a traversal that combines
426 the _copy_internals() method.
427
428 """
429
430 skip = self._memoized_keys
431 c = self.__class__.__new__(self.__class__)
432
433 if skip:
434 # ensure this iteration remains atomic
435 c.__dict__ = {
436 k: v for k, v in self.__dict__.copy().items() if k not in skip
437 }
438 else:
439 c.__dict__ = self.__dict__.copy()
440
441 # this is a marker that helps to "equate" clauses to each other
442 # when a Select returns its list of FROM clauses. the cloning
443 # process leaves around a lot of remnants of the previous clause
444 # typically in the form of column expressions still attached to the
445 # old table.
446 cc = self._is_clone_of
447 c._is_clone_of = cc if cc is not None else self
448 return c
449
450 def _negate_in_binary(self, negated_op, original_op):
451 """a hook to allow the right side of a binary expression to respond
452 to a negation of the binary expression.
453
454 Used for the special case of expanding bind parameter with IN.
455
456 """
457 return self
458
459 def _with_binary_element_type(self, type_):
460 """in the context of binary expression, convert the type of this
461 object to the one given.
462
463 applies only to :class:`_expression.ColumnElement` classes.
464
465 """
466 return self
467
468 @property
469 def _constructor(self): # type: ignore[override]
470 """return the 'constructor' for this ClauseElement.
471
472 This is for the purposes for creating a new object of
473 this type. Usually, its just the element's __class__.
474 However, the "Annotated" version of the object overrides
475 to return the class of its proxied element.
476
477 """
478 return self.__class__
479
480 @HasMemoized.memoized_attribute
481 def _cloned_set(self):
482 """Return the set consisting all cloned ancestors of this
483 ClauseElement.
484
485 Includes this ClauseElement. This accessor tends to be used for
486 FromClause objects to identify 'equivalent' FROM clauses, regardless
487 of transformative operations.
488
489 """
490 s = util.column_set()
491 f: Optional[ClauseElement] = self
492
493 # note this creates a cycle, asserted in test_memusage. however,
494 # turning this into a plain @property adds tends of thousands of method
495 # calls to Core / ORM performance tests, so the small overhead
496 # introduced by the relatively small amount of short term cycles
497 # produced here is preferable
498 while f is not None:
499 s.add(f)
500 f = f._is_clone_of
501 return s
502
503 def _de_clone(self):
504 while self._is_clone_of is not None:
505 self = self._is_clone_of
506 return self
507
508 @util.ro_non_memoized_property
509 def entity_namespace(self) -> _EntityNamespace:
510 raise AttributeError(
511 "This SQL expression has no entity namespace "
512 "with which to filter from."
513 )
514
515 def __getstate__(self):
516 d = self.__dict__.copy()
517 d.pop("_is_clone_of", None)
518 d.pop("_generate_cache_key", None)
519 return d
520
521 def _execute_on_connection(
522 self,
523 connection: Connection,
524 distilled_params: _CoreMultiExecuteParams,
525 execution_options: CoreExecuteOptionsParameter,
526 ) -> Result[Unpack[TupleAny]]:
527 if self.supports_execution:
528 if TYPE_CHECKING:
529 assert isinstance(self, Executable)
530 return connection._execute_clauseelement(
531 self, distilled_params, execution_options
532 )
533 else:
534 raise exc.ObjectNotExecutableError(self)
535
536 def _execute_on_scalar(
537 self,
538 connection: Connection,
539 distilled_params: _CoreMultiExecuteParams,
540 execution_options: CoreExecuteOptionsParameter,
541 ) -> Any:
542 """an additional hook for subclasses to provide a different
543 implementation for connection.scalar() vs. connection.execute().
544
545 .. versionadded:: 2.0
546
547 """
548 return self._execute_on_connection(
549 connection, distilled_params, execution_options
550 ).scalar()
551
552 def _get_embedded_bindparams(self) -> Sequence[BindParameter[Any]]:
553 """Return the list of :class:`.BindParameter` objects embedded in the
554 object.
555
556 This accomplishes the same purpose as ``visitors.traverse()`` or
557 similar would provide, however by making use of the cache key
558 it takes advantage of memoization of the key to result in fewer
559 net method calls, assuming the statement is also going to be
560 executed.
561
562 """
563
564 key = self._generate_cache_key()
565 if key is None:
566 bindparams: List[BindParameter[Any]] = []
567
568 traverse(self, {}, {"bindparam": bindparams.append})
569 return bindparams
570
571 else:
572 return key.bindparams
573
574 def unique_params(
575 self,
576 __optionaldict: Optional[Dict[str, Any]] = None,
577 /,
578 **kwargs: Any,
579 ) -> Self:
580 """Return a copy with :func:`_expression.bindparam` elements
581 replaced.
582
583 Same functionality as :meth:`_expression.ClauseElement.params`,
584 except adds `unique=True`
585 to affected bind parameters so that multiple statements can be
586 used.
587
588 """
589 return self._replace_params(True, __optionaldict, kwargs)
590
591 def params(
592 self,
593 __optionaldict: Optional[Mapping[str, Any]] = None,
594 /,
595 **kwargs: Any,
596 ) -> Self:
597 """Return a copy with :func:`_expression.bindparam` elements
598 replaced.
599
600 Returns a copy of this ClauseElement with
601 :func:`_expression.bindparam`
602 elements replaced with values taken from the given dictionary::
603
604 >>> clause = column("x") + bindparam("foo")
605 >>> print(clause.compile().params)
606 {'foo':None}
607 >>> print(clause.params({"foo": 7}).compile().params)
608 {'foo':7}
609
610 """
611 return self._replace_params(False, __optionaldict, kwargs)
612
613 def _replace_params(
614 self,
615 unique: bool,
616 optionaldict: Optional[Mapping[str, Any]],
617 kwargs: Dict[str, Any],
618 ) -> Self:
619 if optionaldict:
620 kwargs.update(optionaldict)
621
622 def visit_bindparam(bind: BindParameter[Any]) -> None:
623 if bind.key in kwargs:
624 bind.value = kwargs[bind.key]
625 bind.required = False
626 if unique:
627 bind._convert_to_unique()
628
629 return cloned_traverse(
630 self,
631 {"maintain_key": True, "detect_subquery_cols": True},
632 {"bindparam": visit_bindparam},
633 )
634
635 def compare(self, other: ClauseElement, **kw: Any) -> bool:
636 r"""Compare this :class:`_expression.ClauseElement` to
637 the given :class:`_expression.ClauseElement`.
638
639 Subclasses should override the default behavior, which is a
640 straight identity comparison.
641
642 \**kw are arguments consumed by subclass ``compare()`` methods and
643 may be used to modify the criteria for comparison
644 (see :class:`_expression.ColumnElement`).
645
646 """
647 return traversals.compare(self, other, **kw)
648
649 def self_group(
650 self, against: Optional[OperatorType] = None
651 ) -> ClauseElement:
652 """Apply a 'grouping' to this :class:`_expression.ClauseElement`.
653
654 This method is overridden by subclasses to return a "grouping"
655 construct, i.e. parenthesis. In particular it's used by "binary"
656 expressions to provide a grouping around themselves when placed into a
657 larger expression, as well as by :func:`_expression.select`
658 constructs when placed into the FROM clause of another
659 :func:`_expression.select`. (Note that subqueries should be
660 normally created using the :meth:`_expression.Select.alias` method,
661 as many
662 platforms require nested SELECT statements to be named).
663
664 As expressions are composed together, the application of
665 :meth:`self_group` is automatic - end-user code should never
666 need to use this method directly. Note that SQLAlchemy's
667 clause constructs take operator precedence into account -
668 so parenthesis might not be needed, for example, in
669 an expression like ``x OR (y AND z)`` - AND takes precedence
670 over OR.
671
672 The base :meth:`self_group` method of
673 :class:`_expression.ClauseElement`
674 just returns self.
675 """
676 return self
677
678 def _ungroup(self) -> ClauseElement:
679 """Return this :class:`_expression.ClauseElement`
680 without any groupings.
681 """
682
683 return self
684
685 def _compile_w_cache(
686 self,
687 dialect: Dialect,
688 *,
689 compiled_cache: Optional[CompiledCacheType],
690 column_keys: List[str],
691 for_executemany: bool = False,
692 schema_translate_map: Optional[SchemaTranslateMapType] = None,
693 **kw: Any,
694 ) -> typing_Tuple[
695 Compiled, Optional[Sequence[BindParameter[Any]]], CacheStats
696 ]:
697 elem_cache_key: Optional[CacheKey]
698
699 if compiled_cache is not None and dialect._supports_statement_cache:
700 elem_cache_key = self._generate_cache_key()
701 else:
702 elem_cache_key = None
703
704 extracted_params: Optional[Sequence[BindParameter[Any]]]
705 if elem_cache_key is not None:
706 if TYPE_CHECKING:
707 assert compiled_cache is not None
708
709 cache_key, extracted_params = elem_cache_key
710 key = (
711 dialect,
712 cache_key,
713 tuple(column_keys),
714 bool(schema_translate_map),
715 for_executemany,
716 )
717 compiled_sql = compiled_cache.get(key)
718
719 if compiled_sql is None:
720 cache_hit = dialect.CACHE_MISS
721 compiled_sql = self._compiler(
722 dialect,
723 cache_key=elem_cache_key,
724 column_keys=column_keys,
725 for_executemany=for_executemany,
726 schema_translate_map=schema_translate_map,
727 **kw,
728 )
729 compiled_cache[key] = compiled_sql
730 else:
731 cache_hit = dialect.CACHE_HIT
732 else:
733 extracted_params = None
734 compiled_sql = self._compiler(
735 dialect,
736 cache_key=elem_cache_key,
737 column_keys=column_keys,
738 for_executemany=for_executemany,
739 schema_translate_map=schema_translate_map,
740 **kw,
741 )
742
743 if not dialect._supports_statement_cache:
744 cache_hit = dialect.NO_DIALECT_SUPPORT
745 elif compiled_cache is None:
746 cache_hit = dialect.CACHING_DISABLED
747 else:
748 cache_hit = dialect.NO_CACHE_KEY
749
750 return compiled_sql, extracted_params, cache_hit
751
752 def __invert__(self):
753 # undocumented element currently used by the ORM for
754 # relationship.contains()
755 if hasattr(self, "negation_clause"):
756 return self.negation_clause
757 else:
758 return self._negate()
759
760 def _negate(self) -> ClauseElement:
761 # TODO: this code is uncovered and in all likelihood is not included
762 # in any codepath. So this should raise NotImplementedError in 2.1
763 grouped = self.self_group(against=operators.inv)
764 assert isinstance(grouped, ColumnElement)
765 return UnaryExpression(grouped, operator=operators.inv)
766
767 def __bool__(self):
768 raise TypeError("Boolean value of this clause is not defined")
769
770 def __repr__(self):
771 friendly = self.description
772 if friendly is None:
773 return object.__repr__(self)
774 else:
775 return "<%s.%s at 0x%x; %s>" % (
776 self.__module__,
777 self.__class__.__name__,
778 id(self),
779 friendly,
780 )
781
782
783class DQLDMLClauseElement(ClauseElement):
784 """represents a :class:`.ClauseElement` that compiles to a DQL or DML
785 expression, not DDL.
786
787 .. versionadded:: 2.0
788
789 """
790
791 if typing.TYPE_CHECKING:
792
793 def _compiler(self, dialect: Dialect, **kw: Any) -> SQLCompiler:
794 """Return a compiler appropriate for this ClauseElement, given a
795 Dialect."""
796 ...
797
798 def compile( # noqa: A001
799 self,
800 bind: Optional[_HasDialect] = None,
801 dialect: Optional[Dialect] = None,
802 **kw: Any,
803 ) -> SQLCompiler: ...
804
805
806class CompilerColumnElement(
807 roles.DMLColumnRole,
808 roles.DDLConstraintColumnRole,
809 roles.ColumnsClauseRole,
810 CompilerElement,
811):
812 """A compiler-only column element used for ad-hoc string compilations.
813
814 .. versionadded:: 2.0
815
816 """
817
818 __slots__ = ()
819
820 _propagate_attrs = util.EMPTY_DICT
821 _is_collection_aggregate = False
822 _is_implicitly_boolean = False
823
824 def _with_binary_element_type(self, type_):
825 raise NotImplementedError()
826
827 def _gen_cache_key(self, anon_map, bindparams):
828 raise NotImplementedError()
829
830 @property
831 def _from_objects(self) -> List[FromClause]:
832 raise NotImplementedError()
833
834
835# SQLCoreOperations should be suiting the ExpressionElementRole
836# and ColumnsClauseRole. however the MRO issues become too elaborate
837# at the moment.
838class SQLCoreOperations(Generic[_T_co], ColumnOperators, TypingOnly):
839 __slots__ = ()
840
841 # annotations for comparison methods
842 # these are from operators->Operators / ColumnOperators,
843 # redefined with the specific types returned by ColumnElement hierarchies
844 if typing.TYPE_CHECKING:
845
846 @util.non_memoized_property
847 def _propagate_attrs(self) -> _PropagateAttrsType: ...
848
849 def operate(
850 self, op: OperatorType, *other: Any, **kwargs: Any
851 ) -> ColumnElement[Any]: ...
852
853 def reverse_operate(
854 self, op: OperatorType, other: Any, **kwargs: Any
855 ) -> ColumnElement[Any]: ...
856
857 @overload
858 def op(
859 self,
860 opstring: str,
861 precedence: int = ...,
862 is_comparison: bool = ...,
863 *,
864 return_type: _TypeEngineArgument[_OPT],
865 python_impl: Optional[Callable[..., Any]] = None,
866 operator_class: OperatorClass = ...,
867 visit_name: Optional[str] = ...,
868 ) -> Callable[[Any], BinaryExpression[_OPT]]: ...
869
870 @overload
871 def op(
872 self,
873 opstring: str,
874 precedence: int = ...,
875 is_comparison: bool = ...,
876 return_type: Optional[_TypeEngineArgument[Any]] = ...,
877 python_impl: Optional[Callable[..., Any]] = ...,
878 operator_class: OperatorClass = ...,
879 visit_name: Optional[str] = ...,
880 ) -> Callable[[Any], BinaryExpression[Any]]: ...
881
882 def op(
883 self,
884 opstring: str,
885 precedence: int = 0,
886 is_comparison: bool = False,
887 return_type: Optional[_TypeEngineArgument[Any]] = None,
888 python_impl: Optional[Callable[..., Any]] = None,
889 operator_class: OperatorClass = OperatorClass.BASE,
890 visit_name: Optional[str] = None,
891 ) -> Callable[[Any], BinaryExpression[Any]]: ...
892
893 def bool_op(
894 self,
895 opstring: str,
896 precedence: int = 0,
897 python_impl: Optional[Callable[..., Any]] = None,
898 ) -> Callable[[Any], BinaryExpression[bool]]: ...
899
900 def __and__(self, other: Any) -> BooleanClauseList: ...
901
902 def __or__(self, other: Any) -> BooleanClauseList: ...
903
904 def __invert__(self) -> ColumnElement[_T_co]: ...
905
906 def __lt__(self, other: Any) -> ColumnElement[bool]: ...
907
908 def __le__(self, other: Any) -> ColumnElement[bool]: ...
909
910 # declare also that this class has an hash method otherwise
911 # it may be assumed to be None by type checkers since the
912 # object defines __eq__ and python sets it to None in that case:
913 # https://docs.python.org/3/reference/datamodel.html#object.__hash__
914 def __hash__(self) -> int: ...
915
916 def __eq__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501
917 ...
918
919 def __ne__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501
920 ...
921
922 def is_distinct_from(self, other: Any) -> ColumnElement[bool]: ...
923
924 def is_not_distinct_from(self, other: Any) -> ColumnElement[bool]: ...
925
926 def __gt__(self, other: Any) -> ColumnElement[bool]: ...
927
928 def __ge__(self, other: Any) -> ColumnElement[bool]: ...
929
930 def __neg__(self) -> UnaryExpression[_T_co]: ...
931
932 def __contains__(self, other: Any) -> ColumnElement[bool]: ...
933
934 def __getitem__(self, index: Any) -> ColumnElement[Any]: ...
935
936 @overload
937 def __lshift__(self: _SQO[int], other: Any) -> ColumnElement[int]: ...
938
939 @overload
940 def __lshift__(self, other: Any) -> ColumnElement[Any]: ...
941
942 def __lshift__(self, other: Any) -> ColumnElement[Any]: ...
943
944 @overload
945 def __rlshift__(self: _SQO[int], other: Any) -> ColumnElement[int]: ...
946
947 @overload
948 def __rlshift__(self, other: Any) -> ColumnElement[Any]: ...
949
950 def __rlshift__(self, other: Any) -> ColumnElement[Any]: ...
951
952 @overload
953 def __rshift__(self: _SQO[int], other: Any) -> ColumnElement[int]: ...
954
955 @overload
956 def __rshift__(self, other: Any) -> ColumnElement[Any]: ...
957
958 def __rshift__(self, other: Any) -> ColumnElement[Any]: ...
959
960 @overload
961 def __rrshift__(self: _SQO[int], other: Any) -> ColumnElement[int]: ...
962
963 @overload
964 def __rrshift__(self, other: Any) -> ColumnElement[Any]: ...
965
966 def __rrshift__(self, other: Any) -> ColumnElement[Any]: ...
967
968 def __matmul__(self, other: Any) -> ColumnElement[Any]: ...
969
970 def __rmatmul__(self, other: Any) -> ColumnElement[Any]: ...
971
972 @overload
973 def concat(self: _SQO[str], other: Any) -> ColumnElement[str]: ...
974
975 @overload
976 def concat(self, other: Any) -> ColumnElement[Any]: ...
977
978 def concat(self, other: Any) -> ColumnElement[Any]: ...
979
980 def like(
981 self, other: Any, escape: Optional[str] = None
982 ) -> BinaryExpression[bool]: ...
983
984 def ilike(
985 self, other: Any, escape: Optional[str] = None
986 ) -> BinaryExpression[bool]: ...
987
988 def bitwise_xor(self, other: Any) -> BinaryExpression[Any]: ...
989
990 def bitwise_or(self, other: Any) -> BinaryExpression[Any]: ...
991
992 def bitwise_and(self, other: Any) -> BinaryExpression[Any]: ...
993
994 def bitwise_not(self) -> UnaryExpression[_T_co]: ...
995
996 def bitwise_lshift(self, other: Any) -> BinaryExpression[Any]: ...
997
998 def bitwise_rshift(self, other: Any) -> BinaryExpression[Any]: ...
999
1000 def in_(
1001 self,
1002 other: Union[
1003 Iterable[Any], BindParameter[Any], roles.InElementRole
1004 ],
1005 ) -> BinaryExpression[bool]: ...
1006
1007 def not_in(
1008 self,
1009 other: Union[
1010 Iterable[Any], BindParameter[Any], roles.InElementRole
1011 ],
1012 ) -> BinaryExpression[bool]: ...
1013
1014 def notin_(
1015 self,
1016 other: Union[
1017 Iterable[Any], BindParameter[Any], roles.InElementRole
1018 ],
1019 ) -> BinaryExpression[bool]: ...
1020
1021 def not_like(
1022 self, other: Any, escape: Optional[str] = None
1023 ) -> BinaryExpression[bool]: ...
1024
1025 def notlike(
1026 self, other: Any, escape: Optional[str] = None
1027 ) -> BinaryExpression[bool]: ...
1028
1029 def not_ilike(
1030 self, other: Any, escape: Optional[str] = None
1031 ) -> BinaryExpression[bool]: ...
1032
1033 def notilike(
1034 self, other: Any, escape: Optional[str] = None
1035 ) -> BinaryExpression[bool]: ...
1036
1037 def is_(self, other: Any) -> BinaryExpression[bool]: ...
1038
1039 def is_not(self, other: Any) -> BinaryExpression[bool]: ...
1040
1041 def isnot(self, other: Any) -> BinaryExpression[bool]: ...
1042
1043 def startswith(
1044 self,
1045 other: Any,
1046 escape: Optional[str] = None,
1047 autoescape: bool = False,
1048 ) -> ColumnElement[bool]: ...
1049
1050 def istartswith(
1051 self,
1052 other: Any,
1053 escape: Optional[str] = None,
1054 autoescape: bool = False,
1055 ) -> ColumnElement[bool]: ...
1056
1057 def endswith(
1058 self,
1059 other: Any,
1060 escape: Optional[str] = None,
1061 autoescape: bool = False,
1062 ) -> ColumnElement[bool]: ...
1063
1064 def iendswith(
1065 self,
1066 other: Any,
1067 escape: Optional[str] = None,
1068 autoescape: bool = False,
1069 ) -> ColumnElement[bool]: ...
1070
1071 def contains(self, other: Any, **kw: Any) -> ColumnElement[bool]: ...
1072
1073 def icontains(self, other: Any, **kw: Any) -> ColumnElement[bool]: ...
1074
1075 def match(self, other: Any, **kwargs: Any) -> ColumnElement[bool]: ...
1076
1077 def regexp_match(
1078 self, pattern: Any, flags: Optional[str] = None
1079 ) -> ColumnElement[bool]: ...
1080
1081 def regexp_replace(
1082 self, pattern: Any, replacement: Any, flags: Optional[str] = None
1083 ) -> ColumnElement[str]: ...
1084
1085 def desc(self) -> UnaryExpression[_T_co]: ...
1086
1087 def asc(self) -> UnaryExpression[_T_co]: ...
1088
1089 def nulls_first(self) -> UnaryExpression[_T_co]: ...
1090
1091 def nullsfirst(self) -> UnaryExpression[_T_co]: ...
1092
1093 def nulls_last(self) -> UnaryExpression[_T_co]: ...
1094
1095 def nullslast(self) -> UnaryExpression[_T_co]: ...
1096
1097 def collate(self, collation: str) -> CollationClause: ...
1098
1099 def between(
1100 self, cleft: Any, cright: Any, symmetric: bool = False
1101 ) -> BinaryExpression[bool]: ...
1102
1103 def distinct(self: _SQO[_T_co]) -> UnaryExpression[_T_co]: ...
1104
1105 def any_(self) -> CollectionAggregate[Any]: ...
1106
1107 def all_(self) -> CollectionAggregate[Any]: ...
1108
1109 # numeric overloads. These need more tweaking
1110 # in particular they all need to have a variant for Optiona[_T]
1111 # because Optional only applies to the data side, not the expression
1112 # side
1113
1114 @overload
1115 def __add__(
1116 self: _SQO[_NMT],
1117 other: Any,
1118 ) -> ColumnElement[_NMT]: ...
1119
1120 @overload
1121 def __add__(
1122 self: _SQO[str],
1123 other: Any,
1124 ) -> ColumnElement[str]: ...
1125
1126 @overload
1127 def __add__(self, other: Any) -> ColumnElement[Any]: ...
1128
1129 def __add__(self, other: Any) -> ColumnElement[Any]: ...
1130
1131 @overload
1132 def __radd__(self: _SQO[_NMT], other: Any) -> ColumnElement[_NMT]: ...
1133
1134 @overload
1135 def __radd__(self: _SQO[str], other: Any) -> ColumnElement[str]: ...
1136
1137 def __radd__(self, other: Any) -> ColumnElement[Any]: ...
1138
1139 @overload
1140 def __sub__(
1141 self: _SQO[_NMT],
1142 other: Any,
1143 ) -> ColumnElement[_NMT]: ...
1144
1145 @overload
1146 def __sub__(self, other: Any) -> ColumnElement[Any]: ...
1147
1148 def __sub__(self, other: Any) -> ColumnElement[Any]: ...
1149
1150 @overload
1151 def __rsub__(
1152 self: _SQO[_NMT],
1153 other: Any,
1154 ) -> ColumnElement[_NMT]: ...
1155
1156 @overload
1157 def __rsub__(self, other: Any) -> ColumnElement[Any]: ...
1158
1159 def __rsub__(self, other: Any) -> ColumnElement[Any]: ...
1160
1161 @overload
1162 def __mul__(
1163 self: _SQO[_NMT],
1164 other: Any,
1165 ) -> ColumnElement[_NMT]: ...
1166
1167 @overload
1168 def __mul__(self, other: Any) -> ColumnElement[Any]: ...
1169
1170 def __mul__(self, other: Any) -> ColumnElement[Any]: ...
1171
1172 @overload
1173 def __rmul__(
1174 self: _SQO[_NMT],
1175 other: Any,
1176 ) -> ColumnElement[_NMT]: ...
1177
1178 @overload
1179 def __rmul__(self, other: Any) -> ColumnElement[Any]: ...
1180
1181 def __rmul__(self, other: Any) -> ColumnElement[Any]: ...
1182
1183 @overload
1184 def __mod__(self: _SQO[_NMT], other: Any) -> ColumnElement[_NMT]: ...
1185
1186 @overload
1187 def __mod__(self, other: Any) -> ColumnElement[Any]: ...
1188
1189 def __mod__(self, other: Any) -> ColumnElement[Any]: ...
1190
1191 @overload
1192 def __rmod__(self: _SQO[_NMT], other: Any) -> ColumnElement[_NMT]: ...
1193
1194 @overload
1195 def __rmod__(self, other: Any) -> ColumnElement[Any]: ...
1196
1197 def __rmod__(self, other: Any) -> ColumnElement[Any]: ...
1198
1199 @overload
1200 def __truediv__(
1201 self: _SQO[int], other: Any
1202 ) -> ColumnElement[_NUMERIC]: ...
1203
1204 @overload
1205 def __truediv__(self: _SQO[_NT], other: Any) -> ColumnElement[_NT]: ...
1206
1207 @overload
1208 def __truediv__(self, other: Any) -> ColumnElement[Any]: ...
1209
1210 def __truediv__(self, other: Any) -> ColumnElement[Any]: ...
1211
1212 @overload
1213 def __rtruediv__(
1214 self: _SQO[_NMT], other: Any
1215 ) -> ColumnElement[_NUMERIC]: ...
1216
1217 @overload
1218 def __rtruediv__(self, other: Any) -> ColumnElement[Any]: ...
1219
1220 def __rtruediv__(self, other: Any) -> ColumnElement[Any]: ...
1221
1222 @overload
1223 def __floordiv__(
1224 self: _SQO[_NMT], other: Any
1225 ) -> ColumnElement[_NMT]: ...
1226
1227 @overload
1228 def __floordiv__(self, other: Any) -> ColumnElement[Any]: ...
1229
1230 def __floordiv__(self, other: Any) -> ColumnElement[Any]: ...
1231
1232 @overload
1233 def __rfloordiv__(
1234 self: _SQO[_NMT], other: Any
1235 ) -> ColumnElement[_NMT]: ...
1236
1237 @overload
1238 def __rfloordiv__(self, other: Any) -> ColumnElement[Any]: ...
1239
1240 def __rfloordiv__(self, other: Any) -> ColumnElement[Any]: ...
1241
1242
1243class SQLColumnExpression(
1244 SQLCoreOperations[_T_co], roles.ExpressionElementRole[_T_co], TypingOnly
1245):
1246 """A type that may be used to indicate any SQL column element or object
1247 that acts in place of one.
1248
1249 :class:`.SQLColumnExpression` is a base of
1250 :class:`.ColumnElement`, as well as within the bases of ORM elements
1251 such as :class:`.InstrumentedAttribute`, and may be used in :pep:`484`
1252 typing to indicate arguments or return values that should behave
1253 as column expressions.
1254
1255 .. versionadded:: 2.0.0b4
1256
1257
1258 """
1259
1260 __slots__ = ()
1261
1262
1263_SQO = SQLCoreOperations
1264
1265
1266class ColumnElement(
1267 roles.ColumnArgumentOrKeyRole,
1268 roles.StatementOptionRole,
1269 roles.WhereHavingRole,
1270 roles.BinaryElementRole[_T],
1271 roles.OrderByRole,
1272 roles.ColumnsClauseRole,
1273 roles.LimitOffsetRole,
1274 roles.DMLColumnRole,
1275 roles.DDLConstraintColumnRole,
1276 roles.DDLExpressionRole,
1277 SQLColumnExpression[_T],
1278 DQLDMLClauseElement,
1279):
1280 """Represent a column-oriented SQL expression suitable for usage in the
1281 "columns" clause, WHERE clause etc. of a statement.
1282
1283 While the most familiar kind of :class:`_expression.ColumnElement` is the
1284 :class:`_schema.Column` object, :class:`_expression.ColumnElement`
1285 serves as the basis
1286 for any unit that may be present in a SQL expression, including
1287 the expressions themselves, SQL functions, bound parameters,
1288 literal expressions, keywords such as ``NULL``, etc.
1289 :class:`_expression.ColumnElement`
1290 is the ultimate base class for all such elements.
1291
1292 A wide variety of SQLAlchemy Core functions work at the SQL expression
1293 level, and are intended to accept instances of
1294 :class:`_expression.ColumnElement` as
1295 arguments. These functions will typically document that they accept a
1296 "SQL expression" as an argument. What this means in terms of SQLAlchemy
1297 usually refers to an input which is either already in the form of a
1298 :class:`_expression.ColumnElement` object,
1299 or a value which can be **coerced** into
1300 one. The coercion rules followed by most, but not all, SQLAlchemy Core
1301 functions with regards to SQL expressions are as follows:
1302
1303 * a literal Python value, such as a string, integer or floating
1304 point value, boolean, datetime, ``Decimal`` object, or virtually
1305 any other Python object, will be coerced into a "literal bound
1306 value". This generally means that a :func:`.bindparam` will be
1307 produced featuring the given value embedded into the construct; the
1308 resulting :class:`.BindParameter` object is an instance of
1309 :class:`_expression.ColumnElement`.
1310 The Python value will ultimately be sent
1311 to the DBAPI at execution time as a parameterized argument to the
1312 ``execute()`` or ``executemany()`` methods, after SQLAlchemy
1313 type-specific converters (e.g. those provided by any associated
1314 :class:`.TypeEngine` objects) are applied to the value.
1315
1316 * any special object value, typically ORM-level constructs, which
1317 feature an accessor called ``__clause_element__()``. The Core
1318 expression system looks for this method when an object of otherwise
1319 unknown type is passed to a function that is looking to coerce the
1320 argument into a :class:`_expression.ColumnElement` and sometimes a
1321 :class:`_expression.SelectBase` expression.
1322 It is used within the ORM to
1323 convert from ORM-specific objects like mapped classes and
1324 mapped attributes into Core expression objects.
1325
1326 * The Python ``None`` value is typically interpreted as ``NULL``,
1327 which in SQLAlchemy Core produces an instance of :func:`.null`.
1328
1329 A :class:`_expression.ColumnElement` provides the ability to generate new
1330 :class:`_expression.ColumnElement`
1331 objects using Python expressions. This means that Python operators
1332 such as ``==``, ``!=`` and ``<`` are overloaded to mimic SQL operations,
1333 and allow the instantiation of further :class:`_expression.ColumnElement`
1334 instances
1335 which are composed from other, more fundamental
1336 :class:`_expression.ColumnElement`
1337 objects. For example, two :class:`.ColumnClause` objects can be added
1338 together with the addition operator ``+`` to produce
1339 a :class:`.BinaryExpression`.
1340 Both :class:`.ColumnClause` and :class:`.BinaryExpression` are subclasses
1341 of :class:`_expression.ColumnElement`:
1342
1343 .. sourcecode:: pycon+sql
1344
1345 >>> from sqlalchemy.sql import column
1346 >>> column("a") + column("b")
1347 <sqlalchemy.sql.expression.BinaryExpression object at 0x101029dd0>
1348 >>> print(column("a") + column("b"))
1349 {printsql}a + b
1350
1351 .. seealso::
1352
1353 :class:`_schema.Column`
1354
1355 :func:`_expression.column`
1356
1357 """
1358
1359 __visit_name__ = "column_element"
1360
1361 primary_key: bool = False
1362 _is_clone_of: Optional[ColumnElement[_T]]
1363 _is_column_element = True
1364 _insert_sentinel: bool = False
1365 _omit_from_statements = False
1366 _is_collection_aggregate = False
1367
1368 foreign_keys: AbstractSet[ForeignKey] = frozenset()
1369
1370 @util.memoized_property
1371 def _proxies(self) -> List[ColumnElement[Any]]:
1372 return []
1373
1374 @util.non_memoized_property
1375 def _tq_label(self) -> Optional[str]:
1376 """The named label that can be used to target
1377 this column in a result set in a "table qualified" context.
1378
1379 This label is almost always the label used when
1380 rendering <expr> AS <label> in a SELECT statement when using
1381 the LABEL_STYLE_TABLENAME_PLUS_COL label style, which is what the
1382 legacy ORM ``Query`` object uses as well.
1383
1384 For a regular Column bound to a Table, this is typically the label
1385 <tablename>_<columnname>. For other constructs, different rules
1386 may apply, such as anonymized labels and others.
1387
1388 .. versionchanged:: 1.4.21 renamed from ``._label``
1389
1390 """
1391 return None
1392
1393 key: Optional[str] = None
1394 """The 'key' that in some circumstances refers to this object in a
1395 Python namespace.
1396
1397 This typically refers to the "key" of the column as present in the
1398 ``.c`` collection of a selectable, e.g. ``sometable.c["somekey"]`` would
1399 return a :class:`_schema.Column` with a ``.key`` of "somekey".
1400
1401 """
1402
1403 @HasMemoized.memoized_attribute
1404 def _tq_key_label(self) -> Optional[str]:
1405 """A label-based version of 'key' that in some circumstances refers
1406 to this object in a Python namespace.
1407
1408
1409 _tq_key_label comes into play when a select() statement is constructed
1410 with apply_labels(); in this case, all Column objects in the ``.c``
1411 collection are rendered as <tablename>_<columnname> in SQL; this is
1412 essentially the value of ._label. But to locate those columns in the
1413 ``.c`` collection, the name is along the lines of <tablename>_<key>;
1414 that's the typical value of .key_label.
1415
1416 .. versionchanged:: 1.4.21 renamed from ``._key_label``
1417
1418 """
1419 return self._proxy_key
1420
1421 @property
1422 def _key_label(self) -> Optional[str]:
1423 """legacy; renamed to _tq_key_label"""
1424 return self._tq_key_label
1425
1426 @property
1427 def _label(self) -> Optional[str]:
1428 """legacy; renamed to _tq_label"""
1429 return self._tq_label
1430
1431 @property
1432 def _non_anon_label(self) -> Optional[str]:
1433 """the 'name' that naturally applies this element when rendered in
1434 SQL.
1435
1436 Concretely, this is the "name" of a column or a label in a
1437 SELECT statement; ``<columnname>`` and ``<labelname>`` below:
1438
1439 .. sourcecode:: sql
1440
1441 SELECT <columnmame> FROM table
1442
1443 SELECT column AS <labelname> FROM table
1444
1445 Above, the two names noted will be what's present in the DBAPI
1446 ``cursor.description`` as the names.
1447
1448 If this attribute returns ``None``, it means that the SQL element as
1449 written does not have a 100% fully predictable "name" that would appear
1450 in the ``cursor.description``. Examples include SQL functions, CAST
1451 functions, etc. While such things do return names in
1452 ``cursor.description``, they are only predictable on a
1453 database-specific basis; e.g. an expression like ``MAX(table.col)`` may
1454 appear as the string ``max`` on one database (like PostgreSQL) or may
1455 appear as the whole expression ``max(table.col)`` on SQLite.
1456
1457 The default implementation looks for a ``.name`` attribute on the
1458 object, as has been the precedent established in SQLAlchemy for many
1459 years. An exception is made on the ``FunctionElement`` subclass
1460 so that the return value is always ``None``.
1461
1462 .. versionadded:: 1.4.21
1463
1464
1465
1466 """
1467 return getattr(self, "name", None)
1468
1469 _render_label_in_columns_clause = True
1470 """A flag used by select._columns_plus_names that helps to determine
1471 we are actually going to render in terms of "SELECT <col> AS <label>".
1472 This flag can be returned as False for some Column objects that want
1473 to be rendered as simple "SELECT <col>"; typically columns that don't have
1474 any parent table and are named the same as what the label would be
1475 in any case.
1476
1477 """
1478
1479 _allow_label_resolve = True
1480 """A flag that can be flipped to prevent a column from being resolvable
1481 by string label name.
1482
1483 The joined eager loader strategy in the ORM uses this, for example.
1484
1485 """
1486
1487 _is_implicitly_boolean = False
1488
1489 _alt_names: Sequence[str] = ()
1490
1491 if TYPE_CHECKING:
1492
1493 def _ungroup(self) -> ColumnElement[_T]: ...
1494
1495 @overload
1496 def self_group(self, against: None = None) -> ColumnElement[_T]: ...
1497
1498 @overload
1499 def self_group(
1500 self, against: Optional[OperatorType] = None
1501 ) -> ColumnElement[Any]: ...
1502
1503 def self_group(
1504 self, against: Optional[OperatorType] = None
1505 ) -> ColumnElement[Any]:
1506 if (
1507 against in (operators.and_, operators.or_, operators._asbool)
1508 and self.type._type_affinity is type_api.BOOLEANTYPE._type_affinity
1509 ):
1510 return AsBoolean(self, operators.is_true, operators.is_false)
1511 elif against in (operators.any_op, operators.all_op):
1512 return Grouping(self)
1513 else:
1514 return self
1515
1516 @overload
1517 def _negate(self: ColumnElement[bool]) -> ColumnElement[bool]: ...
1518
1519 @overload
1520 def _negate(self: ColumnElement[_T]) -> ColumnElement[_T]: ...
1521
1522 def _negate(self) -> ColumnElement[Any]:
1523 if self.type._type_affinity is type_api.BOOLEANTYPE._type_affinity:
1524 return AsBoolean(self, operators.is_false, operators.is_true)
1525 else:
1526 grouped = self.self_group(against=operators.inv)
1527 assert isinstance(grouped, ColumnElement)
1528 return UnaryExpression(
1529 grouped,
1530 operator=operators.inv,
1531 )
1532
1533 type: TypeEngine[_T]
1534
1535 if not TYPE_CHECKING:
1536
1537 @util.memoized_property
1538 def type(self) -> TypeEngine[_T]: # noqa: A001
1539 # used for delayed setup of
1540 # type_api
1541 return type_api.NULLTYPE
1542
1543 @HasMemoized.memoized_attribute
1544 def comparator(self) -> TypeEngine.Comparator[_T]:
1545 try:
1546 comparator_factory = self.type.comparator_factory
1547 except AttributeError as err:
1548 raise TypeError(
1549 "Object %r associated with '.type' attribute "
1550 "is not a TypeEngine class or object" % self.type
1551 ) from err
1552 else:
1553 return comparator_factory(self)
1554
1555 def __setstate__(self, state):
1556 self.__dict__.update(state)
1557
1558 def __getattr__(self, key: str) -> Any:
1559 try:
1560 return getattr(self.comparator, key)
1561 except AttributeError as err:
1562 raise AttributeError(
1563 "Neither %r object nor %r object has an attribute %r"
1564 % (
1565 type(self).__name__,
1566 type(self.comparator).__name__,
1567 key,
1568 )
1569 ) from err
1570
1571 def operate(
1572 self,
1573 op: operators.OperatorType,
1574 *other: Any,
1575 **kwargs: Any,
1576 ) -> ColumnElement[Any]:
1577 return op(self.comparator, *other, **kwargs) # type: ignore[no-any-return] # noqa: E501
1578
1579 def reverse_operate(
1580 self, op: operators.OperatorType, other: Any, **kwargs: Any
1581 ) -> ColumnElement[Any]:
1582 return op(other, self.comparator, **kwargs) # type: ignore[no-any-return] # noqa: E501
1583
1584 def _bind_param(
1585 self,
1586 operator: operators.OperatorType,
1587 obj: Any,
1588 type_: Optional[TypeEngine[_T]] = None,
1589 expanding: bool = False,
1590 ) -> BindParameter[_T]:
1591 return BindParameter(
1592 None,
1593 obj,
1594 _compared_to_operator=operator,
1595 type_=type_,
1596 _compared_to_type=self.type,
1597 unique=True,
1598 expanding=expanding,
1599 )
1600
1601 @property
1602 def expression(self) -> ColumnElement[Any]:
1603 """Return a column expression.
1604
1605 Part of the inspection interface; returns self.
1606
1607 """
1608 return self
1609
1610 @property
1611 def _select_iterable(self) -> _SelectIterable:
1612 return (self,)
1613
1614 @util.memoized_property
1615 def base_columns(self) -> FrozenSet[ColumnElement[Any]]:
1616 return frozenset(c for c in self.proxy_set if not c._proxies)
1617
1618 @util.memoized_property
1619 def proxy_set(self) -> FrozenSet[ColumnElement[Any]]:
1620 """set of all columns we are proxying
1621
1622 as of 2.0 this is explicitly deannotated columns. previously it was
1623 effectively deannotated columns but wasn't enforced. annotated
1624 columns should basically not go into sets if at all possible because
1625 their hashing behavior is very non-performant.
1626
1627 """
1628 return frozenset([self._deannotate()]).union(
1629 itertools.chain(*[c.proxy_set for c in self._proxies])
1630 )
1631
1632 @util.memoized_property
1633 def _expanded_proxy_set(self) -> FrozenSet[ColumnElement[Any]]:
1634 return frozenset(_expand_cloned(self.proxy_set))
1635
1636 def _uncached_proxy_list(self) -> List[ColumnElement[Any]]:
1637 """An 'uncached' version of proxy set.
1638
1639 This list includes annotated columns which perform very poorly in
1640 set operations.
1641
1642 """
1643
1644 return [self] + list(
1645 itertools.chain(*[c._uncached_proxy_list() for c in self._proxies])
1646 )
1647
1648 def shares_lineage(self, othercolumn: ColumnElement[Any]) -> bool:
1649 """Return True if the given :class:`_expression.ColumnElement`
1650 has a common ancestor to this :class:`_expression.ColumnElement`."""
1651
1652 return bool(self.proxy_set.intersection(othercolumn.proxy_set))
1653
1654 def _compare_name_for_result(self, other: ColumnElement[Any]) -> bool:
1655 """Return True if the given column element compares to this one
1656 when targeting within a result row."""
1657
1658 return (
1659 hasattr(other, "name")
1660 and hasattr(self, "name")
1661 and other.name == self.name
1662 )
1663
1664 @HasMemoized.memoized_attribute
1665 def _proxy_key(self) -> Optional[str]:
1666 if self._annotations and "proxy_key" in self._annotations:
1667 return cast(str, self._annotations["proxy_key"])
1668
1669 name = self.key
1670 if not name:
1671 # there's a bit of a seeming contradiction which is that the
1672 # "_non_anon_label" of a column can in fact be an
1673 # "_anonymous_label"; this is when it's on a column that is
1674 # proxying for an anonymous expression in a subquery.
1675 name = self._non_anon_label
1676
1677 if isinstance(name, _anonymous_label):
1678 return None
1679 else:
1680 return name
1681
1682 @HasMemoized.memoized_attribute
1683 def _expression_label(self) -> Optional[str]:
1684 """a suggested label to use in the case that the column has no name,
1685 which should be used if possible as the explicit 'AS <label>'
1686 where this expression would normally have an anon label.
1687
1688 this is essentially mostly what _proxy_key does except it returns
1689 None if the column has a normal name that can be used.
1690
1691 """
1692
1693 if getattr(self, "name", None) is not None:
1694 return None
1695 elif self._annotations and "proxy_key" in self._annotations:
1696 return cast(str, self._annotations["proxy_key"])
1697 else:
1698 return None
1699
1700 def _make_proxy(
1701 self,
1702 selectable: FromClause,
1703 *,
1704 primary_key: ColumnSet,
1705 foreign_keys: Set[KeyedColumnElement[Any]],
1706 name: Optional[str] = None,
1707 key: Optional[str] = None,
1708 name_is_truncatable: bool = False,
1709 compound_select_cols: Optional[Sequence[ColumnElement[Any]]] = None,
1710 **kw: Any,
1711 ) -> typing_Tuple[str, ColumnClause[_T]]:
1712 """Create a new :class:`_expression.ColumnElement` representing this
1713 :class:`_expression.ColumnElement` as it appears in the select list of
1714 a descending selectable.
1715
1716 """
1717 if name is None:
1718 name = self._anon_name_label
1719 if key is None:
1720 key = self._proxy_key
1721 else:
1722 key = name
1723
1724 assert key is not None
1725
1726 co: ColumnClause[_T] = ColumnClause(
1727 (
1728 coercions.expect(roles.TruncatedLabelRole, name)
1729 if name_is_truncatable
1730 else name
1731 ),
1732 type_=getattr(self, "type", None),
1733 _selectable=selectable,
1734 )
1735
1736 co._propagate_attrs = selectable._propagate_attrs
1737 if compound_select_cols:
1738 co._proxies = list(compound_select_cols)
1739 else:
1740 co._proxies = [self]
1741 if selectable._is_clone_of is not None:
1742 co._is_clone_of = selectable._is_clone_of.columns.get(key)
1743 return key, co
1744
1745 def cast(self, type_: _TypeEngineArgument[_OPT]) -> Cast[_OPT]:
1746 """Produce a type cast, i.e. ``CAST(<expression> AS <type>)``.
1747
1748 This is a shortcut to the :func:`_expression.cast` function.
1749
1750 .. seealso::
1751
1752 :ref:`tutorial_casts`
1753
1754 :func:`_expression.cast`
1755
1756 :func:`_expression.type_coerce`
1757
1758 """
1759 return Cast(self, type_)
1760
1761 def label(self, name: Optional[str]) -> Label[_T]:
1762 """Produce a column label, i.e. ``<columnname> AS <name>``.
1763
1764 This is a shortcut to the :func:`_expression.label` function.
1765
1766 If 'name' is ``None``, an anonymous label name will be generated.
1767
1768 """
1769 return Label(name, self, self.type)
1770
1771 def _anon_label(
1772 self, seed: Optional[str], add_hash: Optional[int] = None
1773 ) -> _anonymous_label:
1774 while self._is_clone_of is not None:
1775 self = self._is_clone_of
1776
1777 # as of 1.4 anonymous label for ColumnElement uses hash(), not id(),
1778 # as the identifier, because a column and its annotated version are
1779 # the same thing in a SQL statement
1780 hash_value = hash(self)
1781
1782 if add_hash:
1783 # this path is used for disambiguating anon labels that would
1784 # otherwise be the same name for the same element repeated.
1785 # an additional numeric value is factored in for each label.
1786
1787 # shift hash(self) (which is id(self), typically 8 byte integer)
1788 # 16 bits leftward. fill extra add_hash on right
1789 assert add_hash < (2 << 15)
1790 assert seed
1791 hash_value = (hash_value << 16) | add_hash
1792
1793 # extra underscore is added for labels with extra hash
1794 # values, to isolate the "deduped anon" namespace from the
1795 # regular namespace. eliminates chance of these
1796 # manufactured hash values overlapping with regular ones for some
1797 # undefined python interpreter
1798 seed = seed + "_"
1799
1800 if isinstance(seed, _anonymous_label):
1801 # NOTE: the space after the hash is required
1802 return _anonymous_label(f"{seed}%({hash_value} )s")
1803
1804 return _anonymous_label.safe_construct(hash_value, seed or "anon")
1805
1806 @util.memoized_property
1807 def _anon_name_label(self) -> str:
1808 """Provides a constant 'anonymous label' for this ColumnElement.
1809
1810 This is a label() expression which will be named at compile time.
1811 The same label() is returned each time ``anon_label`` is called so
1812 that expressions can reference ``anon_label`` multiple times,
1813 producing the same label name at compile time.
1814
1815 The compiler uses this function automatically at compile time
1816 for expressions that are known to be 'unnamed' like binary
1817 expressions and function calls.
1818
1819 .. versionchanged:: 1.4.9 - this attribute was not intended to be
1820 public and is renamed to _anon_name_label. anon_name exists
1821 for backwards compat
1822
1823 """
1824 name = getattr(self, "name", None)
1825 return self._anon_label(name)
1826
1827 @util.memoized_property
1828 def _anon_key_label(self) -> _anonymous_label:
1829 """Provides a constant 'anonymous key label' for this ColumnElement.
1830
1831 Compare to ``anon_label``, except that the "key" of the column,
1832 if available, is used to generate the label.
1833
1834 This is used when a deduplicating key is placed into the columns
1835 collection of a selectable.
1836
1837 .. versionchanged:: 1.4.9 - this attribute was not intended to be
1838 public and is renamed to _anon_key_label. anon_key_label exists
1839 for backwards compat
1840
1841 """
1842 return self._anon_label(self._proxy_key)
1843
1844 @property
1845 @util.deprecated(
1846 "1.4",
1847 "The :attr:`_expression.ColumnElement.anon_label` attribute is now "
1848 "private, and the public accessor is deprecated.",
1849 )
1850 def anon_label(self) -> str:
1851 return self._anon_name_label
1852
1853 @property
1854 @util.deprecated(
1855 "1.4",
1856 "The :attr:`_expression.ColumnElement.anon_key_label` attribute is "
1857 "now private, and the public accessor is deprecated.",
1858 )
1859 def anon_key_label(self) -> str:
1860 return self._anon_key_label
1861
1862 def _dedupe_anon_label_idx(self, idx: int) -> str:
1863 """label to apply to a column that is anon labeled, but repeated
1864 in the SELECT, so that we have to make an "extra anon" label that
1865 disambiguates it from the previous appearance.
1866
1867 these labels come out like "foo_bar_id__1" and have double underscores
1868 in them.
1869
1870 """
1871 label = getattr(self, "name", None)
1872
1873 # current convention is that if the element doesn't have a
1874 # ".name" (usually because it is not NamedColumn), we try to
1875 # use a "table qualified" form for the "dedupe anon" label,
1876 # based on the notion that a label like
1877 # "CAST(casttest.v1 AS DECIMAL) AS casttest_v1__1" looks better than
1878 # "CAST(casttest.v1 AS DECIMAL) AS anon__1"
1879
1880 if label is None:
1881 return self._dedupe_anon_tq_label_idx(idx)
1882 else:
1883 return self._anon_label(label, add_hash=idx)
1884
1885 @util.memoized_property
1886 def _anon_tq_label(self) -> _anonymous_label:
1887 return self._anon_label(getattr(self, "_tq_label", None))
1888
1889 @util.memoized_property
1890 def _anon_tq_key_label(self) -> _anonymous_label:
1891 return self._anon_label(getattr(self, "_tq_key_label", None))
1892
1893 def _dedupe_anon_tq_label_idx(self, idx: int) -> _anonymous_label:
1894 label = getattr(self, "_tq_label", None) or "anon"
1895
1896 return self._anon_label(label, add_hash=idx)
1897
1898
1899class KeyedColumnElement(ColumnElement[_T]):
1900 """ColumnElement where ``.key`` is non-None."""
1901
1902 _is_keyed_column_element = True
1903
1904 key: str
1905
1906
1907class WrapsColumnExpression(ColumnElement[_T]):
1908 """Mixin that defines a :class:`_expression.ColumnElement`
1909 as a wrapper with special
1910 labeling behavior for an expression that already has a name.
1911
1912 .. versionadded:: 1.4
1913
1914 .. seealso::
1915
1916 :ref:`change_4449`
1917
1918
1919 """
1920
1921 @property
1922 def wrapped_column_expression(self) -> ColumnElement[_T]:
1923 raise NotImplementedError()
1924
1925 @util.non_memoized_property
1926 def _tq_label(self) -> Optional[str]:
1927 wce = self.wrapped_column_expression
1928 if hasattr(wce, "_tq_label"):
1929 return wce._tq_label
1930 else:
1931 return None
1932
1933 @property
1934 def _label(self) -> Optional[str]:
1935 return self._tq_label
1936
1937 @property
1938 def _non_anon_label(self) -> Optional[str]:
1939 return None
1940
1941 @util.non_memoized_property
1942 def _anon_name_label(self) -> str:
1943 wce = self.wrapped_column_expression
1944
1945 # this logic tries to get the WrappedColumnExpression to render
1946 # with "<expr> AS <name>", where "<name>" is the natural name
1947 # within the expression itself. e.g. "CAST(table.foo) AS foo".
1948 if not wce._is_text_clause:
1949 nal = wce._non_anon_label
1950 if nal:
1951 return nal
1952 elif hasattr(wce, "_anon_name_label"):
1953 return wce._anon_name_label
1954 return super()._anon_name_label
1955
1956 def _dedupe_anon_label_idx(self, idx: int) -> str:
1957 wce = self.wrapped_column_expression
1958 nal = wce._non_anon_label
1959 if nal:
1960 return self._anon_label(nal + "_")
1961 else:
1962 return self._dedupe_anon_tq_label_idx(idx)
1963
1964 @property
1965 def _proxy_key(self):
1966 wce = self.wrapped_column_expression
1967
1968 if not wce._is_text_clause:
1969 return wce._proxy_key
1970 return super()._proxy_key
1971
1972
1973class DMLTargetCopy(roles.InElementRole, KeyedColumnElement[_T]):
1974 """Refer to another column's VALUES or SET expression in an INSERT or
1975 UPDATE statement.
1976
1977 See the public-facing :func:`_sql.from_dml_column` constructor for
1978 background.
1979
1980 .. versionadded:: 2.1
1981
1982
1983 """
1984
1985 def __init__(self, column: _DMLOnlyColumnArgument[_T]):
1986 self.column = coercions.expect(roles.ColumnArgumentRole, column)
1987 self.type = self.column.type
1988
1989 __visit_name__ = "dmltargetcopy"
1990
1991 _traverse_internals: _TraverseInternalsType = [
1992 ("column", InternalTraversal.dp_clauseelement),
1993 ]
1994
1995
1996class BindParameter(roles.InElementRole, KeyedColumnElement[_T]):
1997 r"""Represent a "bound expression".
1998
1999 :class:`.BindParameter` is invoked explicitly using the
2000 :func:`.bindparam` function, as in::
2001
2002 from sqlalchemy import bindparam
2003
2004 stmt = select(users_table).where(
2005 users_table.c.name == bindparam("username")
2006 )
2007
2008 Detailed discussion of how :class:`.BindParameter` is used is
2009 at :func:`.bindparam`.
2010
2011 .. seealso::
2012
2013 :func:`.bindparam`
2014
2015 """
2016
2017 __visit_name__ = "bindparam"
2018
2019 _traverse_internals: _TraverseInternalsType = [
2020 ("key", InternalTraversal.dp_anon_name),
2021 ("type", InternalTraversal.dp_type),
2022 ("callable", InternalTraversal.dp_plain_dict),
2023 ("value", InternalTraversal.dp_plain_obj),
2024 ("literal_execute", InternalTraversal.dp_boolean),
2025 ]
2026
2027 key: str
2028 _anon_map_key: Optional[str] = None
2029 type: TypeEngine[_T]
2030 value: Optional[_T]
2031
2032 _is_crud = False
2033 _is_bind_parameter = True
2034
2035 # bindparam implements its own _gen_cache_key() method however
2036 # we check subclasses for this flag, else no cache key is generated
2037 inherit_cache = True
2038
2039 def __init__(
2040 self,
2041 key: Optional[str],
2042 value: Any = _NoArg.NO_ARG,
2043 type_: Optional[_TypeEngineArgument[_T]] = None,
2044 unique: bool = False,
2045 required: Union[bool, Literal[_NoArg.NO_ARG]] = _NoArg.NO_ARG,
2046 quote: Optional[bool] = None,
2047 callable_: Optional[Callable[[], Any]] = None,
2048 expanding: bool = False,
2049 isoutparam: bool = False,
2050 literal_execute: bool = False,
2051 _compared_to_operator: Optional[OperatorType] = None,
2052 _compared_to_type: Optional[TypeEngine[Any]] = None,
2053 _is_crud: bool = False,
2054 ):
2055 if required is _NoArg.NO_ARG:
2056 required = value is _NoArg.NO_ARG and callable_ is None
2057 if value is _NoArg.NO_ARG:
2058 value = None
2059
2060 if quote is not None:
2061 key = quoted_name.construct(key, quote)
2062
2063 if unique:
2064 self.key, self._anon_map_key = (
2065 _anonymous_label.safe_construct_with_key(
2066 id(self),
2067 (
2068 key
2069 if key is not None
2070 and not isinstance(key, _anonymous_label)
2071 else "param"
2072 ),
2073 sanitize_key=True,
2074 )
2075 )
2076 elif key:
2077 self.key = key
2078 else:
2079 self.key, self._anon_map_key = (
2080 _anonymous_label.safe_construct_with_key(id(self), "param")
2081 )
2082
2083 # identifying key that won't change across
2084 # clones, used to identify the bind's logical
2085 # identity
2086 self._identifying_key = self.key
2087
2088 # key that was passed in the first place, used to
2089 # generate new keys
2090 self._orig_key = key or "param"
2091
2092 self.unique = unique
2093 self.value = value
2094 self.callable = callable_
2095 self.isoutparam = isoutparam
2096 self.required = required
2097
2098 # indicate an "expanding" parameter; the compiler sets this
2099 # automatically in the compiler _render_in_expr_w_bindparam method
2100 # for an IN expression
2101 self.expanding = expanding
2102
2103 # this is another hint to help w/ expanding and is typically
2104 # set in the compiler _render_in_expr_w_bindparam method for an
2105 # IN expression
2106 self.expand_op = None
2107
2108 self.literal_execute = literal_execute
2109 if _is_crud:
2110 self._is_crud = True
2111
2112 if type_ is None:
2113 if expanding:
2114 if value:
2115 check_value = value[0]
2116 else:
2117 check_value = type_api._NO_VALUE_IN_LIST
2118 else:
2119 check_value = value
2120 if _compared_to_type is not None:
2121 self.type = _compared_to_type.coerce_compared_value(
2122 _compared_to_operator, check_value
2123 )
2124 else:
2125 self.type = type_api._resolve_value_to_type(check_value)
2126 elif isinstance(type_, type):
2127 self.type = type_()
2128 elif is_tuple_type(type_):
2129 if value:
2130 if expanding:
2131 check_value = value[0]
2132 else:
2133 check_value = value
2134 cast("BindParameter[TupleAny]", self).type = (
2135 type_._resolve_values_to_types(check_value)
2136 )
2137 else:
2138 cast("BindParameter[TupleAny]", self).type = type_
2139 else:
2140 self.type = type_
2141
2142 def _with_value(self, value, maintain_key=False, required=NO_ARG):
2143 """Return a copy of this :class:`.BindParameter` with the given value
2144 set.
2145 """
2146 cloned = self._clone(maintain_key=maintain_key)
2147 cloned.value = value
2148 cloned.callable = None
2149 cloned.required = required if required is not NO_ARG else self.required
2150 if cloned.type is type_api.NULLTYPE:
2151 cloned.type = type_api._resolve_value_to_type(value)
2152 return cloned
2153
2154 @property
2155 def effective_value(self) -> Optional[_T]:
2156 """Return the value of this bound parameter,
2157 taking into account if the ``callable`` parameter
2158 was set.
2159
2160 The ``callable`` value will be evaluated
2161 and returned if present, else ``value``.
2162
2163 """
2164 if self.callable:
2165 # TODO: set up protocol for bind parameter callable
2166 return self.callable() # type: ignore
2167 else:
2168 return self.value
2169
2170 def render_literal_execute(self) -> Self:
2171 """Produce a copy of this bound parameter that will enable the
2172 :paramref:`_sql.BindParameter.literal_execute` flag.
2173
2174 The :paramref:`_sql.BindParameter.literal_execute` flag will
2175 have the effect of the parameter rendered in the compiled SQL
2176 string using ``[POSTCOMPILE]`` form, which is a special form that
2177 is converted to be a rendering of the literal value of the parameter
2178 at SQL execution time. The rationale is to support caching
2179 of SQL statement strings that can embed per-statement literal values,
2180 such as LIMIT and OFFSET parameters, in the final SQL string that
2181 is passed to the DBAPI. Dialects in particular may want to use
2182 this method within custom compilation schemes.
2183
2184 .. versionadded:: 1.4.5
2185
2186 .. seealso::
2187
2188 :ref:`engine_thirdparty_caching`
2189
2190 """
2191 c: Self = ClauseElement._clone(self)
2192 c.literal_execute = True
2193 return c
2194
2195 def _negate_in_binary(self, negated_op, original_op):
2196 if self.expand_op is original_op:
2197 bind = self._clone()
2198 bind.expand_op = negated_op
2199 return bind
2200 else:
2201 return self
2202
2203 def _with_binary_element_type(self, type_: TypeEngine[Any]) -> Self:
2204 c: Self = ClauseElement._clone(self)
2205 c.type = type_
2206 return c
2207
2208 def _clone(self, maintain_key: bool = False, **kw: Any) -> Self:
2209 c: Self = ClauseElement._clone(self, **kw)
2210 # ensure all the BindParameter objects stay in cloned set.
2211 # in #7823, we changed "clone" so that a clone only keeps a reference
2212 # to the "original" element, since for column correspondence, that's
2213 # all we need. However, for BindParam, _cloned_set is used by
2214 # the "cache key bind match" lookup, which means if any of those
2215 # interim BindParameter objects became part of a cache key in the
2216 # cache, we need it. So here, make sure all clones keep carrying
2217 # forward.
2218 c._cloned_set.update(self._cloned_set)
2219 if not maintain_key and self.unique:
2220 c.key, c._anon_map_key = _anonymous_label.safe_construct_with_key(
2221 id(c), c._orig_key or "param", sanitize_key=True
2222 )
2223 return c
2224
2225 def _gen_cache_key(self, anon_map, bindparams):
2226 _gen_cache_ok = self.__class__.__dict__.get("inherit_cache", False)
2227
2228 if not _gen_cache_ok:
2229 if anon_map is not None:
2230 anon_map[NO_CACHE] = True
2231 return None
2232
2233 id_, found = anon_map.get_anon(self)
2234 if found:
2235 return (id_, self.__class__)
2236
2237 if bindparams is not None:
2238 bindparams.append(self)
2239
2240 return (
2241 id_,
2242 self.__class__,
2243 self.type._static_cache_key,
2244 (
2245 anon_map[self._anon_map_key]
2246 if self._anon_map_key is not None
2247 else self.key
2248 ),
2249 self.literal_execute,
2250 )
2251
2252 def _convert_to_unique(self):
2253 if not self.unique:
2254 self.unique = True
2255 self.key, self._anon_map_key = (
2256 _anonymous_label.safe_construct_with_key(
2257 id(self), self._orig_key or "param", sanitize_key=True
2258 )
2259 )
2260
2261 def __getstate__(self):
2262 """execute a deferred value for serialization purposes."""
2263
2264 d = self.__dict__.copy()
2265 v = self.value
2266 if self.callable:
2267 v = self.callable()
2268 d["callable"] = None
2269 d["value"] = v
2270 return d
2271
2272 def __setstate__(self, state):
2273 if state.get("unique", False):
2274 anon_and_key = _anonymous_label.safe_construct_with_key(
2275 id(self), state.get("_orig_key", "param"), sanitize_key=True
2276 )
2277 state["key"], state["_anon_map_key"] = anon_and_key
2278 self.__dict__.update(state)
2279
2280 def __repr__(self):
2281 return "%s(%r, %r, type_=%r)" % (
2282 self.__class__.__name__,
2283 self.key,
2284 self.value,
2285 self.type,
2286 )
2287
2288
2289class TypeClause(DQLDMLClauseElement):
2290 """Handle a type keyword in a SQL statement.
2291
2292 Used by the ``Case`` statement.
2293
2294 """
2295
2296 __visit_name__ = "typeclause"
2297
2298 _traverse_internals: _TraverseInternalsType = [
2299 ("type", InternalTraversal.dp_type)
2300 ]
2301 type: TypeEngine[Any]
2302
2303 def __init__(self, type_: TypeEngine[Any]):
2304 self.type = type_
2305
2306
2307class TextClause(
2308 roles.DDLConstraintColumnRole,
2309 roles.DDLExpressionRole,
2310 roles.StatementOptionRole,
2311 roles.WhereHavingRole,
2312 roles.OrderByRole,
2313 roles.FromClauseRole,
2314 roles.SelectStatementRole,
2315 roles.InElementRole,
2316 Generative,
2317 Executable,
2318 DQLDMLClauseElement,
2319 roles.BinaryElementRole[Any],
2320 inspection.Inspectable["TextClause"],
2321):
2322 """Represent a literal SQL text fragment.
2323
2324 E.g.::
2325
2326 from sqlalchemy import text
2327
2328 t = text("SELECT * FROM users")
2329 result = connection.execute(t)
2330
2331 The :class:`_expression.TextClause` construct is produced using the
2332 :func:`_expression.text`
2333 function; see that function for full documentation.
2334
2335 .. seealso::
2336
2337 :func:`_expression.text`
2338
2339 """
2340
2341 __visit_name__ = "textclause"
2342
2343 _traverse_internals: _TraverseInternalsType = [
2344 ("_bindparams", InternalTraversal.dp_string_clauseelement_dict),
2345 ("text", InternalTraversal.dp_string),
2346 ] + Executable._executable_traverse_internals
2347
2348 _is_text_clause = True
2349
2350 _is_textual = True
2351
2352 _bind_params_regex = re.compile(r"(?<![:\w\x5c]):(\w+)(?!:)", re.UNICODE)
2353 _is_implicitly_boolean = False
2354
2355 _render_label_in_columns_clause = False
2356
2357 _omit_from_statements = False
2358
2359 _is_collection_aggregate = False
2360
2361 @property
2362 def _hide_froms(self) -> Iterable[FromClause]:
2363 return ()
2364
2365 def __and__(self, other):
2366 # support use in select.where(), query.filter()
2367 return and_(self, other)
2368
2369 @property
2370 def _select_iterable(self) -> _SelectIterable:
2371 return (self,)
2372
2373 # help in those cases where text() is
2374 # interpreted in a column expression situation
2375 key: Optional[str] = None
2376 _label: Optional[str] = None
2377
2378 _allow_label_resolve = False
2379
2380 @property
2381 def _is_star(self): # type: ignore[override]
2382 return self.text == "*"
2383
2384 def __init__(self, text: str):
2385 self._bindparams: Dict[str, BindParameter[Any]] = {}
2386
2387 def repl(m):
2388 self._bindparams[m.group(1)] = BindParameter(m.group(1))
2389 return ":%s" % m.group(1)
2390
2391 # scan the string and search for bind parameter names, add them
2392 # to the list of bindparams
2393 self.text = self._bind_params_regex.sub(repl, text)
2394
2395 @_generative
2396 def bindparams(
2397 self,
2398 *binds: BindParameter[Any],
2399 **names_to_values: Any,
2400 ) -> Self:
2401 """Establish the values and/or types of bound parameters within
2402 this :class:`_expression.TextClause` construct.
2403
2404 Given a text construct such as::
2405
2406 from sqlalchemy import text
2407
2408 stmt = text(
2409 "SELECT id, name FROM user WHERE name=:name AND timestamp=:timestamp"
2410 )
2411
2412 the :meth:`_expression.TextClause.bindparams`
2413 method can be used to establish
2414 the initial value of ``:name`` and ``:timestamp``,
2415 using simple keyword arguments::
2416
2417 stmt = stmt.bindparams(
2418 name="jack", timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5)
2419 )
2420
2421 Where above, new :class:`.BindParameter` objects
2422 will be generated with the names ``name`` and ``timestamp``, and
2423 values of ``jack`` and ``datetime.datetime(2012, 10, 8, 15, 12, 5)``,
2424 respectively. The types will be
2425 inferred from the values given, in this case :class:`.String` and
2426 :class:`.DateTime`.
2427
2428 When specific typing behavior is needed, the positional ``*binds``
2429 argument can be used in which to specify :func:`.bindparam` constructs
2430 directly. These constructs must include at least the ``key``
2431 argument, then an optional value and type::
2432
2433 from sqlalchemy import bindparam
2434
2435 stmt = stmt.bindparams(
2436 bindparam("name", value="jack", type_=String),
2437 bindparam("timestamp", type_=DateTime),
2438 )
2439
2440 Above, we specified the type of :class:`.DateTime` for the
2441 ``timestamp`` bind, and the type of :class:`.String` for the ``name``
2442 bind. In the case of ``name`` we also set the default value of
2443 ``"jack"``.
2444
2445 Additional bound parameters can be supplied at statement execution
2446 time, e.g.::
2447
2448 result = connection.execute(
2449 stmt, timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5)
2450 )
2451
2452 The :meth:`_expression.TextClause.bindparams`
2453 method can be called repeatedly,
2454 where it will re-use existing :class:`.BindParameter` objects to add
2455 new information. For example, we can call
2456 :meth:`_expression.TextClause.bindparams`
2457 first with typing information, and a
2458 second time with value information, and it will be combined::
2459
2460 stmt = text(
2461 "SELECT id, name FROM user WHERE name=:name "
2462 "AND timestamp=:timestamp"
2463 )
2464 stmt = stmt.bindparams(
2465 bindparam("name", type_=String), bindparam("timestamp", type_=DateTime)
2466 )
2467 stmt = stmt.bindparams(
2468 name="jack", timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5)
2469 )
2470
2471 The :meth:`_expression.TextClause.bindparams`
2472 method also supports the concept of
2473 **unique** bound parameters. These are parameters that are
2474 "uniquified" on name at statement compilation time, so that multiple
2475 :func:`_expression.text`
2476 constructs may be combined together without the names
2477 conflicting. To use this feature, specify the
2478 :paramref:`.BindParameter.unique` flag on each :func:`.bindparam`
2479 object::
2480
2481 stmt1 = text("select id from table where name=:name").bindparams(
2482 bindparam("name", value="name1", unique=True)
2483 )
2484 stmt2 = text("select id from table where name=:name").bindparams(
2485 bindparam("name", value="name2", unique=True)
2486 )
2487
2488 union = union_all(stmt1.columns(column("id")), stmt2.columns(column("id")))
2489
2490 The above statement will render as:
2491
2492 .. sourcecode:: sql
2493
2494 select id from table where name=:name_1
2495 UNION ALL select id from table where name=:name_2
2496
2497 """ # noqa: E501
2498 self._bindparams = new_params = self._bindparams.copy()
2499
2500 for bind in binds:
2501 try:
2502 # the regex used for text() currently will not match
2503 # a unique/anonymous key in any case, so use the _orig_key
2504 # so that a text() construct can support unique parameters
2505 existing = new_params[bind._orig_key]
2506 except KeyError as err:
2507 raise exc.ArgumentError(
2508 "This text() construct doesn't define a "
2509 "bound parameter named %r" % bind._orig_key
2510 ) from err
2511 else:
2512 new_params[existing._orig_key] = bind
2513
2514 for key, value in names_to_values.items():
2515 try:
2516 existing = new_params[key]
2517 except KeyError as err:
2518 raise exc.ArgumentError(
2519 "This text() construct doesn't define a "
2520 "bound parameter named %r" % key
2521 ) from err
2522 else:
2523 new_params[key] = existing._with_value(value, required=False)
2524 return self
2525
2526 @util.preload_module("sqlalchemy.sql.selectable")
2527 def columns(
2528 self,
2529 *cols: _ColumnExpressionArgument[Any],
2530 **types: _TypeEngineArgument[Any],
2531 ) -> TextualSelect:
2532 r"""Turn this :class:`_expression.TextClause` object into a
2533 :class:`_expression.TextualSelect`
2534 object that serves the same role as a SELECT
2535 statement.
2536
2537 The :class:`_expression.TextualSelect` is part of the
2538 :class:`_expression.SelectBase`
2539 hierarchy and can be embedded into another statement by using the
2540 :meth:`_expression.TextualSelect.subquery` method to produce a
2541 :class:`.Subquery`
2542 object, which can then be SELECTed from.
2543
2544 This function essentially bridges the gap between an entirely
2545 textual SELECT statement and the SQL expression language concept
2546 of a "selectable"::
2547
2548 from sqlalchemy.sql import column, text
2549
2550 stmt = text("SELECT id, name FROM some_table")
2551 stmt = stmt.columns(column("id"), column("name")).subquery("st")
2552
2553 stmt = (
2554 select(mytable)
2555 .select_from(mytable.join(stmt, mytable.c.name == stmt.c.name))
2556 .where(stmt.c.id > 5)
2557 )
2558
2559 Above, we pass a series of :func:`_expression.column` elements to the
2560 :meth:`_expression.TextClause.columns` method positionally. These
2561 :func:`_expression.column`
2562 elements now become first class elements upon the
2563 :attr:`_expression.TextualSelect.selected_columns` column collection,
2564 which then
2565 become part of the :attr:`.Subquery.c` collection after
2566 :meth:`_expression.TextualSelect.subquery` is invoked.
2567
2568 The column expressions we pass to
2569 :meth:`_expression.TextClause.columns` may
2570 also be typed; when we do so, these :class:`.TypeEngine` objects become
2571 the effective return type of the column, so that SQLAlchemy's
2572 result-set-processing systems may be used on the return values.
2573 This is often needed for types such as date or boolean types, as well
2574 as for unicode processing on some dialect configurations::
2575
2576 stmt = text("SELECT id, name, timestamp FROM some_table")
2577 stmt = stmt.columns(
2578 column("id", Integer),
2579 column("name", Unicode),
2580 column("timestamp", DateTime),
2581 )
2582
2583 for id, name, timestamp in connection.execute(stmt):
2584 print(id, name, timestamp)
2585
2586 As a shortcut to the above syntax, keyword arguments referring to
2587 types alone may be used, if only type conversion is needed::
2588
2589 stmt = text("SELECT id, name, timestamp FROM some_table")
2590 stmt = stmt.columns(id=Integer, name=Unicode, timestamp=DateTime)
2591
2592 for id, name, timestamp in connection.execute(stmt):
2593 print(id, name, timestamp)
2594
2595 The positional form of :meth:`_expression.TextClause.columns`
2596 also provides the
2597 unique feature of **positional column targeting**, which is
2598 particularly useful when using the ORM with complex textual queries. If
2599 we specify the columns from our model to
2600 :meth:`_expression.TextClause.columns`,
2601 the result set will match to those columns positionally, meaning the
2602 name or origin of the column in the textual SQL doesn't matter::
2603
2604 stmt = text(
2605 "SELECT users.id, addresses.id, users.id, "
2606 "users.name, addresses.email_address AS email "
2607 "FROM users JOIN addresses ON users.id=addresses.user_id "
2608 "WHERE users.id = 1"
2609 ).columns(
2610 User.id,
2611 Address.id,
2612 Address.user_id,
2613 User.name,
2614 Address.email_address,
2615 )
2616
2617 query = (
2618 session.query(User)
2619 .from_statement(stmt)
2620 .options(contains_eager(User.addresses))
2621 )
2622
2623 The :meth:`_expression.TextClause.columns` method provides a direct
2624 route to calling :meth:`_expression.FromClause.subquery` as well as
2625 :meth:`_expression.SelectBase.cte`
2626 against a textual SELECT statement::
2627
2628 stmt = stmt.columns(id=Integer, name=String).cte("st")
2629
2630 stmt = select(sometable).where(sometable.c.id == stmt.c.id)
2631
2632 :param \*cols: A series of :class:`_expression.ColumnElement` objects,
2633 typically
2634 :class:`_schema.Column` objects from a :class:`_schema.Table`
2635 or ORM level
2636 column-mapped attributes, representing a set of columns that this
2637 textual string will SELECT from.
2638
2639 :param \**types: A mapping of string names to :class:`.TypeEngine`
2640 type objects indicating the datatypes to use for names that are
2641 SELECTed from the textual string. Prefer to use the ``*cols``
2642 argument as it also indicates positional ordering.
2643
2644 """
2645 selectable = util.preloaded.sql_selectable
2646
2647 input_cols: List[NamedColumn[Any]] = [
2648 coercions.expect(roles.LabeledColumnExprRole, col) for col in cols
2649 ]
2650
2651 positional_input_cols = [
2652 (
2653 ColumnClause(col.key, types.pop(col.key))
2654 if col.key in types
2655 else col
2656 )
2657 for col in input_cols
2658 ]
2659 keyed_input_cols: List[NamedColumn[Any]] = [
2660 ColumnClause(key, type_) for key, type_ in types.items()
2661 ]
2662
2663 elem = selectable.TextualSelect.__new__(selectable.TextualSelect)
2664 elem._init(
2665 self,
2666 positional_input_cols + keyed_input_cols,
2667 positional=bool(positional_input_cols) and not keyed_input_cols,
2668 )
2669 return elem
2670
2671 @property
2672 def type(self) -> TypeEngine[Any]:
2673 return type_api.NULLTYPE
2674
2675 @property
2676 def comparator(self):
2677 # TODO: this seems wrong, it seems like we might not
2678 # be using this method.
2679 return self.type.comparator_factory(self) # type: ignore
2680
2681 def self_group(
2682 self, against: Optional[OperatorType] = None
2683 ) -> Union[Self, Grouping[Any]]:
2684 if against is operators.in_op:
2685 return Grouping(self)
2686 else:
2687 return self
2688
2689
2690class Null(SingletonConstant, roles.ConstExprRole[None], ColumnElement[None]):
2691 """Represent the NULL keyword in a SQL statement.
2692
2693 :class:`.Null` is accessed as a constant via the
2694 :func:`.null` function.
2695
2696 """
2697
2698 __visit_name__ = "null"
2699
2700 _traverse_internals: _TraverseInternalsType = []
2701 _singleton: Null
2702
2703 if not TYPE_CHECKING:
2704
2705 @util.memoized_property
2706 def type(self) -> TypeEngine[_T]: # noqa: A001
2707 return type_api.NULLTYPE
2708
2709 @classmethod
2710 def _instance(cls) -> Null:
2711 """Return a constant :class:`.Null` construct."""
2712
2713 return Null._singleton
2714
2715
2716Null._create_singleton()
2717
2718
2719class False_(
2720 SingletonConstant, roles.ConstExprRole[bool], ColumnElement[bool]
2721):
2722 """Represent the ``false`` keyword, or equivalent, in a SQL statement.
2723
2724 :class:`.False_` is accessed as a constant via the
2725 :func:`.false` function.
2726
2727 """
2728
2729 __visit_name__ = "false"
2730 _traverse_internals: _TraverseInternalsType = []
2731 _singleton: False_
2732
2733 if not TYPE_CHECKING:
2734
2735 @util.memoized_property
2736 def type(self) -> TypeEngine[_T]: # noqa: A001
2737 return type_api.BOOLEANTYPE
2738
2739 def _negate(self) -> True_:
2740 return True_._singleton
2741
2742 @classmethod
2743 def _instance(cls) -> False_:
2744 return False_._singleton
2745
2746
2747False_._create_singleton()
2748
2749
2750class True_(SingletonConstant, roles.ConstExprRole[bool], ColumnElement[bool]):
2751 """Represent the ``true`` keyword, or equivalent, in a SQL statement.
2752
2753 :class:`.True_` is accessed as a constant via the
2754 :func:`.true` function.
2755
2756 """
2757
2758 __visit_name__ = "true"
2759
2760 _traverse_internals: _TraverseInternalsType = []
2761 _singleton: True_
2762
2763 if not TYPE_CHECKING:
2764
2765 @util.memoized_property
2766 def type(self) -> TypeEngine[_T]: # noqa: A001
2767 return type_api.BOOLEANTYPE
2768
2769 def _negate(self) -> False_:
2770 return False_._singleton
2771
2772 @classmethod
2773 def _ifnone(
2774 cls, other: Optional[ColumnElement[Any]]
2775 ) -> ColumnElement[Any]:
2776 if other is None:
2777 return cls._instance()
2778 else:
2779 return other
2780
2781 @classmethod
2782 def _instance(cls) -> True_:
2783 return True_._singleton
2784
2785
2786True_._create_singleton()
2787
2788
2789class ElementList(DQLDMLClauseElement):
2790 """Describe a list of clauses that will be space separated.
2791
2792 This is a minimal version of :class:`.ClauseList` which is used by
2793 the :class:`.HasSyntaxExtension` class. It does not do any coercions
2794 so should be used internally only.
2795
2796 .. versionadded:: 2.1
2797
2798 """
2799
2800 __visit_name__ = "element_list"
2801
2802 _traverse_internals: _TraverseInternalsType = [
2803 ("clauses", InternalTraversal.dp_clauseelement_tuple),
2804 ]
2805
2806 clauses: typing_Tuple[ClauseElement, ...]
2807
2808 def __init__(self, clauses: Sequence[ClauseElement]):
2809 self.clauses = tuple(clauses)
2810
2811
2812class OrderByList(
2813 roles.OrderByRole,
2814 operators.OrderingOperators,
2815 DQLDMLClauseElement,
2816):
2817 """Describe a list of clauses that will be comma separated to nest
2818 within an ORDER BY.
2819
2820 .. versionadded:: 2.1
2821
2822 """
2823
2824 __visit_name__ = "order_by_list"
2825
2826 _traverse_internals: _TraverseInternalsType = [
2827 ("clauses", InternalTraversal.dp_clauseelement_tuple),
2828 ]
2829
2830 clauses: List[ColumnElement[Any]]
2831
2832 def __init__(
2833 self,
2834 clauses: Iterable[Union[OrderByList, _ColumnExpressionArgument[Any]]],
2835 ):
2836 text_converter_role: Type[roles.SQLRole] = roles.ByOfRole
2837 self._text_converter_role = text_converter_role
2838
2839 self.clauses = [
2840 coercions.expect(
2841 text_converter_role, clause, apply_propagate_attrs=self
2842 )
2843 for clause in clauses
2844 ]
2845
2846 def __iter__(self) -> Iterator[ColumnElement[Any]]:
2847 return iter(self.clauses)
2848
2849 def __len__(self) -> int:
2850 return len(self.clauses)
2851
2852 @property
2853 def _select_iterable(self) -> _SelectIterable:
2854 return itertools.chain.from_iterable(
2855 [elem._select_iterable for elem in self.clauses]
2856 )
2857
2858 @util.ro_non_memoized_property
2859 def _from_objects(self) -> List[FromClause]:
2860 return list(itertools.chain(*[c._from_objects for c in self.clauses]))
2861
2862 def self_group(
2863 self, against: Optional[OperatorType] = None
2864 ) -> Union[Self, Grouping[Any]]:
2865 return self
2866
2867 def desc(self) -> OrderByList:
2868 return OrderByList([e.desc() for e in self.clauses])
2869
2870 def asc(self) -> OrderByList:
2871 return OrderByList([e.asc() for e in self.clauses])
2872
2873 def nulls_first(self) -> OrderByList:
2874 return OrderByList([e.nulls_first() for e in self.clauses])
2875
2876 def nulls_last(self) -> OrderByList:
2877 return OrderByList([e.nulls_last() for e in self.clauses])
2878
2879
2880class ClauseList(
2881 roles.InElementRole,
2882 roles.OrderByRole,
2883 roles.ColumnsClauseRole,
2884 roles.DMLColumnRole,
2885 DQLDMLClauseElement,
2886):
2887 """Describe a list of clauses, separated by an operator.
2888
2889 By default, is comma-separated, such as a column listing.
2890
2891 """
2892
2893 __visit_name__ = "clauselist"
2894
2895 # Used by ORM context.py to identify ClauseList objects in legacy
2896 # composite attribute queries (see test_query_cols_legacy test)
2897 _is_clause_list = True
2898
2899 _traverse_internals: _TraverseInternalsType = [
2900 ("clauses", InternalTraversal.dp_clauseelement_list),
2901 ("operator", InternalTraversal.dp_operator),
2902 ]
2903
2904 clauses: List[ColumnElement[Any]]
2905
2906 def __init__(
2907 self,
2908 *clauses: _ColumnExpressionArgument[Any],
2909 operator: OperatorType = operators.comma_op,
2910 group: bool = True,
2911 group_contents: bool = True,
2912 _literal_as_text_role: Type[roles.SQLRole] = roles.WhereHavingRole,
2913 ):
2914 self.operator = operator
2915 self.group = group
2916 self.group_contents = group_contents
2917 clauses_iterator: Iterable[_ColumnExpressionArgument[Any]] = clauses
2918 text_converter_role: Type[roles.SQLRole] = _literal_as_text_role
2919 self._text_converter_role = text_converter_role
2920
2921 if self.group_contents:
2922 self.clauses = [
2923 coercions.expect(
2924 text_converter_role, clause, apply_propagate_attrs=self
2925 ).self_group(against=self.operator)
2926 for clause in clauses_iterator
2927 ]
2928 else:
2929 self.clauses = [
2930 coercions.expect(
2931 text_converter_role, clause, apply_propagate_attrs=self
2932 )
2933 for clause in clauses_iterator
2934 ]
2935 self._is_implicitly_boolean = operators.is_boolean(self.operator)
2936
2937 @classmethod
2938 def _construct_raw(
2939 cls,
2940 operator: OperatorType,
2941 clauses: Optional[Sequence[ColumnElement[Any]]] = None,
2942 ) -> ClauseList:
2943 self = cls.__new__(cls)
2944 self.clauses = list(clauses) if clauses else []
2945 self.group = True
2946 self.operator = operator
2947 self.group_contents = True
2948 self._is_implicitly_boolean = False
2949 return self
2950
2951 def __iter__(self) -> Iterator[ColumnElement[Any]]:
2952 return iter(self.clauses)
2953
2954 def __len__(self) -> int:
2955 return len(self.clauses)
2956
2957 @property
2958 def _select_iterable(self) -> _SelectIterable:
2959 return itertools.chain.from_iterable(
2960 [elem._select_iterable for elem in self.clauses]
2961 )
2962
2963 def append(self, clause):
2964 if self.group_contents:
2965 self.clauses.append(
2966 coercions.expect(self._text_converter_role, clause).self_group(
2967 against=self.operator
2968 )
2969 )
2970 else:
2971 self.clauses.append(
2972 coercions.expect(self._text_converter_role, clause)
2973 )
2974
2975 @util.ro_non_memoized_property
2976 def _from_objects(self) -> List[FromClause]:
2977 return list(itertools.chain(*[c._from_objects for c in self.clauses]))
2978
2979 def self_group(
2980 self, against: Optional[OperatorType] = None
2981 ) -> Union[Self, Grouping[Any]]:
2982 if self.group and operators.is_precedent(self.operator, against):
2983 return Grouping(self)
2984 else:
2985 return self
2986
2987
2988class OperatorExpression(ColumnElement[_T]):
2989 """base for expressions that contain an operator and operands
2990
2991 .. versionadded:: 2.0
2992
2993 """
2994
2995 operator: OperatorType
2996 type: TypeEngine[_T]
2997
2998 group: bool = True
2999
3000 @property
3001 def is_comparison(self):
3002 return operators.is_comparison(self.operator)
3003
3004 def self_group(
3005 self, against: Optional[OperatorType] = None
3006 ) -> Union[Self, Grouping[_T]]:
3007 if (
3008 self.group
3009 and operators.is_precedent(self.operator, against)
3010 or (
3011 # a negate against a non-boolean operator
3012 # doesn't make too much sense but we should
3013 # group for that
3014 against is operators.inv
3015 and not operators.is_boolean(self.operator)
3016 )
3017 ):
3018 return Grouping(self)
3019 else:
3020 return self
3021
3022 @property
3023 def _flattened_operator_clauses(
3024 self,
3025 ) -> typing_Tuple[ColumnElement[Any], ...]:
3026 raise NotImplementedError()
3027
3028 @classmethod
3029 def _construct_for_op(
3030 cls,
3031 left: ColumnElement[Any],
3032 right: ColumnElement[Any],
3033 op: OperatorType,
3034 *,
3035 type_: TypeEngine[_T],
3036 negate: Optional[OperatorType] = None,
3037 modifiers: Optional[Mapping[str, Any]] = None,
3038 ) -> OperatorExpression[_T]:
3039 if operators.is_associative(op):
3040 assert (
3041 negate is None
3042 ), f"negate not supported for associative operator {op}"
3043
3044 multi = False
3045 if getattr(
3046 left, "operator", None
3047 ) is op and type_._compare_type_affinity(left.type):
3048 multi = True
3049 left_flattened = left._flattened_operator_clauses
3050 else:
3051 left_flattened = (left,)
3052
3053 if getattr(
3054 right, "operator", None
3055 ) is op and type_._compare_type_affinity(right.type):
3056 multi = True
3057 right_flattened = right._flattened_operator_clauses
3058 else:
3059 right_flattened = (right,)
3060
3061 if multi:
3062 return ExpressionClauseList._construct_for_list(
3063 op,
3064 type_,
3065 *(left_flattened + right_flattened),
3066 )
3067
3068 if right._is_collection_aggregate:
3069 negate = None
3070
3071 return BinaryExpression(
3072 left, right, op, type_=type_, negate=negate, modifiers=modifiers
3073 )
3074
3075
3076class ExpressionClauseList(OperatorExpression[_T]):
3077 """Describe a list of clauses, separated by an operator,
3078 in a column expression context.
3079
3080 :class:`.ExpressionClauseList` differs from :class:`.ClauseList` in that
3081 it represents a column-oriented DQL expression only, not an open ended
3082 list of anything comma separated.
3083
3084 .. versionadded:: 2.0
3085
3086 """
3087
3088 __visit_name__ = "expression_clauselist"
3089
3090 _traverse_internals: _TraverseInternalsType = [
3091 ("clauses", InternalTraversal.dp_clauseelement_tuple),
3092 ("operator", InternalTraversal.dp_operator),
3093 ]
3094
3095 clauses: typing_Tuple[ColumnElement[Any], ...]
3096
3097 group: bool
3098
3099 def __init__(
3100 self,
3101 operator: OperatorType,
3102 *clauses: _ColumnExpressionArgument[Any],
3103 type_: Optional[_TypeEngineArgument[_T]] = None,
3104 ):
3105 self.operator = operator
3106
3107 self.clauses = tuple(
3108 coercions.expect(
3109 roles.ExpressionElementRole, clause, apply_propagate_attrs=self
3110 )
3111 for clause in clauses
3112 )
3113 self._is_implicitly_boolean = operators.is_boolean(self.operator)
3114 self.type = type_api.to_instance(type_) # type: ignore
3115
3116 @property
3117 def _flattened_operator_clauses(
3118 self,
3119 ) -> typing_Tuple[ColumnElement[Any], ...]:
3120 return self.clauses
3121
3122 def __iter__(self) -> Iterator[ColumnElement[Any]]:
3123 return iter(self.clauses)
3124
3125 def __len__(self) -> int:
3126 return len(self.clauses)
3127
3128 @property
3129 def _select_iterable(self) -> _SelectIterable:
3130 return (self,)
3131
3132 @util.ro_non_memoized_property
3133 def _from_objects(self) -> List[FromClause]:
3134 return list(itertools.chain(*[c._from_objects for c in self.clauses]))
3135
3136 def _append_inplace(self, clause: ColumnElement[Any]) -> None:
3137 self.clauses += (clause,)
3138
3139 @classmethod
3140 def _construct_for_list(
3141 cls,
3142 operator: OperatorType,
3143 type_: TypeEngine[_T],
3144 *clauses: ColumnElement[Any],
3145 group: bool = True,
3146 ) -> ExpressionClauseList[_T]:
3147 self = cls.__new__(cls)
3148 self.group = group
3149 if group:
3150 self.clauses = tuple(
3151 c.self_group(against=operator) for c in clauses
3152 )
3153 else:
3154 self.clauses = clauses
3155 self.operator = operator
3156 self.type = type_
3157 for c in clauses:
3158 if c._propagate_attrs:
3159 self._propagate_attrs = c._propagate_attrs
3160 break
3161 return self
3162
3163 def _negate(self) -> Any:
3164 grouped = self.self_group(against=operators.inv)
3165 assert isinstance(grouped, ColumnElement)
3166 return UnaryExpression(grouped, operator=operators.inv)
3167
3168
3169class BooleanClauseList(ExpressionClauseList[bool]):
3170 __visit_name__ = "expression_clauselist"
3171 inherit_cache = True
3172
3173 def __init__(self, *arg, **kw):
3174 raise NotImplementedError(
3175 "BooleanClauseList has a private constructor"
3176 )
3177
3178 @classmethod
3179 def _process_clauses_for_boolean(
3180 cls,
3181 operator: OperatorType,
3182 continue_on: Any,
3183 skip_on: Any,
3184 clauses: Iterable[ColumnElement[Any]],
3185 ) -> typing_Tuple[int, List[ColumnElement[Any]]]:
3186 has_continue_on = None
3187
3188 convert_clauses = []
3189
3190 against = operators._asbool
3191 lcc = 0
3192
3193 for clause in clauses:
3194 if clause is continue_on:
3195 # instance of continue_on, like and_(x, y, True, z), store it
3196 # if we didn't find one already, we will use it if there
3197 # are no other expressions here.
3198 has_continue_on = clause
3199 elif clause is skip_on:
3200 # instance of skip_on, e.g. and_(x, y, False, z), cancels
3201 # the rest out
3202 convert_clauses = [clause]
3203 lcc = 1
3204 break
3205 else:
3206 if not lcc:
3207 lcc = 1
3208 else:
3209 against = operator
3210 # technically this would be len(convert_clauses) + 1
3211 # however this only needs to indicate "greater than one"
3212 lcc = 2
3213 convert_clauses.append(clause)
3214
3215 if not convert_clauses and has_continue_on is not None:
3216 convert_clauses = [has_continue_on]
3217 lcc = 1
3218
3219 return lcc, [c.self_group(against=against) for c in convert_clauses]
3220
3221 @classmethod
3222 def _construct(
3223 cls,
3224 operator: OperatorType,
3225 continue_on: Any,
3226 skip_on: Any,
3227 initial_clause: Any = _NoArg.NO_ARG,
3228 *clauses: Any,
3229 **kw: Any,
3230 ) -> ColumnElement[Any]:
3231 if initial_clause is _NoArg.NO_ARG:
3232 # no elements period. deprecated use case. return an empty
3233 # ClauseList construct that generates nothing unless it has
3234 # elements added to it.
3235 name = operator.__name__
3236
3237 util.warn_deprecated(
3238 f"Invoking {name}() without arguments is deprecated, and "
3239 f"will be disallowed in a future release. For an empty "
3240 f"""{name}() construct, use '{name}({
3241 'true()' if continue_on is True_._singleton else 'false()'
3242 }, *args)' """
3243 f"""or '{name}({
3244 'True' if continue_on is True_._singleton else 'False'
3245 }, *args)'.""",
3246 version="1.4",
3247 )
3248 return cls._construct_raw(operator)
3249
3250 lcc, convert_clauses = cls._process_clauses_for_boolean(
3251 operator,
3252 continue_on,
3253 skip_on,
3254 [
3255 coercions.expect(roles.WhereHavingRole, clause)
3256 for clause in util.coerce_generator_arg(
3257 (initial_clause,) + clauses
3258 )
3259 ],
3260 )
3261
3262 if lcc > 1:
3263 # multiple elements. Return regular BooleanClauseList
3264 # which will link elements against the operator.
3265
3266 flattened_clauses = itertools.chain.from_iterable(
3267 (
3268 (c for c in to_flat._flattened_operator_clauses)
3269 if getattr(to_flat, "operator", None) is operator
3270 else (to_flat,)
3271 )
3272 for to_flat in convert_clauses
3273 )
3274
3275 return cls._construct_raw(operator, flattened_clauses) # type: ignore # noqa: E501
3276 else:
3277 assert lcc
3278 # just one element. return it as a single boolean element,
3279 # not a list and discard the operator.
3280 return convert_clauses[0]
3281
3282 @classmethod
3283 def _construct_for_whereclause(
3284 cls, clauses: Iterable[ColumnElement[Any]]
3285 ) -> Optional[ColumnElement[bool]]:
3286 operator, continue_on, skip_on = (
3287 operators.and_,
3288 True_._singleton,
3289 False_._singleton,
3290 )
3291
3292 lcc, convert_clauses = cls._process_clauses_for_boolean(
3293 operator,
3294 continue_on,
3295 skip_on,
3296 clauses, # these are assumed to be coerced already
3297 )
3298
3299 if lcc > 1:
3300 # multiple elements. Return regular BooleanClauseList
3301 # which will link elements against the operator.
3302 return cls._construct_raw(operator, convert_clauses)
3303 elif lcc == 1:
3304 # just one element. return it as a single boolean element,
3305 # not a list and discard the operator.
3306 return convert_clauses[0]
3307 else:
3308 return None
3309
3310 @classmethod
3311 def _construct_raw(
3312 cls,
3313 operator: OperatorType,
3314 clauses: Optional[Sequence[ColumnElement[Any]]] = None,
3315 ) -> BooleanClauseList:
3316 self = cls.__new__(cls)
3317 self.clauses = tuple(clauses) if clauses else ()
3318 self.group = True
3319 self.operator = operator
3320 self.type = type_api.BOOLEANTYPE
3321 self._is_implicitly_boolean = True
3322 return self
3323
3324 @classmethod
3325 def and_(
3326 cls,
3327 initial_clause: Union[
3328 Literal[True], _ColumnExpressionArgument[bool], _NoArg
3329 ] = _NoArg.NO_ARG,
3330 *clauses: _ColumnExpressionArgument[bool],
3331 ) -> ColumnElement[bool]:
3332 r"""Produce a conjunction of expressions joined by ``AND``.
3333
3334 See :func:`_sql.and_` for full documentation.
3335 """
3336 return cls._construct(
3337 operators.and_,
3338 True_._singleton,
3339 False_._singleton,
3340 initial_clause,
3341 *clauses,
3342 )
3343
3344 @classmethod
3345 def or_(
3346 cls,
3347 initial_clause: Union[
3348 Literal[False], _ColumnExpressionArgument[bool], _NoArg
3349 ] = _NoArg.NO_ARG,
3350 *clauses: _ColumnExpressionArgument[bool],
3351 ) -> ColumnElement[bool]:
3352 """Produce a conjunction of expressions joined by ``OR``.
3353
3354 See :func:`_sql.or_` for full documentation.
3355 """
3356 return cls._construct(
3357 operators.or_,
3358 False_._singleton,
3359 True_._singleton,
3360 initial_clause,
3361 *clauses,
3362 )
3363
3364 @property
3365 def _select_iterable(self) -> _SelectIterable:
3366 return (self,)
3367
3368 def self_group(
3369 self, against: Optional[OperatorType] = None
3370 ) -> Union[Self, Grouping[bool]]:
3371 if not self.clauses:
3372 return self
3373 else:
3374 return super().self_group(against=against)
3375
3376
3377and_ = BooleanClauseList.and_
3378or_ = BooleanClauseList.or_
3379
3380
3381class Tuple(ClauseList, ColumnElement[TupleAny]):
3382 """Represent a SQL tuple."""
3383
3384 __visit_name__ = "tuple"
3385
3386 _traverse_internals: _TraverseInternalsType = (
3387 ClauseList._traverse_internals + []
3388 )
3389
3390 type: TupleType
3391
3392 @util.preload_module("sqlalchemy.sql.sqltypes")
3393 def __init__(
3394 self,
3395 *clauses: _ColumnExpressionArgument[Any],
3396 types: Optional[Sequence[_TypeEngineArgument[Any]]] = None,
3397 ):
3398 sqltypes = util.preloaded.sql_sqltypes
3399
3400 if types is None:
3401 init_clauses: List[ColumnElement[Any]] = [
3402 coercions.expect(roles.ExpressionElementRole, c)
3403 for c in clauses
3404 ]
3405 else:
3406 if len(types) != len(clauses):
3407 raise exc.ArgumentError(
3408 "Wrong number of elements for %d-tuple: %r "
3409 % (len(types), clauses)
3410 )
3411 init_clauses = [
3412 coercions.expect(
3413 roles.ExpressionElementRole,
3414 c,
3415 type_=typ if not typ._isnull else None,
3416 )
3417 for typ, c in zip(types, clauses)
3418 ]
3419
3420 self.type = sqltypes.TupleType(*[arg.type for arg in init_clauses])
3421 super().__init__(*init_clauses)
3422
3423 @property
3424 def _select_iterable(self) -> _SelectIterable:
3425 return (self,)
3426
3427 def _bind_param(self, operator, obj, type_=None, expanding=False):
3428 if expanding:
3429 return BindParameter(
3430 None,
3431 value=obj,
3432 _compared_to_operator=operator,
3433 unique=True,
3434 expanding=True,
3435 type_=type_,
3436 _compared_to_type=self.type,
3437 )
3438 else:
3439 return Tuple(
3440 *[
3441 BindParameter(
3442 None,
3443 o,
3444 _compared_to_operator=operator,
3445 _compared_to_type=compared_to_type,
3446 unique=True,
3447 type_=type_,
3448 )
3449 for o, compared_to_type in zip(obj, self.type.types)
3450 ]
3451 )
3452
3453 def self_group(self, against: Optional[OperatorType] = None) -> Self:
3454 # Tuple is parenthesized by definition.
3455 return self
3456
3457
3458class Case(ColumnElement[_T]):
3459 """Represent a ``CASE`` expression.
3460
3461 :class:`.Case` is produced using the :func:`.case` factory function,
3462 as in::
3463
3464 from sqlalchemy import case
3465
3466 stmt = select(users_table).where(
3467 case(
3468 (users_table.c.name == "wendy", "W"),
3469 (users_table.c.name == "jack", "J"),
3470 else_="E",
3471 )
3472 )
3473
3474 Details on :class:`.Case` usage is at :func:`.case`.
3475
3476 .. seealso::
3477
3478 :func:`.case`
3479
3480 """
3481
3482 __visit_name__ = "case"
3483
3484 _traverse_internals: _TraverseInternalsType = [
3485 ("value", InternalTraversal.dp_clauseelement),
3486 ("whens", InternalTraversal.dp_clauseelement_tuples),
3487 ("else_", InternalTraversal.dp_clauseelement),
3488 ]
3489
3490 # for case(), the type is derived from the whens. so for the moment
3491 # users would have to cast() the case to get a specific type
3492
3493 whens: List[typing_Tuple[ColumnElement[bool], ColumnElement[_T]]]
3494 else_: Optional[ColumnElement[_T]]
3495 value: Optional[ColumnElement[Any]]
3496
3497 def __init__(
3498 self,
3499 *whens: Union[
3500 typing_Tuple[_ColumnExpressionArgument[bool], Any],
3501 Mapping[Any, Any],
3502 ],
3503 value: Optional[Any] = None,
3504 else_: Optional[Any] = None,
3505 ):
3506 new_whens: Iterable[Any] = coercions._expression_collection_was_a_list(
3507 "whens", "case", whens
3508 )
3509 try:
3510 new_whens = util.dictlike_iteritems(new_whens)
3511 except TypeError:
3512 pass
3513
3514 self.whens = [
3515 (
3516 coercions.expect(
3517 roles.ExpressionElementRole,
3518 c,
3519 apply_propagate_attrs=self,
3520 ).self_group(),
3521 coercions.expect(roles.ExpressionElementRole, r),
3522 )
3523 for (c, r) in new_whens
3524 ]
3525
3526 if value is None:
3527 self.value = None
3528 else:
3529 self.value = coercions.expect(roles.ExpressionElementRole, value)
3530
3531 if else_ is not None:
3532 self.else_ = coercions.expect(roles.ExpressionElementRole, else_)
3533 else:
3534 self.else_ = None
3535
3536 type_ = next(
3537 (
3538 then.type
3539 # Iterate `whens` in reverse to match previous behaviour
3540 # where type of final element took priority
3541 for *_, then in reversed(self.whens)
3542 if not then.type._isnull
3543 ),
3544 self.else_.type if self.else_ is not None else type_api.NULLTYPE,
3545 )
3546 self.type = cast(_T, type_)
3547
3548 @util.ro_non_memoized_property
3549 def _from_objects(self) -> List[FromClause]:
3550 return list(
3551 itertools.chain(*[x._from_objects for x in self.get_children()])
3552 )
3553
3554
3555class Cast(WrapsColumnExpression[_T]):
3556 """Represent a ``CAST`` expression.
3557
3558 :class:`.Cast` is produced using the :func:`.cast` factory function,
3559 as in::
3560
3561 from sqlalchemy import cast, Numeric
3562
3563 stmt = select(cast(product_table.c.unit_price, Numeric(10, 4)))
3564
3565 Details on :class:`.Cast` usage is at :func:`.cast`.
3566
3567 .. seealso::
3568
3569 :ref:`tutorial_casts`
3570
3571 :func:`.cast`
3572
3573 :func:`.try_cast`
3574
3575 :func:`.type_coerce` - an alternative to CAST that coerces the type
3576 on the Python side only, which is often sufficient to generate the
3577 correct SQL and data coercion.
3578
3579 """
3580
3581 __visit_name__ = "cast"
3582
3583 _traverse_internals: _TraverseInternalsType = [
3584 ("clause", InternalTraversal.dp_clauseelement),
3585 ("type", InternalTraversal.dp_type),
3586 ]
3587
3588 clause: ColumnElement[Any]
3589 type: TypeEngine[_T]
3590 typeclause: TypeClause
3591
3592 def __init__(
3593 self,
3594 expression: _ColumnExpressionArgument[Any],
3595 type_: _TypeEngineArgument[_T],
3596 ):
3597 self.type = type_api.to_instance(type_)
3598 self.clause = coercions.expect(
3599 roles.ExpressionElementRole,
3600 expression,
3601 type_=self.type,
3602 apply_propagate_attrs=self,
3603 )
3604 self.typeclause = TypeClause(self.type)
3605
3606 @util.ro_non_memoized_property
3607 def _from_objects(self) -> List[FromClause]:
3608 return self.clause._from_objects
3609
3610 @property
3611 def wrapped_column_expression(self):
3612 return self.clause
3613
3614
3615class TryCast(Cast[_T]):
3616 """Represent a TRY_CAST expression.
3617
3618 Details on :class:`.TryCast` usage is at :func:`.try_cast`.
3619
3620 .. seealso::
3621
3622 :func:`.try_cast`
3623
3624 :ref:`tutorial_casts`
3625 """
3626
3627 __visit_name__ = "try_cast"
3628 inherit_cache = True
3629
3630
3631class TypeCoerce(WrapsColumnExpression[_T]):
3632 """Represent a Python-side type-coercion wrapper.
3633
3634 :class:`.TypeCoerce` supplies the :func:`_expression.type_coerce`
3635 function; see that function for usage details.
3636
3637 .. seealso::
3638
3639 :func:`_expression.type_coerce`
3640
3641 :func:`.cast`
3642
3643 """
3644
3645 __visit_name__ = "type_coerce"
3646
3647 _traverse_internals: _TraverseInternalsType = [
3648 ("clause", InternalTraversal.dp_clauseelement),
3649 ("type", InternalTraversal.dp_type),
3650 ]
3651
3652 clause: ColumnElement[Any]
3653 type: TypeEngine[_T]
3654
3655 def __init__(
3656 self,
3657 expression: _ColumnExpressionArgument[Any],
3658 type_: _TypeEngineArgument[_T],
3659 ):
3660 self.type = type_api.to_instance(type_)
3661 self.clause = coercions.expect(
3662 roles.ExpressionElementRole,
3663 expression,
3664 type_=self.type,
3665 apply_propagate_attrs=self,
3666 )
3667
3668 @util.ro_non_memoized_property
3669 def _from_objects(self) -> List[FromClause]:
3670 return self.clause._from_objects
3671
3672 @HasMemoized.memoized_attribute
3673 def typed_expression(self):
3674 if isinstance(self.clause, BindParameter):
3675 bp = self.clause._clone()
3676 bp.type = self.type
3677 return bp
3678 else:
3679 return self.clause
3680
3681 @property
3682 def wrapped_column_expression(self):
3683 return self.clause
3684
3685 def self_group(
3686 self, against: Optional[OperatorType] = None
3687 ) -> TypeCoerce[_T]:
3688 grouped = self.clause.self_group(against=against)
3689 if grouped is not self.clause:
3690 return TypeCoerce(grouped, self.type)
3691 else:
3692 return self
3693
3694
3695class Extract(ColumnElement[int]):
3696 """Represent a SQL EXTRACT clause, ``extract(field FROM expr)``."""
3697
3698 __visit_name__ = "extract"
3699
3700 _traverse_internals: _TraverseInternalsType = [
3701 ("expr", InternalTraversal.dp_clauseelement),
3702 ("field", InternalTraversal.dp_string),
3703 ]
3704
3705 expr: ColumnElement[Any]
3706 field: str
3707
3708 def __init__(self, field: str, expr: _ColumnExpressionArgument[Any]):
3709 self.type = type_api.INTEGERTYPE
3710 self.field = field
3711 self.expr = coercions.expect(roles.ExpressionElementRole, expr)
3712
3713 @util.ro_non_memoized_property
3714 def _from_objects(self) -> List[FromClause]:
3715 return self.expr._from_objects
3716
3717
3718class _label_reference(ColumnElement[_T]):
3719 """Wrap a column expression as it appears in a 'reference' context.
3720
3721 This expression is any that includes an _order_by_label_element,
3722 which is a Label, or a DESC / ASC construct wrapping a Label.
3723
3724 The production of _label_reference() should occur when an expression
3725 is added to this context; this includes the ORDER BY or GROUP BY of a
3726 SELECT statement, as well as a few other places, such as the ORDER BY
3727 within an OVER clause.
3728
3729 """
3730
3731 __visit_name__ = "label_reference"
3732
3733 _traverse_internals: _TraverseInternalsType = [
3734 ("element", InternalTraversal.dp_clauseelement)
3735 ]
3736
3737 element: ColumnElement[_T]
3738
3739 def __init__(self, element: ColumnElement[_T]):
3740 self.element = element
3741 self._propagate_attrs = element._propagate_attrs
3742
3743 @util.ro_non_memoized_property
3744 def _from_objects(self) -> List[FromClause]:
3745 return []
3746
3747
3748class _textual_label_reference(ColumnElement[Any]):
3749 __visit_name__ = "textual_label_reference"
3750
3751 _traverse_internals: _TraverseInternalsType = [
3752 ("element", InternalTraversal.dp_string)
3753 ]
3754
3755 def __init__(self, element: str):
3756 self.element = element
3757
3758 @util.memoized_property
3759 def _text_clause(self) -> TextClause:
3760 return TextClause(self.element)
3761
3762
3763class UnaryExpression(ColumnElement[_T]):
3764 """Define a 'unary' expression.
3765
3766 A unary expression has a single column expression
3767 and an operator. The operator can be placed on the left
3768 (where it is called the 'operator') or right (where it is called the
3769 'modifier') of the column expression.
3770
3771 :class:`.UnaryExpression` is the basis for several unary operators
3772 including those used by :func:`.desc`, :func:`.asc`, :func:`.distinct`,
3773 :func:`.nulls_first` and :func:`.nulls_last`.
3774
3775 """
3776
3777 __visit_name__ = "unary"
3778
3779 _traverse_internals: _TraverseInternalsType = [
3780 ("element", InternalTraversal.dp_clauseelement),
3781 ("operator", InternalTraversal.dp_operator),
3782 ("modifier", InternalTraversal.dp_operator),
3783 ]
3784
3785 element: ColumnElement[Any]
3786 operator: Optional[OperatorType]
3787 modifier: Optional[OperatorType]
3788
3789 def __init__(
3790 self,
3791 element: ColumnElement[Any],
3792 *,
3793 operator: Optional[OperatorType] = None,
3794 modifier: Optional[OperatorType] = None,
3795 type_: Optional[_TypeEngineArgument[_T]] = None,
3796 wraps_column_expression: bool = False, # legacy, not used as of 2.0.42
3797 ):
3798 self.operator = operator
3799 self.modifier = modifier
3800 self._propagate_attrs = element._propagate_attrs
3801 self.element = element.self_group(
3802 against=self.operator or self.modifier
3803 )
3804
3805 # if type is None, we get NULLTYPE, which is our _T. But I don't
3806 # know how to get the overloads to express that correctly
3807 self.type = type_api.to_instance(type_) # type: ignore
3808
3809 def _wraps_unnamed_column(self):
3810 ungrouped = self.element._ungroup()
3811 return (
3812 not isinstance(ungrouped, NamedColumn)
3813 or ungrouped._non_anon_label is None
3814 )
3815
3816 @classmethod
3817 def _create_nulls_first(
3818 cls,
3819 column: _ColumnExpressionArgument[_T],
3820 ) -> UnaryExpression[_T]:
3821 return UnaryExpression(
3822 coercions.expect(roles.ByOfRole, column),
3823 modifier=operators.nulls_first_op,
3824 )
3825
3826 @classmethod
3827 def _create_nulls_last(
3828 cls,
3829 column: _ColumnExpressionArgument[_T],
3830 ) -> UnaryExpression[_T]:
3831 return UnaryExpression(
3832 coercions.expect(roles.ByOfRole, column),
3833 modifier=operators.nulls_last_op,
3834 )
3835
3836 @classmethod
3837 def _create_desc(
3838 cls, column: _ColumnExpressionOrStrLabelArgument[_T]
3839 ) -> UnaryExpression[_T]:
3840
3841 return UnaryExpression(
3842 coercions.expect(roles.ByOfRole, column),
3843 modifier=operators.desc_op,
3844 )
3845
3846 @classmethod
3847 def _create_asc(
3848 cls,
3849 column: _ColumnExpressionOrStrLabelArgument[_T],
3850 ) -> UnaryExpression[_T]:
3851 return UnaryExpression(
3852 coercions.expect(roles.ByOfRole, column),
3853 modifier=operators.asc_op,
3854 )
3855
3856 @classmethod
3857 def _create_distinct(
3858 cls,
3859 expr: _ColumnExpressionArgument[_T],
3860 ) -> UnaryExpression[_T]:
3861 col_expr: ColumnElement[_T] = coercions.expect(
3862 roles.ExpressionElementRole, expr
3863 )
3864 return UnaryExpression(
3865 col_expr,
3866 operator=operators.distinct_op,
3867 type_=col_expr.type,
3868 )
3869
3870 @classmethod
3871 def _create_bitwise_not(
3872 cls,
3873 expr: _ColumnExpressionArgument[_T],
3874 ) -> UnaryExpression[_T]:
3875 col_expr: ColumnElement[_T] = coercions.expect(
3876 roles.ExpressionElementRole, expr
3877 )
3878 return UnaryExpression(
3879 col_expr,
3880 operator=operators.bitwise_not_op,
3881 type_=col_expr.type,
3882 )
3883
3884 @property
3885 def _order_by_label_element(self) -> Optional[Label[Any]]:
3886 if operators.is_order_by_modifier(self.modifier):
3887 return self.element._order_by_label_element
3888 else:
3889 return None
3890
3891 @util.ro_non_memoized_property
3892 def _from_objects(self) -> List[FromClause]:
3893 return self.element._from_objects
3894
3895 def _negate(self) -> ColumnElement[Any]:
3896 if self.type._type_affinity is type_api.BOOLEANTYPE._type_affinity:
3897 return UnaryExpression(
3898 self.self_group(against=operators.inv),
3899 operator=operators.inv,
3900 type_=type_api.BOOLEANTYPE,
3901 )
3902 else:
3903 return ColumnElement._negate(self)
3904
3905 def self_group(
3906 self, against: Optional[OperatorType] = None
3907 ) -> Union[Self, Grouping[_T]]:
3908 if self.operator and operators.is_precedent(self.operator, against):
3909 return Grouping(self)
3910 else:
3911 return self
3912
3913
3914class CollectionAggregate(UnaryExpression[_T]):
3915 """Forms the basis for right-hand collection operator modifiers
3916 ANY and ALL.
3917
3918 The ANY and ALL keywords are available in different ways on different
3919 backends. On PostgreSQL, they only work for an ARRAY type. On
3920 MySQL, they only work for subqueries.
3921
3922 """
3923
3924 inherit_cache = True
3925 _is_collection_aggregate = True
3926
3927 @classmethod
3928 def _create_any(
3929 cls, expr: _ColumnExpressionArgument[_T]
3930 ) -> CollectionAggregate[bool]:
3931 """create CollectionAggregate for the legacy
3932 ARRAY.Comparator.any() method"""
3933 col_expr: ColumnElement[_T] = coercions.expect(
3934 roles.ExpressionElementRole,
3935 expr,
3936 )
3937 col_expr = col_expr.self_group()
3938 return CollectionAggregate(
3939 col_expr,
3940 operator=operators.any_op,
3941 type_=type_api.BOOLEANTYPE,
3942 )
3943
3944 @classmethod
3945 def _create_all(
3946 cls, expr: _ColumnExpressionArgument[_T]
3947 ) -> CollectionAggregate[bool]:
3948 """create CollectionAggregate for the legacy
3949 ARRAY.Comparator.all() method"""
3950 col_expr: ColumnElement[_T] = coercions.expect(
3951 roles.ExpressionElementRole,
3952 expr,
3953 )
3954 col_expr = col_expr.self_group()
3955 return CollectionAggregate(
3956 col_expr,
3957 operator=operators.all_op,
3958 type_=type_api.BOOLEANTYPE,
3959 )
3960
3961 @util.preload_module("sqlalchemy.sql.sqltypes")
3962 def _bind_param(
3963 self,
3964 operator: operators.OperatorType,
3965 obj: Any,
3966 type_: Optional[TypeEngine[_T]] = None,
3967 expanding: bool = False,
3968 ) -> BindParameter[_T]:
3969 """For new style any_(), all_(), ensure compared literal value
3970 receives appropriate bound parameter type."""
3971
3972 # a CollectionAggregate is specific to ARRAY or int
3973 # only. So for ARRAY case, make sure we use correct element type
3974 sqltypes = util.preloaded.sql_sqltypes
3975 if self.element.type._type_affinity is sqltypes.ARRAY:
3976 compared_to_type = cast(
3977 sqltypes.ARRAY[Any], self.element.type
3978 ).item_type
3979 else:
3980 compared_to_type = self.element.type
3981
3982 return BindParameter(
3983 None,
3984 obj,
3985 _compared_to_operator=operator,
3986 type_=type_,
3987 _compared_to_type=compared_to_type,
3988 unique=True,
3989 expanding=expanding,
3990 )
3991
3992 # operate and reverse_operate are hardwired to
3993 # dispatch onto the type comparator directly, so that we can
3994 # ensure "reversed" behavior.
3995 def operate(
3996 self, op: OperatorType, *other: Any, **kwargs: Any
3997 ) -> ColumnElement[_T]:
3998 if not operators.is_comparison(op):
3999 raise exc.ArgumentError(
4000 "Only comparison operators may be used with ANY/ALL"
4001 )
4002 kwargs["reverse"] = True
4003 return self.comparator.operate(operators.mirror(op), *other, **kwargs)
4004
4005 def reverse_operate(
4006 self, op: OperatorType, other: Any, **kwargs: Any
4007 ) -> ColumnElement[_T]:
4008 # comparison operators should never call reverse_operate
4009 assert not operators.is_comparison(op)
4010 raise exc.ArgumentError(
4011 "Only comparison operators may be used with ANY/ALL"
4012 )
4013
4014
4015class AsBoolean(WrapsColumnExpression[bool], UnaryExpression[bool]):
4016 inherit_cache = True
4017
4018 def __init__(self, element, operator, negate):
4019 self.element = element
4020 self.type = type_api.BOOLEANTYPE
4021 self.operator = operator
4022 self.negate = negate
4023 self.modifier = None
4024 self._is_implicitly_boolean = element._is_implicitly_boolean
4025
4026 @property
4027 def wrapped_column_expression(self):
4028 return self.element
4029
4030 def self_group(self, against: Optional[OperatorType] = None) -> Self:
4031 return self
4032
4033 def _negate(self):
4034 if isinstance(self.element, (True_, False_)):
4035 return self.element._negate()
4036 else:
4037 return AsBoolean(self.element, self.negate, self.operator)
4038
4039
4040class BinaryExpression(OperatorExpression[_T]):
4041 """Represent an expression that is ``LEFT <operator> RIGHT``.
4042
4043 A :class:`.BinaryExpression` is generated automatically
4044 whenever two column expressions are used in a Python binary expression:
4045
4046 .. sourcecode:: pycon+sql
4047
4048 >>> from sqlalchemy.sql import column
4049 >>> column("a") + column("b")
4050 <sqlalchemy.sql.expression.BinaryExpression object at 0x101029dd0>
4051 >>> print(column("a") + column("b"))
4052 {printsql}a + b
4053
4054 """
4055
4056 __visit_name__ = "binary"
4057
4058 _traverse_internals: _TraverseInternalsType = [
4059 ("left", InternalTraversal.dp_clauseelement),
4060 ("right", InternalTraversal.dp_clauseelement),
4061 ("operator", InternalTraversal.dp_operator),
4062 ("negate", InternalTraversal.dp_operator),
4063 ("modifiers", InternalTraversal.dp_plain_dict),
4064 (
4065 "type",
4066 InternalTraversal.dp_type,
4067 ),
4068 ]
4069
4070 _cache_key_traversal = [
4071 ("left", InternalTraversal.dp_clauseelement),
4072 ("right", InternalTraversal.dp_clauseelement),
4073 ("operator", InternalTraversal.dp_operator),
4074 ("modifiers", InternalTraversal.dp_plain_dict),
4075 # "type" affects JSON CAST operators, so while redundant in most cases,
4076 # is needed for that one
4077 (
4078 "type",
4079 InternalTraversal.dp_type,
4080 ),
4081 ]
4082
4083 _is_implicitly_boolean = True
4084 """Indicates that any database will know this is a boolean expression
4085 even if the database does not have an explicit boolean datatype.
4086
4087 """
4088
4089 left: ColumnElement[Any]
4090 right: ColumnElement[Any]
4091 modifiers: Mapping[str, Any]
4092
4093 def __init__(
4094 self,
4095 left: ColumnElement[Any],
4096 right: ColumnElement[Any],
4097 operator: OperatorType,
4098 type_: Optional[_TypeEngineArgument[_T]] = None,
4099 negate: Optional[OperatorType] = None,
4100 modifiers: Optional[Mapping[str, Any]] = None,
4101 ):
4102 # allow compatibility with libraries that
4103 # refer to BinaryExpression directly and pass strings
4104 if isinstance(operator, str):
4105 operator = operators.custom_op(operator)
4106 self._orig = (left.__hash__(), right.__hash__())
4107 self._propagate_attrs = left._propagate_attrs or right._propagate_attrs
4108 self.left = left.self_group(against=operator)
4109 self.right = right.self_group(against=operator)
4110 self.operator = operator
4111
4112 # if type is None, we get NULLTYPE, which is our _T. But I don't
4113 # know how to get the overloads to express that correctly
4114 self.type = type_api.to_instance(type_) # type: ignore
4115
4116 self.negate = negate
4117 self._is_implicitly_boolean = operators.is_boolean(operator)
4118
4119 if modifiers is None:
4120 self.modifiers = {}
4121 else:
4122 self.modifiers = modifiers
4123
4124 @property
4125 def _flattened_operator_clauses(
4126 self,
4127 ) -> typing_Tuple[ColumnElement[Any], ...]:
4128 return (self.left, self.right)
4129
4130 def __bool__(self):
4131 """Implement Python-side "bool" for BinaryExpression as a
4132 simple "identity" check for the left and right attributes,
4133 if the operator is "eq" or "ne". Otherwise the expression
4134 continues to not support "bool" like all other column expressions.
4135
4136 The rationale here is so that ColumnElement objects can be hashable.
4137 What? Well, suppose you do this::
4138
4139 c1, c2 = column("x"), column("y")
4140 s1 = set([c1, c2])
4141
4142 We do that **a lot**, columns inside of sets is an extremely basic
4143 thing all over the ORM for example.
4144
4145 So what happens if we do this? ::
4146
4147 c1 in s1
4148
4149 Hashing means it will normally use ``__hash__()`` of the object,
4150 but in case of hash collision, it's going to also do ``c1 == c1``
4151 and/or ``c1 == c2`` inside. Those operations need to return a
4152 True/False value. But because we override ``==`` and ``!=``, they're
4153 going to get a BinaryExpression. Hence we implement ``__bool__`` here
4154 so that these comparisons behave in this particular context mostly
4155 like regular object comparisons. Thankfully Python is OK with
4156 that! Otherwise we'd have to use special set classes for columns
4157 (which we used to do, decades ago).
4158
4159 """
4160 if self.operator in (operators.eq, operators.ne):
4161 # this is using the eq/ne operator given int hash values,
4162 # rather than Operator, so that "bool" can be based on
4163 # identity
4164 return self.operator(*self._orig) # type: ignore
4165 else:
4166 raise TypeError("Boolean value of this clause is not defined")
4167
4168 if typing.TYPE_CHECKING:
4169
4170 def __invert__(
4171 self: BinaryExpression[_T],
4172 ) -> BinaryExpression[_T]: ...
4173
4174 @util.ro_non_memoized_property
4175 def _from_objects(self) -> List[FromClause]:
4176 return self.left._from_objects + self.right._from_objects
4177
4178 def _negate(self):
4179 if self.negate is not None:
4180 return BinaryExpression(
4181 self.left,
4182 self.right._negate_in_binary(self.negate, self.operator),
4183 self.negate,
4184 negate=self.operator,
4185 type_=self.type,
4186 modifiers=self.modifiers,
4187 )
4188 else:
4189 return self.self_group()._negate()
4190
4191
4192class Slice(ColumnElement[Any]):
4193 """Represent SQL for a Python array-slice object.
4194
4195 This is not a specific SQL construct at this level, but
4196 may be interpreted by specific dialects, e.g. PostgreSQL.
4197
4198 """
4199
4200 __visit_name__ = "slice"
4201
4202 _traverse_internals: _TraverseInternalsType = [
4203 ("start", InternalTraversal.dp_clauseelement),
4204 ("stop", InternalTraversal.dp_clauseelement),
4205 ("step", InternalTraversal.dp_clauseelement),
4206 ]
4207
4208 def __init__(self, start, stop, step, _name=None):
4209 self.start = coercions.expect(
4210 roles.ExpressionElementRole,
4211 start,
4212 name=_name,
4213 type_=type_api.INTEGERTYPE,
4214 )
4215 self.stop = coercions.expect(
4216 roles.ExpressionElementRole,
4217 stop,
4218 name=_name,
4219 type_=type_api.INTEGERTYPE,
4220 )
4221 self.step = coercions.expect(
4222 roles.ExpressionElementRole,
4223 step,
4224 name=_name,
4225 type_=type_api.INTEGERTYPE,
4226 )
4227 self.type = type_api.NULLTYPE
4228
4229 def self_group(self, against: Optional[OperatorType] = None) -> Self:
4230 assert against is operator.getitem
4231 return self
4232
4233
4234class IndexExpression(BinaryExpression[Any]):
4235 """Represent the class of expressions that are like an "index"
4236 operation."""
4237
4238 inherit_cache = True
4239
4240
4241class GroupedElement(DQLDMLClauseElement):
4242 """Represent any parenthesized expression"""
4243
4244 __visit_name__ = "grouping"
4245
4246 def self_group(self, against: Optional[OperatorType] = None) -> Self:
4247 return self
4248
4249 def _ungroup(self) -> ClauseElement:
4250 raise NotImplementedError()
4251
4252
4253class Grouping(GroupedElement, ColumnElement[_T]):
4254 """Represent a grouping within a column expression"""
4255
4256 _traverse_internals: _TraverseInternalsType = [
4257 ("element", InternalTraversal.dp_clauseelement),
4258 ("type", InternalTraversal.dp_type),
4259 ]
4260
4261 _cache_key_traversal = [
4262 ("element", InternalTraversal.dp_clauseelement),
4263 ]
4264
4265 element: Union[
4266 TextClause, ClauseList, ColumnElement[_T], CompilerColumnElement
4267 ]
4268
4269 def __init__(
4270 self,
4271 element: Union[
4272 TextClause, ClauseList, ColumnElement[_T], CompilerColumnElement
4273 ],
4274 ):
4275 self.element = element
4276
4277 # nulltype assignment issue
4278 self.type = getattr(element, "type", type_api.NULLTYPE) # type: ignore
4279 self._propagate_attrs = element._propagate_attrs
4280
4281 def _with_binary_element_type(self, type_):
4282 return self.__class__(self.element._with_binary_element_type(type_))
4283
4284 def _ungroup(self) -> ColumnElement[_T]:
4285 assert isinstance(self.element, ColumnElement)
4286 return self.element._ungroup()
4287
4288 @util.memoized_property
4289 def _is_implicitly_boolean(self):
4290 return self.element._is_implicitly_boolean
4291
4292 @util.non_memoized_property
4293 def _tq_label(self) -> Optional[str]:
4294 return (
4295 getattr(self.element, "_tq_label", None) or self._anon_name_label
4296 )
4297
4298 @util.non_memoized_property
4299 def _proxies(self) -> List[ColumnElement[Any]]:
4300 if isinstance(self.element, ColumnElement):
4301 return [self.element]
4302 else:
4303 return []
4304
4305 @util.ro_non_memoized_property
4306 def _from_objects(self) -> List[FromClause]:
4307 return self.element._from_objects
4308
4309 def __getattr__(self, attr):
4310 return getattr(self.element, attr)
4311
4312 def __getstate__(self):
4313 return {"element": self.element, "type": self.type}
4314
4315 def __setstate__(self, state):
4316 self.element = state["element"]
4317 self.type = state["type"]
4318
4319 if TYPE_CHECKING:
4320
4321 def self_group(
4322 self, against: Optional[OperatorType] = None
4323 ) -> Self: ...
4324
4325
4326class _OverrideBinds(Grouping[_T]):
4327 """used by cache_key->_apply_params_to_element to allow compilation /
4328 execution of a SQL element that's been cached, using an alternate set of
4329 bound parameter values.
4330
4331 This is used by the ORM to swap new parameter values into expressions
4332 that are embedded into loader options like with_expression(),
4333 selectinload(). Previously, this task was accomplished using the
4334 .params() method which would perform a deep-copy instead. This deep
4335 copy proved to be too expensive for more complex expressions.
4336
4337 See #11085
4338
4339 """
4340
4341 __visit_name__ = "override_binds"
4342
4343 def __init__(
4344 self,
4345 element: ColumnElement[_T],
4346 bindparams: Sequence[BindParameter[Any]],
4347 replaces_params: Sequence[BindParameter[Any]],
4348 ):
4349 self.element = element
4350 self.translate = {
4351 k.key: v.value for k, v in zip(replaces_params, bindparams)
4352 }
4353
4354 def _gen_cache_key(
4355 self, anon_map: anon_map, bindparams: List[BindParameter[Any]]
4356 ) -> Optional[typing_Tuple[Any, ...]]:
4357 """generate a cache key for the given element, substituting its bind
4358 values for the translation values present."""
4359
4360 existing_bps: List[BindParameter[Any]] = []
4361 ck = self.element._gen_cache_key(anon_map, existing_bps)
4362
4363 bindparams.extend(
4364 (
4365 bp._with_value(
4366 self.translate[bp.key], maintain_key=True, required=False
4367 )
4368 if bp.key in self.translate
4369 else bp
4370 )
4371 for bp in existing_bps
4372 )
4373
4374 return ck
4375
4376
4377_FrameIntTuple = tuple[int | None, int | None]
4378
4379
4380class Over(ColumnElement[_T]):
4381 """Represent an OVER clause.
4382
4383 This is a special operator against a so-called
4384 "window" function, as well as any aggregate function,
4385 which produces results relative to the result set
4386 itself. Most modern SQL backends now support window functions.
4387
4388 """
4389
4390 __visit_name__ = "over"
4391
4392 _traverse_internals: _TraverseInternalsType = [
4393 ("element", InternalTraversal.dp_clauseelement),
4394 ("order_by", InternalTraversal.dp_clauseelement),
4395 ("partition_by", InternalTraversal.dp_clauseelement),
4396 ("range_", InternalTraversal.dp_clauseelement),
4397 ("rows", InternalTraversal.dp_clauseelement),
4398 ("groups", InternalTraversal.dp_clauseelement),
4399 ]
4400
4401 order_by: Optional[ClauseList] = None
4402 partition_by: Optional[ClauseList] = None
4403
4404 element: ColumnElement[_T]
4405 """The underlying expression object to which this :class:`.Over`
4406 object refers."""
4407
4408 range_: FrameClause | None
4409 rows: FrameClause | None
4410 groups: FrameClause | None
4411
4412 def __init__(
4413 self,
4414 element: ColumnElement[_T],
4415 partition_by: Optional[_ByArgument] = None,
4416 order_by: Optional[_ByArgument] = None,
4417 range_: _FrameIntTuple | FrameClause | None = None,
4418 rows: _FrameIntTuple | FrameClause | None = None,
4419 groups: _FrameIntTuple | FrameClause | None = None,
4420 ):
4421 self.element = element
4422 if order_by is not None:
4423 self.order_by = ClauseList(
4424 *util.to_list(order_by), _literal_as_text_role=roles.ByOfRole
4425 )
4426 if partition_by is not None:
4427 self.partition_by = ClauseList(
4428 *util.to_list(partition_by),
4429 _literal_as_text_role=roles.ByOfRole,
4430 )
4431
4432 if sum(item is not None for item in (range_, rows, groups)) > 1:
4433 raise exc.ArgumentError(
4434 "only one of 'rows', 'range_', or 'groups' may be provided"
4435 )
4436 else:
4437 self.range_ = FrameClause._parse(range_, coerce_int=False)
4438 self.rows = FrameClause._parse(rows, coerce_int=True)
4439 self.groups = FrameClause._parse(groups, coerce_int=True)
4440
4441 if not TYPE_CHECKING:
4442
4443 @util.memoized_property
4444 def type(self) -> TypeEngine[_T]: # noqa: A001
4445 return self.element.type
4446
4447 @util.ro_non_memoized_property
4448 def _from_objects(self) -> List[FromClause]:
4449 return list(
4450 itertools.chain(
4451 *[
4452 c._from_objects
4453 for c in (self.element, self.partition_by, self.order_by)
4454 if c is not None
4455 ]
4456 )
4457 )
4458
4459
4460class FrameClauseType(Enum):
4461 """Frame clause type enum for FrameClause lower_type and upper_type.
4462
4463 .. versionadded:: 2.1
4464
4465 """
4466
4467 UNBOUNDED = 0
4468 """Produces an "UNBOUNDED PRECEDING" or "UNBOUNDED FOLLOWING" frame
4469 clause depending on the position.
4470 Requires a ``None`` value for the corresponding bound value.
4471 """
4472 CURRENT = 1
4473 """Produces a "CURRENT ROW" frame clause.
4474 Requires a ``None`` value for the corresponding bound value.
4475 """
4476 PRECEDING = 2
4477 """Produces a "PRECEDING" frame clause."""
4478 FOLLOWING = 3
4479 """Produces a "FOLLOWING" frame clause."""
4480
4481
4482_require_none = (
4483 FrameClauseType.CURRENT,
4484 FrameClauseType.UNBOUNDED,
4485)
4486
4487
4488class FrameClause(ClauseElement):
4489 """Indicate the 'rows' 'range' or 'group' field of a window function,
4490 e.g. using :class:`.Over`.
4491
4492 .. versionadded:: 2.1
4493
4494 """
4495
4496 __visit_name__ = "frame_clause"
4497
4498 _traverse_internals: _TraverseInternalsType = [
4499 ("lower_bind", InternalTraversal.dp_clauseelement),
4500 ("upper_bind", InternalTraversal.dp_clauseelement),
4501 ("lower_type", InternalTraversal.dp_plain_obj),
4502 ("upper_type", InternalTraversal.dp_plain_obj),
4503 ]
4504
4505 def __init__(
4506 self,
4507 start: Any,
4508 end: Any,
4509 start_frame_type: FrameClauseType,
4510 end_frame_type: FrameClauseType,
4511 _validate: bool = True,
4512 ) -> None:
4513 """Creates a new FrameClause specifying the bounds of a window frame.
4514
4515 :param start: The start value.
4516 :param end: The end value.
4517 :param start_frame_type: The :class:`FrameClauseType` for the
4518 start value.
4519 :param end_frame_type: The :class:`FrameClauseType` for the end value.
4520 """
4521 self.lower_bind = self._as_literal(start)
4522 self.upper_bind = self._as_literal(end)
4523 self.lower_type = FrameClauseType(start_frame_type)
4524 self.upper_type = FrameClauseType(end_frame_type)
4525 if _validate:
4526 if (
4527 self.lower_type in _require_none
4528 and self.lower_bind is not None
4529 ):
4530 raise exc.ArgumentError(
4531 "Cannot specify a value for start with frame type "
4532 f"{self.lower_type.name}"
4533 )
4534 if (
4535 self.upper_type in _require_none
4536 and self.upper_bind is not None
4537 ):
4538 raise exc.ArgumentError(
4539 "Cannot specify a value for end with frame type "
4540 f"{self.upper_type.name}"
4541 )
4542
4543 @classmethod
4544 def _as_literal(cls, value: Any) -> BindParameter[Any] | None:
4545 if value is None:
4546 return None
4547 elif isinstance(value, int):
4548 return literal(value, type_api.INTEGERTYPE)
4549 elif isinstance(value, BindParameter):
4550 return value
4551 else:
4552 return literal(value) # let the default type resolution occur
4553
4554 @classmethod
4555 def _handle_int(
4556 cls, value: Any | None, coerce_int: bool
4557 ) -> tuple[int | None, FrameClauseType]:
4558 if value is None:
4559 return None, FrameClauseType.UNBOUNDED
4560
4561 if coerce_int:
4562 try:
4563 integer = int(value)
4564 except ValueError as err:
4565 raise exc.ArgumentError(
4566 "Integer or None expected for values in rows/groups frame"
4567 ) from err
4568 elif not isinstance(value, int):
4569 raise exc.ArgumentError(
4570 "When using a tuple to specify a range only integer or none "
4571 "values are allowed in the range frame. To specify a "
4572 "different type use the FrameClause directly."
4573 )
4574 else:
4575 integer = value
4576 if integer == 0:
4577 return None, FrameClauseType.CURRENT
4578 elif integer < 0:
4579 return abs(integer), FrameClauseType.PRECEDING
4580 else:
4581 return integer, FrameClauseType.FOLLOWING
4582
4583 @classmethod
4584 def _parse(
4585 cls,
4586 range_: _FrameIntTuple | FrameClause | None,
4587 coerce_int: bool,
4588 ) -> FrameClause | None:
4589 if range_ is None or isinstance(range_, FrameClause):
4590 return range_
4591
4592 try:
4593 r0, r1 = range_
4594 except (ValueError, TypeError) as ve:
4595 raise exc.ArgumentError(
4596 "2-tuple expected for range/rows/groups"
4597 ) from ve
4598
4599 l_b, l_t = cls._handle_int(r0, coerce_int)
4600 u_b, u_t = cls._handle_int(r1, coerce_int)
4601
4602 return FrameClause(
4603 start=l_b,
4604 end=u_b,
4605 start_frame_type=l_t,
4606 end_frame_type=u_t,
4607 _validate=False,
4608 )
4609
4610
4611class AggregateOrderBy(WrapsColumnExpression[_T]):
4612 """Represent an aggregate ORDER BY expression.
4613
4614 This is a special operator against aggregate functions such as
4615 ``array_agg()``, ``json_arrayagg()`` ``string_agg()``, etc. that provides
4616 for an ORDER BY expression, using a syntax that's compatible with
4617 the backend.
4618
4619 :class:`.AggregateOrderBy` is a generalized version of the
4620 :class:`.WithinGroup` construct, the latter of which always provides a
4621 "WITHIN GROUP (ORDER BY ...)" expression. :class:`.AggregateOrderBy` will
4622 also compile to "WITHIN GROUP (ORDER BY ...)" on backends such as Oracle
4623 and SQL Server that don't have another style of aggregate function
4624 ordering.
4625
4626 .. versionadded:: 2.1
4627
4628
4629 """
4630
4631 __visit_name__ = "aggregateorderby"
4632
4633 _traverse_internals: _TraverseInternalsType = [
4634 ("element", InternalTraversal.dp_clauseelement),
4635 ("order_by", InternalTraversal.dp_clauseelement),
4636 ]
4637
4638 order_by: ClauseList
4639
4640 def __init__(
4641 self,
4642 element: Union[FunctionElement[_T], FunctionFilter[_T]],
4643 *order_by: _ColumnExpressionArgument[Any],
4644 ):
4645 self.element = element
4646 if not order_by:
4647 raise TypeError("at least one ORDER BY element is required")
4648 self.order_by = ClauseList(
4649 *util.to_list(order_by), _literal_as_text_role=roles.ByOfRole
4650 )
4651
4652 if not TYPE_CHECKING:
4653
4654 @util.memoized_property
4655 def type(self) -> TypeEngine[_T]: # noqa: A001
4656 return self.element.type
4657
4658 @property
4659 def wrapped_column_expression(self) -> ColumnElement[_T]:
4660 return self.element
4661
4662 def __reduce__(self):
4663 return self.__class__, (self.element,) + (
4664 tuple(self.order_by) if self.order_by is not None else ()
4665 )
4666
4667 def over(
4668 self,
4669 *,
4670 partition_by: _ByArgument | None = None,
4671 order_by: _ByArgument | None = None,
4672 rows: _FrameIntTuple | FrameClause | None = None,
4673 range_: _FrameIntTuple | FrameClause | None = None,
4674 groups: _FrameIntTuple | FrameClause | None = None,
4675 ) -> Over[_T]:
4676 """Produce an OVER clause against this :class:`.WithinGroup`
4677 construct.
4678
4679 This function has the same signature as that of
4680 :meth:`.FunctionElement.over`.
4681
4682 """
4683 return Over(
4684 self,
4685 partition_by=partition_by,
4686 order_by=order_by,
4687 range_=range_,
4688 rows=rows,
4689 groups=groups,
4690 )
4691
4692 @overload
4693 def filter(self) -> Self: ...
4694
4695 @overload
4696 def filter(
4697 self,
4698 __criterion0: _ColumnExpressionArgument[bool],
4699 *criterion: _ColumnExpressionArgument[bool],
4700 ) -> FunctionFilter[_T]: ...
4701
4702 def filter(
4703 self, *criterion: _ColumnExpressionArgument[bool]
4704 ) -> Union[Self, FunctionFilter[_T]]:
4705 """Produce a FILTER clause against this function."""
4706 if not criterion:
4707 return self
4708 return FunctionFilter(self, *criterion)
4709
4710 @util.ro_non_memoized_property
4711 def _from_objects(self) -> List[FromClause]:
4712 return list(
4713 itertools.chain(
4714 *[
4715 c._from_objects
4716 for c in (self.element, self.order_by)
4717 if c is not None
4718 ]
4719 )
4720 )
4721
4722
4723class WithinGroup(AggregateOrderBy[_T]):
4724 """Represent a WITHIN GROUP (ORDER BY) clause.
4725
4726 This is a special operator against so-called
4727 "ordered set aggregate" and "hypothetical
4728 set aggregate" functions, including ``percentile_cont()``,
4729 ``rank()``, ``dense_rank()``, etc.
4730
4731 It's supported only by certain database backends, such as PostgreSQL,
4732 Oracle Database and MS SQL Server.
4733
4734 The :class:`.WithinGroup` construct extracts its type from the
4735 method :meth:`.FunctionElement.within_group_type`. If this returns
4736 ``None``, the function's ``.type`` is used.
4737
4738 """
4739
4740 __visit_name__ = "withingroup"
4741 inherit_cache = True
4742
4743 if not TYPE_CHECKING:
4744
4745 @util.memoized_property
4746 def type(self) -> TypeEngine[_T]: # noqa: A001
4747 wgt = self.element.within_group_type(self)
4748 if wgt is not None:
4749 return wgt
4750 else:
4751 return self.element.type
4752
4753
4754class FunctionFilter(Generative, ColumnElement[_T]):
4755 """Represent a function FILTER clause.
4756
4757 This is a special operator against aggregate and window functions,
4758 which controls which rows are passed to it.
4759 It's supported only by certain database backends.
4760
4761 Invocation of :class:`.FunctionFilter` is via
4762 :meth:`.FunctionElement.filter`::
4763
4764 func.count(1).filter(True)
4765
4766 .. seealso::
4767
4768 :meth:`.FunctionElement.filter`
4769
4770 """
4771
4772 __visit_name__ = "funcfilter"
4773
4774 _traverse_internals: _TraverseInternalsType = [
4775 ("func", InternalTraversal.dp_clauseelement),
4776 ("criterion", InternalTraversal.dp_clauseelement),
4777 ]
4778
4779 criterion: Optional[ColumnElement[bool]] = None
4780
4781 def __init__(
4782 self,
4783 func: Union[FunctionElement[_T], AggregateOrderBy[_T]],
4784 *criterion: _ColumnExpressionArgument[bool],
4785 ):
4786 self.func = func
4787 self.filter.non_generative(self, *criterion) # type: ignore
4788
4789 @_generative
4790 def filter(self, *criterion: _ColumnExpressionArgument[bool]) -> Self:
4791 """Produce an additional FILTER against the function.
4792
4793 This method adds additional criteria to the initial criteria
4794 set up by :meth:`.FunctionElement.filter`.
4795
4796 Multiple criteria are joined together at SQL render time
4797 via ``AND``.
4798
4799
4800 """
4801
4802 for crit in list(criterion):
4803 crit = coercions.expect(roles.WhereHavingRole, crit)
4804
4805 if self.criterion is not None:
4806 self.criterion = self.criterion & crit
4807 else:
4808 self.criterion = crit
4809
4810 return self
4811
4812 def over(
4813 self,
4814 partition_by: _ByArgument | None = None,
4815 order_by: _ByArgument | None = None,
4816 range_: _FrameIntTuple | FrameClause | None = None,
4817 rows: _FrameIntTuple | FrameClause | None = None,
4818 groups: _FrameIntTuple | FrameClause | None = None,
4819 ) -> Over[_T]:
4820 """Produce an OVER clause against this filtered function.
4821
4822 Used against aggregate or so-called "window" functions,
4823 for database backends that support window functions.
4824
4825 The expression::
4826
4827 func.rank().filter(MyClass.y > 5).over(order_by="x")
4828
4829 is shorthand for::
4830
4831 from sqlalchemy import over, funcfilter
4832
4833 over(funcfilter(func.rank(), MyClass.y > 5), order_by="x")
4834
4835 See :func:`_expression.over` for a full description.
4836
4837 """
4838 return Over(
4839 self,
4840 partition_by=partition_by,
4841 order_by=order_by,
4842 range_=range_,
4843 rows=rows,
4844 groups=groups,
4845 )
4846
4847 def within_group(
4848 self, *order_by: _ColumnExpressionArgument[Any]
4849 ) -> WithinGroup[_T]:
4850 """Produce a WITHIN GROUP (ORDER BY expr) clause against
4851 this function.
4852 """
4853 return WithinGroup(self, *order_by)
4854
4855 def within_group_type(
4856 self, within_group: WithinGroup[_T]
4857 ) -> Optional[TypeEngine[_T]]:
4858 return None
4859
4860 def self_group(
4861 self, against: Optional[OperatorType] = None
4862 ) -> Union[Self, Grouping[_T]]:
4863 if operators.is_precedent(operators.filter_op, against):
4864 return Grouping(self)
4865 else:
4866 return self
4867
4868 if not TYPE_CHECKING:
4869
4870 @util.memoized_property
4871 def type(self) -> TypeEngine[_T]: # noqa: A001
4872 return self.func.type
4873
4874 @util.ro_non_memoized_property
4875 def _from_objects(self) -> List[FromClause]:
4876 return list(
4877 itertools.chain(
4878 *[
4879 c._from_objects
4880 for c in (self.func, self.criterion)
4881 if c is not None
4882 ]
4883 )
4884 )
4885
4886
4887class NamedColumn(KeyedColumnElement[_T]):
4888 is_literal = False
4889 table: Optional[FromClause] = None
4890 name: str
4891 key: str
4892
4893 def _compare_name_for_result(self, other):
4894 return (hasattr(other, "name") and self.name == other.name) or (
4895 hasattr(other, "_label") and self._label == other._label
4896 )
4897
4898 @util.ro_memoized_property
4899 def description(self) -> str:
4900 return self.name
4901
4902 @HasMemoized.memoized_attribute
4903 def _tq_key_label(self) -> Optional[str]:
4904 """table qualified label based on column key.
4905
4906 for table-bound columns this is <tablename>_<column key/proxy key>;
4907
4908 all other expressions it resolves to key/proxy key.
4909
4910 """
4911 proxy_key = self._proxy_key
4912 if proxy_key and proxy_key != self.name:
4913 return self._gen_tq_label(proxy_key)
4914 else:
4915 return self._tq_label
4916
4917 @HasMemoized.memoized_attribute
4918 def _tq_label(self) -> Optional[str]:
4919 """table qualified label based on column name.
4920
4921 for table-bound columns this is <tablename>_<columnname>; all other
4922 expressions it resolves to .name.
4923
4924 """
4925 return self._gen_tq_label(self.name)
4926
4927 @HasMemoized.memoized_attribute
4928 def _render_label_in_columns_clause(self):
4929 return True
4930
4931 @HasMemoized.memoized_attribute
4932 def _non_anon_label(self):
4933 return self.name
4934
4935 def _gen_tq_label(
4936 self, name: str, dedupe_on_key: bool = True
4937 ) -> Optional[str]:
4938 return name
4939
4940 def _bind_param(
4941 self,
4942 operator: OperatorType,
4943 obj: Any,
4944 type_: Optional[TypeEngine[_T]] = None,
4945 expanding: bool = False,
4946 ) -> BindParameter[_T]:
4947 return BindParameter(
4948 self.key,
4949 obj,
4950 _compared_to_operator=operator,
4951 _compared_to_type=self.type,
4952 type_=type_,
4953 unique=True,
4954 expanding=expanding,
4955 )
4956
4957 def _make_proxy(
4958 self,
4959 selectable: FromClause,
4960 *,
4961 primary_key: ColumnSet,
4962 foreign_keys: Set[KeyedColumnElement[Any]],
4963 name: Optional[str] = None,
4964 key: Optional[str] = None,
4965 name_is_truncatable: bool = False,
4966 compound_select_cols: Optional[Sequence[ColumnElement[Any]]] = None,
4967 disallow_is_literal: bool = False,
4968 **kw: Any,
4969 ) -> typing_Tuple[str, ColumnClause[_T]]:
4970 c = ColumnClause(
4971 (
4972 coercions.expect(roles.TruncatedLabelRole, name or self.name)
4973 if name_is_truncatable
4974 else (name or self.name)
4975 ),
4976 type_=self.type,
4977 _selectable=selectable,
4978 is_literal=False,
4979 )
4980
4981 c._propagate_attrs = selectable._propagate_attrs
4982 if name is None:
4983 c.key = self.key
4984 if compound_select_cols:
4985 c._proxies = list(compound_select_cols)
4986 else:
4987 c._proxies = [self]
4988
4989 if selectable._is_clone_of is not None:
4990 c._is_clone_of = selectable._is_clone_of.columns.get(c.key)
4991 return c.key, c
4992
4993
4994_PS = ParamSpec("_PS")
4995
4996
4997class Label(roles.LabeledColumnExprRole[_T], NamedColumn[_T]):
4998 """Represents a column label (AS).
4999
5000 Represent a label, as typically applied to any column-level
5001 element using the ``AS`` sql keyword.
5002
5003 """
5004
5005 __visit_name__ = "label"
5006
5007 _traverse_internals: _TraverseInternalsType = [
5008 ("name", InternalTraversal.dp_anon_name),
5009 ("type", InternalTraversal.dp_type),
5010 ("_element", InternalTraversal.dp_clauseelement),
5011 ]
5012
5013 _cache_key_traversal = [
5014 ("name", InternalTraversal.dp_anon_name),
5015 ("_element", InternalTraversal.dp_clauseelement),
5016 ]
5017
5018 _element: ColumnElement[_T]
5019 name: str
5020
5021 def __init__(
5022 self,
5023 name: Optional[str],
5024 element: _ColumnExpressionArgument[_T],
5025 type_: Optional[_TypeEngineArgument[_T]] = None,
5026 ):
5027 orig_element = element
5028 element = coercions.expect(
5029 roles.ExpressionElementRole,
5030 element,
5031 apply_propagate_attrs=self,
5032 )
5033 while isinstance(element, Label):
5034 # TODO: this is only covered in test_text.py, but nothing
5035 # fails if it's removed. determine rationale
5036 element = element.element
5037
5038 if name:
5039 self.name = name
5040 else:
5041 self.name = _anonymous_label.safe_construct(
5042 id(self), getattr(element, "name", "anon")
5043 )
5044 if isinstance(orig_element, Label):
5045 # TODO: no coverage for this block, again would be in
5046 # test_text.py where the resolve_label concept is important
5047 self._resolve_label = orig_element._label
5048
5049 self.key = self._tq_label = self._tq_key_label = self.name
5050 self._element = element
5051
5052 self.type = (
5053 type_api.to_instance(type_)
5054 if type_ is not None
5055 else self._element.type
5056 )
5057
5058 self._proxies = [element]
5059
5060 def __reduce__(self):
5061 return self.__class__, (self.name, self._element, self.type)
5062
5063 @HasMemoized.memoized_attribute
5064 def _render_label_in_columns_clause(self):
5065 return True
5066
5067 def _bind_param(self, operator, obj, type_=None, expanding=False):
5068 return BindParameter(
5069 None,
5070 obj,
5071 _compared_to_operator=operator,
5072 type_=type_,
5073 _compared_to_type=self.type,
5074 unique=True,
5075 expanding=expanding,
5076 )
5077
5078 @util.memoized_property
5079 def _is_implicitly_boolean(self):
5080 return self.element._is_implicitly_boolean
5081
5082 @HasMemoized.memoized_attribute
5083 def _allow_label_resolve(self):
5084 return self.element._allow_label_resolve
5085
5086 @property
5087 def _order_by_label_element(self):
5088 return self
5089
5090 def as_reference(self) -> _label_reference[_T]:
5091 """refer to this labeled expression in a clause such as GROUP BY,
5092 ORDER BY etc. as the label name itself, without expanding
5093 into the full expression.
5094
5095 .. versionadded:: 2.1
5096
5097 """
5098 return _label_reference(self)
5099
5100 @HasMemoized.memoized_attribute
5101 def element(self) -> ColumnElement[_T]:
5102 return self._element.self_group(against=operators.as_)
5103
5104 def self_group(self, against: Optional[OperatorType] = None) -> Label[_T]:
5105 return self._apply_to_inner(self._element.self_group, against=against)
5106
5107 def _negate(self):
5108 return self._apply_to_inner(self._element._negate)
5109
5110 def _apply_to_inner(
5111 self,
5112 fn: Callable[_PS, ColumnElement[_T]],
5113 *arg: _PS.args,
5114 **kw: _PS.kwargs,
5115 ) -> Label[_T]:
5116 sub_element = fn(*arg, **kw)
5117 if sub_element is not self._element:
5118 return Label(self.name, sub_element, type_=self.type)
5119 else:
5120 return self
5121
5122 @property
5123 def primary_key(self): # type: ignore[override]
5124 return self.element.primary_key
5125
5126 @property
5127 def foreign_keys(self): # type: ignore[override]
5128 return self.element.foreign_keys
5129
5130 def _copy_internals(
5131 self,
5132 *,
5133 clone: _CloneCallableType = _clone,
5134 anonymize_labels: bool = False,
5135 **kw: Any,
5136 ) -> None:
5137 self._reset_memoizations()
5138 self._element = clone(self._element, **kw)
5139 if anonymize_labels:
5140 self.name = _anonymous_label.safe_construct(
5141 id(self), getattr(self.element, "name", "anon")
5142 )
5143 self.key = self._tq_label = self._tq_key_label = self.name
5144
5145 @util.ro_non_memoized_property
5146 def _from_objects(self) -> List[FromClause]:
5147 return self.element._from_objects
5148
5149 def _make_proxy(
5150 self,
5151 selectable: FromClause,
5152 *,
5153 primary_key: ColumnSet,
5154 foreign_keys: Set[KeyedColumnElement[Any]],
5155 name: Optional[str] = None,
5156 compound_select_cols: Optional[Sequence[ColumnElement[Any]]] = None,
5157 **kw: Any,
5158 ) -> typing_Tuple[str, ColumnClause[_T]]:
5159 name = self.name if not name else name
5160
5161 key, e = self.element._make_proxy(
5162 selectable,
5163 name=name,
5164 disallow_is_literal=True,
5165 name_is_truncatable=isinstance(name, _truncated_label),
5166 compound_select_cols=compound_select_cols,
5167 primary_key=primary_key,
5168 foreign_keys=foreign_keys,
5169 )
5170
5171 # there was a note here to remove this assertion, which was here
5172 # to determine if we later could support a use case where
5173 # the key and name of a label are separate. But I don't know what
5174 # that case was. For now, this is an unexpected case that occurs
5175 # when a label name conflicts with other columns and select()
5176 # is attempting to disambiguate an explicit label, which is not what
5177 # the user would want. See issue #6090.
5178 if key != self.name and not isinstance(self.name, _anonymous_label):
5179 raise exc.InvalidRequestError(
5180 "Label name %s is being renamed to an anonymous label due "
5181 "to disambiguation "
5182 "which is not supported right now. Please use unique names "
5183 "for explicit labels." % (self.name)
5184 )
5185
5186 e._propagate_attrs = selectable._propagate_attrs
5187 e._proxies.append(self)
5188 if self.type is not None:
5189 e.type = self.type
5190
5191 return self.key, e
5192
5193
5194class ColumnClause(
5195 roles.DDLReferredColumnRole,
5196 roles.LabeledColumnExprRole[_T],
5197 roles.StrAsPlainColumnRole,
5198 Immutable,
5199 NamedColumn[_T],
5200):
5201 """Represents a column expression from any textual string.
5202
5203 The :class:`.ColumnClause`, a lightweight analogue to the
5204 :class:`_schema.Column` class, is typically invoked using the
5205 :func:`_expression.column` function, as in::
5206
5207 from sqlalchemy import column
5208
5209 id, name = column("id"), column("name")
5210 stmt = select(id, name).select_from("user")
5211
5212 The above statement would produce SQL like:
5213
5214 .. sourcecode:: sql
5215
5216 SELECT id, name FROM user
5217
5218 :class:`.ColumnClause` is the immediate superclass of the schema-specific
5219 :class:`_schema.Column` object. While the :class:`_schema.Column`
5220 class has all the
5221 same capabilities as :class:`.ColumnClause`, the :class:`.ColumnClause`
5222 class is usable by itself in those cases where behavioral requirements
5223 are limited to simple SQL expression generation. The object has none of
5224 the associations with schema-level metadata or with execution-time
5225 behavior that :class:`_schema.Column` does,
5226 so in that sense is a "lightweight"
5227 version of :class:`_schema.Column`.
5228
5229 Full details on :class:`.ColumnClause` usage is at
5230 :func:`_expression.column`.
5231
5232 .. seealso::
5233
5234 :func:`_expression.column`
5235
5236 :class:`_schema.Column`
5237
5238 """
5239
5240 table: Optional[FromClause]
5241 is_literal: bool
5242
5243 __visit_name__ = "column"
5244
5245 _traverse_internals: _TraverseInternalsType = [
5246 ("name", InternalTraversal.dp_anon_name),
5247 ("type", InternalTraversal.dp_type),
5248 ("table", InternalTraversal.dp_clauseelement),
5249 ("is_literal", InternalTraversal.dp_boolean),
5250 ]
5251
5252 onupdate: Optional[DefaultGenerator] = None
5253 default: Optional[DefaultGenerator] = None
5254 server_default: Optional[FetchedValue] = None
5255 server_onupdate: Optional[FetchedValue] = None
5256
5257 _is_multiparam_column = False
5258
5259 @property
5260 def _is_star(self): # type: ignore[override]
5261 return self.is_literal and self.name == "*"
5262
5263 def __init__(
5264 self,
5265 text: str,
5266 type_: Optional[_TypeEngineArgument[_T]] = None,
5267 is_literal: bool = False,
5268 _selectable: Optional[FromClause] = None,
5269 ):
5270 self.key = self.name = text
5271 self.table = _selectable
5272
5273 # if type is None, we get NULLTYPE, which is our _T. But I don't
5274 # know how to get the overloads to express that correctly
5275 self.type = type_api.to_instance(type_) # type: ignore
5276
5277 self.is_literal = is_literal
5278
5279 def get_children(self, *, column_tables=False, **kw):
5280 # override base get_children() to not return the Table
5281 # or selectable that is parent to this column. Traversals
5282 # expect the columns of tables and subqueries to be leaf nodes.
5283 return []
5284
5285 @property
5286 def entity_namespace(self):
5287 if self.table is not None:
5288 return self.table.entity_namespace
5289 else:
5290 return super().entity_namespace
5291
5292 def _clone(self, detect_subquery_cols=False, **kw):
5293 if (
5294 detect_subquery_cols
5295 and self.table is not None
5296 and self.table._is_subquery
5297 ):
5298 clone = kw.pop("clone")
5299 table = clone(self.table, **kw)
5300 new = table.c.corresponding_column(self)
5301 return new
5302
5303 return super()._clone(**kw)
5304
5305 @HasMemoized_ro_memoized_attribute
5306 def _from_objects(self) -> List[FromClause]:
5307 t = self.table
5308 if t is not None:
5309 return [t]
5310 else:
5311 return []
5312
5313 @HasMemoized.memoized_attribute
5314 def _render_label_in_columns_clause(self):
5315 return self.table is not None
5316
5317 @property
5318 def _ddl_label(self):
5319 return self._gen_tq_label(self.name, dedupe_on_key=False)
5320
5321 def _compare_name_for_result(self, other):
5322 if (
5323 self.is_literal
5324 or self.table is None
5325 or self.table._is_textual
5326 or not hasattr(other, "proxy_set")
5327 or (
5328 isinstance(other, ColumnClause)
5329 and (
5330 other.is_literal
5331 or other.table is None
5332 or other.table._is_textual
5333 )
5334 )
5335 ):
5336 return (hasattr(other, "name") and self.name == other.name) or (
5337 hasattr(other, "_tq_label")
5338 and self._tq_label == other._tq_label
5339 )
5340 else:
5341 return other.proxy_set.intersection(self.proxy_set)
5342
5343 def _gen_tq_label(
5344 self, name: str, dedupe_on_key: bool = True
5345 ) -> Optional[str]:
5346 """generate table-qualified label
5347
5348 for a table-bound column this is <tablename>_<columnname>.
5349
5350 used primarily for LABEL_STYLE_TABLENAME_PLUS_COL
5351 as well as the .columns collection on a Join object.
5352
5353 """
5354 label: str
5355 t = self.table
5356 if self.is_literal:
5357 return None
5358 elif t is not None and is_named_from_clause(t):
5359 if has_schema_attr(t) and t.schema:
5360 label = (
5361 t.schema.replace(".", "_") + "_" + t.name + ("_" + name)
5362 )
5363 else:
5364 assert not TYPE_CHECKING or isinstance(t, NamedFromClause)
5365 label = t.name + ("_" + name)
5366
5367 # propagate name quoting rules for labels.
5368 if is_quoted_name(name) and name.quote is not None:
5369 if is_quoted_name(label):
5370 label.quote = name.quote
5371 else:
5372 label = quoted_name(label, name.quote)
5373 elif is_quoted_name(t.name) and t.name.quote is not None:
5374 # can't get this situation to occur, so let's
5375 # assert false on it for now
5376 assert not isinstance(label, quoted_name)
5377 label = quoted_name(label, t.name.quote)
5378
5379 if dedupe_on_key:
5380 # ensure the label name doesn't conflict with that of an
5381 # existing column. note that this implies that any Column
5382 # must **not** set up its _label before its parent table has
5383 # all of its other Column objects set up. There are several
5384 # tables in the test suite which will fail otherwise; example:
5385 # table "owner" has columns "name" and "owner_name". Therefore
5386 # column owner.name cannot use the label "owner_name", it has
5387 # to be "owner_name_1".
5388 if label in t.c:
5389 _label = label
5390 counter = 1
5391 while _label in t.c:
5392 _label = label + f"_{counter}"
5393 counter += 1
5394 label = _label
5395
5396 return coercions.expect(roles.TruncatedLabelRole, label)
5397
5398 else:
5399 return name
5400
5401 def _make_proxy(
5402 self,
5403 selectable: FromClause,
5404 *,
5405 primary_key: ColumnSet,
5406 foreign_keys: Set[KeyedColumnElement[Any]],
5407 name: Optional[str] = None,
5408 key: Optional[str] = None,
5409 name_is_truncatable: bool = False,
5410 compound_select_cols: Optional[Sequence[ColumnElement[Any]]] = None,
5411 disallow_is_literal: bool = False,
5412 **kw: Any,
5413 ) -> typing_Tuple[str, ColumnClause[_T]]:
5414 # the "is_literal" flag normally should never be propagated; a proxied
5415 # column is always a SQL identifier and never the actual expression
5416 # being evaluated. however, there is a case where the "is_literal" flag
5417 # might be used to allow the given identifier to have a fixed quoting
5418 # pattern already, so maintain the flag for the proxy unless a
5419 # :class:`.Label` object is creating the proxy. See [ticket:4730].
5420 is_literal = (
5421 not disallow_is_literal
5422 and self.is_literal
5423 and (
5424 # note this does not accommodate for quoted_name differences
5425 # right now
5426 name is None
5427 or name == self.name
5428 )
5429 )
5430 c = self._constructor(
5431 (
5432 coercions.expect(roles.TruncatedLabelRole, name or self.name)
5433 if name_is_truncatable
5434 else (name or self.name)
5435 ),
5436 type_=self.type,
5437 _selectable=selectable,
5438 is_literal=is_literal,
5439 )
5440 c._propagate_attrs = selectable._propagate_attrs
5441 if name is None:
5442 c.key = self.key
5443 if compound_select_cols:
5444 c._proxies = list(compound_select_cols)
5445 else:
5446 c._proxies = [self]
5447
5448 if selectable._is_clone_of is not None:
5449 c._is_clone_of = selectable._is_clone_of.columns.get(c.key)
5450 return c.key, c
5451
5452
5453class TableValuedColumn(NamedColumn[_T]):
5454 __visit_name__ = "table_valued_column"
5455
5456 _traverse_internals: _TraverseInternalsType = [
5457 ("name", InternalTraversal.dp_anon_name),
5458 ("type", InternalTraversal.dp_type),
5459 ("scalar_alias", InternalTraversal.dp_clauseelement),
5460 ]
5461
5462 def __init__(self, scalar_alias: NamedFromClause, type_: TypeEngine[_T]):
5463 self.scalar_alias = scalar_alias
5464 self.key = self.name = scalar_alias.name
5465 self.type = type_
5466
5467 def _copy_internals(
5468 self, clone: _CloneCallableType = _clone, **kw: Any
5469 ) -> None:
5470 self.scalar_alias = clone(self.scalar_alias, **kw)
5471 self.key = self.name = self.scalar_alias.name
5472
5473 @util.ro_non_memoized_property
5474 def _from_objects(self) -> List[FromClause]:
5475 return [self.scalar_alias]
5476
5477
5478class CollationClause(ColumnElement[str]):
5479 __visit_name__ = "collation"
5480
5481 _traverse_internals: _TraverseInternalsType = [
5482 ("collation", InternalTraversal.dp_string)
5483 ]
5484
5485 @classmethod
5486 @util.preload_module("sqlalchemy.sql.sqltypes")
5487 def _create_collation_expression(
5488 cls, expression: _ColumnExpressionArgument[str], collation: str
5489 ) -> BinaryExpression[str]:
5490
5491 sqltypes = util.preloaded.sql_sqltypes
5492
5493 expr = coercions.expect(roles.ExpressionElementRole[str], expression)
5494
5495 if expr.type._type_affinity is sqltypes.String:
5496 collate_type = expr.type._with_collation(collation)
5497 else:
5498 collate_type = expr.type
5499
5500 return BinaryExpression(
5501 expr,
5502 CollationClause(collation),
5503 operators.collate,
5504 type_=collate_type,
5505 )
5506
5507 def __init__(self, collation):
5508 self.collation = collation
5509
5510
5511class _IdentifiedClause(Executable, ClauseElement):
5512 __visit_name__ = "identified"
5513
5514 def __init__(self, ident):
5515 self.ident = ident
5516
5517
5518class SavepointClause(_IdentifiedClause):
5519 __visit_name__ = "savepoint"
5520 inherit_cache = False
5521
5522
5523class RollbackToSavepointClause(_IdentifiedClause):
5524 __visit_name__ = "rollback_to_savepoint"
5525 inherit_cache = False
5526
5527
5528class ReleaseSavepointClause(_IdentifiedClause):
5529 __visit_name__ = "release_savepoint"
5530 inherit_cache = False
5531
5532
5533class quoted_name(util.MemoizedSlots, str):
5534 """Represent a SQL identifier combined with quoting preferences.
5535
5536 :class:`.quoted_name` is a Python unicode/str subclass which
5537 represents a particular identifier name along with a
5538 ``quote`` flag. This ``quote`` flag, when set to
5539 ``True`` or ``False``, overrides automatic quoting behavior
5540 for this identifier in order to either unconditionally quote
5541 or to not quote the name. If left at its default of ``None``,
5542 quoting behavior is applied to the identifier on a per-backend basis
5543 based on an examination of the token itself.
5544
5545 A :class:`.quoted_name` object with ``quote=True`` is also
5546 prevented from being modified in the case of a so-called
5547 "name normalize" option. Certain database backends, such as
5548 Oracle Database, Firebird, and DB2 "normalize" case-insensitive names
5549 as uppercase. The SQLAlchemy dialects for these backends
5550 convert from SQLAlchemy's lower-case-means-insensitive convention
5551 to the upper-case-means-insensitive conventions of those backends.
5552 The ``quote=True`` flag here will prevent this conversion from occurring
5553 to support an identifier that's quoted as all lower case against
5554 such a backend.
5555
5556 The :class:`.quoted_name` object is normally created automatically
5557 when specifying the name for key schema constructs such as
5558 :class:`_schema.Table`, :class:`_schema.Column`, and others.
5559 The class can also be
5560 passed explicitly as the name to any function that receives a name which
5561 can be quoted. Such as to use the :meth:`_engine.Engine.has_table`
5562 method with
5563 an unconditionally quoted name::
5564
5565 from sqlalchemy import create_engine
5566 from sqlalchemy import inspect
5567 from sqlalchemy.sql import quoted_name
5568
5569 engine = create_engine("oracle+oracledb://some_dsn")
5570 print(inspect(engine).has_table(quoted_name("some_table", True)))
5571
5572 The above logic will run the "has table" logic against the Oracle Database
5573 backend, passing the name exactly as ``"some_table"`` without converting to
5574 upper case.
5575
5576 """
5577
5578 __slots__ = "quote", "lower", "upper"
5579
5580 quote: Optional[bool]
5581
5582 @overload
5583 @classmethod
5584 def construct(cls, value: str, quote: Optional[bool]) -> quoted_name: ...
5585
5586 @overload
5587 @classmethod
5588 def construct(cls, value: None, quote: Optional[bool]) -> None: ...
5589
5590 @classmethod
5591 def construct(
5592 cls, value: Optional[str], quote: Optional[bool]
5593 ) -> Optional[quoted_name]:
5594 if value is None:
5595 return None
5596 else:
5597 return quoted_name(value, quote)
5598
5599 def __new__(cls, value: str, quote: Optional[bool]) -> quoted_name:
5600 assert (
5601 value is not None
5602 ), "use quoted_name.construct() for None passthrough"
5603 if isinstance(value, cls) and (quote is None or value.quote == quote):
5604 return value
5605 self = super().__new__(cls, value)
5606
5607 self.quote = quote
5608 return self
5609
5610 def __reduce__(self):
5611 return quoted_name, (str(self), self.quote)
5612
5613 def _memoized_method_lower(self):
5614 if self.quote:
5615 return self
5616 else:
5617 return str(self).lower()
5618
5619 def _memoized_method_upper(self):
5620 if self.quote:
5621 return self
5622 else:
5623 return str(self).upper()
5624
5625
5626def _find_columns(clause: ClauseElement) -> Set[ColumnClause[Any]]:
5627 """locate Column objects within the given expression."""
5628
5629 cols: Set[ColumnClause[Any]] = set()
5630 traverse(clause, {}, {"column": cols.add})
5631 return cols
5632
5633
5634def _type_from_args(args: Sequence[ColumnElement[_T]]) -> TypeEngine[_T]:
5635 for a in args:
5636 if not a.type._isnull:
5637 return a.type
5638 else:
5639 return type_api.NULLTYPE # type: ignore
5640
5641
5642def _corresponding_column_or_error(fromclause, column, require_embedded=False):
5643 c = fromclause.corresponding_column(
5644 column, require_embedded=require_embedded
5645 )
5646 if c is None:
5647 raise exc.InvalidRequestError(
5648 "Given column '%s', attached to table '%s', "
5649 "failed to locate a corresponding column from table '%s'"
5650 % (column, getattr(column, "table", None), fromclause.description)
5651 )
5652 return c
5653
5654
5655class _memoized_property_but_not_nulltype(
5656 util.memoized_property["TypeEngine[_T]"]
5657):
5658 """memoized property, but dont memoize NullType"""
5659
5660 def __get__(self, obj, cls):
5661 if obj is None:
5662 return self
5663 result = self.fget(obj)
5664 if not result._isnull:
5665 obj.__dict__[self.__name__] = result
5666 return result
5667
5668
5669class AnnotatedColumnElement(Annotated):
5670 _Annotated__element: ColumnElement[Any]
5671
5672 def __init__(self, element, values):
5673 Annotated.__init__(self, element, values)
5674 for attr in (
5675 "comparator",
5676 "_proxy_key",
5677 "_tq_key_label",
5678 "_tq_label",
5679 "_non_anon_label",
5680 "type",
5681 ):
5682 self.__dict__.pop(attr, None)
5683 for attr in ("name", "key", "table"):
5684 if self.__dict__.get(attr, False) is None:
5685 self.__dict__.pop(attr)
5686
5687 def _with_annotations(self, values):
5688 clone = super()._with_annotations(values)
5689 for attr in (
5690 "comparator",
5691 "_proxy_key",
5692 "_tq_key_label",
5693 "_tq_label",
5694 "_non_anon_label",
5695 ):
5696 clone.__dict__.pop(attr, None)
5697 return clone
5698
5699 @util.memoized_property
5700 def name(self):
5701 """pull 'name' from parent, if not present"""
5702 return self._Annotated__element.name
5703
5704 @_memoized_property_but_not_nulltype
5705 def type(self):
5706 """pull 'type' from parent and don't cache if null.
5707
5708 type is routinely changed on existing columns within the
5709 mapped_column() initialization process, and "type" is also consulted
5710 during the creation of SQL expressions. Therefore it can change after
5711 it was already retrieved. At the same time we don't want annotated
5712 objects having overhead when expressions are produced, so continue
5713 to memoize, but only when we have a non-null type.
5714
5715 """
5716 return self._Annotated__element.type
5717
5718 @util.memoized_property
5719 def table(self):
5720 """pull 'table' from parent, if not present"""
5721 return self._Annotated__element.table
5722
5723 @util.memoized_property
5724 def key(self):
5725 """pull 'key' from parent, if not present"""
5726 return self._Annotated__element.key
5727
5728 @util.memoized_property
5729 def info(self) -> _InfoType:
5730 if TYPE_CHECKING:
5731 assert isinstance(self._Annotated__element, Column)
5732 return self._Annotated__element.info
5733
5734 @util.memoized_property
5735 def _anon_name_label(self) -> str:
5736 return self._Annotated__element._anon_name_label
5737
5738
5739class _truncated_label(quoted_name):
5740 """A unicode subclass used to identify symbolic "
5741 "names that may require truncation."""
5742
5743 __slots__ = ()
5744
5745 def __new__(cls, value: str, quote: Optional[bool] = None) -> Any:
5746 quote = getattr(value, "quote", quote)
5747 # return super(_truncated_label, cls).__new__(cls, value, quote, True)
5748 return super().__new__(cls, value, quote)
5749
5750 def __reduce__(self) -> Any:
5751 return self.__class__, (str(self), self.quote)
5752
5753 def apply_map(self, map_: Mapping[str, Any]) -> str:
5754 return self
5755
5756
5757class conv(_truncated_label):
5758 """Mark a string indicating that a name has already been converted
5759 by a naming convention.
5760
5761 This is a string subclass that indicates a name that should not be
5762 subject to any further naming conventions.
5763
5764 E.g. when we create a :class:`.Constraint` using a naming convention
5765 as follows::
5766
5767 m = MetaData(
5768 naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"}
5769 )
5770 t = Table(
5771 "t", m, Column("x", Integer), CheckConstraint("x > 5", name="x5")
5772 )
5773
5774 The name of the above constraint will be rendered as ``"ck_t_x5"``.
5775 That is, the existing name ``x5`` is used in the naming convention as the
5776 ``constraint_name`` token.
5777
5778 In some situations, such as in migration scripts, we may be rendering
5779 the above :class:`.CheckConstraint` with a name that's already been
5780 converted. In order to make sure the name isn't double-modified, the
5781 new name is applied using the :func:`_schema.conv` marker. We can
5782 use this explicitly as follows::
5783
5784
5785 m = MetaData(
5786 naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"}
5787 )
5788 t = Table(
5789 "t",
5790 m,
5791 Column("x", Integer),
5792 CheckConstraint("x > 5", name=conv("ck_t_x5")),
5793 )
5794
5795 Where above, the :func:`_schema.conv` marker indicates that the constraint
5796 name here is final, and the name will render as ``"ck_t_x5"`` and not
5797 ``"ck_t_ck_t_x5"``
5798
5799 .. seealso::
5800
5801 :ref:`constraint_naming_conventions`
5802
5803 """
5804
5805 __slots__ = ()
5806
5807
5808# for backwards compatibility in case
5809# someone is re-implementing the
5810# _truncated_identifier() sequence in a custom
5811# compiler
5812_generated_label = _truncated_label
5813_anonymous_label_escape = re.compile(r"[%\(\) \$]+")
5814
5815
5816class _anonymous_label(_truncated_label):
5817 """A unicode subclass used to identify anonymously
5818 generated names."""
5819
5820 __slots__ = ()
5821
5822 @classmethod
5823 def safe_construct_with_key(
5824 cls, seed: int, body: str, sanitize_key: bool = False
5825 ) -> typing_Tuple[_anonymous_label, str]:
5826 # need to escape chars that interfere with format
5827 # strings in any case, issue #8724
5828 body = _anonymous_label_escape.sub("_", body)
5829
5830 if sanitize_key:
5831 # sanitize_key is then an extra step used by BindParameter
5832 body = body.strip("_")
5833
5834 key = f"{seed} {body.replace('%', '%%')}"
5835 label = _anonymous_label(f"%({key})s")
5836 return label, key
5837
5838 @classmethod
5839 def safe_construct(
5840 cls, seed: int, body: str, sanitize_key: bool = False
5841 ) -> _anonymous_label:
5842 # need to escape chars that interfere with format
5843 # strings in any case, issue #8724
5844 body = _anonymous_label_escape.sub("_", body)
5845
5846 if sanitize_key:
5847 # sanitize_key is then an extra step used by BindParameter
5848 body = body.strip("_")
5849
5850 return _anonymous_label(f"%({seed} {body.replace('%', '%%')})s")
5851
5852 def __add__(self, other: str) -> _anonymous_label:
5853 if "%" in other and not isinstance(other, _anonymous_label):
5854 other = str(other).replace("%", "%%")
5855 else:
5856 other = str(other)
5857
5858 return _anonymous_label(
5859 quoted_name(
5860 str.__add__(self, other),
5861 self.quote,
5862 )
5863 )
5864
5865 def __radd__(self, other: str) -> _anonymous_label:
5866 if "%" in other and not isinstance(other, _anonymous_label):
5867 other = str(other).replace("%", "%%")
5868 else:
5869 other = str(other)
5870
5871 return _anonymous_label(
5872 quoted_name(
5873 str.__add__(other, self),
5874 self.quote,
5875 )
5876 )
5877
5878 def apply_map(self, map_: Mapping[str, Any]) -> str:
5879 if self.quote is not None:
5880 # preserve quoting only if necessary
5881 return quoted_name(self % map_, self.quote)
5882 else:
5883 # else skip the constructor call
5884 return self % map_