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

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

1826 statements  

1# sql/schema.py 

2# Copyright (C) 2005-2026 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 

8"""The schema module provides the building blocks for database metadata. 

9 

10Each element within this module describes a database entity which can be 

11created and dropped, or is otherwise part of such an entity. Examples include 

12tables, columns, sequences, and indexes. 

13 

14All entities are subclasses of :class:`~sqlalchemy.schema.SchemaItem`, and as 

15defined in this module they are intended to be agnostic of any vendor-specific 

16constructs. 

17 

18A collection of entities are grouped into a unit called 

19:class:`~sqlalchemy.schema.MetaData`. MetaData serves as a logical grouping of 

20schema elements, and can also be associated with an actual database connection 

21such that operations involving the contained elements can contact the database 

22as needed. 

23 

24Two of the elements here also build upon their "syntactic" counterparts, which 

25are defined in :class:`~sqlalchemy.sql.expression.`, specifically 

26:class:`~sqlalchemy.schema.Table` and :class:`~sqlalchemy.schema.Column`. 

27Since these objects are part of the SQL expression language, they are usable 

28as components in SQL expressions. 

29 

30""" 

31 

32from __future__ import annotations 

33 

34from abc import ABC 

35import collections 

36from enum import Enum 

37import operator 

38import typing 

39from typing import Any 

40from typing import Callable 

41from typing import cast 

42from typing import ClassVar 

43from typing import Collection 

44from typing import Dict 

45from typing import Final 

46from typing import Iterable 

47from typing import Iterator 

48from typing import List 

49from typing import Literal 

50from typing import Mapping 

51from typing import NamedTuple 

52from typing import NoReturn 

53from typing import Optional 

54from typing import overload 

55from typing import Protocol 

56from typing import Sequence as _typing_Sequence 

57from typing import Set 

58from typing import Tuple 

59from typing import Type 

60from typing import TYPE_CHECKING 

61from typing import TypedDict 

62from typing import TypeGuard 

63from typing import TypeVar 

64from typing import Union 

65 

66from . import coercions 

67from . import ddl 

68from . import roles 

69from . import type_api 

70from . import visitors 

71from ._annotated_cols import _ColCC_co 

72from ._annotated_cols import _extract_columns_from_class 

73from ._annotated_cols import _TC_co 

74from ._annotated_cols import Named 

75from ._annotated_cols import TypedColumns 

76from ._typing import _T 

77from .base import _DefaultDescriptionTuple 

78from .base import _NoArg 

79from .base import _NoneName 

80from .base import _SentinelColumnCharacterization 

81from .base import _SentinelDefaultCharacterization 

82from .base import DedupeColumnCollection 

83from .base import DialectKWArgs 

84from .base import Executable 

85from .base import SchemaEventTarget as SchemaEventTarget 

86from .base import SchemaVisitable as SchemaVisitable 

87from .base import WriteableColumnCollection 

88from .coercions import _document_text_coercion 

89from .ddl import CheckFirst 

90from .elements import ClauseElement 

91from .elements import ColumnClause 

92from .elements import ColumnElement 

93from .elements import quoted_name 

94from .elements import TextClause 

95from .selectable import TableClause 

96from .type_api import to_instance 

97from .visitors import ExternallyTraversible 

98from .. import event 

99from .. import exc 

100from .. import inspection 

101from .. import util 

102from ..util import HasMemoized 

103from ..util.typing import Self 

104 

105if typing.TYPE_CHECKING: 

106 from ._typing import _AutoIncrementType 

107 from ._typing import _CreateDropBind 

108 from ._typing import _DDLColumnArgument 

109 from ._typing import _DDLColumnReferenceArgument 

110 from ._typing import _InfoType 

111 from ._typing import _TextCoercedExpressionArgument 

112 from ._typing import _TypeEngineArgument 

113 from .base import ColumnSet 

114 from .base import ReadOnlyColumnCollection 

115 from .compiler import DDLCompiler 

116 from .ddl import TableCreateDDL 

117 from .ddl import TableDropDDL 

118 from .elements import BindParameter 

119 from .elements import KeyedColumnElement 

120 from .functions import Function 

121 from .sqltypes import SchemaType 

122 from .type_api import TypeEngine 

123 from .visitors import anon_map 

124 from ..engine import Connection 

125 from ..engine import Engine 

126 from ..engine.interfaces import _CoreMultiExecuteParams 

127 from ..engine.interfaces import CoreExecuteOptionsParameter 

128 from ..engine.interfaces import ExecutionContext 

129 from ..engine.reflection import _ReflectionInfo 

130 from ..sql.selectable import FromClause 

131 

132_SI = TypeVar("_SI", bound="SchemaItem") 

133_TAB = TypeVar("_TAB", bound="Table") 

134 

135 

136_ConstraintNameArgument = Optional[Union[str, _NoneName]] 

137 

138_ServerDefaultArgument = Union[ 

139 "FetchedValue", str, TextClause, ColumnElement[Any] 

140] 

141 

142_ServerOnUpdateArgument = _ServerDefaultArgument 

143 

144 

145class SchemaConst(Enum): 

146 RETAIN_SCHEMA = 1 

147 """Symbol indicating that a :class:`_schema.Table`, :class:`.Sequence` 

148 or in some cases a :class:`_schema.ForeignKey` object, in situations 

149 where the object is being copied for a :meth:`.Table.to_metadata` 

150 operation, should retain the schema name that it already has. 

151 

152 """ 

153 

154 BLANK_SCHEMA = 2 

155 """Symbol indicating that a :class:`_schema.Table` or :class:`.Sequence` 

156 should have 'None' for its schema, even if the parent 

157 :class:`_schema.MetaData` has specified a schema. 

158 

159 .. seealso:: 

160 

161 :paramref:`_schema.MetaData.schema` 

162 

163 :paramref:`_schema.Table.schema` 

164 

165 :paramref:`.Sequence.schema` 

166 

167 """ 

168 

169 NULL_UNSPECIFIED = 3 

170 """Symbol indicating the "nullable" keyword was not passed to a Column. 

171 

172 This is used to distinguish between the use case of passing 

173 ``nullable=None`` to a :class:`.Column`, which has special meaning 

174 on some backends such as SQL Server. 

175 

176 """ 

177 

178 

179RETAIN_SCHEMA: Final[Literal[SchemaConst.RETAIN_SCHEMA]] = ( 

180 SchemaConst.RETAIN_SCHEMA 

181) 

182BLANK_SCHEMA: Final[Literal[SchemaConst.BLANK_SCHEMA]] = ( 

183 SchemaConst.BLANK_SCHEMA 

184) 

185NULL_UNSPECIFIED: Final[Literal[SchemaConst.NULL_UNSPECIFIED]] = ( 

186 SchemaConst.NULL_UNSPECIFIED 

187) 

188 

189 

190def _get_table_key(name: str, schema: Optional[str]) -> str: 

191 if schema is None: 

192 return name 

193 else: 

194 return schema + "." + name 

195 

196 

197# this should really be in sql/util.py but we'd have to 

198# break an import cycle 

199def _copy_expression( 

200 expression: ColumnElement[Any], 

201 source_table: Optional[Table], 

202 target_table: Optional[Table], 

203) -> ColumnElement[Any]: 

204 if source_table is None or target_table is None: 

205 return expression 

206 

207 fixed_source_table = source_table 

208 fixed_target_table = target_table 

209 

210 def replace( 

211 element: ExternallyTraversible, **kw: Any 

212 ) -> Optional[ExternallyTraversible]: 

213 if ( 

214 isinstance(element, Column) 

215 and element.table is fixed_source_table 

216 and element.key in fixed_source_table.c 

217 ): 

218 return fixed_target_table.c[element.key] 

219 else: 

220 return None 

221 

222 return cast( 

223 ColumnElement[Any], 

224 visitors.replacement_traverse(expression, {}, replace), 

225 ) 

226 

227 

228@inspection._self_inspects 

229class SchemaItem(SchemaVisitable): 

230 """Base class for items that define a database schema.""" 

231 

232 __visit_name__ = "schema_item" 

233 

234 create_drop_stringify_dialect = "default" 

235 

236 def _init_items(self, *args: SchemaItem, **kw: Any) -> None: 

237 """Initialize the list of child items for this SchemaItem.""" 

238 for item in args: 

239 if item is not None: 

240 try: 

241 spwd = item._set_parent_with_dispatch 

242 except AttributeError as err: 

243 raise exc.ArgumentError( 

244 "'SchemaItem' object, such as a 'Column' or a " 

245 f"'Constraint' expected, got {item!r}" 

246 ) from err 

247 else: 

248 spwd(self, **kw) 

249 

250 def __repr__(self) -> str: 

251 return util.generic_repr(self, omit_kwarg=["info"]) 

252 

253 @util.memoized_property 

254 def info(self) -> _InfoType: 

255 """Info dictionary associated with the object, allowing user-defined 

256 data to be associated with this :class:`.SchemaItem`. 

257 

258 The dictionary is automatically generated when first accessed. 

259 It can also be specified in the constructor of some objects, 

260 such as :class:`_schema.Table` and :class:`_schema.Column`. 

261 

262 """ 

263 return {} 

264 

265 def _schema_item_copy(self, schema_item: _SI) -> _SI: 

266 if "info" in self.__dict__: 

267 schema_item.info = self.info.copy() 

268 if isinstance(self, DialectKWArgs): 

269 assert isinstance(schema_item, DialectKWArgs) 

270 self._copy_reflect_only_elements(schema_item) 

271 schema_item.dispatch._update(self.dispatch) 

272 return schema_item 

273 

274 _use_schema_map = True 

275 

276 

277class HasConditionalDDL: 

278 """define a class that includes the :meth:`.HasConditionalDDL.ddl_if` 

279 method, allowing for conditional rendering of DDL. 

280 

281 Currently applies to constraints and indexes. 

282 

283 .. versionadded:: 2.0 

284 

285 

286 """ 

287 

288 _ddl_if: Optional[ddl.DDLIf] = None 

289 

290 def ddl_if( 

291 self, 

292 dialect: Optional[str] = None, 

293 callable_: Optional[ddl.DDLIfCallable] = None, 

294 state: Optional[Any] = None, 

295 ) -> Self: 

296 r"""apply a conditional DDL rule to this schema item. 

297 

298 These rules work in a similar manner to the 

299 :meth:`.ExecutableDDLElement.execute_if` callable, with the added 

300 feature that the criteria may be checked within the DDL compilation 

301 phase for a construct such as :class:`.CreateTable`. 

302 :meth:`.HasConditionalDDL.ddl_if` currently applies towards the 

303 :class:`.Index` construct as well as all :class:`.Constraint` 

304 constructs. 

305 

306 :param dialect: string name of a dialect, or a tuple of string names 

307 to indicate multiple dialect types. 

308 

309 :param callable\_: a callable that is constructed using the same form 

310 as that described in 

311 :paramref:`.ExecutableDDLElement.execute_if.callable_`. 

312 

313 :param state: any arbitrary object that will be passed to the 

314 callable, if present. 

315 

316 .. versionadded:: 2.0 

317 

318 .. seealso:: 

319 

320 :ref:`schema_ddl_ddl_if` - background and usage examples 

321 

322 

323 """ 

324 self._ddl_if = ddl.DDLIf(dialect, callable_, state) 

325 return self 

326 

327 

328class HasSchemaAttr(SchemaItem): 

329 """schema item that includes a top-level schema name""" 

330 

331 schema: Optional[str] 

332 

333 

334class Table( 

335 DialectKWArgs, 

336 HasSchemaAttr, 

337 TableClause[_ColCC_co], 

338 inspection.Inspectable["Table"], 

339): 

340 r"""Represent a table in a database. 

341 

342 e.g.:: 

343 

344 from sqlalchemy import Table, MetaData, Integer, String, Column 

345 

346 metadata = MetaData() 

347 

348 mytable = Table( 

349 "mytable", 

350 metadata, 

351 Column("mytable_id", Integer, primary_key=True), 

352 Column("value", String(50)), 

353 ) 

354 

355 The :class:`_schema.Table` 

356 object constructs a unique instance of itself based 

357 on its name and optional schema name within the given 

358 :class:`_schema.MetaData` object. Calling the :class:`_schema.Table` 

359 constructor with the same name and same :class:`_schema.MetaData` argument 

360 a second time will return the *same* :class:`_schema.Table` 

361 object - in this way 

362 the :class:`_schema.Table` constructor acts as a registry function. 

363 

364 May also be defined as "typed table" by passing a subclass of 

365 :class:`_schema.TypedColumns` as the 3rd argument:: 

366 

367 from sqlalchemy import TypedColumns, select 

368 

369 

370 class user_cols(TypedColumns): 

371 id = Column(Integer, primary_key=True) 

372 name: Column[str] 

373 age: Column[int] 

374 middle_name: Column[str | None] 

375 

376 # optional, used to infer the select types when selecting the table 

377 __row_pos__: tuple[int, str, int, str | None] 

378 

379 

380 user = Table("user", metadata, user_cols) 

381 

382 # the columns are typed: the statement has type Select[int, str] 

383 stmt = sa.select(user.c.id, user.c.name).where(user.c.age > 30) 

384 

385 # Inferred as Select[int, str, int, str | None] thanks to __row_pos__ 

386 stmt1 = user.select() 

387 stmt2 = sa.select(user) 

388 

389 The :attr:`sqlalchemy.sql._annotated_cols.HasRowPos.__row_pos__` 

390 annotation is optional, and it's used to infer the types in a 

391 :class:`_sql.Select` when selecting the complete table. 

392 If a :class:`_schema.TypedColumns` does not define it, 

393 the default ``Select[*tuple[Any]]`` will be inferred. 

394 

395 An existing :class:`Table` can be casted as "typed table" using 

396 the :meth:`Table.with_cols`:: 

397 

398 class mytable_cols(TypedColumns): 

399 mytable_id: Column[int] 

400 value: Column[str | None] 

401 

402 

403 typed_mytable = mytable.with_cols(mytable_cols) 

404 

405 .. seealso:: 

406 

407 :ref:`metadata_describing` Introduction to database metadata 

408 

409 :class:`_schema.TypedColumns` More information about typed column 

410 definition 

411 

412 .. versionchanged:: 2.1.0b2 - :class:`_schema.Table` is now generic to 

413 support "typed tables" 

414 """ 

415 

416 __visit_name__ = "table" 

417 

418 if TYPE_CHECKING: 

419 

420 @util.ro_non_memoized_property 

421 def primary_key(self) -> PrimaryKeyConstraint: ... 

422 

423 @util.ro_non_memoized_property 

424 def foreign_keys(self) -> Set[ForeignKey]: ... 

425 

426 def with_cols(self, type_: type[_TC_co]) -> Table[_TC_co]: ... 

427 

428 _columns: DedupeColumnCollection[Column[Any]] # type: ignore[assignment] 

429 

430 _sentinel_column: Optional[Column[Any]] 

431 

432 constraints: Set[Constraint] 

433 """A collection of all :class:`_schema.Constraint` objects associated with 

434 this :class:`_schema.Table`. 

435 

436 Includes :class:`_schema.PrimaryKeyConstraint`, 

437 :class:`_schema.ForeignKeyConstraint`, :class:`_schema.UniqueConstraint`, 

438 :class:`_schema.CheckConstraint`. A separate collection 

439 :attr:`_schema.Table.foreign_key_constraints` refers to the collection 

440 of all :class:`_schema.ForeignKeyConstraint` objects, and the 

441 :attr:`_schema.Table.primary_key` attribute refers to the single 

442 :class:`_schema.PrimaryKeyConstraint` associated with the 

443 :class:`_schema.Table`. 

444 

445 .. seealso:: 

446 

447 :attr:`_schema.Table.constraints` 

448 

449 :attr:`_schema.Table.primary_key` 

450 

451 :attr:`_schema.Table.foreign_key_constraints` 

452 

453 :attr:`_schema.Table.indexes` 

454 

455 :class:`_reflection.Inspector` 

456 

457 

458 """ 

459 

460 indexes: Set[Index] 

461 """A collection of all :class:`_schema.Index` objects associated with this 

462 :class:`_schema.Table`. 

463 

464 .. seealso:: 

465 

466 :meth:`_reflection.Inspector.get_indexes` 

467 

468 """ 

469 

470 def _gen_cache_key( 

471 self, anon_map: anon_map, bindparams: List[BindParameter[Any]] 

472 ) -> Tuple[Any, ...]: 

473 if self._annotations: 

474 return (self,) + self._annotations_cache_key 

475 else: 

476 return (self,) 

477 

478 if not typing.TYPE_CHECKING: 

479 # typing tools seem to be inconsistent in how they handle 

480 # __new__, so suggest this pattern for classes that use 

481 # __new__. apply typing to the __init__ method normally 

482 @util.deprecated_params( 

483 mustexist=( 

484 "1.4", 

485 "Deprecated alias of :paramref:`_schema.Table.must_exist`", 

486 ), 

487 ) 

488 def __new__(cls, *args: Any, **kw: Any) -> Any: 

489 return cls._new(*args, **kw) 

490 

491 @classmethod 

492 def _new(cls, *args: Any, **kw: Any) -> Any: 

493 if not args and not kw: 

494 # python3k pickle seems to call this 

495 return object.__new__(cls) 

496 

497 try: 

498 name, metadata, *other_args = args 

499 except ValueError: 

500 raise TypeError( 

501 "Table() takes at least two positional-only " 

502 "arguments 'name', and 'metadata'" 

503 ) from None 

504 if other_args and isinstance(other_args[0], type): 

505 typed_columns_cls = other_args[0] 

506 if not issubclass(typed_columns_cls, TypedColumns): 

507 raise exc.InvalidRequestError( 

508 "The ``typed_columns_cls`` argument requires a " 

509 "TypedColumns subclass." 

510 ) 

511 elif hasattr(typed_columns_cls, "_sa_class_manager"): 

512 # an orm class subclassed with TypedColumns. Reject it 

513 raise exc.InvalidRequestError( 

514 "To get a typed table from an ORM class, use the " 

515 "`as_typed_table()` function instead." 

516 ) 

517 

518 extracted_columns = _extract_columns_from_class(typed_columns_cls) 

519 other_args = extracted_columns + other_args[1:] 

520 elif "typed_columns_cls" in kw: 

521 raise TypeError( 

522 "The ``typed_columns_cls`` argument may be passed " 

523 "only positionally" 

524 ) 

525 

526 schema = kw.get("schema", None) 

527 if schema is None: 

528 schema = metadata.schema 

529 elif schema is BLANK_SCHEMA: 

530 schema = None 

531 keep_existing = kw.get("keep_existing", False) 

532 extend_existing = kw.get("extend_existing", False) 

533 

534 if keep_existing and extend_existing: 

535 msg = "keep_existing and extend_existing are mutually exclusive." 

536 raise exc.ArgumentError(msg) 

537 

538 must_exist = kw.pop("must_exist", kw.pop("mustexist", False)) 

539 key = _get_table_key(name, schema) 

540 if key in metadata.tables: 

541 if not keep_existing and not extend_existing and bool(other_args): 

542 raise exc.InvalidRequestError( 

543 f"Table '{key}' is already defined for this MetaData " 

544 "instance. Specify 'extend_existing=True' " 

545 "to redefine " 

546 "options and columns on an " 

547 "existing Table object." 

548 ) 

549 table = metadata.tables[key] 

550 if extend_existing: 

551 table._init_existing(*other_args, **kw) 

552 return table 

553 else: 

554 if must_exist: 

555 raise exc.InvalidRequestError(f"Table '{key}' not defined") 

556 table = object.__new__(cls) 

557 table.dispatch.before_parent_attach(table, metadata) 

558 metadata._add_table(name, schema, table) 

559 try: 

560 table.__init__(name, metadata, *other_args, _no_init=False, **kw) # type: ignore[misc] # noqa: E501 

561 table.dispatch.after_parent_attach(table, metadata) 

562 return table 

563 except Exception: 

564 with util.safe_reraise(): 

565 metadata._remove_table(name, schema) 

566 

567 @overload 

568 def __init__( 

569 self: Table[_TC_co], 

570 name: str, 

571 metadata: MetaData, 

572 typed_columns_cls: type[_TC_co], 

573 /, 

574 *args: SchemaItem, 

575 schema: str | Literal[SchemaConst.BLANK_SCHEMA] | None = None, 

576 quote: bool | None = None, 

577 quote_schema: bool | None = None, 

578 keep_existing: bool = False, 

579 extend_existing: bool = False, 

580 implicit_returning: bool = True, 

581 comment: str | None = None, 

582 info: dict[Any, Any] | None = None, 

583 listeners: ( 

584 _typing_Sequence[tuple[str, Callable[..., Any]]] | None 

585 ) = None, 

586 prefixes: _typing_Sequence[str] | None = None, 

587 **kw: Any, 

588 ) -> None: ... 

589 

590 @overload 

591 def __init__( 

592 self: Table[ReadOnlyColumnCollection[str, Column[Any]]], 

593 name: str, 

594 metadata: MetaData, 

595 /, 

596 *args: SchemaItem, 

597 schema: str | Literal[SchemaConst.BLANK_SCHEMA] | None = None, 

598 quote: bool | None = None, 

599 quote_schema: Optional[bool] = None, 

600 autoload_with: Optional[Union[Engine, Connection]] = None, 

601 autoload_replace: bool = True, 

602 keep_existing: bool = False, 

603 extend_existing: bool = False, 

604 resolve_fks: bool = True, 

605 include_columns: Optional[Collection[str]] = None, 

606 implicit_returning: bool = True, 

607 comment: str | None = None, 

608 info: dict[Any, Any] | None = None, 

609 listeners: ( 

610 _typing_Sequence[tuple[str, Callable[..., Any]]] | None 

611 ) = None, 

612 prefixes: _typing_Sequence[str] | None = None, 

613 _creator_ddl: TableCreateDDL | None = None, 

614 _dropper_ddl: TableDropDDL | None = None, 

615 # used internally in the metadata.reflect() process 

616 _extend_on: Optional[Set[Table]] = None, 

617 # used by __new__ to bypass __init__ 

618 _no_init: bool = True, 

619 # dialect-specific keyword args 

620 **kw: Any, 

621 ) -> None: ... 

622 

623 def __init__( 

624 self, 

625 name: str, 

626 metadata: MetaData, 

627 /, 

628 *args: Any, 

629 schema: str | Literal[SchemaConst.BLANK_SCHEMA] | None = None, 

630 quote: bool | None = None, 

631 quote_schema: Optional[bool] = None, 

632 autoload_with: Optional[Union[Engine, Connection]] = None, 

633 autoload_replace: bool = True, 

634 keep_existing: bool = False, 

635 extend_existing: bool = False, 

636 resolve_fks: bool = True, 

637 include_columns: Optional[Collection[str]] = None, 

638 implicit_returning: bool = True, 

639 comment: str | None = None, 

640 info: dict[Any, Any] | None = None, 

641 listeners: ( 

642 _typing_Sequence[tuple[str, Callable[..., Any]]] | None 

643 ) = None, 

644 prefixes: _typing_Sequence[str] | None = None, 

645 _creator_ddl: TableCreateDDL | None = None, 

646 _dropper_ddl: TableDropDDL | None = None, 

647 # used internally in the metadata.reflect() process 

648 _extend_on: Optional[Set[Table]] = None, 

649 # used by __new__ to bypass __init__ 

650 _no_init: bool = True, 

651 # dialect-specific keyword args 

652 **kw: Any, 

653 ) -> None: 

654 r"""Constructor for :class:`_schema.Table`. 

655 

656 

657 :param name: The name of this table as represented in the database. 

658 

659 The table name, along with the value of the ``schema`` parameter, 

660 forms a key which uniquely identifies this :class:`_schema.Table` 

661 within 

662 the owning :class:`_schema.MetaData` collection. 

663 Additional calls to :class:`_schema.Table` with the same name, 

664 metadata, 

665 and schema name will return the same :class:`_schema.Table` object. 

666 

667 Names which contain no upper case characters 

668 will be treated as case insensitive names, and will not be quoted 

669 unless they are a reserved word or contain special characters. 

670 A name with any number of upper case characters is considered 

671 to be case sensitive, and will be sent as quoted. 

672 

673 To enable unconditional quoting for the table name, specify the flag 

674 ``quote=True`` to the constructor, or use the :class:`.quoted_name` 

675 construct to specify the name. 

676 

677 :param metadata: a :class:`_schema.MetaData` 

678 object which will contain this 

679 table. The metadata is used as a point of association of this table 

680 with other tables which are referenced via foreign key. It also 

681 may be used to associate this table with a particular 

682 :class:`.Connection` or :class:`.Engine`. 

683 

684 :param table_columns_cls: a subclass of :class:`_schema.TypedColumns` 

685 that defines the columns that will be "typed" when accessing 

686 them from the :attr:`_schema.Table.c` attribute. 

687 

688 .. versionadded:: 2.1.0b2 

689 

690 :param \*args: Additional positional arguments are used primarily 

691 to add the list of :class:`_schema.Column` 

692 objects contained within this 

693 table. Similar to the style of a CREATE TABLE statement, other 

694 :class:`.SchemaItem` constructs may be added here, including 

695 :class:`.PrimaryKeyConstraint`, and 

696 :class:`_schema.ForeignKeyConstraint`. 

697 Additional columns may be provided also when using a 

698 :paramref:`_schema.Table.table_columns_cls` class; they will 

699 be appended to the "typed" columns and will appear as untyped 

700 when accessing them via the :attr:`_schema.Table.c` collection. 

701 

702 :param autoload_replace: Defaults to ``True``; when using 

703 :paramref:`_schema.Table.autoload_with` 

704 in conjunction with :paramref:`_schema.Table.extend_existing`, 

705 indicates 

706 that :class:`_schema.Column` objects present in the already-existing 

707 :class:`_schema.Table` 

708 object should be replaced with columns of the same 

709 name retrieved from the autoload process. When ``False``, columns 

710 already present under existing names will be omitted from the 

711 reflection process. 

712 

713 Note that this setting does not impact :class:`_schema.Column` objects 

714 specified programmatically within the call to :class:`_schema.Table` 

715 that 

716 also is autoloading; those :class:`_schema.Column` objects will always 

717 replace existing columns of the same name when 

718 :paramref:`_schema.Table.extend_existing` is ``True``. 

719 

720 .. seealso:: 

721 

722 :paramref:`_schema.Table.autoload_with` 

723 

724 :paramref:`_schema.Table.extend_existing` 

725 

726 :param autoload_with: An :class:`_engine.Engine` or 

727 :class:`_engine.Connection` object, 

728 or a :class:`_reflection.Inspector` object as returned by 

729 :func:`_sa.inspect` 

730 against one, with which this :class:`_schema.Table` 

731 object will be reflected. 

732 When set to a non-None value, the autoload process will take place 

733 for this table against the given engine or connection. 

734 

735 .. seealso:: 

736 

737 :ref:`metadata_reflection_toplevel` 

738 

739 :meth:`_events.DDLEvents.column_reflect` 

740 

741 :ref:`metadata_reflection_dbagnostic_types` 

742 

743 :param extend_existing: When ``True``, indicates that if this 

744 :class:`_schema.Table` is already present in the given 

745 :class:`_schema.MetaData`, 

746 apply further arguments within the constructor to the existing 

747 :class:`_schema.Table`. 

748 

749 If :paramref:`_schema.Table.extend_existing` or 

750 :paramref:`_schema.Table.keep_existing` are not set, 

751 and the given name 

752 of the new :class:`_schema.Table` refers to a :class:`_schema.Table` 

753 that is 

754 already present in the target :class:`_schema.MetaData` collection, 

755 and 

756 this :class:`_schema.Table` 

757 specifies additional columns or other constructs 

758 or flags that modify the table's state, an 

759 error is raised. The purpose of these two mutually-exclusive flags 

760 is to specify what action should be taken when a 

761 :class:`_schema.Table` 

762 is specified that matches an existing :class:`_schema.Table`, 

763 yet specifies 

764 additional constructs. 

765 

766 :paramref:`_schema.Table.extend_existing` 

767 will also work in conjunction 

768 with :paramref:`_schema.Table.autoload_with` to run a new reflection 

769 operation against the database, even if a :class:`_schema.Table` 

770 of the same name is already present in the target 

771 :class:`_schema.MetaData`; newly reflected :class:`_schema.Column` 

772 objects 

773 and other options will be added into the state of the 

774 :class:`_schema.Table`, potentially overwriting existing columns 

775 and options of the same name. 

776 

777 As is always the case with :paramref:`_schema.Table.autoload_with`, 

778 :class:`_schema.Column` objects can be specified in the same 

779 :class:`_schema.Table` 

780 constructor, which will take precedence. Below, the existing 

781 table ``mytable`` will be augmented with :class:`_schema.Column` 

782 objects 

783 both reflected from the database, as well as the given 

784 :class:`_schema.Column` 

785 named "y":: 

786 

787 Table( 

788 "mytable", 

789 metadata, 

790 Column("y", Integer), 

791 extend_existing=True, 

792 autoload_with=engine, 

793 ) 

794 

795 .. seealso:: 

796 

797 :paramref:`_schema.Table.autoload_with` 

798 

799 :paramref:`_schema.Table.autoload_replace` 

800 

801 :paramref:`_schema.Table.keep_existing` 

802 

803 

804 :param implicit_returning: True by default - indicates that 

805 RETURNING can be used, typically by the ORM, in order to fetch 

806 server-generated values such as primary key values and 

807 server side defaults, on those backends which support RETURNING. 

808 

809 In modern SQLAlchemy there is generally no reason to alter this 

810 setting, except for some backend specific cases 

811 (see :ref:`mssql_triggers` in the SQL Server dialect documentation 

812 for one such example). 

813 

814 :param include_columns: A list of strings indicating a subset of 

815 columns to be loaded via the ``autoload`` operation; table columns who 

816 aren't present in this list will not be represented on the resulting 

817 ``Table`` object. Defaults to ``None`` which indicates all columns 

818 should be reflected. 

819 

820 :param resolve_fks: Whether or not to reflect :class:`_schema.Table` 

821 objects 

822 related to this one via :class:`_schema.ForeignKey` objects, when 

823 :paramref:`_schema.Table.autoload_with` is 

824 specified. Defaults to True. Set to False to disable reflection of 

825 related tables as :class:`_schema.ForeignKey` 

826 objects are encountered; may be 

827 used either to save on SQL calls or to avoid issues with related tables 

828 that can't be accessed. Note that if a related table is already present 

829 in the :class:`_schema.MetaData` collection, or becomes present later, 

830 a 

831 :class:`_schema.ForeignKey` object associated with this 

832 :class:`_schema.Table` will 

833 resolve to that table normally. 

834 

835 .. seealso:: 

836 

837 :paramref:`.MetaData.reflect.resolve_fks` 

838 

839 

840 :param info: Optional data dictionary which will be populated into the 

841 :attr:`.SchemaItem.info` attribute of this object. 

842 

843 :param keep_existing: When ``True``, indicates that if this Table 

844 is already present in the given :class:`_schema.MetaData`, ignore 

845 further arguments within the constructor to the existing 

846 :class:`_schema.Table`, and return the :class:`_schema.Table` 

847 object as 

848 originally created. This is to allow a function that wishes 

849 to define a new :class:`_schema.Table` on first call, but on 

850 subsequent calls will return the same :class:`_schema.Table`, 

851 without any of the declarations (particularly constraints) 

852 being applied a second time. 

853 

854 If :paramref:`_schema.Table.extend_existing` or 

855 :paramref:`_schema.Table.keep_existing` are not set, 

856 and the given name 

857 of the new :class:`_schema.Table` refers to a :class:`_schema.Table` 

858 that is 

859 already present in the target :class:`_schema.MetaData` collection, 

860 and 

861 this :class:`_schema.Table` 

862 specifies additional columns or other constructs 

863 or flags that modify the table's state, an 

864 error is raised. The purpose of these two mutually-exclusive flags 

865 is to specify what action should be taken when a 

866 :class:`_schema.Table` 

867 is specified that matches an existing :class:`_schema.Table`, 

868 yet specifies 

869 additional constructs. 

870 

871 .. seealso:: 

872 

873 :paramref:`_schema.Table.extend_existing` 

874 

875 :param listeners: A list of tuples of the form ``(<eventname>, <fn>)`` 

876 which will be passed to :func:`.event.listen` upon construction. 

877 This alternate hook to :func:`.event.listen` allows the establishment 

878 of a listener function specific to this :class:`_schema.Table` before 

879 the "autoload" process begins. Historically this has been intended 

880 for use with the :meth:`.DDLEvents.column_reflect` event, however 

881 note that this event hook may now be associated with the 

882 :class:`_schema.MetaData` object directly:: 

883 

884 def listen_for_reflect(table, column_info): 

885 "handle the column reflection event" 

886 # ... 

887 

888 

889 t = Table( 

890 "sometable", 

891 autoload_with=engine, 

892 listeners=[("column_reflect", listen_for_reflect)], 

893 ) 

894 

895 .. seealso:: 

896 

897 :meth:`_events.DDLEvents.column_reflect` 

898 

899 :param must_exist: When ``True``, indicates that this Table must already 

900 be present in the given :class:`_schema.MetaData` collection, else 

901 an exception is raised. 

902 

903 :param prefixes: 

904 A list of strings to insert after CREATE in the CREATE TABLE 

905 statement. They will be separated by spaces. 

906 

907 :param quote: Force quoting of this table's name on or off, corresponding 

908 to ``True`` or ``False``. When left at its default of ``None``, 

909 the column identifier will be quoted according to whether the name is 

910 case sensitive (identifiers with at least one upper case character are 

911 treated as case sensitive), or if it's a reserved word. This flag 

912 is only needed to force quoting of a reserved word which is not known 

913 by the SQLAlchemy dialect. 

914 

915 .. note:: setting this flag to ``False`` will not provide 

916 case-insensitive behavior for table reflection; table reflection 

917 will always search for a mixed-case name in a case sensitive 

918 fashion. Case insensitive names are specified in SQLAlchemy only 

919 by stating the name with all lower case characters. 

920 

921 :param quote_schema: same as 'quote' but applies to the schema identifier. 

922 

923 :param schema: The schema name for this table, which is required if 

924 the table resides in a schema other than the default selected schema 

925 for the engine's database connection. Defaults to ``None``. 

926 

927 If the owning :class:`_schema.MetaData` of this :class:`_schema.Table` 

928 specifies its 

929 own :paramref:`_schema.MetaData.schema` parameter, 

930 then that schema name will 

931 be applied to this :class:`_schema.Table` 

932 if the schema parameter here is set 

933 to ``None``. To set a blank schema name on a :class:`_schema.Table` 

934 that 

935 would otherwise use the schema set on the owning 

936 :class:`_schema.MetaData`, 

937 specify the special symbol :attr:`.BLANK_SCHEMA`. 

938 

939 The quoting rules for the schema name are the same as those for the 

940 ``name`` parameter, in that quoting is applied for reserved words or 

941 case-sensitive names; to enable unconditional quoting for the schema 

942 name, specify the flag ``quote_schema=True`` to the constructor, or use 

943 the :class:`.quoted_name` construct to specify the name. 

944 

945 :param comment: Optional string that will render an SQL comment on table 

946 creation. 

947 

948 :param \**kw: Additional keyword arguments not mentioned above are 

949 dialect specific, and passed in the form ``<dialectname>_<argname>``. 

950 See the documentation regarding an individual dialect at 

951 :ref:`dialect_toplevel` for detail on documented arguments. 

952 

953 """ # noqa: E501 

954 if _no_init: 

955 # don't run __init__ from __new__ by default; 

956 # __new__ has a specific place that __init__ is called 

957 return 

958 if args: 

959 # this is the call done by `__new__` that should have resolved 

960 # TypedColumns to the individual columns 

961 assert not ( 

962 isinstance(args[0], type) and issubclass(args[0], TypedColumns) 

963 ) 

964 

965 super().__init__(quoted_name(name, quote)) 

966 self.metadata = metadata 

967 

968 if schema is None: 

969 self.schema = metadata.schema 

970 elif schema is BLANK_SCHEMA: 

971 self.schema = None 

972 else: 

973 quote_schema = quote_schema 

974 assert isinstance(schema, str) 

975 self.schema = quoted_name(schema, quote_schema) 

976 

977 self._sentinel_column = None 

978 self._creator_ddl = _creator_ddl 

979 self._dropper_ddl = _dropper_ddl 

980 

981 self.indexes = set() 

982 self.constraints = set() 

983 PrimaryKeyConstraint( 

984 _implicit_generated=True 

985 )._set_parent_with_dispatch(self) 

986 self.foreign_keys = set() # type: ignore[misc] 

987 self._extra_dependencies: Set[Table] = set() 

988 if self.schema is not None: 

989 self.fullname = "%s.%s" % (self.schema, self.name) 

990 else: 

991 self.fullname = self.name 

992 

993 self.implicit_returning = implicit_returning 

994 _reflect_info = kw.pop("_reflect_info", None) 

995 

996 self.comment = comment 

997 

998 if info is not None: 

999 self.info = info 

1000 

1001 if listeners is not None: 

1002 for evt, fn in listeners: 

1003 event.listen(self, evt, fn) 

1004 

1005 self._prefixes = prefixes if prefixes else [] 

1006 

1007 self._extra_kwargs(**kw) 

1008 

1009 # load column definitions from the database if 'autoload' is defined 

1010 # we do it after the table is in the singleton dictionary to support 

1011 # circular foreign keys 

1012 if autoload_with is not None: 

1013 self._autoload( 

1014 metadata, 

1015 autoload_with, 

1016 include_columns, 

1017 _extend_on=_extend_on, 

1018 _reflect_info=_reflect_info, 

1019 resolve_fks=resolve_fks, 

1020 ) 

1021 

1022 # initialize all the column, etc. objects. done after reflection to 

1023 # allow user-overrides 

1024 

1025 self._init_items( 

1026 *args, 

1027 allow_replacements=extend_existing 

1028 or keep_existing 

1029 or autoload_with, 

1030 all_names={}, 

1031 ) 

1032 

1033 def set_creator_ddl(self, ddl: TableCreateDDL) -> None: 

1034 """Set the table create DDL for this :class:`.Table`. 

1035 

1036 This allows the CREATE TABLE statement to be controlled or replaced 

1037 entirely when :meth:`.Table.create` or :meth:`.MetaData.create_all` is 

1038 used. 

1039 

1040 E.g.:: 

1041 

1042 from sqlalchemy.schema import CreateTable 

1043 

1044 table.set_creator_ddl(CreateTable(table, if_not_exists=True)) 

1045 

1046 .. versionadded:: 2.1 

1047 

1048 .. seealso:: 

1049 

1050 :meth:`.Table.set_dropper_ddl` 

1051 

1052 """ 

1053 self._creator_ddl = ddl 

1054 

1055 def set_dropper_ddl(self, ddl: TableDropDDL) -> None: 

1056 """Set the table drop DDL for this :class:`.Table`. 

1057 

1058 This allows the DROP TABLE statement to be controlled or replaced 

1059 entirely when :meth:`.Table.drop` or :meth:`.MetaData.drop_all` is 

1060 used. 

1061 

1062 E.g.:: 

1063 

1064 from sqlalchemy.schema import DropTable 

1065 

1066 table.set_dropper_ddl(DropTable(table, if_exists=True)) 

1067 

1068 .. versionadded:: 2.1 

1069 

1070 .. seealso:: 

1071 

1072 :meth:`.Table.set_creator_ddl` 

1073 

1074 """ 

1075 self._dropper_ddl = ddl 

1076 

1077 @property 

1078 def is_view(self) -> bool: 

1079 """True if this table, when DDL for CREATE is emitted, will emit 

1080 CREATE VIEW rather than CREATE TABLE. 

1081 

1082 .. versionadded:: 2.1 

1083 

1084 """ 

1085 return isinstance(self._creator_ddl, ddl.CreateView) 

1086 

1087 def _autoload( 

1088 self, 

1089 metadata: MetaData, 

1090 autoload_with: Union[Engine, Connection], 

1091 include_columns: Optional[Collection[str]], 

1092 exclude_columns: Collection[str] = (), 

1093 resolve_fks: bool = True, 

1094 _extend_on: Optional[Set[Table]] = None, 

1095 _reflect_info: _ReflectionInfo | None = None, 

1096 ) -> None: 

1097 insp = inspection.inspect(autoload_with) 

1098 with insp._inspection_context() as conn_insp: 

1099 conn_insp.reflect_table( 

1100 self, 

1101 include_columns, 

1102 exclude_columns, 

1103 resolve_fks, 

1104 _extend_on=_extend_on, 

1105 _reflect_info=_reflect_info, 

1106 ) 

1107 

1108 @property 

1109 def _sorted_constraints(self) -> List[Constraint]: 

1110 """Return the set of constraints as a list, sorted by creation 

1111 order. 

1112 

1113 """ 

1114 

1115 return sorted(self.constraints, key=lambda c: c._creation_order) 

1116 

1117 @property 

1118 def foreign_key_constraints(self) -> Set[ForeignKeyConstraint]: 

1119 """:class:`_schema.ForeignKeyConstraint` objects referred to by this 

1120 :class:`_schema.Table`. 

1121 

1122 This list is produced from the collection of 

1123 :class:`_schema.ForeignKey` 

1124 objects currently associated. 

1125 

1126 

1127 .. seealso:: 

1128 

1129 :attr:`_schema.Table.constraints` 

1130 

1131 :attr:`_schema.Table.foreign_keys` 

1132 

1133 :attr:`_schema.Table.indexes` 

1134 

1135 """ 

1136 return { 

1137 fkc.constraint 

1138 for fkc in self.foreign_keys 

1139 if fkc.constraint is not None 

1140 } 

1141 

1142 def _init_existing(self, *args: Any, **kwargs: Any) -> None: 

1143 autoload_with = kwargs.pop("autoload_with", None) 

1144 autoload = kwargs.pop("autoload", autoload_with is not None) 

1145 autoload_replace = kwargs.pop("autoload_replace", True) 

1146 schema = kwargs.pop("schema", None) 

1147 _extend_on = kwargs.pop("_extend_on", None) 

1148 _reflect_info = kwargs.pop("_reflect_info", None) 

1149 

1150 # these arguments are only used with _init() 

1151 extend_existing = kwargs.pop("extend_existing", False) 

1152 keep_existing = kwargs.pop("keep_existing", False) 

1153 

1154 assert extend_existing 

1155 assert not keep_existing 

1156 

1157 if schema and schema != self.schema: 

1158 raise exc.ArgumentError( 

1159 f"Can't change schema of existing table " 

1160 f"from '{self.schema}' to '{schema}'", 

1161 ) 

1162 

1163 include_columns = kwargs.pop("include_columns", None) 

1164 if include_columns is not None: 

1165 for c in self.c: 

1166 if c.name not in include_columns: 

1167 self._columns.remove(c) 

1168 

1169 resolve_fks = kwargs.pop("resolve_fks", True) 

1170 

1171 for key in ("quote", "quote_schema"): 

1172 if key in kwargs: 

1173 raise exc.ArgumentError( 

1174 "Can't redefine 'quote' or 'quote_schema' arguments" 

1175 ) 

1176 

1177 # update `self` with these kwargs, if provided 

1178 self.comment = kwargs.pop("comment", self.comment) 

1179 self.implicit_returning = kwargs.pop( 

1180 "implicit_returning", self.implicit_returning 

1181 ) 

1182 self.info = kwargs.pop("info", self.info) 

1183 

1184 exclude_columns: _typing_Sequence[str] 

1185 

1186 if autoload: 

1187 if not autoload_replace: 

1188 # don't replace columns already present. 

1189 # we'd like to do this for constraints also however we don't 

1190 # have simple de-duping for unnamed constraints. 

1191 exclude_columns = [c.name for c in self.c] 

1192 else: 

1193 exclude_columns = () 

1194 self._autoload( 

1195 self.metadata, 

1196 autoload_with, 

1197 include_columns, 

1198 exclude_columns, 

1199 resolve_fks, 

1200 _extend_on=_extend_on, 

1201 _reflect_info=_reflect_info, 

1202 ) 

1203 

1204 all_names = {c.name: c for c in self.c} 

1205 self._extra_kwargs(**kwargs) 

1206 self._init_items(*args, allow_replacements=True, all_names=all_names) 

1207 

1208 def _extra_kwargs(self, **kwargs: Any) -> None: 

1209 self._validate_dialect_kwargs(kwargs) 

1210 

1211 def _init_collections(self) -> None: 

1212 pass 

1213 

1214 def _reset_exported(self) -> None: 

1215 pass 

1216 

1217 @util.ro_non_memoized_property 

1218 def _autoincrement_column(self) -> Optional[Column[int]]: 

1219 return self.primary_key._autoincrement_column 

1220 

1221 @util.ro_memoized_property 

1222 def _sentinel_column_characteristics( 

1223 self, 

1224 ) -> _SentinelColumnCharacterization: 

1225 """determine a candidate column (or columns, in case of a client 

1226 generated composite primary key) which can be used as an 

1227 "insert sentinel" for an INSERT statement. 

1228 

1229 The returned structure, :class:`_SentinelColumnCharacterization`, 

1230 includes all the details needed by :class:`.Dialect` and 

1231 :class:`.SQLCompiler` to determine if these column(s) can be used 

1232 as an INSERT..RETURNING sentinel for a particular database 

1233 dialect. 

1234 

1235 .. versionadded:: 2.0.10 

1236 

1237 """ 

1238 

1239 sentinel_is_explicit = False 

1240 sentinel_is_autoinc = False 

1241 the_sentinel: Optional[_typing_Sequence[Column[Any]]] = None 

1242 

1243 # see if a column was explicitly marked "insert_sentinel=True". 

1244 explicit_sentinel_col = self._sentinel_column 

1245 

1246 if explicit_sentinel_col is not None: 

1247 the_sentinel = (explicit_sentinel_col,) 

1248 sentinel_is_explicit = True 

1249 

1250 autoinc_col = self._autoincrement_column 

1251 if sentinel_is_explicit and explicit_sentinel_col is autoinc_col: 

1252 assert autoinc_col is not None 

1253 sentinel_is_autoinc = True 

1254 elif explicit_sentinel_col is None and autoinc_col is not None: 

1255 the_sentinel = (autoinc_col,) 

1256 sentinel_is_autoinc = True 

1257 

1258 default_characterization = _SentinelDefaultCharacterization.UNKNOWN 

1259 

1260 if the_sentinel: 

1261 the_sentinel_zero = the_sentinel[0] 

1262 if the_sentinel_zero.identity: 

1263 if the_sentinel_zero.identity._increment_is_negative: 

1264 if sentinel_is_explicit: 

1265 raise exc.InvalidRequestError( 

1266 "Can't use IDENTITY default with negative " 

1267 "increment as an explicit sentinel column" 

1268 ) 

1269 else: 

1270 if sentinel_is_autoinc: 

1271 autoinc_col = None 

1272 sentinel_is_autoinc = False 

1273 the_sentinel = None 

1274 else: 

1275 default_characterization = ( 

1276 _SentinelDefaultCharacterization.IDENTITY 

1277 ) 

1278 elif ( 

1279 the_sentinel_zero.default is None 

1280 and the_sentinel_zero.server_default is None 

1281 ): 

1282 if the_sentinel_zero.nullable: 

1283 raise exc.InvalidRequestError( 

1284 f"Column {the_sentinel_zero} has been marked as a " 

1285 "sentinel " 

1286 "column with no default generation function; it " 

1287 "at least needs to be marked nullable=False assuming " 

1288 "user-populated sentinel values will be used." 

1289 ) 

1290 default_characterization = ( 

1291 _SentinelDefaultCharacterization.NONE 

1292 ) 

1293 elif the_sentinel_zero.default is not None: 

1294 if the_sentinel_zero.default.is_sentinel: 

1295 default_characterization = ( 

1296 _SentinelDefaultCharacterization.SENTINEL_DEFAULT 

1297 ) 

1298 elif the_sentinel_zero.default._is_monotonic_fn: 

1299 default_characterization = ( 

1300 _SentinelDefaultCharacterization.MONOTONIC_FUNCTION 

1301 ) 

1302 elif default_is_sequence(the_sentinel_zero.default): 

1303 if the_sentinel_zero.default._increment_is_negative: 

1304 if sentinel_is_explicit: 

1305 raise exc.InvalidRequestError( 

1306 "Can't use SEQUENCE default with negative " 

1307 "increment as an explicit sentinel column" 

1308 ) 

1309 else: 

1310 if sentinel_is_autoinc: 

1311 autoinc_col = None 

1312 sentinel_is_autoinc = False 

1313 the_sentinel = None 

1314 

1315 default_characterization = ( 

1316 _SentinelDefaultCharacterization.SEQUENCE 

1317 ) 

1318 elif the_sentinel_zero.default.is_callable: 

1319 default_characterization = ( 

1320 _SentinelDefaultCharacterization.CLIENTSIDE 

1321 ) 

1322 elif the_sentinel_zero.server_default is not None: 

1323 if sentinel_is_explicit: 

1324 if not the_sentinel_zero.server_default._is_monotonic_fn: 

1325 raise exc.InvalidRequestError( 

1326 f"Column {the_sentinel[0]} can't be a sentinel " 

1327 "column " 

1328 "because it uses an explicit server side default " 

1329 "that's not the Identity() default." 

1330 ) 

1331 else: 

1332 default_characterization = ( 

1333 _SentinelDefaultCharacterization.MONOTONIC_FUNCTION 

1334 ) 

1335 else: 

1336 default_characterization = ( 

1337 _SentinelDefaultCharacterization.SERVERSIDE 

1338 ) 

1339 

1340 if the_sentinel is None and self.primary_key: 

1341 assert autoinc_col is None 

1342 

1343 # determine for non-autoincrement pk if all elements are 

1344 # client side 

1345 for _pkc in self.primary_key: 

1346 if ( 

1347 _pkc.server_default is not None 

1348 and not _pkc.server_default._is_monotonic_fn 

1349 ): 

1350 break 

1351 

1352 if ( 

1353 _pkc.default 

1354 and not _pkc.default.is_callable 

1355 and not _pkc.default._is_monotonic_fn 

1356 ): 

1357 break 

1358 else: 

1359 the_sentinel = tuple(self.primary_key) 

1360 default_characterization = ( 

1361 _SentinelDefaultCharacterization.CLIENTSIDE 

1362 ) 

1363 

1364 return _SentinelColumnCharacterization( 

1365 the_sentinel, 

1366 sentinel_is_explicit, 

1367 sentinel_is_autoinc, 

1368 default_characterization, 

1369 ) 

1370 

1371 @property 

1372 def autoincrement_column(self) -> Optional[Column[int]]: 

1373 """Returns the :class:`.Column` object which currently represents 

1374 the "auto increment" column, if any, else returns None. 

1375 

1376 This is based on the rules for :class:`.Column` as defined by the 

1377 :paramref:`.Column.autoincrement` parameter, which generally means the 

1378 column within a single integer column primary key constraint that is 

1379 not constrained by a foreign key. If the table does not have such 

1380 a primary key constraint, then there's no "autoincrement" column. 

1381 A :class:`.Table` may have only one column defined as the 

1382 "autoincrement" column. 

1383 

1384 .. versionadded:: 2.0.4 

1385 

1386 .. seealso:: 

1387 

1388 :paramref:`.Column.autoincrement` 

1389 

1390 """ 

1391 return self._autoincrement_column 

1392 

1393 @property 

1394 def key(self) -> str: 

1395 """Return the 'key' for this :class:`_schema.Table`. 

1396 

1397 This value is used as the dictionary key within the 

1398 :attr:`_schema.MetaData.tables` collection. It is typically the same 

1399 as that of :attr:`_schema.Table.name` for a table with no 

1400 :attr:`_schema.Table.schema` 

1401 set; otherwise it is typically of the form 

1402 ``schemaname.tablename``. 

1403 

1404 """ 

1405 return _get_table_key(self.name, self.schema) 

1406 

1407 def __repr__(self) -> str: 

1408 return "Table(%s)" % ", ".join( 

1409 [repr(self.name)] 

1410 + [repr(self.metadata)] 

1411 + [repr(x) for x in self.columns] 

1412 + ["%s=%s" % (k, repr(getattr(self, k))) for k in ["schema"]] 

1413 ) 

1414 

1415 def __str__(self) -> str: 

1416 return _get_table_key(self.description, self.schema) 

1417 

1418 def add_is_dependent_on(self, table: Table) -> None: 

1419 """Add a 'dependency' for this Table. 

1420 

1421 This is another Table object which must be created 

1422 first before this one can, or dropped after this one. 

1423 

1424 Usually, dependencies between tables are determined via 

1425 ForeignKey objects. However, for other situations that 

1426 create dependencies outside of foreign keys (rules, inheriting), 

1427 this method can manually establish such a link. 

1428 

1429 """ 

1430 self._extra_dependencies.add(table) 

1431 

1432 def _insert_col_impl( 

1433 self, 

1434 column: ColumnClause[Any], 

1435 *, 

1436 index: Optional[int] = None, 

1437 replace_existing: bool = False, 

1438 ) -> None: 

1439 try: 

1440 column._set_parent_with_dispatch( 

1441 self, 

1442 allow_replacements=replace_existing, 

1443 all_names={c.name: c for c in self.c}, 

1444 index=index, 

1445 ) 

1446 except exc.DuplicateColumnError as de: 

1447 raise exc.DuplicateColumnError( 

1448 f"{de.args[0]} Specify replace_existing=True to " 

1449 "Table.append_column() or Table.insert_column() to replace an " 

1450 "existing column." 

1451 ) from de 

1452 

1453 def insert_column( 

1454 self, 

1455 column: ColumnClause[Any], 

1456 index: int, 

1457 *, 

1458 replace_existing: bool = False, 

1459 ) -> None: 

1460 """Insert a :class:`_schema.Column` to this :class:`_schema.Table` at 

1461 a specific position. 

1462 

1463 Behavior is identical to :meth:`.Table.append_column` except that 

1464 the index position can be controlled using the 

1465 :paramref:`.Table.insert_column.index` 

1466 parameter. 

1467 

1468 :param replace_existing: 

1469 see :paramref:`.Table.append_column.replace_existing` 

1470 :param index: integer index to insert the new column. 

1471 

1472 .. versionadded:: 2.1 

1473 

1474 """ 

1475 self._insert_col_impl( 

1476 column, index=index, replace_existing=replace_existing 

1477 ) 

1478 

1479 def append_column( 

1480 self, column: ColumnClause[Any], *, replace_existing: bool = False 

1481 ) -> None: 

1482 """Append a :class:`_schema.Column` to this :class:`_schema.Table`. 

1483 

1484 The "key" of the newly added :class:`_schema.Column`, i.e. the 

1485 value of its ``.key`` attribute, will then be available 

1486 in the ``.c`` collection of this :class:`_schema.Table`, and the 

1487 column definition will be included in any CREATE TABLE, SELECT, 

1488 UPDATE, etc. statements generated from this :class:`_schema.Table` 

1489 construct. 

1490 

1491 Note that this does **not** change the definition of the table 

1492 as it exists within any underlying database, assuming that 

1493 table has already been created in the database. Relational 

1494 databases support the addition of columns to existing tables 

1495 using the SQL ALTER command, which would need to be 

1496 emitted for an already-existing table that doesn't contain 

1497 the newly added column. 

1498 

1499 :param replace_existing: When ``True``, allows replacing existing 

1500 columns. When ``False``, the default, an warning will be raised 

1501 if a column with the same ``.key`` already exists. A future 

1502 version of sqlalchemy will instead rise a warning. 

1503 

1504 .. versionadded:: 1.4.0 

1505 

1506 .. seealso:: 

1507 

1508 :meth:`.Table.insert_column` 

1509 

1510 """ 

1511 self._insert_col_impl(column, replace_existing=replace_existing) 

1512 

1513 def append_constraint(self, constraint: Union[Index, Constraint]) -> None: 

1514 """Append a :class:`_schema.Constraint` to this 

1515 :class:`_schema.Table`. 

1516 

1517 This has the effect of the constraint being included in any 

1518 future CREATE TABLE statement, assuming specific DDL creation 

1519 events have not been associated with the given 

1520 :class:`_schema.Constraint` object. 

1521 

1522 Note that this does **not** produce the constraint within the 

1523 relational database automatically, for a table that already exists 

1524 in the database. To add a constraint to an 

1525 existing relational database table, the SQL ALTER command must 

1526 be used. SQLAlchemy also provides the 

1527 :class:`.AddConstraint` construct which can produce this SQL when 

1528 invoked as an executable clause. 

1529 

1530 """ 

1531 

1532 constraint._set_parent_with_dispatch(self) 

1533 

1534 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

1535 metadata = parent 

1536 assert isinstance(metadata, MetaData) 

1537 metadata._add_table(self.name, self.schema, self) 

1538 self.metadata = metadata 

1539 

1540 def create( 

1541 self, 

1542 bind: _CreateDropBind, 

1543 checkfirst: Union[bool, CheckFirst] = CheckFirst.TYPES, 

1544 ) -> None: 

1545 """Issue a ``CREATE`` statement for this 

1546 :class:`_schema.Table`, using the given 

1547 :class:`.Connection` or :class:`.Engine` 

1548 for connectivity. 

1549 

1550 .. seealso:: 

1551 

1552 :meth:`_schema.MetaData.create_all`. 

1553 

1554 """ 

1555 

1556 # the default is to only check for schema objects 

1557 bind._run_ddl_visitor(ddl.SchemaGenerator, self, checkfirst=checkfirst) 

1558 

1559 def drop( 

1560 self, 

1561 bind: _CreateDropBind, 

1562 checkfirst: Union[bool, CheckFirst] = CheckFirst.NONE, 

1563 ) -> None: 

1564 """Issue a ``DROP`` statement for this 

1565 :class:`_schema.Table`, using the given 

1566 :class:`.Connection` or :class:`.Engine` for connectivity. 

1567 

1568 .. seealso:: 

1569 

1570 :meth:`_schema.MetaData.drop_all`. 

1571 

1572 """ 

1573 bind._run_ddl_visitor(ddl.SchemaDropper, self, checkfirst=checkfirst) 

1574 

1575 @util.deprecated( 

1576 "1.4", 

1577 ":meth:`_schema.Table.tometadata` is renamed to " 

1578 ":meth:`_schema.Table.to_metadata`", 

1579 ) 

1580 def tometadata( 

1581 self, 

1582 metadata: MetaData, 

1583 schema: Union[str, Literal[SchemaConst.RETAIN_SCHEMA]] = RETAIN_SCHEMA, 

1584 referred_schema_fn: Optional[ 

1585 Callable[ 

1586 [Table, Optional[str], ForeignKeyConstraint, Optional[str]], 

1587 Optional[str], 

1588 ] 

1589 ] = None, 

1590 name: Optional[str] = None, 

1591 ) -> Table[_ColCC_co]: 

1592 """Return a copy of this :class:`_schema.Table` 

1593 associated with a different 

1594 :class:`_schema.MetaData`. 

1595 

1596 See :meth:`_schema.Table.to_metadata` for a full description. 

1597 

1598 """ 

1599 return self.to_metadata( 

1600 metadata, 

1601 schema=schema, 

1602 referred_schema_fn=referred_schema_fn, 

1603 name=name, 

1604 ) 

1605 

1606 def to_metadata( 

1607 self, 

1608 metadata: MetaData, 

1609 schema: Union[str, Literal[SchemaConst.RETAIN_SCHEMA]] = RETAIN_SCHEMA, 

1610 referred_schema_fn: Optional[ 

1611 Callable[ 

1612 [Table, Optional[str], ForeignKeyConstraint, Optional[str]], 

1613 Optional[str], 

1614 ] 

1615 ] = None, 

1616 name: Optional[str] = None, 

1617 ) -> Table[_ColCC_co]: 

1618 """Return a copy of this :class:`_schema.Table` associated with a 

1619 different :class:`_schema.MetaData`. 

1620 

1621 E.g.:: 

1622 

1623 m1 = MetaData() 

1624 

1625 user = Table("user", m1, Column("id", Integer, primary_key=True)) 

1626 

1627 m2 = MetaData() 

1628 user_copy = user.to_metadata(m2) 

1629 

1630 .. versionchanged:: 1.4 The :meth:`_schema.Table.to_metadata` function 

1631 was renamed from :meth:`_schema.Table.tometadata`. 

1632 

1633 

1634 :param metadata: Target :class:`_schema.MetaData` object, 

1635 into which the 

1636 new :class:`_schema.Table` object will be created. 

1637 

1638 :param schema: optional string name indicating the target schema. 

1639 Defaults to the special symbol :attr:`.RETAIN_SCHEMA` which indicates 

1640 that no change to the schema name should be made in the new 

1641 :class:`_schema.Table`. If set to a string name, the new 

1642 :class:`_schema.Table` 

1643 will have this new name as the ``.schema``. If set to ``None``, the 

1644 schema will be set to that of the schema set on the target 

1645 :class:`_schema.MetaData`, which is typically ``None`` as well, 

1646 unless 

1647 set explicitly:: 

1648 

1649 m2 = MetaData(schema="newschema") 

1650 

1651 # user_copy_one will have "newschema" as the schema name 

1652 user_copy_one = user.to_metadata(m2, schema=None) 

1653 

1654 m3 = MetaData() # schema defaults to None 

1655 

1656 # user_copy_two will have None as the schema name 

1657 user_copy_two = user.to_metadata(m3, schema=None) 

1658 

1659 :param referred_schema_fn: optional callable which can be supplied 

1660 in order to provide for the schema name that should be assigned 

1661 to the referenced table of a :class:`_schema.ForeignKeyConstraint`. 

1662 The callable accepts this parent :class:`_schema.Table`, the 

1663 target schema that we are changing to, the 

1664 :class:`_schema.ForeignKeyConstraint` object, and the existing 

1665 "target schema" of that constraint. The function should return the 

1666 string schema name that should be applied. To reset the schema 

1667 to "none", return the symbol :data:`.BLANK_SCHEMA`. To effect no 

1668 change, return ``None`` or :data:`.RETAIN_SCHEMA`. 

1669 

1670 .. versionchanged:: 1.4.33 The ``referred_schema_fn`` function 

1671 may return the :data:`.BLANK_SCHEMA` or :data:`.RETAIN_SCHEMA` 

1672 symbols. 

1673 

1674 E.g.:: 

1675 

1676 def referred_schema_fn(table, to_schema, constraint, referred_schema): 

1677 if referred_schema == "base_tables": 

1678 return referred_schema 

1679 else: 

1680 return to_schema 

1681 

1682 

1683 new_table = table.to_metadata( 

1684 m2, schema="alt_schema", referred_schema_fn=referred_schema_fn 

1685 ) 

1686 

1687 :param name: optional string name indicating the target table name. 

1688 If not specified or None, the table name is retained. This allows 

1689 a :class:`_schema.Table` to be copied to the same 

1690 :class:`_schema.MetaData` target 

1691 with a new name. 

1692 

1693 """ # noqa: E501 

1694 if name is None: 

1695 name = self.name 

1696 

1697 actual_schema: Optional[str] 

1698 

1699 if schema is RETAIN_SCHEMA: 

1700 actual_schema = self.schema 

1701 elif schema is None: 

1702 actual_schema = metadata.schema 

1703 else: 

1704 actual_schema = schema 

1705 key = _get_table_key(name, actual_schema) 

1706 if key in metadata.tables: 

1707 util.warn( 

1708 f"Table '{self.description}' already exists within the given " 

1709 "MetaData - not copying." 

1710 ) 

1711 return metadata.tables[key] 

1712 

1713 args = [] 

1714 for col in self.columns: 

1715 args.append(col._copy(schema=actual_schema, _to_metadata=metadata)) 

1716 

1717 table: Table[_ColCC_co] = Table( # type: ignore[assignment] 

1718 name, 

1719 metadata, 

1720 schema=actual_schema, 

1721 comment=self.comment, 

1722 *args, 

1723 **self.kwargs, 

1724 ) 

1725 

1726 if self._creator_ddl is not None: 

1727 table._creator_ddl = self._creator_ddl.to_metadata(metadata, table) 

1728 if self._dropper_ddl is not None: 

1729 table._dropper_ddl = self._dropper_ddl.to_metadata(metadata, table) 

1730 

1731 for const in self.constraints: 

1732 if isinstance(const, ForeignKeyConstraint): 

1733 referred_schema = const._referred_schema 

1734 if referred_schema_fn: 

1735 fk_constraint_schema = referred_schema_fn( 

1736 self, actual_schema, const, referred_schema 

1737 ) 

1738 else: 

1739 fk_constraint_schema = ( 

1740 actual_schema 

1741 if referred_schema == self.schema 

1742 else None 

1743 ) 

1744 table.append_constraint( 

1745 const._copy( 

1746 schema=fk_constraint_schema, target_table=table 

1747 ) 

1748 ) 

1749 elif not const._type_bound: 

1750 # skip unique constraints that would be generated 

1751 # by the 'unique' flag on Column 

1752 if const._column_flag: 

1753 continue 

1754 

1755 table.append_constraint( 

1756 const._copy(schema=actual_schema, target_table=table) 

1757 ) 

1758 for index in self.indexes: 

1759 # skip indexes that would be generated 

1760 # by the 'index' flag on Column 

1761 if index._column_flag: 

1762 continue 

1763 Index( 

1764 index.name, 

1765 unique=index.unique, 

1766 *[ 

1767 _copy_expression(expr, self, table) 

1768 for expr in index._table_bound_expressions 

1769 ], 

1770 _table=table, 

1771 **index.kwargs, 

1772 **index._reflect_only_kwargs, 

1773 ) 

1774 return self._schema_item_copy(table) 

1775 

1776 

1777class Column(DialectKWArgs, SchemaItem, ColumnClause[_T], Named[_T]): 

1778 """Represents a column in a database table.""" 

1779 

1780 __visit_name__ = "column" 

1781 

1782 inherit_cache = True 

1783 key: str 

1784 

1785 server_default: Optional[FetchedValue] 

1786 

1787 def __init__( 

1788 self, 

1789 __name_pos: Optional[ 

1790 Union[str, _TypeEngineArgument[_T], SchemaEventTarget] 

1791 ] = None, 

1792 __type_pos: Optional[ 

1793 Union[_TypeEngineArgument[_T], SchemaEventTarget] 

1794 ] = None, 

1795 /, 

1796 *args: SchemaEventTarget, 

1797 name: Optional[str] = None, 

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

1799 autoincrement: _AutoIncrementType = "auto", 

1800 default: Optional[Any] = _NoArg.NO_ARG, 

1801 insert_default: Optional[Any] = _NoArg.NO_ARG, 

1802 doc: Optional[str] = None, 

1803 key: Optional[str] = None, 

1804 index: Optional[bool] = None, 

1805 unique: Optional[bool] = None, 

1806 info: Optional[_InfoType] = None, 

1807 nullable: Optional[ 

1808 Union[bool, Literal[SchemaConst.NULL_UNSPECIFIED]] 

1809 ] = SchemaConst.NULL_UNSPECIFIED, 

1810 onupdate: Optional[Any] = None, 

1811 primary_key: bool = False, 

1812 server_default: Optional[_ServerDefaultArgument] = None, 

1813 server_onupdate: Optional[_ServerOnUpdateArgument] = None, 

1814 quote: Optional[bool] = None, 

1815 system: bool = False, 

1816 comment: Optional[str] = None, 

1817 insert_sentinel: bool = False, 

1818 _omit_from_statements: bool = False, 

1819 _proxies: Optional[Any] = None, 

1820 **dialect_kwargs: Any, 

1821 ): 

1822 r""" 

1823 Construct a new ``Column`` object. 

1824 

1825 :param name: The name of this column as represented in the database. 

1826 This argument may be the first positional argument, or specified 

1827 via keyword. 

1828 

1829 Names which contain no upper case characters 

1830 will be treated as case insensitive names, and will not be quoted 

1831 unless they are a reserved word. Names with any number of upper 

1832 case characters will be quoted and sent exactly. Note that this 

1833 behavior applies even for databases which standardize upper 

1834 case names as case insensitive such as Oracle Database. 

1835 

1836 The name field may be omitted at construction time and applied 

1837 later, at any time before the Column is associated with a 

1838 :class:`_schema.Table`. This is to support convenient 

1839 usage within the :mod:`~sqlalchemy.ext.declarative` extension. 

1840 

1841 :param type\_: The column's type, indicated using an instance which 

1842 subclasses :class:`~sqlalchemy.types.TypeEngine`. If no arguments 

1843 are required for the type, the class of the type can be sent 

1844 as well, e.g.:: 

1845 

1846 # use a type with arguments 

1847 Column("data", String(50)) 

1848 

1849 # use no arguments 

1850 Column("level", Integer) 

1851 

1852 The ``type`` argument may be the second positional argument 

1853 or specified by keyword. 

1854 

1855 If the ``type`` is ``None`` or is omitted, it will first default to 

1856 the special type :class:`.NullType`. If and when this 

1857 :class:`_schema.Column` is made to refer to another column using 

1858 :class:`_schema.ForeignKey` and/or 

1859 :class:`_schema.ForeignKeyConstraint`, the type 

1860 of the remote-referenced column will be copied to this column as 

1861 well, at the moment that the foreign key is resolved against that 

1862 remote :class:`_schema.Column` object. 

1863 

1864 :param \*args: Additional positional arguments include various 

1865 :class:`.SchemaItem` derived constructs which will be applied 

1866 as options to the column. These include instances of 

1867 :class:`.Constraint`, :class:`_schema.ForeignKey`, 

1868 :class:`.ColumnDefault`, :class:`.Sequence`, :class:`.Computed` 

1869 :class:`.Identity`. In some cases an 

1870 equivalent keyword argument is available such as ``server_default``, 

1871 ``default`` and ``unique``. 

1872 

1873 :param autoincrement: Set up "auto increment" semantics for an 

1874 **integer primary key column with no foreign key dependencies** 

1875 (see later in this docstring for a more specific definition). 

1876 This may influence the :term:`DDL` that will be emitted for 

1877 this column during a table create, as well as how the column 

1878 will be considered when INSERT statements are compiled and 

1879 executed. 

1880 

1881 The default value is the string ``"auto"``, 

1882 which indicates that a single-column (i.e. non-composite) primary key 

1883 that is of an INTEGER type with no other client-side or server-side 

1884 default constructs indicated should receive auto increment semantics 

1885 automatically. Other values include ``True`` (force this column to 

1886 have auto-increment semantics for a :term:`composite primary key` as 

1887 well), ``False`` (this column should never have auto-increment 

1888 semantics), and the string ``"ignore_fk"`` (special-case for foreign 

1889 key columns, see below). 

1890 

1891 The term "auto increment semantics" refers both to the kind of DDL 

1892 that will be emitted for the column within a CREATE TABLE statement, 

1893 when methods such as :meth:`.MetaData.create_all` and 

1894 :meth:`.Table.create` are invoked, as well as how the column will be 

1895 considered when an INSERT statement is compiled and emitted to the 

1896 database: 

1897 

1898 * **DDL rendering** (i.e. :meth:`.MetaData.create_all`, 

1899 :meth:`.Table.create`): When used on a :class:`.Column` that has 

1900 no other 

1901 default-generating construct associated with it (such as a 

1902 :class:`.Sequence` or :class:`.Identity` construct), the parameter 

1903 will imply that database-specific keywords such as PostgreSQL 

1904 ``SERIAL``, MySQL ``AUTO_INCREMENT``, or ``IDENTITY`` on SQL Server 

1905 should also be rendered. Not every database backend has an 

1906 "implied" default generator available; for example the Oracle Database 

1907 backends always needs an explicit construct such as 

1908 :class:`.Identity` to be included with a :class:`.Column` in order 

1909 for the DDL rendered to include auto-generating constructs to also 

1910 be produced in the database. 

1911 

1912 * **INSERT semantics** (i.e. when a :func:`_sql.insert` construct is 

1913 compiled into a SQL string and is then executed on a database using 

1914 :meth:`_engine.Connection.execute` or equivalent): A single-row 

1915 INSERT statement will be known to produce a new integer primary key 

1916 value automatically for this column, which will be accessible 

1917 after the statement is invoked via the 

1918 :attr:`.CursorResult.inserted_primary_key` attribute upon the 

1919 :class:`_result.Result` object. This also applies towards use of the 

1920 ORM when ORM-mapped objects are persisted to the database, 

1921 indicating that a new integer primary key will be available to 

1922 become part of the :term:`identity key` for that object. This 

1923 behavior takes place regardless of what DDL constructs are 

1924 associated with the :class:`_schema.Column` and is independent 

1925 of the "DDL Rendering" behavior discussed in the previous note 

1926 above. 

1927 

1928 The parameter may be set to ``True`` to indicate that a column which 

1929 is part of a composite (i.e. multi-column) primary key should 

1930 have autoincrement semantics, though note that only one column 

1931 within a primary key may have this setting. It can also 

1932 be set to ``True`` to indicate autoincrement semantics on a 

1933 column that has a client-side or server-side default configured, 

1934 however note that not all dialects can accommodate all styles 

1935 of default as an "autoincrement". It can also be 

1936 set to ``False`` on a single-column primary key that has a 

1937 datatype of INTEGER in order to disable auto increment semantics 

1938 for that column. 

1939 

1940 The setting *only* has an effect for columns which are: 

1941 

1942 * Integer derived (i.e. INT, SMALLINT, BIGINT). 

1943 

1944 * Part of the primary key 

1945 

1946 * Not referring to another column via :class:`_schema.ForeignKey`, 

1947 unless 

1948 the value is specified as ``'ignore_fk'``:: 

1949 

1950 # turn on autoincrement for this column despite 

1951 # the ForeignKey() 

1952 Column( 

1953 "id", 

1954 ForeignKey("other.id"), 

1955 primary_key=True, 

1956 autoincrement="ignore_fk", 

1957 ) 

1958 

1959 It is typically not desirable to have "autoincrement" enabled on a 

1960 column that refers to another via foreign key, as such a column is 

1961 required to refer to a value that originates from elsewhere. 

1962 

1963 The setting has these effects on columns that meet the 

1964 above criteria: 

1965 

1966 * DDL issued for the column, if the column does not already include 

1967 a default generating construct supported by the backend such as 

1968 :class:`.Identity`, will include database-specific 

1969 keywords intended to signify this column as an 

1970 "autoincrement" column for specific backends. Behavior for 

1971 primary SQLAlchemy dialects includes: 

1972 

1973 * AUTO INCREMENT on MySQL and MariaDB 

1974 * SERIAL on PostgreSQL 

1975 * IDENTITY on MS-SQL - this occurs even without the 

1976 :class:`.Identity` construct as the 

1977 :paramref:`.Column.autoincrement` parameter pre-dates this 

1978 construct. 

1979 * SQLite - SQLite integer primary key columns are implicitly 

1980 "auto incrementing" and no additional keywords are rendered; 

1981 to render the special SQLite keyword ``AUTOINCREMENT`` 

1982 is not included as this is unnecessary and not recommended 

1983 by the database vendor. See the section 

1984 :ref:`sqlite_autoincrement` for more background. 

1985 * Oracle Database - The Oracle Database dialects have no default "autoincrement" 

1986 feature available at this time, instead the :class:`.Identity` 

1987 construct is recommended to achieve this (the :class:`.Sequence` 

1988 construct may also be used). 

1989 * Third-party dialects - consult those dialects' documentation 

1990 for details on their specific behaviors. 

1991 

1992 * When a single-row :func:`_sql.insert` construct is compiled and 

1993 executed, which does not set the :meth:`_sql.Insert.inline` 

1994 modifier, newly generated primary key values for this column 

1995 will be automatically retrieved upon statement execution 

1996 using a method specific to the database driver in use: 

1997 

1998 * MySQL, SQLite - calling upon ``cursor.lastrowid()`` 

1999 (see 

2000 `https://www.python.org/dev/peps/pep-0249/#lastrowid 

2001 <https://www.python.org/dev/peps/pep-0249/#lastrowid>`_) 

2002 * PostgreSQL, SQL Server, Oracle Database - use RETURNING or an equivalent 

2003 construct when rendering an INSERT statement, and then retrieving 

2004 the newly generated primary key values after execution 

2005 * PostgreSQL, Oracle Database for :class:`_schema.Table` objects that 

2006 set :paramref:`_schema.Table.implicit_returning` to False - 

2007 for a :class:`.Sequence` only, the :class:`.Sequence` is invoked 

2008 explicitly before the INSERT statement takes place so that the 

2009 newly generated primary key value is available to the client 

2010 * SQL Server for :class:`_schema.Table` objects that 

2011 set :paramref:`_schema.Table.implicit_returning` to False - 

2012 the ``SELECT scope_identity()`` construct is used after the 

2013 INSERT statement is invoked to retrieve the newly generated 

2014 primary key value. 

2015 * Third-party dialects - consult those dialects' documentation 

2016 for details on their specific behaviors. 

2017 

2018 * For multiple-row :func:`_sql.insert` constructs invoked with 

2019 a list of parameters (i.e. "executemany" semantics), primary-key 

2020 retrieving behaviors are generally disabled, however there may 

2021 be special APIs that may be used to retrieve lists of new 

2022 primary key values for an "executemany", such as the psycopg2 

2023 "fast insertmany" feature. Such features are very new and 

2024 may not yet be well covered in documentation. 

2025 

2026 :param default: A scalar, Python callable, or 

2027 :class:`_expression.ColumnElement` expression representing the 

2028 *default value* for this column, which will be invoked upon insert 

2029 if this column is otherwise not specified in the VALUES clause of 

2030 the insert. This is a shortcut to using :class:`.ColumnDefault` as 

2031 a positional argument; see that class for full detail on the 

2032 structure of the argument. 

2033 

2034 Contrast this argument to 

2035 :paramref:`_schema.Column.server_default` 

2036 which creates a default generator on the database side. 

2037 

2038 .. seealso:: 

2039 

2040 :ref:`metadata_defaults_toplevel` 

2041 

2042 :param insert_default: An alias of :paramref:`.Column.default` 

2043 for compatibility with :func:`_orm.mapped_column`. 

2044 

2045 .. versionadded:: 2.0.31 

2046 

2047 :param doc: optional String that can be used by the ORM or similar 

2048 to document attributes on the Python side. This attribute does 

2049 **not** render SQL comments; use the 

2050 :paramref:`_schema.Column.comment` 

2051 parameter for this purpose. 

2052 

2053 :param key: An optional string identifier which will identify this 

2054 ``Column`` object on the :class:`_schema.Table`. 

2055 When a key is provided, 

2056 this is the only identifier referencing the ``Column`` within the 

2057 application, including ORM attribute mapping; the ``name`` field 

2058 is used only when rendering SQL. 

2059 

2060 :param index: When ``True``, indicates that a :class:`_schema.Index` 

2061 construct will be automatically generated for this 

2062 :class:`_schema.Column`, which will result in a "CREATE INDEX" 

2063 statement being emitted for the :class:`_schema.Table` when the DDL 

2064 create operation is invoked. 

2065 

2066 Using this flag is equivalent to making use of the 

2067 :class:`_schema.Index` construct explicitly at the level of the 

2068 :class:`_schema.Table` construct itself:: 

2069 

2070 Table( 

2071 "some_table", 

2072 metadata, 

2073 Column("x", Integer), 

2074 Index("ix_some_table_x", "x"), 

2075 ) 

2076 

2077 To add the :paramref:`_schema.Index.unique` flag to the 

2078 :class:`_schema.Index`, set both the 

2079 :paramref:`_schema.Column.unique` and 

2080 :paramref:`_schema.Column.index` flags to True simultaneously, 

2081 which will have the effect of rendering the "CREATE UNIQUE INDEX" 

2082 DDL instruction instead of "CREATE INDEX". 

2083 

2084 The name of the index is generated using the 

2085 :ref:`default naming convention <constraint_default_naming_convention>` 

2086 which for the :class:`_schema.Index` construct is of the form 

2087 ``ix_<tablename>_<columnname>``. 

2088 

2089 As this flag is intended only as a convenience for the common case 

2090 of adding a single-column, default configured index to a table 

2091 definition, explicit use of the :class:`_schema.Index` construct 

2092 should be preferred for most use cases, including composite indexes 

2093 that encompass more than one column, indexes with SQL expressions 

2094 or ordering, backend-specific index configuration options, and 

2095 indexes that use a specific name. 

2096 

2097 .. note:: the :attr:`_schema.Column.index` attribute on 

2098 :class:`_schema.Column` 

2099 **does not indicate** if this column is indexed or not, only 

2100 if this flag was explicitly set here. To view indexes on 

2101 a column, view the :attr:`_schema.Table.indexes` collection 

2102 or use :meth:`_reflection.Inspector.get_indexes`. 

2103 

2104 .. seealso:: 

2105 

2106 :ref:`schema_indexes` 

2107 

2108 :ref:`constraint_naming_conventions` 

2109 

2110 :paramref:`_schema.Column.unique` 

2111 

2112 :param info: Optional data dictionary which will be populated into the 

2113 :attr:`.SchemaItem.info` attribute of this object. 

2114 

2115 :param nullable: When set to ``False``, will cause the "NOT NULL" 

2116 phrase to be added when generating DDL for the column. When 

2117 ``True``, will normally generate nothing (in SQL this defaults to 

2118 "NULL"), except in some very specific backend-specific edge cases 

2119 where "NULL" may render explicitly. 

2120 Defaults to ``True`` unless :paramref:`_schema.Column.primary_key` 

2121 is also ``True`` or the column specifies a :class:`_sql.Identity`, 

2122 in which case it defaults to ``False``. 

2123 This parameter is only used when issuing CREATE TABLE statements. 

2124 

2125 .. note:: 

2126 

2127 When the column specifies a :class:`_sql.Identity` this 

2128 parameter is in general ignored by the DDL compiler. The 

2129 PostgreSQL database allows nullable identity column by 

2130 setting this parameter to ``True`` explicitly. 

2131 

2132 :param onupdate: A scalar, Python callable, or 

2133 :class:`~sqlalchemy.sql.expression.ClauseElement` representing a 

2134 default value to be applied to the column within UPDATE 

2135 statements, which will be invoked upon update if this column is not 

2136 present in the SET clause of the update. This is a shortcut to 

2137 using :class:`.ColumnDefault` as a positional argument with 

2138 ``for_update=True``. 

2139 

2140 .. seealso:: 

2141 

2142 :ref:`metadata_defaults` - complete discussion of onupdate 

2143 

2144 :param primary_key: If ``True``, marks this column as a primary key 

2145 column. Multiple columns can have this flag set to specify 

2146 composite primary keys. As an alternative, the primary key of a 

2147 :class:`_schema.Table` can be specified via an explicit 

2148 :class:`.PrimaryKeyConstraint` object. 

2149 

2150 :param server_default: A :class:`.FetchedValue` instance, str, Unicode 

2151 or :func:`~sqlalchemy.sql.expression.text` construct representing 

2152 the DDL DEFAULT value for the column. 

2153 

2154 String types will be emitted as-is, surrounded by single quotes:: 

2155 

2156 Column("x", Text, server_default="val") 

2157 

2158 will render: 

2159 

2160 .. sourcecode:: sql 

2161 

2162 x TEXT DEFAULT 'val' 

2163 

2164 A :func:`~sqlalchemy.sql.expression.text` expression will be 

2165 rendered as-is, without quotes:: 

2166 

2167 Column("y", DateTime, server_default=text("NOW()")) 

2168 

2169 will render: 

2170 

2171 .. sourcecode:: sql 

2172 

2173 y DATETIME DEFAULT NOW() 

2174 

2175 Strings and text() will be converted into a 

2176 :class:`.DefaultClause` object upon initialization. 

2177 

2178 This parameter can also accept complex combinations of contextually 

2179 valid SQLAlchemy expressions or constructs:: 

2180 

2181 from sqlalchemy import create_engine 

2182 from sqlalchemy import Table, Column, MetaData, ARRAY, Text 

2183 from sqlalchemy.dialects.postgresql import array 

2184 

2185 engine = create_engine( 

2186 "postgresql+psycopg2://scott:tiger@localhost/mydatabase" 

2187 ) 

2188 metadata_obj = MetaData() 

2189 tbl = Table( 

2190 "foo", 

2191 metadata_obj, 

2192 Column( 

2193 "bar", ARRAY(Text), server_default=array(["biz", "bang", "bash"]) 

2194 ), 

2195 ) 

2196 metadata_obj.create_all(engine) 

2197 

2198 The above results in a table created with the following SQL: 

2199 

2200 .. sourcecode:: sql 

2201 

2202 CREATE TABLE foo ( 

2203 bar TEXT[] DEFAULT ARRAY['biz', 'bang', 'bash'] 

2204 ) 

2205 

2206 Use :class:`.FetchedValue` to indicate that an already-existing 

2207 column will generate a default value on the database side which 

2208 will be available to SQLAlchemy for post-fetch after inserts. This 

2209 construct does not specify any DDL and the implementation is left 

2210 to the database, such as via a trigger. 

2211 

2212 .. seealso:: 

2213 

2214 :ref:`server_defaults` - complete discussion of server side 

2215 defaults 

2216 

2217 :param server_onupdate: A :class:`.FetchedValue` instance 

2218 representing a database-side default generation function, 

2219 such as a trigger. This 

2220 indicates to SQLAlchemy that a newly generated value will be 

2221 available after updates. This construct does not actually 

2222 implement any kind of generation function within the database, 

2223 which instead must be specified separately. 

2224 

2225 

2226 .. warning:: This directive **does not** currently produce MySQL's 

2227 "ON UPDATE CURRENT_TIMESTAMP()" clause. See 

2228 :ref:`mysql_timestamp_onupdate` for background on how to 

2229 produce this clause. 

2230 

2231 .. seealso:: 

2232 

2233 :ref:`triggered_columns` 

2234 

2235 :param quote: Force quoting of this column's name on or off, 

2236 corresponding to ``True`` or ``False``. When left at its default 

2237 of ``None``, the column identifier will be quoted according to 

2238 whether the name is case sensitive (identifiers with at least one 

2239 upper case character are treated as case sensitive), or if it's a 

2240 reserved word. This flag is only needed to force quoting of a 

2241 reserved word which is not known by the SQLAlchemy dialect. 

2242 

2243 :param unique: When ``True``, and the :paramref:`_schema.Column.index` 

2244 parameter is left at its default value of ``False``, 

2245 indicates that a :class:`_schema.UniqueConstraint` 

2246 construct will be automatically generated for this 

2247 :class:`_schema.Column`, 

2248 which will result in a "UNIQUE CONSTRAINT" clause referring 

2249 to this column being included 

2250 in the ``CREATE TABLE`` statement emitted, when the DDL create 

2251 operation for the :class:`_schema.Table` object is invoked. 

2252 

2253 When this flag is ``True`` while the 

2254 :paramref:`_schema.Column.index` parameter is simultaneously 

2255 set to ``True``, the effect instead is that a 

2256 :class:`_schema.Index` construct which includes the 

2257 :paramref:`_schema.Index.unique` parameter set to ``True`` 

2258 is generated. See the documentation for 

2259 :paramref:`_schema.Column.index` for additional detail. 

2260 

2261 Using this flag is equivalent to making use of the 

2262 :class:`_schema.UniqueConstraint` construct explicitly at the 

2263 level of the :class:`_schema.Table` construct itself:: 

2264 

2265 Table("some_table", metadata, Column("x", Integer), UniqueConstraint("x")) 

2266 

2267 The :paramref:`_schema.UniqueConstraint.name` parameter 

2268 of the unique constraint object is left at its default value 

2269 of ``None``; in the absence of a :ref:`naming convention <constraint_naming_conventions>` 

2270 for the enclosing :class:`_schema.MetaData`, the UNIQUE CONSTRAINT 

2271 construct will be emitted as unnamed, which typically invokes 

2272 a database-specific naming convention to take place. 

2273 

2274 As this flag is intended only as a convenience for the common case 

2275 of adding a single-column, default configured unique constraint to a table 

2276 definition, explicit use of the :class:`_schema.UniqueConstraint` construct 

2277 should be preferred for most use cases, including composite constraints 

2278 that encompass more than one column, backend-specific index configuration options, and 

2279 constraints that use a specific name. 

2280 

2281 .. note:: the :attr:`_schema.Column.unique` attribute on 

2282 :class:`_schema.Column` 

2283 **does not indicate** if this column has a unique constraint or 

2284 not, only if this flag was explicitly set here. To view 

2285 indexes and unique constraints that may involve this column, 

2286 view the 

2287 :attr:`_schema.Table.indexes` and/or 

2288 :attr:`_schema.Table.constraints` collections or use 

2289 :meth:`_reflection.Inspector.get_indexes` and/or 

2290 :meth:`_reflection.Inspector.get_unique_constraints` 

2291 

2292 .. seealso:: 

2293 

2294 :ref:`schema_unique_constraint` 

2295 

2296 :ref:`constraint_naming_conventions` 

2297 

2298 :paramref:`_schema.Column.index` 

2299 

2300 :param system: When ``True``, indicates this is a "system" column, 

2301 that is a column which is automatically made available by the 

2302 database, and should not be included in the columns list for a 

2303 ``CREATE TABLE`` statement. 

2304 

2305 For more elaborate scenarios where columns should be 

2306 conditionally rendered differently on different backends, 

2307 consider custom compilation rules for :class:`.CreateColumn`. 

2308 

2309 :param comment: Optional string that will render an SQL comment on 

2310 table creation. 

2311 

2312 :param insert_sentinel: Marks this :class:`_schema.Column` as an 

2313 :term:`insert sentinel` used for optimizing the performance of the 

2314 :term:`insertmanyvalues` feature for tables that don't 

2315 otherwise have qualifying primary key configurations. 

2316 

2317 .. versionadded:: 2.0.10 

2318 

2319 .. seealso:: 

2320 

2321 :func:`_schema.insert_sentinel` - all in one helper for declaring 

2322 sentinel columns 

2323 

2324 :ref:`engine_insertmanyvalues` 

2325 

2326 :ref:`engine_insertmanyvalues_sentinel_columns` 

2327 

2328 

2329 """ # noqa: E501, RST201, RST202 

2330 

2331 l_args = [__name_pos, __type_pos] + list(args) 

2332 del args 

2333 

2334 if isinstance(l_args[0], str): 

2335 if name is not None: 

2336 raise exc.ArgumentError( 

2337 "May not pass name positionally and as a keyword." 

2338 ) 

2339 name = l_args.pop(0) # type: ignore[assignment] 

2340 elif l_args[0] is None: 

2341 l_args.pop(0) 

2342 if l_args: 

2343 coltype = l_args[0] 

2344 

2345 if hasattr(coltype, "_sqla_type"): 

2346 if type_ is not None: 

2347 raise exc.ArgumentError( 

2348 "May not pass type_ positionally and as a keyword." 

2349 ) 

2350 type_ = l_args.pop(0) # type: ignore[assignment] 

2351 elif l_args[0] is None: 

2352 l_args.pop(0) 

2353 

2354 if name is not None: 

2355 name = quoted_name(name, quote) 

2356 elif quote is not None: 

2357 raise exc.ArgumentError( 

2358 "Explicit 'name' is required when sending 'quote' argument" 

2359 ) 

2360 

2361 # name = None is expected to be an interim state 

2362 # note this use case is legacy now that ORM declarative has a 

2363 # dedicated "column" construct local to the ORM 

2364 super().__init__(name, type_) # type: ignore[arg-type] 

2365 

2366 self.key = key if key is not None else name # type: ignore[assignment] 

2367 self.primary_key = primary_key 

2368 self._insert_sentinel = insert_sentinel 

2369 self._omit_from_statements = _omit_from_statements 

2370 self._user_defined_nullable = udn = nullable 

2371 if udn is not NULL_UNSPECIFIED: 

2372 self.nullable = udn 

2373 else: 

2374 self.nullable = not primary_key 

2375 

2376 # these default to None because .index and .unique is *not* 

2377 # an informational flag about Column - there can still be an 

2378 # Index or UniqueConstraint referring to this Column. 

2379 self.index = index 

2380 self.unique = unique 

2381 

2382 self.system = system 

2383 self.doc = doc 

2384 self.autoincrement: _AutoIncrementType = autoincrement 

2385 self.constraints = set() 

2386 self.foreign_keys = set() 

2387 self.comment = comment 

2388 self.computed = None 

2389 self.identity = None 

2390 

2391 # check if this Column is proxying another column 

2392 

2393 if _proxies is not None: 

2394 self._proxies = _proxies 

2395 else: 

2396 # otherwise, add DDL-related events 

2397 self._set_type(self.type) 

2398 

2399 if insert_default is not _NoArg.NO_ARG: 

2400 if default is not _NoArg.NO_ARG: 

2401 raise exc.ArgumentError( 

2402 "The 'default' and 'insert_default' parameters " 

2403 "of Column are mutually exclusive" 

2404 ) 

2405 resolved_default = insert_default 

2406 elif default is not _NoArg.NO_ARG: 

2407 resolved_default = default 

2408 else: 

2409 resolved_default = None 

2410 

2411 if resolved_default is not None: 

2412 if not isinstance(resolved_default, (ColumnDefault, Sequence)): 

2413 resolved_default = ColumnDefault(resolved_default) 

2414 

2415 self.default = resolved_default 

2416 l_args.append(resolved_default) 

2417 else: 

2418 self.default = None 

2419 

2420 if onupdate is not None: 

2421 if not isinstance(onupdate, (ColumnDefault, Sequence)): 

2422 onupdate = ColumnDefault(onupdate, for_update=True) 

2423 

2424 self.onupdate = onupdate 

2425 l_args.append(onupdate) 

2426 else: 

2427 self.onupdate = None 

2428 

2429 if server_default is not None: 

2430 if isinstance(server_default, FetchedValue): 

2431 server_default = server_default._as_for_update(False) 

2432 l_args.append(server_default) 

2433 else: 

2434 server_default = DefaultClause(server_default) 

2435 l_args.append(server_default) 

2436 self.server_default = server_default 

2437 

2438 if server_onupdate is not None: 

2439 if isinstance(server_onupdate, FetchedValue): 

2440 server_onupdate = server_onupdate._as_for_update(True) 

2441 l_args.append(server_onupdate) 

2442 else: 

2443 server_onupdate = DefaultClause( 

2444 server_onupdate, for_update=True 

2445 ) 

2446 l_args.append(server_onupdate) 

2447 self.server_onupdate = server_onupdate 

2448 

2449 self._init_items(*cast(_typing_Sequence[SchemaItem], l_args)) 

2450 

2451 util.set_creation_order(self) 

2452 

2453 if info is not None: 

2454 self.info = info 

2455 

2456 self._extra_kwargs(**dialect_kwargs) 

2457 

2458 table: Table 

2459 

2460 constraints: Set[Constraint] 

2461 

2462 foreign_keys: Set[ForeignKey] 

2463 """A collection of all :class:`_schema.ForeignKey` marker objects 

2464 associated with this :class:`_schema.Column`. 

2465 

2466 Each object is a member of a :class:`_schema.Table`-wide 

2467 :class:`_schema.ForeignKeyConstraint`. 

2468 

2469 .. seealso:: 

2470 

2471 :attr:`_schema.Table.foreign_keys` 

2472 

2473 """ 

2474 

2475 index: Optional[bool] 

2476 """The value of the :paramref:`_schema.Column.index` parameter. 

2477 

2478 Does not indicate if this :class:`_schema.Column` is actually indexed 

2479 or not; use :attr:`_schema.Table.indexes`. 

2480 

2481 .. seealso:: 

2482 

2483 :attr:`_schema.Table.indexes` 

2484 """ 

2485 

2486 unique: Optional[bool] 

2487 """The value of the :paramref:`_schema.Column.unique` parameter. 

2488 

2489 Does not indicate if this :class:`_schema.Column` is actually subject to 

2490 a unique constraint or not; use :attr:`_schema.Table.indexes` and 

2491 :attr:`_schema.Table.constraints`. 

2492 

2493 .. seealso:: 

2494 

2495 :attr:`_schema.Table.indexes` 

2496 

2497 :attr:`_schema.Table.constraints`. 

2498 

2499 """ 

2500 

2501 computed: Optional[Computed] 

2502 

2503 identity: Optional[Identity] 

2504 

2505 def _set_type(self, type_: TypeEngine[Any]) -> None: 

2506 assert self.type._isnull or type_ is self.type 

2507 

2508 self.type = type_ 

2509 if isinstance(self.type, SchemaEventTarget): 

2510 self.type._set_parent_with_dispatch(self) 

2511 for impl in self.type._variant_mapping.values(): 

2512 if isinstance(impl, SchemaEventTarget): 

2513 impl._set_parent_with_dispatch(self) 

2514 

2515 @HasMemoized.memoized_attribute 

2516 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

2517 """used by default.py -> _process_execute_defaults()""" 

2518 

2519 return _DefaultDescriptionTuple._from_column_default(self.default) 

2520 

2521 @HasMemoized.memoized_attribute 

2522 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

2523 """used by default.py -> _process_execute_defaults()""" 

2524 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

2525 

2526 @util.memoized_property 

2527 def _gen_static_annotations_cache_key(self) -> bool: 

2528 """special attribute used by cache key gen, if true, we will 

2529 use a static cache key for the annotations dictionary, else we 

2530 will generate a new cache key for annotations each time. 

2531 

2532 Added for #8790 

2533 

2534 """ 

2535 return self.table is not None and self.table._is_table 

2536 

2537 def _extra_kwargs(self, **kwargs: Any) -> None: 

2538 self._validate_dialect_kwargs(kwargs) 

2539 

2540 def __str__(self) -> str: 

2541 if self.name is None: 

2542 return "(no name)" 

2543 elif self.table is not None: 

2544 if self.table.named_with_column: 

2545 return self.table.description + "." + self.description 

2546 else: 

2547 return self.description 

2548 else: 

2549 return self.description 

2550 

2551 def references(self, column: Column[Any]) -> bool: 

2552 """Return True if this Column references the given column via foreign 

2553 key.""" 

2554 

2555 for fk in self.foreign_keys: 

2556 if fk.column.proxy_set.intersection(column.proxy_set): 

2557 return True 

2558 else: 

2559 return False 

2560 

2561 def append_foreign_key(self, fk: ForeignKey) -> None: 

2562 fk._set_parent_with_dispatch(self) 

2563 

2564 def __repr__(self) -> str: 

2565 kwarg = [] 

2566 if self.key != self.name: 

2567 kwarg.append("key") 

2568 if self.primary_key: 

2569 kwarg.append("primary_key") 

2570 if not self.nullable: 

2571 kwarg.append("nullable") 

2572 if self.onupdate: 

2573 kwarg.append("onupdate") 

2574 if self.default: 

2575 kwarg.append("default") 

2576 if self.server_default: 

2577 kwarg.append("server_default") 

2578 if self.comment: 

2579 kwarg.append("comment") 

2580 return "Column(%s)" % ", ".join( 

2581 [repr(self.name)] 

2582 + [repr(self.type)] 

2583 + [repr(x) for x in self.foreign_keys if x is not None] 

2584 + [repr(x) for x in self.constraints] 

2585 + [ 

2586 ( 

2587 self.table is not None 

2588 and "table=<%s>" % self.table.description 

2589 or "table=None" 

2590 ) 

2591 ] 

2592 + ["%s=%s" % (k, repr(getattr(self, k))) for k in kwarg] 

2593 ) 

2594 

2595 def _set_parent( # type: ignore[override] 

2596 self, 

2597 parent: SchemaEventTarget, 

2598 *, 

2599 all_names: Dict[str, Column[Any]], 

2600 allow_replacements: bool, 

2601 index: Optional[int] = None, 

2602 **kw: Any, 

2603 ) -> None: 

2604 table = parent 

2605 assert isinstance(table, Table) 

2606 if not self.name: 

2607 raise exc.ArgumentError( 

2608 "Column must be constructed with a non-blank name or " 

2609 "assign a non-blank .name before adding to a Table." 

2610 ) 

2611 

2612 self._reset_memoizations() 

2613 

2614 if self.key is None: 

2615 self.key = self.name 

2616 

2617 existing = getattr(self, "table", None) 

2618 if existing is not None and existing is not table: 

2619 raise exc.ArgumentError( 

2620 f"Column object '{self.key}' already " 

2621 f"assigned to Table '{existing.description}'" 

2622 ) 

2623 

2624 extra_remove = None 

2625 existing_col = None 

2626 conflicts_on = "" 

2627 

2628 if self.key in table._columns: 

2629 existing_col = table._columns[self.key] 

2630 if self.key == self.name: 

2631 conflicts_on = "name" 

2632 else: 

2633 conflicts_on = "key" 

2634 elif self.name in all_names: 

2635 existing_col = all_names[self.name] 

2636 extra_remove = {existing_col} 

2637 conflicts_on = "name" 

2638 

2639 if existing_col is not None: 

2640 if existing_col is not self: 

2641 if not allow_replacements: 

2642 raise exc.DuplicateColumnError( 

2643 f"A column with {conflicts_on} " f"""'{ 

2644 self.key if conflicts_on == 'key' else self.name 

2645 }' """ f"is already present in table '{table.name}'." 

2646 ) 

2647 for fk in existing_col.foreign_keys: 

2648 table.foreign_keys.remove(fk) 

2649 if fk.constraint in table.constraints: 

2650 # this might have been removed 

2651 # already, if it's a composite constraint 

2652 # and more than one col being replaced 

2653 table.constraints.remove(fk.constraint) 

2654 

2655 if extra_remove and existing_col is not None and self.key == self.name: 

2656 util.warn( 

2657 f'Column with user-specified key "{existing_col.key}" is ' 

2658 "being replaced with " 

2659 f'plain named column "{self.name}", ' 

2660 f'key "{existing_col.key}" is being removed. If this is a ' 

2661 "reflection operation, specify autoload_replace=False to " 

2662 "prevent this replacement." 

2663 ) 

2664 table._columns.replace(self, extra_remove=extra_remove, index=index) 

2665 all_names[self.name] = self 

2666 self.table = table 

2667 

2668 if self._insert_sentinel: 

2669 if self.table._sentinel_column is not None: 

2670 raise exc.ArgumentError( 

2671 "a Table may have only one explicit sentinel column" 

2672 ) 

2673 self.table._sentinel_column = self 

2674 

2675 if self.primary_key: 

2676 table.primary_key._replace(self) 

2677 elif self.key in table.primary_key: 

2678 raise exc.ArgumentError( 

2679 f"Trying to redefine primary-key column '{self.key}' as a " 

2680 f"non-primary-key column on table '{table.fullname}'" 

2681 ) 

2682 

2683 if self.index: 

2684 if isinstance(self.index, str): 

2685 raise exc.ArgumentError( 

2686 "The 'index' keyword argument on Column is boolean only. " 

2687 "To create indexes with a specific name, create an " 

2688 "explicit Index object external to the Table." 

2689 ) 

2690 table.append_constraint( 

2691 Index( 

2692 None, self.key, unique=bool(self.unique), _column_flag=True 

2693 ) 

2694 ) 

2695 

2696 elif self.unique: 

2697 if isinstance(self.unique, str): 

2698 raise exc.ArgumentError( 

2699 "The 'unique' keyword argument on Column is boolean " 

2700 "only. To create unique constraints or indexes with a " 

2701 "specific name, append an explicit UniqueConstraint to " 

2702 "the Table's list of elements, or create an explicit " 

2703 "Index object external to the Table." 

2704 ) 

2705 table.append_constraint( 

2706 UniqueConstraint(self.key, _column_flag=True) 

2707 ) 

2708 

2709 self._setup_on_memoized_fks(lambda fk: fk._set_remote_table(table)) 

2710 

2711 if self.identity and ( 

2712 isinstance(self.default, Sequence) 

2713 or isinstance(self.onupdate, Sequence) 

2714 ): 

2715 raise exc.ArgumentError( 

2716 "An column cannot specify both Identity and Sequence." 

2717 ) 

2718 

2719 def _setup_on_memoized_fks(self, fn: Callable[..., Any]) -> None: 

2720 fk_keys = [ 

2721 ((self.table.key, self.key), False), 

2722 ((self.table.key, self.name), True), 

2723 ] 

2724 for fk_key, link_to_name in fk_keys: 

2725 if fk_key in self.table.metadata._fk_memos: 

2726 for fk in self.table.metadata._fk_memos[fk_key]: 

2727 if fk.link_to_name is link_to_name: 

2728 fn(fk) 

2729 

2730 def _on_table_attach(self, fn: Callable[..., Any]) -> None: 

2731 if self.table is not None: 

2732 fn(self, self.table) 

2733 else: 

2734 event.listen(self, "after_parent_attach", fn) 

2735 

2736 @util.deprecated( 

2737 "1.4", 

2738 "The :meth:`_schema.Column.copy` method is deprecated " 

2739 "and will be removed in a future release.", 

2740 ) 

2741 def copy(self, **kw: Any) -> Column[Any]: 

2742 return self._copy(**kw) 

2743 

2744 def _copy(self, **kw: Any) -> Column[Any]: 

2745 """Create a copy of this ``Column``, uninitialized. 

2746 

2747 This is used in :meth:`_schema.Table.to_metadata` and by the ORM. 

2748 

2749 """ 

2750 

2751 # Constraint objects plus non-constraint-bound ForeignKey objects 

2752 args: List[SchemaItem] = [ 

2753 c._copy(**kw) for c in self.constraints if not c._type_bound 

2754 ] + [c._copy(**kw) for c in self.foreign_keys if not c.constraint] 

2755 

2756 # ticket #5276 

2757 column_kwargs = {} 

2758 for dialect_name in self.dialect_options: 

2759 dialect_options = self.dialect_options[dialect_name]._non_defaults 

2760 for ( 

2761 dialect_option_key, 

2762 dialect_option_value, 

2763 ) in dialect_options.items(): 

2764 column_kwargs[dialect_name + "_" + dialect_option_key] = ( 

2765 dialect_option_value 

2766 ) 

2767 

2768 default = self.default 

2769 if default is not None: 

2770 default = default._copy() 

2771 onupdate = self.onupdate 

2772 if onupdate is not None: 

2773 onupdate = onupdate._copy() 

2774 server_default = self.server_default 

2775 server_onupdate = self.server_onupdate 

2776 if isinstance(server_default, (Computed, Identity)): 

2777 args.append(server_default._copy(**kw)) 

2778 server_default = server_onupdate = None 

2779 else: 

2780 if server_default is not None: 

2781 server_default = server_default._copy() 

2782 if server_onupdate is not None: 

2783 server_onupdate = server_onupdate._copy() 

2784 

2785 type_ = self.type 

2786 if isinstance(type_, SchemaEventTarget): 

2787 type_ = type_.copy(**kw) 

2788 

2789 c = self._constructor( 

2790 name=self.name, 

2791 type_=type_, 

2792 key=self.key, 

2793 primary_key=self.primary_key, 

2794 unique=self.unique, 

2795 system=self.system, 

2796 # quote=self.quote, # disabled 2013-08-27 (commit 031ef080) 

2797 index=self.index, 

2798 autoincrement=self.autoincrement, 

2799 default=default, 

2800 server_default=server_default, 

2801 onupdate=onupdate, 

2802 server_onupdate=server_onupdate, 

2803 doc=self.doc, 

2804 comment=self.comment, 

2805 _omit_from_statements=self._omit_from_statements, 

2806 insert_sentinel=self._insert_sentinel, 

2807 *args, 

2808 **column_kwargs, 

2809 ) 

2810 

2811 # copy the state of "nullable" exactly, to accommodate for 

2812 # ORM flipping the .nullable flag directly 

2813 c.nullable = self.nullable 

2814 c._user_defined_nullable = self._user_defined_nullable 

2815 

2816 return self._schema_item_copy(c) 

2817 

2818 def _merge( 

2819 self, other: Column[Any], *, omit_defaults: bool = False 

2820 ) -> None: 

2821 """merge the elements of this column onto "other" 

2822 

2823 this is used by ORM pep-593 merge and will likely need a lot 

2824 of fixes. 

2825 

2826 

2827 """ 

2828 

2829 if self.primary_key: 

2830 other.primary_key = True 

2831 

2832 if self.autoincrement != "auto" and other.autoincrement == "auto": 

2833 other.autoincrement = self.autoincrement 

2834 

2835 if self.system: 

2836 other.system = self.system 

2837 

2838 if self.info: 

2839 other.info.update(self.info) 

2840 

2841 type_ = self.type 

2842 if not type_._isnull and other.type._isnull: 

2843 if isinstance(type_, SchemaEventTarget): 

2844 type_ = type_.copy() 

2845 

2846 other.type = type_ 

2847 

2848 if isinstance(type_, SchemaEventTarget): 

2849 type_._set_parent_with_dispatch(other) 

2850 

2851 for impl in type_._variant_mapping.values(): 

2852 if isinstance(impl, SchemaEventTarget): 

2853 impl._set_parent_with_dispatch(other) 

2854 

2855 if ( 

2856 self._user_defined_nullable is not NULL_UNSPECIFIED 

2857 and other._user_defined_nullable is NULL_UNSPECIFIED 

2858 ): 

2859 other.nullable = self.nullable 

2860 other._user_defined_nullable = self._user_defined_nullable 

2861 

2862 if ( 

2863 not omit_defaults 

2864 and self.default is not None 

2865 and other.default is None 

2866 ): 

2867 new_default = self.default._copy() 

2868 new_default._set_parent(other) 

2869 

2870 if self.server_default and other.server_default is None: 

2871 new_server_default = self.server_default 

2872 if isinstance(new_server_default, FetchedValue): 

2873 new_server_default = new_server_default._copy() 

2874 new_server_default._set_parent(other) 

2875 else: 

2876 other.server_default = new_server_default 

2877 

2878 if self.server_onupdate and other.server_onupdate is None: 

2879 new_server_onupdate = self.server_onupdate 

2880 new_server_onupdate = new_server_onupdate._copy() 

2881 new_server_onupdate._set_parent(other) 

2882 

2883 if self.onupdate and other.onupdate is None: 

2884 new_onupdate = self.onupdate._copy() 

2885 new_onupdate._set_parent(other) 

2886 

2887 if self.index in (True, False) and other.index is None: 

2888 other.index = self.index 

2889 

2890 if self.unique in (True, False) and other.unique is None: 

2891 other.unique = self.unique 

2892 

2893 if self.doc and other.doc is None: 

2894 other.doc = self.doc 

2895 

2896 if self.comment and other.comment is None: 

2897 other.comment = self.comment 

2898 

2899 for const in self.constraints: 

2900 if not const._type_bound: 

2901 new_const = const._copy() 

2902 new_const._set_parent(other) 

2903 

2904 for fk in self.foreign_keys: 

2905 if not fk.constraint: 

2906 new_fk = fk._copy() 

2907 new_fk._set_parent(other) 

2908 

2909 def _make_proxy( 

2910 self, 

2911 selectable: FromClause, 

2912 primary_key: ColumnSet, 

2913 foreign_keys: Set[KeyedColumnElement[Any]], 

2914 name: Optional[str] = None, 

2915 key: Optional[str] = None, 

2916 name_is_truncatable: bool = False, 

2917 compound_select_cols: Optional[ 

2918 _typing_Sequence[ColumnElement[Any]] 

2919 ] = None, 

2920 **kw: Any, 

2921 ) -> Tuple[str, ColumnClause[_T]]: 

2922 """Create a *proxy* for this column. 

2923 

2924 This is a copy of this ``Column`` referenced by a different parent 

2925 (such as an alias or select statement). The column should 

2926 be used only in select scenarios, as its full DDL/default 

2927 information is not transferred. 

2928 

2929 """ 

2930 

2931 fk = [ 

2932 ForeignKey( 

2933 col if col is not None else f.target_tokens, 

2934 _unresolvable=col is None, 

2935 _constraint=f.constraint, 

2936 ) 

2937 for f, col in [ 

2938 (fk, fk._resolve_column(raiseerr=False)) 

2939 for fk in self.foreign_keys 

2940 ] 

2941 ] 

2942 

2943 if name is None and self.name is None: 

2944 raise exc.InvalidRequestError( 

2945 "Cannot initialize a sub-selectable" 

2946 " with this Column object until its 'name' has " 

2947 "been assigned." 

2948 ) 

2949 try: 

2950 c = self._constructor( 

2951 ( 

2952 coercions.expect( 

2953 roles.TruncatedLabelRole, name if name else self.name 

2954 ) 

2955 if name_is_truncatable 

2956 else (name or self.name) 

2957 ), 

2958 self.type, 

2959 # this may actually be ._proxy_key when the key is incoming 

2960 key=key if key else name if name else self.key, 

2961 primary_key=self.primary_key, 

2962 nullable=self.nullable, 

2963 _proxies=( 

2964 list(compound_select_cols) 

2965 if compound_select_cols 

2966 else [self] 

2967 ), 

2968 *fk, 

2969 ) 

2970 except TypeError as err: 

2971 raise TypeError( 

2972 "Could not create a copy of this %r object. " 

2973 "Ensure the class includes a _constructor() " 

2974 "attribute or method which accepts the " 

2975 "standard Column constructor arguments, or " 

2976 "references the Column class itself." % self.__class__ 

2977 ) from err 

2978 

2979 c.table = selectable 

2980 c._propagate_attrs = selectable._propagate_attrs 

2981 if selectable._is_clone_of is not None: 

2982 c._is_clone_of = selectable._is_clone_of.columns.get(c.key) 

2983 

2984 if self.primary_key: 

2985 primary_key.add(c) 

2986 

2987 if fk: 

2988 foreign_keys.update(fk) # type: ignore[arg-type] 

2989 

2990 return c.key, c 

2991 

2992 

2993def insert_sentinel( 

2994 name: Optional[str] = None, 

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

2996 *, 

2997 default: Optional[Any] = None, 

2998 omit_from_statements: bool = True, 

2999) -> Column[Any]: 

3000 """Provides a surrogate :class:`_schema.Column` that will act as a 

3001 dedicated insert :term:`sentinel` column, allowing efficient bulk 

3002 inserts with deterministic RETURNING sorting for tables that 

3003 don't otherwise have qualifying primary key configurations. 

3004 

3005 Adding this column to a :class:`.Table` object requires that a 

3006 corresponding database table actually has this column present, so if adding 

3007 it to an existing model, existing database tables would need to be migrated 

3008 (e.g. using ALTER TABLE or similar) to include this column. 

3009 

3010 For background on how this object is used, see the section 

3011 :ref:`engine_insertmanyvalues_sentinel_columns` as part of the 

3012 section :ref:`engine_insertmanyvalues`. 

3013 

3014 The :class:`_schema.Column` returned will be a nullable integer column by 

3015 default and make use of a sentinel-specific default generator used only in 

3016 "insertmanyvalues" operations. 

3017 

3018 .. seealso:: 

3019 

3020 :func:`_orm.orm_insert_sentinel` 

3021 

3022 :paramref:`_schema.Column.insert_sentinel` 

3023 

3024 :ref:`engine_insertmanyvalues` 

3025 

3026 :ref:`engine_insertmanyvalues_sentinel_columns` 

3027 

3028 

3029 .. versionadded:: 2.0.10 

3030 

3031 """ 

3032 return Column( 

3033 name=name, 

3034 type_=type_api.INTEGERTYPE if type_ is None else type_, 

3035 default=( 

3036 default if default is not None else _InsertSentinelColumnDefault() 

3037 ), 

3038 _omit_from_statements=omit_from_statements, 

3039 insert_sentinel=True, 

3040 ) 

3041 

3042 

3043class ForeignKeyTarget(NamedTuple): 

3044 """Represents the target of a :class:`_schema.ForeignKey` as three 

3045 individual name tokens. 

3046 

3047 This is the return value of :attr:`_schema.ForeignKey.target_tokens`, and 

3048 may also be passed directly to the :class:`_schema.ForeignKey` constructor 

3049 as well as to the :paramref:`_schema.ForeignKeyConstraint.refcolumns` 

3050 parameter, as either a three-token tuple ``(schema, table_name, 

3051 column_name)`` or a two-token tuple ``(table_name, column_name)``. 

3052 

3053 The token form is the only representation of a foreign key target that is 

3054 unambiguous in all cases; the dotted string form, available at 

3055 :attr:`_schema.ForeignKey.target_fullname`, cannot represent a target 

3056 where the table or column name itself contains a dot. 

3057 

3058 .. versionadded:: 2.1 

3059 

3060 .. seealso:: 

3061 

3062 :attr:`_schema.ForeignKey.target_tokens` 

3063 

3064 """ 

3065 

3066 schema: Optional[str] 

3067 """The schema name of the target, or ``None`` for the default schema.""" 

3068 

3069 table_name: str 

3070 """The name of the target table.""" 

3071 

3072 column_name: Optional[str] 

3073 """The key of the target column. 

3074 

3075 This is ``None`` for a :class:`_schema.ForeignKey` that was given a table 

3076 name only, in which case the local column's key is used to locate the 

3077 target column. 

3078 

3079 Note that this is the ``key`` of the target column rather than its name, 

3080 unless :paramref:`_schema.ForeignKey.link_to_name` is ``True``. 

3081 

3082 """ 

3083 

3084 def _tokens_no_dots(self) -> _typing_Sequence[str] | None: 

3085 """return a sequence of non-None tokens to create a dotted name. 

3086 

3087 returns None if either of table_name or column_name already have an 

3088 embedded dot, making dotted name string impossible. 

3089 

3090 """ 

3091 tokens = [] 

3092 for i, token in enumerate( 

3093 [self.schema, self.table_name, self.column_name] 

3094 ): 

3095 if token is not None: 

3096 # dot in the table name or column name; a dotted name 

3097 # would be ambiguous 

3098 if i != 0 and "." in token: 

3099 return None 

3100 tokens.append(token) 

3101 elif i == 1: 

3102 # table name is None; not renderable 

3103 return None 

3104 elif i == 2 and self.schema: 

3105 # column name is None and there's a schema; a dotted 

3106 # name would be ambiguous 

3107 return None 

3108 

3109 return tokens 

3110 

3111 def _as_string(self) -> str: 

3112 """Render these tokens as a single dotted string if possible, 

3113 else raise :class:`.InvalidRequestError` if no unambiguous string form 

3114 exists and a string is required. 

3115 

3116 """ 

3117 

3118 tokens_no_dots = self._tokens_no_dots() 

3119 

3120 if tokens_no_dots is None: 

3121 

3122 if not self.table_name: 

3123 reason = ( 

3124 "the target has no table name; a ForeignKey to a Column " 

3125 "which is not yet associated with a Table has no names " 

3126 "to render until that Column is attached" 

3127 ) 

3128 elif "." in self.table_name: 

3129 reason = ( 

3130 f"the table name {self.table_name!r} contains a dot, " 

3131 f"which can't be told apart from the separator between " 

3132 f"a schema name and a table name" 

3133 ) 

3134 elif self.column_name is not None and "." in self.column_name: 

3135 reason = ( 

3136 f"the column name {self.column_name!r} contains a dot, " 

3137 f"which can't be told apart from the separator between " 

3138 f"a table name and a column name" 

3139 ) 

3140 elif self.column_name is None: 

3141 reason = ( 

3142 f"a schema name {self.schema!r} is present with no " 

3143 f"column name, so the schema name can't be told apart " 

3144 f"from a table name" 

3145 ) 

3146 else: 

3147 # this is currently unreachable based on the current behavior 

3148 # of tokens_no_dots 

3149 assert False 

3150 

3151 raise exc.InvalidRequestError( 

3152 f"Can't render a single string representation for foreign " 

3153 f"key target {self._description()}; {reason}. Use " 

3154 f"ForeignKey.target_tokens to receive the schema, table and " 

3155 f"column names individually." 

3156 ) 

3157 

3158 return ".".join(tokens_no_dots) 

3159 

3160 def _description(self) -> str: 

3161 """Render a description of these tokens which never raises. 

3162 

3163 The dotted string form is preferred when it's available, falling 

3164 back to naming the tokens individually when it isn't. 

3165 

3166 """ 

3167 

3168 tokens_no_dots = self._tokens_no_dots() 

3169 if tokens_no_dots: 

3170 return repr(".".join(tokens_no_dots)) 

3171 else: 

3172 return ( 

3173 f"(schema={self.schema!r}, " 

3174 f"table_name={self.table_name!r}, " 

3175 f"column_name={self.column_name!r})" 

3176 ) 

3177 

3178 @classmethod 

3179 def _from_string(cls, spec: str) -> ForeignKeyTarget: 

3180 """Parse a dotted string colspec into its component tokens. 

3181 

3182 A FK between column 'bar' and table 'foo' can be specified as 'foo', 

3183 'foo.bar', 'dbo.foo.bar', 'otherdb.dbo.foo.bar'. Once we have the 

3184 column name and the table name, treat everything else as the schema 

3185 name. Some databases (e.g. Sybase) support inter-database foreign 

3186 keys. See tickets #1341 and -- indirectly related -- #594. 

3187 

3188 This assumes that '.' will never appear *within* the table or column 

3189 name; a target which does contain such a dot has no string form and 

3190 must be given as a :class:`.ForeignKeyTarget` instead. 

3191 

3192 """ 

3193 m = spec.split(".") 

3194 if len(m) == 1: 

3195 return cls(None, m[0], None) 

3196 

3197 colname = m.pop() 

3198 tname = m.pop() 

3199 return cls(".".join(m) if m else None, tname, colname) 

3200 

3201 @classmethod 

3202 def _from_argument( 

3203 cls, argument: _typing_Sequence[Any] 

3204 ) -> ForeignKeyTarget: 

3205 """Coerce a two or three token sequence passed by the user.""" 

3206 

3207 if len(argument) == 3: 

3208 schema, table_name, column_name = argument 

3209 elif len(argument) == 2: 

3210 schema = None 

3211 table_name, column_name = argument 

3212 else: 

3213 raise exc.ArgumentError( 

3214 f"ForeignKey target given as a tuple must have two tokens " 

3215 f"(table_name, column_name) or three tokens " 

3216 f"(schema, table_name, column_name); got {len(argument)}" 

3217 ) 

3218 

3219 if not table_name: 

3220 raise exc.ArgumentError( 

3221 "ForeignKey target table_name must be a non-empty string" 

3222 ) 

3223 

3224 return cls(schema, table_name, column_name) 

3225 

3226 

3227class ForeignKey(DialectKWArgs, SchemaItem): 

3228 """Defines a dependency between two columns. 

3229 

3230 ``ForeignKey`` is specified as an argument to a :class:`_schema.Column` 

3231 object, 

3232 e.g.:: 

3233 

3234 t = Table( 

3235 "remote_table", 

3236 metadata, 

3237 Column("remote_id", ForeignKey("main_table.id")), 

3238 ) 

3239 

3240 Note that ``ForeignKey`` is only a marker object that defines 

3241 a dependency between two columns. The actual constraint 

3242 is in all cases represented by the :class:`_schema.ForeignKeyConstraint` 

3243 object. This object will be generated automatically when 

3244 a ``ForeignKey`` is associated with a :class:`_schema.Column` which 

3245 in turn is associated with a :class:`_schema.Table`. Conversely, 

3246 when :class:`_schema.ForeignKeyConstraint` is applied to a 

3247 :class:`_schema.Table`, 

3248 ``ForeignKey`` markers are automatically generated to be 

3249 present on each associated :class:`_schema.Column`, which are also 

3250 associated with the constraint object. 

3251 

3252 Note that you cannot define a "composite" foreign key constraint, 

3253 that is a constraint between a grouping of multiple parent/child 

3254 columns, using ``ForeignKey`` objects. To define this grouping, 

3255 the :class:`_schema.ForeignKeyConstraint` object must be used, and applied 

3256 to the :class:`_schema.Table`. The associated ``ForeignKey`` objects 

3257 are created automatically. 

3258 

3259 The ``ForeignKey`` objects associated with an individual 

3260 :class:`_schema.Column` 

3261 object are available in the `foreign_keys` collection 

3262 of that column. 

3263 

3264 The target of a ``ForeignKey`` is described by three names -- a schema 

3265 name, a table name and a column name -- which are available at 

3266 :attr:`_schema.ForeignKey.target_tokens` as a 

3267 :class:`_schema.ForeignKeyTarget` named tuple:: 

3268 

3269 >>> fk = ForeignKey("main_table.id") 

3270 >>> fk.target_tokens 

3271 ForeignKeyTarget(schema=None, table_name='main_table', column_name='id') 

3272 

3273 The same three names may be given to ``ForeignKey`` in place of the 

3274 dotted string, as either a two or three token tuple. This is the only 

3275 way to name a target whose table or column name itself contains a dot, 

3276 as the dotted string form has no way of telling such a dot apart from 

3277 the separator between two names:: 

3278 

3279 ForeignKey(("my.tbl", "id")) 

3280 ForeignKey(("my_schema", "my.tbl", "id")) 

3281 

3282 .. versionadded:: 2.1 :attr:`_schema.ForeignKey.target_tokens`, and the 

3283 tuple form of the target. 

3284 

3285 Where the target was given as a :class:`_schema.Column` rather than by 

3286 name, that column is available at 

3287 :attr:`_schema.ForeignKey.target_column`; this is distinct from 

3288 :attr:`_schema.ForeignKey.column`, which is the *resolved* target however 

3289 it was specified. :attr:`_schema.ForeignKey.target_table_key` gives the 

3290 key under which the referenced :class:`_schema.Table` is, or would be, 

3291 registered in :attr:`_schema.MetaData.tables`. 

3292 

3293 Further examples of foreign key configuration are in 

3294 :ref:`metadata_foreignkeys`. 

3295 

3296 """ # noqa: E501 

3297 

3298 __visit_name__ = "foreign_key" 

3299 

3300 parent: Column[Any] 

3301 

3302 _table_column: Optional[Column[Any]] 

3303 """Storage for :attr:`.ForeignKey.target_column`; read that instead. 

3304 

3305 ``None`` when the target was given by name, in which case 

3306 :attr:`.ForeignKey._given_tokens` holds those names. 

3307 

3308 """ 

3309 

3310 _given_tokens: Optional[ForeignKeyTarget] 

3311 """The names of the target, when the target was given by name. 

3312 

3313 ``None`` when the target was given as a :class:`.Column`, in which case 

3314 the names are derived from that column on demand -- read 

3315 :attr:`.ForeignKey.target_tokens` rather than this. 

3316 

3317 """ 

3318 

3319 def __init__( 

3320 self, 

3321 column: _DDLColumnReferenceArgument, 

3322 _constraint: Optional[ForeignKeyConstraint] = None, 

3323 use_alter: bool = False, 

3324 name: _ConstraintNameArgument = None, 

3325 onupdate: Optional[str] = None, 

3326 ondelete: Optional[str] = None, 

3327 deferrable: Optional[bool] = None, 

3328 initially: Optional[str] = None, 

3329 link_to_name: bool = False, 

3330 match: Optional[str] = None, 

3331 info: Optional[_InfoType] = None, 

3332 comment: Optional[str] = None, 

3333 _unresolvable: bool = False, 

3334 **dialect_kw: Any, 

3335 ): 

3336 r""" 

3337 Construct a column-level FOREIGN KEY. 

3338 

3339 The :class:`_schema.ForeignKey` object when constructed generates a 

3340 :class:`_schema.ForeignKeyConstraint` 

3341 which is associated with the parent 

3342 :class:`_schema.Table` object's collection of constraints. 

3343 

3344 :param column: A single target column for the key relationship. A 

3345 :class:`_schema.Column` object or a column name as a string: 

3346 ``tablename.columnkey`` or ``schema.tablename.columnkey``. 

3347 ``columnkey`` is the ``key`` which has been assigned to the column 

3348 (defaults to the column name itself), unless ``link_to_name`` is 

3349 ``True`` in which case the rendered name of the column is used. 

3350 

3351 The target may also be given as a tuple of individual name 

3352 tokens, either ``(table_name, column_name)`` or 

3353 ``(schema, table_name, column_name)``. This is the only form 

3354 which can refer to a name that itself contains a dot, as the 

3355 dotted string form has no way of telling such a dot apart from 

3356 the separator between two names:: 

3357 

3358 ForeignKey(("my.tbl", "z")) 

3359 

3360 .. versionadded:: 2.1 The tuple form. 

3361 

3362 :param name: Optional string. An in-database name for the key if 

3363 `constraint` is not provided. 

3364 

3365 :param onupdate: Optional string. If set, emit ON UPDATE <value> when 

3366 issuing DDL for this constraint. Typical values include CASCADE, 

3367 DELETE and RESTRICT. 

3368 

3369 .. seealso:: 

3370 

3371 :ref:`on_update_on_delete` 

3372 

3373 :param ondelete: Optional string. If set, emit ON DELETE <value> when 

3374 issuing DDL for this constraint. Typical values include CASCADE, 

3375 SET NULL and RESTRICT. Some dialects may allow for additional 

3376 syntaxes. 

3377 

3378 .. seealso:: 

3379 

3380 :ref:`on_update_on_delete` 

3381 

3382 :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT 

3383 DEFERRABLE when issuing DDL for this constraint. 

3384 

3385 :param initially: Optional string. If set, emit INITIALLY <value> when 

3386 issuing DDL for this constraint. 

3387 

3388 :param link_to_name: if True, the string name given in ``column`` is 

3389 the rendered name of the referenced column, not its locally 

3390 assigned ``key``. 

3391 

3392 :param use_alter: passed to the underlying 

3393 :class:`_schema.ForeignKeyConstraint` 

3394 to indicate the constraint should 

3395 be generated/dropped externally from the CREATE TABLE/ DROP TABLE 

3396 statement. See :paramref:`_schema.ForeignKeyConstraint.use_alter` 

3397 for further description. 

3398 

3399 .. seealso:: 

3400 

3401 :paramref:`_schema.ForeignKeyConstraint.use_alter` 

3402 

3403 :ref:`use_alter` 

3404 

3405 :param match: Optional string. If set, emit MATCH <value> when issuing 

3406 DDL for this constraint. Typical values include SIMPLE, PARTIAL 

3407 and FULL. 

3408 

3409 :param info: Optional data dictionary which will be populated into the 

3410 :attr:`.SchemaItem.info` attribute of this object. 

3411 

3412 :param comment: Optional string that will render an SQL comment on 

3413 foreign key constraint creation. 

3414 

3415 .. versionadded:: 2.0 

3416 

3417 :param \**dialect_kw: Additional keyword arguments are dialect 

3418 specific, and passed in the form ``<dialectname>_<argname>``. The 

3419 arguments are ultimately handled by a corresponding 

3420 :class:`_schema.ForeignKeyConstraint`. 

3421 See the documentation regarding 

3422 an individual dialect at :ref:`dialect_toplevel` for detail on 

3423 documented arguments. 

3424 

3425 """ 

3426 

3427 self._unresolvable = _unresolvable 

3428 

3429 self._table_column, self._given_tokens = self._parse_colspec_argument( 

3430 column 

3431 ) 

3432 

3433 # the linked ForeignKeyConstraint. 

3434 # ForeignKey will create this when parent Column 

3435 # is attached to a Table, *or* ForeignKeyConstraint 

3436 # object passes itself in when creating ForeignKey 

3437 # markers. 

3438 self.constraint = _constraint 

3439 

3440 # .parent is not Optional under normal use 

3441 self.parent = None # type: ignore[assignment] 

3442 

3443 self.use_alter = use_alter 

3444 self.name = name 

3445 self.onupdate = onupdate 

3446 self.ondelete = ondelete 

3447 self.deferrable = deferrable 

3448 self.initially = initially 

3449 self.link_to_name = link_to_name 

3450 self.match = match 

3451 self.comment = comment 

3452 if info: 

3453 self.info = info 

3454 self._unvalidated_dialect_kw = dialect_kw 

3455 

3456 def _parse_colspec_argument( 

3457 self, 

3458 argument: _DDLColumnReferenceArgument, 

3459 ) -> Tuple[Optional[Column[Any]], ForeignKeyTarget]: 

3460 """Coerce the ``column`` argument into the target 

3461 :class:`.ForeignKeyTarget`, along with the target :class:`.Column` 

3462 itself if that's how the target was given. 

3463 

3464 """ 

3465 if isinstance(argument, tuple): 

3466 return None, ForeignKeyTarget._from_argument(argument) 

3467 

3468 _colspec = coercions.expect(roles.DDLReferredColumnRole, argument) 

3469 

3470 if isinstance(_colspec, str): 

3471 return None, ForeignKeyTarget._from_string(_colspec) 

3472 

3473 assert isinstance(_colspec, ColumnClause) 

3474 

3475 table = _colspec.table 

3476 if not isinstance(table, (type(None), TableClause)): 

3477 # a Column of some other FromClause, e.g. a subquery or a join; 

3478 # the target of a ForeignKey has to be a Table (or a TableClause, 

3479 # or a Column not yet associated with either) 

3480 raise exc.ArgumentError( 

3481 f"ForeignKey target Column {_colspec!r} is associated with " 

3482 f"{table!r}, which is not a Table; a foreign key may only " 

3483 f"target a Column of a Table" 

3484 ) 

3485 elif table is None: 

3486 # a Column not yet associated with a Table; this is the 

3487 # declarative mixin + declared_attr case, where the target column 

3488 # is attached to its Table after this ForeignKey is constructed 

3489 return _colspec, ForeignKeyTarget(None, _colspec.key, None) 

3490 else: 

3491 return _colspec, ForeignKeyTarget( 

3492 table.schema, table.name, _colspec.key 

3493 ) 

3494 

3495 def __repr__(self) -> str: 

3496 tokens = self.target_tokens 

3497 tokens_no_dots = self.target_tokens._tokens_no_dots() 

3498 

3499 if tokens_no_dots: 

3500 return f"ForeignKey({'.'.join(tokens_no_dots)!r})" 

3501 else: 

3502 # no string form for this target, so name the tokens; this still 

3503 # round trips, as ForeignKeyTarget is accepted by the constructor 

3504 return f"ForeignKey({tokens!r})" 

3505 

3506 @util.deprecated( 

3507 "1.4", 

3508 "The :meth:`_schema.ForeignKey.copy` method is deprecated " 

3509 "and will be removed in a future release.", 

3510 ) 

3511 def copy(self, *, schema: Optional[str] = None, **kw: Any) -> ForeignKey: 

3512 return self._copy(schema=schema, **kw) 

3513 

3514 def _copy(self, *, schema: Optional[str] = None, **kw: Any) -> ForeignKey: 

3515 """Produce a copy of this :class:`_schema.ForeignKey` object. 

3516 

3517 The new :class:`_schema.ForeignKey` will not be bound 

3518 to any :class:`_schema.Column`. 

3519 

3520 This method is usually used by the internal 

3521 copy procedures of :class:`_schema.Column`, :class:`_schema.Table`, 

3522 and :class:`_schema.MetaData`. 

3523 

3524 :param schema: The returned :class:`_schema.ForeignKey` will 

3525 reference the original table and column name, qualified 

3526 by the given string schema name. 

3527 

3528 """ 

3529 fk = ForeignKey( 

3530 self._copy_tokens(schema=schema), 

3531 use_alter=self.use_alter, 

3532 name=self.name, 

3533 onupdate=self.onupdate, 

3534 ondelete=self.ondelete, 

3535 deferrable=self.deferrable, 

3536 initially=self.initially, 

3537 link_to_name=self.link_to_name, 

3538 match=self.match, 

3539 comment=self.comment, 

3540 **self._unvalidated_dialect_kw, 

3541 ) 

3542 return self._schema_item_copy(fk) 

3543 

3544 @property 

3545 def target_tokens(self) -> ForeignKeyTarget: 

3546 """Return the target of this :class:`_schema.ForeignKey` as three 

3547 individual name tokens. 

3548 

3549 The return value is a :class:`_schema.ForeignKeyTarget` named tuple of 

3550 ``(schema, table_name, column_name)``. This is the representation 

3551 SQLAlchemy itself computes against; unlike 

3552 :attr:`_schema.ForeignKey.target_fullname` it is available in all 

3553 cases, including when one of the names contains a dot:: 

3554 

3555 >>> from sqlalchemy import Column, ForeignKey, Integer, MetaData, Table 

3556 >>> m = MetaData() 

3557 >>> r = Table("my.tbl", m, Column("z", Integer, primary_key=True)) 

3558 >>> t = Table("t", m, Column("a", Integer, ForeignKey(r.c.z))) 

3559 >>> list(t.c.a.foreign_keys)[0].target_tokens 

3560 ForeignKeyTarget(schema=None, table_name='my.tbl', column_name='z') 

3561 

3562 The tokens describe the target as it was specified, and are available 

3563 whether or not the target :class:`_schema.Column` has been resolved; 

3564 for the resolved column, see :attr:`_schema.ForeignKey.column`. 

3565 

3566 .. versionadded:: 2.1 

3567 

3568 .. seealso:: 

3569 

3570 :class:`_schema.ForeignKeyTarget` 

3571 

3572 """ # noqa: E501 

3573 

3574 col = self._table_column 

3575 if col is None: 

3576 assert self._given_tokens is not None 

3577 return self._given_tokens 

3578 

3579 # derived on demand rather than captured up front: a target Column 

3580 # may gain both its name and its Table *after* this ForeignKey is 

3581 # constructed, which is what a declarative mixin using declared_attr 

3582 # does (see test_fk_mixin_self_referential_declared_attr) 

3583 table = col.table 

3584 if table is None: 

3585 return ForeignKeyTarget(None, col.key, None) 

3586 

3587 return ForeignKeyTarget(table.schema, table.name, col.key) 

3588 

3589 @property 

3590 def target_column(self) -> Optional[Column[Any]]: 

3591 """Return the target :class:`_schema.Column` of this 

3592 :class:`_schema.ForeignKey`, if the target was given as one. 

3593 

3594 Returns ``None`` when the target was instead given by name, as a 

3595 string or as :class:`_schema.ForeignKeyTarget`; in that case only 

3596 :attr:`_schema.ForeignKey.target_tokens` describes the target until 

3597 it is resolved. 

3598 

3599 This is distinct from :attr:`_schema.ForeignKey.column`, which is the 

3600 *resolved* target however it was specified, and which raises if the 

3601 target can't be resolved. Note also that a target given as a 

3602 :class:`_schema.Column` need not be associated with a 

3603 :class:`_schema.Table` yet. 

3604 

3605 .. versionadded:: 2.1 

3606 

3607 .. seealso:: 

3608 

3609 :attr:`_schema.ForeignKey.target_tokens` 

3610 

3611 :attr:`_schema.ForeignKey.column` 

3612 

3613 """ 

3614 return self._table_column 

3615 

3616 @property 

3617 def _column_tokens(self) -> ForeignKeyTarget: 

3618 """legacy private name for :attr:`.ForeignKey.target_tokens`""" 

3619 

3620 return self.target_tokens 

3621 

3622 @property 

3623 def _colspec(self) -> Union[str, Column[Any]]: 

3624 """Legacy accessor for the target in its pre-2.1 form, either the 

3625 target :class:`.Column` or a dotted string. 

3626 

3627 Raises :class:`.InvalidRequestError` for a target which has no dotted 

3628 string form. Kept for the benefit of third party code which reads it; 

3629 :attr:`.ForeignKey.target_tokens` is what SQLAlchemy itself uses. 

3630 

3631 """ 

3632 col = self.target_column 

3633 return self.target_tokens._as_string() if col is None else col 

3634 

3635 def _copy_tokens( 

3636 self, 

3637 schema: Optional[ 

3638 Union[ 

3639 str, 

3640 Literal[SchemaConst.RETAIN_SCHEMA, SchemaConst.BLANK_SCHEMA], 

3641 ] 

3642 ] = None, 

3643 table_name: Optional[str] = None, 

3644 _is_copy: bool = False, 

3645 ) -> ForeignKeyTarget: 

3646 """Return the tokens for a copy of this :class:`_schema.ForeignKey`, 

3647 optionally rewriting the schema and/or table name. 

3648 

3649 """ 

3650 

3651 col = self.target_column 

3652 

3653 if _is_copy and col is not None and col.table is None: 

3654 raise exc.InvalidRequestError( 

3655 f"Can't copy ForeignKey object which refers to " 

3656 f"non-table bound Column {col!r}" 

3657 ) 

3658 

3659 tokens = self.target_tokens 

3660 

3661 if schema not in (None, RETAIN_SCHEMA): 

3662 return ForeignKeyTarget( 

3663 None if schema is BLANK_SCHEMA else schema, 

3664 table_name if table_name is not None else tokens.table_name, 

3665 tokens.column_name, 

3666 ) 

3667 elif table_name: 

3668 return tokens._replace(table_name=table_name) 

3669 else: 

3670 return tokens 

3671 

3672 def _get_colspec(self) -> str: 

3673 """legacy method for :attr:`.ForeignKey.target_fullname`. 

3674 

3675 Retained as third party code makes use of it; new code should use 

3676 :attr:`.ForeignKey.target_tokens`. 

3677 

3678 """ 

3679 

3680 return self.target_fullname 

3681 

3682 @property 

3683 def _referred_schema(self) -> Optional[str]: 

3684 return self.target_tokens.schema 

3685 

3686 @property 

3687 def target_table_key(self) -> Optional[str]: 

3688 """Return the key under which the target :class:`_schema.Table` is, 

3689 or would be, registered in :attr:`_schema.MetaData.tables`. 

3690 

3691 This is derived from :attr:`_schema.ForeignKey.target_tokens`, and is 

3692 available whether or not the target table exists yet, making it 

3693 usable while a :class:`_schema.Table` is still being constructed. 

3694 

3695 Returns ``None`` in the one case where no key can be named: the 

3696 target was given as a :class:`_schema.Column` which is not yet 

3697 associated with a :class:`_schema.Table`. 

3698 

3699 .. versionadded:: 2.1 

3700 

3701 .. seealso:: 

3702 

3703 :attr:`_schema.ForeignKey.target_tokens` 

3704 

3705 """ 

3706 col = self.target_column 

3707 if col is not None and col.table is None: 

3708 # target Column not yet associated with a Table, so there is no 

3709 # key to report; the tokens name the column, not a table 

3710 return None 

3711 

3712 schema, tname, colname = self.target_tokens 

3713 return _get_table_key(tname, schema) 

3714 

3715 @property 

3716 def target_fullname(self) -> str: 

3717 """Return the target of this :class:`_schema.ForeignKey` as a single 

3718 dotted string, e.g. ``"schema.tablename.columnname"``. 

3719 

3720 This is usually the equivalent of the string-based 

3721 ``"tablename.colname"`` argument first passed to the object's 

3722 constructor. 

3723 

3724 .. versionchanged:: 2.1 This attribute raises 

3725 :class:`.InvalidRequestError` when the target table or column name 

3726 itself contains a dot, as a dotted string can't distinguish such a 

3727 name from the separator between names. The dotted form is now a 

3728 legacy convenience; :attr:`_schema.ForeignKey.target_tokens` is the 

3729 representation that is available in all cases, and is what 

3730 SQLAlchemy itself makes use of. 

3731 

3732 .. seealso:: 

3733 

3734 :attr:`_schema.ForeignKey.target_tokens` 

3735 

3736 """ 

3737 return self.target_tokens._as_string() 

3738 

3739 def references(self, table: Table) -> bool: 

3740 """Return True if the given :class:`_schema.Table` 

3741 is referenced by this 

3742 :class:`_schema.ForeignKey`.""" 

3743 

3744 return table.corresponding_column(self.column) is not None 

3745 

3746 def get_referent(self, table: FromClause) -> Optional[Column[Any]]: 

3747 """Return the :class:`_schema.Column` in the given 

3748 :class:`_schema.Table` (or any :class:`.FromClause`) 

3749 referenced by this :class:`_schema.ForeignKey`. 

3750 

3751 Returns None if this :class:`_schema.ForeignKey` 

3752 does not reference the given 

3753 :class:`_schema.Table`. 

3754 

3755 """ 

3756 # our column is a Column, and any subquery etc. proxying us 

3757 # would be doing so via another Column, so that's what would 

3758 # be returned here 

3759 return table.columns.corresponding_column(self.column) # type: ignore[return-value] # noqa: E501 

3760 

3761 def _resolve_col_tokens(self) -> Tuple[Table, str, Optional[str]]: 

3762 if self.parent is None: 

3763 raise exc.InvalidRequestError( 

3764 "this ForeignKey object does not yet have a " 

3765 "parent Column associated with it." 

3766 ) 

3767 

3768 elif self.parent.table is None: 

3769 raise exc.InvalidRequestError( 

3770 "this ForeignKey's parent column is not yet associated " 

3771 "with a Table." 

3772 ) 

3773 

3774 parenttable = self.parent.table 

3775 

3776 if self._unresolvable: 

3777 schema, tname, colname = self.target_tokens 

3778 tablekey = _get_table_key(tname, schema) 

3779 return parenttable, tablekey, colname 

3780 

3781 # assertion 

3782 # basically Column._make_proxy() sends the actual 

3783 # target Column to the ForeignKey object, so the 

3784 # string resolution here is never called. 

3785 for c in self.parent.base_columns: 

3786 if isinstance(c, Column): 

3787 assert c.table is parenttable 

3788 break 

3789 else: 

3790 assert False 

3791 ###################### 

3792 

3793 schema, tname, colname = self.target_tokens 

3794 

3795 if schema is None and parenttable.metadata.schema is not None: 

3796 schema = parenttable.metadata.schema 

3797 

3798 tablekey = _get_table_key(tname, schema) 

3799 return parenttable, tablekey, colname 

3800 

3801 def _link_to_col_by_colstring( 

3802 self, parenttable: Table, table: Table, colname: Optional[str] 

3803 ) -> Column[Any]: 

3804 _column = None 

3805 if colname is None: 

3806 # colname is None in the case that ForeignKey argument 

3807 # was specified as table name only, in which case we 

3808 # match the column name to the same column on the 

3809 # parent. 

3810 # this use case wasn't working in later 1.x series 

3811 # as it had no test coverage; fixed in 2.0 

3812 parent = self.parent 

3813 assert parent is not None 

3814 key = parent.key 

3815 _column = table.c.get(key, None) 

3816 elif self.link_to_name: 

3817 key = colname 

3818 for c in table.c: 

3819 if c.name == colname: 

3820 _column = c 

3821 else: 

3822 key = colname 

3823 _column = table.c.get(colname, None) 

3824 

3825 if _column is None: 

3826 raise exc.NoReferencedColumnError( 

3827 "Could not initialize target column " 

3828 f"for ForeignKey {self.target_tokens._description()} " 

3829 f"on table '{parenttable.name}': " 

3830 f"table '{table.name}' has no column named '{key}'", 

3831 table.name, 

3832 key, 

3833 ) 

3834 

3835 return _column 

3836 

3837 def _set_target_column(self, column: Column[Any]) -> None: 

3838 assert self.parent is not None 

3839 

3840 # propagate TypeEngine to parent if it didn't have one 

3841 if self.parent.type._isnull: 

3842 self.parent.type = column.type 

3843 

3844 # super-edgy case, if other FKs point to our column, 

3845 # they'd get the type propagated out also. 

3846 

3847 def set_type(fk: ForeignKey) -> None: 

3848 if fk.parent.type._isnull: 

3849 fk.parent.type = column.type 

3850 

3851 self.parent._setup_on_memoized_fks(set_type) 

3852 

3853 self.column = column # type: ignore[misc] 

3854 

3855 @util.ro_memoized_property 

3856 def column(self) -> Column[Any]: 

3857 """Return the target :class:`_schema.Column` referenced by this 

3858 :class:`_schema.ForeignKey`. 

3859 

3860 If no target column has been established, an exception 

3861 is raised. 

3862 

3863 """ 

3864 return self._resolve_column() 

3865 

3866 @overload 

3867 def _resolve_column( 

3868 self, *, raiseerr: Literal[True] = ... 

3869 ) -> Column[Any]: ... 

3870 

3871 @overload 

3872 def _resolve_column( 

3873 self, *, raiseerr: bool = ... 

3874 ) -> Optional[Column[Any]]: ... 

3875 

3876 def _resolve_column( 

3877 self, *, raiseerr: bool = True 

3878 ) -> Optional[Column[Any]]: 

3879 target_column = self.target_column 

3880 

3881 if target_column is None: 

3882 parenttable, tablekey, colname = self._resolve_col_tokens() 

3883 

3884 if self._unresolvable or tablekey not in parenttable.metadata: 

3885 if not raiseerr: 

3886 return None 

3887 raise exc.NoReferencedTableError( 

3888 f"Foreign key associated with column " 

3889 f"'{self.parent}' could not find " 

3890 f"table '{tablekey}' with which to generate a " 

3891 f"foreign key to target column '{colname}'", 

3892 tablekey, 

3893 ) 

3894 elif parenttable.key not in parenttable.metadata: 

3895 if not raiseerr: 

3896 return None 

3897 raise exc.InvalidRequestError( 

3898 f"Table {parenttable} is no longer associated with its " 

3899 "parent MetaData" 

3900 ) 

3901 else: 

3902 table = parenttable.metadata.tables[tablekey] 

3903 return self._link_to_col_by_colstring( 

3904 parenttable, table, colname 

3905 ) 

3906 

3907 else: 

3908 assert target_column is not None 

3909 return target_column 

3910 

3911 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

3912 assert isinstance(parent, Column) 

3913 

3914 if self.parent is not None and self.parent is not parent: 

3915 raise exc.InvalidRequestError( 

3916 "This ForeignKey already has a parent !" 

3917 ) 

3918 self.parent = parent 

3919 self.parent.foreign_keys.add(self) 

3920 self.parent._on_table_attach(self._set_table) 

3921 

3922 def _set_remote_table(self, table: Table) -> None: 

3923 parenttable, _, colname = self._resolve_col_tokens() 

3924 _column = self._link_to_col_by_colstring(parenttable, table, colname) 

3925 self._set_target_column(_column) 

3926 assert self.constraint is not None 

3927 self.constraint._validate_dest_table(table) 

3928 

3929 def _remove_from_metadata(self, metadata: MetaData) -> None: 

3930 parenttable, table_key, colname = self._resolve_col_tokens() 

3931 fk_key = (table_key, colname) 

3932 

3933 if self in metadata._fk_memos[fk_key]: 

3934 # TODO: no test coverage for self not in memos 

3935 metadata._fk_memos[fk_key].remove(self) 

3936 

3937 def _set_table(self, column: Column[Any], table: Table) -> None: 

3938 # standalone ForeignKey - create ForeignKeyConstraint 

3939 # on the hosting Table when attached to the Table. 

3940 assert isinstance(table, Table) 

3941 if self.constraint is None: 

3942 self.constraint = ForeignKeyConstraint( 

3943 [], 

3944 [], 

3945 use_alter=self.use_alter, 

3946 name=self.name, 

3947 onupdate=self.onupdate, 

3948 ondelete=self.ondelete, 

3949 deferrable=self.deferrable, 

3950 initially=self.initially, 

3951 match=self.match, 

3952 comment=self.comment, 

3953 **self._unvalidated_dialect_kw, 

3954 ) 

3955 self.constraint._append_element(column, self) 

3956 self.constraint._set_parent_with_dispatch(table) 

3957 table.foreign_keys.add(self) 

3958 # set up remote ".column" attribute, or a note to pick it 

3959 # up when the other Table/Column shows up 

3960 

3961 target_column = self.target_column 

3962 if target_column is None: 

3963 parenttable, table_key, colname = self._resolve_col_tokens() 

3964 fk_key = (table_key, colname) 

3965 if table_key in parenttable.metadata.tables: 

3966 table = parenttable.metadata.tables[table_key] 

3967 try: 

3968 _column = self._link_to_col_by_colstring( 

3969 parenttable, table, colname 

3970 ) 

3971 except exc.NoReferencedColumnError: 

3972 # this is OK, we'll try later 

3973 pass 

3974 else: 

3975 self._set_target_column(_column) 

3976 

3977 parenttable.metadata._fk_memos[fk_key].append(self) 

3978 else: 

3979 self._set_target_column(target_column) 

3980 

3981 

3982if TYPE_CHECKING: 

3983 

3984 def default_is_sequence( 

3985 obj: Optional[DefaultGenerator], 

3986 ) -> TypeGuard[Sequence]: ... 

3987 

3988 def default_is_clause_element( 

3989 obj: Optional[DefaultGenerator], 

3990 ) -> TypeGuard[ColumnElementColumnDefault]: ... 

3991 

3992 def default_is_scalar( 

3993 obj: Optional[DefaultGenerator], 

3994 ) -> TypeGuard[ScalarElementColumnDefault]: ... 

3995 

3996else: 

3997 default_is_sequence = operator.attrgetter("is_sequence") 

3998 

3999 default_is_clause_element = operator.attrgetter("is_clause_element") 

4000 

4001 default_is_scalar = operator.attrgetter("is_scalar") 

4002 

4003 

4004class DefaultGenerator(Executable, SchemaItem): 

4005 """Base class for column *default* values. 

4006 

4007 This object is only present on column.default or column.onupdate. 

4008 It's not valid as a server default. 

4009 

4010 """ 

4011 

4012 __visit_name__ = "default_generator" 

4013 

4014 _is_default_generator = True 

4015 is_sequence = False 

4016 is_identity = False 

4017 is_server_default = False 

4018 is_clause_element = False 

4019 is_callable = False 

4020 is_scalar = False 

4021 has_arg = False 

4022 is_sentinel = False 

4023 _is_monotonic_fn = False 

4024 column: Optional[Column[Any]] 

4025 

4026 def __init__(self, for_update: bool = False) -> None: 

4027 self.for_update = for_update 

4028 

4029 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

4030 if TYPE_CHECKING: 

4031 assert isinstance(parent, Column) 

4032 self.column = parent 

4033 if self.for_update: 

4034 self.column.onupdate = self 

4035 else: 

4036 self.column.default = self 

4037 

4038 def _copy(self) -> DefaultGenerator: 

4039 raise NotImplementedError() 

4040 

4041 def _execute_on_connection( 

4042 self, 

4043 connection: Connection, 

4044 distilled_params: _CoreMultiExecuteParams, 

4045 execution_options: CoreExecuteOptionsParameter, 

4046 ) -> Any: 

4047 util.warn_deprecated( 

4048 "Using the .execute() method to invoke a " 

4049 "DefaultGenerator object is deprecated; please use " 

4050 "the .scalar() method.", 

4051 "2.0", 

4052 ) 

4053 return self._execute_on_scalar( 

4054 connection, distilled_params, execution_options 

4055 ) 

4056 

4057 def _execute_on_scalar( 

4058 self, 

4059 connection: Connection, 

4060 distilled_params: _CoreMultiExecuteParams, 

4061 execution_options: CoreExecuteOptionsParameter, 

4062 ) -> Any: 

4063 return connection._execute_default( 

4064 self, distilled_params, execution_options 

4065 ) 

4066 

4067 

4068class ColumnDefault(DefaultGenerator, ABC): 

4069 """A plain default value on a column. 

4070 

4071 This could correspond to a constant, a callable function, 

4072 or a SQL clause. 

4073 

4074 :class:`.ColumnDefault` is generated automatically 

4075 whenever the ``default``, ``onupdate`` arguments of 

4076 :class:`_schema.Column` are used. A :class:`.ColumnDefault` 

4077 can be passed positionally as well. 

4078 

4079 For example, the following:: 

4080 

4081 Column("foo", Integer, default=50) 

4082 

4083 Is equivalent to:: 

4084 

4085 Column("foo", Integer, ColumnDefault(50)) 

4086 

4087 """ 

4088 

4089 arg: Any 

4090 

4091 _is_monotonic_fn = False 

4092 

4093 @overload 

4094 def __new__( 

4095 cls, arg: Callable[..., Any], for_update: bool = ... 

4096 ) -> CallableColumnDefault: ... 

4097 

4098 @overload 

4099 def __new__( 

4100 cls, arg: ColumnElement[Any], for_update: bool = ... 

4101 ) -> ColumnElementColumnDefault: ... 

4102 

4103 # if I return ScalarElementColumnDefault here, which is what's actually 

4104 # returned, mypy complains that 

4105 # overloads overlap w/ incompatible return types. 

4106 @overload 

4107 def __new__(cls, arg: object, for_update: bool = ...) -> ColumnDefault: ... 

4108 

4109 def __new__( 

4110 cls, arg: Any = None, for_update: bool = False 

4111 ) -> ColumnDefault: 

4112 """Construct a new :class:`.ColumnDefault`. 

4113 

4114 

4115 :param arg: argument representing the default value. 

4116 May be one of the following: 

4117 

4118 * a plain non-callable Python value, such as a 

4119 string, integer, boolean, or other simple type. 

4120 The default value will be used as is each time. 

4121 * a SQL expression, that is one which derives from 

4122 :class:`_expression.ColumnElement`. The SQL expression will 

4123 be rendered into the INSERT or UPDATE statement, 

4124 or in the case of a primary key column when 

4125 RETURNING is not used may be 

4126 pre-executed before an INSERT within a SELECT. 

4127 * A Python callable. The function will be invoked for each 

4128 new row subject to an INSERT or UPDATE. 

4129 The callable must accept exactly 

4130 zero or one positional arguments. The one-argument form 

4131 will receive an instance of the :class:`.ExecutionContext`, 

4132 which provides contextual information as to the current 

4133 :class:`_engine.Connection` in use as well as the current 

4134 statement and parameters. 

4135 

4136 """ 

4137 

4138 if isinstance(arg, FetchedValue): 

4139 raise exc.ArgumentError( 

4140 "ColumnDefault may not be a server-side default type." 

4141 ) 

4142 elif callable(arg): 

4143 cls = CallableColumnDefault 

4144 elif isinstance(arg, ClauseElement): 

4145 cls = ColumnElementColumnDefault 

4146 elif arg is not None: 

4147 cls = ScalarElementColumnDefault 

4148 

4149 return object.__new__(cls) 

4150 

4151 def __repr__(self) -> str: 

4152 return f"{self.__class__.__name__}({self.arg!r})" 

4153 

4154 

4155class ScalarElementColumnDefault(ColumnDefault): 

4156 """default generator for a fixed scalar Python value 

4157 

4158 .. versionadded:: 2.0 

4159 

4160 """ 

4161 

4162 is_scalar = True 

4163 has_arg = True 

4164 

4165 def __init__(self, arg: Any, for_update: bool = False) -> None: 

4166 self.for_update = for_update 

4167 self.arg = arg 

4168 

4169 def _copy(self) -> ScalarElementColumnDefault: 

4170 return ScalarElementColumnDefault( 

4171 arg=self.arg, for_update=self.for_update 

4172 ) 

4173 

4174 

4175class _InsertSentinelColumnDefault(ColumnDefault): 

4176 """Default generator that's specific to the use of a "sentinel" column 

4177 when using the insertmanyvalues feature. 

4178 

4179 This default is used as part of the :func:`_schema.insert_sentinel` 

4180 construct. 

4181 

4182 """ 

4183 

4184 is_sentinel = True 

4185 for_update = False 

4186 arg = None 

4187 

4188 def __new__(cls) -> _InsertSentinelColumnDefault: 

4189 return object.__new__(cls) 

4190 

4191 def __init__(self) -> None: 

4192 pass 

4193 

4194 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

4195 col = cast("Column[Any]", parent) 

4196 if not col._insert_sentinel: 

4197 raise exc.ArgumentError( 

4198 "The _InsertSentinelColumnDefault may only be applied to a " 

4199 "Column marked as insert_sentinel=True" 

4200 ) 

4201 elif not col.nullable: 

4202 raise exc.ArgumentError( 

4203 "The _InsertSentinelColumnDefault may only be applied to a " 

4204 "Column that is nullable" 

4205 ) 

4206 

4207 super()._set_parent(parent, **kw) 

4208 

4209 def _copy(self) -> _InsertSentinelColumnDefault: 

4210 return _InsertSentinelColumnDefault() 

4211 

4212 

4213_SQLExprDefault = Union["ColumnElement[Any]", "TextClause"] 

4214 

4215 

4216class ColumnElementColumnDefault(ColumnDefault): 

4217 """default generator for a SQL expression 

4218 

4219 .. versionadded:: 2.0 

4220 

4221 """ 

4222 

4223 is_clause_element = True 

4224 has_arg = True 

4225 arg: _SQLExprDefault 

4226 

4227 def __init__( 

4228 self, 

4229 arg: _SQLExprDefault, 

4230 for_update: bool = False, 

4231 ) -> None: 

4232 self.for_update = for_update 

4233 self.arg = arg 

4234 

4235 def _copy(self) -> ColumnElementColumnDefault: 

4236 return ColumnElementColumnDefault( 

4237 arg=self.arg, for_update=self.for_update 

4238 ) 

4239 

4240 @util.memoized_property 

4241 @util.preload_module("sqlalchemy.sql.functions") 

4242 def _is_monotonic_fn(self) -> bool: 

4243 functions = util.preloaded.sql_functions 

4244 return ( 

4245 isinstance(self.arg, functions.FunctionElement) 

4246 and self.arg.monotonic 

4247 ) 

4248 

4249 @util.memoized_property 

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

4251 def _arg_is_typed(self) -> bool: 

4252 sqltypes = util.preloaded.sql_sqltypes 

4253 

4254 return not isinstance(self.arg.type, sqltypes.NullType) 

4255 

4256 

4257class _CallableColumnDefaultProtocol(Protocol): 

4258 def __call__(self, context: ExecutionContext) -> Any: ... 

4259 

4260 

4261class CallableColumnDefault(ColumnDefault): 

4262 """default generator for a callable Python function 

4263 

4264 .. versionadded:: 2.0 

4265 

4266 """ 

4267 

4268 is_callable = True 

4269 arg: _CallableColumnDefaultProtocol 

4270 has_arg = True 

4271 

4272 def __init__( 

4273 self, 

4274 arg: Union[_CallableColumnDefaultProtocol, Callable[[], Any]], 

4275 for_update: bool = False, 

4276 ) -> None: 

4277 self.for_update = for_update 

4278 self.arg = self._maybe_wrap_callable(arg) 

4279 

4280 def _copy(self) -> CallableColumnDefault: 

4281 return CallableColumnDefault(arg=self.arg, for_update=self.for_update) 

4282 

4283 def _maybe_wrap_callable( 

4284 self, fn: Union[_CallableColumnDefaultProtocol, Callable[[], Any]] 

4285 ) -> _CallableColumnDefaultProtocol: 

4286 """Wrap callables that don't accept a context. 

4287 

4288 This is to allow easy compatibility with default callables 

4289 that aren't specific to accepting of a context. 

4290 

4291 """ 

4292 

4293 try: 

4294 argspec = util.get_callable_argspec(fn, no_self=True) 

4295 except TypeError: 

4296 return util.wrap_callable(lambda ctx: fn(), fn) # type: ignore[call-arg, no-any-return, no-untyped-call] # noqa: E501 

4297 

4298 defaulted = argspec[3] is not None and len(argspec[3]) or 0 

4299 positionals = len(argspec[0]) - defaulted 

4300 

4301 if positionals == 0: 

4302 return util.wrap_callable(lambda ctx: fn(), fn) # type: ignore[call-arg, no-any-return, no-untyped-call] # noqa: E501 

4303 

4304 elif positionals == 1: 

4305 return fn # type: ignore[return-value] 

4306 else: 

4307 raise exc.ArgumentError( 

4308 "ColumnDefault Python function takes zero or one " 

4309 "positional arguments" 

4310 ) 

4311 

4312 

4313class IdentityOptions(DialectKWArgs): 

4314 """Defines options for a named database sequence or an identity column. 

4315 

4316 .. seealso:: 

4317 

4318 :class:`.Sequence` 

4319 

4320 """ 

4321 

4322 def __init__( 

4323 self, 

4324 start: Optional[int] = None, 

4325 increment: Optional[int] = None, 

4326 minvalue: Optional[int] = None, 

4327 maxvalue: Optional[int] = None, 

4328 nominvalue: Optional[bool] = None, 

4329 nomaxvalue: Optional[bool] = None, 

4330 cycle: Optional[bool] = None, 

4331 cache: Optional[int] = None, 

4332 order: Optional[bool] = None, 

4333 **dialect_kw: Any, 

4334 ) -> None: 

4335 """Construct a :class:`.IdentityOptions` object. 

4336 

4337 See the :class:`.Sequence` documentation for a complete description 

4338 of the parameters. 

4339 

4340 :param start: the starting index of the sequence. 

4341 :param increment: the increment value of the sequence. 

4342 :param minvalue: the minimum value of the sequence. 

4343 :param maxvalue: the maximum value of the sequence. 

4344 :param nominvalue: no minimum value of the sequence. 

4345 :param nomaxvalue: no maximum value of the sequence. 

4346 :param cycle: allows the sequence to wrap around when the maxvalue 

4347 or minvalue has been reached. 

4348 :param cache: optional integer value; number of future values in the 

4349 sequence which are calculated in advance. 

4350 :param order: optional boolean value; if ``True``, renders the 

4351 ORDER keyword. 

4352 

4353 .. deprecated:: 2.1 Use ``oracle_order`` instead. 

4354 

4355 """ 

4356 self.start = start 

4357 self.increment = increment 

4358 self.minvalue = minvalue 

4359 self.maxvalue = maxvalue 

4360 self.nominvalue = nominvalue 

4361 self.nomaxvalue = nomaxvalue 

4362 self.cycle = cycle 

4363 self.cache = cache 

4364 if order is not None: 

4365 if "oracle_order" in dialect_kw: 

4366 raise exc.ArgumentError( 

4367 "Cannot specify both 'order' and 'oracle_order'. " 

4368 "Please use only 'oracle_order'." 

4369 ) 

4370 dialect_kw["oracle_order"] = order 

4371 self._validate_dialect_kwargs(dialect_kw) 

4372 

4373 @property 

4374 def _increment_is_negative(self) -> bool: 

4375 return self.increment is not None and self.increment < 0 

4376 

4377 @property 

4378 def order(self) -> Optional[bool]: 

4379 """Alias of the ``dialect_kwargs`` ``'oracle_order'``. 

4380 

4381 .. deprecated:: 2.1 The 'order' attribute is deprecated. 

4382 """ 

4383 value: Optional[bool] = self.dialect_kwargs.get("oracle_order") 

4384 return value 

4385 

4386 def _as_dict(self) -> Dict[str, Any]: 

4387 return { 

4388 k: v 

4389 for k, v in { 

4390 "start": self.start, 

4391 "increment": self.increment, 

4392 "minvalue": self.minvalue, 

4393 "maxvalue": self.maxvalue, 

4394 "nominvalue": self.nominvalue, 

4395 "nomaxvalue": self.nomaxvalue, 

4396 "cycle": self.cycle, 

4397 "cache": self.cache, 

4398 }.items() 

4399 if v != None 

4400 } 

4401 

4402 

4403class Sequence(HasSchemaAttr, IdentityOptions, DefaultGenerator): 

4404 """Represents a named database sequence. 

4405 

4406 The :class:`.Sequence` object represents the name and configurational 

4407 parameters of a database sequence. It also represents 

4408 a construct that can be "executed" by a SQLAlchemy :class:`_engine.Engine` 

4409 or :class:`_engine.Connection`, 

4410 rendering the appropriate "next value" function 

4411 for the target database and returning a result. 

4412 

4413 The :class:`.Sequence` is typically associated with a primary key column:: 

4414 

4415 some_table = Table( 

4416 "some_table", 

4417 metadata, 

4418 Column( 

4419 "id", 

4420 Integer, 

4421 Sequence("some_table_seq", start=1), 

4422 primary_key=True, 

4423 ), 

4424 ) 

4425 

4426 When CREATE TABLE is emitted for the above :class:`_schema.Table`, if the 

4427 target platform supports sequences, a CREATE SEQUENCE statement will 

4428 be emitted as well. For platforms that don't support sequences, 

4429 the :class:`.Sequence` construct is ignored. 

4430 

4431 .. seealso:: 

4432 

4433 :ref:`defaults_sequences` 

4434 

4435 :class:`.CreateSequence` 

4436 

4437 :class:`.DropSequence` 

4438 

4439 """ 

4440 

4441 __visit_name__ = "sequence" 

4442 

4443 is_sequence = True 

4444 

4445 column: Optional[Column[Any]] 

4446 data_type: Optional[TypeEngine[int]] 

4447 

4448 metadata: Optional[MetaData] 

4449 

4450 @util.deprecated_params( 

4451 order=( 

4452 "2.1", 

4453 "This parameter is supported only by Oracle Database, " 

4454 "use ``oracle_order`` instead.", 

4455 ) 

4456 ) 

4457 def __init__( 

4458 self, 

4459 name: str, 

4460 start: Optional[int] = None, 

4461 increment: Optional[int] = None, 

4462 minvalue: Optional[int] = None, 

4463 maxvalue: Optional[int] = None, 

4464 nominvalue: Optional[bool] = None, 

4465 nomaxvalue: Optional[bool] = None, 

4466 cycle: Optional[bool] = None, 

4467 schema: Optional[Union[str, Literal[SchemaConst.BLANK_SCHEMA]]] = None, 

4468 cache: Optional[int] = None, 

4469 order: Optional[bool] = None, 

4470 data_type: Optional[_TypeEngineArgument[int]] = None, 

4471 optional: bool = False, 

4472 quote: Optional[bool] = None, 

4473 metadata: Optional[MetaData] = None, 

4474 quote_schema: Optional[bool] = None, 

4475 for_update: bool = False, 

4476 **dialect_kw: Any, 

4477 ) -> None: 

4478 """Construct a :class:`.Sequence` object. 

4479 

4480 :param name: the name of the sequence. 

4481 

4482 :param start: the starting index of the sequence. This value is 

4483 used when the CREATE SEQUENCE command is emitted to the database 

4484 as the value of the "START WITH" clause. If ``None``, the 

4485 clause is omitted, which on most platforms indicates a starting 

4486 value of 1. 

4487 

4488 .. versionchanged:: 2.0 The :paramref:`.Sequence.start` parameter 

4489 is required in order to have DDL emit "START WITH". This is a 

4490 reversal of a change made in version 1.4 which would implicitly 

4491 render "START WITH 1" if the :paramref:`.Sequence.start` were 

4492 not included. See :ref:`change_7211` for more detail. 

4493 

4494 :param increment: the increment value of the sequence. This 

4495 value is used when the CREATE SEQUENCE command is emitted to 

4496 the database as the value of the "INCREMENT BY" clause. If ``None``, 

4497 the clause is omitted, which on most platforms indicates an 

4498 increment of 1. 

4499 :param minvalue: the minimum value of the sequence. This 

4500 value is used when the CREATE SEQUENCE command is emitted to 

4501 the database as the value of the "MINVALUE" clause. If ``None``, 

4502 the clause is omitted, which on most platforms indicates a 

4503 minvalue of 1 and -2^63-1 for ascending and descending sequences, 

4504 respectively. 

4505 

4506 :param maxvalue: the maximum value of the sequence. This 

4507 value is used when the CREATE SEQUENCE command is emitted to 

4508 the database as the value of the "MAXVALUE" clause. If ``None``, 

4509 the clause is omitted, which on most platforms indicates a 

4510 maxvalue of 2^63-1 and -1 for ascending and descending sequences, 

4511 respectively. 

4512 

4513 :param nominvalue: no minimum value of the sequence. This 

4514 value is used when the CREATE SEQUENCE command is emitted to 

4515 the database as the value of the "NO MINVALUE" clause. If ``None``, 

4516 the clause is omitted, which on most platforms indicates a 

4517 minvalue of 1 and -2^63-1 for ascending and descending sequences, 

4518 respectively. 

4519 

4520 :param nomaxvalue: no maximum value of the sequence. This 

4521 value is used when the CREATE SEQUENCE command is emitted to 

4522 the database as the value of the "NO MAXVALUE" clause. If ``None``, 

4523 the clause is omitted, which on most platforms indicates a 

4524 maxvalue of 2^63-1 and -1 for ascending and descending sequences, 

4525 respectively. 

4526 

4527 :param cycle: allows the sequence to wrap around when the maxvalue 

4528 or minvalue has been reached by an ascending or descending sequence 

4529 respectively. This value is used when the CREATE SEQUENCE command 

4530 is emitted to the database as the "CYCLE" clause. If the limit is 

4531 reached, the next number generated will be the minvalue or maxvalue, 

4532 respectively. If cycle=False (the default) any calls to nextval 

4533 after the sequence has reached its maximum value will return an 

4534 error. 

4535 

4536 :param schema: optional schema name for the sequence, if located 

4537 in a schema other than the default. The rules for selecting the 

4538 schema name when a :class:`_schema.MetaData` 

4539 is also present are the same 

4540 as that of :paramref:`_schema.Table.schema`. 

4541 

4542 :param cache: optional integer value; number of future values in the 

4543 sequence which are calculated in advance. Renders the CACHE keyword 

4544 understood by Oracle Database and PostgreSQL. 

4545 

4546 :param order: optional boolean value; if ``True``, renders the 

4547 ORDER keyword, understood by Oracle Database, indicating the sequence 

4548 is definitively ordered. May be necessary to provide deterministic 

4549 ordering using Oracle RAC. 

4550 

4551 :param data_type: The type to be returned by the sequence, for 

4552 dialects that allow us to choose between INTEGER, BIGINT, etc. 

4553 (e.g., mssql). 

4554 

4555 .. versionadded:: 1.4.0 

4556 

4557 :param optional: boolean value, when ``True``, indicates that this 

4558 :class:`.Sequence` object only needs to be explicitly generated 

4559 on backends that don't provide another way to generate primary 

4560 key identifiers. Currently, it essentially means, "don't create 

4561 this sequence on the PostgreSQL backend, where the SERIAL keyword 

4562 creates a sequence for us automatically". 

4563 :param quote: boolean value, when ``True`` or ``False``, explicitly 

4564 forces quoting of the :paramref:`_schema.Sequence.name` on or off. 

4565 When left at its default of ``None``, normal quoting rules based 

4566 on casing and reserved words take place. 

4567 :param quote_schema: Set the quoting preferences for the ``schema`` 

4568 name. 

4569 

4570 :param metadata: optional :class:`_schema.MetaData` object which this 

4571 :class:`.Sequence` will be associated with. A :class:`.Sequence` 

4572 that is associated with a :class:`_schema.MetaData` 

4573 gains the following 

4574 capabilities: 

4575 

4576 * The :class:`.Sequence` will inherit the 

4577 :paramref:`_schema.MetaData.schema` 

4578 parameter specified to the target :class:`_schema.MetaData`, which 

4579 affects the production of CREATE / DROP DDL, if any. 

4580 

4581 * The :meth:`.Sequence.create` and :meth:`.Sequence.drop` methods 

4582 automatically use the engine bound to the :class:`_schema.MetaData` 

4583 object, if any. 

4584 

4585 * The :meth:`_schema.MetaData.create_all` and 

4586 :meth:`_schema.MetaData.drop_all` 

4587 methods will emit CREATE / DROP for this :class:`.Sequence`, 

4588 even if the :class:`.Sequence` is not associated with any 

4589 :class:`_schema.Table` / :class:`_schema.Column` 

4590 that's a member of this 

4591 :class:`_schema.MetaData`. 

4592 

4593 The above behaviors can only occur if the :class:`.Sequence` is 

4594 explicitly associated with the :class:`_schema.MetaData` 

4595 via this parameter. 

4596 

4597 .. seealso:: 

4598 

4599 :ref:`sequence_metadata` - full discussion of the 

4600 :paramref:`.Sequence.metadata` parameter. 

4601 

4602 :param for_update: Indicates this :class:`.Sequence`, when associated 

4603 with a :class:`_schema.Column`, 

4604 should be invoked for UPDATE statements 

4605 on that column's table, rather than for INSERT statements, when 

4606 no value is otherwise present for that column in the statement. 

4607 

4608 """ 

4609 DefaultGenerator.__init__(self, for_update=for_update) 

4610 IdentityOptions.__init__( 

4611 self, 

4612 start=start, 

4613 increment=increment, 

4614 minvalue=minvalue, 

4615 maxvalue=maxvalue, 

4616 nominvalue=nominvalue, 

4617 nomaxvalue=nomaxvalue, 

4618 cycle=cycle, 

4619 cache=cache, 

4620 order=order, 

4621 **dialect_kw, 

4622 ) 

4623 self.column = None 

4624 self.name = quoted_name(name, quote) 

4625 self.optional = optional 

4626 if schema is BLANK_SCHEMA: 

4627 self.schema = schema = None 

4628 elif metadata is not None and schema is None and metadata.schema: 

4629 self.schema = schema = metadata.schema 

4630 else: 

4631 self.schema = quoted_name.construct(schema, quote_schema) 

4632 self._key = _get_table_key(name, schema) 

4633 if data_type is not None: 

4634 self.data_type = to_instance(data_type) 

4635 else: 

4636 self.data_type = None 

4637 

4638 if metadata: 

4639 self._set_metadata(metadata) 

4640 else: 

4641 self.metadata = None 

4642 

4643 @util.preload_module("sqlalchemy.sql.functions") 

4644 def next_value(self) -> Function[int]: 

4645 """Return a :class:`.next_value` function element 

4646 which will render the appropriate increment function 

4647 for this :class:`.Sequence` within any SQL expression. 

4648 

4649 """ 

4650 return util.preloaded.sql_functions.func.next_value(self) 

4651 

4652 def _copy(self) -> Sequence: 

4653 return Sequence( 

4654 name=self.name, 

4655 schema=self.schema, 

4656 data_type=self.data_type, 

4657 optional=self.optional, 

4658 metadata=None, 

4659 for_update=self.for_update, 

4660 **self._as_dict(), 

4661 **self.dialect_kwargs, 

4662 **self._reflect_only_kwargs, 

4663 ) 

4664 

4665 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

4666 assert isinstance(parent, Column) 

4667 super()._set_parent(parent, **kw) 

4668 parent._on_table_attach(self._set_table) 

4669 

4670 def _set_table(self, column: Column[Any], table: Table) -> None: 

4671 self._set_metadata(table.metadata) 

4672 

4673 def _set_metadata(self, metadata: MetaData) -> None: 

4674 self.metadata = metadata 

4675 self.metadata._register_object(self) 

4676 metadata._sequences[self._key] = self 

4677 

4678 def create( 

4679 self, 

4680 bind: _CreateDropBind, 

4681 checkfirst: Union[bool, CheckFirst] = CheckFirst.SEQUENCES, 

4682 ) -> None: 

4683 """Creates this sequence in the database.""" 

4684 

4685 bind._run_ddl_visitor(ddl.SchemaGenerator, self, checkfirst=checkfirst) 

4686 

4687 def drop( 

4688 self, 

4689 bind: _CreateDropBind, 

4690 checkfirst: Union[bool, CheckFirst] = CheckFirst.SEQUENCES, 

4691 ) -> None: 

4692 """Drops this sequence from the database.""" 

4693 

4694 bind._run_ddl_visitor(ddl.SchemaDropper, self, checkfirst=checkfirst) 

4695 

4696 def _not_a_column_expr(self) -> NoReturn: 

4697 raise exc.InvalidRequestError( 

4698 f"This {self.__class__.__name__} cannot be used directly " 

4699 "as a column expression. Use func.next_value(sequence) " 

4700 "to produce a 'next value' function that's usable " 

4701 "as a column element." 

4702 ) 

4703 

4704 

4705@inspection._self_inspects 

4706class FetchedValue(SchemaEventTarget): 

4707 """A marker for a transparent database-side default. 

4708 

4709 Use :class:`.FetchedValue` when the database is configured 

4710 to provide some automatic default for a column. 

4711 

4712 E.g.:: 

4713 

4714 Column("foo", Integer, FetchedValue()) 

4715 

4716 Would indicate that some trigger or default generator 

4717 will create a new value for the ``foo`` column during an 

4718 INSERT. 

4719 

4720 .. seealso:: 

4721 

4722 :ref:`triggered_columns` 

4723 

4724 """ 

4725 

4726 is_server_default = True 

4727 reflected = False 

4728 has_argument = False 

4729 is_clause_element = False 

4730 is_identity = False 

4731 _is_monotonic_fn = False 

4732 

4733 column: Optional[Column[Any]] 

4734 

4735 def __init__(self, for_update: bool = False) -> None: 

4736 self.for_update = for_update 

4737 

4738 def _as_for_update(self, for_update: bool) -> FetchedValue: 

4739 if for_update == self.for_update: 

4740 return self 

4741 else: 

4742 return self._clone(for_update) 

4743 

4744 def _copy(self) -> Self: 

4745 return self._clone(self.for_update) 

4746 

4747 def _clone(self, for_update: bool) -> Self: 

4748 n = self.__class__.__new__(self.__class__) 

4749 n.__dict__.update(self.__dict__) 

4750 n.__dict__.pop("column", None) 

4751 n.for_update = for_update 

4752 return n 

4753 

4754 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

4755 column = parent 

4756 assert isinstance(column, Column) 

4757 self.column = column 

4758 if self.for_update: 

4759 self.column.server_onupdate = self 

4760 else: 

4761 self.column.server_default = self 

4762 

4763 def __repr__(self) -> str: 

4764 return util.generic_repr(self) 

4765 

4766 

4767class DefaultClause(FetchedValue): 

4768 """A DDL-specified DEFAULT column value. 

4769 

4770 :class:`.DefaultClause` is a :class:`.FetchedValue` 

4771 that also generates a "DEFAULT" clause when 

4772 "CREATE TABLE" is emitted. 

4773 

4774 :class:`.DefaultClause` is generated automatically 

4775 whenever the ``server_default``, ``server_onupdate`` arguments of 

4776 :class:`_schema.Column` are used. A :class:`.DefaultClause` 

4777 can be passed positionally as well. 

4778 

4779 For example, the following:: 

4780 

4781 Column("foo", Integer, server_default="50") 

4782 

4783 Is equivalent to:: 

4784 

4785 Column("foo", Integer, DefaultClause("50")) 

4786 

4787 """ 

4788 

4789 has_argument = True 

4790 

4791 def __init__( 

4792 self, 

4793 arg: Union[str, ClauseElement, TextClause], 

4794 for_update: bool = False, 

4795 _reflected: bool = False, 

4796 ) -> None: 

4797 util.assert_arg_type(arg, (str, ClauseElement, TextClause), "arg") 

4798 super().__init__(for_update) 

4799 self.arg = arg 

4800 self.reflected = _reflected 

4801 

4802 @util.memoized_property 

4803 @util.preload_module("sqlalchemy.sql.functions") 

4804 def _is_monotonic_fn(self) -> bool: 

4805 functions = util.preloaded.sql_functions 

4806 return ( 

4807 isinstance(self.arg, functions.FunctionElement) 

4808 and self.arg.monotonic 

4809 ) 

4810 

4811 def __repr__(self) -> str: 

4812 return "DefaultClause(%r, for_update=%r)" % (self.arg, self.for_update) 

4813 

4814 

4815class Constraint(DialectKWArgs, HasConditionalDDL, SchemaItem): 

4816 """A table-level SQL constraint. 

4817 

4818 :class:`_schema.Constraint` serves as the base class for the series of 

4819 constraint objects that can be associated with :class:`_schema.Table` 

4820 objects, including :class:`_schema.PrimaryKeyConstraint`, 

4821 :class:`_schema.ForeignKeyConstraint` 

4822 :class:`_schema.UniqueConstraint`, and 

4823 :class:`_schema.CheckConstraint`. 

4824 

4825 """ 

4826 

4827 __visit_name__ = "constraint" 

4828 

4829 _creation_order: int 

4830 _column_flag: bool 

4831 

4832 def __init__( 

4833 self, 

4834 name: _ConstraintNameArgument = None, 

4835 deferrable: Optional[bool] = None, 

4836 initially: Optional[str] = None, 

4837 info: Optional[_InfoType] = None, 

4838 comment: Optional[str] = None, 

4839 _create_rule: Optional[Any] = None, 

4840 _type_bound: bool = False, 

4841 **dialect_kw: Any, 

4842 ) -> None: 

4843 r"""Create a SQL constraint. 

4844 

4845 :param name: 

4846 Optional, the in-database name of this ``Constraint``. 

4847 

4848 :param deferrable: 

4849 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

4850 issuing DDL for this constraint. 

4851 

4852 :param initially: 

4853 Optional string. If set, emit INITIALLY <value> when issuing DDL 

4854 for this constraint. 

4855 

4856 :param info: Optional data dictionary which will be populated into the 

4857 :attr:`.SchemaItem.info` attribute of this object. 

4858 

4859 :param comment: Optional string that will render an SQL comment on 

4860 foreign key constraint creation. 

4861 

4862 .. versionadded:: 2.0 

4863 

4864 :param \**dialect_kw: Additional keyword arguments are dialect 

4865 specific, and passed in the form ``<dialectname>_<argname>``. See 

4866 the documentation regarding an individual dialect at 

4867 :ref:`dialect_toplevel` for detail on documented arguments. 

4868 

4869 :param _create_rule: 

4870 used internally by some datatypes that also create constraints. 

4871 

4872 :param _type_bound: 

4873 used internally to indicate that this constraint is associated with 

4874 a specific datatype. 

4875 

4876 """ 

4877 

4878 self.name = name 

4879 self.deferrable = deferrable 

4880 self.initially = initially 

4881 if info: 

4882 self.info = info 

4883 self._create_rule = _create_rule 

4884 self._type_bound = _type_bound 

4885 util.set_creation_order(self) 

4886 self._validate_dialect_kwargs(dialect_kw) 

4887 self.comment = comment 

4888 

4889 def _should_create_for_compiler( 

4890 self, compiler: DDLCompiler, **kw: Any 

4891 ) -> bool: 

4892 if self._create_rule is not None and not self._create_rule(compiler): 

4893 return False 

4894 elif self._ddl_if is not None: 

4895 return self._ddl_if._should_execute( 

4896 ddl.CreateConstraint(self), self, None, compiler=compiler, **kw 

4897 ) 

4898 else: 

4899 return True 

4900 

4901 @property 

4902 def table(self) -> Table: 

4903 try: 

4904 if isinstance(self.parent, Table): 

4905 return self.parent 

4906 except AttributeError: 

4907 pass 

4908 raise exc.InvalidRequestError( 

4909 "This constraint is not bound to a table. Did you " 

4910 "mean to call table.append_constraint(constraint) ?" 

4911 ) 

4912 

4913 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

4914 assert isinstance(parent, (Table, Column)) 

4915 self.parent = parent 

4916 parent.constraints.add(self) 

4917 

4918 @util.deprecated( 

4919 "1.4", 

4920 "The :meth:`_schema.Constraint.copy` method is deprecated " 

4921 "and will be removed in a future release.", 

4922 ) 

4923 def copy(self, **kw: Any) -> Self: 

4924 return self._copy(**kw) 

4925 

4926 def _copy(self, **kw: Any) -> Self: 

4927 raise NotImplementedError() 

4928 

4929 

4930class ColumnCollectionMixin: 

4931 """A :class:`_expression.ColumnCollection` of :class:`_schema.Column` 

4932 objects. 

4933 

4934 This collection represents the columns which are referred to by 

4935 this object. 

4936 

4937 """ 

4938 

4939 _columns: WriteableColumnCollection[str, Column[Any]] 

4940 

4941 _column_collection_class: ClassVar[ 

4942 Type[WriteableColumnCollection[Any, Any]] 

4943 ] = DedupeColumnCollection 

4944 

4945 _allow_multiple_tables = False 

4946 

4947 _pending_colargs: List[Optional[Union[str, Column[Any]]]] 

4948 

4949 if TYPE_CHECKING: 

4950 

4951 def _set_parent_with_dispatch( 

4952 self, parent: SchemaEventTarget, **kw: Any 

4953 ) -> None: ... 

4954 

4955 def __init__( 

4956 self, 

4957 *columns: _DDLColumnArgument, 

4958 _autoattach: bool = True, 

4959 _column_flag: bool = False, 

4960 _gather_expressions: Optional[ 

4961 List[Union[str, ColumnElement[Any]]] 

4962 ] = None, 

4963 ) -> None: 

4964 self._column_flag = _column_flag 

4965 self._columns = self._column_collection_class() 

4966 

4967 processed_expressions: Optional[ 

4968 List[Union[ColumnElement[Any], str]] 

4969 ] = _gather_expressions 

4970 

4971 if processed_expressions is not None: 

4972 

4973 # this is expected to be an empty list 

4974 assert not processed_expressions 

4975 

4976 self._pending_colargs = [] 

4977 for ( 

4978 expr, 

4979 _, 

4980 _, 

4981 add_element, 

4982 ) in coercions.expect_col_expression_collection( 

4983 roles.DDLConstraintColumnRole, columns 

4984 ): 

4985 self._pending_colargs.append(add_element) 

4986 processed_expressions.append(expr) 

4987 else: 

4988 self._pending_colargs = [ 

4989 coercions.expect(roles.DDLConstraintColumnRole, column) 

4990 for column in columns 

4991 ] 

4992 

4993 if _autoattach and self._pending_colargs: 

4994 self._check_attach() 

4995 

4996 def _check_attach(self, evt: bool = False) -> None: 

4997 col_objs = [c for c in self._pending_colargs if isinstance(c, Column)] 

4998 

4999 cols_w_table = [c for c in col_objs if isinstance(c.table, Table)] 

5000 

5001 cols_wo_table = set(col_objs).difference(cols_w_table) 

5002 if cols_wo_table: 

5003 # feature #3341 - place event listeners for Column objects 

5004 # such that when all those cols are attached, we autoattach. 

5005 assert not evt, "Should not reach here on event call" 

5006 

5007 # issue #3411 - don't do the per-column auto-attach if some of the 

5008 # columns are specified as strings. 

5009 has_string_cols = { 

5010 c for c in self._pending_colargs if c is not None 

5011 }.difference(col_objs) 

5012 if not has_string_cols: 

5013 

5014 def _col_attached(column: Column[Any], table: Table) -> None: 

5015 # this isinstance() corresponds with the 

5016 # isinstance() above; only want to count Table-bound 

5017 # columns 

5018 if isinstance(table, Table): 

5019 cols_wo_table.discard(column) 

5020 if not cols_wo_table: 

5021 self._check_attach(evt=True) 

5022 

5023 self._cols_wo_table = cols_wo_table 

5024 for col in cols_wo_table: 

5025 col._on_table_attach(_col_attached) 

5026 return 

5027 

5028 columns = cols_w_table 

5029 

5030 tables = {c.table for c in columns} 

5031 if len(tables) == 1: 

5032 self._set_parent_with_dispatch(tables.pop()) 

5033 elif len(tables) > 1 and not self._allow_multiple_tables: 

5034 table = columns[0].table 

5035 others = [c for c in columns[1:] if c.table is not table] 

5036 if others: 

5037 # black could not format this inline 

5038 other_str = ", ".join("'%s'" % c for c in others) 

5039 raise exc.ArgumentError( 

5040 f"Column(s) {other_str} " 

5041 f"are not part of table '{table.description}'." 

5042 ) 

5043 

5044 @util.ro_memoized_property 

5045 def columns(self) -> ReadOnlyColumnCollection[str, Column[Any]]: 

5046 return self._columns.as_readonly() 

5047 

5048 @util.ro_memoized_property 

5049 def c(self) -> ReadOnlyColumnCollection[str, Column[Any]]: 

5050 return self._columns.as_readonly() 

5051 

5052 def _col_expressions( 

5053 self, parent: Union[Table, Column[Any]] 

5054 ) -> List[Optional[Column[Any]]]: 

5055 if isinstance(parent, Column): 

5056 result: List[Optional[Column[Any]]] = [ 

5057 c for c in self._pending_colargs if isinstance(c, Column) 

5058 ] 

5059 assert len(result) == len(self._pending_colargs) 

5060 return result 

5061 else: 

5062 try: 

5063 return [ 

5064 parent.c[col] if isinstance(col, str) else col 

5065 for col in self._pending_colargs 

5066 ] 

5067 except KeyError as ke: 

5068 raise exc.ConstraintColumnNotFoundError( 

5069 f"Can't create {self.__class__.__name__} " 

5070 f"on table '{parent.description}': no column " 

5071 f"named '{ke.args[0]}' is present." 

5072 ) from ke 

5073 

5074 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

5075 assert isinstance(parent, (Table, Column)) 

5076 

5077 for col in self._col_expressions(parent): 

5078 if col is not None: 

5079 self._columns.add(col) 

5080 

5081 

5082class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint): 

5083 """A constraint that proxies a ColumnCollection.""" 

5084 

5085 def __init__( 

5086 self, 

5087 *columns: _DDLColumnArgument, 

5088 name: _ConstraintNameArgument = None, 

5089 deferrable: Optional[bool] = None, 

5090 initially: Optional[str] = None, 

5091 info: Optional[_InfoType] = None, 

5092 _autoattach: bool = True, 

5093 _column_flag: bool = False, 

5094 _gather_expressions: Optional[List[_DDLColumnArgument]] = None, 

5095 **dialect_kw: Any, 

5096 ) -> None: 

5097 r""" 

5098 :param \*columns: 

5099 A sequence of column names or Column objects. 

5100 

5101 :param name: 

5102 Optional, the in-database name of this constraint. 

5103 

5104 :param deferrable: 

5105 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

5106 issuing DDL for this constraint. 

5107 

5108 :param initially: 

5109 Optional string. If set, emit INITIALLY <value> when issuing DDL 

5110 for this constraint. 

5111 

5112 :param \**dialect_kw: other keyword arguments including 

5113 dialect-specific arguments are propagated to the :class:`.Constraint` 

5114 superclass. 

5115 

5116 """ 

5117 Constraint.__init__( 

5118 self, 

5119 name=name, 

5120 deferrable=deferrable, 

5121 initially=initially, 

5122 info=info, 

5123 **dialect_kw, 

5124 ) 

5125 ColumnCollectionMixin.__init__( 

5126 self, *columns, _autoattach=_autoattach, _column_flag=_column_flag 

5127 ) 

5128 

5129 columns: ReadOnlyColumnCollection[str, Column[Any]] 

5130 """A :class:`_expression.ColumnCollection` representing the set of columns 

5131 for this constraint. 

5132 

5133 """ 

5134 

5135 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

5136 assert isinstance(parent, (Column, Table)) 

5137 Constraint._set_parent(self, parent) 

5138 ColumnCollectionMixin._set_parent(self, parent) 

5139 

5140 def __contains__(self, x: Any) -> bool: 

5141 return x in self._columns 

5142 

5143 @util.deprecated( 

5144 "1.4", 

5145 "The :meth:`_schema.ColumnCollectionConstraint.copy` method " 

5146 "is deprecated and will be removed in a future release.", 

5147 ) 

5148 def copy( 

5149 self, 

5150 *, 

5151 target_table: Optional[Table] = None, 

5152 **kw: Any, 

5153 ) -> ColumnCollectionConstraint: 

5154 return self._copy(target_table=target_table, **kw) 

5155 

5156 def _copy( 

5157 self, 

5158 *, 

5159 target_table: Optional[Table] = None, 

5160 **kw: Any, 

5161 ) -> ColumnCollectionConstraint: 

5162 # ticket #5276 

5163 constraint_kwargs = {} 

5164 for dialect_name in self.dialect_options: 

5165 dialect_options = self.dialect_options[dialect_name]._non_defaults 

5166 for ( 

5167 dialect_option_key, 

5168 dialect_option_value, 

5169 ) in dialect_options.items(): 

5170 constraint_kwargs[dialect_name + "_" + dialect_option_key] = ( 

5171 dialect_option_value 

5172 ) 

5173 

5174 assert isinstance(self.parent, Table) 

5175 c = self.__class__( 

5176 name=self.name, 

5177 deferrable=self.deferrable, 

5178 initially=self.initially, 

5179 *[ 

5180 _copy_expression(expr, self.parent, target_table) 

5181 for expr in self._columns 

5182 ], 

5183 comment=self.comment, 

5184 **constraint_kwargs, 

5185 ) 

5186 return self._schema_item_copy(c) 

5187 

5188 def contains_column(self, col: Column[Any]) -> bool: 

5189 """Return True if this constraint contains the given column. 

5190 

5191 Note that this object also contains an attribute ``.columns`` 

5192 which is a :class:`_expression.ColumnCollection` of 

5193 :class:`_schema.Column` objects. 

5194 

5195 """ 

5196 

5197 return self._columns.contains_column(col) 

5198 

5199 def __iter__(self) -> Iterator[Column[Any]]: 

5200 return iter(self._columns) 

5201 

5202 def __len__(self) -> int: 

5203 return len(self._columns) 

5204 

5205 

5206class CheckConstraint(ColumnCollectionConstraint): 

5207 """A table- or column-level CHECK constraint. 

5208 

5209 Can be included in the definition of a Table or Column. 

5210 """ 

5211 

5212 _allow_multiple_tables = True 

5213 

5214 __visit_name__ = "table_or_column_check_constraint" 

5215 

5216 @_document_text_coercion( 

5217 "sqltext", 

5218 ":class:`.CheckConstraint`", 

5219 ":paramref:`.CheckConstraint.sqltext`", 

5220 ) 

5221 def __init__( 

5222 self, 

5223 sqltext: _TextCoercedExpressionArgument[Any], 

5224 name: _ConstraintNameArgument = None, 

5225 deferrable: Optional[bool] = None, 

5226 initially: Optional[str] = None, 

5227 table: Optional[Table] = None, 

5228 info: Optional[_InfoType] = None, 

5229 _create_rule: Optional[Any] = None, 

5230 _autoattach: bool = True, 

5231 _type_bound: bool = False, 

5232 **dialect_kw: Any, 

5233 ) -> None: 

5234 r"""Construct a CHECK constraint. 

5235 

5236 :param sqltext: 

5237 A string containing the constraint definition, which will be used 

5238 verbatim, or a SQL expression construct. If given as a string, 

5239 the object is converted to a :func:`_expression.text` object. 

5240 If the textual 

5241 string includes a colon character, escape this using a backslash:: 

5242 

5243 CheckConstraint(r"foo ~ E'a(?\:b|c)d") 

5244 

5245 :param name: 

5246 Optional, the in-database name of the constraint. 

5247 

5248 :param deferrable: 

5249 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

5250 issuing DDL for this constraint. 

5251 

5252 :param initially: 

5253 Optional string. If set, emit INITIALLY <value> when issuing DDL 

5254 for this constraint. 

5255 

5256 :param info: Optional data dictionary which will be populated into the 

5257 :attr:`.SchemaItem.info` attribute of this object. 

5258 

5259 """ 

5260 

5261 self.sqltext = coercions.expect(roles.DDLExpressionRole, sqltext) 

5262 columns: List[Column[Any]] = [] 

5263 visitors.traverse(self.sqltext, {}, {"column": columns.append}) 

5264 

5265 super().__init__( 

5266 name=name, 

5267 deferrable=deferrable, 

5268 initially=initially, 

5269 _create_rule=_create_rule, 

5270 info=info, 

5271 _type_bound=_type_bound, 

5272 _autoattach=_autoattach, 

5273 *columns, 

5274 **dialect_kw, 

5275 ) 

5276 if table is not None: 

5277 self._set_parent_with_dispatch(table) 

5278 

5279 @property 

5280 def is_column_level(self) -> bool: 

5281 return not isinstance(self.parent, Table) 

5282 

5283 @util.deprecated( 

5284 "1.4", 

5285 "The :meth:`_schema.CheckConstraint.copy` method is deprecated " 

5286 "and will be removed in a future release.", 

5287 ) 

5288 def copy( 

5289 self, *, target_table: Optional[Table] = None, **kw: Any 

5290 ) -> CheckConstraint: 

5291 return self._copy(target_table=target_table, **kw) 

5292 

5293 def _copy( 

5294 self, *, target_table: Optional[Table] = None, **kw: Any 

5295 ) -> CheckConstraint: 

5296 if target_table is not None: 

5297 # note that target_table is None for the copy process of 

5298 # a column-bound CheckConstraint, so this path is not reached 

5299 # in that case. 

5300 sqltext = _copy_expression(self.sqltext, self.table, target_table) 

5301 else: 

5302 sqltext = self.sqltext 

5303 c = CheckConstraint( 

5304 sqltext, 

5305 name=self.name, 

5306 initially=self.initially, 

5307 deferrable=self.deferrable, 

5308 _create_rule=self._create_rule, 

5309 table=target_table, 

5310 comment=self.comment, 

5311 _autoattach=False, 

5312 _type_bound=self._type_bound, 

5313 ) 

5314 return self._schema_item_copy(c) 

5315 

5316 

5317class ForeignKeyConstraint(ColumnCollectionConstraint): 

5318 """A table-level FOREIGN KEY constraint. 

5319 

5320 Defines a single column or composite FOREIGN KEY ... REFERENCES 

5321 constraint. For a no-frills, single column foreign key, adding a 

5322 :class:`_schema.ForeignKey` to the definition of a :class:`_schema.Column` 

5323 is a 

5324 shorthand equivalent for an unnamed, single column 

5325 :class:`_schema.ForeignKeyConstraint`. 

5326 

5327 Examples of foreign key configuration are in :ref:`metadata_foreignkeys`. 

5328 

5329 """ 

5330 

5331 __visit_name__ = "foreign_key_constraint" 

5332 

5333 # a FOREIGN KEY may name the same local column more than once, e.g. 

5334 # FOREIGN KEY (a, a) REFERENCES r (b, c). the collection is therefore 

5335 # positional and parallel to self.elements, not deduplicating. 

5336 _column_collection_class = WriteableColumnCollection 

5337 

5338 def __init__( 

5339 self, 

5340 columns: _typing_Sequence[_DDLColumnArgument], 

5341 refcolumns: _typing_Sequence[_DDLColumnReferenceArgument], 

5342 name: _ConstraintNameArgument = None, 

5343 onupdate: Optional[str] = None, 

5344 ondelete: Optional[str] = None, 

5345 deferrable: Optional[bool] = None, 

5346 initially: Optional[str] = None, 

5347 use_alter: bool = False, 

5348 link_to_name: bool = False, 

5349 match: Optional[str] = None, 

5350 table: Optional[Table] = None, 

5351 info: Optional[_InfoType] = None, 

5352 comment: Optional[str] = None, 

5353 **dialect_kw: Any, 

5354 ) -> None: 

5355 r"""Construct a composite-capable FOREIGN KEY. 

5356 

5357 :param columns: A sequence of local column names. The named columns 

5358 must be defined and present in the parent Table. The names should 

5359 match the ``key`` given to each column (defaults to the name) unless 

5360 ``link_to_name`` is True. The same column may be named more than 

5361 once, e.g. ``FOREIGN KEY (a, a) REFERENCES r (b, c)``, which 

5362 constrains the referenced row so that its ``b`` and ``c`` values 

5363 are equal. 

5364 

5365 .. versionchanged:: 2.1 The same local column may be named more 

5366 than once. 

5367 

5368 :param refcolumns: A sequence of foreign column names or Column 

5369 objects. The columns must all be located within the same Table. 

5370 The number of entries must match that of 

5371 :paramref:`_schema.ForeignKeyConstraint.columns`. Each entry 

5372 accepts the same forms as :paramref:`_schema.ForeignKey.column`, 

5373 including the ``(table_name, column_name)`` and 

5374 ``(schema, table_name, column_name)`` tuple forms. 

5375 

5376 .. versionchanged:: 2.1 Individual entries may be given as a 

5377 tuple of name tokens. 

5378 

5379 :param name: Optional, the in-database name of the key. 

5380 

5381 :param onupdate: Optional string. If set, emit ON UPDATE <value> when 

5382 issuing DDL for this constraint. Typical values include CASCADE, 

5383 DELETE and RESTRICT. 

5384 

5385 .. seealso:: 

5386 

5387 :ref:`on_update_on_delete` 

5388 

5389 :param ondelete: Optional string. If set, emit ON DELETE <value> when 

5390 issuing DDL for this constraint. Typical values include CASCADE, 

5391 SET NULL and RESTRICT. Some dialects may allow for additional 

5392 syntaxes. 

5393 

5394 .. seealso:: 

5395 

5396 :ref:`on_update_on_delete` 

5397 

5398 :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT 

5399 DEFERRABLE when issuing DDL for this constraint. 

5400 

5401 :param initially: Optional string. If set, emit INITIALLY <value> when 

5402 issuing DDL for this constraint. 

5403 

5404 :param link_to_name: if True, the string name given in ``column`` is 

5405 the rendered name of the referenced column, not its locally assigned 

5406 ``key``. 

5407 

5408 :param use_alter: If True, do not emit the DDL for this constraint as 

5409 part of the CREATE TABLE definition. Instead, generate it via an 

5410 ALTER TABLE statement issued after the full collection of tables 

5411 have been created, and drop it via an ALTER TABLE statement before 

5412 the full collection of tables are dropped. 

5413 

5414 The use of :paramref:`_schema.ForeignKeyConstraint.use_alter` is 

5415 particularly geared towards the case where two or more tables 

5416 are established within a mutually-dependent foreign key constraint 

5417 relationship; however, the :meth:`_schema.MetaData.create_all` and 

5418 :meth:`_schema.MetaData.drop_all` 

5419 methods will perform this resolution 

5420 automatically, so the flag is normally not needed. 

5421 

5422 .. seealso:: 

5423 

5424 :ref:`use_alter` 

5425 

5426 :param match: Optional string. If set, emit MATCH <value> when issuing 

5427 DDL for this constraint. Typical values include SIMPLE, PARTIAL 

5428 and FULL. 

5429 

5430 :param info: Optional data dictionary which will be populated into the 

5431 :attr:`.SchemaItem.info` attribute of this object. 

5432 

5433 :param comment: Optional string that will render an SQL comment on 

5434 foreign key constraint creation. 

5435 

5436 .. versionadded:: 2.0 

5437 

5438 :param \**dialect_kw: Additional keyword arguments are dialect 

5439 specific, and passed in the form ``<dialectname>_<argname>``. See 

5440 the documentation regarding an individual dialect at 

5441 :ref:`dialect_toplevel` for detail on documented arguments. 

5442 

5443 """ 

5444 

5445 Constraint.__init__( 

5446 self, 

5447 name=name, 

5448 deferrable=deferrable, 

5449 initially=initially, 

5450 info=info, 

5451 comment=comment, 

5452 **dialect_kw, 

5453 ) 

5454 self.onupdate = onupdate 

5455 self.ondelete = ondelete 

5456 self.link_to_name = link_to_name 

5457 self.use_alter = use_alter 

5458 self.match = match 

5459 

5460 if len(columns) != len(refcolumns): 

5461 # e.g. FOREIGN KEY (a) REFERENCES r (b, c) 

5462 # paraphrasing 

5463 # https://www.postgresql.org/docs/current/static/ddl-constraints.html 

5464 raise exc.ArgumentError( 

5465 "ForeignKeyConstraint number " 

5466 "of constrained columns must match the number of " 

5467 "referenced columns." 

5468 ) 

5469 

5470 # standalone ForeignKeyConstraint - create 

5471 # associated ForeignKey objects which will be applied to hosted 

5472 # Column objects (in col.foreign_keys), either now or when attached 

5473 # to the Table for string-specified names 

5474 self.elements = [ 

5475 ForeignKey( 

5476 refcol, 

5477 _constraint=self, 

5478 name=self.name, 

5479 onupdate=self.onupdate, 

5480 ondelete=self.ondelete, 

5481 use_alter=self.use_alter, 

5482 link_to_name=self.link_to_name, 

5483 match=self.match, 

5484 deferrable=self.deferrable, 

5485 initially=self.initially, 

5486 **self.dialect_kwargs, 

5487 ) 

5488 for refcol in refcolumns 

5489 ] 

5490 

5491 ColumnCollectionMixin.__init__(self, *columns) 

5492 if table is not None: 

5493 if hasattr(self, "parent"): 

5494 assert table is self.parent 

5495 self._set_parent_with_dispatch(table) 

5496 

5497 def _append_element(self, column: Column[Any], fk: ForeignKey) -> None: 

5498 self._columns.add(column) 

5499 self.elements.append(fk) 

5500 

5501 columns: ReadOnlyColumnCollection[str, Column[Any]] 

5502 """A :class:`_expression.ColumnCollection` representing the local columns 

5503 of this constraint, in the order given and parallel to 

5504 :attr:`.ForeignKeyConstraint.elements`. 

5505 

5506 Unlike the column collection of other constraint types, this collection 

5507 does not deduplicate; a constraint which names the same column more than 

5508 once, such as ``FOREIGN KEY (a, a) REFERENCES r (b, c)``, includes that 

5509 column once per position. 

5510 

5511 .. versionchanged:: 2.1 A :class:`_schema.ForeignKeyConstraint` may name 

5512 the same local column more than once, and this collection retains the 

5513 repeated entries. 

5514 

5515 """ 

5516 

5517 elements: List[ForeignKey] 

5518 """A sequence of :class:`_schema.ForeignKey` objects. 

5519 

5520 Each :class:`_schema.ForeignKey` 

5521 represents a single referring column/referred 

5522 column pair. 

5523 

5524 This collection is intended to be read-only. 

5525 

5526 """ 

5527 

5528 @property 

5529 def _referred_schema(self) -> Optional[str]: 

5530 for elem in self.elements: 

5531 return elem._referred_schema 

5532 else: 

5533 return None 

5534 

5535 @property 

5536 def referred_table(self) -> Table: 

5537 """The :class:`_schema.Table` object to which this 

5538 :class:`_schema.ForeignKeyConstraint` references. 

5539 

5540 This is a dynamically calculated attribute which may not be available 

5541 if the constraint and/or parent table is not yet associated with 

5542 a metadata collection that contains the referred table. 

5543 

5544 """ 

5545 return self.elements[0].column.table 

5546 

5547 def _validate_dest_table(self, table: Table) -> None: 

5548 table_keys = {elem.target_table_key for elem in self.elements} 

5549 if None not in table_keys and len(table_keys) > 1: 

5550 elem0, elem1 = sorted(cast("Set[str]", table_keys))[0:2] 

5551 raise exc.ArgumentError( 

5552 f"ForeignKeyConstraint on " 

5553 f"{table.fullname}({self._col_description}) refers to " 

5554 f"multiple remote tables: {elem0} and {elem1}" 

5555 ) 

5556 

5557 @property 

5558 def column_keys(self) -> _typing_Sequence[str]: 

5559 """Return a list of string keys representing the local 

5560 columns in this :class:`_schema.ForeignKeyConstraint`. 

5561 

5562 This list is either the original string arguments sent 

5563 to the constructor of the :class:`_schema.ForeignKeyConstraint`, 

5564 or if the constraint has been initialized with :class:`_schema.Column` 

5565 objects, is the string ``.key`` of each element. 

5566 

5567 """ 

5568 if hasattr(self, "parent"): 

5569 return self._columns.keys() 

5570 else: 

5571 return [ 

5572 col.key if isinstance(col, ColumnElement) else str(col) 

5573 for col in self._pending_colargs 

5574 ] 

5575 

5576 @property 

5577 def _col_description(self) -> str: 

5578 return ", ".join(self.column_keys) 

5579 

5580 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

5581 table = parent 

5582 assert isinstance(table, Table) 

5583 Constraint._set_parent(self, table) 

5584 

5585 if self._pending_colargs: 

5586 # this collection is positional and parallel to self.elements, 

5587 # retaining duplicate entries for a constraint such as 

5588 # FOREIGN KEY (a, a) REFERENCES r (b, c). _set_parent may run 

5589 # more than once for the same table, e.g. for an inline-declared 

5590 # constraint that also auto-attaches when its Column objects 

5591 # are attached, so populate rather than accumulate. 

5592 self._columns._populate_separate_keys( 

5593 (col.key, col) 

5594 for col in self._col_expressions(table) 

5595 if col is not None 

5596 ) 

5597 

5598 for col, fk in zip(self._columns, self.elements): 

5599 if not hasattr(fk, "parent") or fk.parent is not col: 

5600 fk._set_parent_with_dispatch(col) 

5601 

5602 self._validate_dest_table(table) 

5603 

5604 @util.deprecated( 

5605 "1.4", 

5606 "The :meth:`_schema.ForeignKeyConstraint.copy` method is deprecated " 

5607 "and will be removed in a future release.", 

5608 ) 

5609 def copy( 

5610 self, 

5611 *, 

5612 schema: Optional[str] = None, 

5613 target_table: Optional[Table] = None, 

5614 **kw: Any, 

5615 ) -> ForeignKeyConstraint: 

5616 return self._copy(schema=schema, target_table=target_table, **kw) 

5617 

5618 def _copy( 

5619 self, 

5620 *, 

5621 schema: Optional[str] = None, 

5622 target_table: Optional[Table] = None, 

5623 **kw: Any, 

5624 ) -> ForeignKeyConstraint: 

5625 fkc = ForeignKeyConstraint( 

5626 [x.parent.key for x in self.elements], 

5627 [ 

5628 x._copy_tokens( 

5629 schema=schema, 

5630 table_name=( 

5631 target_table.name 

5632 if target_table is not None 

5633 and x.target_table_key == x.parent.table.key 

5634 else None 

5635 ), 

5636 _is_copy=True, 

5637 ) 

5638 for x in self.elements 

5639 ], 

5640 name=self.name, 

5641 onupdate=self.onupdate, 

5642 ondelete=self.ondelete, 

5643 use_alter=self.use_alter, 

5644 deferrable=self.deferrable, 

5645 initially=self.initially, 

5646 link_to_name=self.link_to_name, 

5647 match=self.match, 

5648 comment=self.comment, 

5649 ) 

5650 for self_fk, other_fk in zip(self.elements, fkc.elements): 

5651 self_fk._schema_item_copy(other_fk) 

5652 return self._schema_item_copy(fkc) 

5653 

5654 

5655class PrimaryKeyConstraint(ColumnCollectionConstraint): 

5656 """A table-level PRIMARY KEY constraint. 

5657 

5658 The :class:`.PrimaryKeyConstraint` object is present automatically 

5659 on any :class:`_schema.Table` object; it is assigned a set of 

5660 :class:`_schema.Column` objects corresponding to those marked with 

5661 the :paramref:`_schema.Column.primary_key` flag:: 

5662 

5663 >>> my_table = Table( 

5664 ... "mytable", 

5665 ... metadata, 

5666 ... Column("id", Integer, primary_key=True), 

5667 ... Column("version_id", Integer, primary_key=True), 

5668 ... Column("data", String(50)), 

5669 ... ) 

5670 >>> my_table.primary_key 

5671 PrimaryKeyConstraint( 

5672 Column('id', Integer(), table=<mytable>, 

5673 primary_key=True, nullable=False), 

5674 Column('version_id', Integer(), table=<mytable>, 

5675 primary_key=True, nullable=False) 

5676 ) 

5677 

5678 The primary key of a :class:`_schema.Table` can also be specified by using 

5679 a :class:`.PrimaryKeyConstraint` object explicitly; in this mode of usage, 

5680 the "name" of the constraint can also be specified, as well as other 

5681 options which may be recognized by dialects:: 

5682 

5683 my_table = Table( 

5684 "mytable", 

5685 metadata, 

5686 Column("id", Integer), 

5687 Column("version_id", Integer), 

5688 Column("data", String(50)), 

5689 PrimaryKeyConstraint("id", "version_id", name="mytable_pk"), 

5690 ) 

5691 

5692 The two styles of column-specification should generally not be mixed. 

5693 An warning is emitted if the columns present in the 

5694 :class:`.PrimaryKeyConstraint` 

5695 don't match the columns that were marked as ``primary_key=True``, if both 

5696 are present; in this case, the columns are taken strictly from the 

5697 :class:`.PrimaryKeyConstraint` declaration, and those columns otherwise 

5698 marked as ``primary_key=True`` are ignored. This behavior is intended to 

5699 be backwards compatible with previous behavior. 

5700 

5701 For the use case where specific options are to be specified on the 

5702 :class:`.PrimaryKeyConstraint`, but the usual style of using 

5703 ``primary_key=True`` flags is still desirable, an empty 

5704 :class:`.PrimaryKeyConstraint` may be specified, which will take on the 

5705 primary key column collection from the :class:`_schema.Table` based on the 

5706 flags:: 

5707 

5708 my_table = Table( 

5709 "mytable", 

5710 metadata, 

5711 Column("id", Integer, primary_key=True), 

5712 Column("version_id", Integer, primary_key=True), 

5713 Column("data", String(50)), 

5714 PrimaryKeyConstraint(name="mytable_pk", mssql_clustered=True), 

5715 ) 

5716 

5717 """ 

5718 

5719 __visit_name__ = "primary_key_constraint" 

5720 

5721 _columns: DedupeColumnCollection[Column[Any]] 

5722 

5723 def __init__( 

5724 self, 

5725 *columns: _DDLColumnArgument, 

5726 name: Optional[str] = None, 

5727 deferrable: Optional[bool] = None, 

5728 initially: Optional[str] = None, 

5729 info: Optional[_InfoType] = None, 

5730 _implicit_generated: bool = False, 

5731 **dialect_kw: Any, 

5732 ) -> None: 

5733 self._implicit_generated = _implicit_generated 

5734 super().__init__( 

5735 *columns, 

5736 name=name, 

5737 deferrable=deferrable, 

5738 initially=initially, 

5739 info=info, 

5740 **dialect_kw, 

5741 ) 

5742 

5743 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

5744 table = parent 

5745 assert isinstance(table, Table) 

5746 super()._set_parent(table) 

5747 

5748 if table.primary_key is not self: 

5749 table.constraints.discard(table.primary_key) 

5750 table.primary_key = self # type: ignore[misc] 

5751 table.constraints.add(self) 

5752 

5753 table_pks = [c for c in table.c if c.primary_key] 

5754 if ( 

5755 self._columns 

5756 and table_pks 

5757 and set(table_pks) != set(self._columns) 

5758 ): 

5759 # black could not format these inline 

5760 table_pk_str = ", ".join("'%s'" % c.name for c in table_pks) 

5761 col_str = ", ".join("'%s'" % c.name for c in self._columns) 

5762 

5763 util.warn( 

5764 f"Table '{table.name}' specifies columns " 

5765 f"{table_pk_str} as " 

5766 f"primary_key=True, " 

5767 f"not matching locally specified columns {col_str}; " 

5768 f"setting the " 

5769 f"current primary key columns to " 

5770 f"{col_str}. " 

5771 f"This warning " 

5772 f"may become an exception in a future release" 

5773 ) 

5774 table_pks[:] = [] 

5775 

5776 for c in self._columns: 

5777 c.primary_key = True 

5778 if c._user_defined_nullable is NULL_UNSPECIFIED: 

5779 c.nullable = False 

5780 if table_pks: 

5781 self._columns.extend(table_pks) 

5782 

5783 def _reload(self, columns: Iterable[Column[Any]]) -> None: 

5784 """repopulate this :class:`.PrimaryKeyConstraint` given 

5785 a set of columns. 

5786 

5787 Existing columns in the table that are marked as primary_key=True 

5788 are maintained. 

5789 

5790 Also fires a new event. 

5791 

5792 This is basically like putting a whole new 

5793 :class:`.PrimaryKeyConstraint` object on the parent 

5794 :class:`_schema.Table` object without actually replacing the object. 

5795 

5796 The ordering of the given list of columns is also maintained; these 

5797 columns will be appended to the list of columns after any which 

5798 are already present. 

5799 

5800 """ 

5801 # set the primary key flag on new columns. 

5802 # note any existing PK cols on the table also have their 

5803 # flag still set. 

5804 for col in columns: 

5805 col.primary_key = True 

5806 

5807 self._columns.extend(columns) 

5808 

5809 PrimaryKeyConstraint._autoincrement_column._reset(self) # type: ignore[attr-defined] # noqa: E501 

5810 self._set_parent_with_dispatch(self.table) 

5811 

5812 def _replace(self, col: Column[Any]) -> None: 

5813 PrimaryKeyConstraint._autoincrement_column._reset(self) # type: ignore[attr-defined] # noqa: E501 

5814 self._columns.replace(col) 

5815 

5816 self.dispatch._sa_event_column_added_to_pk_constraint(self, col) 

5817 

5818 @property 

5819 def columns_autoinc_first(self) -> List[Column[Any]]: 

5820 autoinc = self._autoincrement_column 

5821 

5822 if autoinc is not None: 

5823 return [autoinc] + [c for c in self._columns if c is not autoinc] 

5824 else: 

5825 return list(self._columns) 

5826 

5827 @util.ro_memoized_property 

5828 def _autoincrement_column(self) -> Optional[Column[int]]: 

5829 def _validate_autoinc(col: Column[Any], autoinc_true: bool) -> bool: 

5830 if col.type._type_affinity is not None and issubclass( 

5831 col.type._type_affinity, type_api.NUMERICTYPE._type_affinity 

5832 ): 

5833 scale = col.type.scale # type: ignore[attr-defined] 

5834 if scale != 0 and autoinc_true: 

5835 raise exc.ArgumentError( 

5836 f"Column type {col.type} with non-zero scale " 

5837 f"{scale} on column '{col}' is not " 

5838 f"compatible with autoincrement=True" 

5839 ) 

5840 elif not autoinc_true: 

5841 return False 

5842 elif col.type._type_affinity is None or not issubclass( 

5843 col.type._type_affinity, type_api.INTEGERTYPE._type_affinity 

5844 ): 

5845 if autoinc_true: 

5846 raise exc.ArgumentError( 

5847 f"Column type {col.type} on column '{col}' is not " 

5848 f"compatible with autoincrement=True" 

5849 ) 

5850 else: 

5851 return False 

5852 elif ( 

5853 col.default is not None 

5854 and not isinstance(col.default, Sequence) 

5855 and not autoinc_true 

5856 ): 

5857 return False 

5858 elif ( 

5859 col.server_default is not None 

5860 and not isinstance(col.server_default, Identity) 

5861 and not autoinc_true 

5862 ): 

5863 return False 

5864 elif col.foreign_keys and col.autoincrement not in ( 

5865 True, 

5866 "ignore_fk", 

5867 ): 

5868 return False 

5869 return True 

5870 

5871 if len(self._columns) == 1: 

5872 col = list(self._columns)[0] 

5873 

5874 if col.autoincrement is True: 

5875 _validate_autoinc(col, True) 

5876 return col 

5877 elif col.autoincrement in ( 

5878 "auto", 

5879 "ignore_fk", 

5880 ) and _validate_autoinc(col, False): 

5881 return col 

5882 else: 

5883 return None 

5884 

5885 else: 

5886 autoinc = None 

5887 for col in self._columns: 

5888 if col.autoincrement is True: 

5889 _validate_autoinc(col, True) 

5890 if autoinc is not None: 

5891 raise exc.ArgumentError( 

5892 f"Only one Column may be marked " 

5893 f"autoincrement=True, found both " 

5894 f"{col.name} and {autoinc.name}." 

5895 ) 

5896 else: 

5897 autoinc = col 

5898 

5899 return autoinc 

5900 

5901 

5902class UniqueConstraint(ColumnCollectionConstraint): 

5903 """A table-level UNIQUE constraint. 

5904 

5905 Defines a single column or composite UNIQUE constraint. For a no-frills, 

5906 single column constraint, adding ``unique=True`` to the ``Column`` 

5907 definition is a shorthand equivalent for an unnamed, single column 

5908 UniqueConstraint. 

5909 """ 

5910 

5911 __visit_name__ = "unique_constraint" 

5912 

5913 

5914class Index( 

5915 DialectKWArgs, ColumnCollectionMixin, HasConditionalDDL, SchemaItem 

5916): 

5917 """A table-level INDEX. 

5918 

5919 Defines a composite (one or more column) INDEX. 

5920 

5921 E.g.:: 

5922 

5923 sometable = Table( 

5924 "sometable", 

5925 metadata, 

5926 Column("name", String(50)), 

5927 Column("address", String(100)), 

5928 ) 

5929 

5930 Index("some_index", sometable.c.name) 

5931 

5932 For a no-frills, single column index, adding 

5933 :class:`_schema.Column` also supports ``index=True``:: 

5934 

5935 sometable = Table( 

5936 "sometable", metadata, Column("name", String(50), index=True) 

5937 ) 

5938 

5939 For a composite index, multiple columns can be specified:: 

5940 

5941 Index("some_index", sometable.c.name, sometable.c.address) 

5942 

5943 Functional indexes are supported as well, typically by using the 

5944 :data:`.func` construct in conjunction with table-bound 

5945 :class:`_schema.Column` objects:: 

5946 

5947 Index("some_index", func.lower(sometable.c.name)) 

5948 

5949 An :class:`.Index` can also be manually associated with a 

5950 :class:`_schema.Table`, 

5951 either through inline declaration or using 

5952 :meth:`_schema.Table.append_constraint`. When this approach is used, 

5953 the names 

5954 of the indexed columns can be specified as strings:: 

5955 

5956 Table( 

5957 "sometable", 

5958 metadata, 

5959 Column("name", String(50)), 

5960 Column("address", String(100)), 

5961 Index("some_index", "name", "address"), 

5962 ) 

5963 

5964 To support functional or expression-based indexes in this form, the 

5965 :func:`_expression.text` construct may be used:: 

5966 

5967 from sqlalchemy import text 

5968 

5969 Table( 

5970 "sometable", 

5971 metadata, 

5972 Column("name", String(50)), 

5973 Column("address", String(100)), 

5974 Index("some_index", text("lower(name)")), 

5975 ) 

5976 

5977 .. seealso:: 

5978 

5979 :ref:`schema_indexes` - General information on :class:`.Index`. 

5980 

5981 :ref:`postgresql_indexes` - PostgreSQL-specific options available for 

5982 the :class:`.Index` construct. 

5983 

5984 :ref:`mysql_indexes` - MySQL-specific options available for the 

5985 :class:`.Index` construct. 

5986 

5987 :ref:`mssql_indexes` - MSSQL-specific options available for the 

5988 :class:`.Index` construct. 

5989 

5990 """ 

5991 

5992 __visit_name__ = "index" 

5993 

5994 table: Optional[Table] 

5995 expressions: _typing_Sequence[Union[str, ColumnElement[Any]]] 

5996 _table_bound_expressions: _typing_Sequence[ColumnElement[Any]] 

5997 

5998 def __init__( 

5999 self, 

6000 name: Optional[str], 

6001 *expressions: _DDLColumnArgument, 

6002 unique: bool = False, 

6003 quote: Optional[bool] = None, 

6004 info: Optional[_InfoType] = None, 

6005 _table: Optional[Table] = None, 

6006 _column_flag: bool = False, 

6007 **dialect_kw: Any, 

6008 ) -> None: 

6009 r"""Construct an index object. 

6010 

6011 :param name: 

6012 The name of the index 

6013 

6014 :param \*expressions: 

6015 Column expressions to include in the index. The expressions 

6016 are normally instances of :class:`_schema.Column`, but may also 

6017 be arbitrary SQL expressions which ultimately refer to a 

6018 :class:`_schema.Column`. 

6019 

6020 :param unique=False: 

6021 Keyword only argument; if True, create a unique index. 

6022 

6023 :param quote=None: 

6024 Keyword only argument; whether to apply quoting to the name of 

6025 the index. Works in the same manner as that of 

6026 :paramref:`_schema.Column.quote`. 

6027 

6028 :param info=None: Optional data dictionary which will be populated 

6029 into the :attr:`.SchemaItem.info` attribute of this object. 

6030 

6031 :param \**dialect_kw: Additional keyword arguments not mentioned above 

6032 are dialect specific, and passed in the form 

6033 ``<dialectname>_<argname>``. See the documentation regarding an 

6034 individual dialect at :ref:`dialect_toplevel` for detail on 

6035 documented arguments. 

6036 

6037 """ 

6038 self.table = table = None 

6039 

6040 self.name = quoted_name.construct(name, quote) 

6041 self.unique = unique 

6042 if info is not None: 

6043 self.info = info 

6044 

6045 # TODO: consider "table" argument being public, but for 

6046 # the purpose of the fix here, it starts as private. 

6047 if _table is not None: 

6048 table = _table 

6049 

6050 self._validate_dialect_kwargs(dialect_kw) 

6051 

6052 self.expressions = [] 

6053 # will call _set_parent() if table-bound column 

6054 # objects are present 

6055 ColumnCollectionMixin.__init__( 

6056 self, 

6057 *expressions, 

6058 _column_flag=_column_flag, 

6059 _gather_expressions=self.expressions, 

6060 ) 

6061 if table is not None: 

6062 self._set_parent(table) 

6063 

6064 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

6065 table = parent 

6066 assert isinstance(table, Table) 

6067 ColumnCollectionMixin._set_parent(self, table) 

6068 

6069 if self.table is not None and table is not self.table: 

6070 raise exc.ArgumentError( 

6071 f"Index '{self.name}' is against table " 

6072 f"'{self.table.description}', and " 

6073 f"cannot be associated with table '{table.description}'." 

6074 ) 

6075 self.table = table 

6076 table.indexes.add(self) 

6077 

6078 expressions = self.expressions 

6079 col_expressions = self._col_expressions(table) 

6080 assert len(expressions) == len(col_expressions) 

6081 

6082 exprs = [] 

6083 for expr, colexpr in zip(expressions, col_expressions): 

6084 if isinstance(expr, ClauseElement): 

6085 exprs.append(expr) 

6086 elif colexpr is not None: 

6087 exprs.append(colexpr) 

6088 else: 

6089 assert False 

6090 self.expressions = self._table_bound_expressions = exprs 

6091 

6092 def create( 

6093 self, 

6094 bind: _CreateDropBind, 

6095 checkfirst: Union[bool, CheckFirst] = CheckFirst.NONE, 

6096 ) -> None: 

6097 """Issue a ``CREATE`` statement for this 

6098 :class:`.Index`, using the given 

6099 :class:`.Connection` or :class:`.Engine`` for connectivity. 

6100 

6101 .. seealso:: 

6102 

6103 :meth:`_schema.MetaData.create_all`. 

6104 

6105 """ 

6106 bind._run_ddl_visitor(ddl.SchemaGenerator, self, checkfirst=checkfirst) 

6107 

6108 def drop( 

6109 self, 

6110 bind: _CreateDropBind, 

6111 checkfirst: Union[bool, CheckFirst] = CheckFirst.NONE, 

6112 ) -> None: 

6113 """Issue a ``DROP`` statement for this 

6114 :class:`.Index`, using the given 

6115 :class:`.Connection` or :class:`.Engine` for connectivity. 

6116 

6117 .. seealso:: 

6118 

6119 :meth:`_schema.MetaData.drop_all`. 

6120 

6121 """ 

6122 bind._run_ddl_visitor(ddl.SchemaDropper, self, checkfirst=checkfirst) 

6123 

6124 def __repr__(self) -> str: 

6125 exprs: _typing_Sequence[Any] # noqa: F842 

6126 

6127 return "Index(%s)" % ( 

6128 ", ".join( 

6129 [repr(self.name)] 

6130 + [repr(e) for e in self.expressions] 

6131 + (self.unique and ["unique=True"] or []) 

6132 ) 

6133 ) 

6134 

6135 

6136_NamingSchemaCallable = Union[ 

6137 Callable[[Constraint, Table], str], 

6138 Callable[[Index, Table], str], 

6139] 

6140_NamingSchemaDirective = Union[str, _NamingSchemaCallable] 

6141 

6142 

6143class _NamingSchemaTD(TypedDict, total=False): 

6144 fk: _NamingSchemaDirective 

6145 pk: _NamingSchemaDirective 

6146 ix: _NamingSchemaDirective 

6147 ck: _NamingSchemaDirective 

6148 uq: _NamingSchemaDirective 

6149 

6150 

6151_NamingSchemaParameter = Union[ 

6152 # it seems like the TypedDict here is useful for pylance typeahead, 

6153 # and not much else 

6154 _NamingSchemaTD, 

6155 # there is no form that allows Union[Type[Any], str] to work in all 

6156 # cases, including breaking out Mapping[] entries for each combination 

6157 # even, therefore keys must be `Any` (see #10264) 

6158 Mapping[Any, _NamingSchemaDirective], 

6159] 

6160 

6161 

6162DEFAULT_NAMING_CONVENTION: _NamingSchemaParameter = util.immutabledict( 

6163 {"ix": "ix_%(column_0_label)s"} 

6164) 

6165 

6166 

6167class MetaData(HasSchemaAttr): 

6168 """A collection of :class:`_schema.Table` 

6169 objects and their associated schema 

6170 constructs. 

6171 

6172 Holds a collection of :class:`_schema.Table` objects as well as 

6173 an optional binding to an :class:`_engine.Engine` or 

6174 :class:`_engine.Connection`. If bound, the :class:`_schema.Table` objects 

6175 in the collection and their columns may participate in implicit SQL 

6176 execution. 

6177 

6178 The :class:`_schema.Table` objects themselves are stored in the 

6179 :attr:`_schema.MetaData.tables` dictionary. 

6180 

6181 :class:`_schema.MetaData` is a thread-safe object for read operations. 

6182 Construction of new tables within a single :class:`_schema.MetaData` 

6183 object, 

6184 either explicitly or via reflection, may not be completely thread-safe. 

6185 

6186 .. seealso:: 

6187 

6188 :ref:`metadata_describing` - Introduction to database metadata 

6189 

6190 """ 

6191 

6192 __visit_name__ = "metadata" 

6193 

6194 def __init__( 

6195 self, 

6196 schema: Optional[str] = None, 

6197 quote_schema: Optional[bool] = None, 

6198 naming_convention: Optional[_NamingSchemaParameter] = None, 

6199 info: Optional[_InfoType] = None, 

6200 ) -> None: 

6201 """Create a new MetaData object. 

6202 

6203 :param schema: 

6204 The default schema to use for the :class:`_schema.Table`, 

6205 :class:`.Sequence`, and potentially other objects associated with 

6206 this :class:`_schema.MetaData`. Defaults to ``None``. 

6207 

6208 .. seealso:: 

6209 

6210 :ref:`schema_metadata_schema_name` - details on how the 

6211 :paramref:`_schema.MetaData.schema` parameter is used. 

6212 

6213 :paramref:`_schema.Table.schema` 

6214 

6215 :paramref:`.Sequence.schema` 

6216 

6217 :param quote_schema: 

6218 Sets the ``quote_schema`` flag for those :class:`_schema.Table`, 

6219 :class:`.Sequence`, and other objects which make usage of the 

6220 local ``schema`` name. 

6221 

6222 :param info: Optional data dictionary which will be populated into the 

6223 :attr:`.SchemaItem.info` attribute of this object. 

6224 

6225 :param naming_convention: a dictionary referring to values which 

6226 will establish default naming conventions for :class:`.Constraint` 

6227 and :class:`.Index` objects, for those objects which are not given 

6228 a name explicitly. 

6229 

6230 The keys of this dictionary may be: 

6231 

6232 * a constraint or Index class, e.g. the :class:`.UniqueConstraint`, 

6233 :class:`_schema.ForeignKeyConstraint` class, the :class:`.Index` 

6234 class 

6235 

6236 * a string mnemonic for one of the known constraint classes; 

6237 ``"fk"``, ``"pk"``, ``"ix"``, ``"ck"``, ``"uq"`` for foreign key, 

6238 primary key, index, check, and unique constraint, respectively. 

6239 

6240 * the string name of a user-defined "token" that can be used 

6241 to define new naming tokens. 

6242 

6243 The values associated with each "constraint class" or "constraint 

6244 mnemonic" key are string naming templates, such as 

6245 ``"uq_%(table_name)s_%(column_0_name)s"``, 

6246 which describe how the name should be composed. The values 

6247 associated with user-defined "token" keys should be callables of the 

6248 form ``fn(constraint, table)``, which accepts the constraint/index 

6249 object and :class:`_schema.Table` as arguments, returning a string 

6250 result. 

6251 

6252 The built-in names are as follows, some of which may only be 

6253 available for certain types of constraint: 

6254 

6255 * ``%(table_name)s`` - the name of the :class:`_schema.Table` 

6256 object 

6257 associated with the constraint. 

6258 

6259 * ``%(referred_table_name)s`` - the name of the 

6260 :class:`_schema.Table` 

6261 object associated with the referencing target of a 

6262 :class:`_schema.ForeignKeyConstraint`. 

6263 

6264 * ``%(column_0_name)s`` - the name of the :class:`_schema.Column` 

6265 at 

6266 index position "0" within the constraint. 

6267 

6268 * ``%(column_0N_name)s`` - the name of all :class:`_schema.Column` 

6269 objects in order within the constraint, joined without a 

6270 separator. 

6271 

6272 * ``%(column_0_N_name)s`` - the name of all 

6273 :class:`_schema.Column` 

6274 objects in order within the constraint, joined with an 

6275 underscore as a separator. 

6276 

6277 * ``%(column_0_label)s``, ``%(column_0N_label)s``, 

6278 ``%(column_0_N_label)s`` - the label of either the zeroth 

6279 :class:`_schema.Column` or all :class:`.Columns`, separated with 

6280 or without an underscore 

6281 

6282 * ``%(column_0_key)s``, ``%(column_0N_key)s``, 

6283 ``%(column_0_N_key)s`` - the key of either the zeroth 

6284 :class:`_schema.Column` or all :class:`.Columns`, separated with 

6285 or without an underscore 

6286 

6287 * ``%(referred_column_0_name)s``, ``%(referred_column_0N_name)s`` 

6288 ``%(referred_column_0_N_name)s``, ``%(referred_column_0_key)s``, 

6289 ``%(referred_column_0N_key)s``, ... column tokens which 

6290 render the names/keys/labels of columns that are referenced 

6291 by a :class:`_schema.ForeignKeyConstraint`. 

6292 

6293 * ``%(constraint_name)s`` - a special key that refers to the 

6294 existing name given to the constraint. When this key is 

6295 present, the :class:`.Constraint` object's existing name will be 

6296 replaced with one that is composed from template string that 

6297 uses this token. When this token is present, it is required that 

6298 the :class:`.Constraint` is given an explicit name ahead of time. 

6299 

6300 * user-defined: any additional token may be implemented by passing 

6301 it along with a ``fn(constraint, table)`` callable to the 

6302 naming_convention dictionary. 

6303 

6304 .. seealso:: 

6305 

6306 :ref:`constraint_naming_conventions` - for detailed usage 

6307 examples. 

6308 

6309 """ 

6310 if schema is not None and not isinstance(schema, str): 

6311 raise exc.ArgumentError( 

6312 "expected schema argument to be a string, " 

6313 f"got {type(schema)}." 

6314 ) 

6315 self.tables = util.FacadeDict() 

6316 self.schema = quoted_name.construct(schema, quote_schema) 

6317 self.naming_convention = ( 

6318 naming_convention 

6319 if naming_convention 

6320 else DEFAULT_NAMING_CONVENTION 

6321 ) 

6322 if info: 

6323 self.info = info 

6324 self._schemas: Set[str] = set() 

6325 self._sequences: Dict[str, Sequence] = {} 

6326 self._fk_memos: Dict[Tuple[str, Optional[str]], List[ForeignKey]] = ( 

6327 collections.defaultdict(list) 

6328 ) 

6329 self._objects: Set[Union[HasSchemaAttr, SchemaType]] = set() 

6330 

6331 tables: util.FacadeDict[str, Table] 

6332 """A dictionary of :class:`_schema.Table` 

6333 objects keyed to their name or "table key". 

6334 

6335 The exact key is that determined by the :attr:`_schema.Table.key` 

6336 attribute; 

6337 for a table with no :attr:`_schema.Table.schema` attribute, 

6338 this is the same 

6339 as :attr:`_schema.Table.name`. For a table with a schema, 

6340 it is typically of the 

6341 form ``schemaname.tablename``. 

6342 

6343 .. seealso:: 

6344 

6345 :attr:`_schema.MetaData.sorted_tables` 

6346 

6347 """ 

6348 

6349 def __repr__(self) -> str: 

6350 return "MetaData()" 

6351 

6352 def __contains__(self, table_or_key: Union[str, Table]) -> bool: 

6353 if not isinstance(table_or_key, str): 

6354 table_or_key = table_or_key.key 

6355 return table_or_key in self.tables 

6356 

6357 def _add_table( 

6358 self, name: str, schema: Optional[str], table: Table 

6359 ) -> None: 

6360 key = _get_table_key(name, schema) 

6361 self.tables._insert_item(key, table) 

6362 if schema: 

6363 self._schemas.add(schema) 

6364 

6365 def _remove_table(self, name: str, schema: Optional[str]) -> None: 

6366 key = _get_table_key(name, schema) 

6367 removed = dict.pop(self.tables, key, None) 

6368 if removed is not None: 

6369 for fk in removed.foreign_keys: 

6370 fk._remove_from_metadata(self) 

6371 if self._schemas: 

6372 self._schemas = { 

6373 t.schema for t in self.tables.values() if t.schema is not None 

6374 } 

6375 

6376 def __getstate__(self) -> Dict[str, Any]: 

6377 return { 

6378 "tables": self.tables, 

6379 "schema": self.schema, 

6380 "schemas": self._schemas, 

6381 "sequences": self._sequences, 

6382 "fk_memos": self._fk_memos, 

6383 "naming_convention": self.naming_convention, 

6384 "objects": self._objects, 

6385 } 

6386 

6387 def __setstate__(self, state: Dict[str, Any]) -> None: 

6388 self.tables = state["tables"] 

6389 self.schema = state["schema"] 

6390 self.naming_convention = state["naming_convention"] 

6391 self._sequences = state["sequences"] 

6392 self._schemas = state["schemas"] 

6393 self._fk_memos = state["fk_memos"] 

6394 self._objects = state.get("objects", set()) 

6395 

6396 def clear(self) -> None: 

6397 """Clear all objects from this MetaData.""" 

6398 

6399 dict.clear(self.tables) 

6400 self._schemas.clear() 

6401 self._fk_memos.clear() 

6402 self._sequences.clear() 

6403 self._objects.clear() 

6404 

6405 def remove(self, table: Table) -> None: 

6406 """Remove the given Table object from this MetaData.""" 

6407 

6408 self._remove_table(table.name, table.schema) 

6409 

6410 @property 

6411 def sorted_tables(self) -> List[Table]: 

6412 """Returns a list of :class:`_schema.Table` objects sorted in order of 

6413 foreign key dependency. 

6414 

6415 The sorting will place :class:`_schema.Table` 

6416 objects that have dependencies 

6417 first, before the dependencies themselves, representing the 

6418 order in which they can be created. To get the order in which 

6419 the tables would be dropped, use the ``reversed()`` Python built-in. 

6420 

6421 .. warning:: 

6422 

6423 The :attr:`.MetaData.sorted_tables` attribute cannot by itself 

6424 accommodate automatic resolution of dependency cycles between 

6425 tables, which are usually caused by mutually dependent foreign key 

6426 constraints. When these cycles are detected, the foreign keys 

6427 of these tables are omitted from consideration in the sort. 

6428 A warning is emitted when this condition occurs, which will be an 

6429 exception raise in a future release. Tables which are not part 

6430 of the cycle will still be returned in dependency order. 

6431 

6432 To resolve these cycles, the 

6433 :paramref:`_schema.ForeignKeyConstraint.use_alter` parameter may be 

6434 applied to those constraints which create a cycle. Alternatively, 

6435 the :func:`_schema.sort_tables_and_constraints` function will 

6436 automatically return foreign key constraints in a separate 

6437 collection when cycles are detected so that they may be applied 

6438 to a schema separately. 

6439 

6440 .. seealso:: 

6441 

6442 :func:`_schema.sort_tables` 

6443 

6444 :func:`_schema.sort_tables_and_constraints` 

6445 

6446 :attr:`_schema.MetaData.tables` 

6447 

6448 :meth:`_reflection.Inspector.get_table_names` 

6449 

6450 :meth:`_reflection.Inspector.get_sorted_table_and_fkc_names` 

6451 

6452 

6453 """ 

6454 return ddl.sort_tables( 

6455 sorted(self.tables.values(), key=lambda t: t.key) # type: ignore[attr-defined] # noqa: E501 

6456 ) 

6457 

6458 # overload needed to work around mypy this mypy 

6459 # https://github.com/python/mypy/issues/17093 

6460 @overload 

6461 def reflect( 

6462 self, 

6463 bind: Engine, 

6464 schema: Optional[str] = ..., 

6465 views: bool = ..., 

6466 only: Union[ 

6467 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

6468 ] = ..., 

6469 extend_existing: bool = ..., 

6470 autoload_replace: bool = ..., 

6471 resolve_fks: bool = ..., 

6472 **dialect_kwargs: Any, 

6473 ) -> None: ... 

6474 

6475 @overload 

6476 def reflect( 

6477 self, 

6478 bind: Connection, 

6479 schema: Optional[str] = ..., 

6480 views: bool = ..., 

6481 only: Union[ 

6482 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

6483 ] = ..., 

6484 extend_existing: bool = ..., 

6485 autoload_replace: bool = ..., 

6486 resolve_fks: bool = ..., 

6487 **dialect_kwargs: Any, 

6488 ) -> None: ... 

6489 

6490 @util.preload_module("sqlalchemy.engine.reflection") 

6491 def reflect( 

6492 self, 

6493 bind: Union[Engine, Connection], 

6494 schema: Optional[str] = None, 

6495 views: bool = False, 

6496 only: Union[ 

6497 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

6498 ] = None, 

6499 extend_existing: bool = False, 

6500 autoload_replace: bool = True, 

6501 resolve_fks: bool = True, 

6502 **dialect_kwargs: Any, 

6503 ) -> None: 

6504 r"""Load all available table definitions from the database. 

6505 

6506 Automatically creates ``Table`` entries in this ``MetaData`` for any 

6507 table available in the database but not yet present in the 

6508 ``MetaData``. May be called multiple times to pick up tables recently 

6509 added to the database, however no special action is taken if a table 

6510 in this ``MetaData`` no longer exists in the database. 

6511 

6512 :param bind: 

6513 A :class:`.Connection` or :class:`.Engine` used to access the 

6514 database. 

6515 

6516 :param schema: 

6517 Optional, query and reflect tables from an alternate schema. 

6518 If None, the schema associated with this :class:`_schema.MetaData` 

6519 is used, if any. 

6520 

6521 :param views: 

6522 If True, also reflect views (materialized and plain). 

6523 

6524 :param only: 

6525 Optional. Load only a sub-set of available named tables. May be 

6526 specified as a sequence of names or a callable. 

6527 

6528 If a sequence of names is provided, only those tables will be 

6529 reflected. An error is raised if a table is requested but not 

6530 available. Named tables already present in this ``MetaData`` are 

6531 ignored. 

6532 

6533 If a callable is provided, it will be used as a boolean predicate to 

6534 filter the list of potential table names. The callable is called 

6535 with a table name and this ``MetaData`` instance as positional 

6536 arguments and should return a true value for any table to reflect. 

6537 

6538 :param extend_existing: Passed along to each :class:`_schema.Table` as 

6539 :paramref:`_schema.Table.extend_existing`. 

6540 

6541 :param autoload_replace: Passed along to each :class:`_schema.Table` 

6542 as 

6543 :paramref:`_schema.Table.autoload_replace`. 

6544 

6545 :param resolve_fks: if True, reflect :class:`_schema.Table` 

6546 objects linked 

6547 to :class:`_schema.ForeignKey` objects located in each 

6548 :class:`_schema.Table`. 

6549 For :meth:`_schema.MetaData.reflect`, 

6550 this has the effect of reflecting 

6551 related tables that might otherwise not be in the list of tables 

6552 being reflected, for example if the referenced table is in a 

6553 different schema or is omitted via the 

6554 :paramref:`.MetaData.reflect.only` parameter. When False, 

6555 :class:`_schema.ForeignKey` objects are not followed to the 

6556 :class:`_schema.Table` 

6557 in which they link, however if the related table is also part of the 

6558 list of tables that would be reflected in any case, the 

6559 :class:`_schema.ForeignKey` object will still resolve to its related 

6560 :class:`_schema.Table` after the :meth:`_schema.MetaData.reflect` 

6561 operation is 

6562 complete. Defaults to True. 

6563 

6564 .. seealso:: 

6565 

6566 :paramref:`_schema.Table.resolve_fks` 

6567 

6568 :param \**dialect_kwargs: Additional keyword arguments not mentioned 

6569 above are dialect specific, and passed in the form 

6570 ``<dialectname>_<argname>``. See the documentation regarding an 

6571 individual dialect at :ref:`dialect_toplevel` for detail on 

6572 documented arguments. 

6573 

6574 .. seealso:: 

6575 

6576 :ref:`metadata_reflection_toplevel` 

6577 

6578 :meth:`_events.DDLEvents.column_reflect` - Event used to customize 

6579 the reflected columns. Usually used to generalize the types using 

6580 :meth:`_types.TypeEngine.as_generic` 

6581 

6582 :ref:`metadata_reflection_dbagnostic_types` - describes how to 

6583 reflect tables using general types. 

6584 

6585 """ 

6586 

6587 with inspection.inspect(bind)._inspection_context() as insp: 

6588 reflect_opts: Any = { 

6589 "autoload_with": insp, 

6590 "extend_existing": extend_existing, 

6591 "autoload_replace": autoload_replace, 

6592 "resolve_fks": resolve_fks, 

6593 "_extend_on": set(), 

6594 } 

6595 

6596 reflect_opts.update(dialect_kwargs) 

6597 

6598 if schema is None: 

6599 schema = self.schema 

6600 

6601 if schema is not None: 

6602 reflect_opts["schema"] = schema 

6603 

6604 kind = util.preloaded.engine_reflection.ObjectKind.TABLE 

6605 available: util.OrderedSet[str] = util.OrderedSet( 

6606 insp.get_table_names(schema, **dialect_kwargs) 

6607 ) 

6608 if views: 

6609 kind = util.preloaded.engine_reflection.ObjectKind.ANY 

6610 available.update(insp.get_view_names(schema, **dialect_kwargs)) 

6611 try: 

6612 available.update( 

6613 insp.get_materialized_view_names( 

6614 schema, **dialect_kwargs 

6615 ) 

6616 ) 

6617 except NotImplementedError: 

6618 pass 

6619 

6620 if schema is not None: 

6621 available_w_schema: util.OrderedSet[str] = util.OrderedSet( 

6622 [f"{schema}.{name}" for name in available] 

6623 ) 

6624 else: 

6625 available_w_schema = available 

6626 

6627 current = set(self.tables) 

6628 

6629 if only is None: 

6630 load = [ 

6631 name 

6632 for name, schname in zip(available, available_w_schema) 

6633 if extend_existing or schname not in current 

6634 ] 

6635 elif callable(only): 

6636 load = [ 

6637 name 

6638 for name, schname in zip(available, available_w_schema) 

6639 if (extend_existing or schname not in current) 

6640 and only(name, self) 

6641 ] 

6642 else: 

6643 missing = [name for name in only if name not in available] 

6644 if missing: 

6645 s = schema and (" schema '%s'" % schema) or "" 

6646 missing_str = ", ".join(missing) 

6647 raise exc.InvalidRequestError( 

6648 f"Could not reflect: requested table(s) not available " 

6649 f"in {bind.engine!r}{s}: ({missing_str})" 

6650 ) 

6651 load = [ 

6652 name 

6653 for name in only 

6654 if extend_existing or name not in current 

6655 ] 

6656 # pass the available tables so the inspector can 

6657 # choose to ignore the filter_names 

6658 _reflect_info = insp._get_reflection_info( 

6659 schema=schema, 

6660 filter_names=load, 

6661 available=available, 

6662 kind=kind, 

6663 scope=util.preloaded.engine_reflection.ObjectScope.ANY, 

6664 **dialect_kwargs, 

6665 ) 

6666 reflect_opts["_reflect_info"] = _reflect_info 

6667 

6668 for name in load: 

6669 try: 

6670 Table(name, self, **reflect_opts) 

6671 except exc.UnreflectableTableError as uerr: 

6672 util.warn(f"Skipping table {name}: {uerr}") 

6673 

6674 def create_all( 

6675 self, 

6676 bind: _CreateDropBind, 

6677 tables: Optional[_typing_Sequence[Table]] = None, 

6678 checkfirst: Union[bool, CheckFirst] = CheckFirst.ALL, 

6679 ) -> None: 

6680 """Create all tables stored in this metadata. 

6681 

6682 Conditional by default, will not attempt to recreate tables already 

6683 present in the target database. 

6684 

6685 :param bind: 

6686 A :class:`.Connection` or :class:`.Engine` used to access the 

6687 database. 

6688 

6689 :param tables: 

6690 Optional list of ``Table`` objects, which is a subset of the total 

6691 tables in the ``MetaData`` (others are ignored). 

6692 

6693 :param checkfirst: A boolean value or instance of :class:`.CheckFirst`. 

6694 Indicates which objects should be checked for within a separate pass 

6695 before creating schema objects. 

6696 

6697 """ 

6698 bind._run_ddl_visitor( 

6699 ddl.SchemaGenerator, self, checkfirst=checkfirst, tables=tables 

6700 ) 

6701 

6702 def drop_all( 

6703 self, 

6704 bind: _CreateDropBind, 

6705 tables: Optional[_typing_Sequence[Table]] = None, 

6706 checkfirst: Union[bool, CheckFirst] = CheckFirst.ALL, 

6707 ) -> None: 

6708 """Drop all tables stored in this metadata. 

6709 

6710 Conditional by default, will not attempt to drop tables not present in 

6711 the target database. 

6712 

6713 :param bind: 

6714 A :class:`.Connection` or :class:`.Engine` used to access the 

6715 database. 

6716 

6717 :param tables: 

6718 Optional list of ``Table`` objects, which is a subset of the 

6719 total tables in the ``MetaData`` (others are ignored). 

6720 

6721 :param checkfirst: A boolean value or instance of :class:`.CheckFirst`. 

6722 Indicates which objects should be checked for within a separate pass 

6723 before dropping schema objects. 

6724 

6725 """ 

6726 bind._run_ddl_visitor( 

6727 ddl.SchemaDropper, self, checkfirst=checkfirst, tables=tables 

6728 ) 

6729 

6730 @property 

6731 def schemas(self) -> _typing_Sequence[str]: 

6732 """A sequence of schema names that are present in this MetaData.""" 

6733 schemas = self._schemas 

6734 if self.schema: 

6735 schemas = schemas | {self.schema} 

6736 return tuple(schemas) 

6737 

6738 def get_schema_objects( 

6739 self, 

6740 kind: Type[_T], 

6741 *, 

6742 schema: Union[str, None, Literal[_NoArg.NO_ARG]] = _NoArg.NO_ARG, 

6743 ) -> _typing_Sequence[_T]: 

6744 """Return a sequence of schema objects of the given kind. 

6745 

6746 This method can be used to return :class:`_sqltypes.Enum`, 

6747 :class:`.Sequence`, etc. objects registered in this 

6748 :class:`_schema.MetaData`. 

6749 

6750 :param kind: a type that indicates what object to return, such as 

6751 :class:`Enum` or :class:`Sequence`. 

6752 :param schema: Optional, a schema name to filter the objects by. If 

6753 not provided the default schema of the metadata is used. 

6754 

6755 """ 

6756 

6757 if schema is _NoArg.NO_ARG: 

6758 schema = self.schema 

6759 return tuple( 

6760 obj 

6761 for obj in self._objects 

6762 if isinstance(obj, kind) and obj.schema == schema 

6763 ) 

6764 

6765 def get_schema_object_by_name( 

6766 self, 

6767 kind: Type[_T], 

6768 name: str, 

6769 *, 

6770 schema: Union[str, None, Literal[_NoArg.NO_ARG]] = _NoArg.NO_ARG, 

6771 ) -> Optional[_T]: 

6772 """Return a schema objects of the given kind and name if found. 

6773 

6774 This method can be used to return :class:`_sqltypes.Enum`, 

6775 :class:`.Sequence`, etc. objects registered in this 

6776 :class:`_schema.MetaData`. 

6777 

6778 :param kind: a type that indicates what object to return, such as 

6779 :class:`Enum` or :class:`Sequence`. 

6780 :param name: the name of the object to return. 

6781 :param schema: Optional, a schema name to filter the objects by. If 

6782 not provided the default schema of the metadata is used. 

6783 

6784 """ 

6785 

6786 for obj in self.get_schema_objects(kind, schema=schema): 

6787 if getattr(obj, "name", None) == name: 

6788 return obj 

6789 return None 

6790 

6791 def _register_object(self, obj: Union[HasSchemaAttr, SchemaType]) -> None: 

6792 self._objects.add(obj) 

6793 

6794 

6795class Computed(FetchedValue, SchemaItem): 

6796 """Defines a generated column, i.e. "GENERATED ALWAYS AS" syntax. 

6797 

6798 The :class:`.Computed` construct is an inline construct added to the 

6799 argument list of a :class:`_schema.Column` object:: 

6800 

6801 from sqlalchemy import Computed 

6802 

6803 Table( 

6804 "square", 

6805 metadata_obj, 

6806 Column("side", Float, nullable=False), 

6807 Column("area", Float, Computed("side * side")), 

6808 ) 

6809 

6810 See the linked documentation below for complete details. 

6811 

6812 .. seealso:: 

6813 

6814 :ref:`computed_ddl` 

6815 

6816 """ 

6817 

6818 __visit_name__ = "computed_column" 

6819 

6820 column: Optional[Column[Any]] 

6821 

6822 @_document_text_coercion( 

6823 "sqltext", ":class:`.Computed`", ":paramref:`.Computed.sqltext`" 

6824 ) 

6825 def __init__( 

6826 self, sqltext: _DDLColumnArgument, persisted: Optional[bool] = None 

6827 ) -> None: 

6828 """Construct a GENERATED ALWAYS AS DDL construct to accompany a 

6829 :class:`_schema.Column`. 

6830 

6831 :param sqltext: 

6832 A string containing the column generation expression, which will be 

6833 used verbatim, or a SQL expression construct, such as a 

6834 :func:`_expression.text` 

6835 object. If given as a string, the object is converted to a 

6836 :func:`_expression.text` object. 

6837 

6838 :param persisted: 

6839 Optional, controls how this column should be persisted by the 

6840 database. Possible values are: 

6841 

6842 * ``None``, the default, it will use the default persistence 

6843 defined by the database. 

6844 * ``True``, will render ``GENERATED ALWAYS AS ... STORED``, or the 

6845 equivalent for the target database if supported. 

6846 * ``False``, will render ``GENERATED ALWAYS AS ... VIRTUAL``, or 

6847 the equivalent for the target database if supported. 

6848 

6849 Specifying ``True`` or ``False`` may raise an error when the DDL 

6850 is emitted to the target database if the database does not support 

6851 that persistence option. Leaving this parameter at its default 

6852 of ``None`` is guaranteed to succeed for all databases that support 

6853 ``GENERATED ALWAYS AS``. 

6854 

6855 """ 

6856 self.sqltext = coercions.expect(roles.DDLExpressionRole, sqltext) 

6857 self.persisted = persisted 

6858 self.column = None 

6859 

6860 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

6861 assert isinstance(parent, Column) 

6862 

6863 if not isinstance( 

6864 parent.server_default, (type(None), Computed) 

6865 ) or not isinstance(parent.server_onupdate, (type(None), Computed)): 

6866 raise exc.ArgumentError( 

6867 "A generated column cannot specify a server_default or a " 

6868 "server_onupdate argument" 

6869 ) 

6870 self.column = parent 

6871 parent.computed = self 

6872 self.column.server_onupdate = self 

6873 self.column.server_default = self 

6874 

6875 def _as_for_update(self, for_update: bool) -> FetchedValue: 

6876 return self 

6877 

6878 @util.deprecated( 

6879 "1.4", 

6880 "The :meth:`_schema.Computed.copy` method is deprecated " 

6881 "and will be removed in a future release.", 

6882 ) 

6883 def copy( 

6884 self, *, target_table: Optional[Table] = None, **kw: Any 

6885 ) -> Computed: 

6886 return self._copy(target_table=target_table, **kw) 

6887 

6888 def _copy( 

6889 self, *, target_table: Optional[Table] = None, **kw: Any 

6890 ) -> Computed: 

6891 sqltext = _copy_expression( 

6892 self.sqltext, 

6893 self.column.table if self.column is not None else None, 

6894 target_table, 

6895 ) 

6896 g = Computed(sqltext, persisted=self.persisted) 

6897 

6898 return self._schema_item_copy(g) 

6899 

6900 

6901class Identity(IdentityOptions, FetchedValue, SchemaItem): 

6902 """Defines an identity column, i.e. "GENERATED { ALWAYS | BY DEFAULT } 

6903 AS IDENTITY" syntax. 

6904 

6905 The :class:`.Identity` construct is an inline construct added to the 

6906 argument list of a :class:`_schema.Column` object:: 

6907 

6908 from sqlalchemy import Identity 

6909 

6910 Table( 

6911 "foo", 

6912 metadata_obj, 

6913 Column("id", Integer, Identity()), 

6914 Column("description", Text), 

6915 ) 

6916 

6917 See the linked documentation below for complete details. 

6918 

6919 .. versionadded:: 1.4 

6920 

6921 .. seealso:: 

6922 

6923 :ref:`identity_ddl` 

6924 

6925 """ 

6926 

6927 __visit_name__ = "identity_column" 

6928 

6929 is_identity = True 

6930 

6931 @util.deprecated_params( 

6932 order=( 

6933 "2.1", 

6934 "This parameter is supported only by Oracle Database, " 

6935 "use ``oracle_order`` instead.", 

6936 ), 

6937 on_null=( 

6938 "2.1", 

6939 "This parameter is supported only by Oracle Database, " 

6940 "use ``oracle_on_null`` instead.", 

6941 ), 

6942 ) 

6943 def __init__( 

6944 self, 

6945 always: Optional[bool] = False, 

6946 on_null: Optional[bool] = None, 

6947 start: Optional[int] = None, 

6948 increment: Optional[int] = None, 

6949 minvalue: Optional[int] = None, 

6950 maxvalue: Optional[int] = None, 

6951 nominvalue: Optional[bool] = None, 

6952 nomaxvalue: Optional[bool] = None, 

6953 cycle: Optional[bool] = None, 

6954 cache: Optional[int] = None, 

6955 order: Optional[bool] = None, 

6956 **dialect_kw: Any, 

6957 ) -> None: 

6958 """Construct a GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY DDL 

6959 construct to accompany a :class:`_schema.Column`. 

6960 

6961 See the :class:`.Sequence` documentation for a complete description 

6962 of most parameters. 

6963 

6964 .. note:: 

6965 MSSQL supports this construct as the preferred alternative to 

6966 generate an IDENTITY on a column, but it uses non standard 

6967 syntax that only support :paramref:`_schema.Identity.start` 

6968 and :paramref:`_schema.Identity.increment`. 

6969 All other parameters are ignored. 

6970 

6971 :param always: 

6972 A boolean, that indicates the type of identity column. 

6973 If ``False`` is specified, the default, then the user-specified 

6974 value takes precedence. 

6975 If ``True`` is specified, a user-specified value is not accepted ( 

6976 on some backends, like PostgreSQL, OVERRIDING SYSTEM VALUE, or 

6977 similar, may be specified in an INSERT to override the sequence 

6978 value). 

6979 Some backends also have a default value for this parameter, 

6980 ``None`` can be used to omit rendering this part in the DDL. It 

6981 will be treated as ``False`` if a backend does not have a default 

6982 value. 

6983 

6984 :param on_null: 

6985 Set to ``True`` to specify ON NULL in conjunction with a 

6986 ``always=False`` identity column. This option is only supported on 

6987 some backends, like Oracle Database. 

6988 

6989 :param start: the starting index of the sequence. 

6990 :param increment: the increment value of the sequence. 

6991 :param minvalue: the minimum value of the sequence. 

6992 :param maxvalue: the maximum value of the sequence. 

6993 :param nominvalue: no minimum value of the sequence. 

6994 :param nomaxvalue: no maximum value of the sequence. 

6995 :param cycle: allows the sequence to wrap around when the maxvalue 

6996 or minvalue has been reached. 

6997 :param cache: optional integer value; number of future values in the 

6998 sequence which are calculated in advance. 

6999 :param order: optional boolean value; if true, renders the 

7000 ORDER keyword. 

7001 

7002 """ 

7003 self.dialect_options 

7004 if on_null is not None: 

7005 if "oracle_on_null" in dialect_kw: 

7006 raise exc.ArgumentError( 

7007 "Cannot specify both 'on_null' and 'oracle_on_null'. " 

7008 "Please use only 'oracle_on_null'." 

7009 ) 

7010 dialect_kw["oracle_on_null"] = on_null 

7011 

7012 IdentityOptions.__init__( 

7013 self, 

7014 start=start, 

7015 increment=increment, 

7016 minvalue=minvalue, 

7017 maxvalue=maxvalue, 

7018 nominvalue=nominvalue, 

7019 nomaxvalue=nomaxvalue, 

7020 cycle=cycle, 

7021 cache=cache, 

7022 order=order, 

7023 **dialect_kw, 

7024 ) 

7025 self.always = always 

7026 self.column = None 

7027 

7028 @property 

7029 def on_null(self) -> Optional[bool]: 

7030 """Alias of the ``dialect_kwargs`` ``'oracle_on_null'``. 

7031 

7032 .. deprecated:: 2.1 The 'on_null' attribute is deprecated. 

7033 """ 

7034 value: Optional[bool] = self.dialect_kwargs.get("oracle_on_null") 

7035 return value 

7036 

7037 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

7038 assert isinstance(parent, Column) 

7039 if not isinstance( 

7040 parent.server_default, (type(None), Identity) 

7041 ) or not isinstance(parent.server_onupdate, type(None)): 

7042 raise exc.ArgumentError( 

7043 "A column with an Identity object cannot specify a " 

7044 "server_default or a server_onupdate argument" 

7045 ) 

7046 if parent.autoincrement is False: 

7047 raise exc.ArgumentError( 

7048 "A column with an Identity object cannot specify " 

7049 "autoincrement=False" 

7050 ) 

7051 self.column = parent 

7052 

7053 parent.identity = self 

7054 if parent._user_defined_nullable is NULL_UNSPECIFIED: 

7055 parent.nullable = False 

7056 

7057 parent.server_default = self 

7058 

7059 def _as_for_update(self, for_update: bool) -> FetchedValue: 

7060 return self 

7061 

7062 @util.deprecated( 

7063 "1.4", 

7064 "The :meth:`_schema.Identity.copy` method is deprecated " 

7065 "and will be removed in a future release.", 

7066 ) 

7067 def copy(self, **kw: Any) -> Identity: 

7068 return self._copy(**kw) 

7069 

7070 def _copy(self, **kw: Any) -> Identity: 

7071 i = Identity(**self._as_dict(), **self.dialect_kwargs) 

7072 

7073 return self._schema_item_copy(i) 

7074 

7075 def _as_dict(self) -> Dict[str, Any]: 

7076 return { 

7077 # always=None means something different than always=False 

7078 "always": self.always, 

7079 **super()._as_dict(), 

7080 }