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