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