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

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

1847 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 _CovariantTypeEngineArgument 

108 from ._typing import _CreateDropBind 

109 from ._typing import _DDLColumnArgument 

110 from ._typing import _DDLColumnReferenceArgument 

111 from ._typing import _InfoType 

112 from ._typing import _TextCoercedExpressionArgument 

113 from ._typing import _TypeEngineArgument 

114 from .base import ColumnSet 

115 from .base import ReadOnlyColumnCollection 

116 from .compiler import DDLCompiler 

117 from .ddl import TableCreateDDL 

118 from .ddl import TableDropDDL 

119 from .elements import BindParameter 

120 from .elements import KeyedColumnElement 

121 from .functions import Function 

122 from .sqltypes import SchemaType 

123 from .type_api import TypeEngine 

124 from .visitors import anon_map 

125 from ..engine import Connection 

126 from ..engine import Engine 

127 from ..engine.interfaces import _CoreMultiExecuteParams 

128 from ..engine.interfaces import CoreExecuteOptionsParameter 

129 from ..engine.interfaces import ExecutionContext 

130 from ..engine.reflection import _ReflectionInfo 

131 from ..sql.selectable import FromClause 

132 

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

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

135 

136 

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

138 

139_ServerDefaultArgument = Union[ 

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

141] 

142 

143_ServerOnUpdateArgument = _ServerDefaultArgument 

144 

145 

146class SchemaConst(Enum): 

147 RETAIN_SCHEMA = 1 

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

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

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

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

152 

153 """ 

154 

155 BLANK_SCHEMA = 2 

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

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

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

159 

160 .. seealso:: 

161 

162 :paramref:`_schema.MetaData.schema` 

163 

164 :paramref:`_schema.Table.schema` 

165 

166 :paramref:`.Sequence.schema` 

167 

168 """ 

169 

170 NULL_UNSPECIFIED = 3 

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

172 

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

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

175 on some backends such as SQL Server. 

176 

177 """ 

178 

179 

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

181 SchemaConst.RETAIN_SCHEMA 

182) 

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

184 SchemaConst.BLANK_SCHEMA 

185) 

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

187 SchemaConst.NULL_UNSPECIFIED 

188) 

189 

190 

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

192 if schema is None: 

193 return name 

194 else: 

195 return schema + "." + name 

196 

197 

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

199# break an import cycle 

200def _copy_expression( 

201 expression: ColumnElement[Any], 

202 source_table: Optional[Table], 

203 target_table: Optional[Table], 

204) -> ColumnElement[Any]: 

205 if source_table is None or target_table is None: 

206 return expression 

207 

208 fixed_source_table = source_table 

209 fixed_target_table = target_table 

210 

211 def replace( 

212 element: ExternallyTraversible, **kw: Any 

213 ) -> Optional[ExternallyTraversible]: 

214 if ( 

215 isinstance(element, Column) 

216 and element.table is fixed_source_table 

217 and element.key in fixed_source_table.c 

218 ): 

219 return fixed_target_table.c[element.key] 

220 else: 

221 return None 

222 

223 return cast( 

224 ColumnElement[Any], 

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

226 ) 

227 

228 

229@inspection._self_inspects 

230class SchemaItem(SchemaVisitable): 

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

232 

233 __visit_name__ = "schema_item" 

234 

235 create_drop_stringify_dialect = "default" 

236 

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

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

239 for item in args: 

240 if item is not None: 

241 try: 

242 spwd = item._set_parent_with_dispatch 

243 except AttributeError as err: 

244 raise exc.ArgumentError( 

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

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

247 ) from err 

248 else: 

249 spwd(self, **kw) 

250 

251 def __repr__(self) -> str: 

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

253 

254 @util.memoized_property 

255 def info(self) -> _InfoType: 

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

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

258 

259 The dictionary is automatically generated when first accessed. 

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

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

262 

263 """ 

264 return {} 

265 

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

267 if "info" in self.__dict__: 

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

269 if isinstance(self, DialectKWArgs): 

270 assert isinstance(schema_item, DialectKWArgs) 

271 self._copy_reflect_only_elements(schema_item) 

272 schema_item.dispatch._update(self.dispatch) 

273 return schema_item 

274 

275 _use_schema_map = True 

276 

277 

278class HasConditionalDDL: 

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

280 method, allowing for conditional rendering of DDL. 

281 

282 Currently applies to constraints and indexes. 

283 

284 .. versionadded:: 2.0 

285 

286 

287 """ 

288 

289 _ddl_if: Optional[ddl.DDLIf] = None 

290 

291 def ddl_if( 

292 self, 

293 dialect: Optional[str] = None, 

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

295 state: Optional[Any] = None, 

296 ) -> Self: 

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

298 

299 These rules work in a similar manner to the 

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

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

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

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

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

305 constructs. 

306 

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

308 to indicate multiple dialect types. 

309 

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

311 as that described in 

312 :paramref:`.ExecutableDDLElement.execute_if.callable_`. 

313 

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

315 callable, if present. 

316 

317 .. versionadded:: 2.0 

318 

319 .. seealso:: 

320 

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

322 

323 

324 """ 

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

326 return self 

327 

328 

329class HasSchemaAttr(SchemaItem): 

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

331 

332 schema: Optional[str] 

333 

334 

335class Table( 

336 DialectKWArgs, 

337 HasSchemaAttr, 

338 TableClause[_ColCC_co], 

339 inspection.Inspectable["Table"], 

340): 

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

342 

343 e.g.:: 

344 

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

346 

347 metadata = MetaData() 

348 

349 mytable = Table( 

350 "mytable", 

351 metadata, 

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

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

354 ) 

355 

356 The :class:`_schema.Table` 

357 object constructs a unique instance of itself based 

358 on its name and optional schema name within the given 

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

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

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

362 object - in this way 

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

364 

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

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

367 

368 from sqlalchemy import TypedColumns, select 

369 

370 

371 class user_cols(TypedColumns): 

372 id = Column(Integer, primary_key=True) 

373 name: Column[str] 

374 age: Column[int] 

375 middle_name: Column[str | None] 

376 

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

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

379 

380 

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

382 

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

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

385 

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

387 stmt1 = user.select() 

388 stmt2 = sa.select(user) 

389 

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

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

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

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

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

395 

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

397 the :meth:`Table.with_cols`:: 

398 

399 class mytable_cols(TypedColumns): 

400 mytable_id: Column[int] 

401 value: Column[str | None] 

402 

403 

404 typed_mytable = mytable.with_cols(mytable_cols) 

405 

406 .. seealso:: 

407 

408 :ref:`metadata_describing` Introduction to database metadata 

409 

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

411 definition 

412 

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

414 support "typed tables" 

415 """ 

416 

417 __visit_name__ = "table" 

418 

419 if TYPE_CHECKING: 

420 

421 @util.ro_non_memoized_property 

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

423 

424 @util.ro_non_memoized_property 

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

426 

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

428 

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

430 

431 _sentinel_column: Optional[Column[Any]] 

432 

433 constraints: Set[Constraint] 

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

435 this :class:`_schema.Table`. 

436 

437 Includes :class:`_schema.PrimaryKeyConstraint`, 

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

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

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

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

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

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

444 :class:`_schema.Table`. 

445 

446 .. seealso:: 

447 

448 :attr:`_schema.Table.constraints` 

449 

450 :attr:`_schema.Table.primary_key` 

451 

452 :attr:`_schema.Table.foreign_key_constraints` 

453 

454 :attr:`_schema.Table.indexes` 

455 

456 :class:`_reflection.Inspector` 

457 

458 

459 """ 

460 

461 indexes: Set[Index] 

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

463 :class:`_schema.Table`. 

464 

465 .. seealso:: 

466 

467 :meth:`_reflection.Inspector.get_indexes` 

468 

469 """ 

470 

471 def _gen_cache_key( 

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

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

474 if self._annotations: 

475 return (self,) + self._annotations_cache_key 

476 else: 

477 return (self,) 

478 

479 if not typing.TYPE_CHECKING: 

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

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

482 # __new__. apply typing to the __init__ method normally 

483 @util.deprecated_params( 

484 mustexist=( 

485 "1.4", 

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

487 ), 

488 ) 

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

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

491 

492 @classmethod 

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

494 if not args and not kw: 

495 # python3k pickle seems to call this 

496 return object.__new__(cls) 

497 

498 try: 

499 name, metadata, *other_args = args 

500 except ValueError: 

501 raise TypeError( 

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

503 "arguments 'name', and 'metadata'" 

504 ) from None 

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

506 typed_columns_cls = other_args[0] 

507 if not issubclass(typed_columns_cls, TypedColumns): 

508 raise exc.InvalidRequestError( 

509 "The ``typed_columns_cls`` argument requires a " 

510 "TypedColumns subclass." 

511 ) 

512 elif hasattr(typed_columns_cls, "_sa_class_manager"): 

513 # an orm class subclassed with TypedColumns. Reject it 

514 raise exc.InvalidRequestError( 

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

516 "`as_typed_table()` function instead." 

517 ) 

518 

519 extracted_columns = _extract_columns_from_class(typed_columns_cls) 

520 other_args = extracted_columns + other_args[1:] 

521 elif "typed_columns_cls" in kw: 

522 raise TypeError( 

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

524 "only positionally" 

525 ) 

526 

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

528 if schema is None: 

529 schema = metadata.schema 

530 elif schema is BLANK_SCHEMA: 

531 schema = None 

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

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

534 

535 if keep_existing and extend_existing: 

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

537 raise exc.ArgumentError(msg) 

538 

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

540 key = _get_table_key(name, schema) 

541 if key in metadata.tables: 

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

543 raise exc.InvalidRequestError( 

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

545 "instance. Specify 'extend_existing=True' " 

546 "to redefine " 

547 "options and columns on an " 

548 "existing Table object." 

549 ) 

550 table = metadata.tables[key] 

551 if extend_existing: 

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

553 return table 

554 else: 

555 if must_exist: 

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

557 table = object.__new__(cls) 

558 table.dispatch.before_parent_attach(table, metadata) 

559 metadata._add_table(name, schema, table) 

560 try: 

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

562 table.dispatch.after_parent_attach(table, metadata) 

563 return table 

564 except Exception: 

565 with util.safe_reraise(): 

566 metadata._remove_table(name, schema) 

567 

568 @overload 

569 def __init__( 

570 self: Table[_TC_co], 

571 name: str, 

572 metadata: MetaData, 

573 typed_columns_cls: type[_TC_co], 

574 /, 

575 *args: SchemaItem, 

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

577 quote: bool | None = None, 

578 quote_schema: bool | None = None, 

579 keep_existing: bool = False, 

580 extend_existing: bool = False, 

581 implicit_returning: bool = True, 

582 comment: str | None = None, 

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

584 listeners: ( 

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

586 ) = None, 

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

588 **kw: Any, 

589 ) -> None: ... 

590 

591 @overload 

592 def __init__( 

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

594 name: str, 

595 metadata: MetaData, 

596 /, 

597 *args: SchemaItem, 

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

599 quote: bool | None = None, 

600 quote_schema: Optional[bool] = None, 

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

602 autoload_replace: bool = True, 

603 keep_existing: bool = False, 

604 extend_existing: bool = False, 

605 resolve_fks: bool = True, 

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

607 implicit_returning: bool = True, 

608 comment: str | None = None, 

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

610 listeners: ( 

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

612 ) = None, 

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

614 _creator_ddl: TableCreateDDL | None = None, 

615 _dropper_ddl: TableDropDDL | None = None, 

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

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

618 # used by __new__ to bypass __init__ 

619 _no_init: bool = True, 

620 # dialect-specific keyword args 

621 **kw: Any, 

622 ) -> None: ... 

623 

624 def __init__( 

625 self, 

626 name: str, 

627 metadata: MetaData, 

628 /, 

629 *args: Any, 

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

631 quote: bool | None = None, 

632 quote_schema: Optional[bool] = None, 

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

634 autoload_replace: bool = True, 

635 keep_existing: bool = False, 

636 extend_existing: bool = False, 

637 resolve_fks: bool = True, 

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

639 implicit_returning: bool = True, 

640 comment: str | None = None, 

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

642 listeners: ( 

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

644 ) = None, 

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

646 _creator_ddl: TableCreateDDL | None = None, 

647 _dropper_ddl: TableDropDDL | None = None, 

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

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

650 # used by __new__ to bypass __init__ 

651 _no_init: bool = True, 

652 # dialect-specific keyword args 

653 **kw: Any, 

654 ) -> None: 

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

656 

657 

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

659 

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

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

662 within 

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

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

665 metadata, 

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

667 

668 Names which contain no upper case characters 

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

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

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

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

673 

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

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

676 construct to specify the name. 

677 

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

679 object which will contain this 

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

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

682 may be used to associate this table with a particular 

683 :class:`.Connection` or :class:`.Engine`. 

684 

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

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

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

688 

689 .. versionadded:: 2.1.0b2 

690 

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

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

693 objects contained within this 

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

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

696 :class:`.PrimaryKeyConstraint`, and 

697 :class:`_schema.ForeignKeyConstraint`. 

698 Additional columns may be provided also when using a 

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

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

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

702 

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

704 :paramref:`_schema.Table.autoload_with` 

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

706 indicates 

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

708 :class:`_schema.Table` 

709 object should be replaced with columns of the same 

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

711 already present under existing names will be omitted from the 

712 reflection process. 

713 

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

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

716 that 

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

718 replace existing columns of the same name when 

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

720 

721 .. seealso:: 

722 

723 :paramref:`_schema.Table.autoload_with` 

724 

725 :paramref:`_schema.Table.extend_existing` 

726 

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

728 :class:`_engine.Connection` object, 

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

730 :func:`_sa.inspect` 

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

732 object will be reflected. 

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

734 for this table against the given engine or connection. 

735 

736 .. seealso:: 

737 

738 :ref:`metadata_reflection_toplevel` 

739 

740 :meth:`_events.DDLEvents.column_reflect` 

741 

742 :ref:`metadata_reflection_dbagnostic_types` 

743 

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

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

746 :class:`_schema.MetaData`, 

747 apply further arguments within the constructor to the existing 

748 :class:`_schema.Table`. 

749 

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

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

752 and the given name 

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

754 that is 

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

756 and 

757 this :class:`_schema.Table` 

758 specifies additional columns or other constructs 

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

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

761 is to specify what action should be taken when a 

762 :class:`_schema.Table` 

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

764 yet specifies 

765 additional constructs. 

766 

767 :paramref:`_schema.Table.extend_existing` 

768 will also work in conjunction 

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

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

771 of the same name is already present in the target 

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

773 objects 

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

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

776 and options of the same name. 

777 

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

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

780 :class:`_schema.Table` 

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

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

783 objects 

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

785 :class:`_schema.Column` 

786 named "y":: 

787 

788 Table( 

789 "mytable", 

790 metadata, 

791 Column("y", Integer), 

792 extend_existing=True, 

793 autoload_with=engine, 

794 ) 

795 

796 .. seealso:: 

797 

798 :paramref:`_schema.Table.autoload_with` 

799 

800 :paramref:`_schema.Table.autoload_replace` 

801 

802 :paramref:`_schema.Table.keep_existing` 

803 

804 

805 :param implicit_returning: True by default - indicates that 

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

807 server-generated values such as primary key values and 

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

809 

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

811 setting, except for some backend specific cases 

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

813 for one such example). 

814 

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

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

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

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

819 should be reflected. 

820 

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

822 objects 

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

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

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

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

827 objects are encountered; may be 

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

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

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

831 a 

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

833 :class:`_schema.Table` will 

834 resolve to that table normally. 

835 

836 .. seealso:: 

837 

838 :paramref:`.MetaData.reflect.resolve_fks` 

839 

840 

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

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

843 

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

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

846 further arguments within the constructor to the existing 

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

848 object as 

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

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

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

852 without any of the declarations (particularly constraints) 

853 being applied a second time. 

854 

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

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

857 and the given name 

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

859 that is 

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

861 and 

862 this :class:`_schema.Table` 

863 specifies additional columns or other constructs 

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

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

866 is to specify what action should be taken when a 

867 :class:`_schema.Table` 

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

869 yet specifies 

870 additional constructs. 

871 

872 .. seealso:: 

873 

874 :paramref:`_schema.Table.extend_existing` 

875 

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

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

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

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

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

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

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

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

884 

885 def listen_for_reflect(table, column_info): 

886 "handle the column reflection event" 

887 # ... 

888 

889 

890 t = Table( 

891 "sometable", 

892 autoload_with=engine, 

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

894 ) 

895 

896 .. seealso:: 

897 

898 :meth:`_events.DDLEvents.column_reflect` 

899 

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

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

902 an exception is raised. 

903 

904 :param prefixes: 

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

906 statement. They will be separated by spaces. 

907 

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

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

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

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

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

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

914 by the SQLAlchemy dialect. 

915 

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

917 case-insensitive behavior for table reflection; table reflection 

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

919 fashion. Case insensitive names are specified in SQLAlchemy only 

920 by stating the name with all lower case characters. 

921 

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

923 

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

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

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

927 

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

929 specifies its 

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

931 then that schema name will 

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

933 if the schema parameter here is set 

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

935 that 

936 would otherwise use the schema set on the owning 

937 :class:`_schema.MetaData`, 

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

939 

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

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

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

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

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

945 

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

947 creation. 

948 

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

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

951 See the documentation regarding an individual dialect at 

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

953 

954 """ # noqa: E501 

955 if _no_init: 

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

957 # __new__ has a specific place that __init__ is called 

958 return 

959 if args: 

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

961 # TypedColumns to the individual columns 

962 assert not ( 

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

964 ) 

965 

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

967 self.metadata = metadata 

968 

969 if schema is None: 

970 self.schema = metadata.schema 

971 elif schema is BLANK_SCHEMA: 

972 self.schema = None 

973 else: 

974 quote_schema = quote_schema 

975 assert isinstance(schema, str) 

976 self.schema = quoted_name(schema, quote_schema) 

977 

978 self._sentinel_column = None 

979 self._creator_ddl = _creator_ddl 

980 self._dropper_ddl = _dropper_ddl 

981 

982 self.indexes = set() 

983 self.constraints = set() 

984 PrimaryKeyConstraint( 

985 _implicit_generated=True 

986 )._set_parent_with_dispatch(self) 

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

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

989 if self.schema is not None: 

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

991 else: 

992 self.fullname = self.name 

993 

994 self.implicit_returning = implicit_returning 

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

996 

997 self.comment = comment 

998 

999 if info is not None: 

1000 self.info = info 

1001 

1002 if listeners is not None: 

1003 for evt, fn in listeners: 

1004 event.listen(self, evt, fn) 

1005 

1006 self._prefixes = prefixes if prefixes else [] 

1007 

1008 self._extra_kwargs(**kw) 

1009 

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

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

1012 # circular foreign keys 

1013 if autoload_with is not None: 

1014 self._autoload( 

1015 metadata, 

1016 autoload_with, 

1017 include_columns, 

1018 _extend_on=_extend_on, 

1019 _reflect_info=_reflect_info, 

1020 resolve_fks=resolve_fks, 

1021 ) 

1022 

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

1024 # allow user-overrides 

1025 

1026 self._init_items( 

1027 *args, 

1028 allow_replacements=extend_existing 

1029 or keep_existing 

1030 or autoload_with, 

1031 all_names={}, 

1032 ) 

1033 

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

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

1036 

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

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

1039 used. 

1040 

1041 E.g.:: 

1042 

1043 from sqlalchemy.schema import CreateTable 

1044 

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

1046 

1047 .. versionadded:: 2.1 

1048 

1049 .. seealso:: 

1050 

1051 :meth:`.Table.set_dropper_ddl` 

1052 

1053 """ 

1054 self._creator_ddl = ddl 

1055 

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

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

1058 

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

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

1061 used. 

1062 

1063 E.g.:: 

1064 

1065 from sqlalchemy.schema import DropTable 

1066 

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

1068 

1069 .. versionadded:: 2.1 

1070 

1071 .. seealso:: 

1072 

1073 :meth:`.Table.set_creator_ddl` 

1074 

1075 """ 

1076 self._dropper_ddl = ddl 

1077 

1078 @property 

1079 def is_view(self) -> bool: 

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

1081 CREATE VIEW rather than CREATE TABLE. 

1082 

1083 .. versionadded:: 2.1 

1084 

1085 """ 

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

1087 

1088 def _autoload( 

1089 self, 

1090 metadata: MetaData, 

1091 autoload_with: Union[Engine, Connection], 

1092 include_columns: Optional[Collection[str]], 

1093 exclude_columns: Collection[str] = (), 

1094 resolve_fks: bool = True, 

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

1096 _reflect_info: _ReflectionInfo | None = None, 

1097 ) -> None: 

1098 insp = inspection.inspect(autoload_with) 

1099 with insp._inspection_context() as conn_insp: 

1100 conn_insp.reflect_table( 

1101 self, 

1102 include_columns, 

1103 exclude_columns, 

1104 resolve_fks, 

1105 _extend_on=_extend_on, 

1106 _reflect_info=_reflect_info, 

1107 ) 

1108 

1109 @property 

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

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

1112 order. 

1113 

1114 """ 

1115 

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

1117 

1118 @property 

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

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

1121 :class:`_schema.Table`. 

1122 

1123 This list is produced from the collection of 

1124 :class:`_schema.ForeignKey` 

1125 objects currently associated. 

1126 

1127 

1128 .. seealso:: 

1129 

1130 :attr:`_schema.Table.constraints` 

1131 

1132 :attr:`_schema.Table.foreign_keys` 

1133 

1134 :attr:`_schema.Table.indexes` 

1135 

1136 """ 

1137 return { 

1138 fkc.constraint 

1139 for fkc in self.foreign_keys 

1140 if fkc.constraint is not None 

1141 } 

1142 

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

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

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

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

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

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

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

1150 

1151 # these arguments are only used with _init() 

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

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

1154 

1155 assert extend_existing 

1156 assert not keep_existing 

1157 

1158 if schema and schema != self.schema: 

1159 raise exc.ArgumentError( 

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

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

1162 ) 

1163 

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

1165 if include_columns is not None: 

1166 for c in self.c: 

1167 if c.name not in include_columns: 

1168 self._columns.remove(c) 

1169 

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

1171 

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

1173 if key in kwargs: 

1174 raise exc.ArgumentError( 

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

1176 ) 

1177 

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

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

1180 self.implicit_returning = kwargs.pop( 

1181 "implicit_returning", self.implicit_returning 

1182 ) 

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

1184 

1185 exclude_columns: _typing_Sequence[str] 

1186 

1187 if autoload: 

1188 if not autoload_replace: 

1189 # don't replace columns already present. 

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

1191 # have simple de-duping for unnamed constraints. 

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

1193 else: 

1194 exclude_columns = () 

1195 self._autoload( 

1196 self.metadata, 

1197 autoload_with, 

1198 include_columns, 

1199 exclude_columns, 

1200 resolve_fks, 

1201 _extend_on=_extend_on, 

1202 _reflect_info=_reflect_info, 

1203 ) 

1204 

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

1206 self._extra_kwargs(**kwargs) 

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

1208 

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

1210 self._validate_dialect_kwargs(kwargs) 

1211 

1212 def _init_collections(self) -> None: 

1213 pass 

1214 

1215 def _reset_exported(self) -> None: 

1216 pass 

1217 

1218 @util.ro_non_memoized_property 

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

1220 return self.primary_key._autoincrement_column 

1221 

1222 @util.ro_memoized_property 

1223 def _sentinel_column_characteristics( 

1224 self, 

1225 ) -> _SentinelColumnCharacterization: 

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

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

1228 "insert sentinel" for an INSERT statement. 

1229 

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

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

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

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

1234 dialect. 

1235 

1236 .. versionadded:: 2.0.10 

1237 

1238 """ 

1239 

1240 sentinel_is_explicit = False 

1241 sentinel_is_autoinc = False 

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

1243 

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

1245 explicit_sentinel_col = self._sentinel_column 

1246 

1247 if explicit_sentinel_col is not None: 

1248 the_sentinel = (explicit_sentinel_col,) 

1249 sentinel_is_explicit = True 

1250 

1251 autoinc_col = self._autoincrement_column 

1252 if sentinel_is_explicit and explicit_sentinel_col is autoinc_col: 

1253 assert autoinc_col is not None 

1254 sentinel_is_autoinc = True 

1255 elif explicit_sentinel_col is None and autoinc_col is not None: 

1256 the_sentinel = (autoinc_col,) 

1257 sentinel_is_autoinc = True 

1258 

1259 default_characterization = _SentinelDefaultCharacterization.UNKNOWN 

1260 

1261 if the_sentinel: 

1262 the_sentinel_zero = the_sentinel[0] 

1263 if the_sentinel_zero.identity: 

1264 if the_sentinel_zero.identity._increment_is_negative: 

1265 if sentinel_is_explicit: 

1266 raise exc.InvalidRequestError( 

1267 "Can't use IDENTITY default with negative " 

1268 "increment as an explicit sentinel column" 

1269 ) 

1270 else: 

1271 if sentinel_is_autoinc: 

1272 autoinc_col = None 

1273 sentinel_is_autoinc = False 

1274 the_sentinel = None 

1275 else: 

1276 default_characterization = ( 

1277 _SentinelDefaultCharacterization.IDENTITY 

1278 ) 

1279 elif ( 

1280 the_sentinel_zero.default is None 

1281 and the_sentinel_zero.server_default is None 

1282 ): 

1283 if the_sentinel_zero.nullable: 

1284 raise exc.InvalidRequestError( 

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

1286 "sentinel " 

1287 "column with no default generation function; it " 

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

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

1290 ) 

1291 default_characterization = ( 

1292 _SentinelDefaultCharacterization.NONE 

1293 ) 

1294 elif the_sentinel_zero.default is not None: 

1295 if the_sentinel_zero.default.is_sentinel: 

1296 default_characterization = ( 

1297 _SentinelDefaultCharacterization.SENTINEL_DEFAULT 

1298 ) 

1299 elif the_sentinel_zero.default._is_monotonic_fn: 

1300 default_characterization = ( 

1301 _SentinelDefaultCharacterization.MONOTONIC_FUNCTION 

1302 ) 

1303 elif default_is_sequence(the_sentinel_zero.default): 

1304 if the_sentinel_zero.default._increment_is_negative: 

1305 if sentinel_is_explicit: 

1306 raise exc.InvalidRequestError( 

1307 "Can't use SEQUENCE default with negative " 

1308 "increment as an explicit sentinel column" 

1309 ) 

1310 else: 

1311 if sentinel_is_autoinc: 

1312 autoinc_col = None 

1313 sentinel_is_autoinc = False 

1314 the_sentinel = None 

1315 

1316 default_characterization = ( 

1317 _SentinelDefaultCharacterization.SEQUENCE 

1318 ) 

1319 elif the_sentinel_zero.default.is_callable: 

1320 default_characterization = ( 

1321 _SentinelDefaultCharacterization.CLIENTSIDE 

1322 ) 

1323 elif the_sentinel_zero.server_default is not None: 

1324 if sentinel_is_explicit: 

1325 if not the_sentinel_zero.server_default._is_monotonic_fn: 

1326 raise exc.InvalidRequestError( 

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

1328 "column " 

1329 "because it uses an explicit server side default " 

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

1331 ) 

1332 else: 

1333 default_characterization = ( 

1334 _SentinelDefaultCharacterization.MONOTONIC_FUNCTION 

1335 ) 

1336 else: 

1337 default_characterization = ( 

1338 _SentinelDefaultCharacterization.SERVERSIDE 

1339 ) 

1340 

1341 if the_sentinel is None and self.primary_key: 

1342 assert autoinc_col is None 

1343 

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

1345 # client side 

1346 for _pkc in self.primary_key: 

1347 if ( 

1348 _pkc.server_default is not None 

1349 and not _pkc.server_default._is_monotonic_fn 

1350 ): 

1351 break 

1352 

1353 if ( 

1354 _pkc.default 

1355 and not _pkc.default.is_callable 

1356 and not _pkc.default._is_monotonic_fn 

1357 ): 

1358 break 

1359 else: 

1360 the_sentinel = tuple(self.primary_key) 

1361 default_characterization = ( 

1362 _SentinelDefaultCharacterization.CLIENTSIDE 

1363 ) 

1364 

1365 return _SentinelColumnCharacterization( 

1366 the_sentinel, 

1367 sentinel_is_explicit, 

1368 sentinel_is_autoinc, 

1369 default_characterization, 

1370 ) 

1371 

1372 @property 

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

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

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

1376 

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

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

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

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

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

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

1383 "autoincrement" column. 

1384 

1385 .. versionadded:: 2.0.4 

1386 

1387 .. seealso:: 

1388 

1389 :paramref:`.Column.autoincrement` 

1390 

1391 """ 

1392 return self._autoincrement_column 

1393 

1394 @property 

1395 def key(self) -> str: 

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

1397 

1398 This value is used as the dictionary key within the 

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

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

1401 :attr:`_schema.Table.schema` 

1402 set; otherwise it is typically of the form 

1403 ``schemaname.tablename``. 

1404 

1405 """ 

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

1407 

1408 def __repr__(self) -> str: 

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

1410 [repr(self.name)] 

1411 + [repr(self.metadata)] 

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

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

1414 ) 

1415 

1416 def __str__(self) -> str: 

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

1418 

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

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

1421 

1422 This is another Table object which must be created 

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

1424 

1425 Usually, dependencies between tables are determined via 

1426 ForeignKey objects. However, for other situations that 

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

1428 this method can manually establish such a link. 

1429 

1430 """ 

1431 self._extra_dependencies.add(table) 

1432 

1433 def _insert_col_impl( 

1434 self, 

1435 column: ColumnClause[Any], 

1436 *, 

1437 index: Optional[int] = None, 

1438 replace_existing: bool = False, 

1439 ) -> None: 

1440 try: 

1441 column._set_parent_with_dispatch( 

1442 self, 

1443 allow_replacements=replace_existing, 

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

1445 index=index, 

1446 ) 

1447 except exc.DuplicateColumnError as de: 

1448 raise exc.DuplicateColumnError( 

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

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

1451 "existing column." 

1452 ) from de 

1453 

1454 def insert_column( 

1455 self, 

1456 column: ColumnClause[Any], 

1457 index: int, 

1458 *, 

1459 replace_existing: bool = False, 

1460 ) -> None: 

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

1462 a specific position. 

1463 

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

1465 the index position can be controlled using the 

1466 :paramref:`.Table.insert_column.index` 

1467 parameter. 

1468 

1469 :param replace_existing: 

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

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

1472 

1473 .. versionadded:: 2.1 

1474 

1475 """ 

1476 self._insert_col_impl( 

1477 column, index=index, replace_existing=replace_existing 

1478 ) 

1479 

1480 def append_column( 

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

1482 ) -> None: 

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

1484 

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

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

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

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

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

1490 construct. 

1491 

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

1493 as it exists within any underlying database, assuming that 

1494 table has already been created in the database. Relational 

1495 databases support the addition of columns to existing tables 

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

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

1498 the newly added column. 

1499 

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

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

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

1503 version of sqlalchemy will instead rise a warning. 

1504 

1505 .. versionadded:: 1.4.0 

1506 

1507 .. seealso:: 

1508 

1509 :meth:`.Table.insert_column` 

1510 

1511 """ 

1512 self._insert_col_impl(column, replace_existing=replace_existing) 

1513 

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

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

1516 :class:`_schema.Table`. 

1517 

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

1519 future CREATE TABLE statement, assuming specific DDL creation 

1520 events have not been associated with the given 

1521 :class:`_schema.Constraint` object. 

1522 

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

1524 relational database automatically, for a table that already exists 

1525 in the database. To add a constraint to an 

1526 existing relational database table, the SQL ALTER command must 

1527 be used. SQLAlchemy also provides the 

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

1529 invoked as an executable clause. 

1530 

1531 """ 

1532 

1533 constraint._set_parent_with_dispatch(self) 

1534 

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

1536 metadata = parent 

1537 assert isinstance(metadata, MetaData) 

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

1539 self.metadata = metadata 

1540 

1541 def create( 

1542 self, 

1543 bind: _CreateDropBind, 

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

1545 ) -> None: 

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

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

1548 :class:`.Connection` or :class:`.Engine` 

1549 for connectivity. 

1550 

1551 .. seealso:: 

1552 

1553 :meth:`_schema.MetaData.create_all`. 

1554 

1555 """ 

1556 

1557 # the default is to only check for schema objects 

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

1559 

1560 def drop( 

1561 self, 

1562 bind: _CreateDropBind, 

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

1564 ) -> None: 

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

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

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

1568 

1569 .. seealso:: 

1570 

1571 :meth:`_schema.MetaData.drop_all`. 

1572 

1573 """ 

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

1575 

1576 @util.deprecated( 

1577 "1.4", 

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

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

1580 ) 

1581 def tometadata( 

1582 self, 

1583 metadata: MetaData, 

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

1585 referred_schema_fn: Optional[ 

1586 Callable[ 

1587 [Table, Optional[str], ForeignKeyConstraint, Optional[str]], 

1588 Optional[str], 

1589 ] 

1590 ] = None, 

1591 name: Optional[str] = None, 

1592 ) -> Table[_ColCC_co]: 

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

1594 associated with a different 

1595 :class:`_schema.MetaData`. 

1596 

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

1598 

1599 """ 

1600 return self.to_metadata( 

1601 metadata, 

1602 schema=schema, 

1603 referred_schema_fn=referred_schema_fn, 

1604 name=name, 

1605 ) 

1606 

1607 def to_metadata( 

1608 self, 

1609 metadata: MetaData, 

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

1611 referred_schema_fn: Optional[ 

1612 Callable[ 

1613 [Table, Optional[str], ForeignKeyConstraint, Optional[str]], 

1614 Optional[str], 

1615 ] 

1616 ] = None, 

1617 name: Optional[str] = None, 

1618 ) -> Table[_ColCC_co]: 

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

1620 different :class:`_schema.MetaData`. 

1621 

1622 E.g.:: 

1623 

1624 m1 = MetaData() 

1625 

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

1627 

1628 m2 = MetaData() 

1629 user_copy = user.to_metadata(m2) 

1630 

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

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

1633 

1634 

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

1636 into which the 

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

1638 

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

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

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

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

1643 :class:`_schema.Table` 

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

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

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

1647 unless 

1648 set explicitly:: 

1649 

1650 m2 = MetaData(schema="newschema") 

1651 

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

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

1654 

1655 m3 = MetaData() # schema defaults to None 

1656 

1657 # user_copy_two will have None as the schema name 

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

1659 

1660 :param referred_schema_fn: optional callable which can be supplied 

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

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

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

1664 target schema that we are changing to, the 

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

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

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

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

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

1670 

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

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

1673 symbols. 

1674 

1675 E.g.:: 

1676 

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

1678 if referred_schema == "base_tables": 

1679 return referred_schema 

1680 else: 

1681 return to_schema 

1682 

1683 

1684 new_table = table.to_metadata( 

1685 m2, schema="alt_schema", referred_schema_fn=referred_schema_fn 

1686 ) 

1687 

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

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

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

1691 :class:`_schema.MetaData` target 

1692 with a new name. 

1693 

1694 """ # noqa: E501 

1695 if name is None: 

1696 name = self.name 

1697 

1698 actual_schema: Optional[str] 

1699 

1700 if schema is RETAIN_SCHEMA: 

1701 actual_schema = self.schema 

1702 elif schema is None: 

1703 actual_schema = metadata.schema 

1704 else: 

1705 actual_schema = schema 

1706 key = _get_table_key(name, actual_schema) 

1707 if key in metadata.tables: 

1708 util.warn( 

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

1710 "MetaData - not copying." 

1711 ) 

1712 return metadata.tables[key] 

1713 

1714 args = [] 

1715 for col in self.columns: 

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

1717 

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

1719 name, 

1720 metadata, 

1721 schema=actual_schema, 

1722 comment=self.comment, 

1723 *args, 

1724 **self.kwargs, 

1725 ) 

1726 

1727 if self._creator_ddl is not None: 

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

1729 if self._dropper_ddl is not None: 

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

1731 

1732 for const in self.constraints: 

1733 if isinstance(const, ForeignKeyConstraint): 

1734 referred_schema = const._referred_schema 

1735 if referred_schema_fn: 

1736 fk_constraint_schema = referred_schema_fn( 

1737 self, actual_schema, const, referred_schema 

1738 ) 

1739 else: 

1740 fk_constraint_schema = ( 

1741 actual_schema 

1742 if referred_schema == self.schema 

1743 else None 

1744 ) 

1745 table.append_constraint( 

1746 const._copy( 

1747 schema=fk_constraint_schema, target_table=table 

1748 ) 

1749 ) 

1750 elif not const._type_bound: 

1751 # skip unique constraints that would be generated 

1752 # by the 'unique' flag on Column 

1753 if const._column_flag: 

1754 continue 

1755 

1756 table.append_constraint( 

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

1758 ) 

1759 for index in self.indexes: 

1760 # skip indexes that would be generated 

1761 # by the 'index' flag on Column 

1762 if index._column_flag: 

1763 continue 

1764 Index( 

1765 index.name, 

1766 unique=index.unique, 

1767 *[ 

1768 _copy_expression(expr, self, table) 

1769 for expr in index._table_bound_expressions 

1770 ], 

1771 _table=table, 

1772 **index.kwargs, 

1773 **index._reflect_only_kwargs, 

1774 ) 

1775 return self._schema_item_copy(table) 

1776 

1777 

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

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

1780 

1781 __visit_name__ = "column" 

1782 

1783 inherit_cache = True 

1784 key: str 

1785 

1786 server_default: Optional[FetchedValue] 

1787 

1788 def __init__( 

1789 self, 

1790 __name_pos: Optional[ 

1791 Union[str, _CovariantTypeEngineArgument[_T], SchemaEventTarget] 

1792 ] = None, 

1793 __type_pos: Optional[ 

1794 Union[_CovariantTypeEngineArgument[_T], SchemaEventTarget] 

1795 ] = None, 

1796 /, 

1797 *args: SchemaEventTarget, 

1798 name: Optional[str] = None, 

1799 type_: Optional[_CovariantTypeEngineArgument[_T]] = None, 

1800 autoincrement: _AutoIncrementType = "auto", 

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

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

1803 doc: Optional[str] = None, 

1804 key: Optional[str] = None, 

1805 index: Optional[bool] = None, 

1806 unique: Optional[bool] = None, 

1807 info: Optional[_InfoType] = None, 

1808 nullable: Optional[ 

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

1810 ] = SchemaConst.NULL_UNSPECIFIED, 

1811 onupdate: Optional[Any] = None, 

1812 primary_key: bool = False, 

1813 server_default: Optional[_ServerDefaultArgument] = None, 

1814 server_onupdate: Optional[_ServerOnUpdateArgument] = None, 

1815 quote: Optional[bool] = None, 

1816 system: bool = False, 

1817 comment: Optional[str] = None, 

1818 insert_sentinel: bool = False, 

1819 _omit_from_statements: bool = False, 

1820 _proxies: Optional[Any] = None, 

1821 **dialect_kwargs: Any, 

1822 ): 

1823 r""" 

1824 Construct a new ``Column`` object. 

1825 

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

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

1828 via keyword. 

1829 

1830 Names which contain no upper case characters 

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

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

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

1834 behavior applies even for databases which standardize upper 

1835 case names as case insensitive such as Oracle Database. 

1836 

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

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

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

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

1841 

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

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

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

1845 as well, e.g.:: 

1846 

1847 # use a type with arguments 

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

1849 

1850 # use no arguments 

1851 Column("level", Integer) 

1852 

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

1854 or specified by keyword. 

1855 

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

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

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

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

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

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

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

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

1864 

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

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

1867 as options to the column. These include instances of 

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

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

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

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

1872 ``default`` and ``unique``. 

1873 

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

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

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

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

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

1879 will be considered when INSERT statements are compiled and 

1880 executed. 

1881 

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

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

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

1885 default constructs indicated should receive auto increment semantics 

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

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

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

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

1890 key columns, see below). 

1891 

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

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

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

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

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

1897 database: 

1898 

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

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

1901 no other 

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

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

1904 will imply that database-specific keywords such as PostgreSQL 

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

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

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

1908 backends always needs an explicit construct such as 

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

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

1911 be produced in the database. 

1912 

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

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

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

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

1917 value automatically for this column, which will be accessible 

1918 after the statement is invoked via the 

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

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

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

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

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

1924 behavior takes place regardless of what DDL constructs are 

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

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

1927 above. 

1928 

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

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

1931 have autoincrement semantics, though note that only one column 

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

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

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

1935 however note that not all dialects can accommodate all styles 

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

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

1938 datatype of INTEGER in order to disable auto increment semantics 

1939 for that column. 

1940 

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

1942 

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

1944 

1945 * Part of the primary key 

1946 

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

1948 unless 

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

1950 

1951 # turn on autoincrement for this column despite 

1952 # the ForeignKey() 

1953 Column( 

1954 "id", 

1955 ForeignKey("other.id"), 

1956 primary_key=True, 

1957 autoincrement="ignore_fk", 

1958 ) 

1959 

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

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

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

1963 

1964 The setting has these effects on columns that meet the 

1965 above criteria: 

1966 

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

1968 a default generating construct supported by the backend such as 

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

1970 keywords intended to signify this column as an 

1971 "autoincrement" column for specific backends. Behavior for 

1972 primary SQLAlchemy dialects includes: 

1973 

1974 * AUTO INCREMENT on MySQL and MariaDB 

1975 * SERIAL on PostgreSQL 

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

1977 :class:`.Identity` construct as the 

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

1979 construct. 

1980 * SQLite - SQLite integer primary key columns are implicitly 

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

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

1983 is not included as this is unnecessary and not recommended 

1984 by the database vendor. See the section 

1985 :ref:`sqlite_autoincrement` for more background. 

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

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

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

1989 construct may also be used). 

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

1991 for details on their specific behaviors. 

1992 

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

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

1995 modifier, newly generated primary key values for this column 

1996 will be automatically retrieved upon statement execution 

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

1998 

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

2000 (see 

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

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

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

2004 construct when rendering an INSERT statement, and then retrieving 

2005 the newly generated primary key values after execution 

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

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

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

2009 explicitly before the INSERT statement takes place so that the 

2010 newly generated primary key value is available to the client 

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

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

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

2014 INSERT statement is invoked to retrieve the newly generated 

2015 primary key value. 

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

2017 for details on their specific behaviors. 

2018 

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

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

2021 retrieving behaviors are generally disabled, however there may 

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

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

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

2025 may not yet be well covered in documentation. 

2026 

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

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

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

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

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

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

2033 structure of the argument. 

2034 

2035 Contrast this argument to 

2036 :paramref:`_schema.Column.server_default` 

2037 which creates a default generator on the database side. 

2038 

2039 .. seealso:: 

2040 

2041 :ref:`metadata_defaults_toplevel` 

2042 

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

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

2045 

2046 .. versionadded:: 2.0.31 

2047 

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

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

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

2051 :paramref:`_schema.Column.comment` 

2052 parameter for this purpose. 

2053 

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

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

2056 When a key is provided, 

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

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

2059 is used only when rendering SQL. 

2060 

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

2062 construct will be automatically generated for this 

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

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

2065 create operation is invoked. 

2066 

2067 Using this flag is equivalent to making use of the 

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

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

2070 

2071 Table( 

2072 "some_table", 

2073 metadata, 

2074 Column("x", Integer), 

2075 Index("ix_some_table_x", "x"), 

2076 ) 

2077 

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

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

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

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

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

2083 DDL instruction instead of "CREATE INDEX". 

2084 

2085 The name of the index is generated using the 

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

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

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

2089 

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

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

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

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

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

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

2096 indexes that use a specific name. 

2097 

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

2099 :class:`_schema.Column` 

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

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

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

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

2104 

2105 .. seealso:: 

2106 

2107 :ref:`schema_indexes` 

2108 

2109 :ref:`constraint_naming_conventions` 

2110 

2111 :paramref:`_schema.Column.unique` 

2112 

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

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

2115 

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

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

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

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

2120 where "NULL" may render explicitly. 

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

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

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

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

2125 

2126 .. note:: 

2127 

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

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

2130 PostgreSQL database allows nullable identity column by 

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

2132 

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

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

2135 default value to be applied to the column within UPDATE 

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

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

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

2139 ``for_update=True``. 

2140 

2141 .. seealso:: 

2142 

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

2144 

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

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

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

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

2149 :class:`.PrimaryKeyConstraint` object. 

2150 

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

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

2153 the DDL DEFAULT value for the column. 

2154 

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

2156 

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

2158 

2159 will render: 

2160 

2161 .. sourcecode:: sql 

2162 

2163 x TEXT DEFAULT 'val' 

2164 

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

2166 rendered as-is, without quotes:: 

2167 

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

2169 

2170 will render: 

2171 

2172 .. sourcecode:: sql 

2173 

2174 y DATETIME DEFAULT NOW() 

2175 

2176 Strings and text() will be converted into a 

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

2178 

2179 This parameter can also accept complex combinations of contextually 

2180 valid SQLAlchemy expressions or constructs:: 

2181 

2182 from sqlalchemy import create_engine 

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

2184 from sqlalchemy.dialects.postgresql import array 

2185 

2186 engine = create_engine( 

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

2188 ) 

2189 metadata_obj = MetaData() 

2190 tbl = Table( 

2191 "foo", 

2192 metadata_obj, 

2193 Column( 

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

2195 ), 

2196 ) 

2197 metadata_obj.create_all(engine) 

2198 

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

2200 

2201 .. sourcecode:: sql 

2202 

2203 CREATE TABLE foo ( 

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

2205 ) 

2206 

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

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

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

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

2211 to the database, such as via a trigger. 

2212 

2213 .. seealso:: 

2214 

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

2216 defaults 

2217 

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

2219 representing a database-side default generation function, 

2220 such as a trigger. This 

2221 indicates to SQLAlchemy that a newly generated value will be 

2222 available after updates. This construct does not actually 

2223 implement any kind of generation function within the database, 

2224 which instead must be specified separately. 

2225 

2226 

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

2228 "ON UPDATE CURRENT_TIMESTAMP()" clause. See 

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

2230 produce this clause. 

2231 

2232 .. seealso:: 

2233 

2234 :ref:`triggered_columns` 

2235 

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

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

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

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

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

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

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

2243 

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

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

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

2247 construct will be automatically generated for this 

2248 :class:`_schema.Column`, 

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

2250 to this column being included 

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

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

2253 

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

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

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

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

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

2259 is generated. See the documentation for 

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

2261 

2262 Using this flag is equivalent to making use of the 

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

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

2265 

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

2267 

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

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

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

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

2272 construct will be emitted as unnamed, which typically invokes 

2273 a database-specific naming convention to take place. 

2274 

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

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

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

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

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

2280 constraints that use a specific name. 

2281 

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

2283 :class:`_schema.Column` 

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

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

2286 indexes and unique constraints that may involve this column, 

2287 view the 

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

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

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

2291 :meth:`_reflection.Inspector.get_unique_constraints` 

2292 

2293 .. seealso:: 

2294 

2295 :ref:`schema_unique_constraint` 

2296 

2297 :ref:`constraint_naming_conventions` 

2298 

2299 :paramref:`_schema.Column.index` 

2300 

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

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

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

2304 ``CREATE TABLE`` statement. 

2305 

2306 For more elaborate scenarios where columns should be 

2307 conditionally rendered differently on different backends, 

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

2309 

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

2311 table creation. 

2312 

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

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

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

2316 otherwise have qualifying primary key configurations. 

2317 

2318 .. versionadded:: 2.0.10 

2319 

2320 .. seealso:: 

2321 

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

2323 sentinel columns 

2324 

2325 :ref:`engine_insertmanyvalues` 

2326 

2327 :ref:`engine_insertmanyvalues_sentinel_columns` 

2328 

2329 

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

2331 

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

2333 del args 

2334 

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

2336 if name is not None: 

2337 raise exc.ArgumentError( 

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

2339 ) 

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

2341 elif l_args[0] is None: 

2342 l_args.pop(0) 

2343 if l_args: 

2344 coltype = l_args[0] 

2345 

2346 if hasattr(coltype, "_sqla_type"): 

2347 if type_ is not None: 

2348 raise exc.ArgumentError( 

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

2350 ) 

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

2352 elif l_args[0] is None: 

2353 l_args.pop(0) 

2354 

2355 if name is not None: 

2356 name = quoted_name(name, quote) 

2357 elif quote is not None: 

2358 raise exc.ArgumentError( 

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

2360 ) 

2361 

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

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

2364 # dedicated "column" construct local to the ORM 

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

2366 

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

2368 self.primary_key = primary_key 

2369 self._insert_sentinel = insert_sentinel 

2370 self._omit_from_statements = _omit_from_statements 

2371 self._user_defined_nullable = udn = nullable 

2372 if udn is not NULL_UNSPECIFIED: 

2373 self.nullable = udn 

2374 else: 

2375 self.nullable = not primary_key 

2376 

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

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

2379 # Index or UniqueConstraint referring to this Column. 

2380 self.index = index 

2381 self.unique = unique 

2382 

2383 self.system = system 

2384 self.doc = doc 

2385 self.autoincrement: _AutoIncrementType = autoincrement 

2386 self.constraints = set() 

2387 self.foreign_keys = set() 

2388 self.comment = comment 

2389 self.computed = None 

2390 self.identity = None 

2391 

2392 # check if this Column is proxying another column 

2393 

2394 if _proxies is not None: 

2395 self._proxies = _proxies 

2396 else: 

2397 # otherwise, add DDL-related events 

2398 self._set_type(self.type) 

2399 

2400 if insert_default is not _NoArg.NO_ARG: 

2401 if default is not _NoArg.NO_ARG: 

2402 raise exc.ArgumentError( 

2403 "The 'default' and 'insert_default' parameters " 

2404 "of Column are mutually exclusive" 

2405 ) 

2406 resolved_default = insert_default 

2407 elif default is not _NoArg.NO_ARG: 

2408 resolved_default = default 

2409 else: 

2410 resolved_default = None 

2411 

2412 if resolved_default is not None: 

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

2414 resolved_default = ColumnDefault(resolved_default) 

2415 

2416 self.default = resolved_default 

2417 l_args.append(resolved_default) 

2418 else: 

2419 self.default = None 

2420 

2421 if onupdate is not None: 

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

2423 onupdate = ColumnDefault(onupdate, for_update=True) 

2424 

2425 self.onupdate = onupdate 

2426 l_args.append(onupdate) 

2427 else: 

2428 self.onupdate = None 

2429 

2430 if server_default is not None: 

2431 if isinstance(server_default, FetchedValue): 

2432 server_default = server_default._as_for_update(False) 

2433 l_args.append(server_default) 

2434 else: 

2435 server_default = DefaultClause(server_default) 

2436 l_args.append(server_default) 

2437 self.server_default = server_default 

2438 

2439 if server_onupdate is not None: 

2440 if isinstance(server_onupdate, FetchedValue): 

2441 server_onupdate = server_onupdate._as_for_update(True) 

2442 l_args.append(server_onupdate) 

2443 else: 

2444 server_onupdate = DefaultClause( 

2445 server_onupdate, for_update=True 

2446 ) 

2447 l_args.append(server_onupdate) 

2448 self.server_onupdate = server_onupdate 

2449 

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

2451 

2452 util.set_creation_order(self) 

2453 

2454 if info is not None: 

2455 self.info = info 

2456 

2457 self._extra_kwargs(**dialect_kwargs) 

2458 

2459 table: Table 

2460 

2461 constraints: Set[Constraint] 

2462 

2463 foreign_keys: Set[ForeignKey] 

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

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

2466 

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

2468 :class:`_schema.ForeignKeyConstraint`. 

2469 

2470 .. seealso:: 

2471 

2472 :attr:`_schema.Table.foreign_keys` 

2473 

2474 """ 

2475 

2476 index: Optional[bool] 

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

2478 

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

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

2481 

2482 .. seealso:: 

2483 

2484 :attr:`_schema.Table.indexes` 

2485 """ 

2486 

2487 unique: Optional[bool] 

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

2489 

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

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

2492 :attr:`_schema.Table.constraints`. 

2493 

2494 .. seealso:: 

2495 

2496 :attr:`_schema.Table.indexes` 

2497 

2498 :attr:`_schema.Table.constraints`. 

2499 

2500 """ 

2501 

2502 computed: Optional[Computed] 

2503 

2504 identity: Optional[Identity] 

2505 

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

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

2508 

2509 self.type = type_ 

2510 if isinstance(self.type, SchemaEventTarget): 

2511 self.type._set_parent_with_dispatch(self) 

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

2513 if isinstance(impl, SchemaEventTarget): 

2514 impl._set_parent_with_dispatch(self) 

2515 

2516 @HasMemoized.memoized_attribute 

2517 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

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

2519 

2520 return _DefaultDescriptionTuple._from_column_default(self.default) 

2521 

2522 @HasMemoized.memoized_attribute 

2523 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

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

2525 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

2526 

2527 @util.memoized_property 

2528 def _gen_static_annotations_cache_key(self) -> bool: 

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

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

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

2532 

2533 Added for #8790 

2534 

2535 """ 

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

2537 

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

2539 self._validate_dialect_kwargs(kwargs) 

2540 

2541 def __str__(self) -> str: 

2542 if self.name is None: 

2543 return "(no name)" 

2544 elif self.table is not None: 

2545 if self.table.named_with_column: 

2546 return self.table.description + "." + self.description 

2547 else: 

2548 return self.description 

2549 else: 

2550 return self.description 

2551 

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

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

2554 key.""" 

2555 

2556 for fk in self.foreign_keys: 

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

2558 return True 

2559 else: 

2560 return False 

2561 

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

2563 fk._set_parent_with_dispatch(self) 

2564 

2565 def __repr__(self) -> str: 

2566 kwarg = [] 

2567 if self.key != self.name: 

2568 kwarg.append("key") 

2569 if self.primary_key: 

2570 kwarg.append("primary_key") 

2571 if not self.nullable: 

2572 kwarg.append("nullable") 

2573 if self.onupdate: 

2574 kwarg.append("onupdate") 

2575 if self.default: 

2576 kwarg.append("default") 

2577 if self.server_default: 

2578 kwarg.append("server_default") 

2579 if self.comment: 

2580 kwarg.append("comment") 

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

2582 [repr(self.name)] 

2583 + [repr(self.type)] 

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

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

2586 + [ 

2587 ( 

2588 self.table is not None 

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

2590 or "table=None" 

2591 ) 

2592 ] 

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

2594 ) 

2595 

2596 def _set_parent( # type: ignore[override] 

2597 self, 

2598 parent: SchemaEventTarget, 

2599 *, 

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

2601 allow_replacements: bool, 

2602 index: Optional[int] = None, 

2603 **kw: Any, 

2604 ) -> None: 

2605 table = parent 

2606 assert isinstance(table, Table) 

2607 if not self.name: 

2608 raise exc.ArgumentError( 

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

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

2611 ) 

2612 

2613 self._reset_memoizations() 

2614 

2615 if self.key is None: 

2616 self.key = self.name 

2617 

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

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

2620 raise exc.ArgumentError( 

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

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

2623 ) 

2624 

2625 extra_remove = None 

2626 existing_col = None 

2627 conflicts_on = "" 

2628 

2629 if self.key in table._columns: 

2630 existing_col = table._columns[self.key] 

2631 if self.key == self.name: 

2632 conflicts_on = "name" 

2633 else: 

2634 conflicts_on = "key" 

2635 elif self.name in all_names: 

2636 existing_col = all_names[self.name] 

2637 extra_remove = {existing_col} 

2638 conflicts_on = "name" 

2639 

2640 if existing_col is not None: 

2641 if existing_col is not self: 

2642 if not allow_replacements: 

2643 raise exc.DuplicateColumnError( 

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

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

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

2647 ) 

2648 for fk in existing_col.foreign_keys: 

2649 table.foreign_keys.remove(fk) 

2650 if fk.constraint in table.constraints: 

2651 # this might have been removed 

2652 # already, if it's a composite constraint 

2653 # and more than one col being replaced 

2654 table.constraints.remove(fk.constraint) 

2655 

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

2657 util.warn( 

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

2659 "being replaced with " 

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

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

2662 "reflection operation, specify autoload_replace=False to " 

2663 "prevent this replacement." 

2664 ) 

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

2666 all_names[self.name] = self 

2667 self.table = table 

2668 

2669 if self._insert_sentinel: 

2670 if self.table._sentinel_column is not None: 

2671 raise exc.ArgumentError( 

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

2673 ) 

2674 self.table._sentinel_column = self 

2675 

2676 if self.primary_key: 

2677 table.primary_key._replace(self) 

2678 elif self.key in table.primary_key: 

2679 raise exc.ArgumentError( 

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

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

2682 ) 

2683 

2684 if self.index: 

2685 if isinstance(self.index, str): 

2686 raise exc.ArgumentError( 

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

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

2689 "explicit Index object external to the Table." 

2690 ) 

2691 table.append_constraint( 

2692 Index( 

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

2694 ) 

2695 ) 

2696 

2697 elif self.unique: 

2698 if isinstance(self.unique, str): 

2699 raise exc.ArgumentError( 

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

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

2702 "specific name, append an explicit UniqueConstraint to " 

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

2704 "Index object external to the Table." 

2705 ) 

2706 table.append_constraint( 

2707 UniqueConstraint(self.key, _column_flag=True) 

2708 ) 

2709 

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

2711 

2712 if self.identity and ( 

2713 isinstance(self.default, Sequence) 

2714 or isinstance(self.onupdate, Sequence) 

2715 ): 

2716 raise exc.ArgumentError( 

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

2718 ) 

2719 

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

2721 fk_keys = [ 

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

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

2724 ] 

2725 for fk_key, link_to_name in fk_keys: 

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

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

2728 if fk.link_to_name is link_to_name: 

2729 fn(fk) 

2730 

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

2732 if self.table is not None: 

2733 fn(self, self.table) 

2734 else: 

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

2736 

2737 @util.deprecated( 

2738 "1.4", 

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

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

2741 ) 

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

2743 return self._copy(**kw) 

2744 

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

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

2747 

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

2749 

2750 """ 

2751 

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

2753 args: List[SchemaItem] = [ 

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

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

2756 

2757 # ticket #5276 

2758 column_kwargs = {} 

2759 for dialect_name in self.dialect_options: 

2760 dialect_options = self.dialect_options[dialect_name]._non_defaults 

2761 for ( 

2762 dialect_option_key, 

2763 dialect_option_value, 

2764 ) in dialect_options.items(): 

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

2766 dialect_option_value 

2767 ) 

2768 

2769 default = self.default 

2770 if default is not None: 

2771 default = default._copy() 

2772 onupdate = self.onupdate 

2773 if onupdate is not None: 

2774 onupdate = onupdate._copy() 

2775 server_default = self.server_default 

2776 server_onupdate = self.server_onupdate 

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

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

2779 server_default = server_onupdate = None 

2780 else: 

2781 if server_default is not None: 

2782 server_default = server_default._copy() 

2783 if server_onupdate is not None: 

2784 server_onupdate = server_onupdate._copy() 

2785 

2786 type_ = self.type 

2787 if isinstance(type_, SchemaEventTarget): 

2788 type_ = type_.copy(**kw) 

2789 

2790 c = self._constructor( 

2791 name=self.name, 

2792 type_=type_, 

2793 key=self.key, 

2794 primary_key=self.primary_key, 

2795 unique=self.unique, 

2796 system=self.system, 

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

2798 index=self.index, 

2799 autoincrement=self.autoincrement, 

2800 default=default, 

2801 server_default=server_default, 

2802 onupdate=onupdate, 

2803 server_onupdate=server_onupdate, 

2804 doc=self.doc, 

2805 comment=self.comment, 

2806 _omit_from_statements=self._omit_from_statements, 

2807 insert_sentinel=self._insert_sentinel, 

2808 *args, 

2809 **column_kwargs, 

2810 ) 

2811 

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

2813 # ORM flipping the .nullable flag directly 

2814 c.nullable = self.nullable 

2815 c._user_defined_nullable = self._user_defined_nullable 

2816 

2817 return self._schema_item_copy(c) 

2818 

2819 def _merge( 

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

2821 ) -> None: 

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

2823 

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

2825 of fixes. 

2826 

2827 

2828 """ 

2829 

2830 if self.primary_key: 

2831 other.primary_key = True 

2832 

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

2834 other.autoincrement = self.autoincrement 

2835 

2836 if self.system: 

2837 other.system = self.system 

2838 

2839 if self.info: 

2840 other.info.update(self.info) 

2841 

2842 type_ = self.type 

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

2844 if isinstance(type_, SchemaEventTarget): 

2845 type_ = type_.copy() 

2846 

2847 other.type = type_ 

2848 

2849 if isinstance(type_, SchemaEventTarget): 

2850 type_._set_parent_with_dispatch(other) 

2851 

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

2853 if isinstance(impl, SchemaEventTarget): 

2854 impl._set_parent_with_dispatch(other) 

2855 

2856 if ( 

2857 self._user_defined_nullable is not NULL_UNSPECIFIED 

2858 and other._user_defined_nullable is NULL_UNSPECIFIED 

2859 ): 

2860 other.nullable = self.nullable 

2861 other._user_defined_nullable = self._user_defined_nullable 

2862 

2863 if ( 

2864 not omit_defaults 

2865 and self.default is not None 

2866 and other.default is None 

2867 ): 

2868 new_default = self.default._copy() 

2869 new_default._set_parent(other) 

2870 

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

2872 new_server_default = self.server_default 

2873 if isinstance(new_server_default, FetchedValue): 

2874 new_server_default = new_server_default._copy() 

2875 new_server_default._set_parent(other) 

2876 else: 

2877 other.server_default = new_server_default 

2878 

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

2880 new_server_onupdate = self.server_onupdate 

2881 new_server_onupdate = new_server_onupdate._copy() 

2882 new_server_onupdate._set_parent(other) 

2883 

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

2885 new_onupdate = self.onupdate._copy() 

2886 new_onupdate._set_parent(other) 

2887 

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

2889 other.index = self.index 

2890 

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

2892 other.unique = self.unique 

2893 

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

2895 other.doc = self.doc 

2896 

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

2898 other.comment = self.comment 

2899 

2900 for const in self.constraints: 

2901 if not const._type_bound: 

2902 new_const = const._copy() 

2903 new_const._set_parent(other) 

2904 

2905 for fk in self.foreign_keys: 

2906 if not fk.constraint: 

2907 new_fk = fk._copy() 

2908 new_fk._set_parent(other) 

2909 

2910 def _make_proxy( 

2911 self, 

2912 selectable: FromClause, 

2913 primary_key: ColumnSet, 

2914 foreign_keys: Set[KeyedColumnElement[Any]], 

2915 name: Optional[str] = None, 

2916 key: Optional[str] = None, 

2917 name_is_truncatable: bool = False, 

2918 compound_select_cols: Optional[ 

2919 _typing_Sequence[ColumnElement[Any]] 

2920 ] = None, 

2921 **kw: Any, 

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

2923 """Create a *proxy* for this column. 

2924 

2925 This is a copy of this ``Column`` referenced by a different parent 

2926 (such as an alias or select statement). The column should 

2927 be used only in select scenarios, as its full DDL/default 

2928 information is not transferred. 

2929 

2930 """ 

2931 

2932 fk = [ 

2933 ForeignKey( 

2934 col if col is not None else f.target_tokens, 

2935 _unresolvable=col is None, 

2936 _constraint=f.constraint, 

2937 ) 

2938 for f, col in [ 

2939 (fk, fk._resolve_column(raiseerr=False)) 

2940 for fk in self.foreign_keys 

2941 ] 

2942 ] 

2943 

2944 if name is None and self.name is None: 

2945 raise exc.InvalidRequestError( 

2946 "Cannot initialize a sub-selectable" 

2947 " with this Column object until its 'name' has " 

2948 "been assigned." 

2949 ) 

2950 try: 

2951 c = self._constructor( 

2952 ( 

2953 coercions.expect( 

2954 roles.TruncatedLabelRole, name if name else self.name 

2955 ) 

2956 if name_is_truncatable 

2957 else (name or self.name) 

2958 ), 

2959 self.type, 

2960 # this may actually be ._proxy_key when the key is incoming 

2961 key=key if key else name if name else self.key, 

2962 primary_key=self.primary_key, 

2963 nullable=self.nullable, 

2964 _proxies=( 

2965 list(compound_select_cols) 

2966 if compound_select_cols 

2967 else [self] 

2968 ), 

2969 *fk, 

2970 ) 

2971 except TypeError as err: 

2972 raise TypeError( 

2973 "Could not create a copy of this %r object. " 

2974 "Ensure the class includes a _constructor() " 

2975 "attribute or method which accepts the " 

2976 "standard Column constructor arguments, or " 

2977 "references the Column class itself." % self.__class__ 

2978 ) from err 

2979 

2980 c.table = selectable 

2981 c._propagate_attrs = selectable._propagate_attrs 

2982 if selectable._is_clone_of is not None: 

2983 c._is_clone_of = selectable._is_clone_of.columns.get(c.key) 

2984 

2985 if self.primary_key: 

2986 primary_key.add(c) 

2987 

2988 if fk: 

2989 foreign_keys.update(fk) # type: ignore[arg-type] 

2990 

2991 return c.key, c 

2992 

2993 

2994def insert_sentinel( 

2995 name: Optional[str] = None, 

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

2997 *, 

2998 default: Optional[Any] = None, 

2999 omit_from_statements: bool = True, 

3000) -> Column[Any]: 

3001 """Provides a surrogate :class:`_schema.Column` that will act as a 

3002 dedicated insert :term:`sentinel` column, allowing efficient bulk 

3003 inserts with deterministic RETURNING sorting for tables that 

3004 don't otherwise have qualifying primary key configurations. 

3005 

3006 Adding this column to a :class:`.Table` object requires that a 

3007 corresponding database table actually has this column present, so if adding 

3008 it to an existing model, existing database tables would need to be migrated 

3009 (e.g. using ALTER TABLE or similar) to include this column. 

3010 

3011 For background on how this object is used, see the section 

3012 :ref:`engine_insertmanyvalues_sentinel_columns` as part of the 

3013 section :ref:`engine_insertmanyvalues`. 

3014 

3015 The :class:`_schema.Column` returned will be a nullable integer column by 

3016 default and make use of a sentinel-specific default generator used only in 

3017 "insertmanyvalues" operations. 

3018 

3019 .. seealso:: 

3020 

3021 :func:`_orm.orm_insert_sentinel` 

3022 

3023 :paramref:`_schema.Column.insert_sentinel` 

3024 

3025 :ref:`engine_insertmanyvalues` 

3026 

3027 :ref:`engine_insertmanyvalues_sentinel_columns` 

3028 

3029 

3030 .. versionadded:: 2.0.10 

3031 

3032 """ 

3033 return Column( 

3034 name=name, 

3035 type_=type_api.INTEGERTYPE if type_ is None else type_, 

3036 default=( 

3037 default if default is not None else _InsertSentinelColumnDefault() 

3038 ), 

3039 _omit_from_statements=omit_from_statements, 

3040 insert_sentinel=True, 

3041 ) 

3042 

3043 

3044class ForeignKeyTarget(NamedTuple): 

3045 """Represents the target of a :class:`_schema.ForeignKey` as three 

3046 individual name tokens. 

3047 

3048 This is the return value of :attr:`_schema.ForeignKey.target_tokens`, and 

3049 may also be passed directly to the :class:`_schema.ForeignKey` constructor 

3050 as well as to the :paramref:`_schema.ForeignKeyConstraint.refcolumns` 

3051 parameter, as either a three-token tuple ``(schema, table_name, 

3052 column_name)`` or a two-token tuple ``(table_name, column_name)``. 

3053 

3054 The token form is the only representation of a foreign key target that is 

3055 unambiguous in all cases; the dotted string form, available at 

3056 :attr:`_schema.ForeignKey.target_fullname`, cannot represent a target 

3057 where the table or column name itself contains a dot. 

3058 

3059 .. versionadded:: 2.1 

3060 

3061 .. seealso:: 

3062 

3063 :attr:`_schema.ForeignKey.target_tokens` 

3064 

3065 """ 

3066 

3067 schema: Optional[str] 

3068 """The schema name of the target, or ``None`` for the default schema.""" 

3069 

3070 table_name: str 

3071 """The name of the target table.""" 

3072 

3073 column_name: Optional[str] 

3074 """The key of the target column. 

3075 

3076 This is ``None`` for a :class:`_schema.ForeignKey` that was given a table 

3077 name only, in which case the local column's key is used to locate the 

3078 target column. 

3079 

3080 Note that this is the ``key`` of the target column rather than its name, 

3081 unless :paramref:`_schema.ForeignKey.link_to_name` is ``True``. 

3082 

3083 """ 

3084 

3085 def _tokens_no_dots(self) -> _typing_Sequence[str] | None: 

3086 """return a sequence of non-None tokens to create a dotted name. 

3087 

3088 returns None if either of table_name or column_name already have an 

3089 embedded dot, making dotted name string impossible. 

3090 

3091 """ 

3092 tokens = [] 

3093 for i, token in enumerate( 

3094 [self.schema, self.table_name, self.column_name] 

3095 ): 

3096 if token is not None: 

3097 # dot in the table name or column name; a dotted name 

3098 # would be ambiguous 

3099 if i != 0 and "." in token: 

3100 return None 

3101 tokens.append(token) 

3102 elif i == 1: 

3103 # table name is None; not renderable 

3104 return None 

3105 elif i == 2 and self.schema: 

3106 # column name is None and there's a schema; a dotted 

3107 # name would be ambiguous 

3108 return None 

3109 

3110 return tokens 

3111 

3112 def _as_string(self) -> str: 

3113 """Render these tokens as a single dotted string if possible, 

3114 else raise :class:`.InvalidRequestError` if no unambiguous string form 

3115 exists and a string is required. 

3116 

3117 """ 

3118 

3119 tokens_no_dots = self._tokens_no_dots() 

3120 

3121 if tokens_no_dots is None: 

3122 

3123 if not self.table_name: 

3124 reason = ( 

3125 "the target has no table name; a ForeignKey to a Column " 

3126 "which is not yet associated with a Table has no names " 

3127 "to render until that Column is attached" 

3128 ) 

3129 elif "." in self.table_name: 

3130 reason = ( 

3131 f"the table name {self.table_name!r} contains a dot, " 

3132 f"which can't be told apart from the separator between " 

3133 f"a schema name and a table name" 

3134 ) 

3135 elif self.column_name is not None and "." in self.column_name: 

3136 reason = ( 

3137 f"the column name {self.column_name!r} contains a dot, " 

3138 f"which can't be told apart from the separator between " 

3139 f"a table name and a column name" 

3140 ) 

3141 elif self.column_name is None: 

3142 reason = ( 

3143 f"a schema name {self.schema!r} is present with no " 

3144 f"column name, so the schema name can't be told apart " 

3145 f"from a table name" 

3146 ) 

3147 else: 

3148 # this is currently unreachable based on the current behavior 

3149 # of tokens_no_dots 

3150 assert False 

3151 

3152 raise exc.InvalidRequestError( 

3153 f"Can't render a single string representation for foreign " 

3154 f"key target {self._description()}; {reason}. Use " 

3155 f"ForeignKey.target_tokens to receive the schema, table and " 

3156 f"column names individually." 

3157 ) 

3158 

3159 return ".".join(tokens_no_dots) 

3160 

3161 def _description(self) -> str: 

3162 """Render a description of these tokens which never raises. 

3163 

3164 The dotted string form is preferred when it's available, falling 

3165 back to naming the tokens individually when it isn't. 

3166 

3167 """ 

3168 

3169 tokens_no_dots = self._tokens_no_dots() 

3170 if tokens_no_dots: 

3171 return repr(".".join(tokens_no_dots)) 

3172 else: 

3173 return ( 

3174 f"(schema={self.schema!r}, " 

3175 f"table_name={self.table_name!r}, " 

3176 f"column_name={self.column_name!r})" 

3177 ) 

3178 

3179 @classmethod 

3180 def _from_string(cls, spec: str) -> ForeignKeyTarget: 

3181 """Parse a dotted string colspec into its component tokens. 

3182 

3183 A FK between column 'bar' and table 'foo' can be specified as 'foo', 

3184 'foo.bar', 'dbo.foo.bar', 'otherdb.dbo.foo.bar'. Once we have the 

3185 column name and the table name, treat everything else as the schema 

3186 name. Some databases (e.g. Sybase) support inter-database foreign 

3187 keys. See tickets #1341 and -- indirectly related -- #594. 

3188 

3189 This assumes that '.' will never appear *within* the table or column 

3190 name; a target which does contain such a dot has no string form and 

3191 must be given as a :class:`.ForeignKeyTarget` instead. 

3192 

3193 """ 

3194 m = spec.split(".") 

3195 if len(m) == 1: 

3196 return cls(None, m[0], None) 

3197 

3198 colname = m.pop() 

3199 tname = m.pop() 

3200 return cls(".".join(m) if m else None, tname, colname) 

3201 

3202 @classmethod 

3203 def _from_argument( 

3204 cls, argument: _typing_Sequence[Any] 

3205 ) -> ForeignKeyTarget: 

3206 """Coerce a two or three token sequence passed by the user.""" 

3207 

3208 if len(argument) == 3: 

3209 schema, table_name, column_name = argument 

3210 elif len(argument) == 2: 

3211 schema = None 

3212 table_name, column_name = argument 

3213 else: 

3214 raise exc.ArgumentError( 

3215 f"ForeignKey target given as a tuple must have two tokens " 

3216 f"(table_name, column_name) or three tokens " 

3217 f"(schema, table_name, column_name); got {len(argument)}" 

3218 ) 

3219 

3220 if not table_name: 

3221 raise exc.ArgumentError( 

3222 "ForeignKey target table_name must be a non-empty string" 

3223 ) 

3224 

3225 return cls(schema, table_name, column_name) 

3226 

3227 

3228class ForeignKey(DialectKWArgs, SchemaItem): 

3229 """Defines a dependency between two columns. 

3230 

3231 ``ForeignKey`` is specified as an argument to a :class:`_schema.Column` 

3232 object, 

3233 e.g.:: 

3234 

3235 t = Table( 

3236 "remote_table", 

3237 metadata, 

3238 Column("remote_id", ForeignKey("main_table.id")), 

3239 ) 

3240 

3241 Note that ``ForeignKey`` is only a marker object that defines 

3242 a dependency between two columns. The actual constraint 

3243 is in all cases represented by the :class:`_schema.ForeignKeyConstraint` 

3244 object. This object will be generated automatically when 

3245 a ``ForeignKey`` is associated with a :class:`_schema.Column` which 

3246 in turn is associated with a :class:`_schema.Table`. Conversely, 

3247 when :class:`_schema.ForeignKeyConstraint` is applied to a 

3248 :class:`_schema.Table`, 

3249 ``ForeignKey`` markers are automatically generated to be 

3250 present on each associated :class:`_schema.Column`, which are also 

3251 associated with the constraint object. 

3252 

3253 Note that you cannot define a "composite" foreign key constraint, 

3254 that is a constraint between a grouping of multiple parent/child 

3255 columns, using ``ForeignKey`` objects. To define this grouping, 

3256 the :class:`_schema.ForeignKeyConstraint` object must be used, and applied 

3257 to the :class:`_schema.Table`. The associated ``ForeignKey`` objects 

3258 are created automatically. 

3259 

3260 The ``ForeignKey`` objects associated with an individual 

3261 :class:`_schema.Column` 

3262 object are available in the `foreign_keys` collection 

3263 of that column. 

3264 

3265 The target of a ``ForeignKey`` is described by three names -- a schema 

3266 name, a table name and a column name -- which are available at 

3267 :attr:`_schema.ForeignKey.target_tokens` as a 

3268 :class:`_schema.ForeignKeyTarget` named tuple:: 

3269 

3270 >>> fk = ForeignKey("main_table.id") 

3271 >>> fk.target_tokens 

3272 ForeignKeyTarget(schema=None, table_name='main_table', column_name='id') 

3273 

3274 The same three names may be given to ``ForeignKey`` in place of the 

3275 dotted string, as either a two or three token tuple. This is the only 

3276 way to name a target whose table or column name itself contains a dot, 

3277 as the dotted string form has no way of telling such a dot apart from 

3278 the separator between two names:: 

3279 

3280 ForeignKey(("my.tbl", "id")) 

3281 ForeignKey(("my_schema", "my.tbl", "id")) 

3282 

3283 .. versionadded:: 2.1 :attr:`_schema.ForeignKey.target_tokens`, and the 

3284 tuple form of the target. 

3285 

3286 Where the target was given as a :class:`_schema.Column` rather than by 

3287 name, that column is available at 

3288 :attr:`_schema.ForeignKey.target_column`; this is distinct from 

3289 :attr:`_schema.ForeignKey.column`, which is the *resolved* target however 

3290 it was specified. :attr:`_schema.ForeignKey.target_table_key` gives the 

3291 key under which the referenced :class:`_schema.Table` is, or would be, 

3292 registered in :attr:`_schema.MetaData.tables`. 

3293 

3294 Further examples of foreign key configuration are in 

3295 :ref:`metadata_foreignkeys`. 

3296 

3297 """ # noqa: E501 

3298 

3299 __visit_name__ = "foreign_key" 

3300 

3301 parent: Column[Any] 

3302 

3303 _table_column: Optional[Column[Any]] 

3304 """Storage for :attr:`.ForeignKey.target_column`; read that instead. 

3305 

3306 ``None`` when the target was given by name, in which case 

3307 :attr:`.ForeignKey._given_tokens` holds those names. 

3308 

3309 """ 

3310 

3311 _given_tokens: Optional[ForeignKeyTarget] 

3312 """The names of the target, when the target was given by name. 

3313 

3314 ``None`` when the target was given as a :class:`.Column`, in which case 

3315 the names are derived from that column on demand -- read 

3316 :attr:`.ForeignKey.target_tokens` rather than this. 

3317 

3318 """ 

3319 

3320 def __init__( 

3321 self, 

3322 column: _DDLColumnReferenceArgument, 

3323 _constraint: Optional[ForeignKeyConstraint] = None, 

3324 use_alter: bool = False, 

3325 name: _ConstraintNameArgument = None, 

3326 onupdate: Optional[str] = None, 

3327 ondelete: Optional[str] = None, 

3328 deferrable: Optional[bool] = None, 

3329 initially: Optional[str] = None, 

3330 link_to_name: bool = False, 

3331 match: Optional[str] = None, 

3332 info: Optional[_InfoType] = None, 

3333 comment: Optional[str] = None, 

3334 _unresolvable: bool = False, 

3335 **dialect_kw: Any, 

3336 ): 

3337 r""" 

3338 Construct a column-level FOREIGN KEY. 

3339 

3340 The :class:`_schema.ForeignKey` object when constructed generates a 

3341 :class:`_schema.ForeignKeyConstraint` 

3342 which is associated with the parent 

3343 :class:`_schema.Table` object's collection of constraints. 

3344 

3345 :param column: A single target column for the key relationship. A 

3346 :class:`_schema.Column` object or a column name as a string: 

3347 ``tablename.columnkey`` or ``schema.tablename.columnkey``. 

3348 ``columnkey`` is the ``key`` which has been assigned to the column 

3349 (defaults to the column name itself), unless ``link_to_name`` is 

3350 ``True`` in which case the rendered name of the column is used. 

3351 

3352 The target may also be given as a tuple of individual name 

3353 tokens, either ``(table_name, column_name)`` or 

3354 ``(schema, table_name, column_name)``. This is the only form 

3355 which can refer to a name that itself contains a dot, as the 

3356 dotted string form has no way of telling such a dot apart from 

3357 the separator between two names:: 

3358 

3359 ForeignKey(("my.tbl", "z")) 

3360 

3361 .. versionadded:: 2.1 The tuple form. 

3362 

3363 :param name: Optional string. An in-database name for the key if 

3364 `constraint` is not provided. 

3365 

3366 :param onupdate: Optional string. If set, emit ON UPDATE <value> when 

3367 issuing DDL for this constraint. Typical values include CASCADE, 

3368 DELETE and RESTRICT. 

3369 

3370 .. seealso:: 

3371 

3372 :ref:`on_update_on_delete` 

3373 

3374 :param ondelete: Optional string. If set, emit ON DELETE <value> when 

3375 issuing DDL for this constraint. Typical values include CASCADE, 

3376 SET NULL and RESTRICT. Some dialects may allow for additional 

3377 syntaxes. 

3378 

3379 .. seealso:: 

3380 

3381 :ref:`on_update_on_delete` 

3382 

3383 :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT 

3384 DEFERRABLE when issuing DDL for this constraint. 

3385 

3386 :param initially: Optional string. If set, emit INITIALLY <value> when 

3387 issuing DDL for this constraint. 

3388 

3389 :param link_to_name: if True, the string name given in ``column`` is 

3390 the rendered name of the referenced column, not its locally 

3391 assigned ``key``. 

3392 

3393 :param use_alter: passed to the underlying 

3394 :class:`_schema.ForeignKeyConstraint` 

3395 to indicate the constraint should 

3396 be generated/dropped externally from the CREATE TABLE/ DROP TABLE 

3397 statement. See :paramref:`_schema.ForeignKeyConstraint.use_alter` 

3398 for further description. 

3399 

3400 .. seealso:: 

3401 

3402 :paramref:`_schema.ForeignKeyConstraint.use_alter` 

3403 

3404 :ref:`use_alter` 

3405 

3406 :param match: Optional string. If set, emit MATCH <value> when issuing 

3407 DDL for this constraint. Typical values include SIMPLE, PARTIAL 

3408 and FULL. 

3409 

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

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

3412 

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

3414 foreign key constraint creation. 

3415 

3416 .. versionadded:: 2.0 

3417 

3418 :param \**dialect_kw: Additional keyword arguments are dialect 

3419 specific, and passed in the form ``<dialectname>_<argname>``. The 

3420 arguments are ultimately handled by a corresponding 

3421 :class:`_schema.ForeignKeyConstraint`. 

3422 See the documentation regarding 

3423 an individual dialect at :ref:`dialect_toplevel` for detail on 

3424 documented arguments. 

3425 

3426 """ 

3427 

3428 self._unresolvable = _unresolvable 

3429 

3430 self._table_column, self._given_tokens = self._parse_colspec_argument( 

3431 column 

3432 ) 

3433 

3434 # the linked ForeignKeyConstraint. 

3435 # ForeignKey will create this when parent Column 

3436 # is attached to a Table, *or* ForeignKeyConstraint 

3437 # object passes itself in when creating ForeignKey 

3438 # markers. 

3439 self.constraint = _constraint 

3440 

3441 # .parent is not Optional under normal use 

3442 self.parent = None # type: ignore[assignment] 

3443 

3444 self.use_alter = use_alter 

3445 self.name = name 

3446 self.onupdate = onupdate 

3447 self.ondelete = ondelete 

3448 self.deferrable = deferrable 

3449 self.initially = initially 

3450 self.link_to_name = link_to_name 

3451 self.match = match 

3452 self.comment = comment 

3453 if info: 

3454 self.info = info 

3455 self._unvalidated_dialect_kw = dialect_kw 

3456 

3457 def _parse_colspec_argument( 

3458 self, 

3459 argument: _DDLColumnReferenceArgument, 

3460 ) -> Tuple[Optional[Column[Any]], ForeignKeyTarget]: 

3461 """Coerce the ``column`` argument into the target 

3462 :class:`.ForeignKeyTarget`, along with the target :class:`.Column` 

3463 itself if that's how the target was given. 

3464 

3465 """ 

3466 if isinstance(argument, tuple): 

3467 return None, ForeignKeyTarget._from_argument(argument) 

3468 

3469 _colspec = coercions.expect(roles.DDLReferredColumnRole, argument) 

3470 

3471 if isinstance(_colspec, str): 

3472 return None, ForeignKeyTarget._from_string(_colspec) 

3473 

3474 assert isinstance(_colspec, ColumnClause) 

3475 

3476 table = _colspec.table 

3477 if not isinstance(table, (type(None), TableClause)): 

3478 # a Column of some other FromClause, e.g. a subquery or a join; 

3479 # the target of a ForeignKey has to be a Table (or a TableClause, 

3480 # or a Column not yet associated with either) 

3481 raise exc.ArgumentError( 

3482 f"ForeignKey target Column {_colspec!r} is associated with " 

3483 f"{table!r}, which is not a Table; a foreign key may only " 

3484 f"target a Column of a Table" 

3485 ) 

3486 elif table is None: 

3487 # a Column not yet associated with a Table; this is the 

3488 # declarative mixin + declared_attr case, where the target column 

3489 # is attached to its Table after this ForeignKey is constructed 

3490 return _colspec, ForeignKeyTarget(None, _colspec.key, None) 

3491 else: 

3492 return _colspec, ForeignKeyTarget( 

3493 table.schema, table.name, _colspec.key 

3494 ) 

3495 

3496 def __repr__(self) -> str: 

3497 tokens = self.target_tokens 

3498 tokens_no_dots = self.target_tokens._tokens_no_dots() 

3499 

3500 if tokens_no_dots: 

3501 return f"ForeignKey({'.'.join(tokens_no_dots)!r})" 

3502 else: 

3503 # no string form for this target, so name the tokens; this still 

3504 # round trips, as ForeignKeyTarget is accepted by the constructor 

3505 return f"ForeignKey({tokens!r})" 

3506 

3507 @util.deprecated( 

3508 "1.4", 

3509 "The :meth:`_schema.ForeignKey.copy` method is deprecated " 

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

3511 ) 

3512 def copy(self, *, schema: Optional[str] = None, **kw: Any) -> ForeignKey: 

3513 return self._copy(schema=schema, **kw) 

3514 

3515 def _copy(self, *, schema: Optional[str] = None, **kw: Any) -> ForeignKey: 

3516 """Produce a copy of this :class:`_schema.ForeignKey` object. 

3517 

3518 The new :class:`_schema.ForeignKey` will not be bound 

3519 to any :class:`_schema.Column`. 

3520 

3521 This method is usually used by the internal 

3522 copy procedures of :class:`_schema.Column`, :class:`_schema.Table`, 

3523 and :class:`_schema.MetaData`. 

3524 

3525 :param schema: The returned :class:`_schema.ForeignKey` will 

3526 reference the original table and column name, qualified 

3527 by the given string schema name. 

3528 

3529 """ 

3530 fk = ForeignKey( 

3531 self._copy_tokens(schema=schema), 

3532 use_alter=self.use_alter, 

3533 name=self.name, 

3534 onupdate=self.onupdate, 

3535 ondelete=self.ondelete, 

3536 deferrable=self.deferrable, 

3537 initially=self.initially, 

3538 link_to_name=self.link_to_name, 

3539 match=self.match, 

3540 comment=self.comment, 

3541 **self._unvalidated_dialect_kw, 

3542 ) 

3543 return self._schema_item_copy(fk) 

3544 

3545 @property 

3546 def target_tokens(self) -> ForeignKeyTarget: 

3547 """Return the target of this :class:`_schema.ForeignKey` as three 

3548 individual name tokens. 

3549 

3550 The return value is a :class:`_schema.ForeignKeyTarget` named tuple of 

3551 ``(schema, table_name, column_name)``. This is the representation 

3552 SQLAlchemy itself computes against; unlike 

3553 :attr:`_schema.ForeignKey.target_fullname` it is available in all 

3554 cases, including when one of the names contains a dot:: 

3555 

3556 >>> from sqlalchemy import Column, ForeignKey, Integer, MetaData, Table 

3557 >>> m = MetaData() 

3558 >>> r = Table("my.tbl", m, Column("z", Integer, primary_key=True)) 

3559 >>> t = Table("t", m, Column("a", Integer, ForeignKey(r.c.z))) 

3560 >>> list(t.c.a.foreign_keys)[0].target_tokens 

3561 ForeignKeyTarget(schema=None, table_name='my.tbl', column_name='z') 

3562 

3563 The tokens describe the target as it was specified, and are available 

3564 whether or not the target :class:`_schema.Column` has been resolved; 

3565 for the resolved column, see :attr:`_schema.ForeignKey.column`. 

3566 

3567 .. versionadded:: 2.1 

3568 

3569 .. seealso:: 

3570 

3571 :class:`_schema.ForeignKeyTarget` 

3572 

3573 """ # noqa: E501 

3574 

3575 col = self._table_column 

3576 if col is None: 

3577 assert self._given_tokens is not None 

3578 return self._given_tokens 

3579 

3580 # derived on demand rather than captured up front: a target Column 

3581 # may gain both its name and its Table *after* this ForeignKey is 

3582 # constructed, which is what a declarative mixin using declared_attr 

3583 # does (see test_fk_mixin_self_referential_declared_attr) 

3584 table = col.table 

3585 if table is None: 

3586 return ForeignKeyTarget(None, col.key, None) 

3587 

3588 return ForeignKeyTarget(table.schema, table.name, col.key) 

3589 

3590 @property 

3591 def target_column(self) -> Optional[Column[Any]]: 

3592 """Return the target :class:`_schema.Column` of this 

3593 :class:`_schema.ForeignKey`, if the target was given as one. 

3594 

3595 Returns ``None`` when the target was instead given by name, as a 

3596 string or as :class:`_schema.ForeignKeyTarget`; in that case only 

3597 :attr:`_schema.ForeignKey.target_tokens` describes the target until 

3598 it is resolved. 

3599 

3600 This is distinct from :attr:`_schema.ForeignKey.column`, which is the 

3601 *resolved* target however it was specified, and which raises if the 

3602 target can't be resolved. Note also that a target given as a 

3603 :class:`_schema.Column` need not be associated with a 

3604 :class:`_schema.Table` yet. 

3605 

3606 .. versionadded:: 2.1 

3607 

3608 .. seealso:: 

3609 

3610 :attr:`_schema.ForeignKey.target_tokens` 

3611 

3612 :attr:`_schema.ForeignKey.column` 

3613 

3614 """ 

3615 return self._table_column 

3616 

3617 @property 

3618 def _column_tokens(self) -> ForeignKeyTarget: 

3619 """legacy private name for :attr:`.ForeignKey.target_tokens`""" 

3620 

3621 return self.target_tokens 

3622 

3623 @property 

3624 def _colspec(self) -> Union[str, Column[Any]]: 

3625 """Legacy accessor for the target in its pre-2.1 form, either the 

3626 target :class:`.Column` or a dotted string. 

3627 

3628 Raises :class:`.InvalidRequestError` for a target which has no dotted 

3629 string form. Kept for the benefit of third party code which reads it; 

3630 :attr:`.ForeignKey.target_tokens` is what SQLAlchemy itself uses. 

3631 

3632 """ 

3633 col = self.target_column 

3634 return self.target_tokens._as_string() if col is None else col 

3635 

3636 def _copy_tokens( 

3637 self, 

3638 schema: Optional[ 

3639 Union[ 

3640 str, 

3641 Literal[SchemaConst.RETAIN_SCHEMA, SchemaConst.BLANK_SCHEMA], 

3642 ] 

3643 ] = None, 

3644 table_name: Optional[str] = None, 

3645 _is_copy: bool = False, 

3646 ) -> ForeignKeyTarget: 

3647 """Return the tokens for a copy of this :class:`_schema.ForeignKey`, 

3648 optionally rewriting the schema and/or table name. 

3649 

3650 """ 

3651 

3652 col = self.target_column 

3653 

3654 if _is_copy and col is not None and col.table is None: 

3655 raise exc.InvalidRequestError( 

3656 f"Can't copy ForeignKey object which refers to " 

3657 f"non-table bound Column {col!r}" 

3658 ) 

3659 

3660 tokens = self.target_tokens 

3661 

3662 if schema not in (None, RETAIN_SCHEMA): 

3663 return ForeignKeyTarget( 

3664 None if schema is BLANK_SCHEMA else schema, 

3665 table_name if table_name is not None else tokens.table_name, 

3666 tokens.column_name, 

3667 ) 

3668 elif table_name: 

3669 return tokens._replace(table_name=table_name) 

3670 else: 

3671 return tokens 

3672 

3673 def _get_colspec(self) -> str: 

3674 """legacy method for :attr:`.ForeignKey.target_fullname`. 

3675 

3676 Retained as third party code makes use of it; new code should use 

3677 :attr:`.ForeignKey.target_tokens`. 

3678 

3679 """ 

3680 

3681 return self.target_fullname 

3682 

3683 @property 

3684 def _referred_schema(self) -> Optional[str]: 

3685 return self.target_tokens.schema 

3686 

3687 @property 

3688 def target_table_key(self) -> Optional[str]: 

3689 """Return the key under which the target :class:`_schema.Table` is, 

3690 or would be, registered in :attr:`_schema.MetaData.tables`. 

3691 

3692 This is derived from :attr:`_schema.ForeignKey.target_tokens`, and is 

3693 available whether or not the target table exists yet, making it 

3694 usable while a :class:`_schema.Table` is still being constructed. 

3695 

3696 Returns ``None`` in the one case where no key can be named: the 

3697 target was given as a :class:`_schema.Column` which is not yet 

3698 associated with a :class:`_schema.Table`. 

3699 

3700 .. versionadded:: 2.1 

3701 

3702 .. seealso:: 

3703 

3704 :attr:`_schema.ForeignKey.target_tokens` 

3705 

3706 """ 

3707 col = self.target_column 

3708 if col is not None and col.table is None: 

3709 # target Column not yet associated with a Table, so there is no 

3710 # key to report; the tokens name the column, not a table 

3711 return None 

3712 

3713 schema, tname, colname = self.target_tokens 

3714 return _get_table_key(tname, schema) 

3715 

3716 @property 

3717 def target_fullname(self) -> str: 

3718 """Return the target of this :class:`_schema.ForeignKey` as a single 

3719 dotted string, e.g. ``"schema.tablename.columnname"``. 

3720 

3721 This is usually the equivalent of the string-based 

3722 ``"tablename.colname"`` argument first passed to the object's 

3723 constructor. 

3724 

3725 .. versionchanged:: 2.1 This attribute raises 

3726 :class:`.InvalidRequestError` when the target table or column name 

3727 itself contains a dot, as a dotted string can't distinguish such a 

3728 name from the separator between names. The dotted form is now a 

3729 legacy convenience; :attr:`_schema.ForeignKey.target_tokens` is the 

3730 representation that is available in all cases, and is what 

3731 SQLAlchemy itself makes use of. 

3732 

3733 .. seealso:: 

3734 

3735 :attr:`_schema.ForeignKey.target_tokens` 

3736 

3737 """ 

3738 return self.target_tokens._as_string() 

3739 

3740 def references(self, table: Table) -> bool: 

3741 """Return True if the given :class:`_schema.Table` 

3742 is referenced by this 

3743 :class:`_schema.ForeignKey`.""" 

3744 

3745 return table.corresponding_column(self.column) is not None 

3746 

3747 def get_referent(self, table: FromClause) -> Optional[Column[Any]]: 

3748 """Return the :class:`_schema.Column` in the given 

3749 :class:`_schema.Table` (or any :class:`.FromClause`) 

3750 referenced by this :class:`_schema.ForeignKey`. 

3751 

3752 Returns None if this :class:`_schema.ForeignKey` 

3753 does not reference the given 

3754 :class:`_schema.Table`. 

3755 

3756 """ 

3757 # our column is a Column, and any subquery etc. proxying us 

3758 # would be doing so via another Column, so that's what would 

3759 # be returned here 

3760 return table.columns.corresponding_column(self.column) # type: ignore[return-value] # noqa: E501 

3761 

3762 def _resolve_col_tokens(self) -> Tuple[Table, str, Optional[str]]: 

3763 if self.parent is None: 

3764 raise exc.InvalidRequestError( 

3765 "this ForeignKey object does not yet have a " 

3766 "parent Column associated with it." 

3767 ) 

3768 

3769 elif self.parent.table is None: 

3770 raise exc.InvalidRequestError( 

3771 "this ForeignKey's parent column is not yet associated " 

3772 "with a Table." 

3773 ) 

3774 

3775 parenttable = self.parent.table 

3776 

3777 if self._unresolvable: 

3778 schema, tname, colname = self.target_tokens 

3779 tablekey = _get_table_key(tname, schema) 

3780 return parenttable, tablekey, colname 

3781 

3782 # assertion 

3783 # basically Column._make_proxy() sends the actual 

3784 # target Column to the ForeignKey object, so the 

3785 # string resolution here is never called. 

3786 for c in self.parent.base_columns: 

3787 if isinstance(c, Column): 

3788 assert c.table is parenttable 

3789 break 

3790 else: 

3791 assert False 

3792 ###################### 

3793 

3794 schema, tname, colname = self.target_tokens 

3795 

3796 if schema is None and parenttable.metadata.schema is not None: 

3797 schema = parenttable.metadata.schema 

3798 

3799 tablekey = _get_table_key(tname, schema) 

3800 return parenttable, tablekey, colname 

3801 

3802 def _link_to_col_by_colstring( 

3803 self, parenttable: Table, table: Table, colname: Optional[str] 

3804 ) -> Column[Any]: 

3805 _column = None 

3806 if colname is None: 

3807 # colname is None in the case that ForeignKey argument 

3808 # was specified as table name only, in which case we 

3809 # match the column name to the same column on the 

3810 # parent. 

3811 # this use case wasn't working in later 1.x series 

3812 # as it had no test coverage; fixed in 2.0 

3813 parent = self.parent 

3814 assert parent is not None 

3815 key = parent.key 

3816 _column = table.c.get(key, None) 

3817 elif self.link_to_name: 

3818 key = colname 

3819 for c in table.c: 

3820 if c.name == colname: 

3821 _column = c 

3822 else: 

3823 key = colname 

3824 _column = table.c.get(colname, None) 

3825 

3826 if _column is None: 

3827 raise exc.NoReferencedColumnError( 

3828 "Could not initialize target column " 

3829 f"for ForeignKey {self.target_tokens._description()} " 

3830 f"on table '{parenttable.name}': " 

3831 f"table '{table.name}' has no column named '{key}'", 

3832 table.name, 

3833 key, 

3834 ) 

3835 

3836 return _column 

3837 

3838 def _set_target_column(self, column: Column[Any]) -> None: 

3839 assert self.parent is not None 

3840 

3841 # propagate TypeEngine to parent if it didn't have one 

3842 if self.parent.type._isnull: 

3843 self.parent.type = column.type 

3844 

3845 # super-edgy case, if other FKs point to our column, 

3846 # they'd get the type propagated out also. 

3847 

3848 def set_type(fk: ForeignKey) -> None: 

3849 if fk.parent.type._isnull: 

3850 fk.parent.type = column.type 

3851 

3852 self.parent._setup_on_memoized_fks(set_type) 

3853 

3854 self.column = column # type: ignore[misc] 

3855 

3856 @util.ro_memoized_property 

3857 def column(self) -> Column[Any]: 

3858 """Return the target :class:`_schema.Column` referenced by this 

3859 :class:`_schema.ForeignKey`. 

3860 

3861 If no target column has been established, an exception 

3862 is raised. 

3863 

3864 """ 

3865 return self._resolve_column() 

3866 

3867 @overload 

3868 def _resolve_column( 

3869 self, *, raiseerr: Literal[True] = ... 

3870 ) -> Column[Any]: ... 

3871 

3872 @overload 

3873 def _resolve_column( 

3874 self, *, raiseerr: bool = ... 

3875 ) -> Optional[Column[Any]]: ... 

3876 

3877 def _resolve_column( 

3878 self, *, raiseerr: bool = True 

3879 ) -> Optional[Column[Any]]: 

3880 target_column = self.target_column 

3881 

3882 if target_column is None: 

3883 parenttable, tablekey, colname = self._resolve_col_tokens() 

3884 

3885 if self._unresolvable or tablekey not in parenttable.metadata: 

3886 if not raiseerr: 

3887 return None 

3888 raise exc.NoReferencedTableError( 

3889 f"Foreign key associated with column " 

3890 f"'{self.parent}' could not find " 

3891 f"table '{tablekey}' with which to generate a " 

3892 f"foreign key to target column '{colname}'", 

3893 tablekey, 

3894 ) 

3895 elif parenttable.key not in parenttable.metadata: 

3896 if not raiseerr: 

3897 return None 

3898 raise exc.InvalidRequestError( 

3899 f"Table {parenttable} is no longer associated with its " 

3900 "parent MetaData" 

3901 ) 

3902 else: 

3903 table = parenttable.metadata.tables[tablekey] 

3904 return self._link_to_col_by_colstring( 

3905 parenttable, table, colname 

3906 ) 

3907 

3908 else: 

3909 assert target_column is not None 

3910 return target_column 

3911 

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

3913 assert isinstance(parent, Column) 

3914 

3915 if self.parent is not None and self.parent is not parent: 

3916 raise exc.InvalidRequestError( 

3917 "This ForeignKey already has a parent !" 

3918 ) 

3919 self.parent = parent 

3920 self.parent.foreign_keys.add(self) 

3921 self.parent._on_table_attach(self._set_table) 

3922 

3923 def _set_remote_table(self, table: Table) -> None: 

3924 parenttable, _, colname = self._resolve_col_tokens() 

3925 _column = self._link_to_col_by_colstring(parenttable, table, colname) 

3926 self._set_target_column(_column) 

3927 assert self.constraint is not None 

3928 self.constraint._validate_dest_table(table) 

3929 

3930 def _remove_from_metadata(self, metadata: MetaData) -> None: 

3931 parenttable, table_key, colname = self._resolve_col_tokens() 

3932 fk_key = (table_key, colname) 

3933 

3934 if self in metadata._fk_memos[fk_key]: 

3935 # TODO: no test coverage for self not in memos 

3936 metadata._fk_memos[fk_key].remove(self) 

3937 

3938 def _set_table(self, column: Column[Any], table: Table) -> None: 

3939 # standalone ForeignKey - create ForeignKeyConstraint 

3940 # on the hosting Table when attached to the Table. 

3941 assert isinstance(table, Table) 

3942 if self.constraint is None: 

3943 self.constraint = ForeignKeyConstraint( 

3944 [], 

3945 [], 

3946 use_alter=self.use_alter, 

3947 name=self.name, 

3948 onupdate=self.onupdate, 

3949 ondelete=self.ondelete, 

3950 deferrable=self.deferrable, 

3951 initially=self.initially, 

3952 match=self.match, 

3953 comment=self.comment, 

3954 **self._unvalidated_dialect_kw, 

3955 ) 

3956 self.constraint._append_element(column, self) 

3957 self.constraint._set_parent_with_dispatch(table) 

3958 table.foreign_keys.add(self) 

3959 # set up remote ".column" attribute, or a note to pick it 

3960 # up when the other Table/Column shows up 

3961 

3962 target_column = self.target_column 

3963 if target_column is None: 

3964 parenttable, table_key, colname = self._resolve_col_tokens() 

3965 fk_key = (table_key, colname) 

3966 if table_key in parenttable.metadata.tables: 

3967 table = parenttable.metadata.tables[table_key] 

3968 try: 

3969 _column = self._link_to_col_by_colstring( 

3970 parenttable, table, colname 

3971 ) 

3972 except exc.NoReferencedColumnError: 

3973 # this is OK, we'll try later 

3974 pass 

3975 else: 

3976 self._set_target_column(_column) 

3977 

3978 parenttable.metadata._fk_memos[fk_key].append(self) 

3979 else: 

3980 self._set_target_column(target_column) 

3981 

3982 

3983if TYPE_CHECKING: 

3984 

3985 def default_is_sequence( 

3986 obj: Optional[DefaultGenerator], 

3987 ) -> TypeGuard[Sequence]: ... 

3988 

3989 def default_is_clause_element( 

3990 obj: Optional[DefaultGenerator], 

3991 ) -> TypeGuard[ColumnElementColumnDefault]: ... 

3992 

3993 def default_is_scalar( 

3994 obj: Optional[DefaultGenerator], 

3995 ) -> TypeGuard[ScalarElementColumnDefault]: ... 

3996 

3997else: 

3998 default_is_sequence = operator.attrgetter("is_sequence") 

3999 

4000 default_is_clause_element = operator.attrgetter("is_clause_element") 

4001 

4002 default_is_scalar = operator.attrgetter("is_scalar") 

4003 

4004 

4005class DefaultGenerator(Executable, SchemaItem): 

4006 """Base class for column *default* values. 

4007 

4008 This object is only present on column.default or column.onupdate. 

4009 It's not valid as a server default. 

4010 

4011 """ 

4012 

4013 __visit_name__ = "default_generator" 

4014 

4015 _is_default_generator = True 

4016 is_sequence = False 

4017 is_identity = False 

4018 is_server_default = False 

4019 is_clause_element = False 

4020 is_callable = False 

4021 is_scalar = False 

4022 has_arg = False 

4023 is_sentinel = False 

4024 _is_monotonic_fn = False 

4025 column: Optional[Column[Any]] 

4026 

4027 def __init__(self, for_update: bool = False) -> None: 

4028 self.for_update = for_update 

4029 

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

4031 if TYPE_CHECKING: 

4032 assert isinstance(parent, Column) 

4033 self.column = parent 

4034 if self.for_update: 

4035 self.column.onupdate = self 

4036 else: 

4037 self.column.default = self 

4038 

4039 def _copy(self) -> DefaultGenerator: 

4040 raise NotImplementedError() 

4041 

4042 def _execute_on_connection( 

4043 self, 

4044 connection: Connection, 

4045 distilled_params: _CoreMultiExecuteParams, 

4046 execution_options: CoreExecuteOptionsParameter, 

4047 ) -> Any: 

4048 util.warn_deprecated( 

4049 "Using the .execute() method to invoke a " 

4050 "DefaultGenerator object is deprecated; please use " 

4051 "the .scalar() method.", 

4052 "2.0", 

4053 ) 

4054 return self._execute_on_scalar( 

4055 connection, distilled_params, execution_options 

4056 ) 

4057 

4058 def _execute_on_scalar( 

4059 self, 

4060 connection: Connection, 

4061 distilled_params: _CoreMultiExecuteParams, 

4062 execution_options: CoreExecuteOptionsParameter, 

4063 ) -> Any: 

4064 return connection._execute_default( 

4065 self, distilled_params, execution_options 

4066 ) 

4067 

4068 

4069class ColumnDefault(DefaultGenerator, ABC): 

4070 """A plain default value on a column. 

4071 

4072 This could correspond to a constant, a callable function, 

4073 or a SQL clause. 

4074 

4075 :class:`.ColumnDefault` is generated automatically 

4076 whenever the ``default``, ``onupdate`` arguments of 

4077 :class:`_schema.Column` are used. A :class:`.ColumnDefault` 

4078 can be passed positionally as well. 

4079 

4080 For example, the following:: 

4081 

4082 Column("foo", Integer, default=50) 

4083 

4084 Is equivalent to:: 

4085 

4086 Column("foo", Integer, ColumnDefault(50)) 

4087 

4088 """ 

4089 

4090 arg: Any 

4091 

4092 _is_monotonic_fn = False 

4093 

4094 @overload 

4095 def __new__( 

4096 cls, arg: Callable[..., Any], for_update: bool = ... 

4097 ) -> CallableColumnDefault: ... 

4098 

4099 @overload 

4100 def __new__( 

4101 cls, arg: ColumnElement[Any], for_update: bool = ... 

4102 ) -> ColumnElementColumnDefault: ... 

4103 

4104 # if I return ScalarElementColumnDefault here, which is what's actually 

4105 # returned, mypy complains that 

4106 # overloads overlap w/ incompatible return types. 

4107 @overload 

4108 def __new__(cls, arg: object, for_update: bool = ...) -> ColumnDefault: ... 

4109 

4110 def __new__( 

4111 cls, arg: Any = None, for_update: bool = False 

4112 ) -> ColumnDefault: 

4113 """Construct a new :class:`.ColumnDefault`. 

4114 

4115 

4116 :param arg: argument representing the default value. 

4117 May be one of the following: 

4118 

4119 * a plain non-callable Python value, such as a 

4120 string, integer, boolean, or other simple type. 

4121 The default value will be used as is each time. 

4122 * a SQL expression, that is one which derives from 

4123 :class:`_expression.ColumnElement`. The SQL expression will 

4124 be rendered into the INSERT or UPDATE statement, 

4125 or in the case of a primary key column when 

4126 RETURNING is not used may be 

4127 pre-executed before an INSERT within a SELECT. 

4128 * A Python callable. The function will be invoked for each 

4129 new row subject to an INSERT or UPDATE. 

4130 The callable must accept exactly 

4131 zero or one positional arguments. The one-argument form 

4132 will receive an instance of the :class:`.ExecutionContext`, 

4133 which provides contextual information as to the current 

4134 :class:`_engine.Connection` in use as well as the current 

4135 statement and parameters. 

4136 

4137 """ 

4138 

4139 if isinstance(arg, FetchedValue): 

4140 raise exc.ArgumentError( 

4141 "ColumnDefault may not be a server-side default type." 

4142 ) 

4143 elif callable(arg): 

4144 cls = CallableColumnDefault 

4145 elif isinstance(arg, ClauseElement): 

4146 cls = ColumnElementColumnDefault 

4147 elif arg is not None: 

4148 cls = ScalarElementColumnDefault 

4149 

4150 return object.__new__(cls) 

4151 

4152 def compare(self, other: ColumnDefault) -> bool: 

4153 """Compare this :class:`.ColumnDefault` to another 

4154 :class:`.ColumnDefault`. 

4155 

4156 Returns True if both objects are of the same type, both apply to 

4157 INSERT or both apply to UPDATE, and both represent the same default 

4158 as determined by :meth:`.ColumnDefault.compare_argument`. 

4159 

4160 .. versionadded:: 2.1.7 

4161 

4162 """ 

4163 return ( 

4164 self.__class__ is other.__class__ 

4165 and self.for_update == other.for_update 

4166 and self.compare_argument(other._given_arg) 

4167 ) 

4168 

4169 def compare_argument(self, argument: Any) -> bool: 

4170 """Compare the default represented by this :class:`.ColumnDefault` 

4171 to the given argument, in the form that would be passed to 

4172 :class:`.ColumnDefault` or :paramref:`_schema.Column.default`. 

4173 

4174 Returns True for a plain Python value that is equal to this 

4175 default's value, a SQL expression that compares as equal to this 

4176 default's expression using :meth:`_expression.ClauseElement.compare`, 

4177 or the same Python callable as this default's callable. 

4178 

4179 .. versionadded:: 2.1.7 

4180 

4181 """ 

4182 raise NotImplementedError() 

4183 

4184 @property 

4185 def _given_arg(self) -> Any: 

4186 """the argument as it was passed to the constructor""" 

4187 return self.arg 

4188 

4189 def __repr__(self) -> str: 

4190 return f"{self.__class__.__name__}({self.arg!r})" 

4191 

4192 

4193class ScalarElementColumnDefault(ColumnDefault): 

4194 """default generator for a fixed scalar Python value 

4195 

4196 .. versionadded:: 2.0 

4197 

4198 """ 

4199 

4200 is_scalar = True 

4201 has_arg = True 

4202 

4203 def __init__(self, arg: Any, for_update: bool = False) -> None: 

4204 self.for_update = for_update 

4205 self.arg = arg 

4206 

4207 def _copy(self) -> ScalarElementColumnDefault: 

4208 return ScalarElementColumnDefault( 

4209 arg=self.arg, for_update=self.for_update 

4210 ) 

4211 

4212 def compare_argument(self, argument: Any) -> bool: 

4213 return self.arg is argument or ( 

4214 not callable(argument) 

4215 and not isinstance(argument, ClauseElement) 

4216 and bool(self.arg == argument) 

4217 ) 

4218 

4219 

4220class _InsertSentinelColumnDefault(ColumnDefault): 

4221 """Default generator that's specific to the use of a "sentinel" column 

4222 when using the insertmanyvalues feature. 

4223 

4224 This default is used as part of the :func:`_schema.insert_sentinel` 

4225 construct. 

4226 

4227 """ 

4228 

4229 is_sentinel = True 

4230 for_update = False 

4231 arg = None 

4232 

4233 def __new__(cls) -> _InsertSentinelColumnDefault: 

4234 return object.__new__(cls) 

4235 

4236 def __init__(self) -> None: 

4237 pass 

4238 

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

4240 col = cast("Column[Any]", parent) 

4241 if not col._insert_sentinel: 

4242 raise exc.ArgumentError( 

4243 "The _InsertSentinelColumnDefault may only be applied to a " 

4244 "Column marked as insert_sentinel=True" 

4245 ) 

4246 elif not col.nullable: 

4247 raise exc.ArgumentError( 

4248 "The _InsertSentinelColumnDefault may only be applied to a " 

4249 "Column that is nullable" 

4250 ) 

4251 

4252 super()._set_parent(parent, **kw) 

4253 

4254 def _copy(self) -> _InsertSentinelColumnDefault: 

4255 return _InsertSentinelColumnDefault() 

4256 

4257 def compare_argument(self, argument: Any) -> bool: 

4258 return argument is None 

4259 

4260 

4261_SQLExprDefault = Union["ColumnElement[Any]", "TextClause"] 

4262 

4263 

4264class ColumnElementColumnDefault(ColumnDefault): 

4265 """default generator for a SQL expression 

4266 

4267 .. versionadded:: 2.0 

4268 

4269 """ 

4270 

4271 is_clause_element = True 

4272 has_arg = True 

4273 arg: _SQLExprDefault 

4274 

4275 def __init__( 

4276 self, 

4277 arg: _SQLExprDefault, 

4278 for_update: bool = False, 

4279 ) -> None: 

4280 self.for_update = for_update 

4281 self.arg = arg 

4282 

4283 def _copy(self) -> ColumnElementColumnDefault: 

4284 return ColumnElementColumnDefault( 

4285 arg=self.arg, for_update=self.for_update 

4286 ) 

4287 

4288 def compare_argument(self, argument: Any) -> bool: 

4289 return isinstance(argument, ClauseElement) and self.arg.compare( 

4290 argument 

4291 ) 

4292 

4293 @util.memoized_property 

4294 @util.preload_module("sqlalchemy.sql.functions") 

4295 def _is_monotonic_fn(self) -> bool: 

4296 functions = util.preloaded.sql_functions 

4297 return ( 

4298 isinstance(self.arg, functions.FunctionElement) 

4299 and self.arg.monotonic 

4300 ) 

4301 

4302 @util.memoized_property 

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

4304 def _arg_is_typed(self) -> bool: 

4305 sqltypes = util.preloaded.sql_sqltypes 

4306 

4307 return not isinstance(self.arg.type, sqltypes.NullType) 

4308 

4309 

4310class _CallableColumnDefaultProtocol(Protocol): 

4311 def __call__(self, context: ExecutionContext) -> Any: ... 

4312 

4313 

4314class CallableColumnDefault(ColumnDefault): 

4315 """default generator for a callable Python function 

4316 

4317 .. versionadded:: 2.0 

4318 

4319 """ 

4320 

4321 is_callable = True 

4322 arg: _CallableColumnDefaultProtocol 

4323 has_arg = True 

4324 

4325 _fn: Union[_CallableColumnDefaultProtocol, Callable[[], Any]] 

4326 

4327 def __init__( 

4328 self, 

4329 arg: Union[_CallableColumnDefaultProtocol, Callable[[], Any]], 

4330 for_update: bool = False, 

4331 ) -> None: 

4332 self.for_update = for_update 

4333 

4334 # the callable as given, before it's possibly wrapped to accept 

4335 # a context 

4336 self._fn = arg 

4337 self.arg = self._maybe_wrap_callable(arg) 

4338 

4339 def _copy(self) -> CallableColumnDefault: 

4340 return CallableColumnDefault(arg=self._fn, for_update=self.for_update) 

4341 

4342 def compare_argument(self, argument: Any) -> bool: 

4343 return argument is self._fn 

4344 

4345 @property 

4346 def _given_arg(self) -> Any: 

4347 return self._fn 

4348 

4349 def _maybe_wrap_callable( 

4350 self, fn: Union[_CallableColumnDefaultProtocol, Callable[[], Any]] 

4351 ) -> _CallableColumnDefaultProtocol: 

4352 """Wrap callables that don't accept a context. 

4353 

4354 This is to allow easy compatibility with default callables 

4355 that aren't specific to accepting of a context. 

4356 

4357 """ 

4358 

4359 try: 

4360 argspec = util.get_callable_argspec(fn, no_self=True) 

4361 except TypeError: 

4362 return util.wrap_callable(lambda ctx: fn(), fn) # type: ignore[call-arg, no-any-return, no-untyped-call] # noqa: E501 

4363 

4364 defaulted = argspec[3] is not None and len(argspec[3]) or 0 

4365 positionals = len(argspec[0]) - defaulted 

4366 

4367 if positionals == 0: 

4368 return util.wrap_callable(lambda ctx: fn(), fn) # type: ignore[call-arg, no-any-return, no-untyped-call] # noqa: E501 

4369 

4370 elif positionals == 1: 

4371 return fn # type: ignore[return-value] 

4372 else: 

4373 raise exc.ArgumentError( 

4374 "ColumnDefault Python function takes zero or one " 

4375 "positional arguments" 

4376 ) 

4377 

4378 

4379class IdentityOptions(DialectKWArgs): 

4380 """Defines options for a named database sequence or an identity column. 

4381 

4382 .. seealso:: 

4383 

4384 :class:`.Sequence` 

4385 

4386 """ 

4387 

4388 def __init__( 

4389 self, 

4390 start: Optional[int] = None, 

4391 increment: Optional[int] = None, 

4392 minvalue: Optional[int] = None, 

4393 maxvalue: Optional[int] = None, 

4394 nominvalue: Optional[bool] = None, 

4395 nomaxvalue: Optional[bool] = None, 

4396 cycle: Optional[bool] = None, 

4397 cache: Optional[int] = None, 

4398 order: Optional[bool] = None, 

4399 **dialect_kw: Any, 

4400 ) -> None: 

4401 """Construct a :class:`.IdentityOptions` object. 

4402 

4403 See the :class:`.Sequence` documentation for a complete description 

4404 of the parameters. 

4405 

4406 :param start: the starting index of the sequence. 

4407 :param increment: the increment value of the sequence. 

4408 :param minvalue: the minimum value of the sequence. 

4409 :param maxvalue: the maximum value of the sequence. 

4410 :param nominvalue: no minimum value of the sequence. 

4411 :param nomaxvalue: no maximum value of the sequence. 

4412 :param cycle: allows the sequence to wrap around when the maxvalue 

4413 or minvalue has been reached. 

4414 :param cache: optional integer value; number of future values in the 

4415 sequence which are calculated in advance. 

4416 :param order: optional boolean value; if ``True``, renders the 

4417 ORDER keyword. 

4418 

4419 .. deprecated:: 2.1 Use ``oracle_order`` instead. 

4420 

4421 """ 

4422 self.start = start 

4423 self.increment = increment 

4424 self.minvalue = minvalue 

4425 self.maxvalue = maxvalue 

4426 self.nominvalue = nominvalue 

4427 self.nomaxvalue = nomaxvalue 

4428 self.cycle = cycle 

4429 self.cache = cache 

4430 if order is not None: 

4431 if "oracle_order" in dialect_kw: 

4432 raise exc.ArgumentError( 

4433 "Cannot specify both 'order' and 'oracle_order'. " 

4434 "Please use only 'oracle_order'." 

4435 ) 

4436 dialect_kw["oracle_order"] = order 

4437 self._validate_dialect_kwargs(dialect_kw) 

4438 

4439 @property 

4440 def _increment_is_negative(self) -> bool: 

4441 return self.increment is not None and self.increment < 0 

4442 

4443 @property 

4444 def order(self) -> Optional[bool]: 

4445 """Alias of the ``dialect_kwargs`` ``'oracle_order'``. 

4446 

4447 .. deprecated:: 2.1 The 'order' attribute is deprecated. 

4448 """ 

4449 value: Optional[bool] = self.dialect_kwargs.get("oracle_order") 

4450 return value 

4451 

4452 def _as_dict(self) -> Dict[str, Any]: 

4453 return { 

4454 k: v 

4455 for k, v in { 

4456 "start": self.start, 

4457 "increment": self.increment, 

4458 "minvalue": self.minvalue, 

4459 "maxvalue": self.maxvalue, 

4460 "nominvalue": self.nominvalue, 

4461 "nomaxvalue": self.nomaxvalue, 

4462 "cycle": self.cycle, 

4463 "cache": self.cache, 

4464 }.items() 

4465 if v != None 

4466 } 

4467 

4468 

4469class Sequence(HasSchemaAttr, IdentityOptions, DefaultGenerator): 

4470 """Represents a named database sequence. 

4471 

4472 The :class:`.Sequence` object represents the name and configurational 

4473 parameters of a database sequence. It also represents 

4474 a construct that can be "executed" by a SQLAlchemy :class:`_engine.Engine` 

4475 or :class:`_engine.Connection`, 

4476 rendering the appropriate "next value" function 

4477 for the target database and returning a result. 

4478 

4479 The :class:`.Sequence` is typically associated with a primary key column:: 

4480 

4481 some_table = Table( 

4482 "some_table", 

4483 metadata, 

4484 Column( 

4485 "id", 

4486 Integer, 

4487 Sequence("some_table_seq", start=1), 

4488 primary_key=True, 

4489 ), 

4490 ) 

4491 

4492 When CREATE TABLE is emitted for the above :class:`_schema.Table`, if the 

4493 target platform supports sequences, a CREATE SEQUENCE statement will 

4494 be emitted as well. For platforms that don't support sequences, 

4495 the :class:`.Sequence` construct is ignored. 

4496 

4497 .. seealso:: 

4498 

4499 :ref:`defaults_sequences` 

4500 

4501 :class:`.CreateSequence` 

4502 

4503 :class:`.DropSequence` 

4504 

4505 """ 

4506 

4507 __visit_name__ = "sequence" 

4508 

4509 is_sequence = True 

4510 

4511 column: Optional[Column[Any]] 

4512 data_type: Optional[TypeEngine[int]] 

4513 

4514 metadata: Optional[MetaData] 

4515 

4516 @util.deprecated_params( 

4517 order=( 

4518 "2.1", 

4519 "This parameter is supported only by Oracle Database, " 

4520 "use ``oracle_order`` instead.", 

4521 ) 

4522 ) 

4523 def __init__( 

4524 self, 

4525 name: str, 

4526 start: Optional[int] = None, 

4527 increment: Optional[int] = None, 

4528 minvalue: Optional[int] = None, 

4529 maxvalue: Optional[int] = None, 

4530 nominvalue: Optional[bool] = None, 

4531 nomaxvalue: Optional[bool] = None, 

4532 cycle: Optional[bool] = None, 

4533 schema: Optional[Union[str, Literal[SchemaConst.BLANK_SCHEMA]]] = None, 

4534 cache: Optional[int] = None, 

4535 order: Optional[bool] = None, 

4536 data_type: Optional[_TypeEngineArgument[int]] = None, 

4537 optional: bool = False, 

4538 quote: Optional[bool] = None, 

4539 metadata: Optional[MetaData] = None, 

4540 quote_schema: Optional[bool] = None, 

4541 for_update: bool = False, 

4542 **dialect_kw: Any, 

4543 ) -> None: 

4544 """Construct a :class:`.Sequence` object. 

4545 

4546 :param name: the name of the sequence. 

4547 

4548 :param start: the starting index of the sequence. This value is 

4549 used when the CREATE SEQUENCE command is emitted to the database 

4550 as the value of the "START WITH" clause. If ``None``, the 

4551 clause is omitted, which on most platforms indicates a starting 

4552 value of 1. 

4553 

4554 .. versionchanged:: 2.0 The :paramref:`.Sequence.start` parameter 

4555 is required in order to have DDL emit "START WITH". This is a 

4556 reversal of a change made in version 1.4 which would implicitly 

4557 render "START WITH 1" if the :paramref:`.Sequence.start` were 

4558 not included. See :ref:`change_7211` for more detail. 

4559 

4560 :param increment: the increment value of the sequence. This 

4561 value is used when the CREATE SEQUENCE command is emitted to 

4562 the database as the value of the "INCREMENT BY" clause. If ``None``, 

4563 the clause is omitted, which on most platforms indicates an 

4564 increment of 1. 

4565 :param minvalue: the minimum value of the sequence. This 

4566 value is used when the CREATE SEQUENCE command is emitted to 

4567 the database as the value of the "MINVALUE" clause. If ``None``, 

4568 the clause is omitted, which on most platforms indicates a 

4569 minvalue of 1 and -2^63-1 for ascending and descending sequences, 

4570 respectively. 

4571 

4572 :param maxvalue: the maximum value of the sequence. This 

4573 value is used when the CREATE SEQUENCE command is emitted to 

4574 the database as the value of the "MAXVALUE" clause. If ``None``, 

4575 the clause is omitted, which on most platforms indicates a 

4576 maxvalue of 2^63-1 and -1 for ascending and descending sequences, 

4577 respectively. 

4578 

4579 :param nominvalue: no minimum value of the sequence. This 

4580 value is used when the CREATE SEQUENCE command is emitted to 

4581 the database as the value of the "NO MINVALUE" clause. If ``None``, 

4582 the clause is omitted, which on most platforms indicates a 

4583 minvalue of 1 and -2^63-1 for ascending and descending sequences, 

4584 respectively. 

4585 

4586 :param nomaxvalue: no maximum value of the sequence. This 

4587 value is used when the CREATE SEQUENCE command is emitted to 

4588 the database as the value of the "NO MAXVALUE" clause. If ``None``, 

4589 the clause is omitted, which on most platforms indicates a 

4590 maxvalue of 2^63-1 and -1 for ascending and descending sequences, 

4591 respectively. 

4592 

4593 :param cycle: allows the sequence to wrap around when the maxvalue 

4594 or minvalue has been reached by an ascending or descending sequence 

4595 respectively. This value is used when the CREATE SEQUENCE command 

4596 is emitted to the database as the "CYCLE" clause. If the limit is 

4597 reached, the next number generated will be the minvalue or maxvalue, 

4598 respectively. If cycle=False (the default) any calls to nextval 

4599 after the sequence has reached its maximum value will return an 

4600 error. 

4601 

4602 :param schema: optional schema name for the sequence, if located 

4603 in a schema other than the default. The rules for selecting the 

4604 schema name when a :class:`_schema.MetaData` 

4605 is also present are the same 

4606 as that of :paramref:`_schema.Table.schema`. 

4607 

4608 :param cache: optional integer value; number of future values in the 

4609 sequence which are calculated in advance. Renders the CACHE keyword 

4610 understood by Oracle Database and PostgreSQL. 

4611 

4612 :param order: optional boolean value; if ``True``, renders the 

4613 ORDER keyword, understood by Oracle Database, indicating the sequence 

4614 is definitively ordered. May be necessary to provide deterministic 

4615 ordering using Oracle RAC. 

4616 

4617 :param data_type: The type to be returned by the sequence, for 

4618 dialects that allow us to choose between INTEGER, BIGINT, etc. 

4619 (e.g., mssql). 

4620 

4621 .. versionadded:: 1.4.0 

4622 

4623 :param optional: boolean value, when ``True``, indicates that this 

4624 :class:`.Sequence` object only needs to be explicitly generated 

4625 on backends that don't provide another way to generate primary 

4626 key identifiers. Currently, it essentially means, "don't create 

4627 this sequence on the PostgreSQL backend, where the SERIAL keyword 

4628 creates a sequence for us automatically". 

4629 :param quote: boolean value, when ``True`` or ``False``, explicitly 

4630 forces quoting of the :paramref:`_schema.Sequence.name` on or off. 

4631 When left at its default of ``None``, normal quoting rules based 

4632 on casing and reserved words take place. 

4633 :param quote_schema: Set the quoting preferences for the ``schema`` 

4634 name. 

4635 

4636 :param metadata: optional :class:`_schema.MetaData` object which this 

4637 :class:`.Sequence` will be associated with. A :class:`.Sequence` 

4638 that is associated with a :class:`_schema.MetaData` 

4639 gains the following 

4640 capabilities: 

4641 

4642 * The :class:`.Sequence` will inherit the 

4643 :paramref:`_schema.MetaData.schema` 

4644 parameter specified to the target :class:`_schema.MetaData`, which 

4645 affects the production of CREATE / DROP DDL, if any. 

4646 

4647 * The :meth:`.Sequence.create` and :meth:`.Sequence.drop` methods 

4648 automatically use the engine bound to the :class:`_schema.MetaData` 

4649 object, if any. 

4650 

4651 * The :meth:`_schema.MetaData.create_all` and 

4652 :meth:`_schema.MetaData.drop_all` 

4653 methods will emit CREATE / DROP for this :class:`.Sequence`, 

4654 even if the :class:`.Sequence` is not associated with any 

4655 :class:`_schema.Table` / :class:`_schema.Column` 

4656 that's a member of this 

4657 :class:`_schema.MetaData`. 

4658 

4659 The above behaviors can only occur if the :class:`.Sequence` is 

4660 explicitly associated with the :class:`_schema.MetaData` 

4661 via this parameter. 

4662 

4663 .. seealso:: 

4664 

4665 :ref:`sequence_metadata` - full discussion of the 

4666 :paramref:`.Sequence.metadata` parameter. 

4667 

4668 :param for_update: Indicates this :class:`.Sequence`, when associated 

4669 with a :class:`_schema.Column`, 

4670 should be invoked for UPDATE statements 

4671 on that column's table, rather than for INSERT statements, when 

4672 no value is otherwise present for that column in the statement. 

4673 

4674 """ 

4675 DefaultGenerator.__init__(self, for_update=for_update) 

4676 IdentityOptions.__init__( 

4677 self, 

4678 start=start, 

4679 increment=increment, 

4680 minvalue=minvalue, 

4681 maxvalue=maxvalue, 

4682 nominvalue=nominvalue, 

4683 nomaxvalue=nomaxvalue, 

4684 cycle=cycle, 

4685 cache=cache, 

4686 order=order, 

4687 **dialect_kw, 

4688 ) 

4689 self.column = None 

4690 self.name = quoted_name(name, quote) 

4691 self.optional = optional 

4692 if schema is BLANK_SCHEMA: 

4693 self.schema = schema = None 

4694 elif metadata is not None and schema is None and metadata.schema: 

4695 self.schema = schema = metadata.schema 

4696 else: 

4697 self.schema = quoted_name.construct(schema, quote_schema) 

4698 self._key = _get_table_key(name, schema) 

4699 if data_type is not None: 

4700 self.data_type = to_instance(data_type) 

4701 else: 

4702 self.data_type = None 

4703 

4704 if metadata: 

4705 self._set_metadata(metadata) 

4706 else: 

4707 self.metadata = None 

4708 

4709 @util.preload_module("sqlalchemy.sql.functions") 

4710 def next_value(self) -> Function[int]: 

4711 """Return a :class:`.next_value` function element 

4712 which will render the appropriate increment function 

4713 for this :class:`.Sequence` within any SQL expression. 

4714 

4715 """ 

4716 return util.preloaded.sql_functions.func.next_value(self) 

4717 

4718 def _copy(self) -> Sequence: 

4719 return Sequence( 

4720 name=self.name, 

4721 schema=self.schema, 

4722 data_type=self.data_type, 

4723 optional=self.optional, 

4724 metadata=None, 

4725 for_update=self.for_update, 

4726 **self._as_dict(), 

4727 **self.dialect_kwargs, 

4728 **self._reflect_only_kwargs, 

4729 ) 

4730 

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

4732 assert isinstance(parent, Column) 

4733 super()._set_parent(parent, **kw) 

4734 parent._on_table_attach(self._set_table) 

4735 

4736 def _set_table(self, column: Column[Any], table: Table) -> None: 

4737 self._set_metadata(table.metadata) 

4738 

4739 def _set_metadata(self, metadata: MetaData) -> None: 

4740 self.metadata = metadata 

4741 self.metadata._register_object(self) 

4742 metadata._sequences[self._key] = self 

4743 

4744 def create( 

4745 self, 

4746 bind: _CreateDropBind, 

4747 checkfirst: Union[bool, CheckFirst] = CheckFirst.SEQUENCES, 

4748 ) -> None: 

4749 """Creates this sequence in the database.""" 

4750 

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

4752 

4753 def drop( 

4754 self, 

4755 bind: _CreateDropBind, 

4756 checkfirst: Union[bool, CheckFirst] = CheckFirst.SEQUENCES, 

4757 ) -> None: 

4758 """Drops this sequence from the database.""" 

4759 

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

4761 

4762 def _not_a_column_expr(self) -> NoReturn: 

4763 raise exc.InvalidRequestError( 

4764 f"This {self.__class__.__name__} cannot be used directly " 

4765 "as a column expression. Use func.next_value(sequence) " 

4766 "to produce a 'next value' function that's usable " 

4767 "as a column element." 

4768 ) 

4769 

4770 

4771@inspection._self_inspects 

4772class FetchedValue(SchemaEventTarget): 

4773 """A marker for a transparent database-side default. 

4774 

4775 Use :class:`.FetchedValue` when the database is configured 

4776 to provide some automatic default for a column. 

4777 

4778 E.g.:: 

4779 

4780 Column("foo", Integer, FetchedValue()) 

4781 

4782 Would indicate that some trigger or default generator 

4783 will create a new value for the ``foo`` column during an 

4784 INSERT. 

4785 

4786 .. seealso:: 

4787 

4788 :ref:`triggered_columns` 

4789 

4790 """ 

4791 

4792 is_server_default = True 

4793 reflected = False 

4794 has_argument = False 

4795 is_clause_element = False 

4796 is_identity = False 

4797 _is_monotonic_fn = False 

4798 

4799 column: Optional[Column[Any]] 

4800 

4801 def __init__(self, for_update: bool = False) -> None: 

4802 self.for_update = for_update 

4803 

4804 def _as_for_update(self, for_update: bool) -> FetchedValue: 

4805 if for_update == self.for_update: 

4806 return self 

4807 else: 

4808 return self._clone(for_update) 

4809 

4810 def _copy(self) -> Self: 

4811 return self._clone(self.for_update) 

4812 

4813 def _clone(self, for_update: bool) -> Self: 

4814 n = self.__class__.__new__(self.__class__) 

4815 n.__dict__.update(self.__dict__) 

4816 n.__dict__.pop("column", None) 

4817 n.for_update = for_update 

4818 return n 

4819 

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

4821 column = parent 

4822 assert isinstance(column, Column) 

4823 self.column = column 

4824 if self.for_update: 

4825 self.column.server_onupdate = self 

4826 else: 

4827 self.column.server_default = self 

4828 

4829 def __repr__(self) -> str: 

4830 return util.generic_repr(self) 

4831 

4832 

4833class DefaultClause(FetchedValue): 

4834 """A DDL-specified DEFAULT column value. 

4835 

4836 :class:`.DefaultClause` is a :class:`.FetchedValue` 

4837 that also generates a "DEFAULT" clause when 

4838 "CREATE TABLE" is emitted. 

4839 

4840 :class:`.DefaultClause` is generated automatically 

4841 whenever the ``server_default``, ``server_onupdate`` arguments of 

4842 :class:`_schema.Column` are used. A :class:`.DefaultClause` 

4843 can be passed positionally as well. 

4844 

4845 For example, the following:: 

4846 

4847 Column("foo", Integer, server_default="50") 

4848 

4849 Is equivalent to:: 

4850 

4851 Column("foo", Integer, DefaultClause("50")) 

4852 

4853 """ 

4854 

4855 has_argument = True 

4856 

4857 def __init__( 

4858 self, 

4859 arg: Union[str, ClauseElement, TextClause], 

4860 for_update: bool = False, 

4861 _reflected: bool = False, 

4862 ) -> None: 

4863 util.assert_arg_type(arg, (str, ClauseElement, TextClause), "arg") 

4864 super().__init__(for_update) 

4865 self.arg = arg 

4866 self.reflected = _reflected 

4867 

4868 @util.memoized_property 

4869 @util.preload_module("sqlalchemy.sql.functions") 

4870 def _is_monotonic_fn(self) -> bool: 

4871 functions = util.preloaded.sql_functions 

4872 return ( 

4873 isinstance(self.arg, functions.FunctionElement) 

4874 and self.arg.monotonic 

4875 ) 

4876 

4877 def __repr__(self) -> str: 

4878 return "DefaultClause(%r, for_update=%r)" % (self.arg, self.for_update) 

4879 

4880 

4881class Constraint(DialectKWArgs, HasConditionalDDL, SchemaItem): 

4882 """A table-level SQL constraint. 

4883 

4884 :class:`_schema.Constraint` serves as the base class for the series of 

4885 constraint objects that can be associated with :class:`_schema.Table` 

4886 objects, including :class:`_schema.PrimaryKeyConstraint`, 

4887 :class:`_schema.ForeignKeyConstraint` 

4888 :class:`_schema.UniqueConstraint`, and 

4889 :class:`_schema.CheckConstraint`. 

4890 

4891 """ 

4892 

4893 __visit_name__ = "constraint" 

4894 

4895 _creation_order: int 

4896 _column_flag: bool 

4897 

4898 def __init__( 

4899 self, 

4900 name: _ConstraintNameArgument = None, 

4901 deferrable: Optional[bool] = None, 

4902 initially: Optional[str] = None, 

4903 info: Optional[_InfoType] = None, 

4904 comment: Optional[str] = None, 

4905 _create_rule: Optional[Any] = None, 

4906 _type_bound: bool = False, 

4907 **dialect_kw: Any, 

4908 ) -> None: 

4909 r"""Create a SQL constraint. 

4910 

4911 :param name: 

4912 Optional, the in-database name of this ``Constraint``. 

4913 

4914 :param deferrable: 

4915 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

4916 issuing DDL for this constraint. 

4917 

4918 :param initially: 

4919 Optional string. If set, emit INITIALLY <value> when issuing DDL 

4920 for this constraint. 

4921 

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

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

4924 

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

4926 foreign key constraint creation. 

4927 

4928 .. versionadded:: 2.0 

4929 

4930 :param \**dialect_kw: Additional keyword arguments are dialect 

4931 specific, and passed in the form ``<dialectname>_<argname>``. See 

4932 the documentation regarding an individual dialect at 

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

4934 

4935 :param _create_rule: 

4936 used internally by some datatypes that also create constraints. 

4937 

4938 :param _type_bound: 

4939 used internally to indicate that this constraint is associated with 

4940 a specific datatype. 

4941 

4942 """ 

4943 

4944 self.name = name 

4945 self.deferrable = deferrable 

4946 self.initially = initially 

4947 if info: 

4948 self.info = info 

4949 self._create_rule = _create_rule 

4950 self._type_bound = _type_bound 

4951 util.set_creation_order(self) 

4952 self._validate_dialect_kwargs(dialect_kw) 

4953 self.comment = comment 

4954 

4955 def _should_create_for_compiler( 

4956 self, compiler: DDLCompiler, **kw: Any 

4957 ) -> bool: 

4958 if self._create_rule is not None and not self._create_rule(compiler): 

4959 return False 

4960 elif self._ddl_if is not None: 

4961 return self._ddl_if._should_execute( 

4962 ddl.CreateConstraint(self), self, None, compiler=compiler, **kw 

4963 ) 

4964 else: 

4965 return True 

4966 

4967 @property 

4968 def table(self) -> Table: 

4969 try: 

4970 if isinstance(self.parent, Table): 

4971 return self.parent 

4972 except AttributeError: 

4973 pass 

4974 raise exc.InvalidRequestError( 

4975 "This constraint is not bound to a table. Did you " 

4976 "mean to call table.append_constraint(constraint) ?" 

4977 ) 

4978 

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

4980 assert isinstance(parent, (Table, Column)) 

4981 self.parent = parent 

4982 parent.constraints.add(self) 

4983 

4984 @util.deprecated( 

4985 "1.4", 

4986 "The :meth:`_schema.Constraint.copy` method is deprecated " 

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

4988 ) 

4989 def copy(self, **kw: Any) -> Self: 

4990 return self._copy(**kw) 

4991 

4992 def _copy(self, **kw: Any) -> Self: 

4993 raise NotImplementedError() 

4994 

4995 

4996class ColumnCollectionMixin: 

4997 """A :class:`_expression.ColumnCollection` of :class:`_schema.Column` 

4998 objects. 

4999 

5000 This collection represents the columns which are referred to by 

5001 this object. 

5002 

5003 """ 

5004 

5005 _columns: WriteableColumnCollection[str, Column[Any]] 

5006 

5007 _column_collection_class: ClassVar[ 

5008 Type[WriteableColumnCollection[Any, Any]] 

5009 ] = DedupeColumnCollection 

5010 

5011 _allow_multiple_tables = False 

5012 

5013 _pending_colargs: List[Optional[Union[str, Column[Any]]]] 

5014 

5015 if TYPE_CHECKING: 

5016 

5017 def _set_parent_with_dispatch( 

5018 self, parent: SchemaEventTarget, **kw: Any 

5019 ) -> None: ... 

5020 

5021 def __init__( 

5022 self, 

5023 *columns: _DDLColumnArgument, 

5024 _autoattach: bool = True, 

5025 _column_flag: bool = False, 

5026 _gather_expressions: Optional[ 

5027 List[Union[str, ColumnElement[Any]]] 

5028 ] = None, 

5029 ) -> None: 

5030 self._column_flag = _column_flag 

5031 self._columns = self._column_collection_class() 

5032 

5033 processed_expressions: Optional[ 

5034 List[Union[ColumnElement[Any], str]] 

5035 ] = _gather_expressions 

5036 

5037 if processed_expressions is not None: 

5038 

5039 # this is expected to be an empty list 

5040 assert not processed_expressions 

5041 

5042 self._pending_colargs = [] 

5043 for ( 

5044 expr, 

5045 _, 

5046 _, 

5047 add_element, 

5048 ) in coercions.expect_col_expression_collection( 

5049 roles.DDLConstraintColumnRole, columns 

5050 ): 

5051 self._pending_colargs.append(add_element) 

5052 processed_expressions.append(expr) 

5053 else: 

5054 self._pending_colargs = [ 

5055 coercions.expect(roles.DDLConstraintColumnRole, column) 

5056 for column in columns 

5057 ] 

5058 

5059 if _autoattach and self._pending_colargs: 

5060 self._check_attach() 

5061 

5062 def _check_attach(self, evt: bool = False) -> None: 

5063 col_objs = [c for c in self._pending_colargs if isinstance(c, Column)] 

5064 

5065 cols_w_table = [c for c in col_objs if isinstance(c.table, Table)] 

5066 

5067 cols_wo_table = set(col_objs).difference(cols_w_table) 

5068 if cols_wo_table: 

5069 # feature #3341 - place event listeners for Column objects 

5070 # such that when all those cols are attached, we autoattach. 

5071 assert not evt, "Should not reach here on event call" 

5072 

5073 # issue #3411 - don't do the per-column auto-attach if some of the 

5074 # columns are specified as strings. 

5075 has_string_cols = { 

5076 c for c in self._pending_colargs if c is not None 

5077 }.difference(col_objs) 

5078 if not has_string_cols: 

5079 

5080 def _col_attached(column: Column[Any], table: Table) -> None: 

5081 # this isinstance() corresponds with the 

5082 # isinstance() above; only want to count Table-bound 

5083 # columns 

5084 if isinstance(table, Table): 

5085 cols_wo_table.discard(column) 

5086 if not cols_wo_table: 

5087 self._check_attach(evt=True) 

5088 

5089 self._cols_wo_table = cols_wo_table 

5090 for col in cols_wo_table: 

5091 col._on_table_attach(_col_attached) 

5092 return 

5093 

5094 columns = cols_w_table 

5095 

5096 tables = {c.table for c in columns} 

5097 if len(tables) == 1: 

5098 self._set_parent_with_dispatch(tables.pop()) 

5099 elif len(tables) > 1 and not self._allow_multiple_tables: 

5100 table = columns[0].table 

5101 others = [c for c in columns[1:] if c.table is not table] 

5102 if others: 

5103 # black could not format this inline 

5104 other_str = ", ".join("'%s'" % c for c in others) 

5105 raise exc.ArgumentError( 

5106 f"Column(s) {other_str} " 

5107 f"are not part of table '{table.description}'." 

5108 ) 

5109 

5110 @util.ro_memoized_property 

5111 def columns(self) -> ReadOnlyColumnCollection[str, Column[Any]]: 

5112 return self._columns.as_readonly() 

5113 

5114 @util.ro_memoized_property 

5115 def c(self) -> ReadOnlyColumnCollection[str, Column[Any]]: 

5116 return self._columns.as_readonly() 

5117 

5118 def _col_expressions( 

5119 self, parent: Union[Table, Column[Any]] 

5120 ) -> List[Optional[Column[Any]]]: 

5121 if isinstance(parent, Column): 

5122 result: List[Optional[Column[Any]]] = [ 

5123 c for c in self._pending_colargs if isinstance(c, Column) 

5124 ] 

5125 assert len(result) == len(self._pending_colargs) 

5126 return result 

5127 else: 

5128 try: 

5129 return [ 

5130 parent.c[col] if isinstance(col, str) else col 

5131 for col in self._pending_colargs 

5132 ] 

5133 except KeyError as ke: 

5134 raise exc.ConstraintColumnNotFoundError( 

5135 f"Can't create {self.__class__.__name__} " 

5136 f"on table '{parent.description}': no column " 

5137 f"named '{ke.args[0]}' is present." 

5138 ) from ke 

5139 

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

5141 assert isinstance(parent, (Table, Column)) 

5142 

5143 for col in self._col_expressions(parent): 

5144 if col is not None: 

5145 self._columns.add(col) 

5146 

5147 

5148class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint): 

5149 """A constraint that proxies a ColumnCollection.""" 

5150 

5151 def __init__( 

5152 self, 

5153 *columns: _DDLColumnArgument, 

5154 name: _ConstraintNameArgument = None, 

5155 deferrable: Optional[bool] = None, 

5156 initially: Optional[str] = None, 

5157 info: Optional[_InfoType] = None, 

5158 _autoattach: bool = True, 

5159 _column_flag: bool = False, 

5160 _gather_expressions: Optional[List[_DDLColumnArgument]] = None, 

5161 **dialect_kw: Any, 

5162 ) -> None: 

5163 r""" 

5164 :param \*columns: 

5165 A sequence of column names or Column objects. 

5166 

5167 :param name: 

5168 Optional, the in-database name of this constraint. 

5169 

5170 :param deferrable: 

5171 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

5172 issuing DDL for this constraint. 

5173 

5174 :param initially: 

5175 Optional string. If set, emit INITIALLY <value> when issuing DDL 

5176 for this constraint. 

5177 

5178 :param \**dialect_kw: other keyword arguments including 

5179 dialect-specific arguments are propagated to the :class:`.Constraint` 

5180 superclass. 

5181 

5182 """ 

5183 Constraint.__init__( 

5184 self, 

5185 name=name, 

5186 deferrable=deferrable, 

5187 initially=initially, 

5188 info=info, 

5189 **dialect_kw, 

5190 ) 

5191 ColumnCollectionMixin.__init__( 

5192 self, *columns, _autoattach=_autoattach, _column_flag=_column_flag 

5193 ) 

5194 

5195 columns: ReadOnlyColumnCollection[str, Column[Any]] 

5196 """A :class:`_expression.ColumnCollection` representing the set of columns 

5197 for this constraint. 

5198 

5199 """ 

5200 

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

5202 assert isinstance(parent, (Column, Table)) 

5203 Constraint._set_parent(self, parent) 

5204 ColumnCollectionMixin._set_parent(self, parent) 

5205 

5206 def __contains__(self, x: Any) -> bool: 

5207 return x in self._columns 

5208 

5209 @util.deprecated( 

5210 "1.4", 

5211 "The :meth:`_schema.ColumnCollectionConstraint.copy` method " 

5212 "is deprecated and will be removed in a future release.", 

5213 ) 

5214 def copy( 

5215 self, 

5216 *, 

5217 target_table: Optional[Table] = None, 

5218 **kw: Any, 

5219 ) -> ColumnCollectionConstraint: 

5220 return self._copy(target_table=target_table, **kw) 

5221 

5222 def _copy( 

5223 self, 

5224 *, 

5225 target_table: Optional[Table] = None, 

5226 **kw: Any, 

5227 ) -> ColumnCollectionConstraint: 

5228 # ticket #5276 

5229 constraint_kwargs = {} 

5230 for dialect_name in self.dialect_options: 

5231 dialect_options = self.dialect_options[dialect_name]._non_defaults 

5232 for ( 

5233 dialect_option_key, 

5234 dialect_option_value, 

5235 ) in dialect_options.items(): 

5236 constraint_kwargs[dialect_name + "_" + dialect_option_key] = ( 

5237 dialect_option_value 

5238 ) 

5239 

5240 assert isinstance(self.parent, Table) 

5241 c = self.__class__( 

5242 name=self.name, 

5243 deferrable=self.deferrable, 

5244 initially=self.initially, 

5245 *[ 

5246 _copy_expression(expr, self.parent, target_table) 

5247 for expr in self._columns 

5248 ], 

5249 comment=self.comment, 

5250 **constraint_kwargs, 

5251 ) 

5252 return self._schema_item_copy(c) 

5253 

5254 def contains_column(self, col: Column[Any]) -> bool: 

5255 """Return True if this constraint contains the given column. 

5256 

5257 Note that this object also contains an attribute ``.columns`` 

5258 which is a :class:`_expression.ColumnCollection` of 

5259 :class:`_schema.Column` objects. 

5260 

5261 """ 

5262 

5263 return self._columns.contains_column(col) 

5264 

5265 def __iter__(self) -> Iterator[Column[Any]]: 

5266 return iter(self._columns) 

5267 

5268 def __len__(self) -> int: 

5269 return len(self._columns) 

5270 

5271 

5272class CheckConstraint(ColumnCollectionConstraint): 

5273 """A table- or column-level CHECK constraint. 

5274 

5275 Can be included in the definition of a Table or Column. 

5276 """ 

5277 

5278 _allow_multiple_tables = True 

5279 

5280 __visit_name__ = "table_or_column_check_constraint" 

5281 

5282 @_document_text_coercion( 

5283 "sqltext", 

5284 ":class:`.CheckConstraint`", 

5285 ":paramref:`.CheckConstraint.sqltext`", 

5286 ) 

5287 def __init__( 

5288 self, 

5289 sqltext: _TextCoercedExpressionArgument[Any], 

5290 name: _ConstraintNameArgument = None, 

5291 deferrable: Optional[bool] = None, 

5292 initially: Optional[str] = None, 

5293 table: Optional[Table] = None, 

5294 info: Optional[_InfoType] = None, 

5295 _create_rule: Optional[Any] = None, 

5296 _autoattach: bool = True, 

5297 _type_bound: bool = False, 

5298 **dialect_kw: Any, 

5299 ) -> None: 

5300 r"""Construct a CHECK constraint. 

5301 

5302 :param sqltext: 

5303 A string containing the constraint definition, which will be used 

5304 verbatim, or a SQL expression construct. If given as a string, 

5305 the object is converted to a :func:`_expression.text` object. 

5306 If the textual 

5307 string includes a colon character, escape this using a backslash:: 

5308 

5309 CheckConstraint(r"foo ~ E'a(?\:b|c)d") 

5310 

5311 :param name: 

5312 Optional, the in-database name of the constraint. 

5313 

5314 :param deferrable: 

5315 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

5316 issuing DDL for this constraint. 

5317 

5318 :param initially: 

5319 Optional string. If set, emit INITIALLY <value> when issuing DDL 

5320 for this constraint. 

5321 

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

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

5324 

5325 """ 

5326 

5327 self.sqltext = coercions.expect(roles.DDLExpressionRole, sqltext) 

5328 columns: List[Column[Any]] = [] 

5329 visitors.traverse(self.sqltext, {}, {"column": columns.append}) 

5330 

5331 super().__init__( 

5332 name=name, 

5333 deferrable=deferrable, 

5334 initially=initially, 

5335 _create_rule=_create_rule, 

5336 info=info, 

5337 _type_bound=_type_bound, 

5338 _autoattach=_autoattach, 

5339 *columns, 

5340 **dialect_kw, 

5341 ) 

5342 if table is not None: 

5343 self._set_parent_with_dispatch(table) 

5344 

5345 @property 

5346 def is_column_level(self) -> bool: 

5347 return not isinstance(self.parent, Table) 

5348 

5349 @util.deprecated( 

5350 "1.4", 

5351 "The :meth:`_schema.CheckConstraint.copy` method is deprecated " 

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

5353 ) 

5354 def copy( 

5355 self, *, target_table: Optional[Table] = None, **kw: Any 

5356 ) -> CheckConstraint: 

5357 return self._copy(target_table=target_table, **kw) 

5358 

5359 def _copy( 

5360 self, *, target_table: Optional[Table] = None, **kw: Any 

5361 ) -> CheckConstraint: 

5362 if target_table is not None: 

5363 # note that target_table is None for the copy process of 

5364 # a column-bound CheckConstraint, so this path is not reached 

5365 # in that case. 

5366 sqltext = _copy_expression(self.sqltext, self.table, target_table) 

5367 else: 

5368 sqltext = self.sqltext 

5369 c = CheckConstraint( 

5370 sqltext, 

5371 name=self.name, 

5372 initially=self.initially, 

5373 deferrable=self.deferrable, 

5374 _create_rule=self._create_rule, 

5375 table=target_table, 

5376 comment=self.comment, 

5377 _autoattach=False, 

5378 _type_bound=self._type_bound, 

5379 **self.dialect_kwargs, 

5380 ) 

5381 return self._schema_item_copy(c) 

5382 

5383 

5384class ForeignKeyConstraint(ColumnCollectionConstraint): 

5385 """A table-level FOREIGN KEY constraint. 

5386 

5387 Defines a single column or composite FOREIGN KEY ... REFERENCES 

5388 constraint. For a no-frills, single column foreign key, adding a 

5389 :class:`_schema.ForeignKey` to the definition of a :class:`_schema.Column` 

5390 is a 

5391 shorthand equivalent for an unnamed, single column 

5392 :class:`_schema.ForeignKeyConstraint`. 

5393 

5394 Examples of foreign key configuration are in :ref:`metadata_foreignkeys`. 

5395 

5396 """ 

5397 

5398 __visit_name__ = "foreign_key_constraint" 

5399 

5400 # a FOREIGN KEY may name the same local column more than once, e.g. 

5401 # FOREIGN KEY (a, a) REFERENCES r (b, c). the collection is therefore 

5402 # positional and parallel to self.elements, not deduplicating. 

5403 _column_collection_class = WriteableColumnCollection 

5404 

5405 def __init__( 

5406 self, 

5407 columns: _typing_Sequence[_DDLColumnArgument], 

5408 refcolumns: _typing_Sequence[_DDLColumnReferenceArgument], 

5409 name: _ConstraintNameArgument = None, 

5410 onupdate: Optional[str] = None, 

5411 ondelete: Optional[str] = None, 

5412 deferrable: Optional[bool] = None, 

5413 initially: Optional[str] = None, 

5414 use_alter: bool = False, 

5415 link_to_name: bool = False, 

5416 match: Optional[str] = None, 

5417 table: Optional[Table] = None, 

5418 info: Optional[_InfoType] = None, 

5419 comment: Optional[str] = None, 

5420 **dialect_kw: Any, 

5421 ) -> None: 

5422 r"""Construct a composite-capable FOREIGN KEY. 

5423 

5424 :param columns: A sequence of local column names. The named columns 

5425 must be defined and present in the parent Table. The names should 

5426 match the ``key`` given to each column (defaults to the name) unless 

5427 ``link_to_name`` is True. The same column may be named more than 

5428 once, e.g. ``FOREIGN KEY (a, a) REFERENCES r (b, c)``, which 

5429 constrains the referenced row so that its ``b`` and ``c`` values 

5430 are equal. 

5431 

5432 .. versionchanged:: 2.1 The same local column may be named more 

5433 than once. 

5434 

5435 :param refcolumns: A sequence of foreign column names or Column 

5436 objects. The columns must all be located within the same Table. 

5437 The number of entries must match that of 

5438 :paramref:`_schema.ForeignKeyConstraint.columns`. Each entry 

5439 accepts the same forms as :paramref:`_schema.ForeignKey.column`, 

5440 including the ``(table_name, column_name)`` and 

5441 ``(schema, table_name, column_name)`` tuple forms. 

5442 

5443 .. versionchanged:: 2.1 Individual entries may be given as a 

5444 tuple of name tokens. 

5445 

5446 :param name: Optional, the in-database name of the key. 

5447 

5448 :param onupdate: Optional string. If set, emit ON UPDATE <value> when 

5449 issuing DDL for this constraint. Typical values include CASCADE, 

5450 DELETE and RESTRICT. 

5451 

5452 .. seealso:: 

5453 

5454 :ref:`on_update_on_delete` 

5455 

5456 :param ondelete: Optional string. If set, emit ON DELETE <value> when 

5457 issuing DDL for this constraint. Typical values include CASCADE, 

5458 SET NULL and RESTRICT. Some dialects may allow for additional 

5459 syntaxes. 

5460 

5461 .. seealso:: 

5462 

5463 :ref:`on_update_on_delete` 

5464 

5465 :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT 

5466 DEFERRABLE when issuing DDL for this constraint. 

5467 

5468 :param initially: Optional string. If set, emit INITIALLY <value> when 

5469 issuing DDL for this constraint. 

5470 

5471 :param link_to_name: if True, the string name given in ``column`` is 

5472 the rendered name of the referenced column, not its locally assigned 

5473 ``key``. 

5474 

5475 :param use_alter: If True, do not emit the DDL for this constraint as 

5476 part of the CREATE TABLE definition. Instead, generate it via an 

5477 ALTER TABLE statement issued after the full collection of tables 

5478 have been created, and drop it via an ALTER TABLE statement before 

5479 the full collection of tables are dropped. 

5480 

5481 The use of :paramref:`_schema.ForeignKeyConstraint.use_alter` is 

5482 particularly geared towards the case where two or more tables 

5483 are established within a mutually-dependent foreign key constraint 

5484 relationship; however, the :meth:`_schema.MetaData.create_all` and 

5485 :meth:`_schema.MetaData.drop_all` 

5486 methods will perform this resolution 

5487 automatically, so the flag is normally not needed. 

5488 

5489 .. seealso:: 

5490 

5491 :ref:`use_alter` 

5492 

5493 :param match: Optional string. If set, emit MATCH <value> when issuing 

5494 DDL for this constraint. Typical values include SIMPLE, PARTIAL 

5495 and FULL. 

5496 

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

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

5499 

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

5501 foreign key constraint creation. 

5502 

5503 .. versionadded:: 2.0 

5504 

5505 :param \**dialect_kw: Additional keyword arguments are dialect 

5506 specific, and passed in the form ``<dialectname>_<argname>``. See 

5507 the documentation regarding an individual dialect at 

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

5509 

5510 """ 

5511 

5512 Constraint.__init__( 

5513 self, 

5514 name=name, 

5515 deferrable=deferrable, 

5516 initially=initially, 

5517 info=info, 

5518 comment=comment, 

5519 **dialect_kw, 

5520 ) 

5521 self.onupdate = onupdate 

5522 self.ondelete = ondelete 

5523 self.link_to_name = link_to_name 

5524 self.use_alter = use_alter 

5525 self.match = match 

5526 

5527 if len(columns) != len(refcolumns): 

5528 # e.g. FOREIGN KEY (a) REFERENCES r (b, c) 

5529 # paraphrasing 

5530 # https://www.postgresql.org/docs/current/static/ddl-constraints.html 

5531 raise exc.ArgumentError( 

5532 "ForeignKeyConstraint number " 

5533 "of constrained columns must match the number of " 

5534 "referenced columns." 

5535 ) 

5536 

5537 # standalone ForeignKeyConstraint - create 

5538 # associated ForeignKey objects which will be applied to hosted 

5539 # Column objects (in col.foreign_keys), either now or when attached 

5540 # to the Table for string-specified names 

5541 self.elements = [ 

5542 ForeignKey( 

5543 refcol, 

5544 _constraint=self, 

5545 name=self.name, 

5546 onupdate=self.onupdate, 

5547 ondelete=self.ondelete, 

5548 use_alter=self.use_alter, 

5549 link_to_name=self.link_to_name, 

5550 match=self.match, 

5551 deferrable=self.deferrable, 

5552 initially=self.initially, 

5553 **self.dialect_kwargs, 

5554 ) 

5555 for refcol in refcolumns 

5556 ] 

5557 

5558 ColumnCollectionMixin.__init__(self, *columns) 

5559 if table is not None: 

5560 if hasattr(self, "parent"): 

5561 assert table is self.parent 

5562 self._set_parent_with_dispatch(table) 

5563 

5564 def _append_element(self, column: Column[Any], fk: ForeignKey) -> None: 

5565 self._columns.add(column) 

5566 self.elements.append(fk) 

5567 

5568 columns: ReadOnlyColumnCollection[str, Column[Any]] 

5569 """A :class:`_expression.ColumnCollection` representing the local columns 

5570 of this constraint, in the order given and parallel to 

5571 :attr:`.ForeignKeyConstraint.elements`. 

5572 

5573 Unlike the column collection of other constraint types, this collection 

5574 does not deduplicate; a constraint which names the same column more than 

5575 once, such as ``FOREIGN KEY (a, a) REFERENCES r (b, c)``, includes that 

5576 column once per position. 

5577 

5578 .. versionchanged:: 2.1 A :class:`_schema.ForeignKeyConstraint` may name 

5579 the same local column more than once, and this collection retains the 

5580 repeated entries. 

5581 

5582 """ 

5583 

5584 elements: List[ForeignKey] 

5585 """A sequence of :class:`_schema.ForeignKey` objects. 

5586 

5587 Each :class:`_schema.ForeignKey` 

5588 represents a single referring column/referred 

5589 column pair. 

5590 

5591 This collection is intended to be read-only. 

5592 

5593 """ 

5594 

5595 @property 

5596 def _referred_schema(self) -> Optional[str]: 

5597 for elem in self.elements: 

5598 return elem._referred_schema 

5599 else: 

5600 return None 

5601 

5602 @property 

5603 def referred_table(self) -> Table: 

5604 """The :class:`_schema.Table` object to which this 

5605 :class:`_schema.ForeignKeyConstraint` references. 

5606 

5607 This is a dynamically calculated attribute which may not be available 

5608 if the constraint and/or parent table is not yet associated with 

5609 a metadata collection that contains the referred table. 

5610 

5611 """ 

5612 return self.elements[0].column.table 

5613 

5614 def _validate_dest_table(self, table: Table) -> None: 

5615 table_keys = {elem.target_table_key for elem in self.elements} 

5616 if None not in table_keys and len(table_keys) > 1: 

5617 elem0, elem1 = sorted(cast("Set[str]", table_keys))[0:2] 

5618 raise exc.ArgumentError( 

5619 f"ForeignKeyConstraint on " 

5620 f"{table.fullname}({self._col_description}) refers to " 

5621 f"multiple remote tables: {elem0} and {elem1}" 

5622 ) 

5623 

5624 @property 

5625 def column_keys(self) -> _typing_Sequence[str]: 

5626 """Return a list of string keys representing the local 

5627 columns in this :class:`_schema.ForeignKeyConstraint`. 

5628 

5629 This list is either the original string arguments sent 

5630 to the constructor of the :class:`_schema.ForeignKeyConstraint`, 

5631 or if the constraint has been initialized with :class:`_schema.Column` 

5632 objects, is the string ``.key`` of each element. 

5633 

5634 """ 

5635 if hasattr(self, "parent"): 

5636 return self._columns.keys() 

5637 else: 

5638 return [ 

5639 col.key if isinstance(col, ColumnElement) else str(col) 

5640 for col in self._pending_colargs 

5641 ] 

5642 

5643 @property 

5644 def _col_description(self) -> str: 

5645 return ", ".join(self.column_keys) 

5646 

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

5648 table = parent 

5649 assert isinstance(table, Table) 

5650 Constraint._set_parent(self, table) 

5651 

5652 if self._pending_colargs: 

5653 # this collection is positional and parallel to self.elements, 

5654 # retaining duplicate entries for a constraint such as 

5655 # FOREIGN KEY (a, a) REFERENCES r (b, c). _set_parent may run 

5656 # more than once for the same table, e.g. for an inline-declared 

5657 # constraint that also auto-attaches when its Column objects 

5658 # are attached, so populate rather than accumulate. 

5659 self._columns._populate_separate_keys( 

5660 (col.key, col) 

5661 for col in self._col_expressions(table) 

5662 if col is not None 

5663 ) 

5664 

5665 for col, fk in zip(self._columns, self.elements): 

5666 if not hasattr(fk, "parent") or fk.parent is not col: 

5667 fk._set_parent_with_dispatch(col) 

5668 

5669 self._validate_dest_table(table) 

5670 

5671 @util.deprecated( 

5672 "1.4", 

5673 "The :meth:`_schema.ForeignKeyConstraint.copy` method is deprecated " 

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

5675 ) 

5676 def copy( 

5677 self, 

5678 *, 

5679 schema: Optional[str] = None, 

5680 target_table: Optional[Table] = None, 

5681 **kw: Any, 

5682 ) -> ForeignKeyConstraint: 

5683 return self._copy(schema=schema, target_table=target_table, **kw) 

5684 

5685 def _copy( 

5686 self, 

5687 *, 

5688 schema: Optional[str] = None, 

5689 target_table: Optional[Table] = None, 

5690 **kw: Any, 

5691 ) -> ForeignKeyConstraint: 

5692 fkc = ForeignKeyConstraint( 

5693 [x.parent.key for x in self.elements], 

5694 [ 

5695 x._copy_tokens( 

5696 schema=schema, 

5697 table_name=( 

5698 target_table.name 

5699 if target_table is not None 

5700 and x.target_table_key == x.parent.table.key 

5701 else None 

5702 ), 

5703 _is_copy=True, 

5704 ) 

5705 for x in self.elements 

5706 ], 

5707 name=self.name, 

5708 onupdate=self.onupdate, 

5709 ondelete=self.ondelete, 

5710 use_alter=self.use_alter, 

5711 deferrable=self.deferrable, 

5712 initially=self.initially, 

5713 link_to_name=self.link_to_name, 

5714 match=self.match, 

5715 comment=self.comment, 

5716 **self.dialect_kwargs, 

5717 ) 

5718 for self_fk, other_fk in zip(self.elements, fkc.elements): 

5719 self_fk._schema_item_copy(other_fk) 

5720 return self._schema_item_copy(fkc) 

5721 

5722 

5723class PrimaryKeyConstraint(ColumnCollectionConstraint): 

5724 """A table-level PRIMARY KEY constraint. 

5725 

5726 The :class:`.PrimaryKeyConstraint` object is present automatically 

5727 on any :class:`_schema.Table` object; it is assigned a set of 

5728 :class:`_schema.Column` objects corresponding to those marked with 

5729 the :paramref:`_schema.Column.primary_key` flag:: 

5730 

5731 >>> my_table = Table( 

5732 ... "mytable", 

5733 ... metadata, 

5734 ... Column("id", Integer, primary_key=True), 

5735 ... Column("version_id", Integer, primary_key=True), 

5736 ... Column("data", String(50)), 

5737 ... ) 

5738 >>> my_table.primary_key 

5739 PrimaryKeyConstraint( 

5740 Column('id', Integer(), table=<mytable>, 

5741 primary_key=True, nullable=False), 

5742 Column('version_id', Integer(), table=<mytable>, 

5743 primary_key=True, nullable=False) 

5744 ) 

5745 

5746 The primary key of a :class:`_schema.Table` can also be specified by using 

5747 a :class:`.PrimaryKeyConstraint` object explicitly; in this mode of usage, 

5748 the "name" of the constraint can also be specified, as well as other 

5749 options which may be recognized by dialects:: 

5750 

5751 my_table = Table( 

5752 "mytable", 

5753 metadata, 

5754 Column("id", Integer), 

5755 Column("version_id", Integer), 

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

5757 PrimaryKeyConstraint("id", "version_id", name="mytable_pk"), 

5758 ) 

5759 

5760 The two styles of column-specification should generally not be mixed. 

5761 An warning is emitted if the columns present in the 

5762 :class:`.PrimaryKeyConstraint` 

5763 don't match the columns that were marked as ``primary_key=True``, if both 

5764 are present; in this case, the columns are taken strictly from the 

5765 :class:`.PrimaryKeyConstraint` declaration, and those columns otherwise 

5766 marked as ``primary_key=True`` are ignored. This behavior is intended to 

5767 be backwards compatible with previous behavior. 

5768 

5769 For the use case where specific options are to be specified on the 

5770 :class:`.PrimaryKeyConstraint`, but the usual style of using 

5771 ``primary_key=True`` flags is still desirable, an empty 

5772 :class:`.PrimaryKeyConstraint` may be specified, which will take on the 

5773 primary key column collection from the :class:`_schema.Table` based on the 

5774 flags:: 

5775 

5776 my_table = Table( 

5777 "mytable", 

5778 metadata, 

5779 Column("id", Integer, primary_key=True), 

5780 Column("version_id", Integer, primary_key=True), 

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

5782 PrimaryKeyConstraint(name="mytable_pk", mssql_clustered=True), 

5783 ) 

5784 

5785 """ 

5786 

5787 __visit_name__ = "primary_key_constraint" 

5788 

5789 _columns: DedupeColumnCollection[Column[Any]] 

5790 

5791 def __init__( 

5792 self, 

5793 *columns: _DDLColumnArgument, 

5794 name: Optional[str] = None, 

5795 deferrable: Optional[bool] = None, 

5796 initially: Optional[str] = None, 

5797 info: Optional[_InfoType] = None, 

5798 _implicit_generated: bool = False, 

5799 **dialect_kw: Any, 

5800 ) -> None: 

5801 self._implicit_generated = _implicit_generated 

5802 super().__init__( 

5803 *columns, 

5804 name=name, 

5805 deferrable=deferrable, 

5806 initially=initially, 

5807 info=info, 

5808 **dialect_kw, 

5809 ) 

5810 

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

5812 table = parent 

5813 assert isinstance(table, Table) 

5814 super()._set_parent(table) 

5815 

5816 if table.primary_key is not self: 

5817 table.constraints.discard(table.primary_key) 

5818 table.primary_key = self # type: ignore[misc] 

5819 table.constraints.add(self) 

5820 

5821 table_pks = [c for c in table.c if c.primary_key] 

5822 if ( 

5823 self._columns 

5824 and table_pks 

5825 and set(table_pks) != set(self._columns) 

5826 ): 

5827 # black could not format these inline 

5828 table_pk_str = ", ".join("'%s'" % c.name for c in table_pks) 

5829 col_str = ", ".join("'%s'" % c.name for c in self._columns) 

5830 

5831 util.warn( 

5832 f"Table '{table.name}' specifies columns " 

5833 f"{table_pk_str} as " 

5834 f"primary_key=True, " 

5835 f"not matching locally specified columns {col_str}; " 

5836 f"setting the " 

5837 f"current primary key columns to " 

5838 f"{col_str}. " 

5839 f"This warning " 

5840 f"may become an exception in a future release" 

5841 ) 

5842 table_pks[:] = [] 

5843 

5844 for c in self._columns: 

5845 c.primary_key = True 

5846 if c._user_defined_nullable is NULL_UNSPECIFIED: 

5847 c.nullable = False 

5848 if table_pks: 

5849 self._columns.extend(table_pks) 

5850 

5851 def _reload(self, columns: Iterable[Column[Any]]) -> None: 

5852 """repopulate this :class:`.PrimaryKeyConstraint` given 

5853 a set of columns. 

5854 

5855 Existing columns in the table that are marked as primary_key=True 

5856 are maintained. 

5857 

5858 Also fires a new event. 

5859 

5860 This is basically like putting a whole new 

5861 :class:`.PrimaryKeyConstraint` object on the parent 

5862 :class:`_schema.Table` object without actually replacing the object. 

5863 

5864 The ordering of the given list of columns is also maintained; these 

5865 columns will be appended to the list of columns after any which 

5866 are already present. 

5867 

5868 """ 

5869 # set the primary key flag on new columns. 

5870 # note any existing PK cols on the table also have their 

5871 # flag still set. 

5872 for col in columns: 

5873 col.primary_key = True 

5874 

5875 self._columns.extend(columns) 

5876 

5877 PrimaryKeyConstraint._autoincrement_column._reset(self) # type: ignore[attr-defined] # noqa: E501 

5878 self._set_parent_with_dispatch(self.table) 

5879 

5880 def _replace(self, col: Column[Any]) -> None: 

5881 PrimaryKeyConstraint._autoincrement_column._reset(self) # type: ignore[attr-defined] # noqa: E501 

5882 self._columns.replace(col) 

5883 

5884 self.dispatch._sa_event_column_added_to_pk_constraint(self, col) 

5885 

5886 @property 

5887 def columns_autoinc_first(self) -> List[Column[Any]]: 

5888 autoinc = self._autoincrement_column 

5889 

5890 if autoinc is not None: 

5891 return [autoinc] + [c for c in self._columns if c is not autoinc] 

5892 else: 

5893 return list(self._columns) 

5894 

5895 @util.ro_memoized_property 

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

5897 def _validate_autoinc(col: Column[Any], autoinc_true: bool) -> bool: 

5898 if col.type._type_affinity is not None and issubclass( 

5899 col.type._type_affinity, type_api.NUMERICTYPE._type_affinity 

5900 ): 

5901 scale = col.type.scale # type: ignore[attr-defined] 

5902 if scale != 0 and autoinc_true: 

5903 raise exc.ArgumentError( 

5904 f"Column type {col.type} with non-zero scale " 

5905 f"{scale} on column '{col}' is not " 

5906 f"compatible with autoincrement=True" 

5907 ) 

5908 elif not autoinc_true: 

5909 return False 

5910 elif col.type._type_affinity is None or not issubclass( 

5911 col.type._type_affinity, type_api.INTEGERTYPE._type_affinity 

5912 ): 

5913 if autoinc_true: 

5914 raise exc.ArgumentError( 

5915 f"Column type {col.type} on column '{col}' is not " 

5916 f"compatible with autoincrement=True" 

5917 ) 

5918 else: 

5919 return False 

5920 elif ( 

5921 col.default is not None 

5922 and not isinstance(col.default, Sequence) 

5923 and not autoinc_true 

5924 ): 

5925 return False 

5926 elif ( 

5927 col.server_default is not None 

5928 and not isinstance(col.server_default, Identity) 

5929 and not autoinc_true 

5930 ): 

5931 return False 

5932 elif col.foreign_keys and col.autoincrement not in ( 

5933 True, 

5934 "ignore_fk", 

5935 ): 

5936 return False 

5937 return True 

5938 

5939 if len(self._columns) == 1: 

5940 col = list(self._columns)[0] 

5941 

5942 if col.autoincrement is True: 

5943 _validate_autoinc(col, True) 

5944 return col 

5945 elif col.autoincrement in ( 

5946 "auto", 

5947 "ignore_fk", 

5948 ) and _validate_autoinc(col, False): 

5949 return col 

5950 else: 

5951 return None 

5952 

5953 else: 

5954 autoinc = None 

5955 for col in self._columns: 

5956 if col.autoincrement is True: 

5957 _validate_autoinc(col, True) 

5958 if autoinc is not None: 

5959 raise exc.ArgumentError( 

5960 f"Only one Column may be marked " 

5961 f"autoincrement=True, found both " 

5962 f"{col.name} and {autoinc.name}." 

5963 ) 

5964 else: 

5965 autoinc = col 

5966 

5967 return autoinc 

5968 

5969 

5970class UniqueConstraint(ColumnCollectionConstraint): 

5971 """A table-level UNIQUE constraint. 

5972 

5973 Defines a single column or composite UNIQUE constraint. For a no-frills, 

5974 single column constraint, adding ``unique=True`` to the ``Column`` 

5975 definition is a shorthand equivalent for an unnamed, single column 

5976 UniqueConstraint. 

5977 """ 

5978 

5979 __visit_name__ = "unique_constraint" 

5980 

5981 

5982class Index( 

5983 DialectKWArgs, ColumnCollectionMixin, HasConditionalDDL, SchemaItem 

5984): 

5985 """A table-level INDEX. 

5986 

5987 Defines a composite (one or more column) INDEX. 

5988 

5989 E.g.:: 

5990 

5991 sometable = Table( 

5992 "sometable", 

5993 metadata, 

5994 Column("name", String(50)), 

5995 Column("address", String(100)), 

5996 ) 

5997 

5998 Index("some_index", sometable.c.name) 

5999 

6000 For a no-frills, single column index, adding 

6001 :class:`_schema.Column` also supports ``index=True``:: 

6002 

6003 sometable = Table( 

6004 "sometable", metadata, Column("name", String(50), index=True) 

6005 ) 

6006 

6007 For a composite index, multiple columns can be specified:: 

6008 

6009 Index("some_index", sometable.c.name, sometable.c.address) 

6010 

6011 Functional indexes are supported as well, typically by using the 

6012 :data:`.func` construct in conjunction with table-bound 

6013 :class:`_schema.Column` objects:: 

6014 

6015 Index("some_index", func.lower(sometable.c.name)) 

6016 

6017 An :class:`.Index` can also be manually associated with a 

6018 :class:`_schema.Table`, 

6019 either through inline declaration or using 

6020 :meth:`_schema.Table.append_constraint`. When this approach is used, 

6021 the names 

6022 of the indexed columns can be specified as strings:: 

6023 

6024 Table( 

6025 "sometable", 

6026 metadata, 

6027 Column("name", String(50)), 

6028 Column("address", String(100)), 

6029 Index("some_index", "name", "address"), 

6030 ) 

6031 

6032 To support functional or expression-based indexes in this form, the 

6033 :func:`_expression.text` construct may be used:: 

6034 

6035 from sqlalchemy import text 

6036 

6037 Table( 

6038 "sometable", 

6039 metadata, 

6040 Column("name", String(50)), 

6041 Column("address", String(100)), 

6042 Index("some_index", text("lower(name)")), 

6043 ) 

6044 

6045 .. seealso:: 

6046 

6047 :ref:`schema_indexes` - General information on :class:`.Index`. 

6048 

6049 :ref:`postgresql_indexes` - PostgreSQL-specific options available for 

6050 the :class:`.Index` construct. 

6051 

6052 :ref:`mysql_indexes` - MySQL-specific options available for the 

6053 :class:`.Index` construct. 

6054 

6055 :ref:`mssql_indexes` - MSSQL-specific options available for the 

6056 :class:`.Index` construct. 

6057 

6058 """ 

6059 

6060 __visit_name__ = "index" 

6061 

6062 table: Optional[Table] 

6063 expressions: _typing_Sequence[Union[str, ColumnElement[Any]]] 

6064 _table_bound_expressions: _typing_Sequence[ColumnElement[Any]] 

6065 

6066 def __init__( 

6067 self, 

6068 name: Optional[str], 

6069 *expressions: _DDLColumnArgument, 

6070 unique: bool = False, 

6071 quote: Optional[bool] = None, 

6072 info: Optional[_InfoType] = None, 

6073 _table: Optional[Table] = None, 

6074 _column_flag: bool = False, 

6075 **dialect_kw: Any, 

6076 ) -> None: 

6077 r"""Construct an index object. 

6078 

6079 :param name: 

6080 The name of the index 

6081 

6082 :param \*expressions: 

6083 Column expressions to include in the index. The expressions 

6084 are normally instances of :class:`_schema.Column`, but may also 

6085 be arbitrary SQL expressions which ultimately refer to a 

6086 :class:`_schema.Column`. 

6087 

6088 :param unique=False: 

6089 Keyword only argument; if True, create a unique index. 

6090 

6091 :param quote=None: 

6092 Keyword only argument; whether to apply quoting to the name of 

6093 the index. Works in the same manner as that of 

6094 :paramref:`_schema.Column.quote`. 

6095 

6096 :param info=None: Optional data dictionary which will be populated 

6097 into the :attr:`.SchemaItem.info` attribute of this object. 

6098 

6099 :param \**dialect_kw: Additional keyword arguments not mentioned above 

6100 are dialect specific, and passed in the form 

6101 ``<dialectname>_<argname>``. See the documentation regarding an 

6102 individual dialect at :ref:`dialect_toplevel` for detail on 

6103 documented arguments. 

6104 

6105 """ 

6106 self.table = table = None 

6107 

6108 self.name = quoted_name.construct(name, quote) 

6109 self.unique = unique 

6110 if info is not None: 

6111 self.info = info 

6112 

6113 # TODO: consider "table" argument being public, but for 

6114 # the purpose of the fix here, it starts as private. 

6115 if _table is not None: 

6116 table = _table 

6117 

6118 self._validate_dialect_kwargs(dialect_kw) 

6119 

6120 self.expressions = [] 

6121 # will call _set_parent() if table-bound column 

6122 # objects are present 

6123 ColumnCollectionMixin.__init__( 

6124 self, 

6125 *expressions, 

6126 _column_flag=_column_flag, 

6127 _gather_expressions=self.expressions, 

6128 ) 

6129 if table is not None: 

6130 self._set_parent(table) 

6131 

6132 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

6133 table = parent 

6134 assert isinstance(table, Table) 

6135 ColumnCollectionMixin._set_parent(self, table) 

6136 

6137 if self.table is not None and table is not self.table: 

6138 raise exc.ArgumentError( 

6139 f"Index '{self.name}' is against table " 

6140 f"'{self.table.description}', and " 

6141 f"cannot be associated with table '{table.description}'." 

6142 ) 

6143 self.table = table 

6144 table.indexes.add(self) 

6145 

6146 expressions = self.expressions 

6147 col_expressions = self._col_expressions(table) 

6148 assert len(expressions) == len(col_expressions) 

6149 

6150 exprs = [] 

6151 for expr, colexpr in zip(expressions, col_expressions): 

6152 if isinstance(expr, ClauseElement): 

6153 exprs.append(expr) 

6154 elif colexpr is not None: 

6155 exprs.append(colexpr) 

6156 else: 

6157 assert False 

6158 self.expressions = self._table_bound_expressions = exprs 

6159 

6160 def create( 

6161 self, 

6162 bind: _CreateDropBind, 

6163 checkfirst: Union[bool, CheckFirst] = CheckFirst.NONE, 

6164 ) -> None: 

6165 """Issue a ``CREATE`` statement for this 

6166 :class:`.Index`, using the given 

6167 :class:`.Connection` or :class:`.Engine`` for connectivity. 

6168 

6169 .. seealso:: 

6170 

6171 :meth:`_schema.MetaData.create_all`. 

6172 

6173 """ 

6174 bind._run_ddl_visitor(ddl.SchemaGenerator, self, checkfirst=checkfirst) 

6175 

6176 def drop( 

6177 self, 

6178 bind: _CreateDropBind, 

6179 checkfirst: Union[bool, CheckFirst] = CheckFirst.NONE, 

6180 ) -> None: 

6181 """Issue a ``DROP`` statement for this 

6182 :class:`.Index`, using the given 

6183 :class:`.Connection` or :class:`.Engine` for connectivity. 

6184 

6185 .. seealso:: 

6186 

6187 :meth:`_schema.MetaData.drop_all`. 

6188 

6189 """ 

6190 bind._run_ddl_visitor(ddl.SchemaDropper, self, checkfirst=checkfirst) 

6191 

6192 def __repr__(self) -> str: 

6193 exprs: _typing_Sequence[Any] # noqa: F842 

6194 

6195 return "Index(%s)" % ( 

6196 ", ".join( 

6197 [repr(self.name)] 

6198 + [repr(e) for e in self.expressions] 

6199 + (self.unique and ["unique=True"] or []) 

6200 ) 

6201 ) 

6202 

6203 

6204_NamingSchemaCallable = Union[ 

6205 Callable[[Constraint, Table], str], 

6206 Callable[[Index, Table], str], 

6207] 

6208_NamingSchemaDirective = Union[str, _NamingSchemaCallable] 

6209 

6210 

6211class _NamingSchemaTD(TypedDict, total=False): 

6212 fk: _NamingSchemaDirective 

6213 pk: _NamingSchemaDirective 

6214 ix: _NamingSchemaDirective 

6215 ck: _NamingSchemaDirective 

6216 uq: _NamingSchemaDirective 

6217 

6218 

6219_NamingSchemaParameter = Union[ 

6220 # it seems like the TypedDict here is useful for pylance typeahead, 

6221 # and not much else 

6222 _NamingSchemaTD, 

6223 # there is no form that allows Union[Type[Any], str] to work in all 

6224 # cases, including breaking out Mapping[] entries for each combination 

6225 # even, therefore keys must be `Any` (see #10264) 

6226 Mapping[Any, _NamingSchemaDirective], 

6227] 

6228 

6229 

6230DEFAULT_NAMING_CONVENTION: _NamingSchemaParameter = util.immutabledict( 

6231 {"ix": "ix_%(column_0_label)s"} 

6232) 

6233 

6234 

6235class MetaData(HasSchemaAttr): 

6236 """A collection of :class:`_schema.Table` 

6237 objects and their associated schema 

6238 constructs. 

6239 

6240 Holds a collection of :class:`_schema.Table` objects as well as 

6241 an optional binding to an :class:`_engine.Engine` or 

6242 :class:`_engine.Connection`. If bound, the :class:`_schema.Table` objects 

6243 in the collection and their columns may participate in implicit SQL 

6244 execution. 

6245 

6246 The :class:`_schema.Table` objects themselves are stored in the 

6247 :attr:`_schema.MetaData.tables` dictionary. 

6248 

6249 :class:`_schema.MetaData` is a thread-safe object for read operations. 

6250 Construction of new tables within a single :class:`_schema.MetaData` 

6251 object, 

6252 either explicitly or via reflection, may not be completely thread-safe. 

6253 

6254 .. seealso:: 

6255 

6256 :ref:`metadata_describing` - Introduction to database metadata 

6257 

6258 """ 

6259 

6260 __visit_name__ = "metadata" 

6261 

6262 def __init__( 

6263 self, 

6264 schema: Optional[str] = None, 

6265 quote_schema: Optional[bool] = None, 

6266 naming_convention: Optional[_NamingSchemaParameter] = None, 

6267 info: Optional[_InfoType] = None, 

6268 ) -> None: 

6269 """Create a new MetaData object. 

6270 

6271 :param schema: 

6272 The default schema to use for the :class:`_schema.Table`, 

6273 :class:`.Sequence`, and potentially other objects associated with 

6274 this :class:`_schema.MetaData`. Defaults to ``None``. 

6275 

6276 .. seealso:: 

6277 

6278 :ref:`schema_metadata_schema_name` - details on how the 

6279 :paramref:`_schema.MetaData.schema` parameter is used. 

6280 

6281 :paramref:`_schema.Table.schema` 

6282 

6283 :paramref:`.Sequence.schema` 

6284 

6285 :param quote_schema: 

6286 Sets the ``quote_schema`` flag for those :class:`_schema.Table`, 

6287 :class:`.Sequence`, and other objects which make usage of the 

6288 local ``schema`` name. 

6289 

6290 :param info: Optional data dictionary which will be populated into the 

6291 :attr:`.SchemaItem.info` attribute of this object. 

6292 

6293 :param naming_convention: a dictionary referring to values which 

6294 will establish default naming conventions for :class:`.Constraint` 

6295 and :class:`.Index` objects, for those objects which are not given 

6296 a name explicitly. 

6297 

6298 The keys of this dictionary may be: 

6299 

6300 * a constraint or Index class, e.g. the :class:`.UniqueConstraint`, 

6301 :class:`_schema.ForeignKeyConstraint` class, the :class:`.Index` 

6302 class 

6303 

6304 * a string mnemonic for one of the known constraint classes; 

6305 ``"fk"``, ``"pk"``, ``"ix"``, ``"ck"``, ``"uq"`` for foreign key, 

6306 primary key, index, check, and unique constraint, respectively. 

6307 

6308 * the string name of a user-defined "token" that can be used 

6309 to define new naming tokens. 

6310 

6311 The values associated with each "constraint class" or "constraint 

6312 mnemonic" key are string naming templates, such as 

6313 ``"uq_%(table_name)s_%(column_0_name)s"``, 

6314 which describe how the name should be composed. The values 

6315 associated with user-defined "token" keys should be callables of the 

6316 form ``fn(constraint, table)``, which accepts the constraint/index 

6317 object and :class:`_schema.Table` as arguments, returning a string 

6318 result. 

6319 

6320 The built-in names are as follows, some of which may only be 

6321 available for certain types of constraint: 

6322 

6323 * ``%(table_name)s`` - the name of the :class:`_schema.Table` 

6324 object 

6325 associated with the constraint. 

6326 

6327 * ``%(referred_table_name)s`` - the name of the 

6328 :class:`_schema.Table` 

6329 object associated with the referencing target of a 

6330 :class:`_schema.ForeignKeyConstraint`. 

6331 

6332 * ``%(column_0_name)s`` - the name of the :class:`_schema.Column` 

6333 at 

6334 index position "0" within the constraint. 

6335 

6336 * ``%(column_0N_name)s`` - the name of all :class:`_schema.Column` 

6337 objects in order within the constraint, joined without a 

6338 separator. 

6339 

6340 * ``%(column_0_N_name)s`` - the name of all 

6341 :class:`_schema.Column` 

6342 objects in order within the constraint, joined with an 

6343 underscore as a separator. 

6344 

6345 * ``%(column_0_label)s``, ``%(column_0N_label)s``, 

6346 ``%(column_0_N_label)s`` - the label of either the zeroth 

6347 :class:`_schema.Column` or all :class:`.Columns`, separated with 

6348 or without an underscore 

6349 

6350 * ``%(column_0_key)s``, ``%(column_0N_key)s``, 

6351 ``%(column_0_N_key)s`` - the key of either the zeroth 

6352 :class:`_schema.Column` or all :class:`.Columns`, separated with 

6353 or without an underscore 

6354 

6355 * ``%(referred_column_0_name)s``, ``%(referred_column_0N_name)s`` 

6356 ``%(referred_column_0_N_name)s``, ``%(referred_column_0_key)s``, 

6357 ``%(referred_column_0N_key)s``, ... column tokens which 

6358 render the names/keys/labels of columns that are referenced 

6359 by a :class:`_schema.ForeignKeyConstraint`. 

6360 

6361 * ``%(constraint_name)s`` - a special key that refers to the 

6362 existing name given to the constraint. When this key is 

6363 present, the :class:`.Constraint` object's existing name will be 

6364 replaced with one that is composed from template string that 

6365 uses this token. When this token is present, it is required that 

6366 the :class:`.Constraint` is given an explicit name ahead of time. 

6367 

6368 * user-defined: any additional token may be implemented by passing 

6369 it along with a ``fn(constraint, table)`` callable to the 

6370 naming_convention dictionary. 

6371 

6372 .. seealso:: 

6373 

6374 :ref:`constraint_naming_conventions` - for detailed usage 

6375 examples. 

6376 

6377 """ 

6378 if schema is not None and not isinstance(schema, str): 

6379 raise exc.ArgumentError( 

6380 "expected schema argument to be a string, " 

6381 f"got {type(schema)}." 

6382 ) 

6383 self.tables = util.FacadeDict() 

6384 self.schema = quoted_name.construct(schema, quote_schema) 

6385 self.naming_convention = ( 

6386 naming_convention 

6387 if naming_convention 

6388 else DEFAULT_NAMING_CONVENTION 

6389 ) 

6390 if info: 

6391 self.info = info 

6392 self._schemas: Set[str] = set() 

6393 self._sequences: Dict[str, Sequence] = {} 

6394 self._fk_memos: Dict[Tuple[str, Optional[str]], List[ForeignKey]] = ( 

6395 collections.defaultdict(list) 

6396 ) 

6397 self._objects: Set[Union[HasSchemaAttr, SchemaType]] = set() 

6398 

6399 tables: util.FacadeDict[str, Table] 

6400 """A dictionary of :class:`_schema.Table` 

6401 objects keyed to their name or "table key". 

6402 

6403 The exact key is that determined by the :attr:`_schema.Table.key` 

6404 attribute; 

6405 for a table with no :attr:`_schema.Table.schema` attribute, 

6406 this is the same 

6407 as :attr:`_schema.Table.name`. For a table with a schema, 

6408 it is typically of the 

6409 form ``schemaname.tablename``. 

6410 

6411 .. seealso:: 

6412 

6413 :attr:`_schema.MetaData.sorted_tables` 

6414 

6415 """ 

6416 

6417 def __repr__(self) -> str: 

6418 return "MetaData()" 

6419 

6420 def __contains__(self, table_or_key: Union[str, Table]) -> bool: 

6421 if not isinstance(table_or_key, str): 

6422 table_or_key = table_or_key.key 

6423 return table_or_key in self.tables 

6424 

6425 def _add_table( 

6426 self, name: str, schema: Optional[str], table: Table 

6427 ) -> None: 

6428 key = _get_table_key(name, schema) 

6429 self.tables._insert_item(key, table) 

6430 if schema: 

6431 self._schemas.add(schema) 

6432 

6433 def _remove_table(self, name: str, schema: Optional[str]) -> None: 

6434 key = _get_table_key(name, schema) 

6435 removed = dict.pop(self.tables, key, None) 

6436 if removed is not None: 

6437 for fk in removed.foreign_keys: 

6438 fk._remove_from_metadata(self) 

6439 if self._schemas: 

6440 self._schemas = { 

6441 t.schema for t in self.tables.values() if t.schema is not None 

6442 } 

6443 

6444 def __getstate__(self) -> Dict[str, Any]: 

6445 return { 

6446 "tables": self.tables, 

6447 "schema": self.schema, 

6448 "schemas": self._schemas, 

6449 "sequences": self._sequences, 

6450 "fk_memos": self._fk_memos, 

6451 "naming_convention": self.naming_convention, 

6452 "objects": self._objects, 

6453 } 

6454 

6455 def __setstate__(self, state: Dict[str, Any]) -> None: 

6456 self.tables = state["tables"] 

6457 self.schema = state["schema"] 

6458 self.naming_convention = state["naming_convention"] 

6459 self._sequences = state["sequences"] 

6460 self._schemas = state["schemas"] 

6461 self._fk_memos = state["fk_memos"] 

6462 self._objects = state.get("objects", set()) 

6463 

6464 def clear(self) -> None: 

6465 """Clear all objects from this MetaData.""" 

6466 

6467 dict.clear(self.tables) 

6468 self._schemas.clear() 

6469 self._fk_memos.clear() 

6470 self._sequences.clear() 

6471 self._objects.clear() 

6472 

6473 def remove(self, table: Table) -> None: 

6474 """Remove the given Table object from this MetaData.""" 

6475 

6476 self._remove_table(table.name, table.schema) 

6477 

6478 @property 

6479 def sorted_tables(self) -> List[Table]: 

6480 """Returns a list of :class:`_schema.Table` objects sorted in order of 

6481 foreign key dependency. 

6482 

6483 The sorting will place :class:`_schema.Table` 

6484 objects that have dependencies 

6485 first, before the dependencies themselves, representing the 

6486 order in which they can be created. To get the order in which 

6487 the tables would be dropped, use the ``reversed()`` Python built-in. 

6488 

6489 .. warning:: 

6490 

6491 The :attr:`.MetaData.sorted_tables` attribute cannot by itself 

6492 accommodate automatic resolution of dependency cycles between 

6493 tables, which are usually caused by mutually dependent foreign key 

6494 constraints. When these cycles are detected, the foreign keys 

6495 of these tables are omitted from consideration in the sort. 

6496 A warning is emitted when this condition occurs, which will be an 

6497 exception raise in a future release. Tables which are not part 

6498 of the cycle will still be returned in dependency order. 

6499 

6500 To resolve these cycles, the 

6501 :paramref:`_schema.ForeignKeyConstraint.use_alter` parameter may be 

6502 applied to those constraints which create a cycle. Alternatively, 

6503 the :func:`_schema.sort_tables_and_constraints` function will 

6504 automatically return foreign key constraints in a separate 

6505 collection when cycles are detected so that they may be applied 

6506 to a schema separately. 

6507 

6508 .. seealso:: 

6509 

6510 :func:`_schema.sort_tables` 

6511 

6512 :func:`_schema.sort_tables_and_constraints` 

6513 

6514 :attr:`_schema.MetaData.tables` 

6515 

6516 :meth:`_reflection.Inspector.get_table_names` 

6517 

6518 :meth:`_reflection.Inspector.get_sorted_table_and_fkc_names` 

6519 

6520 

6521 """ 

6522 return ddl.sort_tables( 

6523 sorted(self.tables.values(), key=lambda t: t.key) # type: ignore[attr-defined] # noqa: E501 

6524 ) 

6525 

6526 # overload needed to work around mypy this mypy 

6527 # https://github.com/python/mypy/issues/17093 

6528 @overload 

6529 def reflect( 

6530 self, 

6531 bind: Engine, 

6532 schema: Optional[str] = ..., 

6533 views: bool = ..., 

6534 only: Union[ 

6535 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

6536 ] = ..., 

6537 extend_existing: bool = ..., 

6538 autoload_replace: bool = ..., 

6539 resolve_fks: bool = ..., 

6540 **dialect_kwargs: Any, 

6541 ) -> None: ... 

6542 

6543 @overload 

6544 def reflect( 

6545 self, 

6546 bind: Connection, 

6547 schema: Optional[str] = ..., 

6548 views: bool = ..., 

6549 only: Union[ 

6550 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

6551 ] = ..., 

6552 extend_existing: bool = ..., 

6553 autoload_replace: bool = ..., 

6554 resolve_fks: bool = ..., 

6555 **dialect_kwargs: Any, 

6556 ) -> None: ... 

6557 

6558 @util.preload_module("sqlalchemy.engine.reflection") 

6559 def reflect( 

6560 self, 

6561 bind: Union[Engine, Connection], 

6562 schema: Optional[str] = None, 

6563 views: bool = False, 

6564 only: Union[ 

6565 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

6566 ] = None, 

6567 extend_existing: bool = False, 

6568 autoload_replace: bool = True, 

6569 resolve_fks: bool = True, 

6570 **dialect_kwargs: Any, 

6571 ) -> None: 

6572 r"""Load all available table definitions from the database. 

6573 

6574 Automatically creates ``Table`` entries in this ``MetaData`` for any 

6575 table available in the database but not yet present in the 

6576 ``MetaData``. May be called multiple times to pick up tables recently 

6577 added to the database, however no special action is taken if a table 

6578 in this ``MetaData`` no longer exists in the database. 

6579 

6580 :param bind: 

6581 A :class:`.Connection` or :class:`.Engine` used to access the 

6582 database. 

6583 

6584 :param schema: 

6585 Optional, query and reflect tables from an alternate schema. 

6586 If None, the schema associated with this :class:`_schema.MetaData` 

6587 is used, if any. 

6588 

6589 :param views: 

6590 If True, also reflect views (materialized and plain). 

6591 

6592 :param only: 

6593 Optional. Load only a sub-set of available named tables. May be 

6594 specified as a sequence of names or a callable. 

6595 

6596 If a sequence of names is provided, only those tables will be 

6597 reflected. An error is raised if a table is requested but not 

6598 available. Named tables already present in this ``MetaData`` are 

6599 ignored. 

6600 

6601 If a callable is provided, it will be used as a boolean predicate to 

6602 filter the list of potential table names. The callable is called 

6603 with a table name and this ``MetaData`` instance as positional 

6604 arguments and should return a true value for any table to reflect. 

6605 

6606 :param extend_existing: Passed along to each :class:`_schema.Table` as 

6607 :paramref:`_schema.Table.extend_existing`. 

6608 

6609 :param autoload_replace: Passed along to each :class:`_schema.Table` 

6610 as 

6611 :paramref:`_schema.Table.autoload_replace`. 

6612 

6613 :param resolve_fks: if True, reflect :class:`_schema.Table` 

6614 objects linked 

6615 to :class:`_schema.ForeignKey` objects located in each 

6616 :class:`_schema.Table`. 

6617 For :meth:`_schema.MetaData.reflect`, 

6618 this has the effect of reflecting 

6619 related tables that might otherwise not be in the list of tables 

6620 being reflected, for example if the referenced table is in a 

6621 different schema or is omitted via the 

6622 :paramref:`.MetaData.reflect.only` parameter. When False, 

6623 :class:`_schema.ForeignKey` objects are not followed to the 

6624 :class:`_schema.Table` 

6625 in which they link, however if the related table is also part of the 

6626 list of tables that would be reflected in any case, the 

6627 :class:`_schema.ForeignKey` object will still resolve to its related 

6628 :class:`_schema.Table` after the :meth:`_schema.MetaData.reflect` 

6629 operation is 

6630 complete. Defaults to True. 

6631 

6632 .. seealso:: 

6633 

6634 :paramref:`_schema.Table.resolve_fks` 

6635 

6636 :param \**dialect_kwargs: Additional keyword arguments not mentioned 

6637 above are dialect specific, and passed in the form 

6638 ``<dialectname>_<argname>``. See the documentation regarding an 

6639 individual dialect at :ref:`dialect_toplevel` for detail on 

6640 documented arguments. 

6641 

6642 .. seealso:: 

6643 

6644 :ref:`metadata_reflection_toplevel` 

6645 

6646 :meth:`_events.DDLEvents.column_reflect` - Event used to customize 

6647 the reflected columns. Usually used to generalize the types using 

6648 :meth:`_types.TypeEngine.as_generic` 

6649 

6650 :ref:`metadata_reflection_dbagnostic_types` - describes how to 

6651 reflect tables using general types. 

6652 

6653 """ 

6654 

6655 with inspection.inspect(bind)._inspection_context() as insp: 

6656 reflect_opts: Any = { 

6657 "autoload_with": insp, 

6658 "extend_existing": extend_existing, 

6659 "autoload_replace": autoload_replace, 

6660 "resolve_fks": resolve_fks, 

6661 "_extend_on": set(), 

6662 } 

6663 

6664 reflect_opts.update(dialect_kwargs) 

6665 

6666 if schema is None: 

6667 schema = self.schema 

6668 

6669 if schema is not None: 

6670 reflect_opts["schema"] = schema 

6671 

6672 kind = util.preloaded.engine_reflection.ObjectKind.TABLE 

6673 available: util.OrderedSet[str] = util.OrderedSet( 

6674 insp.get_table_names(schema, **dialect_kwargs) 

6675 ) 

6676 if views: 

6677 kind = util.preloaded.engine_reflection.ObjectKind.ANY 

6678 available.update(insp.get_view_names(schema, **dialect_kwargs)) 

6679 try: 

6680 available.update( 

6681 insp.get_materialized_view_names( 

6682 schema, **dialect_kwargs 

6683 ) 

6684 ) 

6685 except NotImplementedError: 

6686 pass 

6687 

6688 if schema is not None: 

6689 available_w_schema: util.OrderedSet[str] = util.OrderedSet( 

6690 [f"{schema}.{name}" for name in available] 

6691 ) 

6692 else: 

6693 available_w_schema = available 

6694 

6695 current = set(self.tables) 

6696 

6697 if only is None: 

6698 load = [ 

6699 name 

6700 for name, schname in zip(available, available_w_schema) 

6701 if extend_existing or schname not in current 

6702 ] 

6703 elif callable(only): 

6704 load = [ 

6705 name 

6706 for name, schname in zip(available, available_w_schema) 

6707 if (extend_existing or schname not in current) 

6708 and only(name, self) 

6709 ] 

6710 else: 

6711 missing = [name for name in only if name not in available] 

6712 if missing: 

6713 s = schema and (" schema '%s'" % schema) or "" 

6714 missing_str = ", ".join(missing) 

6715 raise exc.InvalidRequestError( 

6716 f"Could not reflect: requested table(s) not available " 

6717 f"in {bind.engine!r}{s}: ({missing_str})" 

6718 ) 

6719 load = [ 

6720 name 

6721 for name in only 

6722 if extend_existing or name not in current 

6723 ] 

6724 # pass the available tables so the inspector can 

6725 # choose to ignore the filter_names 

6726 _reflect_info = insp._get_reflection_info( 

6727 schema=schema, 

6728 filter_names=load, 

6729 available=available, 

6730 kind=kind, 

6731 scope=util.preloaded.engine_reflection.ObjectScope.ANY, 

6732 **dialect_kwargs, 

6733 ) 

6734 reflect_opts["_reflect_info"] = _reflect_info 

6735 

6736 for name in load: 

6737 try: 

6738 Table(name, self, **reflect_opts) 

6739 except exc.UnreflectableTableError as uerr: 

6740 util.warn(f"Skipping table {name}: {uerr}") 

6741 

6742 def create_all( 

6743 self, 

6744 bind: _CreateDropBind, 

6745 tables: Optional[_typing_Sequence[Table]] = None, 

6746 checkfirst: Union[bool, CheckFirst] = CheckFirst.ALL, 

6747 ) -> None: 

6748 """Create all tables stored in this metadata. 

6749 

6750 Conditional by default, will not attempt to recreate tables already 

6751 present in the target database. 

6752 

6753 :param bind: 

6754 A :class:`.Connection` or :class:`.Engine` used to access the 

6755 database. 

6756 

6757 :param tables: 

6758 Optional list of ``Table`` objects, which is a subset of the total 

6759 tables in the ``MetaData`` (others are ignored). 

6760 

6761 :param checkfirst: A boolean value or instance of :class:`.CheckFirst`. 

6762 Indicates which objects should be checked for within a separate pass 

6763 before creating schema objects. 

6764 

6765 """ 

6766 bind._run_ddl_visitor( 

6767 ddl.SchemaGenerator, self, checkfirst=checkfirst, tables=tables 

6768 ) 

6769 

6770 def drop_all( 

6771 self, 

6772 bind: _CreateDropBind, 

6773 tables: Optional[_typing_Sequence[Table]] = None, 

6774 checkfirst: Union[bool, CheckFirst] = CheckFirst.ALL, 

6775 ) -> None: 

6776 """Drop all tables stored in this metadata. 

6777 

6778 Conditional by default, will not attempt to drop tables not present in 

6779 the target database. 

6780 

6781 :param bind: 

6782 A :class:`.Connection` or :class:`.Engine` used to access the 

6783 database. 

6784 

6785 :param tables: 

6786 Optional list of ``Table`` objects, which is a subset of the 

6787 total tables in the ``MetaData`` (others are ignored). 

6788 

6789 :param checkfirst: A boolean value or instance of :class:`.CheckFirst`. 

6790 Indicates which objects should be checked for within a separate pass 

6791 before dropping schema objects. 

6792 

6793 """ 

6794 bind._run_ddl_visitor( 

6795 ddl.SchemaDropper, self, checkfirst=checkfirst, tables=tables 

6796 ) 

6797 

6798 @property 

6799 def schemas(self) -> _typing_Sequence[str]: 

6800 """A sequence of schema names that are present in this MetaData.""" 

6801 schemas = self._schemas 

6802 if self.schema: 

6803 schemas = schemas | {self.schema} 

6804 return tuple(schemas) 

6805 

6806 def get_schema_objects( 

6807 self, 

6808 kind: Type[_T], 

6809 *, 

6810 schema: Union[str, None, Literal[_NoArg.NO_ARG]] = _NoArg.NO_ARG, 

6811 ) -> _typing_Sequence[_T]: 

6812 """Return a sequence of schema objects of the given kind. 

6813 

6814 This method can be used to return :class:`_sqltypes.Enum`, 

6815 :class:`.Sequence`, etc. objects registered in this 

6816 :class:`_schema.MetaData`. 

6817 

6818 :param kind: a type that indicates what object to return, such as 

6819 :class:`Enum` or :class:`Sequence`. 

6820 :param schema: Optional, a schema name to filter the objects by. If 

6821 not provided the default schema of the metadata is used. 

6822 

6823 """ 

6824 

6825 if schema is _NoArg.NO_ARG: 

6826 schema = self.schema 

6827 return tuple( 

6828 obj 

6829 for obj in self._objects 

6830 if isinstance(obj, kind) and obj.schema == schema 

6831 ) 

6832 

6833 def get_schema_object_by_name( 

6834 self, 

6835 kind: Type[_T], 

6836 name: str, 

6837 *, 

6838 schema: Union[str, None, Literal[_NoArg.NO_ARG]] = _NoArg.NO_ARG, 

6839 ) -> Optional[_T]: 

6840 """Return a schema objects of the given kind and name if found. 

6841 

6842 This method can be used to return :class:`_sqltypes.Enum`, 

6843 :class:`.Sequence`, etc. objects registered in this 

6844 :class:`_schema.MetaData`. 

6845 

6846 :param kind: a type that indicates what object to return, such as 

6847 :class:`Enum` or :class:`Sequence`. 

6848 :param name: the name of the object to return. 

6849 :param schema: Optional, a schema name to filter the objects by. If 

6850 not provided the default schema of the metadata is used. 

6851 

6852 """ 

6853 

6854 for obj in self.get_schema_objects(kind, schema=schema): 

6855 if getattr(obj, "name", None) == name: 

6856 return obj 

6857 return None 

6858 

6859 def _register_object(self, obj: Union[HasSchemaAttr, SchemaType]) -> None: 

6860 self._objects.add(obj) 

6861 

6862 

6863class Computed(FetchedValue, SchemaItem): 

6864 """Defines a generated column, i.e. "GENERATED ALWAYS AS" syntax. 

6865 

6866 The :class:`.Computed` construct is an inline construct added to the 

6867 argument list of a :class:`_schema.Column` object:: 

6868 

6869 from sqlalchemy import Computed 

6870 

6871 Table( 

6872 "square", 

6873 metadata_obj, 

6874 Column("side", Float, nullable=False), 

6875 Column("area", Float, Computed("side * side")), 

6876 ) 

6877 

6878 See the linked documentation below for complete details. 

6879 

6880 .. seealso:: 

6881 

6882 :ref:`computed_ddl` 

6883 

6884 """ 

6885 

6886 __visit_name__ = "computed_column" 

6887 

6888 column: Optional[Column[Any]] 

6889 

6890 @_document_text_coercion( 

6891 "sqltext", ":class:`.Computed`", ":paramref:`.Computed.sqltext`" 

6892 ) 

6893 def __init__( 

6894 self, sqltext: _DDLColumnArgument, persisted: Optional[bool] = None 

6895 ) -> None: 

6896 """Construct a GENERATED ALWAYS AS DDL construct to accompany a 

6897 :class:`_schema.Column`. 

6898 

6899 :param sqltext: 

6900 A string containing the column generation expression, which will be 

6901 used verbatim, or a SQL expression construct, such as a 

6902 :func:`_expression.text` 

6903 object. If given as a string, the object is converted to a 

6904 :func:`_expression.text` object. 

6905 

6906 :param persisted: 

6907 Optional, controls how this column should be persisted by the 

6908 database. Possible values are: 

6909 

6910 * ``None``, the default, it will use the default persistence 

6911 defined by the database. 

6912 * ``True``, will render ``GENERATED ALWAYS AS ... STORED``, or the 

6913 equivalent for the target database if supported. 

6914 * ``False``, will render ``GENERATED ALWAYS AS ... VIRTUAL``, or 

6915 the equivalent for the target database if supported. 

6916 

6917 Specifying ``True`` or ``False`` may raise an error when the DDL 

6918 is emitted to the target database if the database does not support 

6919 that persistence option. Leaving this parameter at its default 

6920 of ``None`` is guaranteed to succeed for all databases that support 

6921 ``GENERATED ALWAYS AS``. 

6922 

6923 """ 

6924 self.sqltext = coercions.expect(roles.DDLExpressionRole, sqltext) 

6925 self.persisted = persisted 

6926 self.column = None 

6927 

6928 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

6929 assert isinstance(parent, Column) 

6930 

6931 if not isinstance( 

6932 parent.server_default, (type(None), Computed) 

6933 ) or not isinstance(parent.server_onupdate, (type(None), Computed)): 

6934 raise exc.ArgumentError( 

6935 "A generated column cannot specify a server_default or a " 

6936 "server_onupdate argument" 

6937 ) 

6938 self.column = parent 

6939 parent.computed = self 

6940 self.column.server_onupdate = self 

6941 self.column.server_default = self 

6942 

6943 def _as_for_update(self, for_update: bool) -> FetchedValue: 

6944 return self 

6945 

6946 @util.deprecated( 

6947 "1.4", 

6948 "The :meth:`_schema.Computed.copy` method is deprecated " 

6949 "and will be removed in a future release.", 

6950 ) 

6951 def copy( 

6952 self, *, target_table: Optional[Table] = None, **kw: Any 

6953 ) -> Computed: 

6954 return self._copy(target_table=target_table, **kw) 

6955 

6956 def _copy( 

6957 self, *, target_table: Optional[Table] = None, **kw: Any 

6958 ) -> Computed: 

6959 sqltext = _copy_expression( 

6960 self.sqltext, 

6961 self.column.table if self.column is not None else None, 

6962 target_table, 

6963 ) 

6964 g = Computed(sqltext, persisted=self.persisted) 

6965 

6966 return self._schema_item_copy(g) 

6967 

6968 

6969class Identity(IdentityOptions, FetchedValue, SchemaItem): 

6970 """Defines an identity column, i.e. "GENERATED { ALWAYS | BY DEFAULT } 

6971 AS IDENTITY" syntax. 

6972 

6973 The :class:`.Identity` construct is an inline construct added to the 

6974 argument list of a :class:`_schema.Column` object:: 

6975 

6976 from sqlalchemy import Identity 

6977 

6978 Table( 

6979 "foo", 

6980 metadata_obj, 

6981 Column("id", Integer, Identity()), 

6982 Column("description", Text), 

6983 ) 

6984 

6985 See the linked documentation below for complete details. 

6986 

6987 .. versionadded:: 1.4 

6988 

6989 .. seealso:: 

6990 

6991 :ref:`identity_ddl` 

6992 

6993 """ 

6994 

6995 __visit_name__ = "identity_column" 

6996 

6997 is_identity = True 

6998 

6999 @util.deprecated_params( 

7000 order=( 

7001 "2.1", 

7002 "This parameter is supported only by Oracle Database, " 

7003 "use ``oracle_order`` instead.", 

7004 ), 

7005 on_null=( 

7006 "2.1", 

7007 "This parameter is supported only by Oracle Database, " 

7008 "use ``oracle_on_null`` instead.", 

7009 ), 

7010 ) 

7011 def __init__( 

7012 self, 

7013 always: Optional[bool] = False, 

7014 on_null: Optional[bool] = None, 

7015 start: Optional[int] = None, 

7016 increment: Optional[int] = None, 

7017 minvalue: Optional[int] = None, 

7018 maxvalue: Optional[int] = None, 

7019 nominvalue: Optional[bool] = None, 

7020 nomaxvalue: Optional[bool] = None, 

7021 cycle: Optional[bool] = None, 

7022 cache: Optional[int] = None, 

7023 order: Optional[bool] = None, 

7024 **dialect_kw: Any, 

7025 ) -> None: 

7026 """Construct a GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY DDL 

7027 construct to accompany a :class:`_schema.Column`. 

7028 

7029 See the :class:`.Sequence` documentation for a complete description 

7030 of most parameters. 

7031 

7032 .. note:: 

7033 MSSQL supports this construct as the preferred alternative to 

7034 generate an IDENTITY on a column, but it uses non standard 

7035 syntax that only support :paramref:`_schema.Identity.start` 

7036 and :paramref:`_schema.Identity.increment`. 

7037 All other parameters are ignored. 

7038 

7039 :param always: 

7040 A boolean, that indicates the type of identity column. 

7041 If ``False`` is specified, the default, then the user-specified 

7042 value takes precedence. 

7043 If ``True`` is specified, a user-specified value is not accepted ( 

7044 on some backends, like PostgreSQL, OVERRIDING SYSTEM VALUE, or 

7045 similar, may be specified in an INSERT to override the sequence 

7046 value). 

7047 Some backends also have a default value for this parameter, 

7048 ``None`` can be used to omit rendering this part in the DDL. It 

7049 will be treated as ``False`` if a backend does not have a default 

7050 value. 

7051 

7052 :param on_null: 

7053 Set to ``True`` to specify ON NULL in conjunction with a 

7054 ``always=False`` identity column. This option is only supported on 

7055 some backends, like Oracle Database. 

7056 

7057 :param start: the starting index of the sequence. 

7058 :param increment: the increment value of the sequence. 

7059 :param minvalue: the minimum value of the sequence. 

7060 :param maxvalue: the maximum value of the sequence. 

7061 :param nominvalue: no minimum value of the sequence. 

7062 :param nomaxvalue: no maximum value of the sequence. 

7063 :param cycle: allows the sequence to wrap around when the maxvalue 

7064 or minvalue has been reached. 

7065 :param cache: optional integer value; number of future values in the 

7066 sequence which are calculated in advance. 

7067 :param order: optional boolean value; if true, renders the 

7068 ORDER keyword. 

7069 

7070 """ 

7071 self.dialect_options 

7072 if on_null is not None: 

7073 if "oracle_on_null" in dialect_kw: 

7074 raise exc.ArgumentError( 

7075 "Cannot specify both 'on_null' and 'oracle_on_null'. " 

7076 "Please use only 'oracle_on_null'." 

7077 ) 

7078 dialect_kw["oracle_on_null"] = on_null 

7079 

7080 IdentityOptions.__init__( 

7081 self, 

7082 start=start, 

7083 increment=increment, 

7084 minvalue=minvalue, 

7085 maxvalue=maxvalue, 

7086 nominvalue=nominvalue, 

7087 nomaxvalue=nomaxvalue, 

7088 cycle=cycle, 

7089 cache=cache, 

7090 order=order, 

7091 **dialect_kw, 

7092 ) 

7093 self.always = always 

7094 self.column = None 

7095 

7096 @property 

7097 def on_null(self) -> Optional[bool]: 

7098 """Alias of the ``dialect_kwargs`` ``'oracle_on_null'``. 

7099 

7100 .. deprecated:: 2.1 The 'on_null' attribute is deprecated. 

7101 """ 

7102 value: Optional[bool] = self.dialect_kwargs.get("oracle_on_null") 

7103 return value 

7104 

7105 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

7106 assert isinstance(parent, Column) 

7107 if not isinstance( 

7108 parent.server_default, (type(None), Identity) 

7109 ) or not isinstance(parent.server_onupdate, type(None)): 

7110 raise exc.ArgumentError( 

7111 "A column with an Identity object cannot specify a " 

7112 "server_default or a server_onupdate argument" 

7113 ) 

7114 if parent.autoincrement is False: 

7115 raise exc.ArgumentError( 

7116 "A column with an Identity object cannot specify " 

7117 "autoincrement=False" 

7118 ) 

7119 self.column = parent 

7120 

7121 parent.identity = self 

7122 if parent._user_defined_nullable is NULL_UNSPECIFIED: 

7123 parent.nullable = False 

7124 

7125 parent.server_default = self 

7126 

7127 def _as_for_update(self, for_update: bool) -> FetchedValue: 

7128 return self 

7129 

7130 @util.deprecated( 

7131 "1.4", 

7132 "The :meth:`_schema.Identity.copy` method is deprecated " 

7133 "and will be removed in a future release.", 

7134 ) 

7135 def copy(self, **kw: Any) -> Identity: 

7136 return self._copy(**kw) 

7137 

7138 def _copy(self, **kw: Any) -> Identity: 

7139 i = Identity(**self._as_dict(), **self.dialect_kwargs) 

7140 

7141 return self._schema_item_copy(i) 

7142 

7143 def _as_dict(self) -> Dict[str, Any]: 

7144 return { 

7145 # always=None means something different than always=False 

7146 "always": self.always, 

7147 **super()._as_dict(), 

7148 }