Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/elements.py: 44%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1919 statements  

1# sql/elements.py 

2# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# 

5# This module is part of SQLAlchemy and is released under 

6# the MIT License: https://www.opensource.org/licenses/mit-license.php 

7# mypy: allow-untyped-defs, allow-untyped-calls 

8 

9"""Core SQL expression elements, including :class:`_expression.ClauseElement`, 

10:class:`_expression.ColumnElement`, and derived classes. 

11 

12""" 

13 

14from __future__ import annotations 

15 

16from decimal import Decimal 

17from enum import Enum 

18import itertools 

19import operator 

20import re 

21import typing 

22from typing import AbstractSet 

23from typing import Any 

24from typing import Callable 

25from typing import cast 

26from typing import Dict 

27from typing import FrozenSet 

28from typing import Generic 

29from typing import Iterable 

30from typing import Iterator 

31from typing import List 

32from typing import Mapping 

33from typing import Optional 

34from typing import overload 

35from typing import Sequence 

36from typing import Set 

37from typing import Tuple as typing_Tuple 

38from typing import Type 

39from typing import TYPE_CHECKING 

40from typing import TypeVar 

41from typing import Union 

42 

43from . import coercions 

44from . import operators 

45from . import roles 

46from . import traversals 

47from . import type_api 

48from ._typing import has_schema_attr 

49from ._typing import is_named_from_clause 

50from ._typing import is_quoted_name 

51from ._typing import is_tuple_type 

52from .annotation import Annotated 

53from .annotation import SupportsWrappingAnnotations 

54from .base import _clone 

55from .base import _expand_cloned 

56from .base import _generative 

57from .base import _NoArg 

58from .base import Executable 

59from .base import Generative 

60from .base import HasMemoized 

61from .base import Immutable 

62from .base import NO_ARG 

63from .base import SingletonConstant 

64from .cache_key import MemoizedHasCacheKey 

65from .cache_key import NO_CACHE 

66from .coercions import _document_text_coercion # noqa 

67from .operators import ColumnOperators 

68from .traversals import HasCopyInternals 

69from .visitors import cloned_traverse 

70from .visitors import ExternallyTraversible 

71from .visitors import InternalTraversal 

72from .visitors import traverse 

73from .visitors import Visitable 

74from .. import exc 

75from .. import inspection 

76from .. import util 

77from ..util import HasMemoized_ro_memoized_attribute 

78from ..util import TypingOnly 

79from ..util.typing import Literal 

80from ..util.typing import ParamSpec 

81from ..util.typing import Self 

82 

83 

84if typing.TYPE_CHECKING: 

85 from ._typing import _ByArgument 

86 from ._typing import _ColumnExpressionArgument 

87 from ._typing import _ColumnExpressionOrStrLabelArgument 

88 from ._typing import _HasDialect 

89 from ._typing import _InfoType 

90 from ._typing import _OnlyColumnArgument 

91 from ._typing import _PropagateAttrsType 

92 from ._typing import _TypeEngineArgument 

93 from .base import _EntityNamespace 

94 from .base import ColumnSet 

95 from .cache_key import _CacheKeyTraversalType 

96 from .cache_key import CacheKey 

97 from .compiler import Compiled 

98 from .compiler import SQLCompiler 

99 from .functions import FunctionElement 

100 from .operators import OperatorType 

101 from .schema import Column 

102 from .schema import DefaultGenerator 

103 from .schema import FetchedValue 

104 from .schema import ForeignKey 

105 from .selectable import _SelectIterable 

106 from .selectable import FromClause 

107 from .selectable import NamedFromClause 

108 from .selectable import TextualSelect 

109 from .sqltypes import TupleType 

110 from .type_api import TypeEngine 

111 from .visitors import _CloneCallableType 

112 from .visitors import _TraverseInternalsType 

113 from .visitors import anon_map 

114 from ..engine import Connection 

115 from ..engine import Dialect 

116 from ..engine.interfaces import _CoreMultiExecuteParams 

117 from ..engine.interfaces import CacheStats 

118 from ..engine.interfaces import CompiledCacheType 

119 from ..engine.interfaces import CoreExecuteOptionsParameter 

120 from ..engine.interfaces import SchemaTranslateMapType 

121 from ..engine.result import Result 

122 

123 

124_NUMERIC = Union[float, Decimal] 

125_NUMBER = Union[float, int, Decimal] 

126 

127_T = TypeVar("_T", bound="Any") 

128_T_co = TypeVar("_T_co", bound=Any, covariant=True) 

129_OPT = TypeVar("_OPT", bound="Any") 

130_NT = TypeVar("_NT", bound="_NUMERIC") 

131 

132_NMT = TypeVar("_NMT", bound="_NUMBER") 

133 

134 

135@overload 

136def literal( 

137 value: Any, 

138 type_: _TypeEngineArgument[_T], 

139 literal_execute: bool = False, 

140) -> BindParameter[_T]: ... 

141 

142 

143@overload 

144def literal( 

145 value: _T, 

146 type_: None = None, 

147 literal_execute: bool = False, 

148) -> BindParameter[_T]: ... 

149 

150 

151@overload 

152def literal( 

153 value: Any, 

154 type_: Optional[_TypeEngineArgument[Any]] = None, 

155 literal_execute: bool = False, 

156) -> BindParameter[Any]: ... 

157 

158 

159def literal( 

160 value: Any, 

161 type_: Optional[_TypeEngineArgument[Any]] = None, 

162 literal_execute: bool = False, 

163) -> BindParameter[Any]: 

164 r"""Return a literal clause, bound to a bind parameter. 

165 

166 Literal clauses are created automatically when non- 

167 :class:`_expression.ClauseElement` objects (such as strings, ints, dates, 

168 etc.) are 

169 used in a comparison operation with a :class:`_expression.ColumnElement` 

170 subclass, 

171 such as a :class:`~sqlalchemy.schema.Column` object. Use this function 

172 to force the generation of a literal clause, which will be created as a 

173 :class:`BindParameter` with a bound value. 

174 

175 :param value: the value to be bound. Can be any Python object supported by 

176 the underlying DB-API, or is translatable via the given type argument. 

177 

178 :param type\_: an optional :class:`~sqlalchemy.types.TypeEngine` which will 

179 provide bind-parameter translation for this literal. 

180 

181 :param literal_execute: optional bool, when True, the SQL engine will 

182 attempt to render the bound value directly in the SQL statement at 

183 execution time rather than providing as a parameter value. 

184 

185 .. versionadded:: 2.0 

186 

187 """ 

188 return coercions.expect( 

189 roles.LiteralValueRole, 

190 value, 

191 type_=type_, 

192 literal_execute=literal_execute, 

193 ) 

194 

195 

196def literal_column( 

197 text: str, type_: Optional[_TypeEngineArgument[_T]] = None 

198) -> ColumnClause[_T]: 

199 r"""Produce a :class:`.ColumnClause` object that has the 

200 :paramref:`_expression.column.is_literal` flag set to True. 

201 

202 :func:`_expression.literal_column` is similar to 

203 :func:`_expression.column`, except that 

204 it is more often used as a "standalone" column expression that renders 

205 exactly as stated; while :func:`_expression.column` 

206 stores a string name that 

207 will be assumed to be part of a table and may be quoted as such, 

208 :func:`_expression.literal_column` can be that, 

209 or any other arbitrary column-oriented 

210 expression. 

211 

212 :param text: the text of the expression; can be any SQL expression. 

213 Quoting rules will not be applied. To specify a column-name expression 

214 which should be subject to quoting rules, use the :func:`column` 

215 function. 

216 

217 :param type\_: an optional :class:`~sqlalchemy.types.TypeEngine` 

218 object which will 

219 provide result-set translation and additional expression semantics for 

220 this column. If left as ``None`` the type will be :class:`.NullType`. 

221 

222 .. seealso:: 

223 

224 :func:`_expression.column` 

225 

226 :func:`_expression.text` 

227 

228 :ref:`tutorial_select_arbitrary_text` 

229 

230 """ 

231 return ColumnClause(text, type_=type_, is_literal=True) 

232 

233 

234class CompilerElement(Visitable): 

235 """base class for SQL elements that can be compiled to produce a 

236 SQL string. 

237 

238 .. versionadded:: 2.0 

239 

240 """ 

241 

242 __slots__ = () 

243 __visit_name__ = "compiler_element" 

244 

245 supports_execution = False 

246 

247 stringify_dialect = "default" 

248 

249 @util.preload_module("sqlalchemy.engine.default") 

250 @util.preload_module("sqlalchemy.engine.url") 

251 def compile( 

252 self, 

253 bind: Optional[_HasDialect] = None, 

254 dialect: Optional[Dialect] = None, 

255 **kw: Any, 

256 ) -> Compiled: 

257 """Compile this SQL expression. 

258 

259 The return value is a :class:`~.Compiled` object. 

260 Calling ``str()`` or ``unicode()`` on the returned value will yield a 

261 string representation of the result. The 

262 :class:`~.Compiled` object also can return a 

263 dictionary of bind parameter names and values 

264 using the ``params`` accessor. 

265 

266 :param bind: An :class:`.Connection` or :class:`.Engine` which 

267 can provide a :class:`.Dialect` in order to generate a 

268 :class:`.Compiled` object. If the ``bind`` and 

269 ``dialect`` parameters are both omitted, a default SQL compiler 

270 is used. 

271 

272 :param column_keys: Used for INSERT and UPDATE statements, a list of 

273 column names which should be present in the VALUES clause of the 

274 compiled statement. If ``None``, all columns from the target table 

275 object are rendered. 

276 

277 :param dialect: A :class:`.Dialect` instance which can generate 

278 a :class:`.Compiled` object. This argument takes precedence over 

279 the ``bind`` argument. 

280 

281 :param compile_kwargs: optional dictionary of additional parameters 

282 that will be passed through to the compiler within all "visit" 

283 methods. This allows any custom flag to be passed through to 

284 a custom compilation construct, for example. It is also used 

285 for the case of passing the ``literal_binds`` flag through:: 

286 

287 from sqlalchemy.sql import table, column, select 

288 

289 t = table("t", column("x")) 

290 

291 s = select(t).where(t.c.x == 5) 

292 

293 print(s.compile(compile_kwargs={"literal_binds": True})) 

294 

295 .. seealso:: 

296 

297 :ref:`faq_sql_expression_string` 

298 

299 """ 

300 

301 if dialect is None: 

302 if bind: 

303 dialect = bind.dialect 

304 elif self.stringify_dialect == "default": 

305 dialect = self._default_dialect() 

306 else: 

307 url = util.preloaded.engine_url 

308 dialect = url.URL.create( 

309 self.stringify_dialect 

310 ).get_dialect()() 

311 

312 return self._compiler(dialect, **kw) 

313 

314 def _default_dialect(self): 

315 default = util.preloaded.engine_default 

316 return default.StrCompileDialect() 

317 

318 def _compiler(self, dialect: Dialect, **kw: Any) -> Compiled: 

319 """Return a compiler appropriate for this ClauseElement, given a 

320 Dialect.""" 

321 

322 if TYPE_CHECKING: 

323 assert isinstance(self, ClauseElement) 

324 return dialect.statement_compiler(dialect, self, **kw) 

325 

326 def __str__(self) -> str: 

327 return str(self.compile()) 

328 

329 

330@inspection._self_inspects 

331class ClauseElement( 

332 SupportsWrappingAnnotations, 

333 MemoizedHasCacheKey, 

334 HasCopyInternals, 

335 ExternallyTraversible, 

336 CompilerElement, 

337): 

338 """Base class for elements of a programmatically constructed SQL 

339 expression. 

340 

341 """ 

342 

343 __visit_name__ = "clause" 

344 

345 if TYPE_CHECKING: 

346 

347 @util.memoized_property 

348 def _propagate_attrs(self) -> _PropagateAttrsType: 

349 """like annotations, however these propagate outwards liberally 

350 as SQL constructs are built, and are set up at construction time. 

351 

352 """ 

353 ... 

354 

355 else: 

356 _propagate_attrs = util.EMPTY_DICT 

357 

358 @util.ro_memoized_property 

359 def description(self) -> Optional[str]: 

360 return None 

361 

362 _is_clone_of: Optional[Self] = None 

363 

364 is_clause_element = True 

365 is_selectable = False 

366 is_dml = False 

367 _is_column_element = False 

368 _is_keyed_column_element = False 

369 _is_table = False 

370 _gen_static_annotations_cache_key = False 

371 _is_textual = False 

372 _is_from_clause = False 

373 _is_returns_rows = False 

374 _is_text_clause = False 

375 _is_from_container = False 

376 _is_select_container = False 

377 _is_select_base = False 

378 _is_select_statement = False 

379 _is_bind_parameter = False 

380 _is_clause_list = False 

381 _is_lambda_element = False 

382 _is_singleton_constant = False 

383 _is_immutable = False 

384 _is_star = False 

385 

386 @property 

387 def _order_by_label_element(self) -> Optional[Label[Any]]: 

388 return None 

389 

390 _cache_key_traversal: _CacheKeyTraversalType = None 

391 

392 negation_clause: ColumnElement[bool] 

393 

394 if typing.TYPE_CHECKING: 

395 

396 def get_children( 

397 self, *, omit_attrs: typing_Tuple[str, ...] = ..., **kw: Any 

398 ) -> Iterable[ClauseElement]: ... 

399 

400 @util.ro_non_memoized_property 

401 def _from_objects(self) -> List[FromClause]: 

402 return [] 

403 

404 def _set_propagate_attrs(self, values: Mapping[str, Any]) -> Self: 

405 # usually, self._propagate_attrs is empty here. one case where it's 

406 # not is a subquery against ORM select, that is then pulled as a 

407 # property of an aliased class. should all be good 

408 

409 # assert not self._propagate_attrs 

410 

411 self._propagate_attrs = util.immutabledict(values) 

412 return self 

413 

414 def _default_compiler(self) -> SQLCompiler: 

415 dialect = self._default_dialect() 

416 return dialect.statement_compiler(dialect, self) # type: ignore 

417 

418 def _clone(self, **kw: Any) -> Self: 

419 """Create a shallow copy of this ClauseElement. 

420 

421 This method may be used by a generative API. Its also used as 

422 part of the "deep" copy afforded by a traversal that combines 

423 the _copy_internals() method. 

424 

425 """ 

426 

427 skip = self._memoized_keys 

428 c = self.__class__.__new__(self.__class__) 

429 

430 if skip: 

431 # ensure this iteration remains atomic 

432 c.__dict__ = { 

433 k: v for k, v in self.__dict__.copy().items() if k not in skip 

434 } 

435 else: 

436 c.__dict__ = self.__dict__.copy() 

437 

438 # this is a marker that helps to "equate" clauses to each other 

439 # when a Select returns its list of FROM clauses. the cloning 

440 # process leaves around a lot of remnants of the previous clause 

441 # typically in the form of column expressions still attached to the 

442 # old table. 

443 cc = self._is_clone_of 

444 c._is_clone_of = cc if cc is not None else self 

445 return c 

446 

447 def _negate_in_binary(self, negated_op, original_op): 

448 """a hook to allow the right side of a binary expression to respond 

449 to a negation of the binary expression. 

450 

451 Used for the special case of expanding bind parameter with IN. 

452 

453 """ 

454 return self 

455 

456 def _with_binary_element_type(self, type_): 

457 """in the context of binary expression, convert the type of this 

458 object to the one given. 

459 

460 applies only to :class:`_expression.ColumnElement` classes. 

461 

462 """ 

463 return self 

464 

465 @property 

466 def _constructor(self): # type: ignore[override] 

467 """return the 'constructor' for this ClauseElement. 

468 

469 This is for the purposes for creating a new object of 

470 this type. Usually, its just the element's __class__. 

471 However, the "Annotated" version of the object overrides 

472 to return the class of its proxied element. 

473 

474 """ 

475 return self.__class__ 

476 

477 @HasMemoized.memoized_attribute 

478 def _cloned_set(self): 

479 """Return the set consisting all cloned ancestors of this 

480 ClauseElement. 

481 

482 Includes this ClauseElement. This accessor tends to be used for 

483 FromClause objects to identify 'equivalent' FROM clauses, regardless 

484 of transformative operations. 

485 

486 """ 

487 s = util.column_set() 

488 f: Optional[ClauseElement] = self 

489 

490 # note this creates a cycle, asserted in test_memusage. however, 

491 # turning this into a plain @property adds tends of thousands of method 

492 # calls to Core / ORM performance tests, so the small overhead 

493 # introduced by the relatively small amount of short term cycles 

494 # produced here is preferable 

495 while f is not None: 

496 s.add(f) 

497 f = f._is_clone_of 

498 return s 

499 

500 def _de_clone(self): 

501 while self._is_clone_of is not None: 

502 self = self._is_clone_of 

503 return self 

504 

505 @util.ro_non_memoized_property 

506 def entity_namespace(self) -> _EntityNamespace: 

507 raise AttributeError( 

508 "This SQL expression has no entity namespace " 

509 "with which to filter from." 

510 ) 

511 

512 def __getstate__(self): 

513 d = self.__dict__.copy() 

514 d.pop("_is_clone_of", None) 

515 d.pop("_generate_cache_key", None) 

516 return d 

517 

518 def _execute_on_connection( 

519 self, 

520 connection: Connection, 

521 distilled_params: _CoreMultiExecuteParams, 

522 execution_options: CoreExecuteOptionsParameter, 

523 ) -> Result[Any]: 

524 if self.supports_execution: 

525 if TYPE_CHECKING: 

526 assert isinstance(self, Executable) 

527 return connection._execute_clauseelement( 

528 self, distilled_params, execution_options 

529 ) 

530 else: 

531 raise exc.ObjectNotExecutableError(self) 

532 

533 def _execute_on_scalar( 

534 self, 

535 connection: Connection, 

536 distilled_params: _CoreMultiExecuteParams, 

537 execution_options: CoreExecuteOptionsParameter, 

538 ) -> Any: 

539 """an additional hook for subclasses to provide a different 

540 implementation for connection.scalar() vs. connection.execute(). 

541 

542 .. versionadded:: 2.0 

543 

544 """ 

545 return self._execute_on_connection( 

546 connection, distilled_params, execution_options 

547 ).scalar() 

548 

549 def _get_embedded_bindparams(self) -> Sequence[BindParameter[Any]]: 

550 """Return the list of :class:`.BindParameter` objects embedded in the 

551 object. 

552 

553 This accomplishes the same purpose as ``visitors.traverse()`` or 

554 similar would provide, however by making use of the cache key 

555 it takes advantage of memoization of the key to result in fewer 

556 net method calls, assuming the statement is also going to be 

557 executed. 

558 

559 """ 

560 

561 key = self._generate_cache_key() 

562 if key is None: 

563 bindparams: List[BindParameter[Any]] = [] 

564 

565 traverse(self, {}, {"bindparam": bindparams.append}) 

566 return bindparams 

567 

568 else: 

569 return key.bindparams 

570 

571 def unique_params( 

572 self, 

573 __optionaldict: Optional[Dict[str, Any]] = None, 

574 **kwargs: Any, 

575 ) -> Self: 

576 """Return a copy with :func:`_expression.bindparam` elements 

577 replaced. 

578 

579 Same functionality as :meth:`_expression.ClauseElement.params`, 

580 except adds `unique=True` 

581 to affected bind parameters so that multiple statements can be 

582 used. 

583 

584 """ 

585 return self._replace_params(True, __optionaldict, kwargs) 

586 

587 def params( 

588 self, 

589 __optionaldict: Optional[Mapping[str, Any]] = None, 

590 **kwargs: Any, 

591 ) -> Self: 

592 """Return a copy with :func:`_expression.bindparam` elements 

593 replaced. 

594 

595 Returns a copy of this ClauseElement with 

596 :func:`_expression.bindparam` 

597 elements replaced with values taken from the given dictionary:: 

598 

599 >>> clause = column("x") + bindparam("foo") 

600 >>> print(clause.compile().params) 

601 {'foo':None} 

602 >>> print(clause.params({"foo": 7}).compile().params) 

603 {'foo':7} 

604 

605 """ 

606 return self._replace_params(False, __optionaldict, kwargs) 

607 

608 def _replace_params( 

609 self, 

610 unique: bool, 

611 optionaldict: Optional[Mapping[str, Any]], 

612 kwargs: Dict[str, Any], 

613 ) -> Self: 

614 if optionaldict: 

615 kwargs.update(optionaldict) 

616 

617 def visit_bindparam(bind: BindParameter[Any]) -> None: 

618 if bind.key in kwargs: 

619 bind.value = kwargs[bind.key] 

620 bind.required = False 

621 if unique: 

622 bind._convert_to_unique() 

623 

624 return cloned_traverse( 

625 self, 

626 {"maintain_key": True, "detect_subquery_cols": True}, 

627 {"bindparam": visit_bindparam}, 

628 ) 

629 

630 def compare(self, other: ClauseElement, **kw: Any) -> bool: 

631 r"""Compare this :class:`_expression.ClauseElement` to 

632 the given :class:`_expression.ClauseElement`. 

633 

634 Subclasses should override the default behavior, which is a 

635 straight identity comparison. 

636 

637 \**kw are arguments consumed by subclass ``compare()`` methods and 

638 may be used to modify the criteria for comparison 

639 (see :class:`_expression.ColumnElement`). 

640 

641 """ 

642 return traversals.compare(self, other, **kw) 

643 

644 def self_group( 

645 self, against: Optional[OperatorType] = None 

646 ) -> ClauseElement: 

647 """Apply a 'grouping' to this :class:`_expression.ClauseElement`. 

648 

649 This method is overridden by subclasses to return a "grouping" 

650 construct, i.e. parenthesis. In particular it's used by "binary" 

651 expressions to provide a grouping around themselves when placed into a 

652 larger expression, as well as by :func:`_expression.select` 

653 constructs when placed into the FROM clause of another 

654 :func:`_expression.select`. (Note that subqueries should be 

655 normally created using the :meth:`_expression.Select.alias` method, 

656 as many 

657 platforms require nested SELECT statements to be named). 

658 

659 As expressions are composed together, the application of 

660 :meth:`self_group` is automatic - end-user code should never 

661 need to use this method directly. Note that SQLAlchemy's 

662 clause constructs take operator precedence into account - 

663 so parenthesis might not be needed, for example, in 

664 an expression like ``x OR (y AND z)`` - AND takes precedence 

665 over OR. 

666 

667 The base :meth:`self_group` method of 

668 :class:`_expression.ClauseElement` 

669 just returns self. 

670 """ 

671 return self 

672 

673 def _ungroup(self) -> ClauseElement: 

674 """Return this :class:`_expression.ClauseElement` 

675 without any groupings. 

676 """ 

677 

678 return self 

679 

680 def _compile_w_cache( 

681 self, 

682 dialect: Dialect, 

683 *, 

684 compiled_cache: Optional[CompiledCacheType], 

685 column_keys: List[str], 

686 for_executemany: bool = False, 

687 schema_translate_map: Optional[SchemaTranslateMapType] = None, 

688 **kw: Any, 

689 ) -> typing_Tuple[ 

690 Compiled, Optional[Sequence[BindParameter[Any]]], CacheStats 

691 ]: 

692 elem_cache_key: Optional[CacheKey] 

693 

694 if compiled_cache is not None and dialect._supports_statement_cache: 

695 elem_cache_key = self._generate_cache_key() 

696 else: 

697 elem_cache_key = None 

698 

699 extracted_params: Optional[Sequence[BindParameter[Any]]] 

700 if elem_cache_key is not None: 

701 if TYPE_CHECKING: 

702 assert compiled_cache is not None 

703 

704 cache_key, extracted_params = elem_cache_key 

705 key = ( 

706 dialect, 

707 cache_key, 

708 tuple(column_keys), 

709 bool(schema_translate_map), 

710 for_executemany, 

711 ) 

712 compiled_sql = compiled_cache.get(key) 

713 

714 if compiled_sql is None: 

715 cache_hit = dialect.CACHE_MISS 

716 compiled_sql = self._compiler( 

717 dialect, 

718 cache_key=elem_cache_key, 

719 column_keys=column_keys, 

720 for_executemany=for_executemany, 

721 schema_translate_map=schema_translate_map, 

722 **kw, 

723 ) 

724 compiled_cache[key] = compiled_sql 

725 else: 

726 cache_hit = dialect.CACHE_HIT 

727 else: 

728 extracted_params = None 

729 compiled_sql = self._compiler( 

730 dialect, 

731 cache_key=elem_cache_key, 

732 column_keys=column_keys, 

733 for_executemany=for_executemany, 

734 schema_translate_map=schema_translate_map, 

735 **kw, 

736 ) 

737 

738 if not dialect._supports_statement_cache: 

739 cache_hit = dialect.NO_DIALECT_SUPPORT 

740 elif compiled_cache is None: 

741 cache_hit = dialect.CACHING_DISABLED 

742 else: 

743 cache_hit = dialect.NO_CACHE_KEY 

744 

745 return compiled_sql, extracted_params, cache_hit 

746 

747 def __invert__(self): 

748 # undocumented element currently used by the ORM for 

749 # relationship.contains() 

750 if hasattr(self, "negation_clause"): 

751 return self.negation_clause 

752 else: 

753 return self._negate() 

754 

755 def _negate(self) -> ClauseElement: 

756 # TODO: this code is uncovered and in all likelihood is not included 

757 # in any codepath. So this should raise NotImplementedError in 2.1 

758 grouped = self.self_group(against=operators.inv) 

759 assert isinstance(grouped, ColumnElement) 

760 return UnaryExpression(grouped, operator=operators.inv) 

761 

762 def __bool__(self): 

763 raise TypeError("Boolean value of this clause is not defined") 

764 

765 def __repr__(self): 

766 friendly = self.description 

767 if friendly is None: 

768 return object.__repr__(self) 

769 else: 

770 return "<%s.%s at 0x%x; %s>" % ( 

771 self.__module__, 

772 self.__class__.__name__, 

773 id(self), 

774 friendly, 

775 ) 

776 

777 

778class DQLDMLClauseElement(ClauseElement): 

779 """represents a :class:`.ClauseElement` that compiles to a DQL or DML 

780 expression, not DDL. 

781 

782 .. versionadded:: 2.0 

783 

784 """ 

785 

786 if typing.TYPE_CHECKING: 

787 

788 def _compiler(self, dialect: Dialect, **kw: Any) -> SQLCompiler: 

789 """Return a compiler appropriate for this ClauseElement, given a 

790 Dialect.""" 

791 ... 

792 

793 def compile( # noqa: A001 

794 self, 

795 bind: Optional[_HasDialect] = None, 

796 dialect: Optional[Dialect] = None, 

797 **kw: Any, 

798 ) -> SQLCompiler: ... 

799 

800 

801class CompilerColumnElement( 

802 roles.DMLColumnRole, 

803 roles.DDLConstraintColumnRole, 

804 roles.ColumnsClauseRole, 

805 CompilerElement, 

806): 

807 """A compiler-only column element used for ad-hoc string compilations. 

808 

809 .. versionadded:: 2.0 

810 

811 """ 

812 

813 __slots__ = () 

814 

815 _propagate_attrs = util.EMPTY_DICT 

816 _is_collection_aggregate = False 

817 

818 

819# SQLCoreOperations should be suiting the ExpressionElementRole 

820# and ColumnsClauseRole. however the MRO issues become too elaborate 

821# at the moment. 

822class SQLCoreOperations(Generic[_T_co], ColumnOperators, TypingOnly): 

823 __slots__ = () 

824 

825 # annotations for comparison methods 

826 # these are from operators->Operators / ColumnOperators, 

827 # redefined with the specific types returned by ColumnElement hierarchies 

828 if typing.TYPE_CHECKING: 

829 

830 @util.non_memoized_property 

831 def _propagate_attrs(self) -> _PropagateAttrsType: ... 

832 

833 def operate( 

834 self, op: OperatorType, *other: Any, **kwargs: Any 

835 ) -> ColumnElement[Any]: ... 

836 

837 def reverse_operate( 

838 self, op: OperatorType, other: Any, **kwargs: Any 

839 ) -> ColumnElement[Any]: ... 

840 

841 @overload 

842 def op( 

843 self, 

844 opstring: str, 

845 precedence: int = ..., 

846 is_comparison: bool = ..., 

847 *, 

848 return_type: _TypeEngineArgument[_OPT], 

849 python_impl: Optional[Callable[..., Any]] = None, 

850 ) -> Callable[[Any], BinaryExpression[_OPT]]: ... 

851 

852 @overload 

853 def op( 

854 self, 

855 opstring: str, 

856 precedence: int = ..., 

857 is_comparison: bool = ..., 

858 return_type: Optional[_TypeEngineArgument[Any]] = ..., 

859 python_impl: Optional[Callable[..., Any]] = ..., 

860 ) -> Callable[[Any], BinaryExpression[Any]]: ... 

861 

862 def op( 

863 self, 

864 opstring: str, 

865 precedence: int = 0, 

866 is_comparison: bool = False, 

867 return_type: Optional[_TypeEngineArgument[Any]] = None, 

868 python_impl: Optional[Callable[..., Any]] = None, 

869 ) -> Callable[[Any], BinaryExpression[Any]]: ... 

870 

871 def bool_op( 

872 self, 

873 opstring: str, 

874 precedence: int = 0, 

875 python_impl: Optional[Callable[..., Any]] = None, 

876 ) -> Callable[[Any], BinaryExpression[bool]]: ... 

877 

878 def __and__(self, other: Any) -> BooleanClauseList: ... 

879 

880 def __or__(self, other: Any) -> BooleanClauseList: ... 

881 

882 def __invert__(self) -> ColumnElement[_T_co]: ... 

883 

884 def __lt__(self, other: Any) -> ColumnElement[bool]: ... 

885 

886 def __le__(self, other: Any) -> ColumnElement[bool]: ... 

887 

888 # declare also that this class has an hash method otherwise 

889 # it may be assumed to be None by type checkers since the 

890 # object defines __eq__ and python sets it to None in that case: 

891 # https://docs.python.org/3/reference/datamodel.html#object.__hash__ 

892 def __hash__(self) -> int: ... 

893 

894 def __eq__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 

895 ... 

896 

897 def __ne__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 

898 ... 

899 

900 def is_distinct_from(self, other: Any) -> ColumnElement[bool]: ... 

901 

902 def is_not_distinct_from(self, other: Any) -> ColumnElement[bool]: ... 

903 

904 def __gt__(self, other: Any) -> ColumnElement[bool]: ... 

905 

906 def __ge__(self, other: Any) -> ColumnElement[bool]: ... 

907 

908 def __neg__(self) -> UnaryExpression[_T_co]: ... 

909 

910 def __contains__(self, other: Any) -> ColumnElement[bool]: ... 

911 

912 def __getitem__(self, index: Any) -> ColumnElement[Any]: ... 

913 

914 @overload 

915 def __lshift__(self: _SQO[int], other: Any) -> ColumnElement[int]: ... 

916 

917 @overload 

918 def __lshift__(self, other: Any) -> ColumnElement[Any]: ... 

919 

920 def __lshift__(self, other: Any) -> ColumnElement[Any]: ... 

921 

922 @overload 

923 def __rshift__(self: _SQO[int], other: Any) -> ColumnElement[int]: ... 

924 

925 @overload 

926 def __rshift__(self, other: Any) -> ColumnElement[Any]: ... 

927 

928 def __rshift__(self, other: Any) -> ColumnElement[Any]: ... 

929 

930 @overload 

931 def concat(self: _SQO[str], other: Any) -> ColumnElement[str]: ... 

932 

933 @overload 

934 def concat(self, other: Any) -> ColumnElement[Any]: ... 

935 

936 def concat(self, other: Any) -> ColumnElement[Any]: ... 

937 

938 def like( 

939 self, other: Any, escape: Optional[str] = None 

940 ) -> BinaryExpression[bool]: ... 

941 

942 def ilike( 

943 self, other: Any, escape: Optional[str] = None 

944 ) -> BinaryExpression[bool]: ... 

945 

946 def bitwise_xor(self, other: Any) -> BinaryExpression[Any]: ... 

947 

948 def bitwise_or(self, other: Any) -> BinaryExpression[Any]: ... 

949 

950 def bitwise_and(self, other: Any) -> BinaryExpression[Any]: ... 

951 

952 def bitwise_not(self) -> UnaryExpression[_T_co]: ... 

953 

954 def bitwise_lshift(self, other: Any) -> BinaryExpression[Any]: ... 

955 

956 def bitwise_rshift(self, other: Any) -> BinaryExpression[Any]: ... 

957 

958 def in_( 

959 self, 

960 other: Union[ 

961 Iterable[Any], BindParameter[Any], roles.InElementRole 

962 ], 

963 ) -> BinaryExpression[bool]: ... 

964 

965 def not_in( 

966 self, 

967 other: Union[ 

968 Iterable[Any], BindParameter[Any], roles.InElementRole 

969 ], 

970 ) -> BinaryExpression[bool]: ... 

971 

972 def notin_( 

973 self, 

974 other: Union[ 

975 Iterable[Any], BindParameter[Any], roles.InElementRole 

976 ], 

977 ) -> BinaryExpression[bool]: ... 

978 

979 def not_like( 

980 self, other: Any, escape: Optional[str] = None 

981 ) -> BinaryExpression[bool]: ... 

982 

983 def notlike( 

984 self, other: Any, escape: Optional[str] = None 

985 ) -> BinaryExpression[bool]: ... 

986 

987 def not_ilike( 

988 self, other: Any, escape: Optional[str] = None 

989 ) -> BinaryExpression[bool]: ... 

990 

991 def notilike( 

992 self, other: Any, escape: Optional[str] = None 

993 ) -> BinaryExpression[bool]: ... 

994 

995 def is_(self, other: Any) -> BinaryExpression[bool]: ... 

996 

997 def is_not(self, other: Any) -> BinaryExpression[bool]: ... 

998 

999 def isnot(self, other: Any) -> BinaryExpression[bool]: ... 

1000 

1001 def startswith( 

1002 self, 

1003 other: Any, 

1004 escape: Optional[str] = None, 

1005 autoescape: bool = False, 

1006 ) -> ColumnElement[bool]: ... 

1007 

1008 def istartswith( 

1009 self, 

1010 other: Any, 

1011 escape: Optional[str] = None, 

1012 autoescape: bool = False, 

1013 ) -> ColumnElement[bool]: ... 

1014 

1015 def endswith( 

1016 self, 

1017 other: Any, 

1018 escape: Optional[str] = None, 

1019 autoescape: bool = False, 

1020 ) -> ColumnElement[bool]: ... 

1021 

1022 def iendswith( 

1023 self, 

1024 other: Any, 

1025 escape: Optional[str] = None, 

1026 autoescape: bool = False, 

1027 ) -> ColumnElement[bool]: ... 

1028 

1029 def contains(self, other: Any, **kw: Any) -> ColumnElement[bool]: ... 

1030 

1031 def icontains(self, other: Any, **kw: Any) -> ColumnElement[bool]: ... 

1032 

1033 def match(self, other: Any, **kwargs: Any) -> ColumnElement[bool]: ... 

1034 

1035 def regexp_match( 

1036 self, pattern: Any, flags: Optional[str] = None 

1037 ) -> ColumnElement[bool]: ... 

1038 

1039 def regexp_replace( 

1040 self, pattern: Any, replacement: Any, flags: Optional[str] = None 

1041 ) -> ColumnElement[str]: ... 

1042 

1043 def desc(self) -> UnaryExpression[_T_co]: ... 

1044 

1045 def asc(self) -> UnaryExpression[_T_co]: ... 

1046 

1047 def nulls_first(self) -> UnaryExpression[_T_co]: ... 

1048 

1049 def nullsfirst(self) -> UnaryExpression[_T_co]: ... 

1050 

1051 def nulls_last(self) -> UnaryExpression[_T_co]: ... 

1052 

1053 def nullslast(self) -> UnaryExpression[_T_co]: ... 

1054 

1055 def collate(self, collation: str) -> CollationClause: ... 

1056 

1057 def between( 

1058 self, cleft: Any, cright: Any, symmetric: bool = False 

1059 ) -> BinaryExpression[bool]: ... 

1060 

1061 def distinct(self: _SQO[_T_co]) -> UnaryExpression[_T_co]: ... 

1062 

1063 def any_(self) -> CollectionAggregate[Any]: ... 

1064 

1065 def all_(self) -> CollectionAggregate[Any]: ... 

1066 

1067 # numeric overloads. These need more tweaking 

1068 # in particular they all need to have a variant for Optiona[_T] 

1069 # because Optional only applies to the data side, not the expression 

1070 # side 

1071 

1072 @overload 

1073 def __add__( 

1074 self: _SQO[_NMT], 

1075 other: Any, 

1076 ) -> ColumnElement[_NMT]: ... 

1077 

1078 @overload 

1079 def __add__( 

1080 self: _SQO[str], 

1081 other: Any, 

1082 ) -> ColumnElement[str]: ... 

1083 

1084 @overload 

1085 def __add__(self, other: Any) -> ColumnElement[Any]: ... 

1086 

1087 def __add__(self, other: Any) -> ColumnElement[Any]: ... 

1088 

1089 @overload 

1090 def __radd__(self: _SQO[_NMT], other: Any) -> ColumnElement[_NMT]: ... 

1091 

1092 @overload 

1093 def __radd__(self: _SQO[str], other: Any) -> ColumnElement[str]: ... 

1094 

1095 def __radd__(self, other: Any) -> ColumnElement[Any]: ... 

1096 

1097 @overload 

1098 def __sub__( 

1099 self: _SQO[_NMT], 

1100 other: Any, 

1101 ) -> ColumnElement[_NMT]: ... 

1102 

1103 @overload 

1104 def __sub__(self, other: Any) -> ColumnElement[Any]: ... 

1105 

1106 def __sub__(self, other: Any) -> ColumnElement[Any]: ... 

1107 

1108 @overload 

1109 def __rsub__( 

1110 self: _SQO[_NMT], 

1111 other: Any, 

1112 ) -> ColumnElement[_NMT]: ... 

1113 

1114 @overload 

1115 def __rsub__(self, other: Any) -> ColumnElement[Any]: ... 

1116 

1117 def __rsub__(self, other: Any) -> ColumnElement[Any]: ... 

1118 

1119 @overload 

1120 def __mul__( 

1121 self: _SQO[_NMT], 

1122 other: Any, 

1123 ) -> ColumnElement[_NMT]: ... 

1124 

1125 @overload 

1126 def __mul__(self, other: Any) -> ColumnElement[Any]: ... 

1127 

1128 def __mul__(self, other: Any) -> ColumnElement[Any]: ... 

1129 

1130 @overload 

1131 def __rmul__( 

1132 self: _SQO[_NMT], 

1133 other: Any, 

1134 ) -> ColumnElement[_NMT]: ... 

1135 

1136 @overload 

1137 def __rmul__(self, other: Any) -> ColumnElement[Any]: ... 

1138 

1139 def __rmul__(self, other: Any) -> ColumnElement[Any]: ... 

1140 

1141 @overload 

1142 def __mod__(self: _SQO[_NMT], other: Any) -> ColumnElement[_NMT]: ... 

1143 

1144 @overload 

1145 def __mod__(self, other: Any) -> ColumnElement[Any]: ... 

1146 

1147 def __mod__(self, other: Any) -> ColumnElement[Any]: ... 

1148 

1149 @overload 

1150 def __rmod__(self: _SQO[_NMT], other: Any) -> ColumnElement[_NMT]: ... 

1151 

1152 @overload 

1153 def __rmod__(self, other: Any) -> ColumnElement[Any]: ... 

1154 

1155 def __rmod__(self, other: Any) -> ColumnElement[Any]: ... 

1156 

1157 @overload 

1158 def __truediv__( 

1159 self: _SQO[int], other: Any 

1160 ) -> ColumnElement[_NUMERIC]: ... 

1161 

1162 @overload 

1163 def __truediv__(self: _SQO[_NT], other: Any) -> ColumnElement[_NT]: ... 

1164 

1165 @overload 

1166 def __truediv__(self, other: Any) -> ColumnElement[Any]: ... 

1167 

1168 def __truediv__(self, other: Any) -> ColumnElement[Any]: ... 

1169 

1170 @overload 

1171 def __rtruediv__( 

1172 self: _SQO[_NMT], other: Any 

1173 ) -> ColumnElement[_NUMERIC]: ... 

1174 

1175 @overload 

1176 def __rtruediv__(self, other: Any) -> ColumnElement[Any]: ... 

1177 

1178 def __rtruediv__(self, other: Any) -> ColumnElement[Any]: ... 

1179 

1180 @overload 

1181 def __floordiv__( 

1182 self: _SQO[_NMT], other: Any 

1183 ) -> ColumnElement[_NMT]: ... 

1184 

1185 @overload 

1186 def __floordiv__(self, other: Any) -> ColumnElement[Any]: ... 

1187 

1188 def __floordiv__(self, other: Any) -> ColumnElement[Any]: ... 

1189 

1190 @overload 

1191 def __rfloordiv__( 

1192 self: _SQO[_NMT], other: Any 

1193 ) -> ColumnElement[_NMT]: ... 

1194 

1195 @overload 

1196 def __rfloordiv__(self, other: Any) -> ColumnElement[Any]: ... 

1197 

1198 def __rfloordiv__(self, other: Any) -> ColumnElement[Any]: ... 

1199 

1200 

1201class SQLColumnExpression( 

1202 SQLCoreOperations[_T_co], roles.ExpressionElementRole[_T_co], TypingOnly 

1203): 

1204 """A type that may be used to indicate any SQL column element or object 

1205 that acts in place of one. 

1206 

1207 :class:`.SQLColumnExpression` is a base of 

1208 :class:`.ColumnElement`, as well as within the bases of ORM elements 

1209 such as :class:`.InstrumentedAttribute`, and may be used in :pep:`484` 

1210 typing to indicate arguments or return values that should behave 

1211 as column expressions. 

1212 

1213 .. versionadded:: 2.0.0b4 

1214 

1215 

1216 """ 

1217 

1218 __slots__ = () 

1219 

1220 

1221_SQO = SQLCoreOperations 

1222 

1223 

1224class ColumnElement( 

1225 roles.ColumnArgumentOrKeyRole, 

1226 roles.StatementOptionRole, 

1227 roles.WhereHavingRole, 

1228 roles.BinaryElementRole[_T], 

1229 roles.OrderByRole, 

1230 roles.ColumnsClauseRole, 

1231 roles.LimitOffsetRole, 

1232 roles.DMLColumnRole, 

1233 roles.DDLConstraintColumnRole, 

1234 roles.DDLExpressionRole, 

1235 SQLColumnExpression[_T], 

1236 DQLDMLClauseElement, 

1237): 

1238 """Represent a column-oriented SQL expression suitable for usage in the 

1239 "columns" clause, WHERE clause etc. of a statement. 

1240 

1241 While the most familiar kind of :class:`_expression.ColumnElement` is the 

1242 :class:`_schema.Column` object, :class:`_expression.ColumnElement` 

1243 serves as the basis 

1244 for any unit that may be present in a SQL expression, including 

1245 the expressions themselves, SQL functions, bound parameters, 

1246 literal expressions, keywords such as ``NULL``, etc. 

1247 :class:`_expression.ColumnElement` 

1248 is the ultimate base class for all such elements. 

1249 

1250 A wide variety of SQLAlchemy Core functions work at the SQL expression 

1251 level, and are intended to accept instances of 

1252 :class:`_expression.ColumnElement` as 

1253 arguments. These functions will typically document that they accept a 

1254 "SQL expression" as an argument. What this means in terms of SQLAlchemy 

1255 usually refers to an input which is either already in the form of a 

1256 :class:`_expression.ColumnElement` object, 

1257 or a value which can be **coerced** into 

1258 one. The coercion rules followed by most, but not all, SQLAlchemy Core 

1259 functions with regards to SQL expressions are as follows: 

1260 

1261 * a literal Python value, such as a string, integer or floating 

1262 point value, boolean, datetime, ``Decimal`` object, or virtually 

1263 any other Python object, will be coerced into a "literal bound 

1264 value". This generally means that a :func:`.bindparam` will be 

1265 produced featuring the given value embedded into the construct; the 

1266 resulting :class:`.BindParameter` object is an instance of 

1267 :class:`_expression.ColumnElement`. 

1268 The Python value will ultimately be sent 

1269 to the DBAPI at execution time as a parameterized argument to the 

1270 ``execute()`` or ``executemany()`` methods, after SQLAlchemy 

1271 type-specific converters (e.g. those provided by any associated 

1272 :class:`.TypeEngine` objects) are applied to the value. 

1273 

1274 * any special object value, typically ORM-level constructs, which 

1275 feature an accessor called ``__clause_element__()``. The Core 

1276 expression system looks for this method when an object of otherwise 

1277 unknown type is passed to a function that is looking to coerce the 

1278 argument into a :class:`_expression.ColumnElement` and sometimes a 

1279 :class:`_expression.SelectBase` expression. 

1280 It is used within the ORM to 

1281 convert from ORM-specific objects like mapped classes and 

1282 mapped attributes into Core expression objects. 

1283 

1284 * The Python ``None`` value is typically interpreted as ``NULL``, 

1285 which in SQLAlchemy Core produces an instance of :func:`.null`. 

1286 

1287 A :class:`_expression.ColumnElement` provides the ability to generate new 

1288 :class:`_expression.ColumnElement` 

1289 objects using Python expressions. This means that Python operators 

1290 such as ``==``, ``!=`` and ``<`` are overloaded to mimic SQL operations, 

1291 and allow the instantiation of further :class:`_expression.ColumnElement` 

1292 instances 

1293 which are composed from other, more fundamental 

1294 :class:`_expression.ColumnElement` 

1295 objects. For example, two :class:`.ColumnClause` objects can be added 

1296 together with the addition operator ``+`` to produce 

1297 a :class:`.BinaryExpression`. 

1298 Both :class:`.ColumnClause` and :class:`.BinaryExpression` are subclasses 

1299 of :class:`_expression.ColumnElement`: 

1300 

1301 .. sourcecode:: pycon+sql 

1302 

1303 >>> from sqlalchemy.sql import column 

1304 >>> column("a") + column("b") 

1305 <sqlalchemy.sql.expression.BinaryExpression object at 0x101029dd0> 

1306 >>> print(column("a") + column("b")) 

1307 {printsql}a + b 

1308 

1309 .. seealso:: 

1310 

1311 :class:`_schema.Column` 

1312 

1313 :func:`_expression.column` 

1314 

1315 """ 

1316 

1317 __visit_name__ = "column_element" 

1318 

1319 primary_key: bool = False 

1320 _is_clone_of: Optional[ColumnElement[_T]] 

1321 _is_column_element = True 

1322 _insert_sentinel: bool = False 

1323 _omit_from_statements = False 

1324 _is_collection_aggregate = False 

1325 

1326 foreign_keys: AbstractSet[ForeignKey] = frozenset() 

1327 

1328 @util.memoized_property 

1329 def _proxies(self) -> List[ColumnElement[Any]]: 

1330 return [] 

1331 

1332 @util.non_memoized_property 

1333 def _tq_label(self) -> Optional[str]: 

1334 """The named label that can be used to target 

1335 this column in a result set in a "table qualified" context. 

1336 

1337 This label is almost always the label used when 

1338 rendering <expr> AS <label> in a SELECT statement when using 

1339 the LABEL_STYLE_TABLENAME_PLUS_COL label style, which is what the 

1340 legacy ORM ``Query`` object uses as well. 

1341 

1342 For a regular Column bound to a Table, this is typically the label 

1343 <tablename>_<columnname>. For other constructs, different rules 

1344 may apply, such as anonymized labels and others. 

1345 

1346 .. versionchanged:: 1.4.21 renamed from ``._label`` 

1347 

1348 """ 

1349 return None 

1350 

1351 key: Optional[str] = None 

1352 """The 'key' that in some circumstances refers to this object in a 

1353 Python namespace. 

1354 

1355 This typically refers to the "key" of the column as present in the 

1356 ``.c`` collection of a selectable, e.g. ``sometable.c["somekey"]`` would 

1357 return a :class:`_schema.Column` with a ``.key`` of "somekey". 

1358 

1359 """ 

1360 

1361 @HasMemoized.memoized_attribute 

1362 def _tq_key_label(self) -> Optional[str]: 

1363 """A label-based version of 'key' that in some circumstances refers 

1364 to this object in a Python namespace. 

1365 

1366 

1367 _tq_key_label comes into play when a select() statement is constructed 

1368 with apply_labels(); in this case, all Column objects in the ``.c`` 

1369 collection are rendered as <tablename>_<columnname> in SQL; this is 

1370 essentially the value of ._label. But to locate those columns in the 

1371 ``.c`` collection, the name is along the lines of <tablename>_<key>; 

1372 that's the typical value of .key_label. 

1373 

1374 .. versionchanged:: 1.4.21 renamed from ``._key_label`` 

1375 

1376 """ 

1377 return self._proxy_key 

1378 

1379 @property 

1380 def _key_label(self) -> Optional[str]: 

1381 """legacy; renamed to _tq_key_label""" 

1382 return self._tq_key_label 

1383 

1384 @property 

1385 def _label(self) -> Optional[str]: 

1386 """legacy; renamed to _tq_label""" 

1387 return self._tq_label 

1388 

1389 @property 

1390 def _non_anon_label(self) -> Optional[str]: 

1391 """the 'name' that naturally applies this element when rendered in 

1392 SQL. 

1393 

1394 Concretely, this is the "name" of a column or a label in a 

1395 SELECT statement; ``<columnname>`` and ``<labelname>`` below: 

1396 

1397 .. sourcecode:: sql 

1398 

1399 SELECT <columnmame> FROM table 

1400 

1401 SELECT column AS <labelname> FROM table 

1402 

1403 Above, the two names noted will be what's present in the DBAPI 

1404 ``cursor.description`` as the names. 

1405 

1406 If this attribute returns ``None``, it means that the SQL element as 

1407 written does not have a 100% fully predictable "name" that would appear 

1408 in the ``cursor.description``. Examples include SQL functions, CAST 

1409 functions, etc. While such things do return names in 

1410 ``cursor.description``, they are only predictable on a 

1411 database-specific basis; e.g. an expression like ``MAX(table.col)`` may 

1412 appear as the string ``max`` on one database (like PostgreSQL) or may 

1413 appear as the whole expression ``max(table.col)`` on SQLite. 

1414 

1415 The default implementation looks for a ``.name`` attribute on the 

1416 object, as has been the precedent established in SQLAlchemy for many 

1417 years. An exception is made on the ``FunctionElement`` subclass 

1418 so that the return value is always ``None``. 

1419 

1420 .. versionadded:: 1.4.21 

1421 

1422 

1423 

1424 """ 

1425 return getattr(self, "name", None) 

1426 

1427 _render_label_in_columns_clause = True 

1428 """A flag used by select._columns_plus_names that helps to determine 

1429 we are actually going to render in terms of "SELECT <col> AS <label>". 

1430 This flag can be returned as False for some Column objects that want 

1431 to be rendered as simple "SELECT <col>"; typically columns that don't have 

1432 any parent table and are named the same as what the label would be 

1433 in any case. 

1434 

1435 """ 

1436 

1437 _allow_label_resolve = True 

1438 """A flag that can be flipped to prevent a column from being resolvable 

1439 by string label name. 

1440 

1441 The joined eager loader strategy in the ORM uses this, for example. 

1442 

1443 """ 

1444 

1445 _is_implicitly_boolean = False 

1446 

1447 _alt_names: Sequence[str] = () 

1448 

1449 if TYPE_CHECKING: 

1450 

1451 def _ungroup(self) -> ColumnElement[_T]: ... 

1452 

1453 @overload 

1454 def self_group(self, against: None = None) -> ColumnElement[_T]: ... 

1455 

1456 @overload 

1457 def self_group( 

1458 self, against: Optional[OperatorType] = None 

1459 ) -> ColumnElement[Any]: ... 

1460 

1461 def self_group( 

1462 self, against: Optional[OperatorType] = None 

1463 ) -> ColumnElement[Any]: 

1464 if ( 

1465 against in (operators.and_, operators.or_, operators._asbool) 

1466 and self.type._type_affinity is type_api.BOOLEANTYPE._type_affinity 

1467 ): 

1468 return AsBoolean(self, operators.is_true, operators.is_false) 

1469 elif against in (operators.any_op, operators.all_op): 

1470 return Grouping(self) 

1471 else: 

1472 return self 

1473 

1474 @overload 

1475 def _negate(self: ColumnElement[bool]) -> ColumnElement[bool]: ... 

1476 

1477 @overload 

1478 def _negate(self: ColumnElement[_T]) -> ColumnElement[_T]: ... 

1479 

1480 def _negate(self) -> ColumnElement[Any]: 

1481 if self.type._type_affinity is type_api.BOOLEANTYPE._type_affinity: 

1482 return AsBoolean(self, operators.is_false, operators.is_true) 

1483 else: 

1484 grouped = self.self_group(against=operators.inv) 

1485 assert isinstance(grouped, ColumnElement) 

1486 return UnaryExpression( 

1487 grouped, 

1488 operator=operators.inv, 

1489 ) 

1490 

1491 type: TypeEngine[_T] 

1492 

1493 if not TYPE_CHECKING: 

1494 

1495 @util.memoized_property 

1496 def type(self) -> TypeEngine[_T]: # noqa: A001 

1497 # used for delayed setup of 

1498 # type_api 

1499 return type_api.NULLTYPE 

1500 

1501 @HasMemoized.memoized_attribute 

1502 def comparator(self) -> TypeEngine.Comparator[_T]: 

1503 try: 

1504 comparator_factory = self.type.comparator_factory 

1505 except AttributeError as err: 

1506 raise TypeError( 

1507 "Object %r associated with '.type' attribute " 

1508 "is not a TypeEngine class or object" % self.type 

1509 ) from err 

1510 else: 

1511 return comparator_factory(self) 

1512 

1513 def __setstate__(self, state): 

1514 self.__dict__.update(state) 

1515 

1516 def __getattr__(self, key: str) -> Any: 

1517 try: 

1518 return getattr(self.comparator, key) 

1519 except AttributeError as err: 

1520 raise AttributeError( 

1521 "Neither %r object nor %r object has an attribute %r" 

1522 % ( 

1523 type(self).__name__, 

1524 type(self.comparator).__name__, 

1525 key, 

1526 ) 

1527 ) from err 

1528 

1529 def operate( 

1530 self, 

1531 op: operators.OperatorType, 

1532 *other: Any, 

1533 **kwargs: Any, 

1534 ) -> ColumnElement[Any]: 

1535 return op(self.comparator, *other, **kwargs) # type: ignore[no-any-return] # noqa: E501 

1536 

1537 def reverse_operate( 

1538 self, op: operators.OperatorType, other: Any, **kwargs: Any 

1539 ) -> ColumnElement[Any]: 

1540 return op(other, self.comparator, **kwargs) # type: ignore[no-any-return] # noqa: E501 

1541 

1542 def _bind_param( 

1543 self, 

1544 operator: operators.OperatorType, 

1545 obj: Any, 

1546 type_: Optional[TypeEngine[_T]] = None, 

1547 expanding: bool = False, 

1548 ) -> BindParameter[_T]: 

1549 return BindParameter( 

1550 None, 

1551 obj, 

1552 _compared_to_operator=operator, 

1553 type_=type_, 

1554 _compared_to_type=self.type, 

1555 unique=True, 

1556 expanding=expanding, 

1557 ) 

1558 

1559 @property 

1560 def expression(self) -> ColumnElement[Any]: 

1561 """Return a column expression. 

1562 

1563 Part of the inspection interface; returns self. 

1564 

1565 """ 

1566 return self 

1567 

1568 @property 

1569 def _select_iterable(self) -> _SelectIterable: 

1570 return (self,) 

1571 

1572 @util.memoized_property 

1573 def base_columns(self) -> FrozenSet[ColumnElement[Any]]: 

1574 return frozenset(c for c in self.proxy_set if not c._proxies) 

1575 

1576 @util.memoized_property 

1577 def proxy_set(self) -> FrozenSet[ColumnElement[Any]]: 

1578 """set of all columns we are proxying 

1579 

1580 as of 2.0 this is explicitly deannotated columns. previously it was 

1581 effectively deannotated columns but wasn't enforced. annotated 

1582 columns should basically not go into sets if at all possible because 

1583 their hashing behavior is very non-performant. 

1584 

1585 """ 

1586 return frozenset([self._deannotate()]).union( 

1587 itertools.chain(*[c.proxy_set for c in self._proxies]) 

1588 ) 

1589 

1590 @util.memoized_property 

1591 def _expanded_proxy_set(self) -> FrozenSet[ColumnElement[Any]]: 

1592 return frozenset(_expand_cloned(self.proxy_set)) 

1593 

1594 def _uncached_proxy_list(self) -> List[ColumnElement[Any]]: 

1595 """An 'uncached' version of proxy set. 

1596 

1597 This list includes annotated columns which perform very poorly in 

1598 set operations. 

1599 

1600 """ 

1601 

1602 return [self] + list( 

1603 itertools.chain(*[c._uncached_proxy_list() for c in self._proxies]) 

1604 ) 

1605 

1606 def shares_lineage(self, othercolumn: ColumnElement[Any]) -> bool: 

1607 """Return True if the given :class:`_expression.ColumnElement` 

1608 has a common ancestor to this :class:`_expression.ColumnElement`.""" 

1609 

1610 return bool(self.proxy_set.intersection(othercolumn.proxy_set)) 

1611 

1612 def _compare_name_for_result(self, other: ColumnElement[Any]) -> bool: 

1613 """Return True if the given column element compares to this one 

1614 when targeting within a result row.""" 

1615 

1616 return ( 

1617 hasattr(other, "name") 

1618 and hasattr(self, "name") 

1619 and other.name == self.name 

1620 ) 

1621 

1622 @HasMemoized.memoized_attribute 

1623 def _proxy_key(self) -> Optional[str]: 

1624 if self._annotations and "proxy_key" in self._annotations: 

1625 return cast(str, self._annotations["proxy_key"]) 

1626 

1627 name = self.key 

1628 if not name: 

1629 # there's a bit of a seeming contradiction which is that the 

1630 # "_non_anon_label" of a column can in fact be an 

1631 # "_anonymous_label"; this is when it's on a column that is 

1632 # proxying for an anonymous expression in a subquery. 

1633 name = self._non_anon_label 

1634 

1635 if isinstance(name, _anonymous_label): 

1636 return None 

1637 else: 

1638 return name 

1639 

1640 @HasMemoized.memoized_attribute 

1641 def _expression_label(self) -> Optional[str]: 

1642 """a suggested label to use in the case that the column has no name, 

1643 which should be used if possible as the explicit 'AS <label>' 

1644 where this expression would normally have an anon label. 

1645 

1646 this is essentially mostly what _proxy_key does except it returns 

1647 None if the column has a normal name that can be used. 

1648 

1649 """ 

1650 

1651 if getattr(self, "name", None) is not None: 

1652 return None 

1653 elif self._annotations and "proxy_key" in self._annotations: 

1654 return cast(str, self._annotations["proxy_key"]) 

1655 else: 

1656 return None 

1657 

1658 def _make_proxy( 

1659 self, 

1660 selectable: FromClause, 

1661 *, 

1662 primary_key: ColumnSet, 

1663 foreign_keys: Set[KeyedColumnElement[Any]], 

1664 name: Optional[str] = None, 

1665 key: Optional[str] = None, 

1666 name_is_truncatable: bool = False, 

1667 compound_select_cols: Optional[Sequence[ColumnElement[Any]]] = None, 

1668 **kw: Any, 

1669 ) -> typing_Tuple[str, ColumnClause[_T]]: 

1670 """Create a new :class:`_expression.ColumnElement` representing this 

1671 :class:`_expression.ColumnElement` as it appears in the select list of 

1672 a descending selectable. 

1673 

1674 """ 

1675 if name is None: 

1676 name = self._anon_name_label 

1677 if key is None: 

1678 key = self._proxy_key 

1679 else: 

1680 key = name 

1681 

1682 assert key is not None 

1683 

1684 co: ColumnClause[_T] = ColumnClause( 

1685 ( 

1686 coercions.expect(roles.TruncatedLabelRole, name) 

1687 if name_is_truncatable 

1688 else name 

1689 ), 

1690 type_=getattr(self, "type", None), 

1691 _selectable=selectable, 

1692 ) 

1693 

1694 co._propagate_attrs = selectable._propagate_attrs 

1695 if compound_select_cols: 

1696 co._proxies = list(compound_select_cols) 

1697 else: 

1698 co._proxies = [self] 

1699 if selectable._is_clone_of is not None: 

1700 co._is_clone_of = selectable._is_clone_of.columns.get(key) 

1701 return key, co 

1702 

1703 def cast(self, type_: _TypeEngineArgument[_OPT]) -> Cast[_OPT]: 

1704 """Produce a type cast, i.e. ``CAST(<expression> AS <type>)``. 

1705 

1706 This is a shortcut to the :func:`_expression.cast` function. 

1707 

1708 .. seealso:: 

1709 

1710 :ref:`tutorial_casts` 

1711 

1712 :func:`_expression.cast` 

1713 

1714 :func:`_expression.type_coerce` 

1715 

1716 """ 

1717 return Cast(self, type_) 

1718 

1719 def label(self, name: Optional[str]) -> Label[_T]: 

1720 """Produce a column label, i.e. ``<columnname> AS <name>``. 

1721 

1722 This is a shortcut to the :func:`_expression.label` function. 

1723 

1724 If 'name' is ``None``, an anonymous label name will be generated. 

1725 

1726 """ 

1727 return Label(name, self, self.type) 

1728 

1729 def _anon_label( 

1730 self, seed: Optional[str], add_hash: Optional[int] = None 

1731 ) -> _anonymous_label: 

1732 while self._is_clone_of is not None: 

1733 self = self._is_clone_of 

1734 

1735 # as of 1.4 anonymous label for ColumnElement uses hash(), not id(), 

1736 # as the identifier, because a column and its annotated version are 

1737 # the same thing in a SQL statement 

1738 hash_value = hash(self) 

1739 

1740 if add_hash: 

1741 # this path is used for disambiguating anon labels that would 

1742 # otherwise be the same name for the same element repeated. 

1743 # an additional numeric value is factored in for each label. 

1744 

1745 # shift hash(self) (which is id(self), typically 8 byte integer) 

1746 # 16 bits leftward. fill extra add_hash on right 

1747 assert add_hash < (2 << 15) 

1748 assert seed 

1749 hash_value = (hash_value << 16) | add_hash 

1750 

1751 # extra underscore is added for labels with extra hash 

1752 # values, to isolate the "deduped anon" namespace from the 

1753 # regular namespace. eliminates chance of these 

1754 # manufactured hash values overlapping with regular ones for some 

1755 # undefined python interpreter 

1756 seed = seed + "_" 

1757 

1758 if isinstance(seed, _anonymous_label): 

1759 return _anonymous_label.safe_construct( 

1760 hash_value, "", enclosing_label=seed 

1761 ) 

1762 

1763 return _anonymous_label.safe_construct(hash_value, seed or "anon") 

1764 

1765 @util.memoized_property 

1766 def _anon_name_label(self) -> str: 

1767 """Provides a constant 'anonymous label' for this ColumnElement. 

1768 

1769 This is a label() expression which will be named at compile time. 

1770 The same label() is returned each time ``anon_label`` is called so 

1771 that expressions can reference ``anon_label`` multiple times, 

1772 producing the same label name at compile time. 

1773 

1774 The compiler uses this function automatically at compile time 

1775 for expressions that are known to be 'unnamed' like binary 

1776 expressions and function calls. 

1777 

1778 .. versionchanged:: 1.4.9 - this attribute was not intended to be 

1779 public and is renamed to _anon_name_label. anon_name exists 

1780 for backwards compat 

1781 

1782 """ 

1783 name = getattr(self, "name", None) 

1784 return self._anon_label(name) 

1785 

1786 @util.memoized_property 

1787 def _anon_key_label(self) -> _anonymous_label: 

1788 """Provides a constant 'anonymous key label' for this ColumnElement. 

1789 

1790 Compare to ``anon_label``, except that the "key" of the column, 

1791 if available, is used to generate the label. 

1792 

1793 This is used when a deduplicating key is placed into the columns 

1794 collection of a selectable. 

1795 

1796 .. versionchanged:: 1.4.9 - this attribute was not intended to be 

1797 public and is renamed to _anon_key_label. anon_key_label exists 

1798 for backwards compat 

1799 

1800 """ 

1801 return self._anon_label(self._proxy_key) 

1802 

1803 @property 

1804 @util.deprecated( 

1805 "1.4", 

1806 "The :attr:`_expression.ColumnElement.anon_label` attribute is now " 

1807 "private, and the public accessor is deprecated.", 

1808 ) 

1809 def anon_label(self) -> str: 

1810 return self._anon_name_label 

1811 

1812 @property 

1813 @util.deprecated( 

1814 "1.4", 

1815 "The :attr:`_expression.ColumnElement.anon_key_label` attribute is " 

1816 "now private, and the public accessor is deprecated.", 

1817 ) 

1818 def anon_key_label(self) -> str: 

1819 return self._anon_key_label 

1820 

1821 def _dedupe_anon_label_idx(self, idx: int) -> str: 

1822 """label to apply to a column that is anon labeled, but repeated 

1823 in the SELECT, so that we have to make an "extra anon" label that 

1824 disambiguates it from the previous appearance. 

1825 

1826 these labels come out like "foo_bar_id__1" and have double underscores 

1827 in them. 

1828 

1829 """ 

1830 label = getattr(self, "name", None) 

1831 

1832 # current convention is that if the element doesn't have a 

1833 # ".name" (usually because it is not NamedColumn), we try to 

1834 # use a "table qualified" form for the "dedupe anon" label, 

1835 # based on the notion that a label like 

1836 # "CAST(casttest.v1 AS DECIMAL) AS casttest_v1__1" looks better than 

1837 # "CAST(casttest.v1 AS DECIMAL) AS anon__1" 

1838 

1839 if label is None: 

1840 return self._dedupe_anon_tq_label_idx(idx) 

1841 else: 

1842 return self._anon_label(label, add_hash=idx) 

1843 

1844 @util.memoized_property 

1845 def _anon_tq_label(self) -> _anonymous_label: 

1846 return self._anon_label(getattr(self, "_tq_label", None)) 

1847 

1848 @util.memoized_property 

1849 def _anon_tq_key_label(self) -> _anonymous_label: 

1850 return self._anon_label(getattr(self, "_tq_key_label", None)) 

1851 

1852 def _dedupe_anon_tq_label_idx(self, idx: int) -> _anonymous_label: 

1853 label = getattr(self, "_tq_label", None) or "anon" 

1854 

1855 return self._anon_label(label, add_hash=idx) 

1856 

1857 

1858class KeyedColumnElement(ColumnElement[_T]): 

1859 """ColumnElement where ``.key`` is non-None.""" 

1860 

1861 _is_keyed_column_element = True 

1862 

1863 key: str 

1864 

1865 

1866class WrapsColumnExpression(ColumnElement[_T]): 

1867 """Mixin that defines a :class:`_expression.ColumnElement` 

1868 as a wrapper with special 

1869 labeling behavior for an expression that already has a name. 

1870 

1871 .. versionadded:: 1.4 

1872 

1873 .. seealso:: 

1874 

1875 :ref:`change_4449` 

1876 

1877 

1878 """ 

1879 

1880 @property 

1881 def wrapped_column_expression(self) -> ColumnElement[_T]: 

1882 raise NotImplementedError() 

1883 

1884 @util.non_memoized_property 

1885 def _tq_label(self) -> Optional[str]: 

1886 wce = self.wrapped_column_expression 

1887 if hasattr(wce, "_tq_label"): 

1888 return wce._tq_label 

1889 else: 

1890 return None 

1891 

1892 @property 

1893 def _label(self) -> Optional[str]: 

1894 return self._tq_label 

1895 

1896 @property 

1897 def _non_anon_label(self) -> Optional[str]: 

1898 return None 

1899 

1900 @util.non_memoized_property 

1901 def _anon_name_label(self) -> str: 

1902 wce = self.wrapped_column_expression 

1903 

1904 # this logic tries to get the WrappedColumnExpression to render 

1905 # with "<expr> AS <name>", where "<name>" is the natural name 

1906 # within the expression itself. e.g. "CAST(table.foo) AS foo". 

1907 if not wce._is_text_clause: 

1908 nal = wce._non_anon_label 

1909 if nal: 

1910 return nal 

1911 elif hasattr(wce, "_anon_name_label"): 

1912 return wce._anon_name_label 

1913 return super()._anon_name_label 

1914 

1915 def _dedupe_anon_label_idx(self, idx: int) -> str: 

1916 wce = self.wrapped_column_expression 

1917 nal = wce._non_anon_label 

1918 if nal: 

1919 return self._anon_label(nal + "_") 

1920 else: 

1921 return self._dedupe_anon_tq_label_idx(idx) 

1922 

1923 @property 

1924 def _proxy_key(self): 

1925 wce = self.wrapped_column_expression 

1926 

1927 if not wce._is_text_clause: 

1928 return wce._proxy_key 

1929 return super()._proxy_key 

1930 

1931 

1932class BindParameter(roles.InElementRole, KeyedColumnElement[_T]): 

1933 r"""Represent a "bound expression". 

1934 

1935 :class:`.BindParameter` is invoked explicitly using the 

1936 :func:`.bindparam` function, as in:: 

1937 

1938 from sqlalchemy import bindparam 

1939 

1940 stmt = select(users_table).where( 

1941 users_table.c.name == bindparam("username") 

1942 ) 

1943 

1944 Detailed discussion of how :class:`.BindParameter` is used is 

1945 at :func:`.bindparam`. 

1946 

1947 .. seealso:: 

1948 

1949 :func:`.bindparam` 

1950 

1951 """ 

1952 

1953 __visit_name__ = "bindparam" 

1954 

1955 _traverse_internals: _TraverseInternalsType = [ 

1956 ("key", InternalTraversal.dp_anon_name), 

1957 ("type", InternalTraversal.dp_type), 

1958 ("callable", InternalTraversal.dp_plain_dict), 

1959 ("value", InternalTraversal.dp_plain_obj), 

1960 ("literal_execute", InternalTraversal.dp_boolean), 

1961 ] 

1962 

1963 key: str 

1964 type: TypeEngine[_T] 

1965 value: Optional[_T] 

1966 

1967 _is_crud = False 

1968 _is_bind_parameter = True 

1969 _key_is_anon = False 

1970 

1971 # bindparam implements its own _gen_cache_key() method however 

1972 # we check subclasses for this flag, else no cache key is generated 

1973 inherit_cache = True 

1974 

1975 def __init__( 

1976 self, 

1977 key: Optional[str], 

1978 value: Any = _NoArg.NO_ARG, 

1979 type_: Optional[_TypeEngineArgument[_T]] = None, 

1980 unique: bool = False, 

1981 required: Union[bool, Literal[_NoArg.NO_ARG]] = _NoArg.NO_ARG, 

1982 quote: Optional[bool] = None, 

1983 callable_: Optional[Callable[[], Any]] = None, 

1984 expanding: bool = False, 

1985 isoutparam: bool = False, 

1986 literal_execute: bool = False, 

1987 _compared_to_operator: Optional[OperatorType] = None, 

1988 _compared_to_type: Optional[TypeEngine[Any]] = None, 

1989 _is_crud: bool = False, 

1990 ): 

1991 if required is _NoArg.NO_ARG: 

1992 required = value is _NoArg.NO_ARG and callable_ is None 

1993 if value is _NoArg.NO_ARG: 

1994 value = None 

1995 

1996 if quote is not None: 

1997 key = quoted_name.construct(key, quote) 

1998 

1999 if unique: 

2000 self.key = _anonymous_label.safe_construct( 

2001 id(self), 

2002 ( 

2003 key 

2004 if key is not None 

2005 and not isinstance(key, _anonymous_label) 

2006 else "param" 

2007 ), 

2008 sanitize_key=True, 

2009 ) 

2010 self._key_is_anon = True 

2011 elif key: 

2012 self.key = key 

2013 else: 

2014 self.key = _anonymous_label.safe_construct(id(self), "param") 

2015 self._key_is_anon = True 

2016 

2017 # identifying key that won't change across 

2018 # clones, used to identify the bind's logical 

2019 # identity 

2020 self._identifying_key = self.key 

2021 

2022 # key that was passed in the first place, used to 

2023 # generate new keys 

2024 self._orig_key = key or "param" 

2025 

2026 self.unique = unique 

2027 self.value = value 

2028 self.callable = callable_ 

2029 self.isoutparam = isoutparam 

2030 self.required = required 

2031 

2032 # indicate an "expanding" parameter; the compiler sets this 

2033 # automatically in the compiler _render_in_expr_w_bindparam method 

2034 # for an IN expression 

2035 self.expanding = expanding 

2036 

2037 # this is another hint to help w/ expanding and is typically 

2038 # set in the compiler _render_in_expr_w_bindparam method for an 

2039 # IN expression 

2040 self.expand_op = None 

2041 

2042 self.literal_execute = literal_execute 

2043 if _is_crud: 

2044 self._is_crud = True 

2045 

2046 if type_ is None: 

2047 if expanding: 

2048 if value: 

2049 check_value = value[0] 

2050 else: 

2051 check_value = type_api._NO_VALUE_IN_LIST 

2052 else: 

2053 check_value = value 

2054 if _compared_to_type is not None: 

2055 self.type = _compared_to_type.coerce_compared_value( 

2056 _compared_to_operator, check_value 

2057 ) 

2058 else: 

2059 self.type = type_api._resolve_value_to_type(check_value) 

2060 elif isinstance(type_, type): 

2061 self.type = type_() 

2062 elif is_tuple_type(type_): 

2063 if value: 

2064 if expanding: 

2065 check_value = value[0] 

2066 else: 

2067 check_value = value 

2068 cast("BindParameter[typing_Tuple[Any, ...]]", self).type = ( 

2069 type_._resolve_values_to_types(check_value) 

2070 ) 

2071 else: 

2072 cast("BindParameter[typing_Tuple[Any, ...]]", self).type = ( 

2073 type_ 

2074 ) 

2075 else: 

2076 self.type = type_ 

2077 

2078 def _with_value(self, value, maintain_key=False, required=NO_ARG): 

2079 """Return a copy of this :class:`.BindParameter` with the given value 

2080 set. 

2081 """ 

2082 cloned = self._clone(maintain_key=maintain_key) 

2083 cloned.value = value 

2084 cloned.callable = None 

2085 cloned.required = required if required is not NO_ARG else self.required 

2086 if cloned.type is type_api.NULLTYPE: 

2087 cloned.type = type_api._resolve_value_to_type(value) 

2088 return cloned 

2089 

2090 @property 

2091 def effective_value(self) -> Optional[_T]: 

2092 """Return the value of this bound parameter, 

2093 taking into account if the ``callable`` parameter 

2094 was set. 

2095 

2096 The ``callable`` value will be evaluated 

2097 and returned if present, else ``value``. 

2098 

2099 """ 

2100 if self.callable: 

2101 # TODO: set up protocol for bind parameter callable 

2102 return self.callable() # type: ignore 

2103 else: 

2104 return self.value 

2105 

2106 def render_literal_execute(self) -> BindParameter[_T]: 

2107 """Produce a copy of this bound parameter that will enable the 

2108 :paramref:`_sql.BindParameter.literal_execute` flag. 

2109 

2110 The :paramref:`_sql.BindParameter.literal_execute` flag will 

2111 have the effect of the parameter rendered in the compiled SQL 

2112 string using ``[POSTCOMPILE]`` form, which is a special form that 

2113 is converted to be a rendering of the literal value of the parameter 

2114 at SQL execution time. The rationale is to support caching 

2115 of SQL statement strings that can embed per-statement literal values, 

2116 such as LIMIT and OFFSET parameters, in the final SQL string that 

2117 is passed to the DBAPI. Dialects in particular may want to use 

2118 this method within custom compilation schemes. 

2119 

2120 .. versionadded:: 1.4.5 

2121 

2122 .. seealso:: 

2123 

2124 :ref:`engine_thirdparty_caching` 

2125 

2126 """ 

2127 c = ClauseElement._clone(self) 

2128 c.literal_execute = True 

2129 return c 

2130 

2131 def _negate_in_binary(self, negated_op, original_op): 

2132 if self.expand_op is original_op: 

2133 bind = self._clone() 

2134 bind.expand_op = negated_op 

2135 return bind 

2136 else: 

2137 return self 

2138 

2139 def _with_binary_element_type(self, type_: TypeEngine[Any]) -> Self: 

2140 c: Self = ClauseElement._clone(self) 

2141 c.type = type_ 

2142 return c 

2143 

2144 def _clone(self, maintain_key: bool = False, **kw: Any) -> Self: 

2145 c = ClauseElement._clone(self, **kw) 

2146 # ensure all the BindParameter objects stay in cloned set. 

2147 # in #7823, we changed "clone" so that a clone only keeps a reference 

2148 # to the "original" element, since for column correspondence, that's 

2149 # all we need. However, for BindParam, _cloned_set is used by 

2150 # the "cache key bind match" lookup, which means if any of those 

2151 # interim BindParameter objects became part of a cache key in the 

2152 # cache, we need it. So here, make sure all clones keep carrying 

2153 # forward. 

2154 c._cloned_set.update(self._cloned_set) 

2155 if not maintain_key and self.unique: 

2156 c.key = _anonymous_label.safe_construct( 

2157 id(c), c._orig_key or "param", sanitize_key=True 

2158 ) 

2159 return c 

2160 

2161 def _gen_cache_key(self, anon_map, bindparams): 

2162 _gen_cache_ok = self.__class__.__dict__.get("inherit_cache", False) 

2163 

2164 if not _gen_cache_ok: 

2165 if anon_map is not None: 

2166 anon_map[NO_CACHE] = True 

2167 return None 

2168 

2169 id_, found = anon_map.get_anon(self) 

2170 if found: 

2171 return (id_, self.__class__) 

2172 

2173 if bindparams is not None: 

2174 bindparams.append(self) 

2175 

2176 return ( 

2177 id_, 

2178 self.__class__, 

2179 self.type._static_cache_key, 

2180 self.key % anon_map if self._key_is_anon else self.key, 

2181 self.literal_execute, 

2182 ) 

2183 

2184 def _convert_to_unique(self): 

2185 if not self.unique: 

2186 self.unique = True 

2187 self.key = _anonymous_label.safe_construct( 

2188 id(self), self._orig_key or "param", sanitize_key=True 

2189 ) 

2190 

2191 def __getstate__(self): 

2192 """execute a deferred value for serialization purposes.""" 

2193 

2194 d = self.__dict__.copy() 

2195 v = self.value 

2196 if self.callable: 

2197 v = self.callable() 

2198 d["callable"] = None 

2199 d["value"] = v 

2200 return d 

2201 

2202 def __setstate__(self, state): 

2203 if state.get("unique", False): 

2204 state["key"] = _anonymous_label.safe_construct( 

2205 id(self), state.get("_orig_key", "param"), sanitize_key=True 

2206 ) 

2207 self.__dict__.update(state) 

2208 

2209 def __repr__(self): 

2210 return "%s(%r, %r, type_=%r)" % ( 

2211 self.__class__.__name__, 

2212 self.key, 

2213 self.value, 

2214 self.type, 

2215 ) 

2216 

2217 

2218class TypeClause(DQLDMLClauseElement): 

2219 """Handle a type keyword in a SQL statement. 

2220 

2221 Used by the ``Case`` statement. 

2222 

2223 """ 

2224 

2225 __visit_name__ = "typeclause" 

2226 

2227 _traverse_internals: _TraverseInternalsType = [ 

2228 ("type", InternalTraversal.dp_type) 

2229 ] 

2230 type: TypeEngine[Any] 

2231 

2232 def __init__(self, type_: TypeEngine[Any]): 

2233 self.type = type_ 

2234 

2235 

2236class TextClause( 

2237 roles.DDLConstraintColumnRole, 

2238 roles.DDLExpressionRole, 

2239 roles.StatementOptionRole, 

2240 roles.WhereHavingRole, 

2241 roles.OrderByRole, 

2242 roles.FromClauseRole, 

2243 roles.SelectStatementRole, 

2244 roles.InElementRole, 

2245 Generative, 

2246 Executable, 

2247 DQLDMLClauseElement, 

2248 roles.BinaryElementRole[Any], 

2249 inspection.Inspectable["TextClause"], 

2250): 

2251 """Represent a literal SQL text fragment. 

2252 

2253 E.g.:: 

2254 

2255 from sqlalchemy import text 

2256 

2257 t = text("SELECT * FROM users") 

2258 result = connection.execute(t) 

2259 

2260 The :class:`_expression.TextClause` construct is produced using the 

2261 :func:`_expression.text` 

2262 function; see that function for full documentation. 

2263 

2264 .. seealso:: 

2265 

2266 :func:`_expression.text` 

2267 

2268 """ 

2269 

2270 __visit_name__ = "textclause" 

2271 

2272 _traverse_internals: _TraverseInternalsType = [ 

2273 ("_bindparams", InternalTraversal.dp_string_clauseelement_dict), 

2274 ("text", InternalTraversal.dp_string), 

2275 ] + Executable._executable_traverse_internals 

2276 

2277 _is_text_clause = True 

2278 

2279 _is_textual = True 

2280 

2281 _bind_params_regex = re.compile(r"(?<![:\w\x5c]):(\w+)(?!:)", re.UNICODE) 

2282 _is_implicitly_boolean = False 

2283 

2284 _render_label_in_columns_clause = False 

2285 

2286 _omit_from_statements = False 

2287 

2288 _is_collection_aggregate = False 

2289 

2290 @property 

2291 def _hide_froms(self) -> Iterable[FromClause]: 

2292 return () 

2293 

2294 def __and__(self, other): 

2295 # support use in select.where(), query.filter() 

2296 return and_(self, other) 

2297 

2298 @property 

2299 def _select_iterable(self) -> _SelectIterable: 

2300 return (self,) 

2301 

2302 # help in those cases where text() is 

2303 # interpreted in a column expression situation 

2304 key: Optional[str] = None 

2305 _label: Optional[str] = None 

2306 

2307 _allow_label_resolve = False 

2308 

2309 @property 

2310 def _is_star(self): # type: ignore[override] 

2311 return self.text == "*" 

2312 

2313 def __init__(self, text: str): 

2314 self._bindparams: Dict[str, BindParameter[Any]] = {} 

2315 

2316 def repl(m): 

2317 self._bindparams[m.group(1)] = BindParameter(m.group(1)) 

2318 return ":%s" % m.group(1) 

2319 

2320 # scan the string and search for bind parameter names, add them 

2321 # to the list of bindparams 

2322 self.text = self._bind_params_regex.sub(repl, text) 

2323 

2324 @_generative 

2325 def bindparams( 

2326 self, 

2327 *binds: BindParameter[Any], 

2328 **names_to_values: Any, 

2329 ) -> Self: 

2330 """Establish the values and/or types of bound parameters within 

2331 this :class:`_expression.TextClause` construct. 

2332 

2333 Given a text construct such as:: 

2334 

2335 from sqlalchemy import text 

2336 

2337 stmt = text( 

2338 "SELECT id, name FROM user WHERE name=:name AND timestamp=:timestamp" 

2339 ) 

2340 

2341 the :meth:`_expression.TextClause.bindparams` 

2342 method can be used to establish 

2343 the initial value of ``:name`` and ``:timestamp``, 

2344 using simple keyword arguments:: 

2345 

2346 stmt = stmt.bindparams( 

2347 name="jack", timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5) 

2348 ) 

2349 

2350 Where above, new :class:`.BindParameter` objects 

2351 will be generated with the names ``name`` and ``timestamp``, and 

2352 values of ``jack`` and ``datetime.datetime(2012, 10, 8, 15, 12, 5)``, 

2353 respectively. The types will be 

2354 inferred from the values given, in this case :class:`.String` and 

2355 :class:`.DateTime`. 

2356 

2357 When specific typing behavior is needed, the positional ``*binds`` 

2358 argument can be used in which to specify :func:`.bindparam` constructs 

2359 directly. These constructs must include at least the ``key`` 

2360 argument, then an optional value and type:: 

2361 

2362 from sqlalchemy import bindparam 

2363 

2364 stmt = stmt.bindparams( 

2365 bindparam("name", value="jack", type_=String), 

2366 bindparam("timestamp", type_=DateTime), 

2367 ) 

2368 

2369 Above, we specified the type of :class:`.DateTime` for the 

2370 ``timestamp`` bind, and the type of :class:`.String` for the ``name`` 

2371 bind. In the case of ``name`` we also set the default value of 

2372 ``"jack"``. 

2373 

2374 Additional bound parameters can be supplied at statement execution 

2375 time, e.g.:: 

2376 

2377 result = connection.execute( 

2378 stmt, timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5) 

2379 ) 

2380 

2381 The :meth:`_expression.TextClause.bindparams` 

2382 method can be called repeatedly, 

2383 where it will re-use existing :class:`.BindParameter` objects to add 

2384 new information. For example, we can call 

2385 :meth:`_expression.TextClause.bindparams` 

2386 first with typing information, and a 

2387 second time with value information, and it will be combined:: 

2388 

2389 stmt = text( 

2390 "SELECT id, name FROM user WHERE name=:name " 

2391 "AND timestamp=:timestamp" 

2392 ) 

2393 stmt = stmt.bindparams( 

2394 bindparam("name", type_=String), bindparam("timestamp", type_=DateTime) 

2395 ) 

2396 stmt = stmt.bindparams( 

2397 name="jack", timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5) 

2398 ) 

2399 

2400 The :meth:`_expression.TextClause.bindparams` 

2401 method also supports the concept of 

2402 **unique** bound parameters. These are parameters that are 

2403 "uniquified" on name at statement compilation time, so that multiple 

2404 :func:`_expression.text` 

2405 constructs may be combined together without the names 

2406 conflicting. To use this feature, specify the 

2407 :paramref:`.BindParameter.unique` flag on each :func:`.bindparam` 

2408 object:: 

2409 

2410 stmt1 = text("select id from table where name=:name").bindparams( 

2411 bindparam("name", value="name1", unique=True) 

2412 ) 

2413 stmt2 = text("select id from table where name=:name").bindparams( 

2414 bindparam("name", value="name2", unique=True) 

2415 ) 

2416 

2417 union = union_all(stmt1.columns(column("id")), stmt2.columns(column("id"))) 

2418 

2419 The above statement will render as: 

2420 

2421 .. sourcecode:: sql 

2422 

2423 select id from table where name=:name_1 

2424 UNION ALL select id from table where name=:name_2 

2425 

2426 .. versionadded:: 1.3.11 Added support for the 

2427 :paramref:`.BindParameter.unique` flag to work with 

2428 :func:`_expression.text` 

2429 constructs. 

2430 

2431 """ # noqa: E501 

2432 self._bindparams = new_params = self._bindparams.copy() 

2433 

2434 for bind in binds: 

2435 try: 

2436 # the regex used for text() currently will not match 

2437 # a unique/anonymous key in any case, so use the _orig_key 

2438 # so that a text() construct can support unique parameters 

2439 existing = new_params[bind._orig_key] 

2440 except KeyError as err: 

2441 raise exc.ArgumentError( 

2442 "This text() construct doesn't define a " 

2443 "bound parameter named %r" % bind._orig_key 

2444 ) from err 

2445 else: 

2446 new_params[existing._orig_key] = bind 

2447 

2448 for key, value in names_to_values.items(): 

2449 try: 

2450 existing = new_params[key] 

2451 except KeyError as err: 

2452 raise exc.ArgumentError( 

2453 "This text() construct doesn't define a " 

2454 "bound parameter named %r" % key 

2455 ) from err 

2456 else: 

2457 new_params[key] = existing._with_value(value, required=False) 

2458 return self 

2459 

2460 @util.preload_module("sqlalchemy.sql.selectable") 

2461 def columns( 

2462 self, 

2463 *cols: _OnlyColumnArgument[Any], 

2464 **types: _TypeEngineArgument[Any], 

2465 ) -> TextualSelect: 

2466 r"""Turn this :class:`_expression.TextClause` object into a 

2467 :class:`_expression.TextualSelect` 

2468 object that serves the same role as a SELECT 

2469 statement. 

2470 

2471 The :class:`_expression.TextualSelect` is part of the 

2472 :class:`_expression.SelectBase` 

2473 hierarchy and can be embedded into another statement by using the 

2474 :meth:`_expression.TextualSelect.subquery` method to produce a 

2475 :class:`.Subquery` 

2476 object, which can then be SELECTed from. 

2477 

2478 This function essentially bridges the gap between an entirely 

2479 textual SELECT statement and the SQL expression language concept 

2480 of a "selectable":: 

2481 

2482 from sqlalchemy.sql import column, text 

2483 

2484 stmt = text("SELECT id, name FROM some_table") 

2485 stmt = stmt.columns(column("id"), column("name")).subquery("st") 

2486 

2487 stmt = ( 

2488 select(mytable) 

2489 .select_from(mytable.join(stmt, mytable.c.name == stmt.c.name)) 

2490 .where(stmt.c.id > 5) 

2491 ) 

2492 

2493 Above, we pass a series of :func:`_expression.column` elements to the 

2494 :meth:`_expression.TextClause.columns` method positionally. These 

2495 :func:`_expression.column` 

2496 elements now become first class elements upon the 

2497 :attr:`_expression.TextualSelect.selected_columns` column collection, 

2498 which then 

2499 become part of the :attr:`.Subquery.c` collection after 

2500 :meth:`_expression.TextualSelect.subquery` is invoked. 

2501 

2502 The column expressions we pass to 

2503 :meth:`_expression.TextClause.columns` may 

2504 also be typed; when we do so, these :class:`.TypeEngine` objects become 

2505 the effective return type of the column, so that SQLAlchemy's 

2506 result-set-processing systems may be used on the return values. 

2507 This is often needed for types such as date or boolean types, as well 

2508 as for unicode processing on some dialect configurations:: 

2509 

2510 stmt = text("SELECT id, name, timestamp FROM some_table") 

2511 stmt = stmt.columns( 

2512 column("id", Integer), 

2513 column("name", Unicode), 

2514 column("timestamp", DateTime), 

2515 ) 

2516 

2517 for id, name, timestamp in connection.execute(stmt): 

2518 print(id, name, timestamp) 

2519 

2520 As a shortcut to the above syntax, keyword arguments referring to 

2521 types alone may be used, if only type conversion is needed:: 

2522 

2523 stmt = text("SELECT id, name, timestamp FROM some_table") 

2524 stmt = stmt.columns(id=Integer, name=Unicode, timestamp=DateTime) 

2525 

2526 for id, name, timestamp in connection.execute(stmt): 

2527 print(id, name, timestamp) 

2528 

2529 The positional form of :meth:`_expression.TextClause.columns` 

2530 also provides the 

2531 unique feature of **positional column targeting**, which is 

2532 particularly useful when using the ORM with complex textual queries. If 

2533 we specify the columns from our model to 

2534 :meth:`_expression.TextClause.columns`, 

2535 the result set will match to those columns positionally, meaning the 

2536 name or origin of the column in the textual SQL doesn't matter:: 

2537 

2538 stmt = text( 

2539 "SELECT users.id, addresses.id, users.id, " 

2540 "users.name, addresses.email_address AS email " 

2541 "FROM users JOIN addresses ON users.id=addresses.user_id " 

2542 "WHERE users.id = 1" 

2543 ).columns( 

2544 User.id, 

2545 Address.id, 

2546 Address.user_id, 

2547 User.name, 

2548 Address.email_address, 

2549 ) 

2550 

2551 query = ( 

2552 session.query(User) 

2553 .from_statement(stmt) 

2554 .options(contains_eager(User.addresses)) 

2555 ) 

2556 

2557 The :meth:`_expression.TextClause.columns` method provides a direct 

2558 route to calling :meth:`_expression.FromClause.subquery` as well as 

2559 :meth:`_expression.SelectBase.cte` 

2560 against a textual SELECT statement:: 

2561 

2562 stmt = stmt.columns(id=Integer, name=String).cte("st") 

2563 

2564 stmt = select(sometable).where(sometable.c.id == stmt.c.id) 

2565 

2566 :param \*cols: A series of :class:`_expression.ColumnElement` objects, 

2567 typically 

2568 :class:`_schema.Column` objects from a :class:`_schema.Table` 

2569 or ORM level 

2570 column-mapped attributes, representing a set of columns that this 

2571 textual string will SELECT from. 

2572 

2573 :param \**types: A mapping of string names to :class:`.TypeEngine` 

2574 type objects indicating the datatypes to use for names that are 

2575 SELECTed from the textual string. Prefer to use the ``*cols`` 

2576 argument as it also indicates positional ordering. 

2577 

2578 """ 

2579 selectable = util.preloaded.sql_selectable 

2580 

2581 input_cols: List[NamedColumn[Any]] = [ 

2582 coercions.expect(roles.LabeledColumnExprRole, col) for col in cols 

2583 ] 

2584 

2585 positional_input_cols = [ 

2586 ( 

2587 ColumnClause(col.key, types.pop(col.key)) 

2588 if col.key in types 

2589 else col 

2590 ) 

2591 for col in input_cols 

2592 ] 

2593 keyed_input_cols: List[NamedColumn[Any]] = [ 

2594 ColumnClause(key, type_) for key, type_ in types.items() 

2595 ] 

2596 

2597 elem = selectable.TextualSelect.__new__(selectable.TextualSelect) 

2598 elem._init( 

2599 self, 

2600 positional_input_cols + keyed_input_cols, 

2601 positional=bool(positional_input_cols) and not keyed_input_cols, 

2602 ) 

2603 return elem 

2604 

2605 @property 

2606 def type(self) -> TypeEngine[Any]: 

2607 return type_api.NULLTYPE 

2608 

2609 @property 

2610 def comparator(self): 

2611 # TODO: this seems wrong, it seems like we might not 

2612 # be using this method. 

2613 return self.type.comparator_factory(self) # type: ignore 

2614 

2615 def self_group( 

2616 self, against: Optional[OperatorType] = None 

2617 ) -> Union[Self, Grouping[Any]]: 

2618 if against is operators.in_op: 

2619 return Grouping(self) 

2620 else: 

2621 return self 

2622 

2623 

2624class Null(SingletonConstant, roles.ConstExprRole[None], ColumnElement[None]): 

2625 """Represent the NULL keyword in a SQL statement. 

2626 

2627 :class:`.Null` is accessed as a constant via the 

2628 :func:`.null` function. 

2629 

2630 """ 

2631 

2632 __visit_name__ = "null" 

2633 

2634 _traverse_internals: _TraverseInternalsType = [] 

2635 _singleton: Null 

2636 

2637 if not TYPE_CHECKING: 

2638 

2639 @util.memoized_property 

2640 def type(self) -> TypeEngine[_T]: # noqa: A001 

2641 return type_api.NULLTYPE 

2642 

2643 @classmethod 

2644 def _instance(cls) -> Null: 

2645 """Return a constant :class:`.Null` construct.""" 

2646 

2647 return Null._singleton 

2648 

2649 

2650Null._create_singleton() 

2651 

2652 

2653class False_( 

2654 SingletonConstant, roles.ConstExprRole[bool], ColumnElement[bool] 

2655): 

2656 """Represent the ``false`` keyword, or equivalent, in a SQL statement. 

2657 

2658 :class:`.False_` is accessed as a constant via the 

2659 :func:`.false` function. 

2660 

2661 """ 

2662 

2663 __visit_name__ = "false" 

2664 _traverse_internals: _TraverseInternalsType = [] 

2665 _singleton: False_ 

2666 

2667 if not TYPE_CHECKING: 

2668 

2669 @util.memoized_property 

2670 def type(self) -> TypeEngine[_T]: # noqa: A001 

2671 return type_api.BOOLEANTYPE 

2672 

2673 def _negate(self) -> True_: 

2674 return True_._singleton 

2675 

2676 @classmethod 

2677 def _instance(cls) -> False_: 

2678 return False_._singleton 

2679 

2680 

2681False_._create_singleton() 

2682 

2683 

2684class True_(SingletonConstant, roles.ConstExprRole[bool], ColumnElement[bool]): 

2685 """Represent the ``true`` keyword, or equivalent, in a SQL statement. 

2686 

2687 :class:`.True_` is accessed as a constant via the 

2688 :func:`.true` function. 

2689 

2690 """ 

2691 

2692 __visit_name__ = "true" 

2693 

2694 _traverse_internals: _TraverseInternalsType = [] 

2695 _singleton: True_ 

2696 

2697 if not TYPE_CHECKING: 

2698 

2699 @util.memoized_property 

2700 def type(self) -> TypeEngine[_T]: # noqa: A001 

2701 return type_api.BOOLEANTYPE 

2702 

2703 def _negate(self) -> False_: 

2704 return False_._singleton 

2705 

2706 @classmethod 

2707 def _ifnone( 

2708 cls, other: Optional[ColumnElement[Any]] 

2709 ) -> ColumnElement[Any]: 

2710 if other is None: 

2711 return cls._instance() 

2712 else: 

2713 return other 

2714 

2715 @classmethod 

2716 def _instance(cls) -> True_: 

2717 return True_._singleton 

2718 

2719 

2720True_._create_singleton() 

2721 

2722 

2723class ClauseList( 

2724 roles.InElementRole, 

2725 roles.OrderByRole, 

2726 roles.ColumnsClauseRole, 

2727 roles.DMLColumnRole, 

2728 DQLDMLClauseElement, 

2729): 

2730 """Describe a list of clauses, separated by an operator. 

2731 

2732 By default, is comma-separated, such as a column listing. 

2733 

2734 """ 

2735 

2736 __visit_name__ = "clauselist" 

2737 

2738 # this is used only by the ORM in a legacy use case for 

2739 # composite attributes 

2740 _is_clause_list = True 

2741 

2742 _traverse_internals: _TraverseInternalsType = [ 

2743 ("clauses", InternalTraversal.dp_clauseelement_list), 

2744 ("operator", InternalTraversal.dp_operator), 

2745 ] 

2746 

2747 clauses: List[ColumnElement[Any]] 

2748 

2749 def __init__( 

2750 self, 

2751 *clauses: _ColumnExpressionArgument[Any], 

2752 operator: OperatorType = operators.comma_op, 

2753 group: bool = True, 

2754 group_contents: bool = True, 

2755 _literal_as_text_role: Type[roles.SQLRole] = roles.WhereHavingRole, 

2756 ): 

2757 self.operator = operator 

2758 self.group = group 

2759 self.group_contents = group_contents 

2760 clauses_iterator: Iterable[_ColumnExpressionArgument[Any]] = clauses 

2761 text_converter_role: Type[roles.SQLRole] = _literal_as_text_role 

2762 self._text_converter_role = text_converter_role 

2763 

2764 if self.group_contents: 

2765 self.clauses = [ 

2766 coercions.expect( 

2767 text_converter_role, clause, apply_propagate_attrs=self 

2768 ).self_group(against=self.operator) 

2769 for clause in clauses_iterator 

2770 ] 

2771 else: 

2772 self.clauses = [ 

2773 coercions.expect( 

2774 text_converter_role, clause, apply_propagate_attrs=self 

2775 ) 

2776 for clause in clauses_iterator 

2777 ] 

2778 self._is_implicitly_boolean = operators.is_boolean(self.operator) 

2779 

2780 @classmethod 

2781 def _construct_raw( 

2782 cls, 

2783 operator: OperatorType, 

2784 clauses: Optional[Sequence[ColumnElement[Any]]] = None, 

2785 ) -> ClauseList: 

2786 self = cls.__new__(cls) 

2787 self.clauses = list(clauses) if clauses else [] 

2788 self.group = True 

2789 self.operator = operator 

2790 self.group_contents = True 

2791 self._is_implicitly_boolean = False 

2792 return self 

2793 

2794 def __iter__(self) -> Iterator[ColumnElement[Any]]: 

2795 return iter(self.clauses) 

2796 

2797 def __len__(self) -> int: 

2798 return len(self.clauses) 

2799 

2800 @property 

2801 def _select_iterable(self) -> _SelectIterable: 

2802 return itertools.chain.from_iterable( 

2803 [elem._select_iterable for elem in self.clauses] 

2804 ) 

2805 

2806 def append(self, clause): 

2807 if self.group_contents: 

2808 self.clauses.append( 

2809 coercions.expect(self._text_converter_role, clause).self_group( 

2810 against=self.operator 

2811 ) 

2812 ) 

2813 else: 

2814 self.clauses.append( 

2815 coercions.expect(self._text_converter_role, clause) 

2816 ) 

2817 

2818 @util.ro_non_memoized_property 

2819 def _from_objects(self) -> List[FromClause]: 

2820 return list(itertools.chain(*[c._from_objects for c in self.clauses])) 

2821 

2822 def self_group( 

2823 self, against: Optional[OperatorType] = None 

2824 ) -> Union[Self, Grouping[Any]]: 

2825 if self.group and operators.is_precedent(self.operator, against): 

2826 return Grouping(self) 

2827 else: 

2828 return self 

2829 

2830 

2831class OperatorExpression(ColumnElement[_T]): 

2832 """base for expressions that contain an operator and operands 

2833 

2834 .. versionadded:: 2.0 

2835 

2836 """ 

2837 

2838 operator: OperatorType 

2839 type: TypeEngine[_T] 

2840 

2841 group: bool = True 

2842 

2843 @property 

2844 def is_comparison(self): 

2845 return operators.is_comparison(self.operator) 

2846 

2847 def self_group( 

2848 self, against: Optional[OperatorType] = None 

2849 ) -> Union[Self, Grouping[_T]]: 

2850 if ( 

2851 self.group 

2852 and operators.is_precedent(self.operator, against) 

2853 or ( 

2854 # a negate against a non-boolean operator 

2855 # doesn't make too much sense but we should 

2856 # group for that 

2857 against is operators.inv 

2858 and not operators.is_boolean(self.operator) 

2859 ) 

2860 ): 

2861 return Grouping(self) 

2862 else: 

2863 return self 

2864 

2865 @property 

2866 def _flattened_operator_clauses( 

2867 self, 

2868 ) -> typing_Tuple[ColumnElement[Any], ...]: 

2869 raise NotImplementedError() 

2870 

2871 @classmethod 

2872 def _construct_for_op( 

2873 cls, 

2874 left: ColumnElement[Any], 

2875 right: ColumnElement[Any], 

2876 op: OperatorType, 

2877 *, 

2878 type_: TypeEngine[_T], 

2879 negate: Optional[OperatorType] = None, 

2880 modifiers: Optional[Mapping[str, Any]] = None, 

2881 ) -> OperatorExpression[_T]: 

2882 if operators.is_associative(op): 

2883 assert ( 

2884 negate is None 

2885 ), f"negate not supported for associative operator {op}" 

2886 

2887 multi = False 

2888 if getattr( 

2889 left, "operator", None 

2890 ) is op and type_._compare_type_affinity(left.type): 

2891 multi = True 

2892 left_flattened = left._flattened_operator_clauses 

2893 else: 

2894 left_flattened = (left,) 

2895 

2896 if getattr( 

2897 right, "operator", None 

2898 ) is op and type_._compare_type_affinity(right.type): 

2899 multi = True 

2900 right_flattened = right._flattened_operator_clauses 

2901 else: 

2902 right_flattened = (right,) 

2903 

2904 if multi: 

2905 return ExpressionClauseList._construct_for_list( 

2906 op, 

2907 type_, 

2908 *(left_flattened + right_flattened), 

2909 ) 

2910 

2911 if right._is_collection_aggregate: 

2912 negate = None 

2913 

2914 return BinaryExpression( 

2915 left, right, op, type_=type_, negate=negate, modifiers=modifiers 

2916 ) 

2917 

2918 

2919class ExpressionClauseList(OperatorExpression[_T]): 

2920 """Describe a list of clauses, separated by an operator, 

2921 in a column expression context. 

2922 

2923 :class:`.ExpressionClauseList` differs from :class:`.ClauseList` in that 

2924 it represents a column-oriented DQL expression only, not an open ended 

2925 list of anything comma separated. 

2926 

2927 .. versionadded:: 2.0 

2928 

2929 """ 

2930 

2931 __visit_name__ = "expression_clauselist" 

2932 

2933 _traverse_internals: _TraverseInternalsType = [ 

2934 ("clauses", InternalTraversal.dp_clauseelement_tuple), 

2935 ("operator", InternalTraversal.dp_operator), 

2936 ] 

2937 

2938 clauses: typing_Tuple[ColumnElement[Any], ...] 

2939 

2940 group: bool 

2941 

2942 def __init__( 

2943 self, 

2944 operator: OperatorType, 

2945 *clauses: _ColumnExpressionArgument[Any], 

2946 type_: Optional[_TypeEngineArgument[_T]] = None, 

2947 ): 

2948 self.operator = operator 

2949 

2950 self.clauses = tuple( 

2951 coercions.expect( 

2952 roles.ExpressionElementRole, clause, apply_propagate_attrs=self 

2953 ) 

2954 for clause in clauses 

2955 ) 

2956 self._is_implicitly_boolean = operators.is_boolean(self.operator) 

2957 self.type = type_api.to_instance(type_) # type: ignore 

2958 

2959 @property 

2960 def _flattened_operator_clauses( 

2961 self, 

2962 ) -> typing_Tuple[ColumnElement[Any], ...]: 

2963 return self.clauses 

2964 

2965 def __iter__(self) -> Iterator[ColumnElement[Any]]: 

2966 return iter(self.clauses) 

2967 

2968 def __len__(self) -> int: 

2969 return len(self.clauses) 

2970 

2971 @property 

2972 def _select_iterable(self) -> _SelectIterable: 

2973 return (self,) 

2974 

2975 @util.ro_non_memoized_property 

2976 def _from_objects(self) -> List[FromClause]: 

2977 return list(itertools.chain(*[c._from_objects for c in self.clauses])) 

2978 

2979 def _append_inplace(self, clause: ColumnElement[Any]) -> None: 

2980 self.clauses += (clause,) 

2981 

2982 @classmethod 

2983 def _construct_for_list( 

2984 cls, 

2985 operator: OperatorType, 

2986 type_: TypeEngine[_T], 

2987 *clauses: ColumnElement[Any], 

2988 group: bool = True, 

2989 ) -> ExpressionClauseList[_T]: 

2990 self = cls.__new__(cls) 

2991 self.group = group 

2992 if group: 

2993 self.clauses = tuple( 

2994 c.self_group(against=operator) for c in clauses 

2995 ) 

2996 else: 

2997 self.clauses = clauses 

2998 self.operator = operator 

2999 self.type = type_ 

3000 for c in clauses: 

3001 if c._propagate_attrs: 

3002 self._propagate_attrs = c._propagate_attrs 

3003 break 

3004 return self 

3005 

3006 def _negate(self) -> Any: 

3007 grouped = self.self_group(against=operators.inv) 

3008 assert isinstance(grouped, ColumnElement) 

3009 return UnaryExpression(grouped, operator=operators.inv) 

3010 

3011 

3012class BooleanClauseList(ExpressionClauseList[bool]): 

3013 __visit_name__ = "expression_clauselist" 

3014 inherit_cache = True 

3015 

3016 def __init__(self, *arg, **kw): 

3017 raise NotImplementedError( 

3018 "BooleanClauseList has a private constructor" 

3019 ) 

3020 

3021 @classmethod 

3022 def _process_clauses_for_boolean( 

3023 cls, 

3024 operator: OperatorType, 

3025 continue_on: Any, 

3026 skip_on: Any, 

3027 clauses: Iterable[ColumnElement[Any]], 

3028 ) -> typing_Tuple[int, List[ColumnElement[Any]]]: 

3029 has_continue_on = None 

3030 

3031 convert_clauses = [] 

3032 

3033 against = operators._asbool 

3034 lcc = 0 

3035 

3036 for clause in clauses: 

3037 if clause is continue_on: 

3038 # instance of continue_on, like and_(x, y, True, z), store it 

3039 # if we didn't find one already, we will use it if there 

3040 # are no other expressions here. 

3041 has_continue_on = clause 

3042 elif clause is skip_on: 

3043 # instance of skip_on, e.g. and_(x, y, False, z), cancels 

3044 # the rest out 

3045 convert_clauses = [clause] 

3046 lcc = 1 

3047 break 

3048 else: 

3049 if not lcc: 

3050 lcc = 1 

3051 else: 

3052 against = operator 

3053 # technically this would be len(convert_clauses) + 1 

3054 # however this only needs to indicate "greater than one" 

3055 lcc = 2 

3056 convert_clauses.append(clause) 

3057 

3058 if not convert_clauses and has_continue_on is not None: 

3059 convert_clauses = [has_continue_on] 

3060 lcc = 1 

3061 

3062 return lcc, [c.self_group(against=against) for c in convert_clauses] 

3063 

3064 @classmethod 

3065 def _construct( 

3066 cls, 

3067 operator: OperatorType, 

3068 continue_on: Any, 

3069 skip_on: Any, 

3070 initial_clause: Any = _NoArg.NO_ARG, 

3071 *clauses: Any, 

3072 **kw: Any, 

3073 ) -> ColumnElement[Any]: 

3074 if initial_clause is _NoArg.NO_ARG: 

3075 # no elements period. deprecated use case. return an empty 

3076 # ClauseList construct that generates nothing unless it has 

3077 # elements added to it. 

3078 name = operator.__name__ 

3079 

3080 util.warn_deprecated( 

3081 f"Invoking {name}() without arguments is deprecated, and " 

3082 f"will be disallowed in a future release. For an empty " 

3083 f"""{name}() construct, use '{name}({ 

3084 'true()' if continue_on is True_._singleton else 'false()' 

3085 }, *args)' """ 

3086 f"""or '{name}({ 

3087 'True' if continue_on is True_._singleton else 'False' 

3088 }, *args)'.""", 

3089 version="1.4", 

3090 ) 

3091 return cls._construct_raw(operator) 

3092 

3093 lcc, convert_clauses = cls._process_clauses_for_boolean( 

3094 operator, 

3095 continue_on, 

3096 skip_on, 

3097 [ 

3098 coercions.expect(roles.WhereHavingRole, clause) 

3099 for clause in util.coerce_generator_arg( 

3100 (initial_clause,) + clauses 

3101 ) 

3102 ], 

3103 ) 

3104 

3105 if lcc > 1: 

3106 # multiple elements. Return regular BooleanClauseList 

3107 # which will link elements against the operator. 

3108 

3109 flattened_clauses = itertools.chain.from_iterable( 

3110 ( 

3111 (c for c in to_flat._flattened_operator_clauses) 

3112 if getattr(to_flat, "operator", None) is operator 

3113 else (to_flat,) 

3114 ) 

3115 for to_flat in convert_clauses 

3116 ) 

3117 

3118 return cls._construct_raw(operator, flattened_clauses) # type: ignore # noqa: E501 

3119 else: 

3120 assert lcc 

3121 # just one element. return it as a single boolean element, 

3122 # not a list and discard the operator. 

3123 return convert_clauses[0] 

3124 

3125 @classmethod 

3126 def _construct_for_whereclause( 

3127 cls, clauses: Iterable[ColumnElement[Any]] 

3128 ) -> Optional[ColumnElement[bool]]: 

3129 operator, continue_on, skip_on = ( 

3130 operators.and_, 

3131 True_._singleton, 

3132 False_._singleton, 

3133 ) 

3134 

3135 lcc, convert_clauses = cls._process_clauses_for_boolean( 

3136 operator, 

3137 continue_on, 

3138 skip_on, 

3139 clauses, # these are assumed to be coerced already 

3140 ) 

3141 

3142 if lcc > 1: 

3143 # multiple elements. Return regular BooleanClauseList 

3144 # which will link elements against the operator. 

3145 return cls._construct_raw(operator, convert_clauses) 

3146 elif lcc == 1: 

3147 # just one element. return it as a single boolean element, 

3148 # not a list and discard the operator. 

3149 return convert_clauses[0] 

3150 else: 

3151 return None 

3152 

3153 @classmethod 

3154 def _construct_raw( 

3155 cls, 

3156 operator: OperatorType, 

3157 clauses: Optional[Sequence[ColumnElement[Any]]] = None, 

3158 ) -> BooleanClauseList: 

3159 self = cls.__new__(cls) 

3160 self.clauses = tuple(clauses) if clauses else () 

3161 self.group = True 

3162 self.operator = operator 

3163 self.type = type_api.BOOLEANTYPE 

3164 self._is_implicitly_boolean = True 

3165 return self 

3166 

3167 @classmethod 

3168 def and_( 

3169 cls, 

3170 initial_clause: Union[ 

3171 Literal[True], _ColumnExpressionArgument[bool], _NoArg 

3172 ] = _NoArg.NO_ARG, 

3173 *clauses: _ColumnExpressionArgument[bool], 

3174 ) -> ColumnElement[bool]: 

3175 r"""Produce a conjunction of expressions joined by ``AND``. 

3176 

3177 See :func:`_sql.and_` for full documentation. 

3178 """ 

3179 return cls._construct( 

3180 operators.and_, 

3181 True_._singleton, 

3182 False_._singleton, 

3183 initial_clause, 

3184 *clauses, 

3185 ) 

3186 

3187 @classmethod 

3188 def or_( 

3189 cls, 

3190 initial_clause: Union[ 

3191 Literal[False], _ColumnExpressionArgument[bool], _NoArg 

3192 ] = _NoArg.NO_ARG, 

3193 *clauses: _ColumnExpressionArgument[bool], 

3194 ) -> ColumnElement[bool]: 

3195 """Produce a conjunction of expressions joined by ``OR``. 

3196 

3197 See :func:`_sql.or_` for full documentation. 

3198 """ 

3199 return cls._construct( 

3200 operators.or_, 

3201 False_._singleton, 

3202 True_._singleton, 

3203 initial_clause, 

3204 *clauses, 

3205 ) 

3206 

3207 @property 

3208 def _select_iterable(self) -> _SelectIterable: 

3209 return (self,) 

3210 

3211 def self_group( 

3212 self, against: Optional[OperatorType] = None 

3213 ) -> Union[Self, Grouping[bool]]: 

3214 if not self.clauses: 

3215 return self 

3216 else: 

3217 return super().self_group(against=against) 

3218 

3219 

3220and_ = BooleanClauseList.and_ 

3221or_ = BooleanClauseList.or_ 

3222 

3223 

3224class Tuple(ClauseList, ColumnElement[typing_Tuple[Any, ...]]): 

3225 """Represent a SQL tuple.""" 

3226 

3227 __visit_name__ = "tuple" 

3228 

3229 _traverse_internals: _TraverseInternalsType = ( 

3230 ClauseList._traverse_internals + [] 

3231 ) 

3232 

3233 type: TupleType 

3234 

3235 @util.preload_module("sqlalchemy.sql.sqltypes") 

3236 def __init__( 

3237 self, 

3238 *clauses: _ColumnExpressionArgument[Any], 

3239 types: Optional[Sequence[_TypeEngineArgument[Any]]] = None, 

3240 ): 

3241 sqltypes = util.preloaded.sql_sqltypes 

3242 

3243 if types is None: 

3244 init_clauses: List[ColumnElement[Any]] = [ 

3245 coercions.expect(roles.ExpressionElementRole, c) 

3246 for c in clauses 

3247 ] 

3248 else: 

3249 if len(types) != len(clauses): 

3250 raise exc.ArgumentError( 

3251 "Wrong number of elements for %d-tuple: %r " 

3252 % (len(types), clauses) 

3253 ) 

3254 init_clauses = [ 

3255 coercions.expect( 

3256 roles.ExpressionElementRole, 

3257 c, 

3258 type_=typ if not typ._isnull else None, 

3259 ) 

3260 for typ, c in zip(types, clauses) 

3261 ] 

3262 

3263 self.type = sqltypes.TupleType(*[arg.type for arg in init_clauses]) 

3264 super().__init__(*init_clauses) 

3265 

3266 @property 

3267 def _select_iterable(self) -> _SelectIterable: 

3268 return (self,) 

3269 

3270 def _bind_param(self, operator, obj, type_=None, expanding=False): 

3271 if expanding: 

3272 return BindParameter( 

3273 None, 

3274 value=obj, 

3275 _compared_to_operator=operator, 

3276 unique=True, 

3277 expanding=True, 

3278 type_=type_, 

3279 _compared_to_type=self.type, 

3280 ) 

3281 else: 

3282 return Tuple( 

3283 *[ 

3284 BindParameter( 

3285 None, 

3286 o, 

3287 _compared_to_operator=operator, 

3288 _compared_to_type=compared_to_type, 

3289 unique=True, 

3290 type_=type_, 

3291 ) 

3292 for o, compared_to_type in zip(obj, self.type.types) 

3293 ] 

3294 ) 

3295 

3296 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

3297 # Tuple is parenthesized by definition. 

3298 return self 

3299 

3300 

3301class Case(ColumnElement[_T]): 

3302 """Represent a ``CASE`` expression. 

3303 

3304 :class:`.Case` is produced using the :func:`.case` factory function, 

3305 as in:: 

3306 

3307 from sqlalchemy import case 

3308 

3309 stmt = select(users_table).where( 

3310 case( 

3311 (users_table.c.name == "wendy", "W"), 

3312 (users_table.c.name == "jack", "J"), 

3313 else_="E", 

3314 ) 

3315 ) 

3316 

3317 Details on :class:`.Case` usage is at :func:`.case`. 

3318 

3319 .. seealso:: 

3320 

3321 :func:`.case` 

3322 

3323 """ 

3324 

3325 __visit_name__ = "case" 

3326 

3327 _traverse_internals: _TraverseInternalsType = [ 

3328 ("value", InternalTraversal.dp_clauseelement), 

3329 ("whens", InternalTraversal.dp_clauseelement_tuples), 

3330 ("else_", InternalTraversal.dp_clauseelement), 

3331 ] 

3332 

3333 # for case(), the type is derived from the whens. so for the moment 

3334 # users would have to cast() the case to get a specific type 

3335 

3336 whens: List[typing_Tuple[ColumnElement[bool], ColumnElement[_T]]] 

3337 else_: Optional[ColumnElement[_T]] 

3338 value: Optional[ColumnElement[Any]] 

3339 

3340 def __init__( 

3341 self, 

3342 *whens: Union[ 

3343 typing_Tuple[_ColumnExpressionArgument[bool], Any], 

3344 Mapping[Any, Any], 

3345 ], 

3346 value: Optional[Any] = None, 

3347 else_: Optional[Any] = None, 

3348 ): 

3349 new_whens: Iterable[Any] = coercions._expression_collection_was_a_list( 

3350 "whens", "case", whens 

3351 ) 

3352 try: 

3353 new_whens = util.dictlike_iteritems(new_whens) 

3354 except TypeError: 

3355 pass 

3356 

3357 self.whens = [ 

3358 ( 

3359 coercions.expect( 

3360 roles.ExpressionElementRole, 

3361 c, 

3362 apply_propagate_attrs=self, 

3363 ).self_group(), 

3364 coercions.expect(roles.ExpressionElementRole, r), 

3365 ) 

3366 for (c, r) in new_whens 

3367 ] 

3368 

3369 if value is None: 

3370 self.value = None 

3371 else: 

3372 self.value = coercions.expect(roles.ExpressionElementRole, value) 

3373 

3374 if else_ is not None: 

3375 self.else_ = coercions.expect(roles.ExpressionElementRole, else_) 

3376 else: 

3377 self.else_ = None 

3378 

3379 type_ = next( 

3380 ( 

3381 then.type 

3382 # Iterate `whens` in reverse to match previous behaviour 

3383 # where type of final element took priority 

3384 for *_, then in reversed(self.whens) 

3385 if not then.type._isnull 

3386 ), 

3387 self.else_.type if self.else_ is not None else type_api.NULLTYPE, 

3388 ) 

3389 self.type = cast(_T, type_) 

3390 

3391 @util.ro_non_memoized_property 

3392 def _from_objects(self) -> List[FromClause]: 

3393 return list( 

3394 itertools.chain(*[x._from_objects for x in self.get_children()]) 

3395 ) 

3396 

3397 

3398class Cast(WrapsColumnExpression[_T]): 

3399 """Represent a ``CAST`` expression. 

3400 

3401 :class:`.Cast` is produced using the :func:`.cast` factory function, 

3402 as in:: 

3403 

3404 from sqlalchemy import cast, Numeric 

3405 

3406 stmt = select(cast(product_table.c.unit_price, Numeric(10, 4))) 

3407 

3408 Details on :class:`.Cast` usage is at :func:`.cast`. 

3409 

3410 .. seealso:: 

3411 

3412 :ref:`tutorial_casts` 

3413 

3414 :func:`.cast` 

3415 

3416 :func:`.try_cast` 

3417 

3418 :func:`.type_coerce` - an alternative to CAST that coerces the type 

3419 on the Python side only, which is often sufficient to generate the 

3420 correct SQL and data coercion. 

3421 

3422 """ 

3423 

3424 __visit_name__ = "cast" 

3425 

3426 _traverse_internals: _TraverseInternalsType = [ 

3427 ("clause", InternalTraversal.dp_clauseelement), 

3428 ("type", InternalTraversal.dp_type), 

3429 ] 

3430 

3431 clause: ColumnElement[Any] 

3432 type: TypeEngine[_T] 

3433 typeclause: TypeClause 

3434 

3435 def __init__( 

3436 self, 

3437 expression: _ColumnExpressionArgument[Any], 

3438 type_: _TypeEngineArgument[_T], 

3439 ): 

3440 self.type = type_api.to_instance(type_) 

3441 self.clause = coercions.expect( 

3442 roles.ExpressionElementRole, 

3443 expression, 

3444 type_=self.type, 

3445 apply_propagate_attrs=self, 

3446 ) 

3447 self.typeclause = TypeClause(self.type) 

3448 

3449 @util.ro_non_memoized_property 

3450 def _from_objects(self) -> List[FromClause]: 

3451 return self.clause._from_objects 

3452 

3453 @property 

3454 def wrapped_column_expression(self): 

3455 return self.clause 

3456 

3457 

3458class TryCast(Cast[_T]): 

3459 """Represent a TRY_CAST expression. 

3460 

3461 Details on :class:`.TryCast` usage is at :func:`.try_cast`. 

3462 

3463 .. seealso:: 

3464 

3465 :func:`.try_cast` 

3466 

3467 :ref:`tutorial_casts` 

3468 """ 

3469 

3470 __visit_name__ = "try_cast" 

3471 inherit_cache = True 

3472 

3473 

3474class TypeCoerce(WrapsColumnExpression[_T]): 

3475 """Represent a Python-side type-coercion wrapper. 

3476 

3477 :class:`.TypeCoerce` supplies the :func:`_expression.type_coerce` 

3478 function; see that function for usage details. 

3479 

3480 .. seealso:: 

3481 

3482 :func:`_expression.type_coerce` 

3483 

3484 :func:`.cast` 

3485 

3486 """ 

3487 

3488 __visit_name__ = "type_coerce" 

3489 

3490 _traverse_internals: _TraverseInternalsType = [ 

3491 ("clause", InternalTraversal.dp_clauseelement), 

3492 ("type", InternalTraversal.dp_type), 

3493 ] 

3494 

3495 clause: ColumnElement[Any] 

3496 type: TypeEngine[_T] 

3497 

3498 def __init__( 

3499 self, 

3500 expression: _ColumnExpressionArgument[Any], 

3501 type_: _TypeEngineArgument[_T], 

3502 ): 

3503 self.type = type_api.to_instance(type_) 

3504 self.clause = coercions.expect( 

3505 roles.ExpressionElementRole, 

3506 expression, 

3507 type_=self.type, 

3508 apply_propagate_attrs=self, 

3509 ) 

3510 

3511 @util.ro_non_memoized_property 

3512 def _from_objects(self) -> List[FromClause]: 

3513 return self.clause._from_objects 

3514 

3515 @HasMemoized.memoized_attribute 

3516 def typed_expression(self): 

3517 if isinstance(self.clause, BindParameter): 

3518 bp = self.clause._clone() 

3519 bp.type = self.type 

3520 return bp 

3521 else: 

3522 return self.clause 

3523 

3524 @property 

3525 def wrapped_column_expression(self): 

3526 return self.clause 

3527 

3528 def self_group( 

3529 self, against: Optional[OperatorType] = None 

3530 ) -> TypeCoerce[_T]: 

3531 grouped = self.clause.self_group(against=against) 

3532 if grouped is not self.clause: 

3533 return TypeCoerce(grouped, self.type) 

3534 else: 

3535 return self 

3536 

3537 

3538class Extract(ColumnElement[int]): 

3539 """Represent a SQL EXTRACT clause, ``extract(field FROM expr)``.""" 

3540 

3541 __visit_name__ = "extract" 

3542 

3543 _traverse_internals: _TraverseInternalsType = [ 

3544 ("expr", InternalTraversal.dp_clauseelement), 

3545 ("field", InternalTraversal.dp_string), 

3546 ] 

3547 

3548 expr: ColumnElement[Any] 

3549 field: str 

3550 

3551 def __init__(self, field: str, expr: _ColumnExpressionArgument[Any]): 

3552 self.type = type_api.INTEGERTYPE 

3553 self.field = field 

3554 self.expr = coercions.expect(roles.ExpressionElementRole, expr) 

3555 

3556 @util.ro_non_memoized_property 

3557 def _from_objects(self) -> List[FromClause]: 

3558 return self.expr._from_objects 

3559 

3560 

3561class _label_reference(ColumnElement[_T]): 

3562 """Wrap a column expression as it appears in a 'reference' context. 

3563 

3564 This expression is any that includes an _order_by_label_element, 

3565 which is a Label, or a DESC / ASC construct wrapping a Label. 

3566 

3567 The production of _label_reference() should occur when an expression 

3568 is added to this context; this includes the ORDER BY or GROUP BY of a 

3569 SELECT statement, as well as a few other places, such as the ORDER BY 

3570 within an OVER clause. 

3571 

3572 """ 

3573 

3574 __visit_name__ = "label_reference" 

3575 

3576 _traverse_internals: _TraverseInternalsType = [ 

3577 ("element", InternalTraversal.dp_clauseelement) 

3578 ] 

3579 

3580 element: ColumnElement[_T] 

3581 

3582 def __init__(self, element: ColumnElement[_T]): 

3583 self.element = element 

3584 

3585 @util.ro_non_memoized_property 

3586 def _from_objects(self) -> List[FromClause]: 

3587 return [] 

3588 

3589 

3590class _textual_label_reference(ColumnElement[Any]): 

3591 __visit_name__ = "textual_label_reference" 

3592 

3593 _traverse_internals: _TraverseInternalsType = [ 

3594 ("element", InternalTraversal.dp_string) 

3595 ] 

3596 

3597 def __init__(self, element: str): 

3598 self.element = element 

3599 

3600 @util.memoized_property 

3601 def _text_clause(self) -> TextClause: 

3602 return TextClause(self.element) 

3603 

3604 

3605class UnaryExpression(ColumnElement[_T]): 

3606 """Define a 'unary' expression. 

3607 

3608 A unary expression has a single column expression 

3609 and an operator. The operator can be placed on the left 

3610 (where it is called the 'operator') or right (where it is called the 

3611 'modifier') of the column expression. 

3612 

3613 :class:`.UnaryExpression` is the basis for several unary operators 

3614 including those used by :func:`.desc`, :func:`.asc`, :func:`.distinct`, 

3615 :func:`.nulls_first` and :func:`.nulls_last`. 

3616 

3617 """ 

3618 

3619 __visit_name__ = "unary" 

3620 

3621 _traverse_internals: _TraverseInternalsType = [ 

3622 ("element", InternalTraversal.dp_clauseelement), 

3623 ("operator", InternalTraversal.dp_operator), 

3624 ("modifier", InternalTraversal.dp_operator), 

3625 ] 

3626 

3627 element: ColumnElement[Any] 

3628 operator: Optional[OperatorType] 

3629 modifier: Optional[OperatorType] 

3630 

3631 def __init__( 

3632 self, 

3633 element: ColumnElement[Any], 

3634 *, 

3635 operator: Optional[OperatorType] = None, 

3636 modifier: Optional[OperatorType] = None, 

3637 type_: Optional[_TypeEngineArgument[_T]] = None, 

3638 wraps_column_expression: bool = False, # legacy, not used as of 2.0.42 

3639 ): 

3640 self.operator = operator 

3641 self.modifier = modifier 

3642 self._propagate_attrs = element._propagate_attrs 

3643 self.element = element.self_group( 

3644 against=self.operator or self.modifier 

3645 ) 

3646 

3647 # if type is None, we get NULLTYPE, which is our _T. But I don't 

3648 # know how to get the overloads to express that correctly 

3649 self.type = type_api.to_instance(type_) # type: ignore 

3650 

3651 def _wraps_unnamed_column(self): 

3652 ungrouped = self.element._ungroup() 

3653 return ( 

3654 not isinstance(ungrouped, NamedColumn) 

3655 or ungrouped._non_anon_label is None 

3656 ) 

3657 

3658 @classmethod 

3659 def _create_nulls_first( 

3660 cls, 

3661 column: _ColumnExpressionArgument[_T], 

3662 ) -> UnaryExpression[_T]: 

3663 return UnaryExpression( 

3664 coercions.expect(roles.ByOfRole, column), 

3665 modifier=operators.nulls_first_op, 

3666 ) 

3667 

3668 @classmethod 

3669 def _create_nulls_last( 

3670 cls, 

3671 column: _ColumnExpressionArgument[_T], 

3672 ) -> UnaryExpression[_T]: 

3673 return UnaryExpression( 

3674 coercions.expect(roles.ByOfRole, column), 

3675 modifier=operators.nulls_last_op, 

3676 ) 

3677 

3678 @classmethod 

3679 def _create_desc( 

3680 cls, column: _ColumnExpressionOrStrLabelArgument[_T] 

3681 ) -> UnaryExpression[_T]: 

3682 return UnaryExpression( 

3683 coercions.expect(roles.ByOfRole, column), 

3684 modifier=operators.desc_op, 

3685 ) 

3686 

3687 @classmethod 

3688 def _create_asc( 

3689 cls, 

3690 column: _ColumnExpressionOrStrLabelArgument[_T], 

3691 ) -> UnaryExpression[_T]: 

3692 return UnaryExpression( 

3693 coercions.expect(roles.ByOfRole, column), 

3694 modifier=operators.asc_op, 

3695 ) 

3696 

3697 @classmethod 

3698 def _create_distinct( 

3699 cls, 

3700 expr: _ColumnExpressionArgument[_T], 

3701 ) -> UnaryExpression[_T]: 

3702 col_expr: ColumnElement[_T] = coercions.expect( 

3703 roles.ExpressionElementRole, expr 

3704 ) 

3705 return UnaryExpression( 

3706 col_expr, 

3707 operator=operators.distinct_op, 

3708 type_=col_expr.type, 

3709 ) 

3710 

3711 @classmethod 

3712 def _create_bitwise_not( 

3713 cls, 

3714 expr: _ColumnExpressionArgument[_T], 

3715 ) -> UnaryExpression[_T]: 

3716 col_expr: ColumnElement[_T] = coercions.expect( 

3717 roles.ExpressionElementRole, expr 

3718 ) 

3719 return UnaryExpression( 

3720 col_expr, 

3721 operator=operators.bitwise_not_op, 

3722 type_=col_expr.type, 

3723 ) 

3724 

3725 @property 

3726 def _order_by_label_element(self) -> Optional[Label[Any]]: 

3727 if operators.is_order_by_modifier(self.modifier): 

3728 return self.element._order_by_label_element 

3729 else: 

3730 return None 

3731 

3732 @util.ro_non_memoized_property 

3733 def _from_objects(self) -> List[FromClause]: 

3734 return self.element._from_objects 

3735 

3736 def _negate(self) -> ColumnElement[Any]: 

3737 if self.type._type_affinity is type_api.BOOLEANTYPE._type_affinity: 

3738 return UnaryExpression( 

3739 self.self_group(against=operators.inv), 

3740 operator=operators.inv, 

3741 type_=type_api.BOOLEANTYPE, 

3742 ) 

3743 else: 

3744 return ColumnElement._negate(self) 

3745 

3746 def self_group( 

3747 self, against: Optional[OperatorType] = None 

3748 ) -> Union[Self, Grouping[_T]]: 

3749 if self.operator and operators.is_precedent(self.operator, against): 

3750 return Grouping(self) 

3751 else: 

3752 return self 

3753 

3754 

3755class CollectionAggregate(UnaryExpression[_T]): 

3756 """Forms the basis for right-hand collection operator modifiers 

3757 ANY and ALL. 

3758 

3759 The ANY and ALL keywords are available in different ways on different 

3760 backends. On PostgreSQL, they only work for an ARRAY type. On 

3761 MySQL, they only work for subqueries. 

3762 

3763 """ 

3764 

3765 inherit_cache = True 

3766 _is_collection_aggregate = True 

3767 

3768 @classmethod 

3769 def _create_any( 

3770 cls, expr: _ColumnExpressionArgument[_T] 

3771 ) -> CollectionAggregate[bool]: 

3772 """create CollectionAggregate for the legacy 

3773 ARRAY.Comparator.any() method""" 

3774 col_expr: ColumnElement[_T] = coercions.expect( 

3775 roles.ExpressionElementRole, 

3776 expr, 

3777 ) 

3778 col_expr = col_expr.self_group() 

3779 return CollectionAggregate( 

3780 col_expr, 

3781 operator=operators.any_op, 

3782 type_=type_api.BOOLEANTYPE, 

3783 ) 

3784 

3785 @classmethod 

3786 def _create_all( 

3787 cls, expr: _ColumnExpressionArgument[_T] 

3788 ) -> CollectionAggregate[bool]: 

3789 """create CollectionAggregate for the legacy 

3790 ARRAY.Comparator.all() method""" 

3791 col_expr: ColumnElement[_T] = coercions.expect( 

3792 roles.ExpressionElementRole, 

3793 expr, 

3794 ) 

3795 col_expr = col_expr.self_group() 

3796 return CollectionAggregate( 

3797 col_expr, 

3798 operator=operators.all_op, 

3799 type_=type_api.BOOLEANTYPE, 

3800 ) 

3801 

3802 @util.preload_module("sqlalchemy.sql.sqltypes") 

3803 def _bind_param( 

3804 self, 

3805 operator: operators.OperatorType, 

3806 obj: Any, 

3807 type_: Optional[TypeEngine[_T]] = None, 

3808 expanding: bool = False, 

3809 ) -> BindParameter[_T]: 

3810 """For new style any_(), all_(), ensure compared literal value 

3811 receives appropriate bound parameter type.""" 

3812 

3813 # a CollectionAggregate is specific to ARRAY or int 

3814 # only. So for ARRAY case, make sure we use correct element type 

3815 sqltypes = util.preloaded.sql_sqltypes 

3816 if self.element.type._type_affinity is sqltypes.ARRAY: 

3817 compared_to_type = cast( 

3818 sqltypes.ARRAY[Any], self.element.type 

3819 ).item_type 

3820 else: 

3821 compared_to_type = self.element.type 

3822 

3823 return BindParameter( 

3824 None, 

3825 obj, 

3826 _compared_to_operator=operator, 

3827 type_=type_, 

3828 _compared_to_type=compared_to_type, 

3829 unique=True, 

3830 expanding=expanding, 

3831 ) 

3832 

3833 # operate and reverse_operate are hardwired to 

3834 # dispatch onto the type comparator directly, so that we can 

3835 # ensure "reversed" behavior. 

3836 def operate( 

3837 self, op: OperatorType, *other: Any, **kwargs: Any 

3838 ) -> ColumnElement[_T]: 

3839 if not operators.is_comparison(op): 

3840 raise exc.ArgumentError( 

3841 "Only comparison operators may be used with ANY/ALL" 

3842 ) 

3843 kwargs["reverse"] = True 

3844 return self.comparator.operate(operators.mirror(op), *other, **kwargs) 

3845 

3846 def reverse_operate( 

3847 self, op: OperatorType, other: Any, **kwargs: Any 

3848 ) -> ColumnElement[_T]: 

3849 # comparison operators should never call reverse_operate 

3850 assert not operators.is_comparison(op) 

3851 raise exc.ArgumentError( 

3852 "Only comparison operators may be used with ANY/ALL" 

3853 ) 

3854 

3855 

3856class AsBoolean(WrapsColumnExpression[bool], UnaryExpression[bool]): 

3857 inherit_cache = True 

3858 

3859 def __init__(self, element, operator, negate): 

3860 self.element = element 

3861 self.type = type_api.BOOLEANTYPE 

3862 self.operator = operator 

3863 self.negate = negate 

3864 self.modifier = None 

3865 self._is_implicitly_boolean = element._is_implicitly_boolean 

3866 

3867 @property 

3868 def wrapped_column_expression(self): 

3869 return self.element 

3870 

3871 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

3872 return self 

3873 

3874 def _negate(self): 

3875 if isinstance(self.element, (True_, False_)): 

3876 return self.element._negate() 

3877 else: 

3878 return AsBoolean(self.element, self.negate, self.operator) 

3879 

3880 

3881class BinaryExpression(OperatorExpression[_T]): 

3882 """Represent an expression that is ``LEFT <operator> RIGHT``. 

3883 

3884 A :class:`.BinaryExpression` is generated automatically 

3885 whenever two column expressions are used in a Python binary expression: 

3886 

3887 .. sourcecode:: pycon+sql 

3888 

3889 >>> from sqlalchemy.sql import column 

3890 >>> column("a") + column("b") 

3891 <sqlalchemy.sql.expression.BinaryExpression object at 0x101029dd0> 

3892 >>> print(column("a") + column("b")) 

3893 {printsql}a + b 

3894 

3895 """ 

3896 

3897 __visit_name__ = "binary" 

3898 

3899 _traverse_internals: _TraverseInternalsType = [ 

3900 ("left", InternalTraversal.dp_clauseelement), 

3901 ("right", InternalTraversal.dp_clauseelement), 

3902 ("operator", InternalTraversal.dp_operator), 

3903 ("negate", InternalTraversal.dp_operator), 

3904 ("modifiers", InternalTraversal.dp_plain_dict), 

3905 ( 

3906 "type", 

3907 InternalTraversal.dp_type, 

3908 ), 

3909 ] 

3910 

3911 _cache_key_traversal = [ 

3912 ("left", InternalTraversal.dp_clauseelement), 

3913 ("right", InternalTraversal.dp_clauseelement), 

3914 ("operator", InternalTraversal.dp_operator), 

3915 ("modifiers", InternalTraversal.dp_plain_dict), 

3916 # "type" affects JSON CAST operators, so while redundant in most cases, 

3917 # is needed for that one 

3918 ( 

3919 "type", 

3920 InternalTraversal.dp_type, 

3921 ), 

3922 ] 

3923 

3924 _is_implicitly_boolean = True 

3925 """Indicates that any database will know this is a boolean expression 

3926 even if the database does not have an explicit boolean datatype. 

3927 

3928 """ 

3929 

3930 left: ColumnElement[Any] 

3931 right: ColumnElement[Any] 

3932 modifiers: Mapping[str, Any] 

3933 

3934 def __init__( 

3935 self, 

3936 left: ColumnElement[Any], 

3937 right: ColumnElement[Any], 

3938 operator: OperatorType, 

3939 type_: Optional[_TypeEngineArgument[_T]] = None, 

3940 negate: Optional[OperatorType] = None, 

3941 modifiers: Optional[Mapping[str, Any]] = None, 

3942 ): 

3943 # allow compatibility with libraries that 

3944 # refer to BinaryExpression directly and pass strings 

3945 if isinstance(operator, str): 

3946 operator = operators.custom_op(operator) 

3947 self._orig = (left.__hash__(), right.__hash__()) 

3948 self._propagate_attrs = left._propagate_attrs or right._propagate_attrs 

3949 self.left = left.self_group(against=operator) 

3950 self.right = right.self_group(against=operator) 

3951 self.operator = operator 

3952 

3953 # if type is None, we get NULLTYPE, which is our _T. But I don't 

3954 # know how to get the overloads to express that correctly 

3955 self.type = type_api.to_instance(type_) # type: ignore 

3956 

3957 self.negate = negate 

3958 self._is_implicitly_boolean = operators.is_boolean(operator) 

3959 

3960 if modifiers is None: 

3961 self.modifiers = {} 

3962 else: 

3963 self.modifiers = modifiers 

3964 

3965 @property 

3966 def _flattened_operator_clauses( 

3967 self, 

3968 ) -> typing_Tuple[ColumnElement[Any], ...]: 

3969 return (self.left, self.right) 

3970 

3971 def __bool__(self): 

3972 """Implement Python-side "bool" for BinaryExpression as a 

3973 simple "identity" check for the left and right attributes, 

3974 if the operator is "eq" or "ne". Otherwise the expression 

3975 continues to not support "bool" like all other column expressions. 

3976 

3977 The rationale here is so that ColumnElement objects can be hashable. 

3978 What? Well, suppose you do this:: 

3979 

3980 c1, c2 = column("x"), column("y") 

3981 s1 = set([c1, c2]) 

3982 

3983 We do that **a lot**, columns inside of sets is an extremely basic 

3984 thing all over the ORM for example. 

3985 

3986 So what happens if we do this? :: 

3987 

3988 c1 in s1 

3989 

3990 Hashing means it will normally use ``__hash__()`` of the object, 

3991 but in case of hash collision, it's going to also do ``c1 == c1`` 

3992 and/or ``c1 == c2`` inside. Those operations need to return a 

3993 True/False value. But because we override ``==`` and ``!=``, they're 

3994 going to get a BinaryExpression. Hence we implement ``__bool__`` here 

3995 so that these comparisons behave in this particular context mostly 

3996 like regular object comparisons. Thankfully Python is OK with 

3997 that! Otherwise we'd have to use special set classes for columns 

3998 (which we used to do, decades ago). 

3999 

4000 """ 

4001 if self.operator in (operators.eq, operators.ne): 

4002 # this is using the eq/ne operator given int hash values, 

4003 # rather than Operator, so that "bool" can be based on 

4004 # identity 

4005 return self.operator(*self._orig) # type: ignore 

4006 else: 

4007 raise TypeError("Boolean value of this clause is not defined") 

4008 

4009 if typing.TYPE_CHECKING: 

4010 

4011 def __invert__( 

4012 self: BinaryExpression[_T], 

4013 ) -> BinaryExpression[_T]: ... 

4014 

4015 @util.ro_non_memoized_property 

4016 def _from_objects(self) -> List[FromClause]: 

4017 return self.left._from_objects + self.right._from_objects 

4018 

4019 def _negate(self): 

4020 if self.negate is not None: 

4021 return BinaryExpression( 

4022 self.left, 

4023 self.right._negate_in_binary(self.negate, self.operator), 

4024 self.negate, 

4025 negate=self.operator, 

4026 type_=self.type, 

4027 modifiers=self.modifiers, 

4028 ) 

4029 else: 

4030 return self.self_group()._negate() 

4031 

4032 

4033class Slice(ColumnElement[Any]): 

4034 """Represent SQL for a Python array-slice object. 

4035 

4036 This is not a specific SQL construct at this level, but 

4037 may be interpreted by specific dialects, e.g. PostgreSQL. 

4038 

4039 """ 

4040 

4041 __visit_name__ = "slice" 

4042 

4043 _traverse_internals: _TraverseInternalsType = [ 

4044 ("start", InternalTraversal.dp_clauseelement), 

4045 ("stop", InternalTraversal.dp_clauseelement), 

4046 ("step", InternalTraversal.dp_clauseelement), 

4047 ] 

4048 

4049 def __init__(self, start, stop, step, _name=None): 

4050 self.start = coercions.expect( 

4051 roles.ExpressionElementRole, 

4052 start, 

4053 name=_name, 

4054 type_=type_api.INTEGERTYPE, 

4055 ) 

4056 self.stop = coercions.expect( 

4057 roles.ExpressionElementRole, 

4058 stop, 

4059 name=_name, 

4060 type_=type_api.INTEGERTYPE, 

4061 ) 

4062 self.step = coercions.expect( 

4063 roles.ExpressionElementRole, 

4064 step, 

4065 name=_name, 

4066 type_=type_api.INTEGERTYPE, 

4067 ) 

4068 self.type = type_api.NULLTYPE 

4069 

4070 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

4071 assert against is operator.getitem 

4072 return self 

4073 

4074 

4075class IndexExpression(BinaryExpression[Any]): 

4076 """Represent the class of expressions that are like an "index" 

4077 operation.""" 

4078 

4079 inherit_cache = True 

4080 

4081 

4082class GroupedElement(DQLDMLClauseElement): 

4083 """Represent any parenthesized expression""" 

4084 

4085 __visit_name__ = "grouping" 

4086 

4087 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

4088 return self 

4089 

4090 def _ungroup(self) -> ClauseElement: 

4091 raise NotImplementedError() 

4092 

4093 

4094class Grouping(GroupedElement, ColumnElement[_T]): 

4095 """Represent a grouping within a column expression""" 

4096 

4097 _traverse_internals: _TraverseInternalsType = [ 

4098 ("element", InternalTraversal.dp_clauseelement), 

4099 ("type", InternalTraversal.dp_type), 

4100 ] 

4101 

4102 _cache_key_traversal = [ 

4103 ("element", InternalTraversal.dp_clauseelement), 

4104 ] 

4105 

4106 element: Union[TextClause, ClauseList, ColumnElement[_T]] 

4107 

4108 def __init__( 

4109 self, element: Union[TextClause, ClauseList, ColumnElement[_T]] 

4110 ): 

4111 self.element = element 

4112 

4113 # nulltype assignment issue 

4114 self.type = getattr(element, "type", type_api.NULLTYPE) # type: ignore 

4115 self._propagate_attrs = element._propagate_attrs 

4116 

4117 def _with_binary_element_type(self, type_): 

4118 return self.__class__(self.element._with_binary_element_type(type_)) 

4119 

4120 def _ungroup(self) -> ColumnElement[_T]: 

4121 assert isinstance(self.element, ColumnElement) 

4122 return self.element._ungroup() 

4123 

4124 @util.memoized_property 

4125 def _is_implicitly_boolean(self): 

4126 return self.element._is_implicitly_boolean 

4127 

4128 @util.non_memoized_property 

4129 def _tq_label(self) -> Optional[str]: 

4130 return ( 

4131 getattr(self.element, "_tq_label", None) or self._anon_name_label 

4132 ) 

4133 

4134 @util.non_memoized_property 

4135 def _proxies(self) -> List[ColumnElement[Any]]: 

4136 if isinstance(self.element, ColumnElement): 

4137 return [self.element] 

4138 else: 

4139 return [] 

4140 

4141 @util.ro_non_memoized_property 

4142 def _from_objects(self) -> List[FromClause]: 

4143 return self.element._from_objects 

4144 

4145 def __getattr__(self, attr): 

4146 return getattr(self.element, attr) 

4147 

4148 def __getstate__(self): 

4149 return {"element": self.element, "type": self.type} 

4150 

4151 def __setstate__(self, state): 

4152 self.element = state["element"] 

4153 self.type = state["type"] 

4154 

4155 if TYPE_CHECKING: 

4156 

4157 def self_group( 

4158 self, against: Optional[OperatorType] = None 

4159 ) -> Self: ... 

4160 

4161 

4162class _OverrideBinds(Grouping[_T]): 

4163 """used by cache_key->_apply_params_to_element to allow compilation / 

4164 execution of a SQL element that's been cached, using an alternate set of 

4165 bound parameter values. 

4166 

4167 This is used by the ORM to swap new parameter values into expressions 

4168 that are embedded into loader options like with_expression(), 

4169 selectinload(). Previously, this task was accomplished using the 

4170 .params() method which would perform a deep-copy instead. This deep 

4171 copy proved to be too expensive for more complex expressions. 

4172 

4173 See #11085 

4174 

4175 """ 

4176 

4177 __visit_name__ = "override_binds" 

4178 

4179 def __init__( 

4180 self, 

4181 element: ColumnElement[_T], 

4182 bindparams: Sequence[BindParameter[Any]], 

4183 replaces_params: Sequence[BindParameter[Any]], 

4184 ): 

4185 self.element = element 

4186 self.translate = { 

4187 k.key: v.value for k, v in zip(replaces_params, bindparams) 

4188 } 

4189 

4190 def _gen_cache_key( 

4191 self, anon_map: anon_map, bindparams: List[BindParameter[Any]] 

4192 ) -> Optional[typing_Tuple[Any, ...]]: 

4193 """generate a cache key for the given element, substituting its bind 

4194 values for the translation values present.""" 

4195 

4196 existing_bps: List[BindParameter[Any]] = [] 

4197 ck = self.element._gen_cache_key(anon_map, existing_bps) 

4198 

4199 bindparams.extend( 

4200 ( 

4201 bp._with_value( 

4202 self.translate[bp.key], maintain_key=True, required=False 

4203 ) 

4204 if bp.key in self.translate 

4205 else bp 

4206 ) 

4207 for bp in existing_bps 

4208 ) 

4209 

4210 return ck 

4211 

4212 

4213class _OverRange(Enum): 

4214 RANGE_UNBOUNDED = 0 

4215 RANGE_CURRENT = 1 

4216 

4217 

4218RANGE_UNBOUNDED = _OverRange.RANGE_UNBOUNDED 

4219RANGE_CURRENT = _OverRange.RANGE_CURRENT 

4220 

4221_IntOrRange = Union[int, _OverRange] 

4222 

4223 

4224class Over(ColumnElement[_T]): 

4225 """Represent an OVER clause. 

4226 

4227 This is a special operator against a so-called 

4228 "window" function, as well as any aggregate function, 

4229 which produces results relative to the result set 

4230 itself. Most modern SQL backends now support window functions. 

4231 

4232 """ 

4233 

4234 __visit_name__ = "over" 

4235 

4236 _traverse_internals: _TraverseInternalsType = [ 

4237 ("element", InternalTraversal.dp_clauseelement), 

4238 ("order_by", InternalTraversal.dp_clauseelement), 

4239 ("partition_by", InternalTraversal.dp_clauseelement), 

4240 ("range_", InternalTraversal.dp_plain_obj), 

4241 ("rows", InternalTraversal.dp_plain_obj), 

4242 ("groups", InternalTraversal.dp_plain_obj), 

4243 ] 

4244 

4245 order_by: Optional[ClauseList] = None 

4246 partition_by: Optional[ClauseList] = None 

4247 

4248 element: ColumnElement[_T] 

4249 """The underlying expression object to which this :class:`.Over` 

4250 object refers.""" 

4251 

4252 range_: Optional[typing_Tuple[_IntOrRange, _IntOrRange]] 

4253 rows: Optional[typing_Tuple[_IntOrRange, _IntOrRange]] 

4254 groups: Optional[typing_Tuple[_IntOrRange, _IntOrRange]] 

4255 

4256 def __init__( 

4257 self, 

4258 element: ColumnElement[_T], 

4259 partition_by: Optional[_ByArgument] = None, 

4260 order_by: Optional[_ByArgument] = None, 

4261 range_: Optional[typing_Tuple[Optional[int], Optional[int]]] = None, 

4262 rows: Optional[typing_Tuple[Optional[int], Optional[int]]] = None, 

4263 groups: Optional[typing_Tuple[Optional[int], Optional[int]]] = None, 

4264 ): 

4265 self.element = element 

4266 if order_by is not None: 

4267 self.order_by = ClauseList( 

4268 *util.to_list(order_by), _literal_as_text_role=roles.ByOfRole 

4269 ) 

4270 if partition_by is not None: 

4271 self.partition_by = ClauseList( 

4272 *util.to_list(partition_by), 

4273 _literal_as_text_role=roles.ByOfRole, 

4274 ) 

4275 

4276 if sum(bool(item) for item in (range_, rows, groups)) > 1: 

4277 raise exc.ArgumentError( 

4278 "only one of 'rows', 'range_', or 'groups' may be provided" 

4279 ) 

4280 else: 

4281 self.range_ = self._interpret_range(range_) if range_ else None 

4282 self.rows = self._interpret_range(rows) if rows else None 

4283 self.groups = self._interpret_range(groups) if groups else None 

4284 

4285 def __reduce__(self): 

4286 return self.__class__, ( 

4287 self.element, 

4288 self.partition_by, 

4289 self.order_by, 

4290 self.range_, 

4291 self.rows, 

4292 self.groups, 

4293 ) 

4294 

4295 def _interpret_range( 

4296 self, 

4297 range_: typing_Tuple[Optional[_IntOrRange], Optional[_IntOrRange]], 

4298 ) -> typing_Tuple[_IntOrRange, _IntOrRange]: 

4299 if not isinstance(range_, tuple) or len(range_) != 2: 

4300 raise exc.ArgumentError("2-tuple expected for range/rows") 

4301 

4302 r0, r1 = range_ 

4303 

4304 lower: _IntOrRange 

4305 upper: _IntOrRange 

4306 

4307 if r0 is None: 

4308 lower = RANGE_UNBOUNDED 

4309 elif isinstance(r0, _OverRange): 

4310 lower = r0 

4311 else: 

4312 try: 

4313 lower = int(r0) 

4314 except ValueError as err: 

4315 raise exc.ArgumentError( 

4316 "Integer or None expected for range value" 

4317 ) from err 

4318 else: 

4319 if lower == 0: 

4320 lower = RANGE_CURRENT 

4321 

4322 if r1 is None: 

4323 upper = RANGE_UNBOUNDED 

4324 elif isinstance(r1, _OverRange): 

4325 upper = r1 

4326 else: 

4327 try: 

4328 upper = int(r1) 

4329 except ValueError as err: 

4330 raise exc.ArgumentError( 

4331 "Integer or None expected for range value" 

4332 ) from err 

4333 else: 

4334 if upper == 0: 

4335 upper = RANGE_CURRENT 

4336 

4337 return lower, upper 

4338 

4339 if not TYPE_CHECKING: 

4340 

4341 @util.memoized_property 

4342 def type(self) -> TypeEngine[_T]: # noqa: A001 

4343 return self.element.type 

4344 

4345 @util.ro_non_memoized_property 

4346 def _from_objects(self) -> List[FromClause]: 

4347 return list( 

4348 itertools.chain( 

4349 *[ 

4350 c._from_objects 

4351 for c in (self.element, self.partition_by, self.order_by) 

4352 if c is not None 

4353 ] 

4354 ) 

4355 ) 

4356 

4357 

4358class WithinGroup(ColumnElement[_T]): 

4359 """Represent a WITHIN GROUP (ORDER BY) clause. 

4360 

4361 This is a special operator against so-called 

4362 "ordered set aggregate" and "hypothetical 

4363 set aggregate" functions, including ``percentile_cont()``, 

4364 ``rank()``, ``dense_rank()``, etc. 

4365 

4366 It's supported only by certain database backends, such as PostgreSQL, 

4367 Oracle Database and MS SQL Server. 

4368 

4369 The :class:`.WithinGroup` construct extracts its type from the 

4370 method :meth:`.FunctionElement.within_group_type`. If this returns 

4371 ``None``, the function's ``.type`` is used. 

4372 

4373 """ 

4374 

4375 __visit_name__ = "withingroup" 

4376 

4377 _traverse_internals: _TraverseInternalsType = [ 

4378 ("element", InternalTraversal.dp_clauseelement), 

4379 ("order_by", InternalTraversal.dp_clauseelement), 

4380 ] 

4381 

4382 order_by: Optional[ClauseList] = None 

4383 

4384 def __init__( 

4385 self, 

4386 element: Union[FunctionElement[_T], FunctionFilter[_T]], 

4387 *order_by: _ColumnExpressionArgument[Any], 

4388 ): 

4389 self.element = element 

4390 if order_by is not None: 

4391 self.order_by = ClauseList( 

4392 *util.to_list(order_by), _literal_as_text_role=roles.ByOfRole 

4393 ) 

4394 

4395 def __reduce__(self): 

4396 return self.__class__, (self.element,) + ( 

4397 tuple(self.order_by) if self.order_by is not None else () 

4398 ) 

4399 

4400 def over( 

4401 self, 

4402 *, 

4403 partition_by: Optional[_ByArgument] = None, 

4404 order_by: Optional[_ByArgument] = None, 

4405 rows: Optional[typing_Tuple[Optional[int], Optional[int]]] = None, 

4406 range_: Optional[typing_Tuple[Optional[int], Optional[int]]] = None, 

4407 groups: Optional[typing_Tuple[Optional[int], Optional[int]]] = None, 

4408 ) -> Over[_T]: 

4409 """Produce an OVER clause against this :class:`.WithinGroup` 

4410 construct. 

4411 

4412 This function has the same signature as that of 

4413 :meth:`.FunctionElement.over`. 

4414 

4415 """ 

4416 return Over( 

4417 self, 

4418 partition_by=partition_by, 

4419 order_by=order_by, 

4420 range_=range_, 

4421 rows=rows, 

4422 groups=groups, 

4423 ) 

4424 

4425 @overload 

4426 def filter(self) -> Self: ... 

4427 

4428 @overload 

4429 def filter( 

4430 self, 

4431 __criterion0: _ColumnExpressionArgument[bool], 

4432 *criterion: _ColumnExpressionArgument[bool], 

4433 ) -> FunctionFilter[_T]: ... 

4434 

4435 def filter( 

4436 self, *criterion: _ColumnExpressionArgument[bool] 

4437 ) -> Union[Self, FunctionFilter[_T]]: 

4438 """Produce a FILTER clause against this function.""" 

4439 if not criterion: 

4440 return self 

4441 return FunctionFilter(self, *criterion) 

4442 

4443 if not TYPE_CHECKING: 

4444 

4445 @util.memoized_property 

4446 def type(self) -> TypeEngine[_T]: # noqa: A001 

4447 wgt = self.element.within_group_type(self) 

4448 if wgt is not None: 

4449 return wgt 

4450 else: 

4451 return self.element.type 

4452 

4453 @util.ro_non_memoized_property 

4454 def _from_objects(self) -> List[FromClause]: 

4455 return list( 

4456 itertools.chain( 

4457 *[ 

4458 c._from_objects 

4459 for c in (self.element, self.order_by) 

4460 if c is not None 

4461 ] 

4462 ) 

4463 ) 

4464 

4465 

4466class FunctionFilter(Generative, ColumnElement[_T]): 

4467 """Represent a function FILTER clause. 

4468 

4469 This is a special operator against aggregate and window functions, 

4470 which controls which rows are passed to it. 

4471 It's supported only by certain database backends. 

4472 

4473 Invocation of :class:`.FunctionFilter` is via 

4474 :meth:`.FunctionElement.filter`:: 

4475 

4476 func.count(1).filter(True) 

4477 

4478 .. seealso:: 

4479 

4480 :meth:`.FunctionElement.filter` 

4481 

4482 """ 

4483 

4484 __visit_name__ = "funcfilter" 

4485 

4486 _traverse_internals: _TraverseInternalsType = [ 

4487 ("func", InternalTraversal.dp_clauseelement), 

4488 ("criterion", InternalTraversal.dp_clauseelement), 

4489 ] 

4490 

4491 criterion: Optional[ColumnElement[bool]] = None 

4492 

4493 def __init__( 

4494 self, 

4495 func: Union[FunctionElement[_T], WithinGroup[_T]], 

4496 *criterion: _ColumnExpressionArgument[bool], 

4497 ): 

4498 self.func = func 

4499 self.filter.non_generative(self, *criterion) # type: ignore 

4500 

4501 @_generative 

4502 def filter(self, *criterion: _ColumnExpressionArgument[bool]) -> Self: 

4503 """Produce an additional FILTER against the function. 

4504 

4505 This method adds additional criteria to the initial criteria 

4506 set up by :meth:`.FunctionElement.filter`. 

4507 

4508 Multiple criteria are joined together at SQL render time 

4509 via ``AND``. 

4510 

4511 

4512 """ 

4513 

4514 for crit in list(criterion): 

4515 crit = coercions.expect(roles.WhereHavingRole, crit) 

4516 

4517 if self.criterion is not None: 

4518 self.criterion = self.criterion & crit 

4519 else: 

4520 self.criterion = crit 

4521 

4522 return self 

4523 

4524 def over( 

4525 self, 

4526 partition_by: Optional[ 

4527 Union[ 

4528 Iterable[_ColumnExpressionArgument[Any]], 

4529 _ColumnExpressionArgument[Any], 

4530 ] 

4531 ] = None, 

4532 order_by: Optional[ 

4533 Union[ 

4534 Iterable[_ColumnExpressionArgument[Any]], 

4535 _ColumnExpressionArgument[Any], 

4536 ] 

4537 ] = None, 

4538 range_: Optional[typing_Tuple[Optional[int], Optional[int]]] = None, 

4539 rows: Optional[typing_Tuple[Optional[int], Optional[int]]] = None, 

4540 groups: Optional[typing_Tuple[Optional[int], Optional[int]]] = None, 

4541 ) -> Over[_T]: 

4542 """Produce an OVER clause against this filtered function. 

4543 

4544 Used against aggregate or so-called "window" functions, 

4545 for database backends that support window functions. 

4546 

4547 The expression:: 

4548 

4549 func.rank().filter(MyClass.y > 5).over(order_by="x") 

4550 

4551 is shorthand for:: 

4552 

4553 from sqlalchemy import over, funcfilter 

4554 

4555 over(funcfilter(func.rank(), MyClass.y > 5), order_by="x") 

4556 

4557 See :func:`_expression.over` for a full description. 

4558 

4559 """ 

4560 return Over( 

4561 self, 

4562 partition_by=partition_by, 

4563 order_by=order_by, 

4564 range_=range_, 

4565 rows=rows, 

4566 groups=groups, 

4567 ) 

4568 

4569 def within_group( 

4570 self, *order_by: _ColumnExpressionArgument[Any] 

4571 ) -> WithinGroup[_T]: 

4572 """Produce a WITHIN GROUP (ORDER BY expr) clause against 

4573 this function. 

4574 """ 

4575 return WithinGroup(self, *order_by) 

4576 

4577 def within_group_type( 

4578 self, within_group: WithinGroup[_T] 

4579 ) -> Optional[TypeEngine[_T]]: 

4580 return None 

4581 

4582 def self_group( 

4583 self, against: Optional[OperatorType] = None 

4584 ) -> Union[Self, Grouping[_T]]: 

4585 if operators.is_precedent(operators.filter_op, against): 

4586 return Grouping(self) 

4587 else: 

4588 return self 

4589 

4590 if not TYPE_CHECKING: 

4591 

4592 @util.memoized_property 

4593 def type(self) -> TypeEngine[_T]: # noqa: A001 

4594 return self.func.type 

4595 

4596 @util.ro_non_memoized_property 

4597 def _from_objects(self) -> List[FromClause]: 

4598 return list( 

4599 itertools.chain( 

4600 *[ 

4601 c._from_objects 

4602 for c in (self.func, self.criterion) 

4603 if c is not None 

4604 ] 

4605 ) 

4606 ) 

4607 

4608 

4609class NamedColumn(KeyedColumnElement[_T]): 

4610 is_literal = False 

4611 table: Optional[FromClause] = None 

4612 name: str 

4613 key: str 

4614 

4615 def _compare_name_for_result(self, other): 

4616 return (hasattr(other, "name") and self.name == other.name) or ( 

4617 hasattr(other, "_label") and self._label == other._label 

4618 ) 

4619 

4620 @util.ro_memoized_property 

4621 def description(self) -> str: 

4622 return self.name 

4623 

4624 @HasMemoized.memoized_attribute 

4625 def _tq_key_label(self) -> Optional[str]: 

4626 """table qualified label based on column key. 

4627 

4628 for table-bound columns this is <tablename>_<column key/proxy key>; 

4629 

4630 all other expressions it resolves to key/proxy key. 

4631 

4632 """ 

4633 proxy_key = self._proxy_key 

4634 if proxy_key and proxy_key != self.name: 

4635 return self._gen_tq_label(proxy_key) 

4636 else: 

4637 return self._tq_label 

4638 

4639 @HasMemoized.memoized_attribute 

4640 def _tq_label(self) -> Optional[str]: 

4641 """table qualified label based on column name. 

4642 

4643 for table-bound columns this is <tablename>_<columnname>; all other 

4644 expressions it resolves to .name. 

4645 

4646 """ 

4647 return self._gen_tq_label(self.name) 

4648 

4649 @HasMemoized.memoized_attribute 

4650 def _render_label_in_columns_clause(self): 

4651 return True 

4652 

4653 @HasMemoized.memoized_attribute 

4654 def _non_anon_label(self): 

4655 return self.name 

4656 

4657 def _gen_tq_label( 

4658 self, name: str, dedupe_on_key: bool = True 

4659 ) -> Optional[str]: 

4660 return name 

4661 

4662 def _bind_param( 

4663 self, 

4664 operator: OperatorType, 

4665 obj: Any, 

4666 type_: Optional[TypeEngine[_T]] = None, 

4667 expanding: bool = False, 

4668 ) -> BindParameter[_T]: 

4669 return BindParameter( 

4670 self.key, 

4671 obj, 

4672 _compared_to_operator=operator, 

4673 _compared_to_type=self.type, 

4674 type_=type_, 

4675 unique=True, 

4676 expanding=expanding, 

4677 ) 

4678 

4679 def _make_proxy( 

4680 self, 

4681 selectable: FromClause, 

4682 *, 

4683 primary_key: ColumnSet, 

4684 foreign_keys: Set[KeyedColumnElement[Any]], 

4685 name: Optional[str] = None, 

4686 key: Optional[str] = None, 

4687 name_is_truncatable: bool = False, 

4688 compound_select_cols: Optional[Sequence[ColumnElement[Any]]] = None, 

4689 disallow_is_literal: bool = False, 

4690 **kw: Any, 

4691 ) -> typing_Tuple[str, ColumnClause[_T]]: 

4692 c = ColumnClause( 

4693 ( 

4694 coercions.expect(roles.TruncatedLabelRole, name or self.name) 

4695 if name_is_truncatable 

4696 else (name or self.name) 

4697 ), 

4698 type_=self.type, 

4699 _selectable=selectable, 

4700 is_literal=False, 

4701 ) 

4702 

4703 c._propagate_attrs = selectable._propagate_attrs 

4704 if name is None: 

4705 c.key = self.key 

4706 if compound_select_cols: 

4707 c._proxies = list(compound_select_cols) 

4708 else: 

4709 c._proxies = [self] 

4710 

4711 if selectable._is_clone_of is not None: 

4712 c._is_clone_of = selectable._is_clone_of.columns.get(c.key) 

4713 return c.key, c 

4714 

4715 

4716_PS = ParamSpec("_PS") 

4717 

4718 

4719class Label(roles.LabeledColumnExprRole[_T], NamedColumn[_T]): 

4720 """Represents a column label (AS). 

4721 

4722 Represent a label, as typically applied to any column-level 

4723 element using the ``AS`` sql keyword. 

4724 

4725 """ 

4726 

4727 __visit_name__ = "label" 

4728 

4729 _traverse_internals: _TraverseInternalsType = [ 

4730 ("name", InternalTraversal.dp_anon_name), 

4731 ("type", InternalTraversal.dp_type), 

4732 ("_element", InternalTraversal.dp_clauseelement), 

4733 ] 

4734 

4735 _cache_key_traversal = [ 

4736 ("name", InternalTraversal.dp_anon_name), 

4737 ("_element", InternalTraversal.dp_clauseelement), 

4738 ] 

4739 

4740 _element: ColumnElement[_T] 

4741 name: str 

4742 

4743 def __init__( 

4744 self, 

4745 name: Optional[str], 

4746 element: _ColumnExpressionArgument[_T], 

4747 type_: Optional[_TypeEngineArgument[_T]] = None, 

4748 ): 

4749 orig_element = element 

4750 element = coercions.expect( 

4751 roles.ExpressionElementRole, 

4752 element, 

4753 apply_propagate_attrs=self, 

4754 ) 

4755 while isinstance(element, Label): 

4756 # TODO: this is only covered in test_text.py, but nothing 

4757 # fails if it's removed. determine rationale 

4758 element = element.element 

4759 

4760 if name: 

4761 self.name = name 

4762 else: 

4763 self.name = _anonymous_label.safe_construct( 

4764 id(self), getattr(element, "name", "anon") 

4765 ) 

4766 if isinstance(orig_element, Label): 

4767 # TODO: no coverage for this block, again would be in 

4768 # test_text.py where the resolve_label concept is important 

4769 self._resolve_label = orig_element._label 

4770 

4771 self.key = self._tq_label = self._tq_key_label = self.name 

4772 self._element = element 

4773 

4774 self.type = ( 

4775 type_api.to_instance(type_) 

4776 if type_ is not None 

4777 else self._element.type 

4778 ) 

4779 

4780 self._proxies = [element] 

4781 

4782 def __reduce__(self): 

4783 return self.__class__, (self.name, self._element, self.type) 

4784 

4785 @HasMemoized.memoized_attribute 

4786 def _render_label_in_columns_clause(self): 

4787 return True 

4788 

4789 def _bind_param(self, operator, obj, type_=None, expanding=False): 

4790 return BindParameter( 

4791 None, 

4792 obj, 

4793 _compared_to_operator=operator, 

4794 type_=type_, 

4795 _compared_to_type=self.type, 

4796 unique=True, 

4797 expanding=expanding, 

4798 ) 

4799 

4800 @util.memoized_property 

4801 def _is_implicitly_boolean(self): 

4802 return self.element._is_implicitly_boolean 

4803 

4804 @HasMemoized.memoized_attribute 

4805 def _allow_label_resolve(self): 

4806 return self.element._allow_label_resolve 

4807 

4808 @property 

4809 def _order_by_label_element(self): 

4810 return self 

4811 

4812 @HasMemoized.memoized_attribute 

4813 def element(self) -> ColumnElement[_T]: 

4814 return self._element.self_group(against=operators.as_) 

4815 

4816 def self_group(self, against: Optional[OperatorType] = None) -> Label[_T]: 

4817 return self._apply_to_inner(self._element.self_group, against=against) 

4818 

4819 def _negate(self): 

4820 return self._apply_to_inner(self._element._negate) 

4821 

4822 def _apply_to_inner( 

4823 self, 

4824 fn: Callable[_PS, ColumnElement[_T]], 

4825 *arg: _PS.args, 

4826 **kw: _PS.kwargs, 

4827 ) -> Label[_T]: 

4828 sub_element = fn(*arg, **kw) 

4829 if sub_element is not self._element: 

4830 return Label(self.name, sub_element, type_=self.type) 

4831 else: 

4832 return self 

4833 

4834 @property 

4835 def primary_key(self): # type: ignore[override] 

4836 return self.element.primary_key 

4837 

4838 @property 

4839 def foreign_keys(self): # type: ignore[override] 

4840 return self.element.foreign_keys 

4841 

4842 def _copy_internals( 

4843 self, 

4844 *, 

4845 clone: _CloneCallableType = _clone, 

4846 anonymize_labels: bool = False, 

4847 **kw: Any, 

4848 ) -> None: 

4849 self._reset_memoizations() 

4850 self._element = clone(self._element, **kw) 

4851 if anonymize_labels: 

4852 self.name = _anonymous_label.safe_construct( 

4853 id(self), getattr(self.element, "name", "anon") 

4854 ) 

4855 self.key = self._tq_label = self._tq_key_label = self.name 

4856 

4857 @util.ro_non_memoized_property 

4858 def _from_objects(self) -> List[FromClause]: 

4859 return self.element._from_objects 

4860 

4861 def _make_proxy( 

4862 self, 

4863 selectable: FromClause, 

4864 *, 

4865 primary_key: ColumnSet, 

4866 foreign_keys: Set[KeyedColumnElement[Any]], 

4867 name: Optional[str] = None, 

4868 compound_select_cols: Optional[Sequence[ColumnElement[Any]]] = None, 

4869 **kw: Any, 

4870 ) -> typing_Tuple[str, ColumnClause[_T]]: 

4871 name = self.name if not name else name 

4872 

4873 key, e = self.element._make_proxy( 

4874 selectable, 

4875 name=name, 

4876 disallow_is_literal=True, 

4877 name_is_truncatable=isinstance(name, _truncated_label), 

4878 compound_select_cols=compound_select_cols, 

4879 primary_key=primary_key, 

4880 foreign_keys=foreign_keys, 

4881 ) 

4882 

4883 # there was a note here to remove this assertion, which was here 

4884 # to determine if we later could support a use case where 

4885 # the key and name of a label are separate. But I don't know what 

4886 # that case was. For now, this is an unexpected case that occurs 

4887 # when a label name conflicts with other columns and select() 

4888 # is attempting to disambiguate an explicit label, which is not what 

4889 # the user would want. See issue #6090. 

4890 if key != self.name and not isinstance(self.name, _anonymous_label): 

4891 raise exc.InvalidRequestError( 

4892 "Label name %s is being renamed to an anonymous label due " 

4893 "to disambiguation " 

4894 "which is not supported right now. Please use unique names " 

4895 "for explicit labels." % (self.name) 

4896 ) 

4897 

4898 e._propagate_attrs = selectable._propagate_attrs 

4899 e._proxies.append(self) 

4900 if self.type is not None: 

4901 e.type = self.type 

4902 

4903 return self.key, e 

4904 

4905 

4906class ColumnClause( 

4907 roles.DDLReferredColumnRole, 

4908 roles.LabeledColumnExprRole[_T], 

4909 roles.StrAsPlainColumnRole, 

4910 Immutable, 

4911 NamedColumn[_T], 

4912): 

4913 """Represents a column expression from any textual string. 

4914 

4915 The :class:`.ColumnClause`, a lightweight analogue to the 

4916 :class:`_schema.Column` class, is typically invoked using the 

4917 :func:`_expression.column` function, as in:: 

4918 

4919 from sqlalchemy import column 

4920 

4921 id, name = column("id"), column("name") 

4922 stmt = select(id, name).select_from("user") 

4923 

4924 The above statement would produce SQL like: 

4925 

4926 .. sourcecode:: sql 

4927 

4928 SELECT id, name FROM user 

4929 

4930 :class:`.ColumnClause` is the immediate superclass of the schema-specific 

4931 :class:`_schema.Column` object. While the :class:`_schema.Column` 

4932 class has all the 

4933 same capabilities as :class:`.ColumnClause`, the :class:`.ColumnClause` 

4934 class is usable by itself in those cases where behavioral requirements 

4935 are limited to simple SQL expression generation. The object has none of 

4936 the associations with schema-level metadata or with execution-time 

4937 behavior that :class:`_schema.Column` does, 

4938 so in that sense is a "lightweight" 

4939 version of :class:`_schema.Column`. 

4940 

4941 Full details on :class:`.ColumnClause` usage is at 

4942 :func:`_expression.column`. 

4943 

4944 .. seealso:: 

4945 

4946 :func:`_expression.column` 

4947 

4948 :class:`_schema.Column` 

4949 

4950 """ 

4951 

4952 table: Optional[FromClause] 

4953 is_literal: bool 

4954 

4955 __visit_name__ = "column" 

4956 

4957 _traverse_internals: _TraverseInternalsType = [ 

4958 ("name", InternalTraversal.dp_anon_name), 

4959 ("type", InternalTraversal.dp_type), 

4960 ("table", InternalTraversal.dp_clauseelement), 

4961 ("is_literal", InternalTraversal.dp_boolean), 

4962 ] 

4963 

4964 onupdate: Optional[DefaultGenerator] = None 

4965 default: Optional[DefaultGenerator] = None 

4966 server_default: Optional[FetchedValue] = None 

4967 server_onupdate: Optional[FetchedValue] = None 

4968 

4969 _is_multiparam_column = False 

4970 

4971 @property 

4972 def _is_star(self): # type: ignore[override] 

4973 return self.is_literal and self.name == "*" 

4974 

4975 def __init__( 

4976 self, 

4977 text: str, 

4978 type_: Optional[_TypeEngineArgument[_T]] = None, 

4979 is_literal: bool = False, 

4980 _selectable: Optional[FromClause] = None, 

4981 ): 

4982 self.key = self.name = text 

4983 self.table = _selectable 

4984 

4985 # if type is None, we get NULLTYPE, which is our _T. But I don't 

4986 # know how to get the overloads to express that correctly 

4987 self.type = type_api.to_instance(type_) # type: ignore 

4988 

4989 self.is_literal = is_literal 

4990 

4991 def get_children(self, *, column_tables=False, **kw): 

4992 # override base get_children() to not return the Table 

4993 # or selectable that is parent to this column. Traversals 

4994 # expect the columns of tables and subqueries to be leaf nodes. 

4995 return [] 

4996 

4997 @property 

4998 def entity_namespace(self): 

4999 if self.table is not None: 

5000 return self.table.entity_namespace 

5001 else: 

5002 return super().entity_namespace 

5003 

5004 def _clone(self, detect_subquery_cols=False, **kw): 

5005 if ( 

5006 detect_subquery_cols 

5007 and self.table is not None 

5008 and self.table._is_subquery 

5009 ): 

5010 clone = kw.pop("clone") 

5011 table = clone(self.table, **kw) 

5012 new = table.c.corresponding_column(self) 

5013 return new 

5014 

5015 return super()._clone(**kw) 

5016 

5017 @HasMemoized_ro_memoized_attribute 

5018 def _from_objects(self) -> List[FromClause]: 

5019 t = self.table 

5020 if t is not None: 

5021 return [t] 

5022 else: 

5023 return [] 

5024 

5025 @HasMemoized.memoized_attribute 

5026 def _render_label_in_columns_clause(self): 

5027 return self.table is not None 

5028 

5029 @property 

5030 def _ddl_label(self): 

5031 return self._gen_tq_label(self.name, dedupe_on_key=False) 

5032 

5033 def _compare_name_for_result(self, other): 

5034 if ( 

5035 self.is_literal 

5036 or self.table is None 

5037 or self.table._is_textual 

5038 or not hasattr(other, "proxy_set") 

5039 or ( 

5040 isinstance(other, ColumnClause) 

5041 and ( 

5042 other.is_literal 

5043 or other.table is None 

5044 or other.table._is_textual 

5045 ) 

5046 ) 

5047 ): 

5048 return (hasattr(other, "name") and self.name == other.name) or ( 

5049 hasattr(other, "_tq_label") 

5050 and self._tq_label == other._tq_label 

5051 ) 

5052 else: 

5053 return other.proxy_set.intersection(self.proxy_set) 

5054 

5055 def _gen_tq_label( 

5056 self, name: str, dedupe_on_key: bool = True 

5057 ) -> Optional[str]: 

5058 """generate table-qualified label 

5059 

5060 for a table-bound column this is <tablename>_<columnname>. 

5061 

5062 used primarily for LABEL_STYLE_TABLENAME_PLUS_COL 

5063 as well as the .columns collection on a Join object. 

5064 

5065 """ 

5066 label: str 

5067 t = self.table 

5068 if self.is_literal: 

5069 return None 

5070 elif t is not None and is_named_from_clause(t): 

5071 if has_schema_attr(t) and t.schema: 

5072 label = t.schema.replace(".", "_") + "_" + t.name + "_" + name 

5073 else: 

5074 assert not TYPE_CHECKING or isinstance(t, NamedFromClause) 

5075 label = t.name + "_" + name 

5076 

5077 # propagate name quoting rules for labels. 

5078 if is_quoted_name(name) and name.quote is not None: 

5079 if is_quoted_name(label): 

5080 label.quote = name.quote 

5081 else: 

5082 label = quoted_name(label, name.quote) 

5083 elif is_quoted_name(t.name) and t.name.quote is not None: 

5084 # can't get this situation to occur, so let's 

5085 # assert false on it for now 

5086 assert not isinstance(label, quoted_name) 

5087 label = quoted_name(label, t.name.quote) 

5088 

5089 if dedupe_on_key: 

5090 # ensure the label name doesn't conflict with that of an 

5091 # existing column. note that this implies that any Column 

5092 # must **not** set up its _label before its parent table has 

5093 # all of its other Column objects set up. There are several 

5094 # tables in the test suite which will fail otherwise; example: 

5095 # table "owner" has columns "name" and "owner_name". Therefore 

5096 # column owner.name cannot use the label "owner_name", it has 

5097 # to be "owner_name_1". 

5098 if label in t.c: 

5099 _label = label 

5100 counter = 1 

5101 while _label in t.c: 

5102 _label = label + "_" + str(counter) 

5103 counter += 1 

5104 label = _label 

5105 

5106 return coercions.expect(roles.TruncatedLabelRole, label) 

5107 

5108 else: 

5109 return name 

5110 

5111 def _make_proxy( 

5112 self, 

5113 selectable: FromClause, 

5114 *, 

5115 primary_key: ColumnSet, 

5116 foreign_keys: Set[KeyedColumnElement[Any]], 

5117 name: Optional[str] = None, 

5118 key: Optional[str] = None, 

5119 name_is_truncatable: bool = False, 

5120 compound_select_cols: Optional[Sequence[ColumnElement[Any]]] = None, 

5121 disallow_is_literal: bool = False, 

5122 **kw: Any, 

5123 ) -> typing_Tuple[str, ColumnClause[_T]]: 

5124 # the "is_literal" flag normally should never be propagated; a proxied 

5125 # column is always a SQL identifier and never the actual expression 

5126 # being evaluated. however, there is a case where the "is_literal" flag 

5127 # might be used to allow the given identifier to have a fixed quoting 

5128 # pattern already, so maintain the flag for the proxy unless a 

5129 # :class:`.Label` object is creating the proxy. See [ticket:4730]. 

5130 is_literal = ( 

5131 not disallow_is_literal 

5132 and self.is_literal 

5133 and ( 

5134 # note this does not accommodate for quoted_name differences 

5135 # right now 

5136 name is None 

5137 or name == self.name 

5138 ) 

5139 ) 

5140 c = self._constructor( 

5141 ( 

5142 coercions.expect(roles.TruncatedLabelRole, name or self.name) 

5143 if name_is_truncatable 

5144 else (name or self.name) 

5145 ), 

5146 type_=self.type, 

5147 _selectable=selectable, 

5148 is_literal=is_literal, 

5149 ) 

5150 c._propagate_attrs = selectable._propagate_attrs 

5151 if name is None: 

5152 c.key = self.key 

5153 if compound_select_cols: 

5154 c._proxies = list(compound_select_cols) 

5155 else: 

5156 c._proxies = [self] 

5157 

5158 if selectable._is_clone_of is not None: 

5159 c._is_clone_of = selectable._is_clone_of.columns.get(c.key) 

5160 return c.key, c 

5161 

5162 

5163class TableValuedColumn(NamedColumn[_T]): 

5164 __visit_name__ = "table_valued_column" 

5165 

5166 _traverse_internals: _TraverseInternalsType = [ 

5167 ("name", InternalTraversal.dp_anon_name), 

5168 ("type", InternalTraversal.dp_type), 

5169 ("scalar_alias", InternalTraversal.dp_clauseelement), 

5170 ] 

5171 

5172 def __init__(self, scalar_alias: NamedFromClause, type_: TypeEngine[_T]): 

5173 self.scalar_alias = scalar_alias 

5174 self.key = self.name = scalar_alias.name 

5175 self.type = type_ 

5176 

5177 def _copy_internals( 

5178 self, clone: _CloneCallableType = _clone, **kw: Any 

5179 ) -> None: 

5180 self.scalar_alias = clone(self.scalar_alias, **kw) 

5181 self.key = self.name = self.scalar_alias.name 

5182 

5183 @util.ro_non_memoized_property 

5184 def _from_objects(self) -> List[FromClause]: 

5185 return [self.scalar_alias] 

5186 

5187 

5188class CollationClause(ColumnElement[str]): 

5189 __visit_name__ = "collation" 

5190 

5191 _traverse_internals: _TraverseInternalsType = [ 

5192 ("collation", InternalTraversal.dp_string) 

5193 ] 

5194 

5195 @classmethod 

5196 @util.preload_module("sqlalchemy.sql.sqltypes") 

5197 def _create_collation_expression( 

5198 cls, expression: _ColumnExpressionArgument[str], collation: str 

5199 ) -> BinaryExpression[str]: 

5200 

5201 sqltypes = util.preloaded.sql_sqltypes 

5202 

5203 expr = coercions.expect(roles.ExpressionElementRole[str], expression) 

5204 

5205 if expr.type._type_affinity is sqltypes.String: 

5206 collate_type = expr.type._with_collation(collation) 

5207 else: 

5208 collate_type = expr.type 

5209 

5210 return BinaryExpression( 

5211 expr, 

5212 CollationClause(collation), 

5213 operators.collate, 

5214 type_=collate_type, 

5215 ) 

5216 

5217 def __init__(self, collation): 

5218 self.collation = collation 

5219 

5220 

5221class _IdentifiedClause(Executable, ClauseElement): 

5222 __visit_name__ = "identified" 

5223 

5224 def __init__(self, ident): 

5225 self.ident = ident 

5226 

5227 

5228class SavepointClause(_IdentifiedClause): 

5229 __visit_name__ = "savepoint" 

5230 inherit_cache = False 

5231 

5232 

5233class RollbackToSavepointClause(_IdentifiedClause): 

5234 __visit_name__ = "rollback_to_savepoint" 

5235 inherit_cache = False 

5236 

5237 

5238class ReleaseSavepointClause(_IdentifiedClause): 

5239 __visit_name__ = "release_savepoint" 

5240 inherit_cache = False 

5241 

5242 

5243class quoted_name(util.MemoizedSlots, str): 

5244 """Represent a SQL identifier combined with quoting preferences. 

5245 

5246 :class:`.quoted_name` is a Python unicode/str subclass which 

5247 represents a particular identifier name along with a 

5248 ``quote`` flag. This ``quote`` flag, when set to 

5249 ``True`` or ``False``, overrides automatic quoting behavior 

5250 for this identifier in order to either unconditionally quote 

5251 or to not quote the name. If left at its default of ``None``, 

5252 quoting behavior is applied to the identifier on a per-backend basis 

5253 based on an examination of the token itself. 

5254 

5255 A :class:`.quoted_name` object with ``quote=True`` is also 

5256 prevented from being modified in the case of a so-called 

5257 "name normalize" option. Certain database backends, such as 

5258 Oracle Database, Firebird, and DB2 "normalize" case-insensitive names 

5259 as uppercase. The SQLAlchemy dialects for these backends 

5260 convert from SQLAlchemy's lower-case-means-insensitive convention 

5261 to the upper-case-means-insensitive conventions of those backends. 

5262 The ``quote=True`` flag here will prevent this conversion from occurring 

5263 to support an identifier that's quoted as all lower case against 

5264 such a backend. 

5265 

5266 The :class:`.quoted_name` object is normally created automatically 

5267 when specifying the name for key schema constructs such as 

5268 :class:`_schema.Table`, :class:`_schema.Column`, and others. 

5269 The class can also be 

5270 passed explicitly as the name to any function that receives a name which 

5271 can be quoted. Such as to use the :meth:`_engine.Engine.has_table` 

5272 method with 

5273 an unconditionally quoted name:: 

5274 

5275 from sqlalchemy import create_engine 

5276 from sqlalchemy import inspect 

5277 from sqlalchemy.sql import quoted_name 

5278 

5279 engine = create_engine("oracle+oracledb://some_dsn") 

5280 print(inspect(engine).has_table(quoted_name("some_table", True))) 

5281 

5282 The above logic will run the "has table" logic against the Oracle Database 

5283 backend, passing the name exactly as ``"some_table"`` without converting to 

5284 upper case. 

5285 

5286 .. versionchanged:: 1.2 The :class:`.quoted_name` construct is now 

5287 importable from ``sqlalchemy.sql``, in addition to the previous 

5288 location of ``sqlalchemy.sql.elements``. 

5289 

5290 """ 

5291 

5292 __slots__ = "quote", "lower", "upper" 

5293 

5294 quote: Optional[bool] 

5295 

5296 @overload 

5297 @classmethod 

5298 def construct(cls, value: str, quote: Optional[bool]) -> quoted_name: ... 

5299 

5300 @overload 

5301 @classmethod 

5302 def construct(cls, value: None, quote: Optional[bool]) -> None: ... 

5303 

5304 @classmethod 

5305 def construct( 

5306 cls, value: Optional[str], quote: Optional[bool] 

5307 ) -> Optional[quoted_name]: 

5308 if value is None: 

5309 return None 

5310 else: 

5311 return quoted_name(value, quote) 

5312 

5313 def __new__(cls, value: str, quote: Optional[bool]) -> quoted_name: 

5314 assert ( 

5315 value is not None 

5316 ), "use quoted_name.construct() for None passthrough" 

5317 if isinstance(value, cls) and (quote is None or value.quote == quote): 

5318 return value 

5319 self = super().__new__(cls, value) 

5320 

5321 self.quote = quote 

5322 return self 

5323 

5324 def __reduce__(self): 

5325 return quoted_name, (str(self), self.quote) 

5326 

5327 def _memoized_method_lower(self): 

5328 if self.quote: 

5329 return self 

5330 else: 

5331 return str(self).lower() 

5332 

5333 def _memoized_method_upper(self): 

5334 if self.quote: 

5335 return self 

5336 else: 

5337 return str(self).upper() 

5338 

5339 

5340def _find_columns(clause: ClauseElement) -> Set[ColumnClause[Any]]: 

5341 """locate Column objects within the given expression.""" 

5342 

5343 cols: Set[ColumnClause[Any]] = set() 

5344 traverse(clause, {}, {"column": cols.add}) 

5345 return cols 

5346 

5347 

5348def _type_from_args(args: Sequence[ColumnElement[_T]]) -> TypeEngine[_T]: 

5349 for a in args: 

5350 if not a.type._isnull: 

5351 return a.type 

5352 else: 

5353 return type_api.NULLTYPE # type: ignore 

5354 

5355 

5356def _corresponding_column_or_error(fromclause, column, require_embedded=False): 

5357 c = fromclause.corresponding_column( 

5358 column, require_embedded=require_embedded 

5359 ) 

5360 if c is None: 

5361 raise exc.InvalidRequestError( 

5362 "Given column '%s', attached to table '%s', " 

5363 "failed to locate a corresponding column from table '%s'" 

5364 % (column, getattr(column, "table", None), fromclause.description) 

5365 ) 

5366 return c 

5367 

5368 

5369class _memoized_property_but_not_nulltype( 

5370 util.memoized_property["TypeEngine[_T]"] 

5371): 

5372 """memoized property, but dont memoize NullType""" 

5373 

5374 def __get__(self, obj, cls): 

5375 if obj is None: 

5376 return self 

5377 result = self.fget(obj) 

5378 if not result._isnull: 

5379 obj.__dict__[self.__name__] = result 

5380 return result 

5381 

5382 

5383class AnnotatedColumnElement(Annotated): 

5384 _Annotated__element: ColumnElement[Any] 

5385 

5386 def __init__(self, element, values): 

5387 Annotated.__init__(self, element, values) 

5388 for attr in ( 

5389 "comparator", 

5390 "_proxy_key", 

5391 "_tq_key_label", 

5392 "_tq_label", 

5393 "_non_anon_label", 

5394 "type", 

5395 ): 

5396 self.__dict__.pop(attr, None) 

5397 for attr in ("name", "key", "table"): 

5398 if self.__dict__.get(attr, False) is None: 

5399 self.__dict__.pop(attr) 

5400 

5401 def _with_annotations(self, values): 

5402 clone = super()._with_annotations(values) 

5403 for attr in ( 

5404 "comparator", 

5405 "_proxy_key", 

5406 "_tq_key_label", 

5407 "_tq_label", 

5408 "_non_anon_label", 

5409 ): 

5410 clone.__dict__.pop(attr, None) 

5411 return clone 

5412 

5413 @util.memoized_property 

5414 def name(self): 

5415 """pull 'name' from parent, if not present""" 

5416 return self._Annotated__element.name 

5417 

5418 @_memoized_property_but_not_nulltype 

5419 def type(self): 

5420 """pull 'type' from parent and don't cache if null. 

5421 

5422 type is routinely changed on existing columns within the 

5423 mapped_column() initialization process, and "type" is also consulted 

5424 during the creation of SQL expressions. Therefore it can change after 

5425 it was already retrieved. At the same time we don't want annotated 

5426 objects having overhead when expressions are produced, so continue 

5427 to memoize, but only when we have a non-null type. 

5428 

5429 """ 

5430 return self._Annotated__element.type 

5431 

5432 @util.memoized_property 

5433 def table(self): 

5434 """pull 'table' from parent, if not present""" 

5435 return self._Annotated__element.table 

5436 

5437 @util.memoized_property 

5438 def key(self): 

5439 """pull 'key' from parent, if not present""" 

5440 return self._Annotated__element.key 

5441 

5442 @util.memoized_property 

5443 def info(self) -> _InfoType: 

5444 if TYPE_CHECKING: 

5445 assert isinstance(self._Annotated__element, Column) 

5446 return self._Annotated__element.info 

5447 

5448 @util.memoized_property 

5449 def _anon_name_label(self) -> str: 

5450 return self._Annotated__element._anon_name_label 

5451 

5452 

5453class _truncated_label(quoted_name): 

5454 """A unicode subclass used to identify symbolic " 

5455 "names that may require truncation.""" 

5456 

5457 __slots__ = () 

5458 

5459 def __new__(cls, value: str, quote: Optional[bool] = None) -> Any: 

5460 quote = getattr(value, "quote", quote) 

5461 # return super(_truncated_label, cls).__new__(cls, value, quote, True) 

5462 return super().__new__(cls, value, quote) 

5463 

5464 def __reduce__(self) -> Any: 

5465 return self.__class__, (str(self), self.quote) 

5466 

5467 def apply_map(self, map_: Mapping[str, Any]) -> str: 

5468 return self 

5469 

5470 

5471class conv(_truncated_label): 

5472 """Mark a string indicating that a name has already been converted 

5473 by a naming convention. 

5474 

5475 This is a string subclass that indicates a name that should not be 

5476 subject to any further naming conventions. 

5477 

5478 E.g. when we create a :class:`.Constraint` using a naming convention 

5479 as follows:: 

5480 

5481 m = MetaData( 

5482 naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"} 

5483 ) 

5484 t = Table( 

5485 "t", m, Column("x", Integer), CheckConstraint("x > 5", name="x5") 

5486 ) 

5487 

5488 The name of the above constraint will be rendered as ``"ck_t_x5"``. 

5489 That is, the existing name ``x5`` is used in the naming convention as the 

5490 ``constraint_name`` token. 

5491 

5492 In some situations, such as in migration scripts, we may be rendering 

5493 the above :class:`.CheckConstraint` with a name that's already been 

5494 converted. In order to make sure the name isn't double-modified, the 

5495 new name is applied using the :func:`_schema.conv` marker. We can 

5496 use this explicitly as follows:: 

5497 

5498 

5499 m = MetaData( 

5500 naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"} 

5501 ) 

5502 t = Table( 

5503 "t", 

5504 m, 

5505 Column("x", Integer), 

5506 CheckConstraint("x > 5", name=conv("ck_t_x5")), 

5507 ) 

5508 

5509 Where above, the :func:`_schema.conv` marker indicates that the constraint 

5510 name here is final, and the name will render as ``"ck_t_x5"`` and not 

5511 ``"ck_t_ck_t_x5"`` 

5512 

5513 .. seealso:: 

5514 

5515 :ref:`constraint_naming_conventions` 

5516 

5517 """ 

5518 

5519 __slots__ = () 

5520 

5521 

5522# for backwards compatibility in case 

5523# someone is re-implementing the 

5524# _truncated_identifier() sequence in a custom 

5525# compiler 

5526_generated_label = _truncated_label 

5527 

5528 

5529class _anonymous_label(_truncated_label): 

5530 """A unicode subclass used to identify anonymously 

5531 generated names.""" 

5532 

5533 __slots__ = () 

5534 

5535 @classmethod 

5536 def safe_construct( 

5537 cls, 

5538 seed: int, 

5539 body: str, 

5540 enclosing_label: Optional[str] = None, 

5541 sanitize_key: bool = False, 

5542 ) -> _anonymous_label: 

5543 # need to escape chars that interfere with format 

5544 # strings in any case, issue #8724 

5545 body = re.sub(r"[%\(\) \$]+", "_", body) 

5546 

5547 if sanitize_key: 

5548 # sanitize_key is then an extra step used by BindParameter 

5549 body = body.strip("_") 

5550 

5551 label = "%%(%d %s)s" % (seed, body.replace("%", "%%")) 

5552 if enclosing_label: 

5553 label = "%s%s" % (enclosing_label, label) 

5554 

5555 return _anonymous_label(label) 

5556 

5557 def __add__(self, other): 

5558 if "%" in other and not isinstance(other, _anonymous_label): 

5559 other = str(other).replace("%", "%%") 

5560 else: 

5561 other = str(other) 

5562 

5563 return _anonymous_label( 

5564 quoted_name( 

5565 str.__add__(self, other), 

5566 self.quote, 

5567 ) 

5568 ) 

5569 

5570 def __radd__(self, other): 

5571 if "%" in other and not isinstance(other, _anonymous_label): 

5572 other = str(other).replace("%", "%%") 

5573 else: 

5574 other = str(other) 

5575 

5576 return _anonymous_label( 

5577 quoted_name( 

5578 str.__add__(other, self), 

5579 self.quote, 

5580 ) 

5581 ) 

5582 

5583 def apply_map(self, map_): 

5584 if self.quote is not None: 

5585 # preserve quoting only if necessary 

5586 return quoted_name(self % map_, self.quote) 

5587 else: 

5588 # else skip the constructor call 

5589 return self % map_