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

1742 statements  

1# sql/schema.py 

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

3# <see AUTHORS file> 

4# 

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

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

7 

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""" 

31from __future__ import annotations 

32 

33from abc import ABC 

34import collections 

35from enum import Enum 

36import operator 

37import typing 

38from typing import Any 

39from typing import Callable 

40from typing import cast 

41from typing import Collection 

42from typing import Dict 

43from typing import Final 

44from typing import Iterable 

45from typing import Iterator 

46from typing import List 

47from typing import Literal 

48from typing import Mapping 

49from typing import NoReturn 

50from typing import Optional 

51from typing import overload 

52from typing import Protocol 

53from typing import Sequence as _typing_Sequence 

54from typing import Set 

55from typing import Tuple 

56from typing import Type 

57from typing import TYPE_CHECKING 

58from typing import TypedDict 

59from typing import TypeGuard 

60from typing import TypeVar 

61from typing import Union 

62 

63from . import coercions 

64from . import ddl 

65from . import roles 

66from . import type_api 

67from . import visitors 

68from .base import _DefaultDescriptionTuple 

69from .base import _NoArg 

70from .base import _NoneName 

71from .base import _SentinelColumnCharacterization 

72from .base import _SentinelDefaultCharacterization 

73from .base import DedupeColumnCollection 

74from .base import DialectKWArgs 

75from .base import Executable 

76from .base import SchemaEventTarget as SchemaEventTarget 

77from .base import SchemaVisitable as SchemaVisitable 

78from .coercions import _document_text_coercion 

79from .ddl import CheckFirst 

80from .elements import ClauseElement 

81from .elements import ColumnClause 

82from .elements import ColumnElement 

83from .elements import quoted_name 

84from .elements import TextClause 

85from .selectable import TableClause 

86from .type_api import to_instance 

87from .visitors import ExternallyTraversible 

88from .. import event 

89from .. import exc 

90from .. import inspection 

91from .. import util 

92from ..util import HasMemoized 

93from ..util.typing import Self 

94 

95if typing.TYPE_CHECKING: 

96 from ._typing import _AutoIncrementType 

97 from ._typing import _CreateDropBind 

98 from ._typing import _DDLColumnArgument 

99 from ._typing import _DDLColumnReferenceArgument 

100 from ._typing import _InfoType 

101 from ._typing import _TextCoercedExpressionArgument 

102 from ._typing import _TypeEngineArgument 

103 from .base import ColumnSet 

104 from .base import ReadOnlyColumnCollection 

105 from .compiler import DDLCompiler 

106 from .ddl import TableCreateDDL 

107 from .ddl import TableDropDDL 

108 from .elements import BindParameter 

109 from .elements import KeyedColumnElement 

110 from .functions import Function 

111 from .sqltypes import SchemaType 

112 from .type_api import TypeEngine 

113 from .visitors import anon_map 

114 from ..engine import Connection 

115 from ..engine import Engine 

116 from ..engine.interfaces import _CoreMultiExecuteParams 

117 from ..engine.interfaces import CoreExecuteOptionsParameter 

118 from ..engine.interfaces import ExecutionContext 

119 from ..engine.reflection import _ReflectionInfo 

120 from ..sql.selectable import FromClause 

121 

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

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

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

125 

126 

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

128 

129_ServerDefaultArgument = Union[ 

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

131] 

132 

133_ServerOnUpdateArgument = _ServerDefaultArgument 

134 

135 

136class SchemaConst(Enum): 

137 RETAIN_SCHEMA = 1 

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

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

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

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

142 

143 """ 

144 

145 BLANK_SCHEMA = 2 

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

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

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

149 

150 .. seealso:: 

151 

152 :paramref:`_schema.MetaData.schema` 

153 

154 :paramref:`_schema.Table.schema` 

155 

156 :paramref:`.Sequence.schema` 

157 

158 """ 

159 

160 NULL_UNSPECIFIED = 3 

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

162 

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

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

165 on some backends such as SQL Server. 

166 

167 """ 

168 

169 

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

171 SchemaConst.RETAIN_SCHEMA 

172) 

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

174 SchemaConst.BLANK_SCHEMA 

175) 

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

177 SchemaConst.NULL_UNSPECIFIED 

178) 

179 

180 

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

182 if schema is None: 

183 return name 

184 else: 

185 return schema + "." + name 

186 

187 

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

189# break an import cycle 

190def _copy_expression( 

191 expression: ColumnElement[Any], 

192 source_table: Optional[Table], 

193 target_table: Optional[Table], 

194) -> ColumnElement[Any]: 

195 if source_table is None or target_table is None: 

196 return expression 

197 

198 fixed_source_table = source_table 

199 fixed_target_table = target_table 

200 

201 def replace( 

202 element: ExternallyTraversible, **kw: Any 

203 ) -> Optional[ExternallyTraversible]: 

204 if ( 

205 isinstance(element, Column) 

206 and element.table is fixed_source_table 

207 and element.key in fixed_source_table.c 

208 ): 

209 return fixed_target_table.c[element.key] 

210 else: 

211 return None 

212 

213 return cast( 

214 ColumnElement[Any], 

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

216 ) 

217 

218 

219@inspection._self_inspects 

220class SchemaItem(SchemaVisitable): 

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

222 

223 __visit_name__ = "schema_item" 

224 

225 create_drop_stringify_dialect = "default" 

226 

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

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

229 for item in args: 

230 if item is not None: 

231 try: 

232 spwd = item._set_parent_with_dispatch 

233 except AttributeError as err: 

234 raise exc.ArgumentError( 

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

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

237 ) from err 

238 else: 

239 spwd(self, **kw) 

240 

241 def __repr__(self) -> str: 

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

243 

244 @util.memoized_property 

245 def info(self) -> _InfoType: 

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

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

248 

249 The dictionary is automatically generated when first accessed. 

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

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

252 

253 """ 

254 return {} 

255 

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

257 if "info" in self.__dict__: 

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

259 schema_item.dispatch._update(self.dispatch) 

260 return schema_item 

261 

262 _use_schema_map = True 

263 

264 

265class HasConditionalDDL: 

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

267 method, allowing for conditional rendering of DDL. 

268 

269 Currently applies to constraints and indexes. 

270 

271 .. versionadded:: 2.0 

272 

273 

274 """ 

275 

276 _ddl_if: Optional[ddl.DDLIf] = None 

277 

278 def ddl_if( 

279 self, 

280 dialect: Optional[str] = None, 

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

282 state: Optional[Any] = None, 

283 ) -> Self: 

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

285 

286 These rules work in a similar manner to the 

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

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

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

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

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

292 constructs. 

293 

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

295 to indicate multiple dialect types. 

296 

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

298 as that described in 

299 :paramref:`.ExecutableDDLElement.execute_if.callable_`. 

300 

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

302 callable, if present. 

303 

304 .. versionadded:: 2.0 

305 

306 .. seealso:: 

307 

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

309 

310 

311 """ 

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

313 return self 

314 

315 

316class HasSchemaAttr(SchemaItem): 

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

318 

319 schema: Optional[str] 

320 

321 

322class Table( 

323 DialectKWArgs, HasSchemaAttr, TableClause, inspection.Inspectable["Table"] 

324): 

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

326 

327 e.g.:: 

328 

329 mytable = Table( 

330 "mytable", 

331 metadata, 

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

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

334 ) 

335 

336 The :class:`_schema.Table` 

337 object constructs a unique instance of itself based 

338 on its name and optional schema name within the given 

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

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

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

342 object - in this way 

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

344 

345 .. seealso:: 

346 

347 :ref:`metadata_describing` - Introduction to database metadata 

348 

349 """ 

350 

351 __visit_name__ = "table" 

352 

353 if TYPE_CHECKING: 

354 

355 @util.ro_non_memoized_property 

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

357 

358 @util.ro_non_memoized_property 

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

360 

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

362 

363 _sentinel_column: Optional[Column[Any]] 

364 

365 constraints: Set[Constraint] 

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

367 this :class:`_schema.Table`. 

368 

369 Includes :class:`_schema.PrimaryKeyConstraint`, 

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

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

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

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

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

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

376 :class:`_schema.Table`. 

377 

378 .. seealso:: 

379 

380 :attr:`_schema.Table.constraints` 

381 

382 :attr:`_schema.Table.primary_key` 

383 

384 :attr:`_schema.Table.foreign_key_constraints` 

385 

386 :attr:`_schema.Table.indexes` 

387 

388 :class:`_reflection.Inspector` 

389 

390 

391 """ 

392 

393 indexes: Set[Index] 

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

395 :class:`_schema.Table`. 

396 

397 .. seealso:: 

398 

399 :meth:`_reflection.Inspector.get_indexes` 

400 

401 """ 

402 

403 if TYPE_CHECKING: 

404 

405 @util.ro_non_memoized_property 

406 def columns(self) -> ReadOnlyColumnCollection[str, Column[Any]]: ... 

407 

408 @util.ro_non_memoized_property 

409 def exported_columns( 

410 self, 

411 ) -> ReadOnlyColumnCollection[str, Column[Any]]: ... 

412 

413 @util.ro_non_memoized_property 

414 def c(self) -> ReadOnlyColumnCollection[str, Column[Any]]: ... 

415 

416 def _gen_cache_key( 

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

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

419 if self._annotations: 

420 return (self,) + self._annotations_cache_key 

421 else: 

422 return (self,) 

423 

424 if not typing.TYPE_CHECKING: 

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

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

427 # __new__. apply typing to the __init__ method normally 

428 @util.deprecated_params( 

429 mustexist=( 

430 "1.4", 

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

432 ), 

433 ) 

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

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

436 

437 @classmethod 

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

439 if not args and not kw: 

440 # python3k pickle seems to call this 

441 return object.__new__(cls) 

442 

443 try: 

444 name, metadata, args = args[0], args[1], args[2:] 

445 except IndexError: 

446 raise TypeError( 

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

448 "arguments 'name' and 'metadata'" 

449 ) 

450 

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

452 if schema is None: 

453 schema = metadata.schema 

454 elif schema is BLANK_SCHEMA: 

455 schema = None 

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

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

458 

459 if keep_existing and extend_existing: 

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

461 raise exc.ArgumentError(msg) 

462 

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

464 key = _get_table_key(name, schema) 

465 if key in metadata.tables: 

466 if not keep_existing and not extend_existing and bool(args): 

467 raise exc.InvalidRequestError( 

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

469 "instance. Specify 'extend_existing=True' " 

470 "to redefine " 

471 "options and columns on an " 

472 "existing Table object." 

473 ) 

474 table = metadata.tables[key] 

475 if extend_existing: 

476 table._init_existing(*args, **kw) 

477 return table 

478 else: 

479 if must_exist: 

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

481 table = object.__new__(cls) 

482 table.dispatch.before_parent_attach(table, metadata) 

483 metadata._add_table(name, schema, table) 

484 try: 

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

486 table.dispatch.after_parent_attach(table, metadata) 

487 return table 

488 except Exception: 

489 with util.safe_reraise(): 

490 metadata._remove_table(name, schema) 

491 

492 def __init__( 

493 self, 

494 name: str, 

495 metadata: MetaData, 

496 *args: SchemaItem, 

497 schema: Optional[Union[str, Literal[SchemaConst.BLANK_SCHEMA]]] = None, 

498 quote: Optional[bool] = None, 

499 quote_schema: Optional[bool] = None, 

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

501 autoload_replace: bool = True, 

502 keep_existing: bool = False, 

503 extend_existing: bool = False, 

504 resolve_fks: bool = True, 

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

506 implicit_returning: bool = True, 

507 comment: Optional[str] = None, 

508 info: Optional[Dict[Any, Any]] = None, 

509 listeners: Optional[ 

510 _typing_Sequence[Tuple[str, Callable[..., Any]]] 

511 ] = None, 

512 prefixes: Optional[_typing_Sequence[str]] = None, 

513 _creator_ddl: TableCreateDDL | None = None, 

514 _dropper_ddl: TableDropDDL | None = None, 

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

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

517 # used by __new__ to bypass __init__ 

518 _no_init: bool = True, 

519 # dialect-specific keyword args 

520 **kw: Any, 

521 ) -> None: 

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

523 

524 

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

526 

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

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

529 within 

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

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

532 metadata, 

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

534 

535 Names which contain no upper case characters 

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

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

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

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

540 

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

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

543 construct to specify the name. 

544 

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

546 object which will contain this 

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

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

549 may be used to associate this table with a particular 

550 :class:`.Connection` or :class:`.Engine`. 

551 

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

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

554 objects contained within this 

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

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

557 :class:`.PrimaryKeyConstraint`, and 

558 :class:`_schema.ForeignKeyConstraint`. 

559 

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

561 :paramref:`_schema.Table.autoload_with` 

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

563 indicates 

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

565 :class:`_schema.Table` 

566 object should be replaced with columns of the same 

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

568 already present under existing names will be omitted from the 

569 reflection process. 

570 

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

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

573 that 

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

575 replace existing columns of the same name when 

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

577 

578 .. seealso:: 

579 

580 :paramref:`_schema.Table.autoload_with` 

581 

582 :paramref:`_schema.Table.extend_existing` 

583 

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

585 :class:`_engine.Connection` object, 

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

587 :func:`_sa.inspect` 

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

589 object will be reflected. 

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

591 for this table against the given engine or connection. 

592 

593 .. seealso:: 

594 

595 :ref:`metadata_reflection_toplevel` 

596 

597 :meth:`_events.DDLEvents.column_reflect` 

598 

599 :ref:`metadata_reflection_dbagnostic_types` 

600 

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

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

603 :class:`_schema.MetaData`, 

604 apply further arguments within the constructor to the existing 

605 :class:`_schema.Table`. 

606 

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

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

609 and the given name 

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

611 that is 

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

613 and 

614 this :class:`_schema.Table` 

615 specifies additional columns or other constructs 

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

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

618 is to specify what action should be taken when a 

619 :class:`_schema.Table` 

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

621 yet specifies 

622 additional constructs. 

623 

624 :paramref:`_schema.Table.extend_existing` 

625 will also work in conjunction 

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

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

628 of the same name is already present in the target 

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

630 objects 

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

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

633 and options of the same name. 

634 

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

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

637 :class:`_schema.Table` 

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

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

640 objects 

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

642 :class:`_schema.Column` 

643 named "y":: 

644 

645 Table( 

646 "mytable", 

647 metadata, 

648 Column("y", Integer), 

649 extend_existing=True, 

650 autoload_with=engine, 

651 ) 

652 

653 .. seealso:: 

654 

655 :paramref:`_schema.Table.autoload_with` 

656 

657 :paramref:`_schema.Table.autoload_replace` 

658 

659 :paramref:`_schema.Table.keep_existing` 

660 

661 

662 :param implicit_returning: True by default - indicates that 

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

664 server-generated values such as primary key values and 

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

666 

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

668 setting, except for some backend specific cases 

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

670 for one such example). 

671 

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

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

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

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

676 should be reflected. 

677 

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

679 objects 

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

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

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

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

684 objects are encountered; may be 

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

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

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

688 a 

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

690 :class:`_schema.Table` will 

691 resolve to that table normally. 

692 

693 .. seealso:: 

694 

695 :paramref:`.MetaData.reflect.resolve_fks` 

696 

697 

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

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

700 

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

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

703 further arguments within the constructor to the existing 

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

705 object as 

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

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

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

709 without any of the declarations (particularly constraints) 

710 being applied a second time. 

711 

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

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

714 and the given name 

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

716 that is 

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

718 and 

719 this :class:`_schema.Table` 

720 specifies additional columns or other constructs 

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

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

723 is to specify what action should be taken when a 

724 :class:`_schema.Table` 

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

726 yet specifies 

727 additional constructs. 

728 

729 .. seealso:: 

730 

731 :paramref:`_schema.Table.extend_existing` 

732 

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

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

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

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

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

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

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

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

741 

742 def listen_for_reflect(table, column_info): 

743 "handle the column reflection event" 

744 # ... 

745 

746 

747 t = Table( 

748 "sometable", 

749 autoload_with=engine, 

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

751 ) 

752 

753 .. seealso:: 

754 

755 :meth:`_events.DDLEvents.column_reflect` 

756 

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

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

759 an exception is raised. 

760 

761 :param prefixes: 

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

763 statement. They will be separated by spaces. 

764 

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

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

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

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

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

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

771 by the SQLAlchemy dialect. 

772 

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

774 case-insensitive behavior for table reflection; table reflection 

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

776 fashion. Case insensitive names are specified in SQLAlchemy only 

777 by stating the name with all lower case characters. 

778 

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

780 

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

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

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

784 

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

786 specifies its 

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

788 then that schema name will 

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

790 if the schema parameter here is set 

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

792 that 

793 would otherwise use the schema set on the owning 

794 :class:`_schema.MetaData`, 

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

796 

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

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

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

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

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

802 

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

804 creation. 

805 

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

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

808 See the documentation regarding an individual dialect at 

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

810 

811 """ # noqa: E501 

812 if _no_init: 

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

814 # __new__ has a specific place that __init__ is called 

815 return 

816 

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

818 self.metadata = metadata 

819 

820 if schema is None: 

821 self.schema = metadata.schema 

822 elif schema is BLANK_SCHEMA: 

823 self.schema = None 

824 else: 

825 quote_schema = quote_schema 

826 assert isinstance(schema, str) 

827 self.schema = quoted_name(schema, quote_schema) 

828 

829 self._sentinel_column = None 

830 self._creator_ddl = _creator_ddl 

831 self._dropper_ddl = _dropper_ddl 

832 

833 self.indexes = set() 

834 self.constraints = set() 

835 PrimaryKeyConstraint( 

836 _implicit_generated=True 

837 )._set_parent_with_dispatch(self) 

838 self.foreign_keys = set() # type: ignore 

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

840 if self.schema is not None: 

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

842 else: 

843 self.fullname = self.name 

844 

845 self.implicit_returning = implicit_returning 

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

847 

848 self.comment = comment 

849 

850 if info is not None: 

851 self.info = info 

852 

853 if listeners is not None: 

854 for evt, fn in listeners: 

855 event.listen(self, evt, fn) 

856 

857 self._prefixes = prefixes if prefixes else [] 

858 

859 self._extra_kwargs(**kw) 

860 

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

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

863 # circular foreign keys 

864 if autoload_with is not None: 

865 self._autoload( 

866 metadata, 

867 autoload_with, 

868 include_columns, 

869 _extend_on=_extend_on, 

870 _reflect_info=_reflect_info, 

871 resolve_fks=resolve_fks, 

872 ) 

873 

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

875 # allow user-overrides 

876 

877 self._init_items( 

878 *args, 

879 allow_replacements=extend_existing 

880 or keep_existing 

881 or autoload_with, 

882 all_names={}, 

883 ) 

884 

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

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

887 

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

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

890 used. 

891 

892 E.g.:: 

893 

894 from sqlalchemy.schema import CreateTable 

895 

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

897 

898 .. versionadded:: 2.1 

899 

900 .. seealso:: 

901 

902 :meth:`.Table.set_dropper_ddl` 

903 

904 """ 

905 self._creator_ddl = ddl 

906 

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

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

909 

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

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

912 used. 

913 

914 E.g.:: 

915 

916 from sqlalchemy.schema import DropTable 

917 

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

919 

920 .. versionadded:: 2.1 

921 

922 .. seealso:: 

923 

924 :meth:`.Table.set_creator_ddl` 

925 

926 """ 

927 self._dropper_ddl = ddl 

928 

929 @property 

930 def is_view(self) -> bool: 

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

932 CREATE VIEW rather than CREATE TABLE. 

933 

934 .. versionadded:: 2.1 

935 

936 """ 

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

938 

939 def _autoload( 

940 self, 

941 metadata: MetaData, 

942 autoload_with: Union[Engine, Connection], 

943 include_columns: Optional[Collection[str]], 

944 exclude_columns: Collection[str] = (), 

945 resolve_fks: bool = True, 

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

947 _reflect_info: _ReflectionInfo | None = None, 

948 ) -> None: 

949 insp = inspection.inspect(autoload_with) 

950 with insp._inspection_context() as conn_insp: 

951 conn_insp.reflect_table( 

952 self, 

953 include_columns, 

954 exclude_columns, 

955 resolve_fks, 

956 _extend_on=_extend_on, 

957 _reflect_info=_reflect_info, 

958 ) 

959 

960 @property 

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

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

963 order. 

964 

965 """ 

966 

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

968 

969 @property 

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

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

972 :class:`_schema.Table`. 

973 

974 This list is produced from the collection of 

975 :class:`_schema.ForeignKey` 

976 objects currently associated. 

977 

978 

979 .. seealso:: 

980 

981 :attr:`_schema.Table.constraints` 

982 

983 :attr:`_schema.Table.foreign_keys` 

984 

985 :attr:`_schema.Table.indexes` 

986 

987 """ 

988 return { 

989 fkc.constraint 

990 for fkc in self.foreign_keys 

991 if fkc.constraint is not None 

992 } 

993 

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

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

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

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

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

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

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

1001 

1002 # these arguments are only used with _init() 

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

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

1005 

1006 assert extend_existing 

1007 assert not keep_existing 

1008 

1009 if schema and schema != self.schema: 

1010 raise exc.ArgumentError( 

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

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

1013 ) 

1014 

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

1016 if include_columns is not None: 

1017 for c in self.c: 

1018 if c.name not in include_columns: 

1019 self._columns.remove(c) 

1020 

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

1022 

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

1024 if key in kwargs: 

1025 raise exc.ArgumentError( 

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

1027 ) 

1028 

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

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

1031 self.implicit_returning = kwargs.pop( 

1032 "implicit_returning", self.implicit_returning 

1033 ) 

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

1035 

1036 exclude_columns: _typing_Sequence[str] 

1037 

1038 if autoload: 

1039 if not autoload_replace: 

1040 # don't replace columns already present. 

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

1042 # have simple de-duping for unnamed constraints. 

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

1044 else: 

1045 exclude_columns = () 

1046 self._autoload( 

1047 self.metadata, 

1048 autoload_with, 

1049 include_columns, 

1050 exclude_columns, 

1051 resolve_fks, 

1052 _extend_on=_extend_on, 

1053 _reflect_info=_reflect_info, 

1054 ) 

1055 

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

1057 self._extra_kwargs(**kwargs) 

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

1059 

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

1061 self._validate_dialect_kwargs(kwargs) 

1062 

1063 def _init_collections(self) -> None: 

1064 pass 

1065 

1066 def _reset_exported(self) -> None: 

1067 pass 

1068 

1069 @util.ro_non_memoized_property 

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

1071 return self.primary_key._autoincrement_column 

1072 

1073 @util.ro_memoized_property 

1074 def _sentinel_column_characteristics( 

1075 self, 

1076 ) -> _SentinelColumnCharacterization: 

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

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

1079 "insert sentinel" for an INSERT statement. 

1080 

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

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

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

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

1085 dialect. 

1086 

1087 .. versionadded:: 2.0.10 

1088 

1089 """ 

1090 

1091 sentinel_is_explicit = False 

1092 sentinel_is_autoinc = False 

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

1094 

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

1096 explicit_sentinel_col = self._sentinel_column 

1097 

1098 if explicit_sentinel_col is not None: 

1099 the_sentinel = (explicit_sentinel_col,) 

1100 sentinel_is_explicit = True 

1101 

1102 autoinc_col = self._autoincrement_column 

1103 if sentinel_is_explicit and explicit_sentinel_col is autoinc_col: 

1104 assert autoinc_col is not None 

1105 sentinel_is_autoinc = True 

1106 elif explicit_sentinel_col is None and autoinc_col is not None: 

1107 the_sentinel = (autoinc_col,) 

1108 sentinel_is_autoinc = True 

1109 

1110 default_characterization = _SentinelDefaultCharacterization.UNKNOWN 

1111 

1112 if the_sentinel: 

1113 the_sentinel_zero = the_sentinel[0] 

1114 if the_sentinel_zero.identity: 

1115 if the_sentinel_zero.identity._increment_is_negative: 

1116 if sentinel_is_explicit: 

1117 raise exc.InvalidRequestError( 

1118 "Can't use IDENTITY default with negative " 

1119 "increment as an explicit sentinel column" 

1120 ) 

1121 else: 

1122 if sentinel_is_autoinc: 

1123 autoinc_col = None 

1124 sentinel_is_autoinc = False 

1125 the_sentinel = None 

1126 else: 

1127 default_characterization = ( 

1128 _SentinelDefaultCharacterization.IDENTITY 

1129 ) 

1130 elif ( 

1131 the_sentinel_zero.default is None 

1132 and the_sentinel_zero.server_default is None 

1133 ): 

1134 if the_sentinel_zero.nullable: 

1135 raise exc.InvalidRequestError( 

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

1137 "sentinel " 

1138 "column with no default generation function; it " 

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

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

1141 ) 

1142 default_characterization = ( 

1143 _SentinelDefaultCharacterization.NONE 

1144 ) 

1145 elif the_sentinel_zero.default is not None: 

1146 if the_sentinel_zero.default.is_sentinel: 

1147 default_characterization = ( 

1148 _SentinelDefaultCharacterization.SENTINEL_DEFAULT 

1149 ) 

1150 elif the_sentinel_zero.default._is_monotonic_fn: 

1151 default_characterization = ( 

1152 _SentinelDefaultCharacterization.MONOTONIC_FUNCTION 

1153 ) 

1154 elif default_is_sequence(the_sentinel_zero.default): 

1155 if the_sentinel_zero.default._increment_is_negative: 

1156 if sentinel_is_explicit: 

1157 raise exc.InvalidRequestError( 

1158 "Can't use SEQUENCE default with negative " 

1159 "increment as an explicit sentinel column" 

1160 ) 

1161 else: 

1162 if sentinel_is_autoinc: 

1163 autoinc_col = None 

1164 sentinel_is_autoinc = False 

1165 the_sentinel = None 

1166 

1167 default_characterization = ( 

1168 _SentinelDefaultCharacterization.SEQUENCE 

1169 ) 

1170 elif the_sentinel_zero.default.is_callable: 

1171 default_characterization = ( 

1172 _SentinelDefaultCharacterization.CLIENTSIDE 

1173 ) 

1174 elif the_sentinel_zero.server_default is not None: 

1175 if sentinel_is_explicit: 

1176 if not the_sentinel_zero.server_default._is_monotonic_fn: 

1177 raise exc.InvalidRequestError( 

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

1179 "column " 

1180 "because it uses an explicit server side default " 

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

1182 ) 

1183 else: 

1184 default_characterization = ( 

1185 _SentinelDefaultCharacterization.MONOTONIC_FUNCTION 

1186 ) 

1187 else: 

1188 default_characterization = ( 

1189 _SentinelDefaultCharacterization.SERVERSIDE 

1190 ) 

1191 

1192 if the_sentinel is None and self.primary_key: 

1193 assert autoinc_col is None 

1194 

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

1196 # client side 

1197 for _pkc in self.primary_key: 

1198 if ( 

1199 _pkc.server_default is not None 

1200 and not _pkc.server_default._is_monotonic_fn 

1201 ): 

1202 break 

1203 

1204 if ( 

1205 _pkc.default 

1206 and not _pkc.default.is_callable 

1207 and not _pkc.default._is_monotonic_fn 

1208 ): 

1209 break 

1210 else: 

1211 the_sentinel = tuple(self.primary_key) 

1212 default_characterization = ( 

1213 _SentinelDefaultCharacterization.CLIENTSIDE 

1214 ) 

1215 

1216 return _SentinelColumnCharacterization( 

1217 the_sentinel, 

1218 sentinel_is_explicit, 

1219 sentinel_is_autoinc, 

1220 default_characterization, 

1221 ) 

1222 

1223 @property 

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

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

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

1227 

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

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

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

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

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

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

1234 "autoincrement" column. 

1235 

1236 .. versionadded:: 2.0.4 

1237 

1238 .. seealso:: 

1239 

1240 :paramref:`.Column.autoincrement` 

1241 

1242 """ 

1243 return self._autoincrement_column 

1244 

1245 @property 

1246 def key(self) -> str: 

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

1248 

1249 This value is used as the dictionary key within the 

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

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

1252 :attr:`_schema.Table.schema` 

1253 set; otherwise it is typically of the form 

1254 ``schemaname.tablename``. 

1255 

1256 """ 

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

1258 

1259 def __repr__(self) -> str: 

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

1261 [repr(self.name)] 

1262 + [repr(self.metadata)] 

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

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

1265 ) 

1266 

1267 def __str__(self) -> str: 

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

1269 

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

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

1272 

1273 This is another Table object which must be created 

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

1275 

1276 Usually, dependencies between tables are determined via 

1277 ForeignKey objects. However, for other situations that 

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

1279 this method can manually establish such a link. 

1280 

1281 """ 

1282 self._extra_dependencies.add(table) 

1283 

1284 def _insert_col_impl( 

1285 self, 

1286 column: ColumnClause[Any], 

1287 *, 

1288 index: Optional[int] = None, 

1289 replace_existing: bool = False, 

1290 ) -> None: 

1291 try: 

1292 column._set_parent_with_dispatch( 

1293 self, 

1294 allow_replacements=replace_existing, 

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

1296 index=index, 

1297 ) 

1298 except exc.DuplicateColumnError as de: 

1299 raise exc.DuplicateColumnError( 

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

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

1302 "existing column." 

1303 ) from de 

1304 

1305 def insert_column( 

1306 self, 

1307 column: ColumnClause[Any], 

1308 index: int, 

1309 *, 

1310 replace_existing: bool = False, 

1311 ) -> None: 

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

1313 a specific position. 

1314 

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

1316 the index position can be controlled using the 

1317 :paramref:`.Table.insert_column.index` 

1318 parameter. 

1319 

1320 :param replace_existing: 

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

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

1323 

1324 .. versionadded:: 2.1 

1325 

1326 """ 

1327 self._insert_col_impl( 

1328 column, index=index, replace_existing=replace_existing 

1329 ) 

1330 

1331 def append_column( 

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

1333 ) -> None: 

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

1335 

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

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

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

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

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

1341 construct. 

1342 

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

1344 as it exists within any underlying database, assuming that 

1345 table has already been created in the database. Relational 

1346 databases support the addition of columns to existing tables 

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

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

1349 the newly added column. 

1350 

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

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

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

1354 version of sqlalchemy will instead rise a warning. 

1355 

1356 .. versionadded:: 1.4.0 

1357 

1358 .. seealso:: 

1359 

1360 :meth:`.Table.insert_column` 

1361 

1362 """ 

1363 self._insert_col_impl(column, replace_existing=replace_existing) 

1364 

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

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

1367 :class:`_schema.Table`. 

1368 

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

1370 future CREATE TABLE statement, assuming specific DDL creation 

1371 events have not been associated with the given 

1372 :class:`_schema.Constraint` object. 

1373 

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

1375 relational database automatically, for a table that already exists 

1376 in the database. To add a constraint to an 

1377 existing relational database table, the SQL ALTER command must 

1378 be used. SQLAlchemy also provides the 

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

1380 invoked as an executable clause. 

1381 

1382 """ 

1383 

1384 constraint._set_parent_with_dispatch(self) 

1385 

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

1387 metadata = parent 

1388 assert isinstance(metadata, MetaData) 

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

1390 self.metadata = metadata 

1391 

1392 def create( 

1393 self, 

1394 bind: _CreateDropBind, 

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

1396 ) -> None: 

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

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

1399 :class:`.Connection` or :class:`.Engine` 

1400 for connectivity. 

1401 

1402 .. seealso:: 

1403 

1404 :meth:`_schema.MetaData.create_all`. 

1405 

1406 """ 

1407 

1408 # the default is to only check for schema objects 

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

1410 

1411 def drop( 

1412 self, 

1413 bind: _CreateDropBind, 

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

1415 ) -> None: 

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

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

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

1419 

1420 .. seealso:: 

1421 

1422 :meth:`_schema.MetaData.drop_all`. 

1423 

1424 """ 

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

1426 

1427 @util.deprecated( 

1428 "1.4", 

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

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

1431 ) 

1432 def tometadata( 

1433 self, 

1434 metadata: MetaData, 

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

1436 referred_schema_fn: Optional[ 

1437 Callable[ 

1438 [Table, Optional[str], ForeignKeyConstraint, Optional[str]], 

1439 Optional[str], 

1440 ] 

1441 ] = None, 

1442 name: Optional[str] = None, 

1443 ) -> Table: 

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

1445 associated with a different 

1446 :class:`_schema.MetaData`. 

1447 

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

1449 

1450 """ 

1451 return self.to_metadata( 

1452 metadata, 

1453 schema=schema, 

1454 referred_schema_fn=referred_schema_fn, 

1455 name=name, 

1456 ) 

1457 

1458 def to_metadata( 

1459 self, 

1460 metadata: MetaData, 

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

1462 referred_schema_fn: Optional[ 

1463 Callable[ 

1464 [Table, Optional[str], ForeignKeyConstraint, Optional[str]], 

1465 Optional[str], 

1466 ] 

1467 ] = None, 

1468 name: Optional[str] = None, 

1469 ) -> Table: 

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

1471 different :class:`_schema.MetaData`. 

1472 

1473 E.g.:: 

1474 

1475 m1 = MetaData() 

1476 

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

1478 

1479 m2 = MetaData() 

1480 user_copy = user.to_metadata(m2) 

1481 

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

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

1484 

1485 

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

1487 into which the 

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

1489 

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

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

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

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

1494 :class:`_schema.Table` 

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

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

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

1498 unless 

1499 set explicitly:: 

1500 

1501 m2 = MetaData(schema="newschema") 

1502 

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

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

1505 

1506 m3 = MetaData() # schema defaults to None 

1507 

1508 # user_copy_two will have None as the schema name 

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

1510 

1511 :param referred_schema_fn: optional callable which can be supplied 

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

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

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

1515 target schema that we are changing to, the 

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

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

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

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

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

1521 

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

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

1524 symbols. 

1525 

1526 E.g.:: 

1527 

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

1529 if referred_schema == "base_tables": 

1530 return referred_schema 

1531 else: 

1532 return to_schema 

1533 

1534 

1535 new_table = table.to_metadata( 

1536 m2, schema="alt_schema", referred_schema_fn=referred_schema_fn 

1537 ) 

1538 

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

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

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

1542 :class:`_schema.MetaData` target 

1543 with a new name. 

1544 

1545 """ # noqa: E501 

1546 if name is None: 

1547 name = self.name 

1548 

1549 actual_schema: Optional[str] 

1550 

1551 if schema is RETAIN_SCHEMA: 

1552 actual_schema = self.schema 

1553 elif schema is None: 

1554 actual_schema = metadata.schema 

1555 else: 

1556 actual_schema = schema 

1557 key = _get_table_key(name, actual_schema) 

1558 if key in metadata.tables: 

1559 util.warn( 

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

1561 "MetaData - not copying." 

1562 ) 

1563 return metadata.tables[key] 

1564 

1565 args = [] 

1566 for col in self.columns: 

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

1568 

1569 table = Table( 

1570 name, 

1571 metadata, 

1572 schema=actual_schema, 

1573 comment=self.comment, 

1574 *args, 

1575 **self.kwargs, 

1576 ) 

1577 

1578 if self._creator_ddl is not None: 

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

1580 if self._dropper_ddl is not None: 

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

1582 

1583 for const in self.constraints: 

1584 if isinstance(const, ForeignKeyConstraint): 

1585 referred_schema = const._referred_schema 

1586 if referred_schema_fn: 

1587 fk_constraint_schema = referred_schema_fn( 

1588 self, actual_schema, const, referred_schema 

1589 ) 

1590 else: 

1591 fk_constraint_schema = ( 

1592 actual_schema 

1593 if referred_schema == self.schema 

1594 else None 

1595 ) 

1596 table.append_constraint( 

1597 const._copy( 

1598 schema=fk_constraint_schema, target_table=table 

1599 ) 

1600 ) 

1601 elif not const._type_bound: 

1602 # skip unique constraints that would be generated 

1603 # by the 'unique' flag on Column 

1604 if const._column_flag: 

1605 continue 

1606 

1607 table.append_constraint( 

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

1609 ) 

1610 for index in self.indexes: 

1611 # skip indexes that would be generated 

1612 # by the 'index' flag on Column 

1613 if index._column_flag: 

1614 continue 

1615 Index( 

1616 index.name, 

1617 unique=index.unique, 

1618 *[ 

1619 _copy_expression(expr, self, table) 

1620 for expr in index._table_bound_expressions 

1621 ], 

1622 _table=table, 

1623 **index.kwargs, 

1624 ) 

1625 return self._schema_item_copy(table) 

1626 

1627 

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

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

1630 

1631 __visit_name__ = "column" 

1632 

1633 inherit_cache = True 

1634 key: str 

1635 

1636 server_default: Optional[FetchedValue] 

1637 

1638 def __init__( 

1639 self, 

1640 __name_pos: Optional[ 

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

1642 ] = None, 

1643 __type_pos: Optional[ 

1644 Union[_TypeEngineArgument[_T], SchemaEventTarget] 

1645 ] = None, 

1646 /, 

1647 *args: SchemaEventTarget, 

1648 name: Optional[str] = None, 

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

1650 autoincrement: _AutoIncrementType = "auto", 

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

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

1653 doc: Optional[str] = None, 

1654 key: Optional[str] = None, 

1655 index: Optional[bool] = None, 

1656 unique: Optional[bool] = None, 

1657 info: Optional[_InfoType] = None, 

1658 nullable: Optional[ 

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

1660 ] = SchemaConst.NULL_UNSPECIFIED, 

1661 onupdate: Optional[Any] = None, 

1662 primary_key: bool = False, 

1663 server_default: Optional[_ServerDefaultArgument] = None, 

1664 server_onupdate: Optional[_ServerOnUpdateArgument] = None, 

1665 quote: Optional[bool] = None, 

1666 system: bool = False, 

1667 comment: Optional[str] = None, 

1668 insert_sentinel: bool = False, 

1669 _omit_from_statements: bool = False, 

1670 _proxies: Optional[Any] = None, 

1671 **dialect_kwargs: Any, 

1672 ): 

1673 r""" 

1674 Construct a new ``Column`` object. 

1675 

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

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

1678 via keyword. 

1679 

1680 Names which contain no upper case characters 

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

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

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

1684 behavior applies even for databases which standardize upper 

1685 case names as case insensitive such as Oracle Database. 

1686 

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

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

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

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

1691 

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

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

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

1695 as well, e.g.:: 

1696 

1697 # use a type with arguments 

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

1699 

1700 # use no arguments 

1701 Column("level", Integer) 

1702 

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

1704 or specified by keyword. 

1705 

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

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

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

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

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

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

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

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

1714 

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

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

1717 as options to the column. These include instances of 

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

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

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

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

1722 ``default`` and ``unique``. 

1723 

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

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

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

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

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

1729 will be considered when INSERT statements are compiled and 

1730 executed. 

1731 

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

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

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

1735 default constructs indicated should receive auto increment semantics 

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

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

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

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

1740 key columns, see below). 

1741 

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

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

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

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

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

1747 database: 

1748 

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

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

1751 no other 

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

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

1754 will imply that database-specific keywords such as PostgreSQL 

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

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

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

1758 backends alway needs an explicit construct such as 

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

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

1761 be produced in the database. 

1762 

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

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

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

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

1767 value automatically for this column, which will be accessible 

1768 after the statement is invoked via the 

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

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

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

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

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

1774 behavior takes place regardless of what DDL constructs are 

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

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

1777 above. 

1778 

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

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

1781 have autoincrement semantics, though note that only one column 

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

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

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

1785 however note that not all dialects can accommodate all styles 

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

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

1788 datatype of INTEGER in order to disable auto increment semantics 

1789 for that column. 

1790 

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

1792 

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

1794 

1795 * Part of the primary key 

1796 

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

1798 unless 

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

1800 

1801 # turn on autoincrement for this column despite 

1802 # the ForeignKey() 

1803 Column( 

1804 "id", 

1805 ForeignKey("other.id"), 

1806 primary_key=True, 

1807 autoincrement="ignore_fk", 

1808 ) 

1809 

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

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

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

1813 

1814 The setting has these effects on columns that meet the 

1815 above criteria: 

1816 

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

1818 a default generating construct supported by the backend such as 

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

1820 keywords intended to signify this column as an 

1821 "autoincrement" column for specific backends. Behavior for 

1822 primary SQLAlchemy dialects includes: 

1823 

1824 * AUTO INCREMENT on MySQL and MariaDB 

1825 * SERIAL on PostgreSQL 

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

1827 :class:`.Identity` construct as the 

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

1829 construct. 

1830 * SQLite - SQLite integer primary key columns are implicitly 

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

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

1833 is not included as this is unnecessary and not recommended 

1834 by the database vendor. See the section 

1835 :ref:`sqlite_autoincrement` for more background. 

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

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

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

1839 construct may also be used). 

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

1841 for details on their specific behaviors. 

1842 

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

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

1845 modifier, newly generated primary key values for this column 

1846 will be automatically retrieved upon statement execution 

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

1848 

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

1850 (see 

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

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

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

1854 construct when rendering an INSERT statement, and then retrieving 

1855 the newly generated primary key values after execution 

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

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

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

1859 explicitly before the INSERT statement takes place so that the 

1860 newly generated primary key value is available to the client 

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

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

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

1864 INSERT statement is invoked to retrieve the newly generated 

1865 primary key value. 

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

1867 for details on their specific behaviors. 

1868 

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

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

1871 retrieving behaviors are generally disabled, however there may 

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

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

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

1875 may not yet be well covered in documentation. 

1876 

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

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

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

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

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

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

1883 structure of the argument. 

1884 

1885 Contrast this argument to 

1886 :paramref:`_schema.Column.server_default` 

1887 which creates a default generator on the database side. 

1888 

1889 .. seealso:: 

1890 

1891 :ref:`metadata_defaults_toplevel` 

1892 

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

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

1895 

1896 .. versionadded:: 2.0.31 

1897 

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

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

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

1901 :paramref:`_schema.Column.comment` 

1902 parameter for this purpose. 

1903 

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

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

1906 When a key is provided, 

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

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

1909 is used only when rendering SQL. 

1910 

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

1912 construct will be automatically generated for this 

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

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

1915 create operation is invoked. 

1916 

1917 Using this flag is equivalent to making use of the 

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

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

1920 

1921 Table( 

1922 "some_table", 

1923 metadata, 

1924 Column("x", Integer), 

1925 Index("ix_some_table_x", "x"), 

1926 ) 

1927 

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

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

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

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

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

1933 DDL instruction instead of "CREATE INDEX". 

1934 

1935 The name of the index is generated using the 

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

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

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

1939 

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

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

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

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

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

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

1946 indexes that use a specific name. 

1947 

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

1949 :class:`_schema.Column` 

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

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

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

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

1954 

1955 .. seealso:: 

1956 

1957 :ref:`schema_indexes` 

1958 

1959 :ref:`constraint_naming_conventions` 

1960 

1961 :paramref:`_schema.Column.unique` 

1962 

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

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

1965 

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

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

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

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

1970 where "NULL" may render explicitly. 

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

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

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

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

1975 

1976 .. note:: 

1977 

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

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

1980 PostgreSQL database allows nullable identity column by 

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

1982 

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

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

1985 default value to be applied to the column within UPDATE 

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

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

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

1989 ``for_update=True``. 

1990 

1991 .. seealso:: 

1992 

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

1994 

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

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

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

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

1999 :class:`.PrimaryKeyConstraint` object. 

2000 

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

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

2003 the DDL DEFAULT value for the column. 

2004 

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

2006 

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

2008 

2009 will render: 

2010 

2011 .. sourcecode:: sql 

2012 

2013 x TEXT DEFAULT 'val' 

2014 

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

2016 rendered as-is, without quotes:: 

2017 

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

2019 

2020 will render: 

2021 

2022 .. sourcecode:: sql 

2023 

2024 y DATETIME DEFAULT NOW() 

2025 

2026 Strings and text() will be converted into a 

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

2028 

2029 This parameter can also accept complex combinations of contextually 

2030 valid SQLAlchemy expressions or constructs:: 

2031 

2032 from sqlalchemy import create_engine 

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

2034 from sqlalchemy.dialects.postgresql import array 

2035 

2036 engine = create_engine( 

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

2038 ) 

2039 metadata_obj = MetaData() 

2040 tbl = Table( 

2041 "foo", 

2042 metadata_obj, 

2043 Column( 

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

2045 ), 

2046 ) 

2047 metadata_obj.create_all(engine) 

2048 

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

2050 

2051 .. sourcecode:: sql 

2052 

2053 CREATE TABLE foo ( 

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

2055 ) 

2056 

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

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

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

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

2061 to the database, such as via a trigger. 

2062 

2063 .. seealso:: 

2064 

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

2066 defaults 

2067 

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

2069 representing a database-side default generation function, 

2070 such as a trigger. This 

2071 indicates to SQLAlchemy that a newly generated value will be 

2072 available after updates. This construct does not actually 

2073 implement any kind of generation function within the database, 

2074 which instead must be specified separately. 

2075 

2076 

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

2078 "ON UPDATE CURRENT_TIMESTAMP()" clause. See 

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

2080 produce this clause. 

2081 

2082 .. seealso:: 

2083 

2084 :ref:`triggered_columns` 

2085 

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

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

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

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

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

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

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

2093 

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

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

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

2097 construct will be automatically generated for this 

2098 :class:`_schema.Column`, 

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

2100 to this column being included 

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

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

2103 

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

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

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

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

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

2109 is generated. See the documentation for 

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

2111 

2112 Using this flag is equivalent to making use of the 

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

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

2115 

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

2117 

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

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

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

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

2122 construct will be emitted as unnamed, which typically invokes 

2123 a database-specific naming convention to take place. 

2124 

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

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

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

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

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

2130 constraints that use a specific name. 

2131 

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

2133 :class:`_schema.Column` 

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

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

2136 indexes and unique constraints that may involve this column, 

2137 view the 

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

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

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

2141 :meth:`_reflection.Inspector.get_unique_constraints` 

2142 

2143 .. seealso:: 

2144 

2145 :ref:`schema_unique_constraint` 

2146 

2147 :ref:`constraint_naming_conventions` 

2148 

2149 :paramref:`_schema.Column.index` 

2150 

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

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

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

2154 ``CREATE TABLE`` statement. 

2155 

2156 For more elaborate scenarios where columns should be 

2157 conditionally rendered differently on different backends, 

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

2159 

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

2161 table creation. 

2162 

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

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

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

2166 otherwise have qualifying primary key configurations. 

2167 

2168 .. versionadded:: 2.0.10 

2169 

2170 .. seealso:: 

2171 

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

2173 sentinel columns 

2174 

2175 :ref:`engine_insertmanyvalues` 

2176 

2177 :ref:`engine_insertmanyvalues_sentinel_columns` 

2178 

2179 

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

2181 

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

2183 del args 

2184 

2185 if l_args: 

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

2187 if name is not None: 

2188 raise exc.ArgumentError( 

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

2190 ) 

2191 name = l_args.pop(0) # type: ignore 

2192 elif l_args[0] is None: 

2193 l_args.pop(0) 

2194 if l_args: 

2195 coltype = l_args[0] 

2196 

2197 if hasattr(coltype, "_sqla_type"): 

2198 if type_ is not None: 

2199 raise exc.ArgumentError( 

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

2201 ) 

2202 type_ = l_args.pop(0) # type: ignore 

2203 elif l_args[0] is None: 

2204 l_args.pop(0) 

2205 

2206 if name is not None: 

2207 name = quoted_name(name, quote) 

2208 elif quote is not None: 

2209 raise exc.ArgumentError( 

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

2211 ) 

2212 

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

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

2215 # dedicated "column" construct local to the ORM 

2216 super().__init__(name, type_) # type: ignore 

2217 

2218 self.key = key if key is not None else name # type: ignore 

2219 self.primary_key = primary_key 

2220 self._insert_sentinel = insert_sentinel 

2221 self._omit_from_statements = _omit_from_statements 

2222 self._user_defined_nullable = udn = nullable 

2223 if udn is not NULL_UNSPECIFIED: 

2224 self.nullable = udn 

2225 else: 

2226 self.nullable = not primary_key 

2227 

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

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

2230 # Index or UniqueConstraint referring to this Column. 

2231 self.index = index 

2232 self.unique = unique 

2233 

2234 self.system = system 

2235 self.doc = doc 

2236 self.autoincrement: _AutoIncrementType = autoincrement 

2237 self.constraints = set() 

2238 self.foreign_keys = set() 

2239 self.comment = comment 

2240 self.computed = None 

2241 self.identity = None 

2242 

2243 # check if this Column is proxying another column 

2244 

2245 if _proxies is not None: 

2246 self._proxies = _proxies 

2247 else: 

2248 # otherwise, add DDL-related events 

2249 self._set_type(self.type) 

2250 

2251 if insert_default is not _NoArg.NO_ARG: 

2252 if default is not _NoArg.NO_ARG: 

2253 raise exc.ArgumentError( 

2254 "The 'default' and 'insert_default' parameters " 

2255 "of Column are mutually exclusive" 

2256 ) 

2257 resolved_default = insert_default 

2258 elif default is not _NoArg.NO_ARG: 

2259 resolved_default = default 

2260 else: 

2261 resolved_default = None 

2262 

2263 if resolved_default is not None: 

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

2265 resolved_default = ColumnDefault(resolved_default) 

2266 

2267 self.default = resolved_default 

2268 l_args.append(resolved_default) 

2269 else: 

2270 self.default = None 

2271 

2272 if onupdate is not None: 

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

2274 onupdate = ColumnDefault(onupdate, for_update=True) 

2275 

2276 self.onupdate = onupdate 

2277 l_args.append(onupdate) 

2278 else: 

2279 self.onupdate = None 

2280 

2281 if server_default is not None: 

2282 if isinstance(server_default, FetchedValue): 

2283 server_default = server_default._as_for_update(False) 

2284 l_args.append(server_default) 

2285 else: 

2286 server_default = DefaultClause(server_default) 

2287 l_args.append(server_default) 

2288 self.server_default = server_default 

2289 

2290 if server_onupdate is not None: 

2291 if isinstance(server_onupdate, FetchedValue): 

2292 server_onupdate = server_onupdate._as_for_update(True) 

2293 l_args.append(server_onupdate) 

2294 else: 

2295 server_onupdate = DefaultClause( 

2296 server_onupdate, for_update=True 

2297 ) 

2298 l_args.append(server_onupdate) 

2299 self.server_onupdate = server_onupdate 

2300 

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

2302 

2303 util.set_creation_order(self) 

2304 

2305 if info is not None: 

2306 self.info = info 

2307 

2308 self._extra_kwargs(**dialect_kwargs) 

2309 

2310 table: Table 

2311 

2312 constraints: Set[Constraint] 

2313 

2314 foreign_keys: Set[ForeignKey] 

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

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

2317 

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

2319 :class:`_schema.ForeignKeyConstraint`. 

2320 

2321 .. seealso:: 

2322 

2323 :attr:`_schema.Table.foreign_keys` 

2324 

2325 """ 

2326 

2327 index: Optional[bool] 

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

2329 

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

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

2332 

2333 .. seealso:: 

2334 

2335 :attr:`_schema.Table.indexes` 

2336 """ 

2337 

2338 unique: Optional[bool] 

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

2340 

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

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

2343 :attr:`_schema.Table.constraints`. 

2344 

2345 .. seealso:: 

2346 

2347 :attr:`_schema.Table.indexes` 

2348 

2349 :attr:`_schema.Table.constraints`. 

2350 

2351 """ 

2352 

2353 computed: Optional[Computed] 

2354 

2355 identity: Optional[Identity] 

2356 

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

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

2359 

2360 self.type = type_ 

2361 if isinstance(self.type, SchemaEventTarget): 

2362 self.type._set_parent_with_dispatch(self) 

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

2364 if isinstance(impl, SchemaEventTarget): 

2365 impl._set_parent_with_dispatch(self) 

2366 

2367 @HasMemoized.memoized_attribute 

2368 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

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

2370 

2371 return _DefaultDescriptionTuple._from_column_default(self.default) 

2372 

2373 @HasMemoized.memoized_attribute 

2374 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

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

2376 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

2377 

2378 @util.memoized_property 

2379 def _gen_static_annotations_cache_key(self) -> bool: 

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

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

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

2383 

2384 Added for #8790 

2385 

2386 """ 

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

2388 

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

2390 self._validate_dialect_kwargs(kwargs) 

2391 

2392 def __str__(self) -> str: 

2393 if self.name is None: 

2394 return "(no name)" 

2395 elif self.table is not None: 

2396 if self.table.named_with_column: 

2397 return self.table.description + "." + self.description 

2398 else: 

2399 return self.description 

2400 else: 

2401 return self.description 

2402 

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

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

2405 key.""" 

2406 

2407 for fk in self.foreign_keys: 

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

2409 return True 

2410 else: 

2411 return False 

2412 

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

2414 fk._set_parent_with_dispatch(self) 

2415 

2416 def __repr__(self) -> str: 

2417 kwarg = [] 

2418 if self.key != self.name: 

2419 kwarg.append("key") 

2420 if self.primary_key: 

2421 kwarg.append("primary_key") 

2422 if not self.nullable: 

2423 kwarg.append("nullable") 

2424 if self.onupdate: 

2425 kwarg.append("onupdate") 

2426 if self.default: 

2427 kwarg.append("default") 

2428 if self.server_default: 

2429 kwarg.append("server_default") 

2430 if self.comment: 

2431 kwarg.append("comment") 

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

2433 [repr(self.name)] 

2434 + [repr(self.type)] 

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

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

2437 + [ 

2438 ( 

2439 self.table is not None 

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

2441 or "table=None" 

2442 ) 

2443 ] 

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

2445 ) 

2446 

2447 def _set_parent( # type: ignore[override] 

2448 self, 

2449 parent: SchemaEventTarget, 

2450 *, 

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

2452 allow_replacements: bool, 

2453 index: Optional[int] = None, 

2454 **kw: Any, 

2455 ) -> None: 

2456 table = parent 

2457 assert isinstance(table, Table) 

2458 if not self.name: 

2459 raise exc.ArgumentError( 

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

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

2462 ) 

2463 

2464 self._reset_memoizations() 

2465 

2466 if self.key is None: 

2467 self.key = self.name 

2468 

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

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

2471 raise exc.ArgumentError( 

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

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

2474 ) 

2475 

2476 extra_remove = None 

2477 existing_col = None 

2478 conflicts_on = "" 

2479 

2480 if self.key in table._columns: 

2481 existing_col = table._columns[self.key] 

2482 if self.key == self.name: 

2483 conflicts_on = "name" 

2484 else: 

2485 conflicts_on = "key" 

2486 elif self.name in all_names: 

2487 existing_col = all_names[self.name] 

2488 extra_remove = {existing_col} 

2489 conflicts_on = "name" 

2490 

2491 if existing_col is not None: 

2492 if existing_col is not self: 

2493 if not allow_replacements: 

2494 raise exc.DuplicateColumnError( 

2495 f"A column with {conflicts_on} " 

2496 f"""'{ 

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

2498 }' """ 

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

2500 ) 

2501 for fk in existing_col.foreign_keys: 

2502 table.foreign_keys.remove(fk) 

2503 if fk.constraint in table.constraints: 

2504 # this might have been removed 

2505 # already, if it's a composite constraint 

2506 # and more than one col being replaced 

2507 table.constraints.remove(fk.constraint) 

2508 

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

2510 util.warn( 

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

2512 "being replaced with " 

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

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

2515 "reflection operation, specify autoload_replace=False to " 

2516 "prevent this replacement." 

2517 ) 

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

2519 all_names[self.name] = self 

2520 self.table = table 

2521 

2522 if self._insert_sentinel: 

2523 if self.table._sentinel_column is not None: 

2524 raise exc.ArgumentError( 

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

2526 ) 

2527 self.table._sentinel_column = self 

2528 

2529 if self.primary_key: 

2530 table.primary_key._replace(self) 

2531 elif self.key in table.primary_key: 

2532 raise exc.ArgumentError( 

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

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

2535 ) 

2536 

2537 if self.index: 

2538 if isinstance(self.index, str): 

2539 raise exc.ArgumentError( 

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

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

2542 "explicit Index object external to the Table." 

2543 ) 

2544 table.append_constraint( 

2545 Index( 

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

2547 ) 

2548 ) 

2549 

2550 elif self.unique: 

2551 if isinstance(self.unique, str): 

2552 raise exc.ArgumentError( 

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

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

2555 "specific name, append an explicit UniqueConstraint to " 

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

2557 "Index object external to the Table." 

2558 ) 

2559 table.append_constraint( 

2560 UniqueConstraint(self.key, _column_flag=True) 

2561 ) 

2562 

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

2564 

2565 if self.identity and ( 

2566 isinstance(self.default, Sequence) 

2567 or isinstance(self.onupdate, Sequence) 

2568 ): 

2569 raise exc.ArgumentError( 

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

2571 ) 

2572 

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

2574 fk_keys = [ 

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

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

2577 ] 

2578 for fk_key, link_to_name in fk_keys: 

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

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

2581 if fk.link_to_name is link_to_name: 

2582 fn(fk) 

2583 

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

2585 if self.table is not None: 

2586 fn(self, self.table) 

2587 else: 

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

2589 

2590 @util.deprecated( 

2591 "1.4", 

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

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

2594 ) 

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

2596 return self._copy(**kw) 

2597 

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

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

2600 

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

2602 

2603 """ 

2604 

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

2606 args: List[SchemaItem] = [ 

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

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

2609 

2610 # ticket #5276 

2611 column_kwargs = {} 

2612 for dialect_name in self.dialect_options: 

2613 dialect_options = self.dialect_options[dialect_name]._non_defaults 

2614 for ( 

2615 dialect_option_key, 

2616 dialect_option_value, 

2617 ) in dialect_options.items(): 

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

2619 dialect_option_value 

2620 ) 

2621 

2622 server_default = self.server_default 

2623 server_onupdate = self.server_onupdate 

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

2625 # TODO: likely should be copied in all cases 

2626 # TODO: if a Sequence, we would need to transfer the Sequence 

2627 # .metadata as well 

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

2629 server_default = server_onupdate = None 

2630 

2631 type_ = self.type 

2632 if isinstance(type_, SchemaEventTarget): 

2633 type_ = type_.copy(**kw) 

2634 

2635 # TODO: DefaultGenerator is not copied here! it's just used again 

2636 # with _set_parent() pointing to the old column. see the new 

2637 # use of _copy() in the new _merge() method 

2638 

2639 c = self._constructor( 

2640 name=self.name, 

2641 type_=type_, 

2642 key=self.key, 

2643 primary_key=self.primary_key, 

2644 unique=self.unique, 

2645 system=self.system, 

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

2647 index=self.index, 

2648 autoincrement=self.autoincrement, 

2649 default=self.default, 

2650 server_default=server_default, 

2651 onupdate=self.onupdate, 

2652 server_onupdate=server_onupdate, 

2653 doc=self.doc, 

2654 comment=self.comment, 

2655 _omit_from_statements=self._omit_from_statements, 

2656 insert_sentinel=self._insert_sentinel, 

2657 *args, 

2658 **column_kwargs, 

2659 ) 

2660 

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

2662 # ORM flipping the .nullable flag directly 

2663 c.nullable = self.nullable 

2664 c._user_defined_nullable = self._user_defined_nullable 

2665 

2666 return self._schema_item_copy(c) 

2667 

2668 def _merge( 

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

2670 ) -> None: 

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

2672 

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

2674 of fixes. 

2675 

2676 

2677 """ 

2678 

2679 if self.primary_key: 

2680 other.primary_key = True 

2681 

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

2683 other.autoincrement = self.autoincrement 

2684 

2685 if self.system: 

2686 other.system = self.system 

2687 

2688 if self.info: 

2689 other.info.update(self.info) 

2690 

2691 type_ = self.type 

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

2693 if isinstance(type_, SchemaEventTarget): 

2694 type_ = type_.copy() 

2695 

2696 other.type = type_ 

2697 

2698 if isinstance(type_, SchemaEventTarget): 

2699 type_._set_parent_with_dispatch(other) 

2700 

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

2702 if isinstance(impl, SchemaEventTarget): 

2703 impl._set_parent_with_dispatch(other) 

2704 

2705 if ( 

2706 self._user_defined_nullable is not NULL_UNSPECIFIED 

2707 and other._user_defined_nullable is NULL_UNSPECIFIED 

2708 ): 

2709 other.nullable = self.nullable 

2710 other._user_defined_nullable = self._user_defined_nullable 

2711 

2712 if ( 

2713 not omit_defaults 

2714 and self.default is not None 

2715 and other.default is None 

2716 ): 

2717 new_default = self.default._copy() 

2718 new_default._set_parent(other) 

2719 

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

2721 new_server_default = self.server_default 

2722 if isinstance(new_server_default, FetchedValue): 

2723 new_server_default = new_server_default._copy() 

2724 new_server_default._set_parent(other) 

2725 else: 

2726 other.server_default = new_server_default 

2727 

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

2729 new_server_onupdate = self.server_onupdate 

2730 new_server_onupdate = new_server_onupdate._copy() 

2731 new_server_onupdate._set_parent(other) 

2732 

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

2734 new_onupdate = self.onupdate._copy() 

2735 new_onupdate._set_parent(other) 

2736 

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

2738 other.index = self.index 

2739 

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

2741 other.unique = self.unique 

2742 

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

2744 other.doc = self.doc 

2745 

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

2747 other.comment = self.comment 

2748 

2749 for const in self.constraints: 

2750 if not const._type_bound: 

2751 new_const = const._copy() 

2752 new_const._set_parent(other) 

2753 

2754 for fk in self.foreign_keys: 

2755 if not fk.constraint: 

2756 new_fk = fk._copy() 

2757 new_fk._set_parent(other) 

2758 

2759 def _make_proxy( 

2760 self, 

2761 selectable: FromClause, 

2762 primary_key: ColumnSet, 

2763 foreign_keys: Set[KeyedColumnElement[Any]], 

2764 name: Optional[str] = None, 

2765 key: Optional[str] = None, 

2766 name_is_truncatable: bool = False, 

2767 compound_select_cols: Optional[ 

2768 _typing_Sequence[ColumnElement[Any]] 

2769 ] = None, 

2770 **kw: Any, 

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

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

2773 

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

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

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

2777 information is not transferred. 

2778 

2779 """ 

2780 

2781 fk = [ 

2782 ForeignKey( 

2783 col if col is not None else f._colspec, 

2784 _unresolvable=col is None, 

2785 _constraint=f.constraint, 

2786 ) 

2787 for f, col in [ 

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

2789 for fk in self.foreign_keys 

2790 ] 

2791 ] 

2792 

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

2794 raise exc.InvalidRequestError( 

2795 "Cannot initialize a sub-selectable" 

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

2797 "been assigned." 

2798 ) 

2799 try: 

2800 c = self._constructor( 

2801 ( 

2802 coercions.expect( 

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

2804 ) 

2805 if name_is_truncatable 

2806 else (name or self.name) 

2807 ), 

2808 self.type, 

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

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

2811 primary_key=self.primary_key, 

2812 nullable=self.nullable, 

2813 _proxies=( 

2814 list(compound_select_cols) 

2815 if compound_select_cols 

2816 else [self] 

2817 ), 

2818 *fk, 

2819 ) 

2820 except TypeError as err: 

2821 raise TypeError( 

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

2823 "Ensure the class includes a _constructor() " 

2824 "attribute or method which accepts the " 

2825 "standard Column constructor arguments, or " 

2826 "references the Column class itself." % self.__class__ 

2827 ) from err 

2828 

2829 c.table = selectable 

2830 c._propagate_attrs = selectable._propagate_attrs 

2831 if selectable._is_clone_of is not None: 

2832 c._is_clone_of = selectable._is_clone_of.columns.get(c.key) 

2833 

2834 if self.primary_key: 

2835 primary_key.add(c) 

2836 

2837 if fk: 

2838 foreign_keys.update(fk) # type: ignore 

2839 

2840 return c.key, c 

2841 

2842 

2843def insert_sentinel( 

2844 name: Optional[str] = None, 

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

2846 *, 

2847 default: Optional[Any] = None, 

2848 omit_from_statements: bool = True, 

2849) -> Column[Any]: 

2850 """Provides a surrogate :class:`_schema.Column` that will act as a 

2851 dedicated insert :term:`sentinel` column, allowing efficient bulk 

2852 inserts with deterministic RETURNING sorting for tables that 

2853 don't otherwise have qualifying primary key configurations. 

2854 

2855 Adding this column to a :class:`.Table` object requires that a 

2856 corresponding database table actually has this column present, so if adding 

2857 it to an existing model, existing database tables would need to be migrated 

2858 (e.g. using ALTER TABLE or similar) to include this column. 

2859 

2860 For background on how this object is used, see the section 

2861 :ref:`engine_insertmanyvalues_sentinel_columns` as part of the 

2862 section :ref:`engine_insertmanyvalues`. 

2863 

2864 The :class:`_schema.Column` returned will be a nullable integer column by 

2865 default and make use of a sentinel-specific default generator used only in 

2866 "insertmanyvalues" operations. 

2867 

2868 .. seealso:: 

2869 

2870 :func:`_orm.orm_insert_sentinel` 

2871 

2872 :paramref:`_schema.Column.insert_sentinel` 

2873 

2874 :ref:`engine_insertmanyvalues` 

2875 

2876 :ref:`engine_insertmanyvalues_sentinel_columns` 

2877 

2878 

2879 .. versionadded:: 2.0.10 

2880 

2881 """ 

2882 return Column( 

2883 name=name, 

2884 type_=type_api.INTEGERTYPE if type_ is None else type_, 

2885 default=( 

2886 default if default is not None else _InsertSentinelColumnDefault() 

2887 ), 

2888 _omit_from_statements=omit_from_statements, 

2889 insert_sentinel=True, 

2890 ) 

2891 

2892 

2893class ForeignKey(DialectKWArgs, SchemaItem): 

2894 """Defines a dependency between two columns. 

2895 

2896 ``ForeignKey`` is specified as an argument to a :class:`_schema.Column` 

2897 object, 

2898 e.g.:: 

2899 

2900 t = Table( 

2901 "remote_table", 

2902 metadata, 

2903 Column("remote_id", ForeignKey("main_table.id")), 

2904 ) 

2905 

2906 Note that ``ForeignKey`` is only a marker object that defines 

2907 a dependency between two columns. The actual constraint 

2908 is in all cases represented by the :class:`_schema.ForeignKeyConstraint` 

2909 object. This object will be generated automatically when 

2910 a ``ForeignKey`` is associated with a :class:`_schema.Column` which 

2911 in turn is associated with a :class:`_schema.Table`. Conversely, 

2912 when :class:`_schema.ForeignKeyConstraint` is applied to a 

2913 :class:`_schema.Table`, 

2914 ``ForeignKey`` markers are automatically generated to be 

2915 present on each associated :class:`_schema.Column`, which are also 

2916 associated with the constraint object. 

2917 

2918 Note that you cannot define a "composite" foreign key constraint, 

2919 that is a constraint between a grouping of multiple parent/child 

2920 columns, using ``ForeignKey`` objects. To define this grouping, 

2921 the :class:`_schema.ForeignKeyConstraint` object must be used, and applied 

2922 to the :class:`_schema.Table`. The associated ``ForeignKey`` objects 

2923 are created automatically. 

2924 

2925 The ``ForeignKey`` objects associated with an individual 

2926 :class:`_schema.Column` 

2927 object are available in the `foreign_keys` collection 

2928 of that column. 

2929 

2930 Further examples of foreign key configuration are in 

2931 :ref:`metadata_foreignkeys`. 

2932 

2933 """ 

2934 

2935 __visit_name__ = "foreign_key" 

2936 

2937 parent: Column[Any] 

2938 

2939 _table_column: Optional[Column[Any]] 

2940 

2941 _colspec: Union[str, Column[Any]] 

2942 

2943 def __init__( 

2944 self, 

2945 column: _DDLColumnReferenceArgument, 

2946 _constraint: Optional[ForeignKeyConstraint] = None, 

2947 use_alter: bool = False, 

2948 name: _ConstraintNameArgument = None, 

2949 onupdate: Optional[str] = None, 

2950 ondelete: Optional[str] = None, 

2951 deferrable: Optional[bool] = None, 

2952 initially: Optional[str] = None, 

2953 link_to_name: bool = False, 

2954 match: Optional[str] = None, 

2955 info: Optional[_InfoType] = None, 

2956 comment: Optional[str] = None, 

2957 _unresolvable: bool = False, 

2958 **dialect_kw: Any, 

2959 ): 

2960 r""" 

2961 Construct a column-level FOREIGN KEY. 

2962 

2963 The :class:`_schema.ForeignKey` object when constructed generates a 

2964 :class:`_schema.ForeignKeyConstraint` 

2965 which is associated with the parent 

2966 :class:`_schema.Table` object's collection of constraints. 

2967 

2968 :param column: A single target column for the key relationship. A 

2969 :class:`_schema.Column` object or a column name as a string: 

2970 ``tablename.columnkey`` or ``schema.tablename.columnkey``. 

2971 ``columnkey`` is the ``key`` which has been assigned to the column 

2972 (defaults to the column name itself), unless ``link_to_name`` is 

2973 ``True`` in which case the rendered name of the column is used. 

2974 

2975 :param name: Optional string. An in-database name for the key if 

2976 `constraint` is not provided. 

2977 

2978 :param onupdate: Optional string. If set, emit ON UPDATE <value> when 

2979 issuing DDL for this constraint. Typical values include CASCADE, 

2980 DELETE and RESTRICT. 

2981 

2982 .. seealso:: 

2983 

2984 :ref:`on_update_on_delete` 

2985 

2986 :param ondelete: Optional string. If set, emit ON DELETE <value> when 

2987 issuing DDL for this constraint. Typical values include CASCADE, 

2988 SET NULL and RESTRICT. Some dialects may allow for additional 

2989 syntaxes. 

2990 

2991 .. seealso:: 

2992 

2993 :ref:`on_update_on_delete` 

2994 

2995 :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT 

2996 DEFERRABLE when issuing DDL for this constraint. 

2997 

2998 :param initially: Optional string. If set, emit INITIALLY <value> when 

2999 issuing DDL for this constraint. 

3000 

3001 :param link_to_name: if True, the string name given in ``column`` is 

3002 the rendered name of the referenced column, not its locally 

3003 assigned ``key``. 

3004 

3005 :param use_alter: passed to the underlying 

3006 :class:`_schema.ForeignKeyConstraint` 

3007 to indicate the constraint should 

3008 be generated/dropped externally from the CREATE TABLE/ DROP TABLE 

3009 statement. See :paramref:`_schema.ForeignKeyConstraint.use_alter` 

3010 for further description. 

3011 

3012 .. seealso:: 

3013 

3014 :paramref:`_schema.ForeignKeyConstraint.use_alter` 

3015 

3016 :ref:`use_alter` 

3017 

3018 :param match: Optional string. If set, emit MATCH <value> when issuing 

3019 DDL for this constraint. Typical values include SIMPLE, PARTIAL 

3020 and FULL. 

3021 

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

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

3024 

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

3026 foreign key constraint creation. 

3027 

3028 .. versionadded:: 2.0 

3029 

3030 :param \**dialect_kw: Additional keyword arguments are dialect 

3031 specific, and passed in the form ``<dialectname>_<argname>``. The 

3032 arguments are ultimately handled by a corresponding 

3033 :class:`_schema.ForeignKeyConstraint`. 

3034 See the documentation regarding 

3035 an individual dialect at :ref:`dialect_toplevel` for detail on 

3036 documented arguments. 

3037 

3038 """ 

3039 

3040 self._unresolvable = _unresolvable 

3041 

3042 self._colspec, self._table_column = self._parse_colspec_argument( 

3043 column 

3044 ) 

3045 

3046 # the linked ForeignKeyConstraint. 

3047 # ForeignKey will create this when parent Column 

3048 # is attached to a Table, *or* ForeignKeyConstraint 

3049 # object passes itself in when creating ForeignKey 

3050 # markers. 

3051 self.constraint = _constraint 

3052 

3053 # .parent is not Optional under normal use 

3054 self.parent = None # type: ignore 

3055 

3056 self.use_alter = use_alter 

3057 self.name = name 

3058 self.onupdate = onupdate 

3059 self.ondelete = ondelete 

3060 self.deferrable = deferrable 

3061 self.initially = initially 

3062 self.link_to_name = link_to_name 

3063 self.match = match 

3064 self.comment = comment 

3065 if info: 

3066 self.info = info 

3067 self._unvalidated_dialect_kw = dialect_kw 

3068 

3069 def _resolve_colspec_argument( 

3070 self, 

3071 ) -> Tuple[ 

3072 Union[str, Column[Any]], 

3073 Optional[Column[Any]], 

3074 ]: 

3075 argument = self._colspec 

3076 

3077 return self._parse_colspec_argument(argument) 

3078 

3079 def _parse_colspec_argument( 

3080 self, 

3081 argument: _DDLColumnArgument, 

3082 ) -> Tuple[ 

3083 Union[str, Column[Any]], 

3084 Optional[Column[Any]], 

3085 ]: 

3086 _colspec = coercions.expect(roles.DDLReferredColumnRole, argument) 

3087 

3088 if isinstance(_colspec, str): 

3089 _table_column = None 

3090 else: 

3091 assert isinstance(_colspec, ColumnClause) 

3092 _table_column = _colspec 

3093 

3094 if not isinstance(_table_column.table, (type(None), TableClause)): 

3095 raise exc.ArgumentError( 

3096 "ForeignKey received Column not bound " 

3097 "to a Table, got: %r" % _table_column.table 

3098 ) 

3099 

3100 return _colspec, _table_column 

3101 

3102 def __repr__(self) -> str: 

3103 return "ForeignKey(%r)" % self._get_colspec() 

3104 

3105 @util.deprecated( 

3106 "1.4", 

3107 "The :meth:`_schema.ForeignKey.copy` method is deprecated " 

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

3109 ) 

3110 def copy(self, *, schema: Optional[str] = None, **kw: Any) -> ForeignKey: 

3111 return self._copy(schema=schema, **kw) 

3112 

3113 def _copy(self, *, schema: Optional[str] = None, **kw: Any) -> ForeignKey: 

3114 """Produce a copy of this :class:`_schema.ForeignKey` object. 

3115 

3116 The new :class:`_schema.ForeignKey` will not be bound 

3117 to any :class:`_schema.Column`. 

3118 

3119 This method is usually used by the internal 

3120 copy procedures of :class:`_schema.Column`, :class:`_schema.Table`, 

3121 and :class:`_schema.MetaData`. 

3122 

3123 :param schema: The returned :class:`_schema.ForeignKey` will 

3124 reference the original table and column name, qualified 

3125 by the given string schema name. 

3126 

3127 """ 

3128 fk = ForeignKey( 

3129 self._get_colspec(schema=schema), 

3130 use_alter=self.use_alter, 

3131 name=self.name, 

3132 onupdate=self.onupdate, 

3133 ondelete=self.ondelete, 

3134 deferrable=self.deferrable, 

3135 initially=self.initially, 

3136 link_to_name=self.link_to_name, 

3137 match=self.match, 

3138 comment=self.comment, 

3139 **self._unvalidated_dialect_kw, 

3140 ) 

3141 return self._schema_item_copy(fk) 

3142 

3143 def _get_colspec( 

3144 self, 

3145 schema: Optional[ 

3146 Union[ 

3147 str, 

3148 Literal[SchemaConst.RETAIN_SCHEMA, SchemaConst.BLANK_SCHEMA], 

3149 ] 

3150 ] = None, 

3151 table_name: Optional[str] = None, 

3152 _is_copy: bool = False, 

3153 ) -> str: 

3154 """Return a string based 'column specification' for this 

3155 :class:`_schema.ForeignKey`. 

3156 

3157 This is usually the equivalent of the string-based "tablename.colname" 

3158 argument first passed to the object's constructor. 

3159 

3160 """ 

3161 

3162 _colspec, effective_table_column = self._resolve_colspec_argument() 

3163 

3164 if schema not in (None, RETAIN_SCHEMA): 

3165 _schema, tname, colname = self._column_tokens 

3166 if table_name is not None: 

3167 tname = table_name 

3168 if schema is BLANK_SCHEMA: 

3169 return "%s.%s" % (tname, colname) 

3170 else: 

3171 return "%s.%s.%s" % (schema, tname, colname) 

3172 elif table_name: 

3173 schema, tname, colname = self._column_tokens 

3174 if schema: 

3175 return "%s.%s.%s" % (schema, table_name, colname) 

3176 else: 

3177 return "%s.%s" % (table_name, colname) 

3178 elif effective_table_column is not None: 

3179 if effective_table_column.table is None: 

3180 if _is_copy: 

3181 raise exc.InvalidRequestError( 

3182 f"Can't copy ForeignKey object which refers to " 

3183 f"non-table bound Column {effective_table_column!r}" 

3184 ) 

3185 else: 

3186 return effective_table_column.key 

3187 return "%s.%s" % ( 

3188 effective_table_column.table.fullname, 

3189 effective_table_column.key, 

3190 ) 

3191 else: 

3192 assert isinstance(_colspec, str) 

3193 return _colspec 

3194 

3195 @property 

3196 def _referred_schema(self) -> Optional[str]: 

3197 return self._column_tokens[0] 

3198 

3199 def _table_key_within_construction(self) -> Any: 

3200 """get the table key but only safely""" 

3201 

3202 if self._table_column is not None: 

3203 if self._table_column.table is None: 

3204 return None 

3205 else: 

3206 return self._table_column.table.key 

3207 else: 

3208 schema, tname, colname = self._column_tokens 

3209 return _get_table_key(tname, schema) 

3210 

3211 target_fullname = property(_get_colspec) 

3212 

3213 def references(self, table: Table) -> bool: 

3214 """Return True if the given :class:`_schema.Table` 

3215 is referenced by this 

3216 :class:`_schema.ForeignKey`.""" 

3217 

3218 return table.corresponding_column(self.column) is not None 

3219 

3220 def get_referent(self, table: FromClause) -> Optional[Column[Any]]: 

3221 """Return the :class:`_schema.Column` in the given 

3222 :class:`_schema.Table` (or any :class:`.FromClause`) 

3223 referenced by this :class:`_schema.ForeignKey`. 

3224 

3225 Returns None if this :class:`_schema.ForeignKey` 

3226 does not reference the given 

3227 :class:`_schema.Table`. 

3228 

3229 """ 

3230 # our column is a Column, and any subquery etc. proxying us 

3231 # would be doing so via another Column, so that's what would 

3232 # be returned here 

3233 return table.columns.corresponding_column(self.column) # type: ignore 

3234 

3235 @util.memoized_property 

3236 def _column_tokens(self) -> Tuple[Optional[str], str, Optional[str]]: 

3237 """parse a string-based _colspec into its component parts.""" 

3238 

3239 m = self._get_colspec().split(".") 

3240 if len(m) == 1: 

3241 tname = m.pop() 

3242 colname = None 

3243 else: 

3244 colname = m.pop() 

3245 tname = m.pop() 

3246 

3247 # A FK between column 'bar' and table 'foo' can be 

3248 # specified as 'foo', 'foo.bar', 'dbo.foo.bar', 

3249 # 'otherdb.dbo.foo.bar'. Once we have the column name and 

3250 # the table name, treat everything else as the schema 

3251 # name. Some databases (e.g. Sybase) support 

3252 # inter-database foreign keys. See tickets#1341 and -- 

3253 # indirectly related -- Ticket #594. This assumes that '.' 

3254 # will never appear *within* any component of the FK. 

3255 

3256 if len(m) > 0: 

3257 schema = ".".join(m) 

3258 else: 

3259 schema = None 

3260 return schema, tname, colname 

3261 

3262 def _resolve_col_tokens(self) -> Tuple[Table, str, Optional[str]]: 

3263 if self.parent is None: 

3264 raise exc.InvalidRequestError( 

3265 "this ForeignKey object does not yet have a " 

3266 "parent Column associated with it." 

3267 ) 

3268 

3269 elif self.parent.table is None: 

3270 raise exc.InvalidRequestError( 

3271 "this ForeignKey's parent column is not yet associated " 

3272 "with a Table." 

3273 ) 

3274 

3275 parenttable = self.parent.table 

3276 

3277 if self._unresolvable: 

3278 schema, tname, colname = self._column_tokens 

3279 tablekey = _get_table_key(tname, schema) 

3280 return parenttable, tablekey, colname 

3281 

3282 # assertion 

3283 # basically Column._make_proxy() sends the actual 

3284 # target Column to the ForeignKey object, so the 

3285 # string resolution here is never called. 

3286 for c in self.parent.base_columns: 

3287 if isinstance(c, Column): 

3288 assert c.table is parenttable 

3289 break 

3290 else: 

3291 assert False 

3292 ###################### 

3293 

3294 schema, tname, colname = self._column_tokens 

3295 

3296 if schema is None and parenttable.metadata.schema is not None: 

3297 schema = parenttable.metadata.schema 

3298 

3299 tablekey = _get_table_key(tname, schema) 

3300 return parenttable, tablekey, colname 

3301 

3302 def _link_to_col_by_colstring( 

3303 self, parenttable: Table, table: Table, colname: Optional[str] 

3304 ) -> Column[Any]: 

3305 _column = None 

3306 if colname is None: 

3307 # colname is None in the case that ForeignKey argument 

3308 # was specified as table name only, in which case we 

3309 # match the column name to the same column on the 

3310 # parent. 

3311 # this use case wasn't working in later 1.x series 

3312 # as it had no test coverage; fixed in 2.0 

3313 parent = self.parent 

3314 assert parent is not None 

3315 key = parent.key 

3316 _column = table.c.get(key, None) 

3317 elif self.link_to_name: 

3318 key = colname 

3319 for c in table.c: 

3320 if c.name == colname: 

3321 _column = c 

3322 else: 

3323 key = colname 

3324 _column = table.c.get(colname, None) 

3325 

3326 if _column is None: 

3327 raise exc.NoReferencedColumnError( 

3328 "Could not initialize target column " 

3329 f"for ForeignKey '{self._get_colspec()}' " 

3330 f"on table '{parenttable.name}': " 

3331 f"table '{table.name}' has no column named '{key}'", 

3332 table.name, 

3333 key, 

3334 ) 

3335 

3336 return _column 

3337 

3338 def _set_target_column(self, column: Column[Any]) -> None: 

3339 assert self.parent is not None 

3340 

3341 # propagate TypeEngine to parent if it didn't have one 

3342 if self.parent.type._isnull: 

3343 self.parent.type = column.type 

3344 

3345 # super-edgy case, if other FKs point to our column, 

3346 # they'd get the type propagated out also. 

3347 

3348 def set_type(fk: ForeignKey) -> None: 

3349 if fk.parent.type._isnull: 

3350 fk.parent.type = column.type 

3351 

3352 self.parent._setup_on_memoized_fks(set_type) 

3353 

3354 self.column = column # type: ignore 

3355 

3356 @util.ro_memoized_property 

3357 def column(self) -> Column[Any]: 

3358 """Return the target :class:`_schema.Column` referenced by this 

3359 :class:`_schema.ForeignKey`. 

3360 

3361 If no target column has been established, an exception 

3362 is raised. 

3363 

3364 """ 

3365 return self._resolve_column() 

3366 

3367 @overload 

3368 def _resolve_column( 

3369 self, *, raiseerr: Literal[True] = ... 

3370 ) -> Column[Any]: ... 

3371 

3372 @overload 

3373 def _resolve_column( 

3374 self, *, raiseerr: bool = ... 

3375 ) -> Optional[Column[Any]]: ... 

3376 

3377 def _resolve_column( 

3378 self, *, raiseerr: bool = True 

3379 ) -> Optional[Column[Any]]: 

3380 _column: Column[Any] 

3381 

3382 _colspec, effective_table_column = self._resolve_colspec_argument() 

3383 

3384 if isinstance(_colspec, str): 

3385 parenttable, tablekey, colname = self._resolve_col_tokens() 

3386 

3387 if self._unresolvable or tablekey not in parenttable.metadata: 

3388 if not raiseerr: 

3389 return None 

3390 raise exc.NoReferencedTableError( 

3391 f"Foreign key associated with column " 

3392 f"'{self.parent}' could not find " 

3393 f"table '{tablekey}' with which to generate a " 

3394 f"foreign key to target column '{colname}'", 

3395 tablekey, 

3396 ) 

3397 elif parenttable.key not in parenttable.metadata: 

3398 if not raiseerr: 

3399 return None 

3400 raise exc.InvalidRequestError( 

3401 f"Table {parenttable} is no longer associated with its " 

3402 "parent MetaData" 

3403 ) 

3404 else: 

3405 table = parenttable.metadata.tables[tablekey] 

3406 return self._link_to_col_by_colstring( 

3407 parenttable, table, colname 

3408 ) 

3409 

3410 elif hasattr(_colspec, "__clause_element__"): 

3411 _column = _colspec.__clause_element__() 

3412 return _column 

3413 else: 

3414 assert isinstance(_colspec, Column) 

3415 _column = _colspec 

3416 return _column 

3417 

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

3419 assert isinstance(parent, Column) 

3420 

3421 if self.parent is not None and self.parent is not parent: 

3422 raise exc.InvalidRequestError( 

3423 "This ForeignKey already has a parent !" 

3424 ) 

3425 self.parent = parent 

3426 self.parent.foreign_keys.add(self) 

3427 self.parent._on_table_attach(self._set_table) 

3428 

3429 def _set_remote_table(self, table: Table) -> None: 

3430 parenttable, _, colname = self._resolve_col_tokens() 

3431 _column = self._link_to_col_by_colstring(parenttable, table, colname) 

3432 self._set_target_column(_column) 

3433 assert self.constraint is not None 

3434 self.constraint._validate_dest_table(table) 

3435 

3436 def _remove_from_metadata(self, metadata: MetaData) -> None: 

3437 parenttable, table_key, colname = self._resolve_col_tokens() 

3438 fk_key = (table_key, colname) 

3439 

3440 if self in metadata._fk_memos[fk_key]: 

3441 # TODO: no test coverage for self not in memos 

3442 metadata._fk_memos[fk_key].remove(self) 

3443 

3444 def _set_table(self, column: Column[Any], table: Table) -> None: 

3445 # standalone ForeignKey - create ForeignKeyConstraint 

3446 # on the hosting Table when attached to the Table. 

3447 assert isinstance(table, Table) 

3448 if self.constraint is None: 

3449 self.constraint = ForeignKeyConstraint( 

3450 [], 

3451 [], 

3452 use_alter=self.use_alter, 

3453 name=self.name, 

3454 onupdate=self.onupdate, 

3455 ondelete=self.ondelete, 

3456 deferrable=self.deferrable, 

3457 initially=self.initially, 

3458 match=self.match, 

3459 comment=self.comment, 

3460 **self._unvalidated_dialect_kw, 

3461 ) 

3462 self.constraint._append_element(column, self) 

3463 self.constraint._set_parent_with_dispatch(table) 

3464 table.foreign_keys.add(self) 

3465 # set up remote ".column" attribute, or a note to pick it 

3466 # up when the other Table/Column shows up 

3467 

3468 _colspec, _ = self._resolve_colspec_argument() 

3469 if isinstance(_colspec, str): 

3470 parenttable, table_key, colname = self._resolve_col_tokens() 

3471 fk_key = (table_key, colname) 

3472 if table_key in parenttable.metadata.tables: 

3473 table = parenttable.metadata.tables[table_key] 

3474 try: 

3475 _column = self._link_to_col_by_colstring( 

3476 parenttable, table, colname 

3477 ) 

3478 except exc.NoReferencedColumnError: 

3479 # this is OK, we'll try later 

3480 pass 

3481 else: 

3482 self._set_target_column(_column) 

3483 

3484 parenttable.metadata._fk_memos[fk_key].append(self) 

3485 elif hasattr(_colspec, "__clause_element__"): 

3486 _column = _colspec.__clause_element__() 

3487 self._set_target_column(_column) 

3488 else: 

3489 self._set_target_column(_colspec) 

3490 

3491 

3492if TYPE_CHECKING: 

3493 

3494 def default_is_sequence( 

3495 obj: Optional[DefaultGenerator], 

3496 ) -> TypeGuard[Sequence]: ... 

3497 

3498 def default_is_clause_element( 

3499 obj: Optional[DefaultGenerator], 

3500 ) -> TypeGuard[ColumnElementColumnDefault]: ... 

3501 

3502 def default_is_scalar( 

3503 obj: Optional[DefaultGenerator], 

3504 ) -> TypeGuard[ScalarElementColumnDefault]: ... 

3505 

3506else: 

3507 default_is_sequence = operator.attrgetter("is_sequence") 

3508 

3509 default_is_clause_element = operator.attrgetter("is_clause_element") 

3510 

3511 default_is_scalar = operator.attrgetter("is_scalar") 

3512 

3513 

3514class DefaultGenerator(Executable, SchemaItem): 

3515 """Base class for column *default* values. 

3516 

3517 This object is only present on column.default or column.onupdate. 

3518 It's not valid as a server default. 

3519 

3520 """ 

3521 

3522 __visit_name__ = "default_generator" 

3523 

3524 _is_default_generator = True 

3525 is_sequence = False 

3526 is_identity = False 

3527 is_server_default = False 

3528 is_clause_element = False 

3529 is_callable = False 

3530 is_scalar = False 

3531 has_arg = False 

3532 is_sentinel = False 

3533 _is_monotonic_fn = False 

3534 column: Optional[Column[Any]] 

3535 

3536 def __init__(self, for_update: bool = False) -> None: 

3537 self.for_update = for_update 

3538 

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

3540 if TYPE_CHECKING: 

3541 assert isinstance(parent, Column) 

3542 self.column = parent 

3543 if self.for_update: 

3544 self.column.onupdate = self 

3545 else: 

3546 self.column.default = self 

3547 

3548 def _copy(self) -> DefaultGenerator: 

3549 raise NotImplementedError() 

3550 

3551 def _execute_on_connection( 

3552 self, 

3553 connection: Connection, 

3554 distilled_params: _CoreMultiExecuteParams, 

3555 execution_options: CoreExecuteOptionsParameter, 

3556 ) -> Any: 

3557 util.warn_deprecated( 

3558 "Using the .execute() method to invoke a " 

3559 "DefaultGenerator object is deprecated; please use " 

3560 "the .scalar() method.", 

3561 "2.0", 

3562 ) 

3563 return self._execute_on_scalar( 

3564 connection, distilled_params, execution_options 

3565 ) 

3566 

3567 def _execute_on_scalar( 

3568 self, 

3569 connection: Connection, 

3570 distilled_params: _CoreMultiExecuteParams, 

3571 execution_options: CoreExecuteOptionsParameter, 

3572 ) -> Any: 

3573 return connection._execute_default( 

3574 self, distilled_params, execution_options 

3575 ) 

3576 

3577 

3578class ColumnDefault(DefaultGenerator, ABC): 

3579 """A plain default value on a column. 

3580 

3581 This could correspond to a constant, a callable function, 

3582 or a SQL clause. 

3583 

3584 :class:`.ColumnDefault` is generated automatically 

3585 whenever the ``default``, ``onupdate`` arguments of 

3586 :class:`_schema.Column` are used. A :class:`.ColumnDefault` 

3587 can be passed positionally as well. 

3588 

3589 For example, the following:: 

3590 

3591 Column("foo", Integer, default=50) 

3592 

3593 Is equivalent to:: 

3594 

3595 Column("foo", Integer, ColumnDefault(50)) 

3596 

3597 """ 

3598 

3599 arg: Any 

3600 

3601 _is_monotonic_fn = False 

3602 

3603 @overload 

3604 def __new__( 

3605 cls, arg: Callable[..., Any], for_update: bool = ... 

3606 ) -> CallableColumnDefault: ... 

3607 

3608 @overload 

3609 def __new__( 

3610 cls, arg: ColumnElement[Any], for_update: bool = ... 

3611 ) -> ColumnElementColumnDefault: ... 

3612 

3613 # if I return ScalarElementColumnDefault here, which is what's actually 

3614 # returned, mypy complains that 

3615 # overloads overlap w/ incompatible return types. 

3616 @overload 

3617 def __new__(cls, arg: object, for_update: bool = ...) -> ColumnDefault: ... 

3618 

3619 def __new__( 

3620 cls, arg: Any = None, for_update: bool = False 

3621 ) -> ColumnDefault: 

3622 """Construct a new :class:`.ColumnDefault`. 

3623 

3624 

3625 :param arg: argument representing the default value. 

3626 May be one of the following: 

3627 

3628 * a plain non-callable Python value, such as a 

3629 string, integer, boolean, or other simple type. 

3630 The default value will be used as is each time. 

3631 * a SQL expression, that is one which derives from 

3632 :class:`_expression.ColumnElement`. The SQL expression will 

3633 be rendered into the INSERT or UPDATE statement, 

3634 or in the case of a primary key column when 

3635 RETURNING is not used may be 

3636 pre-executed before an INSERT within a SELECT. 

3637 * A Python callable. The function will be invoked for each 

3638 new row subject to an INSERT or UPDATE. 

3639 The callable must accept exactly 

3640 zero or one positional arguments. The one-argument form 

3641 will receive an instance of the :class:`.ExecutionContext`, 

3642 which provides contextual information as to the current 

3643 :class:`_engine.Connection` in use as well as the current 

3644 statement and parameters. 

3645 

3646 """ 

3647 

3648 if isinstance(arg, FetchedValue): 

3649 raise exc.ArgumentError( 

3650 "ColumnDefault may not be a server-side default type." 

3651 ) 

3652 elif callable(arg): 

3653 cls = CallableColumnDefault 

3654 elif isinstance(arg, ClauseElement): 

3655 cls = ColumnElementColumnDefault 

3656 elif arg is not None: 

3657 cls = ScalarElementColumnDefault 

3658 

3659 return object.__new__(cls) 

3660 

3661 def __repr__(self) -> str: 

3662 return f"{self.__class__.__name__}({self.arg!r})" 

3663 

3664 

3665class ScalarElementColumnDefault(ColumnDefault): 

3666 """default generator for a fixed scalar Python value 

3667 

3668 .. versionadded:: 2.0 

3669 

3670 """ 

3671 

3672 is_scalar = True 

3673 has_arg = True 

3674 

3675 def __init__(self, arg: Any, for_update: bool = False) -> None: 

3676 self.for_update = for_update 

3677 self.arg = arg 

3678 

3679 def _copy(self) -> ScalarElementColumnDefault: 

3680 return ScalarElementColumnDefault( 

3681 arg=self.arg, for_update=self.for_update 

3682 ) 

3683 

3684 

3685class _InsertSentinelColumnDefault(ColumnDefault): 

3686 """Default generator that's specific to the use of a "sentinel" column 

3687 when using the insertmanyvalues feature. 

3688 

3689 This default is used as part of the :func:`_schema.insert_sentinel` 

3690 construct. 

3691 

3692 """ 

3693 

3694 is_sentinel = True 

3695 for_update = False 

3696 arg = None 

3697 

3698 def __new__(cls) -> _InsertSentinelColumnDefault: 

3699 return object.__new__(cls) 

3700 

3701 def __init__(self) -> None: 

3702 pass 

3703 

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

3705 col = cast("Column[Any]", parent) 

3706 if not col._insert_sentinel: 

3707 raise exc.ArgumentError( 

3708 "The _InsertSentinelColumnDefault may only be applied to a " 

3709 "Column marked as insert_sentinel=True" 

3710 ) 

3711 elif not col.nullable: 

3712 raise exc.ArgumentError( 

3713 "The _InsertSentinelColumnDefault may only be applied to a " 

3714 "Column that is nullable" 

3715 ) 

3716 

3717 super()._set_parent(parent, **kw) 

3718 

3719 def _copy(self) -> _InsertSentinelColumnDefault: 

3720 return _InsertSentinelColumnDefault() 

3721 

3722 

3723_SQLExprDefault = Union["ColumnElement[Any]", "TextClause"] 

3724 

3725 

3726class ColumnElementColumnDefault(ColumnDefault): 

3727 """default generator for a SQL expression 

3728 

3729 .. versionadded:: 2.0 

3730 

3731 """ 

3732 

3733 is_clause_element = True 

3734 has_arg = True 

3735 arg: _SQLExprDefault 

3736 

3737 def __init__( 

3738 self, 

3739 arg: _SQLExprDefault, 

3740 for_update: bool = False, 

3741 ) -> None: 

3742 self.for_update = for_update 

3743 self.arg = arg 

3744 

3745 def _copy(self) -> ColumnElementColumnDefault: 

3746 return ColumnElementColumnDefault( 

3747 arg=self.arg, for_update=self.for_update 

3748 ) 

3749 

3750 @util.memoized_property 

3751 @util.preload_module("sqlalchemy.sql.functions") 

3752 def _is_monotonic_fn(self) -> bool: 

3753 functions = util.preloaded.sql_functions 

3754 return ( 

3755 isinstance(self.arg, functions.FunctionElement) 

3756 and self.arg.monotonic 

3757 ) 

3758 

3759 @util.memoized_property 

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

3761 def _arg_is_typed(self) -> bool: 

3762 sqltypes = util.preloaded.sql_sqltypes 

3763 

3764 return not isinstance(self.arg.type, sqltypes.NullType) 

3765 

3766 

3767class _CallableColumnDefaultProtocol(Protocol): 

3768 def __call__(self, context: ExecutionContext) -> Any: ... 

3769 

3770 

3771class CallableColumnDefault(ColumnDefault): 

3772 """default generator for a callable Python function 

3773 

3774 .. versionadded:: 2.0 

3775 

3776 """ 

3777 

3778 is_callable = True 

3779 arg: _CallableColumnDefaultProtocol 

3780 has_arg = True 

3781 

3782 def __init__( 

3783 self, 

3784 arg: Union[_CallableColumnDefaultProtocol, Callable[[], Any]], 

3785 for_update: bool = False, 

3786 ) -> None: 

3787 self.for_update = for_update 

3788 self.arg = self._maybe_wrap_callable(arg) 

3789 

3790 def _copy(self) -> CallableColumnDefault: 

3791 return CallableColumnDefault(arg=self.arg, for_update=self.for_update) 

3792 

3793 def _maybe_wrap_callable( 

3794 self, fn: Union[_CallableColumnDefaultProtocol, Callable[[], Any]] 

3795 ) -> _CallableColumnDefaultProtocol: 

3796 """Wrap callables that don't accept a context. 

3797 

3798 This is to allow easy compatibility with default callables 

3799 that aren't specific to accepting of a context. 

3800 

3801 """ 

3802 

3803 try: 

3804 argspec = util.get_callable_argspec(fn, no_self=True) 

3805 except TypeError: 

3806 return util.wrap_callable(lambda ctx: fn(), fn) # type: ignore 

3807 

3808 defaulted = argspec[3] is not None and len(argspec[3]) or 0 

3809 positionals = len(argspec[0]) - defaulted 

3810 

3811 if positionals == 0: 

3812 return util.wrap_callable(lambda ctx: fn(), fn) # type: ignore 

3813 

3814 elif positionals == 1: 

3815 return fn # type: ignore 

3816 else: 

3817 raise exc.ArgumentError( 

3818 "ColumnDefault Python function takes zero or one " 

3819 "positional arguments" 

3820 ) 

3821 

3822 

3823class IdentityOptions(DialectKWArgs): 

3824 """Defines options for a named database sequence or an identity column. 

3825 

3826 .. seealso:: 

3827 

3828 :class:`.Sequence` 

3829 

3830 """ 

3831 

3832 def __init__( 

3833 self, 

3834 start: Optional[int] = None, 

3835 increment: Optional[int] = None, 

3836 minvalue: Optional[int] = None, 

3837 maxvalue: Optional[int] = None, 

3838 nominvalue: Optional[bool] = None, 

3839 nomaxvalue: Optional[bool] = None, 

3840 cycle: Optional[bool] = None, 

3841 cache: Optional[int] = None, 

3842 order: Optional[bool] = None, 

3843 **dialect_kw: Any, 

3844 ) -> None: 

3845 """Construct a :class:`.IdentityOptions` object. 

3846 

3847 See the :class:`.Sequence` documentation for a complete description 

3848 of the parameters. 

3849 

3850 :param start: the starting index of the sequence. 

3851 :param increment: the increment value of the sequence. 

3852 :param minvalue: the minimum value of the sequence. 

3853 :param maxvalue: the maximum value of the sequence. 

3854 :param nominvalue: no minimum value of the sequence. 

3855 :param nomaxvalue: no maximum value of the sequence. 

3856 :param cycle: allows the sequence to wrap around when the maxvalue 

3857 or minvalue has been reached. 

3858 :param cache: optional integer value; number of future values in the 

3859 sequence which are calculated in advance. 

3860 :param order: optional boolean value; if ``True``, renders the 

3861 ORDER keyword. 

3862 

3863 .. deprecated:: 2.1 Use ``oracle_order`` instead. 

3864 

3865 """ 

3866 self.start = start 

3867 self.increment = increment 

3868 self.minvalue = minvalue 

3869 self.maxvalue = maxvalue 

3870 self.nominvalue = nominvalue 

3871 self.nomaxvalue = nomaxvalue 

3872 self.cycle = cycle 

3873 self.cache = cache 

3874 if order is not None: 

3875 if "oracle_order" in dialect_kw: 

3876 raise exc.ArgumentError( 

3877 "Cannot specify both 'order' and 'oracle_order'. " 

3878 "Plese use only 'oracle_order'." 

3879 ) 

3880 dialect_kw["oracle_order"] = order 

3881 self._validate_dialect_kwargs(dialect_kw) 

3882 

3883 @property 

3884 def _increment_is_negative(self) -> bool: 

3885 return self.increment is not None and self.increment < 0 

3886 

3887 @property 

3888 def order(self) -> Optional[bool]: 

3889 """Alias of the ``dialect_kwargs`` ``'oracle_order'``. 

3890 

3891 .. deprecated:: 2.1 The 'order' attribute is deprecated. 

3892 """ 

3893 value: Optional[bool] = self.dialect_kwargs.get("oracle_order") 

3894 return value 

3895 

3896 def _as_dict(self) -> Dict[str, Any]: 

3897 return { 

3898 k: v 

3899 for k, v in { 

3900 "start": self.start, 

3901 "increment": self.increment, 

3902 "minvalue": self.minvalue, 

3903 "maxvalue": self.maxvalue, 

3904 "nominvalue": self.nominvalue, 

3905 "nomaxvalue": self.nomaxvalue, 

3906 "cycle": self.cycle, 

3907 "cache": self.cache, 

3908 }.items() 

3909 if v != None 

3910 } 

3911 

3912 

3913class Sequence(HasSchemaAttr, IdentityOptions, DefaultGenerator): 

3914 """Represents a named database sequence. 

3915 

3916 The :class:`.Sequence` object represents the name and configurational 

3917 parameters of a database sequence. It also represents 

3918 a construct that can be "executed" by a SQLAlchemy :class:`_engine.Engine` 

3919 or :class:`_engine.Connection`, 

3920 rendering the appropriate "next value" function 

3921 for the target database and returning a result. 

3922 

3923 The :class:`.Sequence` is typically associated with a primary key column:: 

3924 

3925 some_table = Table( 

3926 "some_table", 

3927 metadata, 

3928 Column( 

3929 "id", 

3930 Integer, 

3931 Sequence("some_table_seq", start=1), 

3932 primary_key=True, 

3933 ), 

3934 ) 

3935 

3936 When CREATE TABLE is emitted for the above :class:`_schema.Table`, if the 

3937 target platform supports sequences, a CREATE SEQUENCE statement will 

3938 be emitted as well. For platforms that don't support sequences, 

3939 the :class:`.Sequence` construct is ignored. 

3940 

3941 .. seealso:: 

3942 

3943 :ref:`defaults_sequences` 

3944 

3945 :class:`.CreateSequence` 

3946 

3947 :class:`.DropSequence` 

3948 

3949 """ 

3950 

3951 __visit_name__ = "sequence" 

3952 

3953 is_sequence = True 

3954 

3955 column: Optional[Column[Any]] 

3956 data_type: Optional[TypeEngine[int]] 

3957 

3958 metadata: Optional[MetaData] 

3959 

3960 @util.deprecated_params( 

3961 order=( 

3962 "2.1", 

3963 "This parameter is supported only by Oracle Database, " 

3964 "use ``oracle_order`` instead.", 

3965 ) 

3966 ) 

3967 def __init__( 

3968 self, 

3969 name: str, 

3970 start: Optional[int] = None, 

3971 increment: Optional[int] = None, 

3972 minvalue: Optional[int] = None, 

3973 maxvalue: Optional[int] = None, 

3974 nominvalue: Optional[bool] = None, 

3975 nomaxvalue: Optional[bool] = None, 

3976 cycle: Optional[bool] = None, 

3977 schema: Optional[Union[str, Literal[SchemaConst.BLANK_SCHEMA]]] = None, 

3978 cache: Optional[int] = None, 

3979 order: Optional[bool] = None, 

3980 data_type: Optional[_TypeEngineArgument[int]] = None, 

3981 optional: bool = False, 

3982 quote: Optional[bool] = None, 

3983 metadata: Optional[MetaData] = None, 

3984 quote_schema: Optional[bool] = None, 

3985 for_update: bool = False, 

3986 **dialect_kw: Any, 

3987 ) -> None: 

3988 """Construct a :class:`.Sequence` object. 

3989 

3990 :param name: the name of the sequence. 

3991 

3992 :param start: the starting index of the sequence. This value is 

3993 used when the CREATE SEQUENCE command is emitted to the database 

3994 as the value of the "START WITH" clause. If ``None``, the 

3995 clause is omitted, which on most platforms indicates a starting 

3996 value of 1. 

3997 

3998 .. versionchanged:: 2.0 The :paramref:`.Sequence.start` parameter 

3999 is required in order to have DDL emit "START WITH". This is a 

4000 reversal of a change made in version 1.4 which would implicitly 

4001 render "START WITH 1" if the :paramref:`.Sequence.start` were 

4002 not included. See :ref:`change_7211` for more detail. 

4003 

4004 :param increment: the increment value of the sequence. This 

4005 value is used when the CREATE SEQUENCE command is emitted to 

4006 the database as the value of the "INCREMENT BY" clause. If ``None``, 

4007 the clause is omitted, which on most platforms indicates an 

4008 increment of 1. 

4009 :param minvalue: the minimum value of the sequence. This 

4010 value is used when the CREATE SEQUENCE command is emitted to 

4011 the database as the value of the "MINVALUE" clause. If ``None``, 

4012 the clause is omitted, which on most platforms indicates a 

4013 minvalue of 1 and -2^63-1 for ascending and descending sequences, 

4014 respectively. 

4015 

4016 :param maxvalue: the maximum value of the sequence. This 

4017 value is used when the CREATE SEQUENCE command is emitted to 

4018 the database as the value of the "MAXVALUE" clause. If ``None``, 

4019 the clause is omitted, which on most platforms indicates a 

4020 maxvalue of 2^63-1 and -1 for ascending and descending sequences, 

4021 respectively. 

4022 

4023 :param nominvalue: no minimum value of the sequence. This 

4024 value is used when the CREATE SEQUENCE command is emitted to 

4025 the database as the value of the "NO MINVALUE" clause. If ``None``, 

4026 the clause is omitted, which on most platforms indicates a 

4027 minvalue of 1 and -2^63-1 for ascending and descending sequences, 

4028 respectively. 

4029 

4030 :param nomaxvalue: no maximum value of the sequence. This 

4031 value is used when the CREATE SEQUENCE command is emitted to 

4032 the database as the value of the "NO MAXVALUE" clause. If ``None``, 

4033 the clause is omitted, which on most platforms indicates a 

4034 maxvalue of 2^63-1 and -1 for ascending and descending sequences, 

4035 respectively. 

4036 

4037 :param cycle: allows the sequence to wrap around when the maxvalue 

4038 or minvalue has been reached by an ascending or descending sequence 

4039 respectively. This value is used when the CREATE SEQUENCE command 

4040 is emitted to the database as the "CYCLE" clause. If the limit is 

4041 reached, the next number generated will be the minvalue or maxvalue, 

4042 respectively. If cycle=False (the default) any calls to nextval 

4043 after the sequence has reached its maximum value will return an 

4044 error. 

4045 

4046 :param schema: optional schema name for the sequence, if located 

4047 in a schema other than the default. The rules for selecting the 

4048 schema name when a :class:`_schema.MetaData` 

4049 is also present are the same 

4050 as that of :paramref:`_schema.Table.schema`. 

4051 

4052 :param cache: optional integer value; number of future values in the 

4053 sequence which are calculated in advance. Renders the CACHE keyword 

4054 understood by Oracle Database and PostgreSQL. 

4055 

4056 :param order: optional boolean value; if ``True``, renders the 

4057 ORDER keyword, understood by Oracle Database, indicating the sequence 

4058 is definitively ordered. May be necessary to provide deterministic 

4059 ordering using Oracle RAC. 

4060 

4061 :param data_type: The type to be returned by the sequence, for 

4062 dialects that allow us to choose between INTEGER, BIGINT, etc. 

4063 (e.g., mssql). 

4064 

4065 .. versionadded:: 1.4.0 

4066 

4067 :param optional: boolean value, when ``True``, indicates that this 

4068 :class:`.Sequence` object only needs to be explicitly generated 

4069 on backends that don't provide another way to generate primary 

4070 key identifiers. Currently, it essentially means, "don't create 

4071 this sequence on the PostgreSQL backend, where the SERIAL keyword 

4072 creates a sequence for us automatically". 

4073 :param quote: boolean value, when ``True`` or ``False``, explicitly 

4074 forces quoting of the :paramref:`_schema.Sequence.name` on or off. 

4075 When left at its default of ``None``, normal quoting rules based 

4076 on casing and reserved words take place. 

4077 :param quote_schema: Set the quoting preferences for the ``schema`` 

4078 name. 

4079 

4080 :param metadata: optional :class:`_schema.MetaData` object which this 

4081 :class:`.Sequence` will be associated with. A :class:`.Sequence` 

4082 that is associated with a :class:`_schema.MetaData` 

4083 gains the following 

4084 capabilities: 

4085 

4086 * The :class:`.Sequence` will inherit the 

4087 :paramref:`_schema.MetaData.schema` 

4088 parameter specified to the target :class:`_schema.MetaData`, which 

4089 affects the production of CREATE / DROP DDL, if any. 

4090 

4091 * The :meth:`.Sequence.create` and :meth:`.Sequence.drop` methods 

4092 automatically use the engine bound to the :class:`_schema.MetaData` 

4093 object, if any. 

4094 

4095 * The :meth:`_schema.MetaData.create_all` and 

4096 :meth:`_schema.MetaData.drop_all` 

4097 methods will emit CREATE / DROP for this :class:`.Sequence`, 

4098 even if the :class:`.Sequence` is not associated with any 

4099 :class:`_schema.Table` / :class:`_schema.Column` 

4100 that's a member of this 

4101 :class:`_schema.MetaData`. 

4102 

4103 The above behaviors can only occur if the :class:`.Sequence` is 

4104 explicitly associated with the :class:`_schema.MetaData` 

4105 via this parameter. 

4106 

4107 .. seealso:: 

4108 

4109 :ref:`sequence_metadata` - full discussion of the 

4110 :paramref:`.Sequence.metadata` parameter. 

4111 

4112 :param for_update: Indicates this :class:`.Sequence`, when associated 

4113 with a :class:`_schema.Column`, 

4114 should be invoked for UPDATE statements 

4115 on that column's table, rather than for INSERT statements, when 

4116 no value is otherwise present for that column in the statement. 

4117 

4118 """ 

4119 DefaultGenerator.__init__(self, for_update=for_update) 

4120 IdentityOptions.__init__( 

4121 self, 

4122 start=start, 

4123 increment=increment, 

4124 minvalue=minvalue, 

4125 maxvalue=maxvalue, 

4126 nominvalue=nominvalue, 

4127 nomaxvalue=nomaxvalue, 

4128 cycle=cycle, 

4129 cache=cache, 

4130 order=order, 

4131 **dialect_kw, 

4132 ) 

4133 self.column = None 

4134 self.name = quoted_name(name, quote) 

4135 self.optional = optional 

4136 if schema is BLANK_SCHEMA: 

4137 self.schema = schema = None 

4138 elif metadata is not None and schema is None and metadata.schema: 

4139 self.schema = schema = metadata.schema 

4140 else: 

4141 self.schema = quoted_name.construct(schema, quote_schema) 

4142 self._key = _get_table_key(name, schema) 

4143 if data_type is not None: 

4144 self.data_type = to_instance(data_type) 

4145 else: 

4146 self.data_type = None 

4147 

4148 if metadata: 

4149 self._set_metadata(metadata) 

4150 else: 

4151 self.metadata = None 

4152 

4153 @util.preload_module("sqlalchemy.sql.functions") 

4154 def next_value(self) -> Function[int]: 

4155 """Return a :class:`.next_value` function element 

4156 which will render the appropriate increment function 

4157 for this :class:`.Sequence` within any SQL expression. 

4158 

4159 """ 

4160 return util.preloaded.sql_functions.func.next_value(self) 

4161 

4162 def _copy(self) -> Sequence: 

4163 return Sequence( 

4164 name=self.name, 

4165 schema=self.schema, 

4166 data_type=self.data_type, 

4167 optional=self.optional, 

4168 metadata=self.metadata, 

4169 for_update=self.for_update, 

4170 **self._as_dict(), 

4171 **self.dialect_kwargs, 

4172 ) 

4173 

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

4175 assert isinstance(parent, Column) 

4176 super()._set_parent(parent, **kw) 

4177 parent._on_table_attach(self._set_table) 

4178 

4179 def _set_table(self, column: Column[Any], table: Table) -> None: 

4180 self._set_metadata(table.metadata) 

4181 

4182 def _set_metadata(self, metadata: MetaData) -> None: 

4183 self.metadata = metadata 

4184 self.metadata._register_object(self) 

4185 metadata._sequences[self._key] = self 

4186 

4187 def create( 

4188 self, 

4189 bind: _CreateDropBind, 

4190 checkfirst: Union[bool, CheckFirst] = CheckFirst.SEQUENCES, 

4191 ) -> None: 

4192 """Creates this sequence in the database.""" 

4193 

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

4195 

4196 def drop( 

4197 self, 

4198 bind: _CreateDropBind, 

4199 checkfirst: Union[bool, CheckFirst] = CheckFirst.SEQUENCES, 

4200 ) -> None: 

4201 """Drops this sequence from the database.""" 

4202 

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

4204 

4205 def _not_a_column_expr(self) -> NoReturn: 

4206 raise exc.InvalidRequestError( 

4207 f"This {self.__class__.__name__} cannot be used directly " 

4208 "as a column expression. Use func.next_value(sequence) " 

4209 "to produce a 'next value' function that's usable " 

4210 "as a column element." 

4211 ) 

4212 

4213 

4214@inspection._self_inspects 

4215class FetchedValue(SchemaEventTarget): 

4216 """A marker for a transparent database-side default. 

4217 

4218 Use :class:`.FetchedValue` when the database is configured 

4219 to provide some automatic default for a column. 

4220 

4221 E.g.:: 

4222 

4223 Column("foo", Integer, FetchedValue()) 

4224 

4225 Would indicate that some trigger or default generator 

4226 will create a new value for the ``foo`` column during an 

4227 INSERT. 

4228 

4229 .. seealso:: 

4230 

4231 :ref:`triggered_columns` 

4232 

4233 """ 

4234 

4235 is_server_default = True 

4236 reflected = False 

4237 has_argument = False 

4238 is_clause_element = False 

4239 is_identity = False 

4240 _is_monotonic_fn = False 

4241 

4242 column: Optional[Column[Any]] 

4243 

4244 def __init__(self, for_update: bool = False) -> None: 

4245 self.for_update = for_update 

4246 

4247 def _as_for_update(self, for_update: bool) -> FetchedValue: 

4248 if for_update == self.for_update: 

4249 return self 

4250 else: 

4251 return self._clone(for_update) 

4252 

4253 def _copy(self) -> FetchedValue: 

4254 return FetchedValue(self.for_update) 

4255 

4256 def _clone(self, for_update: bool) -> Self: 

4257 n = self.__class__.__new__(self.__class__) 

4258 n.__dict__.update(self.__dict__) 

4259 n.__dict__.pop("column", None) 

4260 n.for_update = for_update 

4261 return n 

4262 

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

4264 column = parent 

4265 assert isinstance(column, Column) 

4266 self.column = column 

4267 if self.for_update: 

4268 self.column.server_onupdate = self 

4269 else: 

4270 self.column.server_default = self 

4271 

4272 def __repr__(self) -> str: 

4273 return util.generic_repr(self) 

4274 

4275 

4276class DefaultClause(FetchedValue): 

4277 """A DDL-specified DEFAULT column value. 

4278 

4279 :class:`.DefaultClause` is a :class:`.FetchedValue` 

4280 that also generates a "DEFAULT" clause when 

4281 "CREATE TABLE" is emitted. 

4282 

4283 :class:`.DefaultClause` is generated automatically 

4284 whenever the ``server_default``, ``server_onupdate`` arguments of 

4285 :class:`_schema.Column` are used. A :class:`.DefaultClause` 

4286 can be passed positionally as well. 

4287 

4288 For example, the following:: 

4289 

4290 Column("foo", Integer, server_default="50") 

4291 

4292 Is equivalent to:: 

4293 

4294 Column("foo", Integer, DefaultClause("50")) 

4295 

4296 """ 

4297 

4298 has_argument = True 

4299 

4300 def __init__( 

4301 self, 

4302 arg: Union[str, ClauseElement, TextClause], 

4303 for_update: bool = False, 

4304 _reflected: bool = False, 

4305 ) -> None: 

4306 util.assert_arg_type(arg, (str, ClauseElement, TextClause), "arg") 

4307 super().__init__(for_update) 

4308 self.arg = arg 

4309 self.reflected = _reflected 

4310 

4311 @util.memoized_property 

4312 @util.preload_module("sqlalchemy.sql.functions") 

4313 def _is_monotonic_fn(self) -> bool: 

4314 functions = util.preloaded.sql_functions 

4315 return ( 

4316 isinstance(self.arg, functions.FunctionElement) 

4317 and self.arg.monotonic 

4318 ) 

4319 

4320 def _copy(self) -> DefaultClause: 

4321 return DefaultClause( 

4322 arg=self.arg, for_update=self.for_update, _reflected=self.reflected 

4323 ) 

4324 

4325 def __repr__(self) -> str: 

4326 return "DefaultClause(%r, for_update=%r)" % (self.arg, self.for_update) 

4327 

4328 

4329class Constraint(DialectKWArgs, HasConditionalDDL, SchemaItem): 

4330 """A table-level SQL constraint. 

4331 

4332 :class:`_schema.Constraint` serves as the base class for the series of 

4333 constraint objects that can be associated with :class:`_schema.Table` 

4334 objects, including :class:`_schema.PrimaryKeyConstraint`, 

4335 :class:`_schema.ForeignKeyConstraint` 

4336 :class:`_schema.UniqueConstraint`, and 

4337 :class:`_schema.CheckConstraint`. 

4338 

4339 """ 

4340 

4341 __visit_name__ = "constraint" 

4342 

4343 _creation_order: int 

4344 _column_flag: bool 

4345 

4346 def __init__( 

4347 self, 

4348 name: _ConstraintNameArgument = None, 

4349 deferrable: Optional[bool] = None, 

4350 initially: Optional[str] = None, 

4351 info: Optional[_InfoType] = None, 

4352 comment: Optional[str] = None, 

4353 _create_rule: Optional[Any] = None, 

4354 _type_bound: bool = False, 

4355 **dialect_kw: Any, 

4356 ) -> None: 

4357 r"""Create a SQL constraint. 

4358 

4359 :param name: 

4360 Optional, the in-database name of this ``Constraint``. 

4361 

4362 :param deferrable: 

4363 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

4364 issuing DDL for this constraint. 

4365 

4366 :param initially: 

4367 Optional string. If set, emit INITIALLY <value> when issuing DDL 

4368 for this constraint. 

4369 

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

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

4372 

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

4374 foreign key constraint creation. 

4375 

4376 .. versionadded:: 2.0 

4377 

4378 :param \**dialect_kw: Additional keyword arguments are dialect 

4379 specific, and passed in the form ``<dialectname>_<argname>``. See 

4380 the documentation regarding an individual dialect at 

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

4382 

4383 :param _create_rule: 

4384 used internally by some datatypes that also create constraints. 

4385 

4386 :param _type_bound: 

4387 used internally to indicate that this constraint is associated with 

4388 a specific datatype. 

4389 

4390 """ 

4391 

4392 self.name = name 

4393 self.deferrable = deferrable 

4394 self.initially = initially 

4395 if info: 

4396 self.info = info 

4397 self._create_rule = _create_rule 

4398 self._type_bound = _type_bound 

4399 util.set_creation_order(self) 

4400 self._validate_dialect_kwargs(dialect_kw) 

4401 self.comment = comment 

4402 

4403 def _should_create_for_compiler( 

4404 self, compiler: DDLCompiler, **kw: Any 

4405 ) -> bool: 

4406 if self._create_rule is not None and not self._create_rule(compiler): 

4407 return False 

4408 elif self._ddl_if is not None: 

4409 return self._ddl_if._should_execute( 

4410 ddl.CreateConstraint(self), self, None, compiler=compiler, **kw 

4411 ) 

4412 else: 

4413 return True 

4414 

4415 @property 

4416 def table(self) -> Table: 

4417 try: 

4418 if isinstance(self.parent, Table): 

4419 return self.parent 

4420 except AttributeError: 

4421 pass 

4422 raise exc.InvalidRequestError( 

4423 "This constraint is not bound to a table. Did you " 

4424 "mean to call table.append_constraint(constraint) ?" 

4425 ) 

4426 

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

4428 assert isinstance(parent, (Table, Column)) 

4429 self.parent = parent 

4430 parent.constraints.add(self) 

4431 

4432 @util.deprecated( 

4433 "1.4", 

4434 "The :meth:`_schema.Constraint.copy` method is deprecated " 

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

4436 ) 

4437 def copy(self, **kw: Any) -> Self: 

4438 return self._copy(**kw) 

4439 

4440 def _copy(self, **kw: Any) -> Self: 

4441 raise NotImplementedError() 

4442 

4443 

4444class ColumnCollectionMixin: 

4445 """A :class:`_expression.ColumnCollection` of :class:`_schema.Column` 

4446 objects. 

4447 

4448 This collection represents the columns which are referred to by 

4449 this object. 

4450 

4451 """ 

4452 

4453 _columns: DedupeColumnCollection[Column[Any]] 

4454 

4455 _allow_multiple_tables = False 

4456 

4457 _pending_colargs: List[Optional[Union[str, Column[Any]]]] 

4458 

4459 if TYPE_CHECKING: 

4460 

4461 def _set_parent_with_dispatch( 

4462 self, parent: SchemaEventTarget, **kw: Any 

4463 ) -> None: ... 

4464 

4465 def __init__( 

4466 self, 

4467 *columns: _DDLColumnArgument, 

4468 _autoattach: bool = True, 

4469 _column_flag: bool = False, 

4470 _gather_expressions: Optional[ 

4471 List[Union[str, ColumnElement[Any]]] 

4472 ] = None, 

4473 ) -> None: 

4474 self._column_flag = _column_flag 

4475 self._columns = DedupeColumnCollection() 

4476 

4477 processed_expressions: Optional[ 

4478 List[Union[ColumnElement[Any], str]] 

4479 ] = _gather_expressions 

4480 

4481 if processed_expressions is not None: 

4482 

4483 # this is expected to be an empty list 

4484 assert not processed_expressions 

4485 

4486 self._pending_colargs = [] 

4487 for ( 

4488 expr, 

4489 _, 

4490 _, 

4491 add_element, 

4492 ) in coercions.expect_col_expression_collection( 

4493 roles.DDLConstraintColumnRole, columns 

4494 ): 

4495 self._pending_colargs.append(add_element) 

4496 processed_expressions.append(expr) 

4497 else: 

4498 self._pending_colargs = [ 

4499 coercions.expect(roles.DDLConstraintColumnRole, column) 

4500 for column in columns 

4501 ] 

4502 

4503 if _autoattach and self._pending_colargs: 

4504 self._check_attach() 

4505 

4506 def _check_attach(self, evt: bool = False) -> None: 

4507 col_objs = [c for c in self._pending_colargs if isinstance(c, Column)] 

4508 

4509 cols_w_table = [c for c in col_objs if isinstance(c.table, Table)] 

4510 

4511 cols_wo_table = set(col_objs).difference(cols_w_table) 

4512 if cols_wo_table: 

4513 # feature #3341 - place event listeners for Column objects 

4514 # such that when all those cols are attached, we autoattach. 

4515 assert not evt, "Should not reach here on event call" 

4516 

4517 # issue #3411 - don't do the per-column auto-attach if some of the 

4518 # columns are specified as strings. 

4519 has_string_cols = { 

4520 c for c in self._pending_colargs if c is not None 

4521 }.difference(col_objs) 

4522 if not has_string_cols: 

4523 

4524 def _col_attached(column: Column[Any], table: Table) -> None: 

4525 # this isinstance() corresponds with the 

4526 # isinstance() above; only want to count Table-bound 

4527 # columns 

4528 if isinstance(table, Table): 

4529 cols_wo_table.discard(column) 

4530 if not cols_wo_table: 

4531 self._check_attach(evt=True) 

4532 

4533 self._cols_wo_table = cols_wo_table 

4534 for col in cols_wo_table: 

4535 col._on_table_attach(_col_attached) 

4536 return 

4537 

4538 columns = cols_w_table 

4539 

4540 tables = {c.table for c in columns} 

4541 if len(tables) == 1: 

4542 self._set_parent_with_dispatch(tables.pop()) 

4543 elif len(tables) > 1 and not self._allow_multiple_tables: 

4544 table = columns[0].table 

4545 others = [c for c in columns[1:] if c.table is not table] 

4546 if others: 

4547 # black could not format this inline 

4548 other_str = ", ".join("'%s'" % c for c in others) 

4549 raise exc.ArgumentError( 

4550 f"Column(s) {other_str} " 

4551 f"are not part of table '{table.description}'." 

4552 ) 

4553 

4554 @util.ro_memoized_property 

4555 def columns(self) -> ReadOnlyColumnCollection[str, Column[Any]]: 

4556 return self._columns.as_readonly() 

4557 

4558 @util.ro_memoized_property 

4559 def c(self) -> ReadOnlyColumnCollection[str, Column[Any]]: 

4560 return self._columns.as_readonly() 

4561 

4562 def _col_expressions( 

4563 self, parent: Union[Table, Column[Any]] 

4564 ) -> List[Optional[Column[Any]]]: 

4565 if isinstance(parent, Column): 

4566 result: List[Optional[Column[Any]]] = [ 

4567 c for c in self._pending_colargs if isinstance(c, Column) 

4568 ] 

4569 assert len(result) == len(self._pending_colargs) 

4570 return result 

4571 else: 

4572 try: 

4573 return [ 

4574 parent.c[col] if isinstance(col, str) else col 

4575 for col in self._pending_colargs 

4576 ] 

4577 except KeyError as ke: 

4578 raise exc.ConstraintColumnNotFoundError( 

4579 f"Can't create {self.__class__.__name__} " 

4580 f"on table '{parent.description}': no column " 

4581 f"named '{ke.args[0]}' is present." 

4582 ) from ke 

4583 

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

4585 assert isinstance(parent, (Table, Column)) 

4586 

4587 for col in self._col_expressions(parent): 

4588 if col is not None: 

4589 self._columns.add(col) 

4590 

4591 

4592class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint): 

4593 """A constraint that proxies a ColumnCollection.""" 

4594 

4595 def __init__( 

4596 self, 

4597 *columns: _DDLColumnArgument, 

4598 name: _ConstraintNameArgument = None, 

4599 deferrable: Optional[bool] = None, 

4600 initially: Optional[str] = None, 

4601 info: Optional[_InfoType] = None, 

4602 _autoattach: bool = True, 

4603 _column_flag: bool = False, 

4604 _gather_expressions: Optional[List[_DDLColumnArgument]] = None, 

4605 **dialect_kw: Any, 

4606 ) -> None: 

4607 r""" 

4608 :param \*columns: 

4609 A sequence of column names or Column objects. 

4610 

4611 :param name: 

4612 Optional, the in-database name of this constraint. 

4613 

4614 :param deferrable: 

4615 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

4616 issuing DDL for this constraint. 

4617 

4618 :param initially: 

4619 Optional string. If set, emit INITIALLY <value> when issuing DDL 

4620 for this constraint. 

4621 

4622 :param \**dialect_kw: other keyword arguments including 

4623 dialect-specific arguments are propagated to the :class:`.Constraint` 

4624 superclass. 

4625 

4626 """ 

4627 Constraint.__init__( 

4628 self, 

4629 name=name, 

4630 deferrable=deferrable, 

4631 initially=initially, 

4632 info=info, 

4633 **dialect_kw, 

4634 ) 

4635 ColumnCollectionMixin.__init__( 

4636 self, *columns, _autoattach=_autoattach, _column_flag=_column_flag 

4637 ) 

4638 

4639 columns: ReadOnlyColumnCollection[str, Column[Any]] 

4640 """A :class:`_expression.ColumnCollection` representing the set of columns 

4641 for this constraint. 

4642 

4643 """ 

4644 

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

4646 assert isinstance(parent, (Column, Table)) 

4647 Constraint._set_parent(self, parent) 

4648 ColumnCollectionMixin._set_parent(self, parent) 

4649 

4650 def __contains__(self, x: Any) -> bool: 

4651 return x in self._columns 

4652 

4653 @util.deprecated( 

4654 "1.4", 

4655 "The :meth:`_schema.ColumnCollectionConstraint.copy` method " 

4656 "is deprecated and will be removed in a future release.", 

4657 ) 

4658 def copy( 

4659 self, 

4660 *, 

4661 target_table: Optional[Table] = None, 

4662 **kw: Any, 

4663 ) -> ColumnCollectionConstraint: 

4664 return self._copy(target_table=target_table, **kw) 

4665 

4666 def _copy( 

4667 self, 

4668 *, 

4669 target_table: Optional[Table] = None, 

4670 **kw: Any, 

4671 ) -> ColumnCollectionConstraint: 

4672 # ticket #5276 

4673 constraint_kwargs = {} 

4674 for dialect_name in self.dialect_options: 

4675 dialect_options = self.dialect_options[dialect_name]._non_defaults 

4676 for ( 

4677 dialect_option_key, 

4678 dialect_option_value, 

4679 ) in dialect_options.items(): 

4680 constraint_kwargs[dialect_name + "_" + dialect_option_key] = ( 

4681 dialect_option_value 

4682 ) 

4683 

4684 assert isinstance(self.parent, Table) 

4685 c = self.__class__( 

4686 name=self.name, 

4687 deferrable=self.deferrable, 

4688 initially=self.initially, 

4689 *[ 

4690 _copy_expression(expr, self.parent, target_table) 

4691 for expr in self._columns 

4692 ], 

4693 comment=self.comment, 

4694 **constraint_kwargs, 

4695 ) 

4696 return self._schema_item_copy(c) 

4697 

4698 def contains_column(self, col: Column[Any]) -> bool: 

4699 """Return True if this constraint contains the given column. 

4700 

4701 Note that this object also contains an attribute ``.columns`` 

4702 which is a :class:`_expression.ColumnCollection` of 

4703 :class:`_schema.Column` objects. 

4704 

4705 """ 

4706 

4707 return self._columns.contains_column(col) 

4708 

4709 def __iter__(self) -> Iterator[Column[Any]]: 

4710 return iter(self._columns) 

4711 

4712 def __len__(self) -> int: 

4713 return len(self._columns) 

4714 

4715 

4716class CheckConstraint(ColumnCollectionConstraint): 

4717 """A table- or column-level CHECK constraint. 

4718 

4719 Can be included in the definition of a Table or Column. 

4720 """ 

4721 

4722 _allow_multiple_tables = True 

4723 

4724 __visit_name__ = "table_or_column_check_constraint" 

4725 

4726 @_document_text_coercion( 

4727 "sqltext", 

4728 ":class:`.CheckConstraint`", 

4729 ":paramref:`.CheckConstraint.sqltext`", 

4730 ) 

4731 def __init__( 

4732 self, 

4733 sqltext: _TextCoercedExpressionArgument[Any], 

4734 name: _ConstraintNameArgument = None, 

4735 deferrable: Optional[bool] = None, 

4736 initially: Optional[str] = None, 

4737 table: Optional[Table] = None, 

4738 info: Optional[_InfoType] = None, 

4739 _create_rule: Optional[Any] = None, 

4740 _autoattach: bool = True, 

4741 _type_bound: bool = False, 

4742 **dialect_kw: Any, 

4743 ) -> None: 

4744 r"""Construct a CHECK constraint. 

4745 

4746 :param sqltext: 

4747 A string containing the constraint definition, which will be used 

4748 verbatim, or a SQL expression construct. If given as a string, 

4749 the object is converted to a :func:`_expression.text` object. 

4750 If the textual 

4751 string includes a colon character, escape this using a backslash:: 

4752 

4753 CheckConstraint(r"foo ~ E'a(?\:b|c)d") 

4754 

4755 :param name: 

4756 Optional, the in-database name of the constraint. 

4757 

4758 :param deferrable: 

4759 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

4760 issuing DDL for this constraint. 

4761 

4762 :param initially: 

4763 Optional string. If set, emit INITIALLY <value> when issuing DDL 

4764 for this constraint. 

4765 

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

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

4768 

4769 """ 

4770 

4771 self.sqltext = coercions.expect(roles.DDLExpressionRole, sqltext) 

4772 columns: List[Column[Any]] = [] 

4773 visitors.traverse(self.sqltext, {}, {"column": columns.append}) 

4774 

4775 super().__init__( 

4776 name=name, 

4777 deferrable=deferrable, 

4778 initially=initially, 

4779 _create_rule=_create_rule, 

4780 info=info, 

4781 _type_bound=_type_bound, 

4782 _autoattach=_autoattach, 

4783 *columns, 

4784 **dialect_kw, 

4785 ) 

4786 if table is not None: 

4787 self._set_parent_with_dispatch(table) 

4788 

4789 @property 

4790 def is_column_level(self) -> bool: 

4791 return not isinstance(self.parent, Table) 

4792 

4793 @util.deprecated( 

4794 "1.4", 

4795 "The :meth:`_schema.CheckConstraint.copy` method is deprecated " 

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

4797 ) 

4798 def copy( 

4799 self, *, target_table: Optional[Table] = None, **kw: Any 

4800 ) -> CheckConstraint: 

4801 return self._copy(target_table=target_table, **kw) 

4802 

4803 def _copy( 

4804 self, *, target_table: Optional[Table] = None, **kw: Any 

4805 ) -> CheckConstraint: 

4806 if target_table is not None: 

4807 # note that target_table is None for the copy process of 

4808 # a column-bound CheckConstraint, so this path is not reached 

4809 # in that case. 

4810 sqltext = _copy_expression(self.sqltext, self.table, target_table) 

4811 else: 

4812 sqltext = self.sqltext 

4813 c = CheckConstraint( 

4814 sqltext, 

4815 name=self.name, 

4816 initially=self.initially, 

4817 deferrable=self.deferrable, 

4818 _create_rule=self._create_rule, 

4819 table=target_table, 

4820 comment=self.comment, 

4821 _autoattach=False, 

4822 _type_bound=self._type_bound, 

4823 ) 

4824 return self._schema_item_copy(c) 

4825 

4826 

4827class ForeignKeyConstraint(ColumnCollectionConstraint): 

4828 """A table-level FOREIGN KEY constraint. 

4829 

4830 Defines a single column or composite FOREIGN KEY ... REFERENCES 

4831 constraint. For a no-frills, single column foreign key, adding a 

4832 :class:`_schema.ForeignKey` to the definition of a :class:`_schema.Column` 

4833 is a 

4834 shorthand equivalent for an unnamed, single column 

4835 :class:`_schema.ForeignKeyConstraint`. 

4836 

4837 Examples of foreign key configuration are in :ref:`metadata_foreignkeys`. 

4838 

4839 """ 

4840 

4841 __visit_name__ = "foreign_key_constraint" 

4842 

4843 def __init__( 

4844 self, 

4845 columns: _typing_Sequence[_DDLColumnArgument], 

4846 refcolumns: _typing_Sequence[_DDLColumnReferenceArgument], 

4847 name: _ConstraintNameArgument = None, 

4848 onupdate: Optional[str] = None, 

4849 ondelete: Optional[str] = None, 

4850 deferrable: Optional[bool] = None, 

4851 initially: Optional[str] = None, 

4852 use_alter: bool = False, 

4853 link_to_name: bool = False, 

4854 match: Optional[str] = None, 

4855 table: Optional[Table] = None, 

4856 info: Optional[_InfoType] = None, 

4857 comment: Optional[str] = None, 

4858 **dialect_kw: Any, 

4859 ) -> None: 

4860 r"""Construct a composite-capable FOREIGN KEY. 

4861 

4862 :param columns: A sequence of local column names. The named columns 

4863 must be defined and present in the parent Table. The names should 

4864 match the ``key`` given to each column (defaults to the name) unless 

4865 ``link_to_name`` is True. 

4866 

4867 :param refcolumns: A sequence of foreign column names or Column 

4868 objects. The columns must all be located within the same Table. 

4869 

4870 :param name: Optional, the in-database name of the key. 

4871 

4872 :param onupdate: Optional string. If set, emit ON UPDATE <value> when 

4873 issuing DDL for this constraint. Typical values include CASCADE, 

4874 DELETE and RESTRICT. 

4875 

4876 .. seealso:: 

4877 

4878 :ref:`on_update_on_delete` 

4879 

4880 :param ondelete: Optional string. If set, emit ON DELETE <value> when 

4881 issuing DDL for this constraint. Typical values include CASCADE, 

4882 SET NULL and RESTRICT. Some dialects may allow for additional 

4883 syntaxes. 

4884 

4885 .. seealso:: 

4886 

4887 :ref:`on_update_on_delete` 

4888 

4889 :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT 

4890 DEFERRABLE when issuing DDL for this constraint. 

4891 

4892 :param initially: Optional string. If set, emit INITIALLY <value> when 

4893 issuing DDL for this constraint. 

4894 

4895 :param link_to_name: if True, the string name given in ``column`` is 

4896 the rendered name of the referenced column, not its locally assigned 

4897 ``key``. 

4898 

4899 :param use_alter: If True, do not emit the DDL for this constraint as 

4900 part of the CREATE TABLE definition. Instead, generate it via an 

4901 ALTER TABLE statement issued after the full collection of tables 

4902 have been created, and drop it via an ALTER TABLE statement before 

4903 the full collection of tables are dropped. 

4904 

4905 The use of :paramref:`_schema.ForeignKeyConstraint.use_alter` is 

4906 particularly geared towards the case where two or more tables 

4907 are established within a mutually-dependent foreign key constraint 

4908 relationship; however, the :meth:`_schema.MetaData.create_all` and 

4909 :meth:`_schema.MetaData.drop_all` 

4910 methods will perform this resolution 

4911 automatically, so the flag is normally not needed. 

4912 

4913 .. seealso:: 

4914 

4915 :ref:`use_alter` 

4916 

4917 :param match: Optional string. If set, emit MATCH <value> when issuing 

4918 DDL for this constraint. Typical values include SIMPLE, PARTIAL 

4919 and FULL. 

4920 

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

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

4923 

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

4925 foreign key constraint creation. 

4926 

4927 .. versionadded:: 2.0 

4928 

4929 :param \**dialect_kw: Additional keyword arguments are dialect 

4930 specific, and passed in the form ``<dialectname>_<argname>``. See 

4931 the documentation regarding an individual dialect at 

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

4933 

4934 """ 

4935 

4936 Constraint.__init__( 

4937 self, 

4938 name=name, 

4939 deferrable=deferrable, 

4940 initially=initially, 

4941 info=info, 

4942 comment=comment, 

4943 **dialect_kw, 

4944 ) 

4945 self.onupdate = onupdate 

4946 self.ondelete = ondelete 

4947 self.link_to_name = link_to_name 

4948 self.use_alter = use_alter 

4949 self.match = match 

4950 

4951 if len(set(columns)) != len(refcolumns): 

4952 if len(set(columns)) != len(columns): 

4953 # e.g. FOREIGN KEY (a, a) REFERENCES r (b, c) 

4954 raise exc.ArgumentError( 

4955 "ForeignKeyConstraint with duplicate source column " 

4956 "references are not supported." 

4957 ) 

4958 else: 

4959 # e.g. FOREIGN KEY (a) REFERENCES r (b, c) 

4960 # paraphrasing 

4961 # https://www.postgresql.org/docs/current/static/ddl-constraints.html 

4962 raise exc.ArgumentError( 

4963 "ForeignKeyConstraint number " 

4964 "of constrained columns must match the number of " 

4965 "referenced columns." 

4966 ) 

4967 

4968 # standalone ForeignKeyConstraint - create 

4969 # associated ForeignKey objects which will be applied to hosted 

4970 # Column objects (in col.foreign_keys), either now or when attached 

4971 # to the Table for string-specified names 

4972 self.elements = [ 

4973 ForeignKey( 

4974 refcol, 

4975 _constraint=self, 

4976 name=self.name, 

4977 onupdate=self.onupdate, 

4978 ondelete=self.ondelete, 

4979 use_alter=self.use_alter, 

4980 link_to_name=self.link_to_name, 

4981 match=self.match, 

4982 deferrable=self.deferrable, 

4983 initially=self.initially, 

4984 **self.dialect_kwargs, 

4985 ) 

4986 for refcol in refcolumns 

4987 ] 

4988 

4989 ColumnCollectionMixin.__init__(self, *columns) 

4990 if table is not None: 

4991 if hasattr(self, "parent"): 

4992 assert table is self.parent 

4993 self._set_parent_with_dispatch(table) 

4994 

4995 def _append_element(self, column: Column[Any], fk: ForeignKey) -> None: 

4996 self._columns.add(column) 

4997 self.elements.append(fk) 

4998 

4999 columns: ReadOnlyColumnCollection[str, Column[Any]] 

5000 """A :class:`_expression.ColumnCollection` representing the set of columns 

5001 for this constraint. 

5002 

5003 """ 

5004 

5005 elements: List[ForeignKey] 

5006 """A sequence of :class:`_schema.ForeignKey` objects. 

5007 

5008 Each :class:`_schema.ForeignKey` 

5009 represents a single referring column/referred 

5010 column pair. 

5011 

5012 This collection is intended to be read-only. 

5013 

5014 """ 

5015 

5016 @property 

5017 def _elements(self) -> util.OrderedDict[str, ForeignKey]: 

5018 # legacy - provide a dictionary view of (column_key, fk) 

5019 return util.OrderedDict(zip(self.column_keys, self.elements)) 

5020 

5021 @property 

5022 def _referred_schema(self) -> Optional[str]: 

5023 for elem in self.elements: 

5024 return elem._referred_schema 

5025 else: 

5026 return None 

5027 

5028 @property 

5029 def referred_table(self) -> Table: 

5030 """The :class:`_schema.Table` object to which this 

5031 :class:`_schema.ForeignKeyConstraint` references. 

5032 

5033 This is a dynamically calculated attribute which may not be available 

5034 if the constraint and/or parent table is not yet associated with 

5035 a metadata collection that contains the referred table. 

5036 

5037 """ 

5038 return self.elements[0].column.table 

5039 

5040 def _validate_dest_table(self, table: Table) -> None: 

5041 table_keys = { 

5042 elem._table_key_within_construction() for elem in self.elements 

5043 } 

5044 if None not in table_keys and len(table_keys) > 1: 

5045 elem0, elem1 = sorted(table_keys)[0:2] 

5046 raise exc.ArgumentError( 

5047 f"ForeignKeyConstraint on " 

5048 f"{table.fullname}({self._col_description}) refers to " 

5049 f"multiple remote tables: {elem0} and {elem1}" 

5050 ) 

5051 

5052 @property 

5053 def column_keys(self) -> _typing_Sequence[str]: 

5054 """Return a list of string keys representing the local 

5055 columns in this :class:`_schema.ForeignKeyConstraint`. 

5056 

5057 This list is either the original string arguments sent 

5058 to the constructor of the :class:`_schema.ForeignKeyConstraint`, 

5059 or if the constraint has been initialized with :class:`_schema.Column` 

5060 objects, is the string ``.key`` of each element. 

5061 

5062 """ 

5063 if hasattr(self, "parent"): 

5064 return self._columns.keys() 

5065 else: 

5066 return [ 

5067 col.key if isinstance(col, ColumnElement) else str(col) 

5068 for col in self._pending_colargs 

5069 ] 

5070 

5071 @property 

5072 def _col_description(self) -> str: 

5073 return ", ".join(self.column_keys) 

5074 

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

5076 table = parent 

5077 assert isinstance(table, Table) 

5078 Constraint._set_parent(self, table) 

5079 

5080 ColumnCollectionConstraint._set_parent(self, table) 

5081 

5082 for col, fk in zip(self._columns, self.elements): 

5083 if not hasattr(fk, "parent") or fk.parent is not col: 

5084 fk._set_parent_with_dispatch(col) 

5085 

5086 self._validate_dest_table(table) 

5087 

5088 @util.deprecated( 

5089 "1.4", 

5090 "The :meth:`_schema.ForeignKeyConstraint.copy` method is deprecated " 

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

5092 ) 

5093 def copy( 

5094 self, 

5095 *, 

5096 schema: Optional[str] = None, 

5097 target_table: Optional[Table] = None, 

5098 **kw: Any, 

5099 ) -> ForeignKeyConstraint: 

5100 return self._copy(schema=schema, target_table=target_table, **kw) 

5101 

5102 def _copy( 

5103 self, 

5104 *, 

5105 schema: Optional[str] = None, 

5106 target_table: Optional[Table] = None, 

5107 **kw: Any, 

5108 ) -> ForeignKeyConstraint: 

5109 fkc = ForeignKeyConstraint( 

5110 [x.parent.key for x in self.elements], 

5111 [ 

5112 x._get_colspec( 

5113 schema=schema, 

5114 table_name=( 

5115 target_table.name 

5116 if target_table is not None 

5117 and x._table_key_within_construction() 

5118 == x.parent.table.key 

5119 else None 

5120 ), 

5121 _is_copy=True, 

5122 ) 

5123 for x in self.elements 

5124 ], 

5125 name=self.name, 

5126 onupdate=self.onupdate, 

5127 ondelete=self.ondelete, 

5128 use_alter=self.use_alter, 

5129 deferrable=self.deferrable, 

5130 initially=self.initially, 

5131 link_to_name=self.link_to_name, 

5132 match=self.match, 

5133 comment=self.comment, 

5134 ) 

5135 for self_fk, other_fk in zip(self.elements, fkc.elements): 

5136 self_fk._schema_item_copy(other_fk) 

5137 return self._schema_item_copy(fkc) 

5138 

5139 

5140class PrimaryKeyConstraint(ColumnCollectionConstraint): 

5141 """A table-level PRIMARY KEY constraint. 

5142 

5143 The :class:`.PrimaryKeyConstraint` object is present automatically 

5144 on any :class:`_schema.Table` object; it is assigned a set of 

5145 :class:`_schema.Column` objects corresponding to those marked with 

5146 the :paramref:`_schema.Column.primary_key` flag:: 

5147 

5148 >>> my_table = Table( 

5149 ... "mytable", 

5150 ... metadata, 

5151 ... Column("id", Integer, primary_key=True), 

5152 ... Column("version_id", Integer, primary_key=True), 

5153 ... Column("data", String(50)), 

5154 ... ) 

5155 >>> my_table.primary_key 

5156 PrimaryKeyConstraint( 

5157 Column('id', Integer(), table=<mytable>, 

5158 primary_key=True, nullable=False), 

5159 Column('version_id', Integer(), table=<mytable>, 

5160 primary_key=True, nullable=False) 

5161 ) 

5162 

5163 The primary key of a :class:`_schema.Table` can also be specified by using 

5164 a :class:`.PrimaryKeyConstraint` object explicitly; in this mode of usage, 

5165 the "name" of the constraint can also be specified, as well as other 

5166 options which may be recognized by dialects:: 

5167 

5168 my_table = Table( 

5169 "mytable", 

5170 metadata, 

5171 Column("id", Integer), 

5172 Column("version_id", Integer), 

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

5174 PrimaryKeyConstraint("id", "version_id", name="mytable_pk"), 

5175 ) 

5176 

5177 The two styles of column-specification should generally not be mixed. 

5178 An warning is emitted if the columns present in the 

5179 :class:`.PrimaryKeyConstraint` 

5180 don't match the columns that were marked as ``primary_key=True``, if both 

5181 are present; in this case, the columns are taken strictly from the 

5182 :class:`.PrimaryKeyConstraint` declaration, and those columns otherwise 

5183 marked as ``primary_key=True`` are ignored. This behavior is intended to 

5184 be backwards compatible with previous behavior. 

5185 

5186 For the use case where specific options are to be specified on the 

5187 :class:`.PrimaryKeyConstraint`, but the usual style of using 

5188 ``primary_key=True`` flags is still desirable, an empty 

5189 :class:`.PrimaryKeyConstraint` may be specified, which will take on the 

5190 primary key column collection from the :class:`_schema.Table` based on the 

5191 flags:: 

5192 

5193 my_table = Table( 

5194 "mytable", 

5195 metadata, 

5196 Column("id", Integer, primary_key=True), 

5197 Column("version_id", Integer, primary_key=True), 

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

5199 PrimaryKeyConstraint(name="mytable_pk", mssql_clustered=True), 

5200 ) 

5201 

5202 """ 

5203 

5204 __visit_name__ = "primary_key_constraint" 

5205 

5206 def __init__( 

5207 self, 

5208 *columns: _DDLColumnArgument, 

5209 name: Optional[str] = None, 

5210 deferrable: Optional[bool] = None, 

5211 initially: Optional[str] = None, 

5212 info: Optional[_InfoType] = None, 

5213 _implicit_generated: bool = False, 

5214 **dialect_kw: Any, 

5215 ) -> None: 

5216 self._implicit_generated = _implicit_generated 

5217 super().__init__( 

5218 *columns, 

5219 name=name, 

5220 deferrable=deferrable, 

5221 initially=initially, 

5222 info=info, 

5223 **dialect_kw, 

5224 ) 

5225 

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

5227 table = parent 

5228 assert isinstance(table, Table) 

5229 super()._set_parent(table) 

5230 

5231 if table.primary_key is not self: 

5232 table.constraints.discard(table.primary_key) 

5233 table.primary_key = self # type: ignore 

5234 table.constraints.add(self) 

5235 

5236 table_pks = [c for c in table.c if c.primary_key] 

5237 if ( 

5238 self._columns 

5239 and table_pks 

5240 and set(table_pks) != set(self._columns) 

5241 ): 

5242 # black could not format these inline 

5243 table_pk_str = ", ".join("'%s'" % c.name for c in table_pks) 

5244 col_str = ", ".join("'%s'" % c.name for c in self._columns) 

5245 

5246 util.warn( 

5247 f"Table '{table.name}' specifies columns " 

5248 f"{table_pk_str} as " 

5249 f"primary_key=True, " 

5250 f"not matching locally specified columns {col_str}; " 

5251 f"setting the " 

5252 f"current primary key columns to " 

5253 f"{col_str}. " 

5254 f"This warning " 

5255 f"may become an exception in a future release" 

5256 ) 

5257 table_pks[:] = [] 

5258 

5259 for c in self._columns: 

5260 c.primary_key = True 

5261 if c._user_defined_nullable is NULL_UNSPECIFIED: 

5262 c.nullable = False 

5263 if table_pks: 

5264 self._columns.extend(table_pks) 

5265 

5266 def _reload(self, columns: Iterable[Column[Any]]) -> None: 

5267 """repopulate this :class:`.PrimaryKeyConstraint` given 

5268 a set of columns. 

5269 

5270 Existing columns in the table that are marked as primary_key=True 

5271 are maintained. 

5272 

5273 Also fires a new event. 

5274 

5275 This is basically like putting a whole new 

5276 :class:`.PrimaryKeyConstraint` object on the parent 

5277 :class:`_schema.Table` object without actually replacing the object. 

5278 

5279 The ordering of the given list of columns is also maintained; these 

5280 columns will be appended to the list of columns after any which 

5281 are already present. 

5282 

5283 """ 

5284 # set the primary key flag on new columns. 

5285 # note any existing PK cols on the table also have their 

5286 # flag still set. 

5287 for col in columns: 

5288 col.primary_key = True 

5289 

5290 self._columns.extend(columns) 

5291 

5292 PrimaryKeyConstraint._autoincrement_column._reset(self) # type: ignore 

5293 self._set_parent_with_dispatch(self.table) 

5294 

5295 def _replace(self, col: Column[Any]) -> None: 

5296 PrimaryKeyConstraint._autoincrement_column._reset(self) # type: ignore 

5297 self._columns.replace(col) 

5298 

5299 self.dispatch._sa_event_column_added_to_pk_constraint(self, col) 

5300 

5301 @property 

5302 def columns_autoinc_first(self) -> List[Column[Any]]: 

5303 autoinc = self._autoincrement_column 

5304 

5305 if autoinc is not None: 

5306 return [autoinc] + [c for c in self._columns if c is not autoinc] 

5307 else: 

5308 return list(self._columns) 

5309 

5310 @util.ro_memoized_property 

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

5312 def _validate_autoinc(col: Column[Any], autoinc_true: bool) -> bool: 

5313 if col.type._type_affinity is not None and issubclass( 

5314 col.type._type_affinity, type_api.NUMERICTYPE._type_affinity 

5315 ): 

5316 scale = col.type.scale # type: ignore[attr-defined] 

5317 if scale != 0 and autoinc_true: 

5318 raise exc.ArgumentError( 

5319 f"Column type {col.type} with non-zero scale " 

5320 f"{scale} on column '{col}' is not " 

5321 f"compatible with autoincrement=True" 

5322 ) 

5323 elif not autoinc_true: 

5324 return False 

5325 elif col.type._type_affinity is None or not issubclass( 

5326 col.type._type_affinity, type_api.INTEGERTYPE._type_affinity 

5327 ): 

5328 if autoinc_true: 

5329 raise exc.ArgumentError( 

5330 f"Column type {col.type} on column '{col}' is not " 

5331 f"compatible with autoincrement=True" 

5332 ) 

5333 else: 

5334 return False 

5335 elif ( 

5336 col.default is not None 

5337 and not isinstance(col.default, Sequence) 

5338 and not autoinc_true 

5339 ): 

5340 return False 

5341 elif ( 

5342 col.server_default is not None 

5343 and not isinstance(col.server_default, Identity) 

5344 and not autoinc_true 

5345 ): 

5346 return False 

5347 elif col.foreign_keys and col.autoincrement not in ( 

5348 True, 

5349 "ignore_fk", 

5350 ): 

5351 return False 

5352 return True 

5353 

5354 if len(self._columns) == 1: 

5355 col = list(self._columns)[0] 

5356 

5357 if col.autoincrement is True: 

5358 _validate_autoinc(col, True) 

5359 return col 

5360 elif col.autoincrement in ( 

5361 "auto", 

5362 "ignore_fk", 

5363 ) and _validate_autoinc(col, False): 

5364 return col 

5365 else: 

5366 return None 

5367 

5368 else: 

5369 autoinc = None 

5370 for col in self._columns: 

5371 if col.autoincrement is True: 

5372 _validate_autoinc(col, True) 

5373 if autoinc is not None: 

5374 raise exc.ArgumentError( 

5375 f"Only one Column may be marked " 

5376 f"autoincrement=True, found both " 

5377 f"{col.name} and {autoinc.name}." 

5378 ) 

5379 else: 

5380 autoinc = col 

5381 

5382 return autoinc 

5383 

5384 

5385class UniqueConstraint(ColumnCollectionConstraint): 

5386 """A table-level UNIQUE constraint. 

5387 

5388 Defines a single column or composite UNIQUE constraint. For a no-frills, 

5389 single column constraint, adding ``unique=True`` to the ``Column`` 

5390 definition is a shorthand equivalent for an unnamed, single column 

5391 UniqueConstraint. 

5392 """ 

5393 

5394 __visit_name__ = "unique_constraint" 

5395 

5396 

5397class Index( 

5398 DialectKWArgs, ColumnCollectionMixin, HasConditionalDDL, SchemaItem 

5399): 

5400 """A table-level INDEX. 

5401 

5402 Defines a composite (one or more column) INDEX. 

5403 

5404 E.g.:: 

5405 

5406 sometable = Table( 

5407 "sometable", 

5408 metadata, 

5409 Column("name", String(50)), 

5410 Column("address", String(100)), 

5411 ) 

5412 

5413 Index("some_index", sometable.c.name) 

5414 

5415 For a no-frills, single column index, adding 

5416 :class:`_schema.Column` also supports ``index=True``:: 

5417 

5418 sometable = Table( 

5419 "sometable", metadata, Column("name", String(50), index=True) 

5420 ) 

5421 

5422 For a composite index, multiple columns can be specified:: 

5423 

5424 Index("some_index", sometable.c.name, sometable.c.address) 

5425 

5426 Functional indexes are supported as well, typically by using the 

5427 :data:`.func` construct in conjunction with table-bound 

5428 :class:`_schema.Column` objects:: 

5429 

5430 Index("some_index", func.lower(sometable.c.name)) 

5431 

5432 An :class:`.Index` can also be manually associated with a 

5433 :class:`_schema.Table`, 

5434 either through inline declaration or using 

5435 :meth:`_schema.Table.append_constraint`. When this approach is used, 

5436 the names 

5437 of the indexed columns can be specified as strings:: 

5438 

5439 Table( 

5440 "sometable", 

5441 metadata, 

5442 Column("name", String(50)), 

5443 Column("address", String(100)), 

5444 Index("some_index", "name", "address"), 

5445 ) 

5446 

5447 To support functional or expression-based indexes in this form, the 

5448 :func:`_expression.text` construct may be used:: 

5449 

5450 from sqlalchemy import text 

5451 

5452 Table( 

5453 "sometable", 

5454 metadata, 

5455 Column("name", String(50)), 

5456 Column("address", String(100)), 

5457 Index("some_index", text("lower(name)")), 

5458 ) 

5459 

5460 .. seealso:: 

5461 

5462 :ref:`schema_indexes` - General information on :class:`.Index`. 

5463 

5464 :ref:`postgresql_indexes` - PostgreSQL-specific options available for 

5465 the :class:`.Index` construct. 

5466 

5467 :ref:`mysql_indexes` - MySQL-specific options available for the 

5468 :class:`.Index` construct. 

5469 

5470 :ref:`mssql_indexes` - MSSQL-specific options available for the 

5471 :class:`.Index` construct. 

5472 

5473 """ 

5474 

5475 __visit_name__ = "index" 

5476 

5477 table: Optional[Table] 

5478 expressions: _typing_Sequence[Union[str, ColumnElement[Any]]] 

5479 _table_bound_expressions: _typing_Sequence[ColumnElement[Any]] 

5480 

5481 def __init__( 

5482 self, 

5483 name: Optional[str], 

5484 *expressions: _DDLColumnArgument, 

5485 unique: bool = False, 

5486 quote: Optional[bool] = None, 

5487 info: Optional[_InfoType] = None, 

5488 _table: Optional[Table] = None, 

5489 _column_flag: bool = False, 

5490 **dialect_kw: Any, 

5491 ) -> None: 

5492 r"""Construct an index object. 

5493 

5494 :param name: 

5495 The name of the index 

5496 

5497 :param \*expressions: 

5498 Column expressions to include in the index. The expressions 

5499 are normally instances of :class:`_schema.Column`, but may also 

5500 be arbitrary SQL expressions which ultimately refer to a 

5501 :class:`_schema.Column`. 

5502 

5503 :param unique=False: 

5504 Keyword only argument; if True, create a unique index. 

5505 

5506 :param quote=None: 

5507 Keyword only argument; whether to apply quoting to the name of 

5508 the index. Works in the same manner as that of 

5509 :paramref:`_schema.Column.quote`. 

5510 

5511 :param info=None: Optional data dictionary which will be populated 

5512 into the :attr:`.SchemaItem.info` attribute of this object. 

5513 

5514 :param \**dialect_kw: Additional keyword arguments not mentioned above 

5515 are dialect specific, and passed in the form 

5516 ``<dialectname>_<argname>``. See the documentation regarding an 

5517 individual dialect at :ref:`dialect_toplevel` for detail on 

5518 documented arguments. 

5519 

5520 """ 

5521 self.table = table = None 

5522 

5523 self.name = quoted_name.construct(name, quote) 

5524 self.unique = unique 

5525 if info is not None: 

5526 self.info = info 

5527 

5528 # TODO: consider "table" argument being public, but for 

5529 # the purpose of the fix here, it starts as private. 

5530 if _table is not None: 

5531 table = _table 

5532 

5533 self._validate_dialect_kwargs(dialect_kw) 

5534 

5535 self.expressions = [] 

5536 # will call _set_parent() if table-bound column 

5537 # objects are present 

5538 ColumnCollectionMixin.__init__( 

5539 self, 

5540 *expressions, 

5541 _column_flag=_column_flag, 

5542 _gather_expressions=self.expressions, 

5543 ) 

5544 if table is not None: 

5545 self._set_parent(table) 

5546 

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

5548 table = parent 

5549 assert isinstance(table, Table) 

5550 ColumnCollectionMixin._set_parent(self, table) 

5551 

5552 if self.table is not None and table is not self.table: 

5553 raise exc.ArgumentError( 

5554 f"Index '{self.name}' is against table " 

5555 f"'{self.table.description}', and " 

5556 f"cannot be associated with table '{table.description}'." 

5557 ) 

5558 self.table = table 

5559 table.indexes.add(self) 

5560 

5561 expressions = self.expressions 

5562 col_expressions = self._col_expressions(table) 

5563 assert len(expressions) == len(col_expressions) 

5564 

5565 exprs = [] 

5566 for expr, colexpr in zip(expressions, col_expressions): 

5567 if isinstance(expr, ClauseElement): 

5568 exprs.append(expr) 

5569 elif colexpr is not None: 

5570 exprs.append(colexpr) 

5571 else: 

5572 assert False 

5573 self.expressions = self._table_bound_expressions = exprs 

5574 

5575 def create( 

5576 self, 

5577 bind: _CreateDropBind, 

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

5579 ) -> None: 

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

5581 :class:`.Index`, using the given 

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

5583 

5584 .. seealso:: 

5585 

5586 :meth:`_schema.MetaData.create_all`. 

5587 

5588 """ 

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

5590 

5591 def drop( 

5592 self, 

5593 bind: _CreateDropBind, 

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

5595 ) -> None: 

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

5597 :class:`.Index`, using the given 

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

5599 

5600 .. seealso:: 

5601 

5602 :meth:`_schema.MetaData.drop_all`. 

5603 

5604 """ 

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

5606 

5607 def __repr__(self) -> str: 

5608 exprs: _typing_Sequence[Any] # noqa: F842 

5609 

5610 return "Index(%s)" % ( 

5611 ", ".join( 

5612 [repr(self.name)] 

5613 + [repr(e) for e in self.expressions] 

5614 + (self.unique and ["unique=True"] or []) 

5615 ) 

5616 ) 

5617 

5618 

5619_NamingSchemaCallable = Callable[[Constraint, Table], str] 

5620_NamingSchemaDirective = Union[str, _NamingSchemaCallable] 

5621 

5622 

5623class _NamingSchemaTD(TypedDict, total=False): 

5624 fk: _NamingSchemaDirective 

5625 pk: _NamingSchemaDirective 

5626 ix: _NamingSchemaDirective 

5627 ck: _NamingSchemaDirective 

5628 uq: _NamingSchemaDirective 

5629 

5630 

5631_NamingSchemaParameter = Union[ 

5632 # it seems like the TypedDict here is useful for pylance typeahead, 

5633 # and not much else 

5634 _NamingSchemaTD, 

5635 # there is no form that allows Union[Type[Any], str] to work in all 

5636 # cases, including breaking out Mapping[] entries for each combination 

5637 # even, therefore keys must be `Any` (see #10264) 

5638 Mapping[Any, _NamingSchemaDirective], 

5639] 

5640 

5641 

5642DEFAULT_NAMING_CONVENTION: _NamingSchemaParameter = util.immutabledict( 

5643 {"ix": "ix_%(column_0_label)s"} 

5644) 

5645 

5646 

5647class MetaData(HasSchemaAttr): 

5648 """A collection of :class:`_schema.Table` 

5649 objects and their associated schema 

5650 constructs. 

5651 

5652 Holds a collection of :class:`_schema.Table` objects as well as 

5653 an optional binding to an :class:`_engine.Engine` or 

5654 :class:`_engine.Connection`. If bound, the :class:`_schema.Table` objects 

5655 in the collection and their columns may participate in implicit SQL 

5656 execution. 

5657 

5658 The :class:`_schema.Table` objects themselves are stored in the 

5659 :attr:`_schema.MetaData.tables` dictionary. 

5660 

5661 :class:`_schema.MetaData` is a thread-safe object for read operations. 

5662 Construction of new tables within a single :class:`_schema.MetaData` 

5663 object, 

5664 either explicitly or via reflection, may not be completely thread-safe. 

5665 

5666 .. seealso:: 

5667 

5668 :ref:`metadata_describing` - Introduction to database metadata 

5669 

5670 """ 

5671 

5672 __visit_name__ = "metadata" 

5673 

5674 def __init__( 

5675 self, 

5676 schema: Optional[str] = None, 

5677 quote_schema: Optional[bool] = None, 

5678 naming_convention: Optional[_NamingSchemaParameter] = None, 

5679 info: Optional[_InfoType] = None, 

5680 ) -> None: 

5681 """Create a new MetaData object. 

5682 

5683 :param schema: 

5684 The default schema to use for the :class:`_schema.Table`, 

5685 :class:`.Sequence`, and potentially other objects associated with 

5686 this :class:`_schema.MetaData`. Defaults to ``None``. 

5687 

5688 .. seealso:: 

5689 

5690 :ref:`schema_metadata_schema_name` - details on how the 

5691 :paramref:`_schema.MetaData.schema` parameter is used. 

5692 

5693 :paramref:`_schema.Table.schema` 

5694 

5695 :paramref:`.Sequence.schema` 

5696 

5697 :param quote_schema: 

5698 Sets the ``quote_schema`` flag for those :class:`_schema.Table`, 

5699 :class:`.Sequence`, and other objects which make usage of the 

5700 local ``schema`` name. 

5701 

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

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

5704 

5705 :param naming_convention: a dictionary referring to values which 

5706 will establish default naming conventions for :class:`.Constraint` 

5707 and :class:`.Index` objects, for those objects which are not given 

5708 a name explicitly. 

5709 

5710 The keys of this dictionary may be: 

5711 

5712 * a constraint or Index class, e.g. the :class:`.UniqueConstraint`, 

5713 :class:`_schema.ForeignKeyConstraint` class, the :class:`.Index` 

5714 class 

5715 

5716 * a string mnemonic for one of the known constraint classes; 

5717 ``"fk"``, ``"pk"``, ``"ix"``, ``"ck"``, ``"uq"`` for foreign key, 

5718 primary key, index, check, and unique constraint, respectively. 

5719 

5720 * the string name of a user-defined "token" that can be used 

5721 to define new naming tokens. 

5722 

5723 The values associated with each "constraint class" or "constraint 

5724 mnemonic" key are string naming templates, such as 

5725 ``"uq_%(table_name)s_%(column_0_name)s"``, 

5726 which describe how the name should be composed. The values 

5727 associated with user-defined "token" keys should be callables of the 

5728 form ``fn(constraint, table)``, which accepts the constraint/index 

5729 object and :class:`_schema.Table` as arguments, returning a string 

5730 result. 

5731 

5732 The built-in names are as follows, some of which may only be 

5733 available for certain types of constraint: 

5734 

5735 * ``%(table_name)s`` - the name of the :class:`_schema.Table` 

5736 object 

5737 associated with the constraint. 

5738 

5739 * ``%(referred_table_name)s`` - the name of the 

5740 :class:`_schema.Table` 

5741 object associated with the referencing target of a 

5742 :class:`_schema.ForeignKeyConstraint`. 

5743 

5744 * ``%(column_0_name)s`` - the name of the :class:`_schema.Column` 

5745 at 

5746 index position "0" within the constraint. 

5747 

5748 * ``%(column_0N_name)s`` - the name of all :class:`_schema.Column` 

5749 objects in order within the constraint, joined without a 

5750 separator. 

5751 

5752 * ``%(column_0_N_name)s`` - the name of all 

5753 :class:`_schema.Column` 

5754 objects in order within the constraint, joined with an 

5755 underscore as a separator. 

5756 

5757 * ``%(column_0_label)s``, ``%(column_0N_label)s``, 

5758 ``%(column_0_N_label)s`` - the label of either the zeroth 

5759 :class:`_schema.Column` or all :class:`.Columns`, separated with 

5760 or without an underscore 

5761 

5762 * ``%(column_0_key)s``, ``%(column_0N_key)s``, 

5763 ``%(column_0_N_key)s`` - the key of either the zeroth 

5764 :class:`_schema.Column` or all :class:`.Columns`, separated with 

5765 or without an underscore 

5766 

5767 * ``%(referred_column_0_name)s``, ``%(referred_column_0N_name)s`` 

5768 ``%(referred_column_0_N_name)s``, ``%(referred_column_0_key)s``, 

5769 ``%(referred_column_0N_key)s``, ... column tokens which 

5770 render the names/keys/labels of columns that are referenced 

5771 by a :class:`_schema.ForeignKeyConstraint`. 

5772 

5773 * ``%(constraint_name)s`` - a special key that refers to the 

5774 existing name given to the constraint. When this key is 

5775 present, the :class:`.Constraint` object's existing name will be 

5776 replaced with one that is composed from template string that 

5777 uses this token. When this token is present, it is required that 

5778 the :class:`.Constraint` is given an explicit name ahead of time. 

5779 

5780 * user-defined: any additional token may be implemented by passing 

5781 it along with a ``fn(constraint, table)`` callable to the 

5782 naming_convention dictionary. 

5783 

5784 .. seealso:: 

5785 

5786 :ref:`constraint_naming_conventions` - for detailed usage 

5787 examples. 

5788 

5789 """ 

5790 if schema is not None and not isinstance(schema, str): 

5791 raise exc.ArgumentError( 

5792 "expected schema argument to be a string, " 

5793 f"got {type(schema)}." 

5794 ) 

5795 self.tables = util.FacadeDict() 

5796 self.schema = quoted_name.construct(schema, quote_schema) 

5797 self.naming_convention = ( 

5798 naming_convention 

5799 if naming_convention 

5800 else DEFAULT_NAMING_CONVENTION 

5801 ) 

5802 if info: 

5803 self.info = info 

5804 self._schemas: Set[str] = set() 

5805 self._sequences: Dict[str, Sequence] = {} 

5806 self._fk_memos: Dict[Tuple[str, Optional[str]], List[ForeignKey]] = ( 

5807 collections.defaultdict(list) 

5808 ) 

5809 self._objects: Set[Union[HasSchemaAttr, SchemaType]] = set() 

5810 

5811 tables: util.FacadeDict[str, Table] 

5812 """A dictionary of :class:`_schema.Table` 

5813 objects keyed to their name or "table key". 

5814 

5815 The exact key is that determined by the :attr:`_schema.Table.key` 

5816 attribute; 

5817 for a table with no :attr:`_schema.Table.schema` attribute, 

5818 this is the same 

5819 as :attr:`_schema.Table.name`. For a table with a schema, 

5820 it is typically of the 

5821 form ``schemaname.tablename``. 

5822 

5823 .. seealso:: 

5824 

5825 :attr:`_schema.MetaData.sorted_tables` 

5826 

5827 """ 

5828 

5829 def __repr__(self) -> str: 

5830 return "MetaData()" 

5831 

5832 def __contains__(self, table_or_key: Union[str, Table]) -> bool: 

5833 if not isinstance(table_or_key, str): 

5834 table_or_key = table_or_key.key 

5835 return table_or_key in self.tables 

5836 

5837 def _add_table( 

5838 self, name: str, schema: Optional[str], table: Table 

5839 ) -> None: 

5840 key = _get_table_key(name, schema) 

5841 self.tables._insert_item(key, table) 

5842 if schema: 

5843 self._schemas.add(schema) 

5844 

5845 def _remove_table(self, name: str, schema: Optional[str]) -> None: 

5846 key = _get_table_key(name, schema) 

5847 removed = dict.pop(self.tables, key, None) 

5848 if removed is not None: 

5849 for fk in removed.foreign_keys: 

5850 fk._remove_from_metadata(self) 

5851 if self._schemas: 

5852 self._schemas = { 

5853 t.schema for t in self.tables.values() if t.schema is not None 

5854 } 

5855 

5856 def __getstate__(self) -> Dict[str, Any]: 

5857 return { 

5858 "tables": self.tables, 

5859 "schema": self.schema, 

5860 "schemas": self._schemas, 

5861 "sequences": self._sequences, 

5862 "fk_memos": self._fk_memos, 

5863 "naming_convention": self.naming_convention, 

5864 "objects": self._objects, 

5865 } 

5866 

5867 def __setstate__(self, state: Dict[str, Any]) -> None: 

5868 self.tables = state["tables"] 

5869 self.schema = state["schema"] 

5870 self.naming_convention = state["naming_convention"] 

5871 self._sequences = state["sequences"] 

5872 self._schemas = state["schemas"] 

5873 self._fk_memos = state["fk_memos"] 

5874 self._objects = state.get("objects", set()) 

5875 

5876 def clear(self) -> None: 

5877 """Clear all objects from this MetaData.""" 

5878 

5879 dict.clear(self.tables) 

5880 self._schemas.clear() 

5881 self._fk_memos.clear() 

5882 self._sequences.clear() 

5883 self._objects.clear() 

5884 

5885 def remove(self, table: Table) -> None: 

5886 """Remove the given Table object from this MetaData.""" 

5887 

5888 self._remove_table(table.name, table.schema) 

5889 

5890 @property 

5891 def sorted_tables(self) -> List[Table]: 

5892 """Returns a list of :class:`_schema.Table` objects sorted in order of 

5893 foreign key dependency. 

5894 

5895 The sorting will place :class:`_schema.Table` 

5896 objects that have dependencies 

5897 first, before the dependencies themselves, representing the 

5898 order in which they can be created. To get the order in which 

5899 the tables would be dropped, use the ``reversed()`` Python built-in. 

5900 

5901 .. warning:: 

5902 

5903 The :attr:`.MetaData.sorted_tables` attribute cannot by itself 

5904 accommodate automatic resolution of dependency cycles between 

5905 tables, which are usually caused by mutually dependent foreign key 

5906 constraints. When these cycles are detected, the foreign keys 

5907 of these tables are omitted from consideration in the sort. 

5908 A warning is emitted when this condition occurs, which will be an 

5909 exception raise in a future release. Tables which are not part 

5910 of the cycle will still be returned in dependency order. 

5911 

5912 To resolve these cycles, the 

5913 :paramref:`_schema.ForeignKeyConstraint.use_alter` parameter may be 

5914 applied to those constraints which create a cycle. Alternatively, 

5915 the :func:`_schema.sort_tables_and_constraints` function will 

5916 automatically return foreign key constraints in a separate 

5917 collection when cycles are detected so that they may be applied 

5918 to a schema separately. 

5919 

5920 .. seealso:: 

5921 

5922 :func:`_schema.sort_tables` 

5923 

5924 :func:`_schema.sort_tables_and_constraints` 

5925 

5926 :attr:`_schema.MetaData.tables` 

5927 

5928 :meth:`_reflection.Inspector.get_table_names` 

5929 

5930 :meth:`_reflection.Inspector.get_sorted_table_and_fkc_names` 

5931 

5932 

5933 """ 

5934 return ddl.sort_tables( 

5935 sorted(self.tables.values(), key=lambda t: t.key) # type: ignore 

5936 ) 

5937 

5938 # overload needed to work around mypy this mypy 

5939 # https://github.com/python/mypy/issues/17093 

5940 @overload 

5941 def reflect( 

5942 self, 

5943 bind: Engine, 

5944 schema: Optional[str] = ..., 

5945 views: bool = ..., 

5946 only: Union[ 

5947 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

5948 ] = ..., 

5949 extend_existing: bool = ..., 

5950 autoload_replace: bool = ..., 

5951 resolve_fks: bool = ..., 

5952 **dialect_kwargs: Any, 

5953 ) -> None: ... 

5954 

5955 @overload 

5956 def reflect( 

5957 self, 

5958 bind: Connection, 

5959 schema: Optional[str] = ..., 

5960 views: bool = ..., 

5961 only: Union[ 

5962 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

5963 ] = ..., 

5964 extend_existing: bool = ..., 

5965 autoload_replace: bool = ..., 

5966 resolve_fks: bool = ..., 

5967 **dialect_kwargs: Any, 

5968 ) -> None: ... 

5969 

5970 @util.preload_module("sqlalchemy.engine.reflection") 

5971 def reflect( 

5972 self, 

5973 bind: Union[Engine, Connection], 

5974 schema: Optional[str] = None, 

5975 views: bool = False, 

5976 only: Union[ 

5977 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

5978 ] = None, 

5979 extend_existing: bool = False, 

5980 autoload_replace: bool = True, 

5981 resolve_fks: bool = True, 

5982 **dialect_kwargs: Any, 

5983 ) -> None: 

5984 r"""Load all available table definitions from the database. 

5985 

5986 Automatically creates ``Table`` entries in this ``MetaData`` for any 

5987 table available in the database but not yet present in the 

5988 ``MetaData``. May be called multiple times to pick up tables recently 

5989 added to the database, however no special action is taken if a table 

5990 in this ``MetaData`` no longer exists in the database. 

5991 

5992 :param bind: 

5993 A :class:`.Connection` or :class:`.Engine` used to access the 

5994 database. 

5995 

5996 :param schema: 

5997 Optional, query and reflect tables from an alternate schema. 

5998 If None, the schema associated with this :class:`_schema.MetaData` 

5999 is used, if any. 

6000 

6001 :param views: 

6002 If True, also reflect views (materialized and plain). 

6003 

6004 :param only: 

6005 Optional. Load only a sub-set of available named tables. May be 

6006 specified as a sequence of names or a callable. 

6007 

6008 If a sequence of names is provided, only those tables will be 

6009 reflected. An error is raised if a table is requested but not 

6010 available. Named tables already present in this ``MetaData`` are 

6011 ignored. 

6012 

6013 If a callable is provided, it will be used as a boolean predicate to 

6014 filter the list of potential table names. The callable is called 

6015 with a table name and this ``MetaData`` instance as positional 

6016 arguments and should return a true value for any table to reflect. 

6017 

6018 :param extend_existing: Passed along to each :class:`_schema.Table` as 

6019 :paramref:`_schema.Table.extend_existing`. 

6020 

6021 :param autoload_replace: Passed along to each :class:`_schema.Table` 

6022 as 

6023 :paramref:`_schema.Table.autoload_replace`. 

6024 

6025 :param resolve_fks: if True, reflect :class:`_schema.Table` 

6026 objects linked 

6027 to :class:`_schema.ForeignKey` objects located in each 

6028 :class:`_schema.Table`. 

6029 For :meth:`_schema.MetaData.reflect`, 

6030 this has the effect of reflecting 

6031 related tables that might otherwise not be in the list of tables 

6032 being reflected, for example if the referenced table is in a 

6033 different schema or is omitted via the 

6034 :paramref:`.MetaData.reflect.only` parameter. When False, 

6035 :class:`_schema.ForeignKey` objects are not followed to the 

6036 :class:`_schema.Table` 

6037 in which they link, however if the related table is also part of the 

6038 list of tables that would be reflected in any case, the 

6039 :class:`_schema.ForeignKey` object will still resolve to its related 

6040 :class:`_schema.Table` after the :meth:`_schema.MetaData.reflect` 

6041 operation is 

6042 complete. Defaults to True. 

6043 

6044 .. seealso:: 

6045 

6046 :paramref:`_schema.Table.resolve_fks` 

6047 

6048 :param \**dialect_kwargs: Additional keyword arguments not mentioned 

6049 above are dialect specific, and passed in the form 

6050 ``<dialectname>_<argname>``. See the documentation regarding an 

6051 individual dialect at :ref:`dialect_toplevel` for detail on 

6052 documented arguments. 

6053 

6054 .. seealso:: 

6055 

6056 :ref:`metadata_reflection_toplevel` 

6057 

6058 :meth:`_events.DDLEvents.column_reflect` - Event used to customize 

6059 the reflected columns. Usually used to generalize the types using 

6060 :meth:`_types.TypeEngine.as_generic` 

6061 

6062 :ref:`metadata_reflection_dbagnostic_types` - describes how to 

6063 reflect tables using general types. 

6064 

6065 """ 

6066 

6067 with inspection.inspect(bind)._inspection_context() as insp: 

6068 reflect_opts: Any = { 

6069 "autoload_with": insp, 

6070 "extend_existing": extend_existing, 

6071 "autoload_replace": autoload_replace, 

6072 "resolve_fks": resolve_fks, 

6073 "_extend_on": set(), 

6074 } 

6075 

6076 reflect_opts.update(dialect_kwargs) 

6077 

6078 if schema is None: 

6079 schema = self.schema 

6080 

6081 if schema is not None: 

6082 reflect_opts["schema"] = schema 

6083 

6084 kind = util.preloaded.engine_reflection.ObjectKind.TABLE 

6085 available: util.OrderedSet[str] = util.OrderedSet( 

6086 insp.get_table_names(schema, **dialect_kwargs) 

6087 ) 

6088 if views: 

6089 kind = util.preloaded.engine_reflection.ObjectKind.ANY 

6090 available.update(insp.get_view_names(schema, **dialect_kwargs)) 

6091 try: 

6092 available.update( 

6093 insp.get_materialized_view_names( 

6094 schema, **dialect_kwargs 

6095 ) 

6096 ) 

6097 except NotImplementedError: 

6098 pass 

6099 

6100 if schema is not None: 

6101 available_w_schema: util.OrderedSet[str] = util.OrderedSet( 

6102 [f"{schema}.{name}" for name in available] 

6103 ) 

6104 else: 

6105 available_w_schema = available 

6106 

6107 current = set(self.tables) 

6108 

6109 if only is None: 

6110 load = [ 

6111 name 

6112 for name, schname in zip(available, available_w_schema) 

6113 if extend_existing or schname not in current 

6114 ] 

6115 elif callable(only): 

6116 load = [ 

6117 name 

6118 for name, schname in zip(available, available_w_schema) 

6119 if (extend_existing or schname not in current) 

6120 and only(name, self) 

6121 ] 

6122 else: 

6123 missing = [name for name in only if name not in available] 

6124 if missing: 

6125 s = schema and (" schema '%s'" % schema) or "" 

6126 missing_str = ", ".join(missing) 

6127 raise exc.InvalidRequestError( 

6128 f"Could not reflect: requested table(s) not available " 

6129 f"in {bind.engine!r}{s}: ({missing_str})" 

6130 ) 

6131 load = [ 

6132 name 

6133 for name in only 

6134 if extend_existing or name not in current 

6135 ] 

6136 # pass the available tables so the inspector can 

6137 # choose to ignore the filter_names 

6138 _reflect_info = insp._get_reflection_info( 

6139 schema=schema, 

6140 filter_names=load, 

6141 available=available, 

6142 kind=kind, 

6143 scope=util.preloaded.engine_reflection.ObjectScope.ANY, 

6144 **dialect_kwargs, 

6145 ) 

6146 reflect_opts["_reflect_info"] = _reflect_info 

6147 

6148 for name in load: 

6149 try: 

6150 Table(name, self, **reflect_opts) 

6151 except exc.UnreflectableTableError as uerr: 

6152 util.warn(f"Skipping table {name}: {uerr}") 

6153 

6154 def create_all( 

6155 self, 

6156 bind: _CreateDropBind, 

6157 tables: Optional[_typing_Sequence[Table]] = None, 

6158 checkfirst: Union[bool, CheckFirst] = CheckFirst.ALL, 

6159 ) -> None: 

6160 """Create all tables stored in this metadata. 

6161 

6162 Conditional by default, will not attempt to recreate tables already 

6163 present in the target database. 

6164 

6165 :param bind: 

6166 A :class:`.Connection` or :class:`.Engine` used to access the 

6167 database. 

6168 

6169 :param tables: 

6170 Optional list of ``Table`` objects, which is a subset of the total 

6171 tables in the ``MetaData`` (others are ignored). 

6172 

6173 :param checkfirst: A boolean value or instance of :class:`.CheckFirst`. 

6174 Indicates which objects should be checked for within a separate pass 

6175 before creating schema objects. 

6176 

6177 """ 

6178 bind._run_ddl_visitor( 

6179 ddl.SchemaGenerator, self, checkfirst=checkfirst, tables=tables 

6180 ) 

6181 

6182 def drop_all( 

6183 self, 

6184 bind: _CreateDropBind, 

6185 tables: Optional[_typing_Sequence[Table]] = None, 

6186 checkfirst: Union[bool, CheckFirst] = CheckFirst.ALL, 

6187 ) -> None: 

6188 """Drop all tables stored in this metadata. 

6189 

6190 Conditional by default, will not attempt to drop tables not present in 

6191 the target database. 

6192 

6193 :param bind: 

6194 A :class:`.Connection` or :class:`.Engine` used to access the 

6195 database. 

6196 

6197 :param tables: 

6198 Optional list of ``Table`` objects, which is a subset of the 

6199 total tables in the ``MetaData`` (others are ignored). 

6200 

6201 :param checkfirst: A boolean value or instance of :class:`.CheckFirst`. 

6202 Indicates which objects should be checked for within a separate pass 

6203 before dropping schema objects. 

6204 

6205 """ 

6206 bind._run_ddl_visitor( 

6207 ddl.SchemaDropper, self, checkfirst=checkfirst, tables=tables 

6208 ) 

6209 

6210 @property 

6211 def schemas(self) -> _typing_Sequence[str]: 

6212 """A sequence of schema names that are present in this MetaData.""" 

6213 schemas = self._schemas 

6214 if self.schema: 

6215 schemas = schemas | {self.schema} 

6216 return tuple(schemas) 

6217 

6218 def get_schema_objects( 

6219 self, 

6220 kind: Type[_T], 

6221 *, 

6222 schema: Union[str, None, Literal[_NoArg.NO_ARG]] = _NoArg.NO_ARG, 

6223 ) -> _typing_Sequence[_T]: 

6224 """Return a sequence of schema objects of the given kind. 

6225 

6226 This method can be used to return :class:`_sqltypes.Enum`, 

6227 :class:`.Sequence`, etc. objects registered in this 

6228 :class:`_schema.MetaData`. 

6229 

6230 :param kind: a type that indicates what object to return, such as 

6231 :class:`Enum` or :class:`Sequence`. 

6232 :param schema: Optional, a schema name to filter the objects by. If 

6233 not provided the default schema of the metadata is used. 

6234 

6235 """ 

6236 

6237 if schema is _NoArg.NO_ARG: 

6238 schema = self.schema 

6239 return tuple( 

6240 obj 

6241 for obj in self._objects 

6242 if isinstance(obj, kind) and obj.schema == schema 

6243 ) 

6244 

6245 def get_schema_object_by_name( 

6246 self, 

6247 kind: Type[_T], 

6248 name: str, 

6249 *, 

6250 schema: Union[str, None, Literal[_NoArg.NO_ARG]] = _NoArg.NO_ARG, 

6251 ) -> Optional[_T]: 

6252 """Return a schema objects of the given kind and name if found. 

6253 

6254 This method can be used to return :class:`_sqltypes.Enum`, 

6255 :class:`.Sequence`, etc. objects registered in this 

6256 :class:`_schema.MetaData`. 

6257 

6258 :param kind: a type that indicates what object to return, such as 

6259 :class:`Enum` or :class:`Sequence`. 

6260 :param name: the name of the object to return. 

6261 :param schema: Optional, a schema name to filter the objects by. If 

6262 not provided the default schema of the metadata is used. 

6263 

6264 """ 

6265 

6266 for obj in self.get_schema_objects(kind, schema=schema): 

6267 if getattr(obj, "name", None) == name: 

6268 return obj 

6269 return None 

6270 

6271 def _register_object(self, obj: Union[HasSchemaAttr, SchemaType]) -> None: 

6272 self._objects.add(obj) 

6273 

6274 

6275class Computed(FetchedValue, SchemaItem): 

6276 """Defines a generated column, i.e. "GENERATED ALWAYS AS" syntax. 

6277 

6278 The :class:`.Computed` construct is an inline construct added to the 

6279 argument list of a :class:`_schema.Column` object:: 

6280 

6281 from sqlalchemy import Computed 

6282 

6283 Table( 

6284 "square", 

6285 metadata_obj, 

6286 Column("side", Float, nullable=False), 

6287 Column("area", Float, Computed("side * side")), 

6288 ) 

6289 

6290 See the linked documentation below for complete details. 

6291 

6292 .. seealso:: 

6293 

6294 :ref:`computed_ddl` 

6295 

6296 """ 

6297 

6298 __visit_name__ = "computed_column" 

6299 

6300 column: Optional[Column[Any]] 

6301 

6302 @_document_text_coercion( 

6303 "sqltext", ":class:`.Computed`", ":paramref:`.Computed.sqltext`" 

6304 ) 

6305 def __init__( 

6306 self, sqltext: _DDLColumnArgument, persisted: Optional[bool] = None 

6307 ) -> None: 

6308 """Construct a GENERATED ALWAYS AS DDL construct to accompany a 

6309 :class:`_schema.Column`. 

6310 

6311 :param sqltext: 

6312 A string containing the column generation expression, which will be 

6313 used verbatim, or a SQL expression construct, such as a 

6314 :func:`_expression.text` 

6315 object. If given as a string, the object is converted to a 

6316 :func:`_expression.text` object. 

6317 

6318 :param persisted: 

6319 Optional, controls how this column should be persisted by the 

6320 database. Possible values are: 

6321 

6322 * ``None``, the default, it will use the default persistence 

6323 defined by the database. 

6324 * ``True``, will render ``GENERATED ALWAYS AS ... STORED``, or the 

6325 equivalent for the target database if supported. 

6326 * ``False``, will render ``GENERATED ALWAYS AS ... VIRTUAL``, or 

6327 the equivalent for the target database if supported. 

6328 

6329 Specifying ``True`` or ``False`` may raise an error when the DDL 

6330 is emitted to the target database if the database does not support 

6331 that persistence option. Leaving this parameter at its default 

6332 of ``None`` is guaranteed to succeed for all databases that support 

6333 ``GENERATED ALWAYS AS``. 

6334 

6335 """ 

6336 self.sqltext = coercions.expect(roles.DDLExpressionRole, sqltext) 

6337 self.persisted = persisted 

6338 self.column = None 

6339 

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

6341 assert isinstance(parent, Column) 

6342 

6343 if not isinstance( 

6344 parent.server_default, (type(None), Computed) 

6345 ) or not isinstance(parent.server_onupdate, (type(None), Computed)): 

6346 raise exc.ArgumentError( 

6347 "A generated column cannot specify a server_default or a " 

6348 "server_onupdate argument" 

6349 ) 

6350 self.column = parent 

6351 parent.computed = self 

6352 self.column.server_onupdate = self 

6353 self.column.server_default = self 

6354 

6355 def _as_for_update(self, for_update: bool) -> FetchedValue: 

6356 return self 

6357 

6358 @util.deprecated( 

6359 "1.4", 

6360 "The :meth:`_schema.Computed.copy` method is deprecated " 

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

6362 ) 

6363 def copy( 

6364 self, *, target_table: Optional[Table] = None, **kw: Any 

6365 ) -> Computed: 

6366 return self._copy(target_table=target_table, **kw) 

6367 

6368 def _copy( 

6369 self, *, target_table: Optional[Table] = None, **kw: Any 

6370 ) -> Computed: 

6371 sqltext = _copy_expression( 

6372 self.sqltext, 

6373 self.column.table if self.column is not None else None, 

6374 target_table, 

6375 ) 

6376 g = Computed(sqltext, persisted=self.persisted) 

6377 

6378 return self._schema_item_copy(g) 

6379 

6380 

6381class Identity(IdentityOptions, FetchedValue, SchemaItem): 

6382 """Defines an identity column, i.e. "GENERATED { ALWAYS | BY DEFAULT } 

6383 AS IDENTITY" syntax. 

6384 

6385 The :class:`.Identity` construct is an inline construct added to the 

6386 argument list of a :class:`_schema.Column` object:: 

6387 

6388 from sqlalchemy import Identity 

6389 

6390 Table( 

6391 "foo", 

6392 metadata_obj, 

6393 Column("id", Integer, Identity()), 

6394 Column("description", Text), 

6395 ) 

6396 

6397 See the linked documentation below for complete details. 

6398 

6399 .. versionadded:: 1.4 

6400 

6401 .. seealso:: 

6402 

6403 :ref:`identity_ddl` 

6404 

6405 """ 

6406 

6407 __visit_name__ = "identity_column" 

6408 

6409 is_identity = True 

6410 

6411 @util.deprecated_params( 

6412 order=( 

6413 "2.1", 

6414 "This parameter is supported only by Oracle Database, " 

6415 "use ``oracle_order`` instead.", 

6416 ), 

6417 on_null=( 

6418 "2.1", 

6419 "This parameter is supported only by Oracle Database, " 

6420 "use ``oracle_on_null`` instead.", 

6421 ), 

6422 ) 

6423 def __init__( 

6424 self, 

6425 always: Optional[bool] = False, 

6426 on_null: Optional[bool] = None, 

6427 start: Optional[int] = None, 

6428 increment: Optional[int] = None, 

6429 minvalue: Optional[int] = None, 

6430 maxvalue: Optional[int] = None, 

6431 nominvalue: Optional[bool] = None, 

6432 nomaxvalue: Optional[bool] = None, 

6433 cycle: Optional[bool] = None, 

6434 cache: Optional[int] = None, 

6435 order: Optional[bool] = None, 

6436 **dialect_kw: Any, 

6437 ) -> None: 

6438 """Construct a GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY DDL 

6439 construct to accompany a :class:`_schema.Column`. 

6440 

6441 See the :class:`.Sequence` documentation for a complete description 

6442 of most parameters. 

6443 

6444 .. note:: 

6445 MSSQL supports this construct as the preferred alternative to 

6446 generate an IDENTITY on a column, but it uses non standard 

6447 syntax that only support :paramref:`_schema.Identity.start` 

6448 and :paramref:`_schema.Identity.increment`. 

6449 All other parameters are ignored. 

6450 

6451 :param always: 

6452 A boolean, that indicates the type of identity column. 

6453 If ``False`` is specified, the default, then the user-specified 

6454 value takes precedence. 

6455 If ``True`` is specified, a user-specified value is not accepted ( 

6456 on some backends, like PostgreSQL, OVERRIDING SYSTEM VALUE, or 

6457 similar, may be specified in an INSERT to override the sequence 

6458 value). 

6459 Some backends also have a default value for this parameter, 

6460 ``None`` can be used to omit rendering this part in the DDL. It 

6461 will be treated as ``False`` if a backend does not have a default 

6462 value. 

6463 

6464 :param on_null: 

6465 Set to ``True`` to specify ON NULL in conjunction with a 

6466 ``always=False`` identity column. This option is only supported on 

6467 some backends, like Oracle Database. 

6468 

6469 :param start: the starting index of the sequence. 

6470 :param increment: the increment value of the sequence. 

6471 :param minvalue: the minimum value of the sequence. 

6472 :param maxvalue: the maximum value of the sequence. 

6473 :param nominvalue: no minimum value of the sequence. 

6474 :param nomaxvalue: no maximum value of the sequence. 

6475 :param cycle: allows the sequence to wrap around when the maxvalue 

6476 or minvalue has been reached. 

6477 :param cache: optional integer value; number of future values in the 

6478 sequence which are calculated in advance. 

6479 :param order: optional boolean value; if true, renders the 

6480 ORDER keyword. 

6481 

6482 """ 

6483 self.dialect_options 

6484 if on_null is not None: 

6485 if "oracle_on_null" in dialect_kw: 

6486 raise exc.ArgumentError( 

6487 "Cannot specify both 'on_null' and 'oracle_on_null'. " 

6488 "Plese use only 'oracle_on_null'." 

6489 ) 

6490 dialect_kw["oracle_on_null"] = on_null 

6491 

6492 IdentityOptions.__init__( 

6493 self, 

6494 start=start, 

6495 increment=increment, 

6496 minvalue=minvalue, 

6497 maxvalue=maxvalue, 

6498 nominvalue=nominvalue, 

6499 nomaxvalue=nomaxvalue, 

6500 cycle=cycle, 

6501 cache=cache, 

6502 order=order, 

6503 **dialect_kw, 

6504 ) 

6505 self.always = always 

6506 self.column = None 

6507 

6508 @property 

6509 def on_null(self) -> Optional[bool]: 

6510 """Alias of the ``dialect_kwargs`` ``'oracle_on_null'``. 

6511 

6512 .. deprecated:: 2.1 The 'on_null' attribute is deprecated. 

6513 """ 

6514 value: Optional[bool] = self.dialect_kwargs.get("oracle_on_null") 

6515 return value 

6516 

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

6518 assert isinstance(parent, Column) 

6519 if not isinstance( 

6520 parent.server_default, (type(None), Identity) 

6521 ) or not isinstance(parent.server_onupdate, type(None)): 

6522 raise exc.ArgumentError( 

6523 "A column with an Identity object cannot specify a " 

6524 "server_default or a server_onupdate argument" 

6525 ) 

6526 if parent.autoincrement is False: 

6527 raise exc.ArgumentError( 

6528 "A column with an Identity object cannot specify " 

6529 "autoincrement=False" 

6530 ) 

6531 self.column = parent 

6532 

6533 parent.identity = self 

6534 if parent._user_defined_nullable is NULL_UNSPECIFIED: 

6535 parent.nullable = False 

6536 

6537 parent.server_default = self 

6538 

6539 def _as_for_update(self, for_update: bool) -> FetchedValue: 

6540 return self 

6541 

6542 @util.deprecated( 

6543 "1.4", 

6544 "The :meth:`_schema.Identity.copy` method is deprecated " 

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

6546 ) 

6547 def copy(self, **kw: Any) -> Identity: 

6548 return self._copy(**kw) 

6549 

6550 def _copy(self, **kw: Any) -> Identity: 

6551 i = Identity(**self._as_dict(), **self.dialect_kwargs) 

6552 

6553 return self._schema_item_copy(i) 

6554 

6555 def _as_dict(self) -> Dict[str, Any]: 

6556 return { 

6557 # always=None means something different than always=False 

6558 "always": self.always, 

6559 **super()._as_dict(), 

6560 }