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