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