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