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