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

1683 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 Mapping 

48from typing import NoReturn 

49from typing import Optional 

50from typing import overload 

51from typing import Protocol 

52from typing import Sequence as _typing_Sequence 

53from typing import Set 

54from typing import Tuple 

55from typing import TYPE_CHECKING 

56from typing import TypedDict 

57from typing import TypeVar 

58from typing import Union 

59 

60from . import coercions 

61from . import ddl 

62from . import roles 

63from . import type_api 

64from . import visitors 

65from .base import _DefaultDescriptionTuple 

66from .base import _NoArg 

67from .base import _NoneName 

68from .base import _SentinelColumnCharacterization 

69from .base import _SentinelDefaultCharacterization 

70from .base import DedupeColumnCollection 

71from .base import DialectKWArgs 

72from .base import Executable 

73from .base import SchemaEventTarget as SchemaEventTarget 

74from .base import SchemaVisitable as SchemaVisitable 

75from .coercions import _document_text_coercion 

76from .elements import ClauseElement 

77from .elements import ColumnClause 

78from .elements import ColumnElement 

79from .elements import quoted_name 

80from .elements import TextClause 

81from .selectable import TableClause 

82from .type_api import to_instance 

83from .visitors import ExternallyTraversible 

84from .. import event 

85from .. import exc 

86from .. import inspection 

87from .. import util 

88from ..util import HasMemoized 

89from ..util.typing import Literal 

90from ..util.typing import Self 

91from ..util.typing import TypeGuard 

92 

93if typing.TYPE_CHECKING: 

94 from ._typing import _AutoIncrementType 

95 from ._typing import _CreateDropBind 

96 from ._typing import _DDLColumnArgument 

97 from ._typing import _DDLColumnReferenceArgument 

98 from ._typing import _InfoType 

99 from ._typing import _TextCoercedExpressionArgument 

100 from ._typing import _TypeEngineArgument 

101 from .base import ColumnSet 

102 from .base import ReadOnlyColumnCollection 

103 from .compiler import DDLCompiler 

104 from .elements import BindParameter 

105 from .elements import KeyedColumnElement 

106 from .functions import Function 

107 from .type_api import TypeEngine 

108 from .visitors import anon_map 

109 from ..engine import Connection 

110 from ..engine import Engine 

111 from ..engine.interfaces import _CoreMultiExecuteParams 

112 from ..engine.interfaces import CoreExecuteOptionsParameter 

113 from ..engine.interfaces import ExecutionContext 

114 from ..engine.reflection import _ReflectionInfo 

115 from ..sql.selectable import FromClause 

116 

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

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

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

120 

121 

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

123 

124_ServerDefaultArgument = Union[ 

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

126] 

127 

128_ServerOnUpdateArgument = _ServerDefaultArgument 

129 

130 

131class SchemaConst(Enum): 

132 RETAIN_SCHEMA = 1 

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

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

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

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

137 

138 """ 

139 

140 BLANK_SCHEMA = 2 

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

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

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

144 

145 .. seealso:: 

146 

147 :paramref:`_schema.MetaData.schema` 

148 

149 :paramref:`_schema.Table.schema` 

150 

151 :paramref:`.Sequence.schema` 

152 

153 """ 

154 

155 NULL_UNSPECIFIED = 3 

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

157 

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

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

160 on some backends such as SQL Server. 

161 

162 """ 

163 

164 

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

166 SchemaConst.RETAIN_SCHEMA 

167) 

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

169 SchemaConst.BLANK_SCHEMA 

170) 

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

172 SchemaConst.NULL_UNSPECIFIED 

173) 

174 

175 

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

177 if schema is None: 

178 return name 

179 else: 

180 return schema + "." + name 

181 

182 

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

184# break an import cycle 

185def _copy_expression( 

186 expression: ColumnElement[Any], 

187 source_table: Optional[Table], 

188 target_table: Optional[Table], 

189) -> ColumnElement[Any]: 

190 if source_table is None or target_table is None: 

191 return expression 

192 

193 fixed_source_table = source_table 

194 fixed_target_table = target_table 

195 

196 def replace( 

197 element: ExternallyTraversible, **kw: Any 

198 ) -> Optional[ExternallyTraversible]: 

199 if ( 

200 isinstance(element, Column) 

201 and element.table is fixed_source_table 

202 and element.key in fixed_source_table.c 

203 ): 

204 return fixed_target_table.c[element.key] 

205 else: 

206 return None 

207 

208 return cast( 

209 ColumnElement[Any], 

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

211 ) 

212 

213 

214@inspection._self_inspects 

215class SchemaItem(SchemaVisitable): 

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

217 

218 __visit_name__ = "schema_item" 

219 

220 create_drop_stringify_dialect = "default" 

221 

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

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

224 for item in args: 

225 if item is not None: 

226 try: 

227 spwd = item._set_parent_with_dispatch 

228 except AttributeError as err: 

229 raise exc.ArgumentError( 

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

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

232 ) from err 

233 else: 

234 spwd(self, **kw) 

235 

236 def __repr__(self) -> str: 

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

238 

239 @util.memoized_property 

240 def info(self) -> _InfoType: 

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

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

243 

244 The dictionary is automatically generated when first accessed. 

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

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

247 

248 """ 

249 return {} 

250 

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

252 if "info" in self.__dict__: 

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

254 schema_item.dispatch._update(self.dispatch) 

255 return schema_item 

256 

257 _use_schema_map = True 

258 

259 

260class HasConditionalDDL: 

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

262 method, allowing for conditional rendering of DDL. 

263 

264 Currently applies to constraints and indexes. 

265 

266 .. versionadded:: 2.0 

267 

268 

269 """ 

270 

271 _ddl_if: Optional[ddl.DDLIf] = None 

272 

273 def ddl_if( 

274 self, 

275 dialect: Optional[str] = None, 

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

277 state: Optional[Any] = None, 

278 ) -> Self: 

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

280 

281 These rules work in a similar manner to the 

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

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

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

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

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

287 constructs. 

288 

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

290 to indicate multiple dialect types. 

291 

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

293 as that described in 

294 :paramref:`.ExecutableDDLElement.execute_if.callable_`. 

295 

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

297 callable, if present. 

298 

299 .. versionadded:: 2.0 

300 

301 .. seealso:: 

302 

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

304 

305 

306 """ 

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

308 return self 

309 

310 

311class HasSchemaAttr(SchemaItem): 

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

313 

314 schema: Optional[str] 

315 

316 

317class Table( 

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

319): 

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

321 

322 e.g.:: 

323 

324 mytable = Table( 

325 "mytable", 

326 metadata, 

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

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

329 ) 

330 

331 The :class:`_schema.Table` 

332 object constructs a unique instance of itself based 

333 on its name and optional schema name within the given 

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

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

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

337 object - in this way 

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

339 

340 .. seealso:: 

341 

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

343 

344 """ 

345 

346 __visit_name__ = "table" 

347 

348 if TYPE_CHECKING: 

349 

350 @util.ro_non_memoized_property 

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

352 

353 @util.ro_non_memoized_property 

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

355 

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

357 

358 _sentinel_column: Optional[Column[Any]] 

359 

360 constraints: Set[Constraint] 

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

362 this :class:`_schema.Table`. 

363 

364 Includes :class:`_schema.PrimaryKeyConstraint`, 

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

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

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

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

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

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

371 :class:`_schema.Table`. 

372 

373 .. seealso:: 

374 

375 :attr:`_schema.Table.constraints` 

376 

377 :attr:`_schema.Table.primary_key` 

378 

379 :attr:`_schema.Table.foreign_key_constraints` 

380 

381 :attr:`_schema.Table.indexes` 

382 

383 :class:`_reflection.Inspector` 

384 

385 

386 """ 

387 

388 indexes: Set[Index] 

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

390 :class:`_schema.Table`. 

391 

392 .. seealso:: 

393 

394 :meth:`_reflection.Inspector.get_indexes` 

395 

396 """ 

397 

398 if TYPE_CHECKING: 

399 

400 @util.ro_non_memoized_property 

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

402 

403 @util.ro_non_memoized_property 

404 def exported_columns( 

405 self, 

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

407 

408 @util.ro_non_memoized_property 

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

410 

411 def _gen_cache_key( 

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

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

414 if self._annotations: 

415 return (self,) + self._annotations_cache_key 

416 else: 

417 return (self,) 

418 

419 if not typing.TYPE_CHECKING: 

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

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

422 # __new__. apply typing to the __init__ method normally 

423 @util.deprecated_params( 

424 mustexist=( 

425 "1.4", 

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

427 ), 

428 ) 

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

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

431 

432 @classmethod 

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

434 if not args and not kw: 

435 # python3k pickle seems to call this 

436 return object.__new__(cls) 

437 

438 try: 

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

440 except IndexError: 

441 raise TypeError( 

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

443 "arguments 'name' and 'metadata'" 

444 ) 

445 

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

447 if schema is None: 

448 schema = metadata.schema 

449 elif schema is BLANK_SCHEMA: 

450 schema = None 

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

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

453 

454 if keep_existing and extend_existing: 

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

456 raise exc.ArgumentError(msg) 

457 

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

459 key = _get_table_key(name, schema) 

460 if key in metadata.tables: 

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

462 raise exc.InvalidRequestError( 

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

464 "instance. Specify 'extend_existing=True' " 

465 "to redefine " 

466 "options and columns on an " 

467 "existing Table object." 

468 ) 

469 table = metadata.tables[key] 

470 if extend_existing: 

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

472 return table 

473 else: 

474 if must_exist: 

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

476 table = object.__new__(cls) 

477 table.dispatch.before_parent_attach(table, metadata) 

478 metadata._add_table(name, schema, table) 

479 try: 

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

481 table.dispatch.after_parent_attach(table, metadata) 

482 return table 

483 except Exception: 

484 with util.safe_reraise(): 

485 metadata._remove_table(name, schema) 

486 

487 def __init__( 

488 self, 

489 name: str, 

490 metadata: MetaData, 

491 *args: SchemaItem, 

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

493 quote: Optional[bool] = None, 

494 quote_schema: Optional[bool] = None, 

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

496 autoload_replace: bool = True, 

497 keep_existing: bool = False, 

498 extend_existing: bool = False, 

499 resolve_fks: bool = True, 

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

501 implicit_returning: bool = True, 

502 comment: Optional[str] = None, 

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

504 listeners: Optional[ 

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

506 ] = None, 

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

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

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

510 # used by __new__ to bypass __init__ 

511 _no_init: bool = True, 

512 # dialect-specific keyword args 

513 **kw: Any, 

514 ) -> None: 

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

516 

517 

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

519 

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

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

522 within 

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

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

525 metadata, 

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

527 

528 Names which contain no upper case characters 

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

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

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

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

533 

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

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

536 construct to specify the name. 

537 

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

539 object which will contain this 

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

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

542 may be used to associate this table with a particular 

543 :class:`.Connection` or :class:`.Engine`. 

544 

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

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

547 objects contained within this 

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

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

550 :class:`.PrimaryKeyConstraint`, and 

551 :class:`_schema.ForeignKeyConstraint`. 

552 

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

554 :paramref:`_schema.Table.autoload_with` 

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

556 indicates 

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

558 :class:`_schema.Table` 

559 object should be replaced with columns of the same 

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

561 already present under existing names will be omitted from the 

562 reflection process. 

563 

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

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

566 that 

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

568 replace existing columns of the same name when 

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

570 

571 .. seealso:: 

572 

573 :paramref:`_schema.Table.autoload_with` 

574 

575 :paramref:`_schema.Table.extend_existing` 

576 

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

578 :class:`_engine.Connection` object, 

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

580 :func:`_sa.inspect` 

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

582 object will be reflected. 

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

584 for this table against the given engine or connection. 

585 

586 .. seealso:: 

587 

588 :ref:`metadata_reflection_toplevel` 

589 

590 :meth:`_events.DDLEvents.column_reflect` 

591 

592 :ref:`metadata_reflection_dbagnostic_types` 

593 

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

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

596 :class:`_schema.MetaData`, 

597 apply further arguments within the constructor to the existing 

598 :class:`_schema.Table`. 

599 

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

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

602 and the given name 

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

604 that is 

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

606 and 

607 this :class:`_schema.Table` 

608 specifies additional columns or other constructs 

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

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

611 is to specify what action should be taken when a 

612 :class:`_schema.Table` 

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

614 yet specifies 

615 additional constructs. 

616 

617 :paramref:`_schema.Table.extend_existing` 

618 will also work in conjunction 

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

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

621 of the same name is already present in the target 

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

623 objects 

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

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

626 and options of the same name. 

627 

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

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

630 :class:`_schema.Table` 

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

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

633 objects 

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

635 :class:`_schema.Column` 

636 named "y":: 

637 

638 Table( 

639 "mytable", 

640 metadata, 

641 Column("y", Integer), 

642 extend_existing=True, 

643 autoload_with=engine, 

644 ) 

645 

646 .. seealso:: 

647 

648 :paramref:`_schema.Table.autoload_with` 

649 

650 :paramref:`_schema.Table.autoload_replace` 

651 

652 :paramref:`_schema.Table.keep_existing` 

653 

654 

655 :param implicit_returning: True by default - indicates that 

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

657 server-generated values such as primary key values and 

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

659 

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

661 setting, except for some backend specific cases 

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

663 for one such example). 

664 

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

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

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

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

669 should be reflected. 

670 

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

672 objects 

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

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

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

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

677 objects are encountered; may be 

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

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

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

681 a 

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

683 :class:`_schema.Table` will 

684 resolve to that table normally. 

685 

686 .. seealso:: 

687 

688 :paramref:`.MetaData.reflect.resolve_fks` 

689 

690 

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

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

693 

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

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

696 further arguments within the constructor to the existing 

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

698 object as 

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

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

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

702 without any of the declarations (particularly constraints) 

703 being applied a second time. 

704 

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

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

707 and the given name 

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

709 that is 

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

711 and 

712 this :class:`_schema.Table` 

713 specifies additional columns or other constructs 

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

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

716 is to specify what action should be taken when a 

717 :class:`_schema.Table` 

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

719 yet specifies 

720 additional constructs. 

721 

722 .. seealso:: 

723 

724 :paramref:`_schema.Table.extend_existing` 

725 

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

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

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

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

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

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

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

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

734 

735 def listen_for_reflect(table, column_info): 

736 "handle the column reflection event" 

737 # ... 

738 

739 

740 t = Table( 

741 "sometable", 

742 autoload_with=engine, 

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

744 ) 

745 

746 .. seealso:: 

747 

748 :meth:`_events.DDLEvents.column_reflect` 

749 

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

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

752 an exception is raised. 

753 

754 :param prefixes: 

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

756 statement. They will be separated by spaces. 

757 

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

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

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

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

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

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

764 by the SQLAlchemy dialect. 

765 

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

767 case-insensitive behavior for table reflection; table reflection 

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

769 fashion. Case insensitive names are specified in SQLAlchemy only 

770 by stating the name with all lower case characters. 

771 

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

773 

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

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

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

777 

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

779 specifies its 

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

781 then that schema name will 

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

783 if the schema parameter here is set 

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

785 that 

786 would otherwise use the schema set on the owning 

787 :class:`_schema.MetaData`, 

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

789 

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

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

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

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

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

795 

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

797 creation. 

798 

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

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

801 See the documentation regarding an individual dialect at 

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

803 

804 """ # noqa: E501 

805 if _no_init: 

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

807 # __new__ has a specific place that __init__ is called 

808 return 

809 

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

811 self.metadata = metadata 

812 

813 if schema is None: 

814 self.schema = metadata.schema 

815 elif schema is BLANK_SCHEMA: 

816 self.schema = None 

817 else: 

818 quote_schema = quote_schema 

819 assert isinstance(schema, str) 

820 self.schema = quoted_name(schema, quote_schema) 

821 

822 self._sentinel_column = None 

823 

824 self.indexes = set() 

825 self.constraints = set() 

826 PrimaryKeyConstraint( 

827 _implicit_generated=True 

828 )._set_parent_with_dispatch(self) 

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

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

831 if self.schema is not None: 

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

833 else: 

834 self.fullname = self.name 

835 

836 self.implicit_returning = implicit_returning 

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

838 

839 self.comment = comment 

840 

841 if info is not None: 

842 self.info = info 

843 

844 if listeners is not None: 

845 for evt, fn in listeners: 

846 event.listen(self, evt, fn) 

847 

848 self._prefixes = prefixes if prefixes else [] 

849 

850 self._extra_kwargs(**kw) 

851 

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

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

854 # circular foreign keys 

855 if autoload_with is not None: 

856 self._autoload( 

857 metadata, 

858 autoload_with, 

859 include_columns, 

860 _extend_on=_extend_on, 

861 _reflect_info=_reflect_info, 

862 resolve_fks=resolve_fks, 

863 ) 

864 

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

866 # allow user-overrides 

867 

868 self._init_items( 

869 *args, 

870 allow_replacements=extend_existing 

871 or keep_existing 

872 or autoload_with, 

873 all_names={}, 

874 ) 

875 

876 def _autoload( 

877 self, 

878 metadata: MetaData, 

879 autoload_with: Union[Engine, Connection], 

880 include_columns: Optional[Collection[str]], 

881 exclude_columns: Collection[str] = (), 

882 resolve_fks: bool = True, 

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

884 _reflect_info: _ReflectionInfo | None = None, 

885 ) -> None: 

886 insp = inspection.inspect(autoload_with) 

887 with insp._inspection_context() as conn_insp: 

888 conn_insp.reflect_table( 

889 self, 

890 include_columns, 

891 exclude_columns, 

892 resolve_fks, 

893 _extend_on=_extend_on, 

894 _reflect_info=_reflect_info, 

895 ) 

896 

897 @property 

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

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

900 order. 

901 

902 """ 

903 

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

905 

906 @property 

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

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

909 :class:`_schema.Table`. 

910 

911 This list is produced from the collection of 

912 :class:`_schema.ForeignKey` 

913 objects currently associated. 

914 

915 

916 .. seealso:: 

917 

918 :attr:`_schema.Table.constraints` 

919 

920 :attr:`_schema.Table.foreign_keys` 

921 

922 :attr:`_schema.Table.indexes` 

923 

924 """ 

925 return { 

926 fkc.constraint 

927 for fkc in self.foreign_keys 

928 if fkc.constraint is not None 

929 } 

930 

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

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

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

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

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

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

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

938 

939 # these arguments are only used with _init() 

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

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

942 

943 assert extend_existing 

944 assert not keep_existing 

945 

946 if schema and schema != self.schema: 

947 raise exc.ArgumentError( 

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

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

950 ) 

951 

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

953 if include_columns is not None: 

954 for c in self.c: 

955 if c.name not in include_columns: 

956 self._columns.remove(c) 

957 

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

959 

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

961 if key in kwargs: 

962 raise exc.ArgumentError( 

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

964 ) 

965 

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

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

968 self.implicit_returning = kwargs.pop( 

969 "implicit_returning", self.implicit_returning 

970 ) 

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

972 

973 exclude_columns: _typing_Sequence[str] 

974 

975 if autoload: 

976 if not autoload_replace: 

977 # don't replace columns already present. 

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

979 # have simple de-duping for unnamed constraints. 

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

981 else: 

982 exclude_columns = () 

983 self._autoload( 

984 self.metadata, 

985 autoload_with, 

986 include_columns, 

987 exclude_columns, 

988 resolve_fks, 

989 _extend_on=_extend_on, 

990 _reflect_info=_reflect_info, 

991 ) 

992 

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

994 self._extra_kwargs(**kwargs) 

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

996 

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

998 self._validate_dialect_kwargs(kwargs) 

999 

1000 def _init_collections(self) -> None: 

1001 pass 

1002 

1003 def _reset_exported(self) -> None: 

1004 pass 

1005 

1006 @util.ro_non_memoized_property 

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

1008 return self.primary_key._autoincrement_column 

1009 

1010 @util.ro_memoized_property 

1011 def _sentinel_column_characteristics( 

1012 self, 

1013 ) -> _SentinelColumnCharacterization: 

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

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

1016 "insert sentinel" for an INSERT statement. 

1017 

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

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

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

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

1022 dialect. 

1023 

1024 .. versionadded:: 2.0.10 

1025 

1026 """ 

1027 

1028 sentinel_is_explicit = False 

1029 sentinel_is_autoinc = False 

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

1031 

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

1033 explicit_sentinel_col = self._sentinel_column 

1034 

1035 if explicit_sentinel_col is not None: 

1036 the_sentinel = (explicit_sentinel_col,) 

1037 sentinel_is_explicit = True 

1038 

1039 autoinc_col = self._autoincrement_column 

1040 if sentinel_is_explicit and explicit_sentinel_col is autoinc_col: 

1041 assert autoinc_col is not None 

1042 sentinel_is_autoinc = True 

1043 elif explicit_sentinel_col is None and autoinc_col is not None: 

1044 the_sentinel = (autoinc_col,) 

1045 sentinel_is_autoinc = True 

1046 

1047 default_characterization = _SentinelDefaultCharacterization.UNKNOWN 

1048 

1049 if the_sentinel: 

1050 the_sentinel_zero = the_sentinel[0] 

1051 if the_sentinel_zero.identity: 

1052 if the_sentinel_zero.identity._increment_is_negative: 

1053 if sentinel_is_explicit: 

1054 raise exc.InvalidRequestError( 

1055 "Can't use IDENTITY default with negative " 

1056 "increment as an explicit sentinel column" 

1057 ) 

1058 else: 

1059 if sentinel_is_autoinc: 

1060 autoinc_col = None 

1061 sentinel_is_autoinc = False 

1062 the_sentinel = None 

1063 else: 

1064 default_characterization = ( 

1065 _SentinelDefaultCharacterization.IDENTITY 

1066 ) 

1067 elif ( 

1068 the_sentinel_zero.default is None 

1069 and the_sentinel_zero.server_default is None 

1070 ): 

1071 if the_sentinel_zero.nullable: 

1072 raise exc.InvalidRequestError( 

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

1074 "sentinel " 

1075 "column with no default generation function; it " 

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

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

1078 ) 

1079 default_characterization = ( 

1080 _SentinelDefaultCharacterization.NONE 

1081 ) 

1082 elif the_sentinel_zero.default is not None: 

1083 if the_sentinel_zero.default.is_sentinel: 

1084 default_characterization = ( 

1085 _SentinelDefaultCharacterization.SENTINEL_DEFAULT 

1086 ) 

1087 elif default_is_sequence(the_sentinel_zero.default): 

1088 if the_sentinel_zero.default._increment_is_negative: 

1089 if sentinel_is_explicit: 

1090 raise exc.InvalidRequestError( 

1091 "Can't use SEQUENCE default with negative " 

1092 "increment as an explicit sentinel column" 

1093 ) 

1094 else: 

1095 if sentinel_is_autoinc: 

1096 autoinc_col = None 

1097 sentinel_is_autoinc = False 

1098 the_sentinel = None 

1099 

1100 default_characterization = ( 

1101 _SentinelDefaultCharacterization.SEQUENCE 

1102 ) 

1103 elif the_sentinel_zero.default.is_callable: 

1104 default_characterization = ( 

1105 _SentinelDefaultCharacterization.CLIENTSIDE 

1106 ) 

1107 elif the_sentinel_zero.server_default is not None: 

1108 if sentinel_is_explicit: 

1109 raise exc.InvalidRequestError( 

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

1111 "because it uses an explicit server side default " 

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

1113 ) 

1114 

1115 default_characterization = ( 

1116 _SentinelDefaultCharacterization.SERVERSIDE 

1117 ) 

1118 

1119 if the_sentinel is None and self.primary_key: 

1120 assert autoinc_col is None 

1121 

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

1123 # client side 

1124 for _pkc in self.primary_key: 

1125 if _pkc.server_default is not None or ( 

1126 _pkc.default and not _pkc.default.is_callable 

1127 ): 

1128 break 

1129 else: 

1130 the_sentinel = tuple(self.primary_key) 

1131 default_characterization = ( 

1132 _SentinelDefaultCharacterization.CLIENTSIDE 

1133 ) 

1134 

1135 return _SentinelColumnCharacterization( 

1136 the_sentinel, 

1137 sentinel_is_explicit, 

1138 sentinel_is_autoinc, 

1139 default_characterization, 

1140 ) 

1141 

1142 @property 

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

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

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

1146 

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

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

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

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

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

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

1153 "autoincrement" column. 

1154 

1155 .. versionadded:: 2.0.4 

1156 

1157 .. seealso:: 

1158 

1159 :paramref:`.Column.autoincrement` 

1160 

1161 """ 

1162 return self._autoincrement_column 

1163 

1164 @property 

1165 def key(self) -> str: 

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

1167 

1168 This value is used as the dictionary key within the 

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

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

1171 :attr:`_schema.Table.schema` 

1172 set; otherwise it is typically of the form 

1173 ``schemaname.tablename``. 

1174 

1175 """ 

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

1177 

1178 def __repr__(self) -> str: 

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

1180 [repr(self.name)] 

1181 + [repr(self.metadata)] 

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

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

1184 ) 

1185 

1186 def __str__(self) -> str: 

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

1188 

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

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

1191 

1192 This is another Table object which must be created 

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

1194 

1195 Usually, dependencies between tables are determined via 

1196 ForeignKey objects. However, for other situations that 

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

1198 this method can manually establish such a link. 

1199 

1200 """ 

1201 self._extra_dependencies.add(table) 

1202 

1203 def _insert_col_impl( 

1204 self, 

1205 column: ColumnClause[Any], 

1206 *, 

1207 index: Optional[int] = None, 

1208 replace_existing: bool = False, 

1209 ) -> None: 

1210 try: 

1211 column._set_parent_with_dispatch( 

1212 self, 

1213 allow_replacements=replace_existing, 

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

1215 index=index, 

1216 ) 

1217 except exc.DuplicateColumnError as de: 

1218 raise exc.DuplicateColumnError( 

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

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

1221 "existing column." 

1222 ) from de 

1223 

1224 def insert_column( 

1225 self, 

1226 column: ColumnClause[Any], 

1227 index: int, 

1228 *, 

1229 replace_existing: bool = False, 

1230 ) -> None: 

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

1232 a specific position. 

1233 

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

1235 the index position can be controlled using the 

1236 :paramref:`.Table.insert_column.index` 

1237 parameter. 

1238 

1239 :param replace_existing: 

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

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

1242 

1243 .. versionadded:: 2.1 

1244 

1245 """ 

1246 self._insert_col_impl( 

1247 column, index=index, replace_existing=replace_existing 

1248 ) 

1249 

1250 def append_column( 

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

1252 ) -> None: 

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

1254 

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

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

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

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

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

1260 construct. 

1261 

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

1263 as it exists within any underlying database, assuming that 

1264 table has already been created in the database. Relational 

1265 databases support the addition of columns to existing tables 

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

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

1268 the newly added column. 

1269 

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

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

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

1273 version of sqlalchemy will instead rise a warning. 

1274 

1275 .. versionadded:: 1.4.0 

1276 

1277 .. seealso:: 

1278 

1279 :meth:`.Table.insert_column` 

1280 

1281 """ 

1282 self._insert_col_impl(column, replace_existing=replace_existing) 

1283 

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

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

1286 :class:`_schema.Table`. 

1287 

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

1289 future CREATE TABLE statement, assuming specific DDL creation 

1290 events have not been associated with the given 

1291 :class:`_schema.Constraint` object. 

1292 

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

1294 relational database automatically, for a table that already exists 

1295 in the database. To add a constraint to an 

1296 existing relational database table, the SQL ALTER command must 

1297 be used. SQLAlchemy also provides the 

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

1299 invoked as an executable clause. 

1300 

1301 """ 

1302 

1303 constraint._set_parent_with_dispatch(self) 

1304 

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

1306 metadata = parent 

1307 assert isinstance(metadata, MetaData) 

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

1309 self.metadata = metadata 

1310 

1311 def create(self, bind: _CreateDropBind, checkfirst: bool = False) -> None: 

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

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

1314 :class:`.Connection` or :class:`.Engine` 

1315 for connectivity. 

1316 

1317 .. seealso:: 

1318 

1319 :meth:`_schema.MetaData.create_all`. 

1320 

1321 """ 

1322 

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

1324 

1325 def drop(self, bind: _CreateDropBind, checkfirst: bool = False) -> None: 

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

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

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

1329 

1330 .. seealso:: 

1331 

1332 :meth:`_schema.MetaData.drop_all`. 

1333 

1334 """ 

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

1336 

1337 @util.deprecated( 

1338 "1.4", 

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

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

1341 ) 

1342 def tometadata( 

1343 self, 

1344 metadata: MetaData, 

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

1346 referred_schema_fn: Optional[ 

1347 Callable[ 

1348 [Table, Optional[str], ForeignKeyConstraint, Optional[str]], 

1349 Optional[str], 

1350 ] 

1351 ] = None, 

1352 name: Optional[str] = None, 

1353 ) -> Table: 

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

1355 associated with a different 

1356 :class:`_schema.MetaData`. 

1357 

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

1359 

1360 """ 

1361 return self.to_metadata( 

1362 metadata, 

1363 schema=schema, 

1364 referred_schema_fn=referred_schema_fn, 

1365 name=name, 

1366 ) 

1367 

1368 def to_metadata( 

1369 self, 

1370 metadata: MetaData, 

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

1372 referred_schema_fn: Optional[ 

1373 Callable[ 

1374 [Table, Optional[str], ForeignKeyConstraint, Optional[str]], 

1375 Optional[str], 

1376 ] 

1377 ] = None, 

1378 name: Optional[str] = None, 

1379 ) -> Table: 

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

1381 different :class:`_schema.MetaData`. 

1382 

1383 E.g.:: 

1384 

1385 m1 = MetaData() 

1386 

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

1388 

1389 m2 = MetaData() 

1390 user_copy = user.to_metadata(m2) 

1391 

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

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

1394 

1395 

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

1397 into which the 

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

1399 

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

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

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

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

1404 :class:`_schema.Table` 

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

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

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

1408 unless 

1409 set explicitly:: 

1410 

1411 m2 = MetaData(schema="newschema") 

1412 

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

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

1415 

1416 m3 = MetaData() # schema defaults to None 

1417 

1418 # user_copy_two will have None as the schema name 

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

1420 

1421 :param referred_schema_fn: optional callable which can be supplied 

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

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

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

1425 target schema that we are changing to, the 

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

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

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

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

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

1431 

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

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

1434 symbols. 

1435 

1436 E.g.:: 

1437 

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

1439 if referred_schema == "base_tables": 

1440 return referred_schema 

1441 else: 

1442 return to_schema 

1443 

1444 

1445 new_table = table.to_metadata( 

1446 m2, schema="alt_schema", referred_schema_fn=referred_schema_fn 

1447 ) 

1448 

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

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

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

1452 :class:`_schema.MetaData` target 

1453 with a new name. 

1454 

1455 """ # noqa: E501 

1456 if name is None: 

1457 name = self.name 

1458 

1459 actual_schema: Optional[str] 

1460 

1461 if schema is RETAIN_SCHEMA: 

1462 actual_schema = self.schema 

1463 elif schema is None: 

1464 actual_schema = metadata.schema 

1465 else: 

1466 actual_schema = schema 

1467 key = _get_table_key(name, actual_schema) 

1468 if key in metadata.tables: 

1469 util.warn( 

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

1471 "MetaData - not copying." 

1472 ) 

1473 return metadata.tables[key] 

1474 

1475 args = [] 

1476 for col in self.columns: 

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

1478 table = Table( 

1479 name, 

1480 metadata, 

1481 schema=actual_schema, 

1482 comment=self.comment, 

1483 *args, 

1484 **self.kwargs, 

1485 ) 

1486 for const in self.constraints: 

1487 if isinstance(const, ForeignKeyConstraint): 

1488 referred_schema = const._referred_schema 

1489 if referred_schema_fn: 

1490 fk_constraint_schema = referred_schema_fn( 

1491 self, actual_schema, const, referred_schema 

1492 ) 

1493 else: 

1494 fk_constraint_schema = ( 

1495 actual_schema 

1496 if referred_schema == self.schema 

1497 else None 

1498 ) 

1499 table.append_constraint( 

1500 const._copy( 

1501 schema=fk_constraint_schema, target_table=table 

1502 ) 

1503 ) 

1504 elif not const._type_bound: 

1505 # skip unique constraints that would be generated 

1506 # by the 'unique' flag on Column 

1507 if const._column_flag: 

1508 continue 

1509 

1510 table.append_constraint( 

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

1512 ) 

1513 for index in self.indexes: 

1514 # skip indexes that would be generated 

1515 # by the 'index' flag on Column 

1516 if index._column_flag: 

1517 continue 

1518 Index( 

1519 index.name, 

1520 unique=index.unique, 

1521 *[ 

1522 _copy_expression(expr, self, table) 

1523 for expr in index._table_bound_expressions 

1524 ], 

1525 _table=table, 

1526 **index.kwargs, 

1527 ) 

1528 return self._schema_item_copy(table) 

1529 

1530 

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

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

1533 

1534 __visit_name__ = "column" 

1535 

1536 inherit_cache = True 

1537 key: str 

1538 

1539 server_default: Optional[FetchedValue] 

1540 

1541 def __init__( 

1542 self, 

1543 __name_pos: Optional[ 

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

1545 ] = None, 

1546 __type_pos: Optional[ 

1547 Union[_TypeEngineArgument[_T], SchemaEventTarget] 

1548 ] = None, 

1549 /, 

1550 *args: SchemaEventTarget, 

1551 name: Optional[str] = None, 

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

1553 autoincrement: _AutoIncrementType = "auto", 

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

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

1556 doc: Optional[str] = None, 

1557 key: Optional[str] = None, 

1558 index: Optional[bool] = None, 

1559 unique: Optional[bool] = None, 

1560 info: Optional[_InfoType] = None, 

1561 nullable: Optional[ 

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

1563 ] = SchemaConst.NULL_UNSPECIFIED, 

1564 onupdate: Optional[Any] = None, 

1565 primary_key: bool = False, 

1566 server_default: Optional[_ServerDefaultArgument] = None, 

1567 server_onupdate: Optional[_ServerOnUpdateArgument] = None, 

1568 quote: Optional[bool] = None, 

1569 system: bool = False, 

1570 comment: Optional[str] = None, 

1571 insert_sentinel: bool = False, 

1572 _omit_from_statements: bool = False, 

1573 _proxies: Optional[Any] = None, 

1574 **dialect_kwargs: Any, 

1575 ): 

1576 r""" 

1577 Construct a new ``Column`` object. 

1578 

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

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

1581 via keyword. 

1582 

1583 Names which contain no upper case characters 

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

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

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

1587 behavior applies even for databases which standardize upper 

1588 case names as case insensitive such as Oracle Database. 

1589 

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

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

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

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

1594 

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

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

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

1598 as well, e.g.:: 

1599 

1600 # use a type with arguments 

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

1602 

1603 # use no arguments 

1604 Column("level", Integer) 

1605 

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

1607 or specified by keyword. 

1608 

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

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

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

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

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

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

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

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

1617 

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

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

1620 as options to the column. These include instances of 

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

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

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

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

1625 ``default`` and ``unique``. 

1626 

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

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

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

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

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

1632 will be considered when INSERT statements are compiled and 

1633 executed. 

1634 

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

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

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

1638 default constructs indicated should receive auto increment semantics 

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

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

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

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

1643 key columns, see below). 

1644 

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

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

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

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

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

1650 database: 

1651 

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

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

1654 no other 

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

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

1657 will imply that database-specific keywords such as PostgreSQL 

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

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

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

1661 backends alway needs an explicit construct such as 

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

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

1664 be produced in the database. 

1665 

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

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

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

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

1670 value automatically for this column, which will be accessible 

1671 after the statement is invoked via the 

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

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

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

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

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

1677 behavior takes place regardless of what DDL constructs are 

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

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

1680 above. 

1681 

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

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

1684 have autoincrement semantics, though note that only one column 

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

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

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

1688 however note that not all dialects can accommodate all styles 

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

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

1691 datatype of INTEGER in order to disable auto increment semantics 

1692 for that column. 

1693 

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

1695 

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

1697 

1698 * Part of the primary key 

1699 

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

1701 unless 

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

1703 

1704 # turn on autoincrement for this column despite 

1705 # the ForeignKey() 

1706 Column( 

1707 "id", 

1708 ForeignKey("other.id"), 

1709 primary_key=True, 

1710 autoincrement="ignore_fk", 

1711 ) 

1712 

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

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

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

1716 

1717 The setting has these effects on columns that meet the 

1718 above criteria: 

1719 

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

1721 a default generating construct supported by the backend such as 

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

1723 keywords intended to signify this column as an 

1724 "autoincrement" column for specific backends. Behavior for 

1725 primary SQLAlchemy dialects includes: 

1726 

1727 * AUTO INCREMENT on MySQL and MariaDB 

1728 * SERIAL on PostgreSQL 

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

1730 :class:`.Identity` construct as the 

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

1732 construct. 

1733 * SQLite - SQLite integer primary key columns are implicitly 

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

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

1736 is not included as this is unnecessary and not recommended 

1737 by the database vendor. See the section 

1738 :ref:`sqlite_autoincrement` for more background. 

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

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

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

1742 construct may also be used). 

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

1744 for details on their specific behaviors. 

1745 

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

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

1748 modifier, newly generated primary key values for this column 

1749 will be automatically retrieved upon statement execution 

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

1751 

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

1753 (see 

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

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

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

1757 construct when rendering an INSERT statement, and then retrieving 

1758 the newly generated primary key values after execution 

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

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

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

1762 explicitly before the INSERT statement takes place so that the 

1763 newly generated primary key value is available to the client 

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

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

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

1767 INSERT statement is invoked to retrieve the newly generated 

1768 primary key value. 

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

1770 for details on their specific behaviors. 

1771 

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

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

1774 retrieving behaviors are generally disabled, however there may 

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

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

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

1778 may not yet be well covered in documentation. 

1779 

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

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

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

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

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

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

1786 structure of the argument. 

1787 

1788 Contrast this argument to 

1789 :paramref:`_schema.Column.server_default` 

1790 which creates a default generator on the database side. 

1791 

1792 .. seealso:: 

1793 

1794 :ref:`metadata_defaults_toplevel` 

1795 

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

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

1798 

1799 .. versionadded:: 2.0.31 

1800 

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

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

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

1804 :paramref:`_schema.Column.comment` 

1805 parameter for this purpose. 

1806 

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

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

1809 When a key is provided, 

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

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

1812 is used only when rendering SQL. 

1813 

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

1815 construct will be automatically generated for this 

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

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

1818 create operation is invoked. 

1819 

1820 Using this flag is equivalent to making use of the 

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

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

1823 

1824 Table( 

1825 "some_table", 

1826 metadata, 

1827 Column("x", Integer), 

1828 Index("ix_some_table_x", "x"), 

1829 ) 

1830 

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

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

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

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

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

1836 DDL instruction instead of "CREATE INDEX". 

1837 

1838 The name of the index is generated using the 

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

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

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

1842 

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

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

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

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

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

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

1849 indexes that use a specific name. 

1850 

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

1852 :class:`_schema.Column` 

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

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

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

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

1857 

1858 .. seealso:: 

1859 

1860 :ref:`schema_indexes` 

1861 

1862 :ref:`constraint_naming_conventions` 

1863 

1864 :paramref:`_schema.Column.unique` 

1865 

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

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

1868 

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

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

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

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

1873 where "NULL" may render explicitly. 

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

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

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

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

1878 

1879 .. note:: 

1880 

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

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

1883 PostgreSQL database allows nullable identity column by 

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

1885 

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

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

1888 default value to be applied to the column within UPDATE 

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

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

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

1892 ``for_update=True``. 

1893 

1894 .. seealso:: 

1895 

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

1897 

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

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

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

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

1902 :class:`.PrimaryKeyConstraint` object. 

1903 

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

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

1906 the DDL DEFAULT value for the column. 

1907 

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

1909 

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

1911 

1912 will render: 

1913 

1914 .. sourcecode:: sql 

1915 

1916 x TEXT DEFAULT 'val' 

1917 

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

1919 rendered as-is, without quotes:: 

1920 

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

1922 

1923 will render: 

1924 

1925 .. sourcecode:: sql 

1926 

1927 y DATETIME DEFAULT NOW() 

1928 

1929 Strings and text() will be converted into a 

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

1931 

1932 This parameter can also accept complex combinations of contextually 

1933 valid SQLAlchemy expressions or constructs:: 

1934 

1935 from sqlalchemy import create_engine 

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

1937 from sqlalchemy.dialects.postgresql import array 

1938 

1939 engine = create_engine( 

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

1941 ) 

1942 metadata_obj = MetaData() 

1943 tbl = Table( 

1944 "foo", 

1945 metadata_obj, 

1946 Column( 

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

1948 ), 

1949 ) 

1950 metadata_obj.create_all(engine) 

1951 

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

1953 

1954 .. sourcecode:: sql 

1955 

1956 CREATE TABLE foo ( 

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

1958 ) 

1959 

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

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

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

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

1964 to the database, such as via a trigger. 

1965 

1966 .. seealso:: 

1967 

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

1969 defaults 

1970 

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

1972 representing a database-side default generation function, 

1973 such as a trigger. This 

1974 indicates to SQLAlchemy that a newly generated value will be 

1975 available after updates. This construct does not actually 

1976 implement any kind of generation function within the database, 

1977 which instead must be specified separately. 

1978 

1979 

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

1981 "ON UPDATE CURRENT_TIMESTAMP()" clause. See 

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

1983 produce this clause. 

1984 

1985 .. seealso:: 

1986 

1987 :ref:`triggered_columns` 

1988 

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

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

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

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

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

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

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

1996 

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

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

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

2000 construct will be automatically generated for this 

2001 :class:`_schema.Column`, 

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

2003 to this column being included 

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

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

2006 

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

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

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

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

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

2012 is generated. See the documentation for 

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

2014 

2015 Using this flag is equivalent to making use of the 

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

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

2018 

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

2020 

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

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

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

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

2025 construct will be emitted as unnamed, which typically invokes 

2026 a database-specific naming convention to take place. 

2027 

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

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

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

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

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

2033 constraints that use a specific name. 

2034 

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

2036 :class:`_schema.Column` 

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

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

2039 indexes and unique constraints that may involve this column, 

2040 view the 

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

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

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

2044 :meth:`_reflection.Inspector.get_unique_constraints` 

2045 

2046 .. seealso:: 

2047 

2048 :ref:`schema_unique_constraint` 

2049 

2050 :ref:`constraint_naming_conventions` 

2051 

2052 :paramref:`_schema.Column.index` 

2053 

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

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

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

2057 ``CREATE TABLE`` statement. 

2058 

2059 For more elaborate scenarios where columns should be 

2060 conditionally rendered differently on different backends, 

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

2062 

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

2064 table creation. 

2065 

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

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

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

2069 otherwise have qualifying primary key configurations. 

2070 

2071 .. versionadded:: 2.0.10 

2072 

2073 .. seealso:: 

2074 

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

2076 sentinel columns 

2077 

2078 :ref:`engine_insertmanyvalues` 

2079 

2080 :ref:`engine_insertmanyvalues_sentinel_columns` 

2081 

2082 

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

2084 

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

2086 del args 

2087 

2088 if l_args: 

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

2090 if name is not None: 

2091 raise exc.ArgumentError( 

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

2093 ) 

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

2095 elif l_args[0] is None: 

2096 l_args.pop(0) 

2097 if l_args: 

2098 coltype = l_args[0] 

2099 

2100 if hasattr(coltype, "_sqla_type"): 

2101 if type_ is not None: 

2102 raise exc.ArgumentError( 

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

2104 ) 

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

2106 elif l_args[0] is None: 

2107 l_args.pop(0) 

2108 

2109 if name is not None: 

2110 name = quoted_name(name, quote) 

2111 elif quote is not None: 

2112 raise exc.ArgumentError( 

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

2114 ) 

2115 

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

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

2118 # dedicated "column" construct local to the ORM 

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

2120 

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

2122 self.primary_key = primary_key 

2123 self._insert_sentinel = insert_sentinel 

2124 self._omit_from_statements = _omit_from_statements 

2125 self._user_defined_nullable = udn = nullable 

2126 if udn is not NULL_UNSPECIFIED: 

2127 self.nullable = udn 

2128 else: 

2129 self.nullable = not primary_key 

2130 

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

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

2133 # Index or UniqueConstraint referring to this Column. 

2134 self.index = index 

2135 self.unique = unique 

2136 

2137 self.system = system 

2138 self.doc = doc 

2139 self.autoincrement: _AutoIncrementType = autoincrement 

2140 self.constraints = set() 

2141 self.foreign_keys = set() 

2142 self.comment = comment 

2143 self.computed = None 

2144 self.identity = None 

2145 

2146 # check if this Column is proxying another column 

2147 

2148 if _proxies is not None: 

2149 self._proxies = _proxies 

2150 else: 

2151 # otherwise, add DDL-related events 

2152 self._set_type(self.type) 

2153 

2154 if insert_default is not _NoArg.NO_ARG: 

2155 if default is not _NoArg.NO_ARG: 

2156 raise exc.ArgumentError( 

2157 "The 'default' and 'insert_default' parameters " 

2158 "of Column are mutually exclusive" 

2159 ) 

2160 resolved_default = insert_default 

2161 elif default is not _NoArg.NO_ARG: 

2162 resolved_default = default 

2163 else: 

2164 resolved_default = None 

2165 

2166 if resolved_default is not None: 

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

2168 resolved_default = ColumnDefault(resolved_default) 

2169 

2170 self.default = resolved_default 

2171 l_args.append(resolved_default) 

2172 else: 

2173 self.default = None 

2174 

2175 if onupdate is not None: 

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

2177 onupdate = ColumnDefault(onupdate, for_update=True) 

2178 

2179 self.onupdate = onupdate 

2180 l_args.append(onupdate) 

2181 else: 

2182 self.onupdate = None 

2183 

2184 if server_default is not None: 

2185 if isinstance(server_default, FetchedValue): 

2186 server_default = server_default._as_for_update(False) 

2187 l_args.append(server_default) 

2188 else: 

2189 server_default = DefaultClause(server_default) 

2190 l_args.append(server_default) 

2191 self.server_default = server_default 

2192 

2193 if server_onupdate is not None: 

2194 if isinstance(server_onupdate, FetchedValue): 

2195 server_onupdate = server_onupdate._as_for_update(True) 

2196 l_args.append(server_onupdate) 

2197 else: 

2198 server_onupdate = DefaultClause( 

2199 server_onupdate, for_update=True 

2200 ) 

2201 l_args.append(server_onupdate) 

2202 self.server_onupdate = server_onupdate 

2203 

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

2205 

2206 util.set_creation_order(self) 

2207 

2208 if info is not None: 

2209 self.info = info 

2210 

2211 self._extra_kwargs(**dialect_kwargs) 

2212 

2213 table: Table 

2214 

2215 constraints: Set[Constraint] 

2216 

2217 foreign_keys: Set[ForeignKey] 

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

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

2220 

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

2222 :class:`_schema.ForeignKeyConstraint`. 

2223 

2224 .. seealso:: 

2225 

2226 :attr:`_schema.Table.foreign_keys` 

2227 

2228 """ 

2229 

2230 index: Optional[bool] 

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

2232 

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

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

2235 

2236 .. seealso:: 

2237 

2238 :attr:`_schema.Table.indexes` 

2239 """ 

2240 

2241 unique: Optional[bool] 

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

2243 

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

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

2246 :attr:`_schema.Table.constraints`. 

2247 

2248 .. seealso:: 

2249 

2250 :attr:`_schema.Table.indexes` 

2251 

2252 :attr:`_schema.Table.constraints`. 

2253 

2254 """ 

2255 

2256 computed: Optional[Computed] 

2257 

2258 identity: Optional[Identity] 

2259 

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

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

2262 

2263 self.type = type_ 

2264 if isinstance(self.type, SchemaEventTarget): 

2265 self.type._set_parent_with_dispatch(self) 

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

2267 if isinstance(impl, SchemaEventTarget): 

2268 impl._set_parent_with_dispatch(self) 

2269 

2270 @HasMemoized.memoized_attribute 

2271 def _default_description_tuple(self) -> _DefaultDescriptionTuple: 

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

2273 

2274 return _DefaultDescriptionTuple._from_column_default(self.default) 

2275 

2276 @HasMemoized.memoized_attribute 

2277 def _onupdate_description_tuple(self) -> _DefaultDescriptionTuple: 

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

2279 return _DefaultDescriptionTuple._from_column_default(self.onupdate) 

2280 

2281 @util.memoized_property 

2282 def _gen_static_annotations_cache_key(self) -> bool: 

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

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

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

2286 

2287 Added for #8790 

2288 

2289 """ 

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

2291 

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

2293 self._validate_dialect_kwargs(kwargs) 

2294 

2295 def __str__(self) -> str: 

2296 if self.name is None: 

2297 return "(no name)" 

2298 elif self.table is not None: 

2299 if self.table.named_with_column: 

2300 return self.table.description + "." + self.description 

2301 else: 

2302 return self.description 

2303 else: 

2304 return self.description 

2305 

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

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

2308 key.""" 

2309 

2310 for fk in self.foreign_keys: 

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

2312 return True 

2313 else: 

2314 return False 

2315 

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

2317 fk._set_parent_with_dispatch(self) 

2318 

2319 def __repr__(self) -> str: 

2320 kwarg = [] 

2321 if self.key != self.name: 

2322 kwarg.append("key") 

2323 if self.primary_key: 

2324 kwarg.append("primary_key") 

2325 if not self.nullable: 

2326 kwarg.append("nullable") 

2327 if self.onupdate: 

2328 kwarg.append("onupdate") 

2329 if self.default: 

2330 kwarg.append("default") 

2331 if self.server_default: 

2332 kwarg.append("server_default") 

2333 if self.comment: 

2334 kwarg.append("comment") 

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

2336 [repr(self.name)] 

2337 + [repr(self.type)] 

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

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

2340 + [ 

2341 ( 

2342 self.table is not None 

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

2344 or "table=None" 

2345 ) 

2346 ] 

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

2348 ) 

2349 

2350 def _set_parent( # type: ignore[override] 

2351 self, 

2352 parent: SchemaEventTarget, 

2353 *, 

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

2355 allow_replacements: bool, 

2356 index: Optional[int] = None, 

2357 **kw: Any, 

2358 ) -> None: 

2359 table = parent 

2360 assert isinstance(table, Table) 

2361 if not self.name: 

2362 raise exc.ArgumentError( 

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

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

2365 ) 

2366 

2367 self._reset_memoizations() 

2368 

2369 if self.key is None: 

2370 self.key = self.name 

2371 

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

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

2374 raise exc.ArgumentError( 

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

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

2377 ) 

2378 

2379 extra_remove = None 

2380 existing_col = None 

2381 conflicts_on = "" 

2382 

2383 if self.key in table._columns: 

2384 existing_col = table._columns[self.key] 

2385 if self.key == self.name: 

2386 conflicts_on = "name" 

2387 else: 

2388 conflicts_on = "key" 

2389 elif self.name in all_names: 

2390 existing_col = all_names[self.name] 

2391 extra_remove = {existing_col} 

2392 conflicts_on = "name" 

2393 

2394 if existing_col is not None: 

2395 if existing_col is not self: 

2396 if not allow_replacements: 

2397 raise exc.DuplicateColumnError( 

2398 f"A column with {conflicts_on} " 

2399 f"""'{ 

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

2401 }' """ 

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

2403 ) 

2404 for fk in existing_col.foreign_keys: 

2405 table.foreign_keys.remove(fk) 

2406 if fk.constraint in table.constraints: 

2407 # this might have been removed 

2408 # already, if it's a composite constraint 

2409 # and more than one col being replaced 

2410 table.constraints.remove(fk.constraint) 

2411 

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

2413 util.warn( 

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

2415 "being replaced with " 

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

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

2418 "reflection operation, specify autoload_replace=False to " 

2419 "prevent this replacement." 

2420 ) 

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

2422 all_names[self.name] = self 

2423 self.table = table 

2424 

2425 if self._insert_sentinel: 

2426 if self.table._sentinel_column is not None: 

2427 raise exc.ArgumentError( 

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

2429 ) 

2430 self.table._sentinel_column = self 

2431 

2432 if self.primary_key: 

2433 table.primary_key._replace(self) 

2434 elif self.key in table.primary_key: 

2435 raise exc.ArgumentError( 

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

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

2438 ) 

2439 

2440 if self.index: 

2441 if isinstance(self.index, str): 

2442 raise exc.ArgumentError( 

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

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

2445 "explicit Index object external to the Table." 

2446 ) 

2447 table.append_constraint( 

2448 Index( 

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

2450 ) 

2451 ) 

2452 

2453 elif self.unique: 

2454 if isinstance(self.unique, str): 

2455 raise exc.ArgumentError( 

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

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

2458 "specific name, append an explicit UniqueConstraint to " 

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

2460 "Index object external to the Table." 

2461 ) 

2462 table.append_constraint( 

2463 UniqueConstraint(self.key, _column_flag=True) 

2464 ) 

2465 

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

2467 

2468 if self.identity and ( 

2469 isinstance(self.default, Sequence) 

2470 or isinstance(self.onupdate, Sequence) 

2471 ): 

2472 raise exc.ArgumentError( 

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

2474 ) 

2475 

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

2477 fk_keys = [ 

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

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

2480 ] 

2481 for fk_key, link_to_name in fk_keys: 

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

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

2484 if fk.link_to_name is link_to_name: 

2485 fn(fk) 

2486 

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

2488 if self.table is not None: 

2489 fn(self, self.table) 

2490 else: 

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

2492 

2493 @util.deprecated( 

2494 "1.4", 

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

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

2497 ) 

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

2499 return self._copy(**kw) 

2500 

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

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

2503 

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

2505 

2506 """ 

2507 

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

2509 args: List[SchemaItem] = [ 

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

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

2512 

2513 # ticket #5276 

2514 column_kwargs = {} 

2515 for dialect_name in self.dialect_options: 

2516 dialect_options = self.dialect_options[dialect_name]._non_defaults 

2517 for ( 

2518 dialect_option_key, 

2519 dialect_option_value, 

2520 ) in dialect_options.items(): 

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

2522 dialect_option_value 

2523 ) 

2524 

2525 server_default = self.server_default 

2526 server_onupdate = self.server_onupdate 

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

2528 # TODO: likely should be copied in all cases 

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

2530 # .metadata as well 

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

2532 server_default = server_onupdate = None 

2533 

2534 type_ = self.type 

2535 if isinstance(type_, SchemaEventTarget): 

2536 type_ = type_.copy(**kw) 

2537 

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

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

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

2541 

2542 c = self._constructor( 

2543 name=self.name, 

2544 type_=type_, 

2545 key=self.key, 

2546 primary_key=self.primary_key, 

2547 unique=self.unique, 

2548 system=self.system, 

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

2550 index=self.index, 

2551 autoincrement=self.autoincrement, 

2552 default=self.default, 

2553 server_default=server_default, 

2554 onupdate=self.onupdate, 

2555 server_onupdate=server_onupdate, 

2556 doc=self.doc, 

2557 comment=self.comment, 

2558 _omit_from_statements=self._omit_from_statements, 

2559 insert_sentinel=self._insert_sentinel, 

2560 *args, 

2561 **column_kwargs, 

2562 ) 

2563 

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

2565 # ORM flipping the .nullable flag directly 

2566 c.nullable = self.nullable 

2567 c._user_defined_nullable = self._user_defined_nullable 

2568 

2569 return self._schema_item_copy(c) 

2570 

2571 def _merge( 

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

2573 ) -> None: 

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

2575 

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

2577 of fixes. 

2578 

2579 

2580 """ 

2581 

2582 if self.primary_key: 

2583 other.primary_key = True 

2584 

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

2586 other.autoincrement = self.autoincrement 

2587 

2588 if self.system: 

2589 other.system = self.system 

2590 

2591 if self.info: 

2592 other.info.update(self.info) 

2593 

2594 type_ = self.type 

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

2596 if isinstance(type_, SchemaEventTarget): 

2597 type_ = type_.copy() 

2598 

2599 other.type = type_ 

2600 

2601 if isinstance(type_, SchemaEventTarget): 

2602 type_._set_parent_with_dispatch(other) 

2603 

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

2605 if isinstance(impl, SchemaEventTarget): 

2606 impl._set_parent_with_dispatch(other) 

2607 

2608 if ( 

2609 self._user_defined_nullable is not NULL_UNSPECIFIED 

2610 and other._user_defined_nullable is NULL_UNSPECIFIED 

2611 ): 

2612 other.nullable = self.nullable 

2613 other._user_defined_nullable = self._user_defined_nullable 

2614 

2615 if ( 

2616 not omit_defaults 

2617 and self.default is not None 

2618 and other.default is None 

2619 ): 

2620 new_default = self.default._copy() 

2621 new_default._set_parent(other) 

2622 

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

2624 new_server_default = self.server_default 

2625 if isinstance(new_server_default, FetchedValue): 

2626 new_server_default = new_server_default._copy() 

2627 new_server_default._set_parent(other) 

2628 else: 

2629 other.server_default = new_server_default 

2630 

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

2632 new_server_onupdate = self.server_onupdate 

2633 new_server_onupdate = new_server_onupdate._copy() 

2634 new_server_onupdate._set_parent(other) 

2635 

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

2637 new_onupdate = self.onupdate._copy() 

2638 new_onupdate._set_parent(other) 

2639 

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

2641 other.index = self.index 

2642 

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

2644 other.unique = self.unique 

2645 

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

2647 other.doc = self.doc 

2648 

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

2650 other.comment = self.comment 

2651 

2652 for const in self.constraints: 

2653 if not const._type_bound: 

2654 new_const = const._copy() 

2655 new_const._set_parent(other) 

2656 

2657 for fk in self.foreign_keys: 

2658 if not fk.constraint: 

2659 new_fk = fk._copy() 

2660 new_fk._set_parent(other) 

2661 

2662 def _make_proxy( 

2663 self, 

2664 selectable: FromClause, 

2665 primary_key: ColumnSet, 

2666 foreign_keys: Set[KeyedColumnElement[Any]], 

2667 name: Optional[str] = None, 

2668 key: Optional[str] = None, 

2669 name_is_truncatable: bool = False, 

2670 compound_select_cols: Optional[ 

2671 _typing_Sequence[ColumnElement[Any]] 

2672 ] = None, 

2673 **kw: Any, 

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

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

2676 

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

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

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

2680 information is not transferred. 

2681 

2682 """ 

2683 

2684 fk = [ 

2685 ForeignKey( 

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

2687 _unresolvable=col is None, 

2688 _constraint=f.constraint, 

2689 ) 

2690 for f, col in [ 

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

2692 for fk in self.foreign_keys 

2693 ] 

2694 ] 

2695 

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

2697 raise exc.InvalidRequestError( 

2698 "Cannot initialize a sub-selectable" 

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

2700 "been assigned." 

2701 ) 

2702 try: 

2703 c = self._constructor( 

2704 ( 

2705 coercions.expect( 

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

2707 ) 

2708 if name_is_truncatable 

2709 else (name or self.name) 

2710 ), 

2711 self.type, 

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

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

2714 primary_key=self.primary_key, 

2715 nullable=self.nullable, 

2716 _proxies=( 

2717 list(compound_select_cols) 

2718 if compound_select_cols 

2719 else [self] 

2720 ), 

2721 *fk, 

2722 ) 

2723 except TypeError as err: 

2724 raise TypeError( 

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

2726 "Ensure the class includes a _constructor() " 

2727 "attribute or method which accepts the " 

2728 "standard Column constructor arguments, or " 

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

2730 ) from err 

2731 

2732 c.table = selectable 

2733 c._propagate_attrs = selectable._propagate_attrs 

2734 if selectable._is_clone_of is not None: 

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

2736 

2737 if self.primary_key: 

2738 primary_key.add(c) 

2739 

2740 if fk: 

2741 foreign_keys.update(fk) # type: ignore 

2742 

2743 return c.key, c 

2744 

2745 

2746def insert_sentinel( 

2747 name: Optional[str] = None, 

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

2749 *, 

2750 default: Optional[Any] = None, 

2751 omit_from_statements: bool = True, 

2752) -> Column[Any]: 

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

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

2755 inserts with deterministic RETURNING sorting for tables that 

2756 don't otherwise have qualifying primary key configurations. 

2757 

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

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

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

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

2762 

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

2764 :ref:`engine_insertmanyvalues_sentinel_columns` as part of the 

2765 section :ref:`engine_insertmanyvalues`. 

2766 

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

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

2769 "insertmanyvalues" operations. 

2770 

2771 .. seealso:: 

2772 

2773 :func:`_orm.orm_insert_sentinel` 

2774 

2775 :paramref:`_schema.Column.insert_sentinel` 

2776 

2777 :ref:`engine_insertmanyvalues` 

2778 

2779 :ref:`engine_insertmanyvalues_sentinel_columns` 

2780 

2781 

2782 .. versionadded:: 2.0.10 

2783 

2784 """ 

2785 return Column( 

2786 name=name, 

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

2788 default=( 

2789 default if default is not None else _InsertSentinelColumnDefault() 

2790 ), 

2791 _omit_from_statements=omit_from_statements, 

2792 insert_sentinel=True, 

2793 ) 

2794 

2795 

2796class ForeignKey(DialectKWArgs, SchemaItem): 

2797 """Defines a dependency between two columns. 

2798 

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

2800 object, 

2801 e.g.:: 

2802 

2803 t = Table( 

2804 "remote_table", 

2805 metadata, 

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

2807 ) 

2808 

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

2810 a dependency between two columns. The actual constraint 

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

2812 object. This object will be generated automatically when 

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

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

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

2816 :class:`_schema.Table`, 

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

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

2819 associated with the constraint object. 

2820 

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

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

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

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

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

2826 are created automatically. 

2827 

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

2829 :class:`_schema.Column` 

2830 object are available in the `foreign_keys` collection 

2831 of that column. 

2832 

2833 Further examples of foreign key configuration are in 

2834 :ref:`metadata_foreignkeys`. 

2835 

2836 """ 

2837 

2838 __visit_name__ = "foreign_key" 

2839 

2840 parent: Column[Any] 

2841 

2842 _table_column: Optional[Column[Any]] 

2843 

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

2845 

2846 def __init__( 

2847 self, 

2848 column: _DDLColumnReferenceArgument, 

2849 _constraint: Optional[ForeignKeyConstraint] = None, 

2850 use_alter: bool = False, 

2851 name: _ConstraintNameArgument = None, 

2852 onupdate: Optional[str] = None, 

2853 ondelete: Optional[str] = None, 

2854 deferrable: Optional[bool] = None, 

2855 initially: Optional[str] = None, 

2856 link_to_name: bool = False, 

2857 match: Optional[str] = None, 

2858 info: Optional[_InfoType] = None, 

2859 comment: Optional[str] = None, 

2860 _unresolvable: bool = False, 

2861 **dialect_kw: Any, 

2862 ): 

2863 r""" 

2864 Construct a column-level FOREIGN KEY. 

2865 

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

2867 :class:`_schema.ForeignKeyConstraint` 

2868 which is associated with the parent 

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

2870 

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

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

2873 ``tablename.columnkey`` or ``schema.tablename.columnkey``. 

2874 ``columnkey`` is the ``key`` which has been assigned to the column 

2875 (defaults to the column name itself), unless ``link_to_name`` is 

2876 ``True`` in which case the rendered name of the column is used. 

2877 

2878 :param name: Optional string. An in-database name for the key if 

2879 `constraint` is not provided. 

2880 

2881 :param onupdate: Optional string. If set, emit ON UPDATE <value> when 

2882 issuing DDL for this constraint. Typical values include CASCADE, 

2883 DELETE and RESTRICT. 

2884 

2885 .. seealso:: 

2886 

2887 :ref:`on_update_on_delete` 

2888 

2889 :param ondelete: Optional string. If set, emit ON DELETE <value> when 

2890 issuing DDL for this constraint. Typical values include CASCADE, 

2891 SET NULL and RESTRICT. Some dialects may allow for additional 

2892 syntaxes. 

2893 

2894 .. seealso:: 

2895 

2896 :ref:`on_update_on_delete` 

2897 

2898 :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT 

2899 DEFERRABLE when issuing DDL for this constraint. 

2900 

2901 :param initially: Optional string. If set, emit INITIALLY <value> when 

2902 issuing DDL for this constraint. 

2903 

2904 :param link_to_name: if True, the string name given in ``column`` is 

2905 the rendered name of the referenced column, not its locally 

2906 assigned ``key``. 

2907 

2908 :param use_alter: passed to the underlying 

2909 :class:`_schema.ForeignKeyConstraint` 

2910 to indicate the constraint should 

2911 be generated/dropped externally from the CREATE TABLE/ DROP TABLE 

2912 statement. See :paramref:`_schema.ForeignKeyConstraint.use_alter` 

2913 for further description. 

2914 

2915 .. seealso:: 

2916 

2917 :paramref:`_schema.ForeignKeyConstraint.use_alter` 

2918 

2919 :ref:`use_alter` 

2920 

2921 :param match: Optional string. If set, emit MATCH <value> when issuing 

2922 DDL for this constraint. Typical values include SIMPLE, PARTIAL 

2923 and FULL. 

2924 

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

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

2927 

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

2929 foreign key constraint creation. 

2930 

2931 .. versionadded:: 2.0 

2932 

2933 :param \**dialect_kw: Additional keyword arguments are dialect 

2934 specific, and passed in the form ``<dialectname>_<argname>``. The 

2935 arguments are ultimately handled by a corresponding 

2936 :class:`_schema.ForeignKeyConstraint`. 

2937 See the documentation regarding 

2938 an individual dialect at :ref:`dialect_toplevel` for detail on 

2939 documented arguments. 

2940 

2941 """ 

2942 

2943 self._unresolvable = _unresolvable 

2944 

2945 self._colspec, self._table_column = self._parse_colspec_argument( 

2946 column 

2947 ) 

2948 

2949 # the linked ForeignKeyConstraint. 

2950 # ForeignKey will create this when parent Column 

2951 # is attached to a Table, *or* ForeignKeyConstraint 

2952 # object passes itself in when creating ForeignKey 

2953 # markers. 

2954 self.constraint = _constraint 

2955 

2956 # .parent is not Optional under normal use 

2957 self.parent = None # type: ignore 

2958 

2959 self.use_alter = use_alter 

2960 self.name = name 

2961 self.onupdate = onupdate 

2962 self.ondelete = ondelete 

2963 self.deferrable = deferrable 

2964 self.initially = initially 

2965 self.link_to_name = link_to_name 

2966 self.match = match 

2967 self.comment = comment 

2968 if info: 

2969 self.info = info 

2970 self._unvalidated_dialect_kw = dialect_kw 

2971 

2972 def _resolve_colspec_argument( 

2973 self, 

2974 ) -> Tuple[ 

2975 Union[str, Column[Any]], 

2976 Optional[Column[Any]], 

2977 ]: 

2978 argument = self._colspec 

2979 

2980 return self._parse_colspec_argument(argument) 

2981 

2982 def _parse_colspec_argument( 

2983 self, 

2984 argument: _DDLColumnArgument, 

2985 ) -> Tuple[ 

2986 Union[str, Column[Any]], 

2987 Optional[Column[Any]], 

2988 ]: 

2989 _colspec = coercions.expect(roles.DDLReferredColumnRole, argument) 

2990 

2991 if isinstance(_colspec, str): 

2992 _table_column = None 

2993 else: 

2994 assert isinstance(_colspec, ColumnClause) 

2995 _table_column = _colspec 

2996 

2997 if not isinstance(_table_column.table, (type(None), TableClause)): 

2998 raise exc.ArgumentError( 

2999 "ForeignKey received Column not bound " 

3000 "to a Table, got: %r" % _table_column.table 

3001 ) 

3002 

3003 return _colspec, _table_column 

3004 

3005 def __repr__(self) -> str: 

3006 return "ForeignKey(%r)" % self._get_colspec() 

3007 

3008 @util.deprecated( 

3009 "1.4", 

3010 "The :meth:`_schema.ForeignKey.copy` method is deprecated " 

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

3012 ) 

3013 def copy(self, *, schema: Optional[str] = None, **kw: Any) -> ForeignKey: 

3014 return self._copy(schema=schema, **kw) 

3015 

3016 def _copy(self, *, schema: Optional[str] = None, **kw: Any) -> ForeignKey: 

3017 """Produce a copy of this :class:`_schema.ForeignKey` object. 

3018 

3019 The new :class:`_schema.ForeignKey` will not be bound 

3020 to any :class:`_schema.Column`. 

3021 

3022 This method is usually used by the internal 

3023 copy procedures of :class:`_schema.Column`, :class:`_schema.Table`, 

3024 and :class:`_schema.MetaData`. 

3025 

3026 :param schema: The returned :class:`_schema.ForeignKey` will 

3027 reference the original table and column name, qualified 

3028 by the given string schema name. 

3029 

3030 """ 

3031 fk = ForeignKey( 

3032 self._get_colspec(schema=schema), 

3033 use_alter=self.use_alter, 

3034 name=self.name, 

3035 onupdate=self.onupdate, 

3036 ondelete=self.ondelete, 

3037 deferrable=self.deferrable, 

3038 initially=self.initially, 

3039 link_to_name=self.link_to_name, 

3040 match=self.match, 

3041 comment=self.comment, 

3042 **self._unvalidated_dialect_kw, 

3043 ) 

3044 return self._schema_item_copy(fk) 

3045 

3046 def _get_colspec( 

3047 self, 

3048 schema: Optional[ 

3049 Union[ 

3050 str, 

3051 Literal[SchemaConst.RETAIN_SCHEMA, SchemaConst.BLANK_SCHEMA], 

3052 ] 

3053 ] = None, 

3054 table_name: Optional[str] = None, 

3055 _is_copy: bool = False, 

3056 ) -> str: 

3057 """Return a string based 'column specification' for this 

3058 :class:`_schema.ForeignKey`. 

3059 

3060 This is usually the equivalent of the string-based "tablename.colname" 

3061 argument first passed to the object's constructor. 

3062 

3063 """ 

3064 

3065 _colspec, effective_table_column = self._resolve_colspec_argument() 

3066 

3067 if schema not in (None, RETAIN_SCHEMA): 

3068 _schema, tname, colname = self._column_tokens 

3069 if table_name is not None: 

3070 tname = table_name 

3071 if schema is BLANK_SCHEMA: 

3072 return "%s.%s" % (tname, colname) 

3073 else: 

3074 return "%s.%s.%s" % (schema, tname, colname) 

3075 elif table_name: 

3076 schema, tname, colname = self._column_tokens 

3077 if schema: 

3078 return "%s.%s.%s" % (schema, table_name, colname) 

3079 else: 

3080 return "%s.%s" % (table_name, colname) 

3081 elif effective_table_column is not None: 

3082 if effective_table_column.table is None: 

3083 if _is_copy: 

3084 raise exc.InvalidRequestError( 

3085 f"Can't copy ForeignKey object which refers to " 

3086 f"non-table bound Column {effective_table_column!r}" 

3087 ) 

3088 else: 

3089 return effective_table_column.key 

3090 return "%s.%s" % ( 

3091 effective_table_column.table.fullname, 

3092 effective_table_column.key, 

3093 ) 

3094 else: 

3095 assert isinstance(_colspec, str) 

3096 return _colspec 

3097 

3098 @property 

3099 def _referred_schema(self) -> Optional[str]: 

3100 return self._column_tokens[0] 

3101 

3102 def _table_key_within_construction(self) -> Any: 

3103 """get the table key but only safely""" 

3104 

3105 if self._table_column is not None: 

3106 if self._table_column.table is None: 

3107 return None 

3108 else: 

3109 return self._table_column.table.key 

3110 else: 

3111 schema, tname, colname = self._column_tokens 

3112 return _get_table_key(tname, schema) 

3113 

3114 target_fullname = property(_get_colspec) 

3115 

3116 def references(self, table: Table) -> bool: 

3117 """Return True if the given :class:`_schema.Table` 

3118 is referenced by this 

3119 :class:`_schema.ForeignKey`.""" 

3120 

3121 return table.corresponding_column(self.column) is not None 

3122 

3123 def get_referent(self, table: FromClause) -> Optional[Column[Any]]: 

3124 """Return the :class:`_schema.Column` in the given 

3125 :class:`_schema.Table` (or any :class:`.FromClause`) 

3126 referenced by this :class:`_schema.ForeignKey`. 

3127 

3128 Returns None if this :class:`_schema.ForeignKey` 

3129 does not reference the given 

3130 :class:`_schema.Table`. 

3131 

3132 """ 

3133 # our column is a Column, and any subquery etc. proxying us 

3134 # would be doing so via another Column, so that's what would 

3135 # be returned here 

3136 return table.columns.corresponding_column(self.column) # type: ignore 

3137 

3138 @util.memoized_property 

3139 def _column_tokens(self) -> Tuple[Optional[str], str, Optional[str]]: 

3140 """parse a string-based _colspec into its component parts.""" 

3141 

3142 m = self._get_colspec().split(".") 

3143 if len(m) == 1: 

3144 tname = m.pop() 

3145 colname = None 

3146 else: 

3147 colname = m.pop() 

3148 tname = m.pop() 

3149 

3150 # A FK between column 'bar' and table 'foo' can be 

3151 # specified as 'foo', 'foo.bar', 'dbo.foo.bar', 

3152 # 'otherdb.dbo.foo.bar'. Once we have the column name and 

3153 # the table name, treat everything else as the schema 

3154 # name. Some databases (e.g. Sybase) support 

3155 # inter-database foreign keys. See tickets#1341 and -- 

3156 # indirectly related -- Ticket #594. This assumes that '.' 

3157 # will never appear *within* any component of the FK. 

3158 

3159 if len(m) > 0: 

3160 schema = ".".join(m) 

3161 else: 

3162 schema = None 

3163 return schema, tname, colname 

3164 

3165 def _resolve_col_tokens(self) -> Tuple[Table, str, Optional[str]]: 

3166 if self.parent is None: 

3167 raise exc.InvalidRequestError( 

3168 "this ForeignKey object does not yet have a " 

3169 "parent Column associated with it." 

3170 ) 

3171 

3172 elif self.parent.table is None: 

3173 raise exc.InvalidRequestError( 

3174 "this ForeignKey's parent column is not yet associated " 

3175 "with a Table." 

3176 ) 

3177 

3178 parenttable = self.parent.table 

3179 

3180 if self._unresolvable: 

3181 schema, tname, colname = self._column_tokens 

3182 tablekey = _get_table_key(tname, schema) 

3183 return parenttable, tablekey, colname 

3184 

3185 # assertion 

3186 # basically Column._make_proxy() sends the actual 

3187 # target Column to the ForeignKey object, so the 

3188 # string resolution here is never called. 

3189 for c in self.parent.base_columns: 

3190 if isinstance(c, Column): 

3191 assert c.table is parenttable 

3192 break 

3193 else: 

3194 assert False 

3195 ###################### 

3196 

3197 schema, tname, colname = self._column_tokens 

3198 

3199 if schema is None and parenttable.metadata.schema is not None: 

3200 schema = parenttable.metadata.schema 

3201 

3202 tablekey = _get_table_key(tname, schema) 

3203 return parenttable, tablekey, colname 

3204 

3205 def _link_to_col_by_colstring( 

3206 self, parenttable: Table, table: Table, colname: Optional[str] 

3207 ) -> Column[Any]: 

3208 _column = None 

3209 if colname is None: 

3210 # colname is None in the case that ForeignKey argument 

3211 # was specified as table name only, in which case we 

3212 # match the column name to the same column on the 

3213 # parent. 

3214 # this use case wasn't working in later 1.x series 

3215 # as it had no test coverage; fixed in 2.0 

3216 parent = self.parent 

3217 assert parent is not None 

3218 key = parent.key 

3219 _column = table.c.get(key, None) 

3220 elif self.link_to_name: 

3221 key = colname 

3222 for c in table.c: 

3223 if c.name == colname: 

3224 _column = c 

3225 else: 

3226 key = colname 

3227 _column = table.c.get(colname, None) 

3228 

3229 if _column is None: 

3230 raise exc.NoReferencedColumnError( 

3231 "Could not initialize target column " 

3232 f"for ForeignKey '{self._get_colspec()}' " 

3233 f"on table '{parenttable.name}': " 

3234 f"table '{table.name}' has no column named '{key}'", 

3235 table.name, 

3236 key, 

3237 ) 

3238 

3239 return _column 

3240 

3241 def _set_target_column(self, column: Column[Any]) -> None: 

3242 assert self.parent is not None 

3243 

3244 # propagate TypeEngine to parent if it didn't have one 

3245 if self.parent.type._isnull: 

3246 self.parent.type = column.type 

3247 

3248 # super-edgy case, if other FKs point to our column, 

3249 # they'd get the type propagated out also. 

3250 

3251 def set_type(fk: ForeignKey) -> None: 

3252 if fk.parent.type._isnull: 

3253 fk.parent.type = column.type 

3254 

3255 self.parent._setup_on_memoized_fks(set_type) 

3256 

3257 self.column = column # type: ignore 

3258 

3259 @util.ro_memoized_property 

3260 def column(self) -> Column[Any]: 

3261 """Return the target :class:`_schema.Column` referenced by this 

3262 :class:`_schema.ForeignKey`. 

3263 

3264 If no target column has been established, an exception 

3265 is raised. 

3266 

3267 """ 

3268 return self._resolve_column() 

3269 

3270 @overload 

3271 def _resolve_column( 

3272 self, *, raiseerr: Literal[True] = ... 

3273 ) -> Column[Any]: ... 

3274 

3275 @overload 

3276 def _resolve_column( 

3277 self, *, raiseerr: bool = ... 

3278 ) -> Optional[Column[Any]]: ... 

3279 

3280 def _resolve_column( 

3281 self, *, raiseerr: bool = True 

3282 ) -> Optional[Column[Any]]: 

3283 _column: Column[Any] 

3284 

3285 _colspec, effective_table_column = self._resolve_colspec_argument() 

3286 

3287 if isinstance(_colspec, str): 

3288 parenttable, tablekey, colname = self._resolve_col_tokens() 

3289 

3290 if self._unresolvable or tablekey not in parenttable.metadata: 

3291 if not raiseerr: 

3292 return None 

3293 raise exc.NoReferencedTableError( 

3294 f"Foreign key associated with column " 

3295 f"'{self.parent}' could not find " 

3296 f"table '{tablekey}' with which to generate a " 

3297 f"foreign key to target column '{colname}'", 

3298 tablekey, 

3299 ) 

3300 elif parenttable.key not in parenttable.metadata: 

3301 if not raiseerr: 

3302 return None 

3303 raise exc.InvalidRequestError( 

3304 f"Table {parenttable} is no longer associated with its " 

3305 "parent MetaData" 

3306 ) 

3307 else: 

3308 table = parenttable.metadata.tables[tablekey] 

3309 return self._link_to_col_by_colstring( 

3310 parenttable, table, colname 

3311 ) 

3312 

3313 elif hasattr(_colspec, "__clause_element__"): 

3314 _column = _colspec.__clause_element__() 

3315 return _column 

3316 else: 

3317 assert isinstance(_colspec, Column) 

3318 _column = _colspec 

3319 return _column 

3320 

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

3322 assert isinstance(parent, Column) 

3323 

3324 if self.parent is not None and self.parent is not parent: 

3325 raise exc.InvalidRequestError( 

3326 "This ForeignKey already has a parent !" 

3327 ) 

3328 self.parent = parent 

3329 self.parent.foreign_keys.add(self) 

3330 self.parent._on_table_attach(self._set_table) 

3331 

3332 def _set_remote_table(self, table: Table) -> None: 

3333 parenttable, _, colname = self._resolve_col_tokens() 

3334 _column = self._link_to_col_by_colstring(parenttable, table, colname) 

3335 self._set_target_column(_column) 

3336 assert self.constraint is not None 

3337 self.constraint._validate_dest_table(table) 

3338 

3339 def _remove_from_metadata(self, metadata: MetaData) -> None: 

3340 parenttable, table_key, colname = self._resolve_col_tokens() 

3341 fk_key = (table_key, colname) 

3342 

3343 if self in metadata._fk_memos[fk_key]: 

3344 # TODO: no test coverage for self not in memos 

3345 metadata._fk_memos[fk_key].remove(self) 

3346 

3347 def _set_table(self, column: Column[Any], table: Table) -> None: 

3348 # standalone ForeignKey - create ForeignKeyConstraint 

3349 # on the hosting Table when attached to the Table. 

3350 assert isinstance(table, Table) 

3351 if self.constraint is None: 

3352 self.constraint = ForeignKeyConstraint( 

3353 [], 

3354 [], 

3355 use_alter=self.use_alter, 

3356 name=self.name, 

3357 onupdate=self.onupdate, 

3358 ondelete=self.ondelete, 

3359 deferrable=self.deferrable, 

3360 initially=self.initially, 

3361 match=self.match, 

3362 comment=self.comment, 

3363 **self._unvalidated_dialect_kw, 

3364 ) 

3365 self.constraint._append_element(column, self) 

3366 self.constraint._set_parent_with_dispatch(table) 

3367 table.foreign_keys.add(self) 

3368 # set up remote ".column" attribute, or a note to pick it 

3369 # up when the other Table/Column shows up 

3370 

3371 _colspec, _ = self._resolve_colspec_argument() 

3372 if isinstance(_colspec, str): 

3373 parenttable, table_key, colname = self._resolve_col_tokens() 

3374 fk_key = (table_key, colname) 

3375 if table_key in parenttable.metadata.tables: 

3376 table = parenttable.metadata.tables[table_key] 

3377 try: 

3378 _column = self._link_to_col_by_colstring( 

3379 parenttable, table, colname 

3380 ) 

3381 except exc.NoReferencedColumnError: 

3382 # this is OK, we'll try later 

3383 pass 

3384 else: 

3385 self._set_target_column(_column) 

3386 

3387 parenttable.metadata._fk_memos[fk_key].append(self) 

3388 elif hasattr(_colspec, "__clause_element__"): 

3389 _column = _colspec.__clause_element__() 

3390 self._set_target_column(_column) 

3391 else: 

3392 self._set_target_column(_colspec) 

3393 

3394 

3395if TYPE_CHECKING: 

3396 

3397 def default_is_sequence( 

3398 obj: Optional[DefaultGenerator], 

3399 ) -> TypeGuard[Sequence]: ... 

3400 

3401 def default_is_clause_element( 

3402 obj: Optional[DefaultGenerator], 

3403 ) -> TypeGuard[ColumnElementColumnDefault]: ... 

3404 

3405 def default_is_scalar( 

3406 obj: Optional[DefaultGenerator], 

3407 ) -> TypeGuard[ScalarElementColumnDefault]: ... 

3408 

3409else: 

3410 default_is_sequence = operator.attrgetter("is_sequence") 

3411 

3412 default_is_clause_element = operator.attrgetter("is_clause_element") 

3413 

3414 default_is_scalar = operator.attrgetter("is_scalar") 

3415 

3416 

3417class DefaultGenerator(Executable, SchemaItem): 

3418 """Base class for column *default* values. 

3419 

3420 This object is only present on column.default or column.onupdate. 

3421 It's not valid as a server default. 

3422 

3423 """ 

3424 

3425 __visit_name__ = "default_generator" 

3426 

3427 _is_default_generator = True 

3428 is_sequence = False 

3429 is_identity = False 

3430 is_server_default = False 

3431 is_clause_element = False 

3432 is_callable = False 

3433 is_scalar = False 

3434 has_arg = False 

3435 is_sentinel = False 

3436 column: Optional[Column[Any]] 

3437 

3438 def __init__(self, for_update: bool = False) -> None: 

3439 self.for_update = for_update 

3440 

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

3442 if TYPE_CHECKING: 

3443 assert isinstance(parent, Column) 

3444 self.column = parent 

3445 if self.for_update: 

3446 self.column.onupdate = self 

3447 else: 

3448 self.column.default = self 

3449 

3450 def _copy(self) -> DefaultGenerator: 

3451 raise NotImplementedError() 

3452 

3453 def _execute_on_connection( 

3454 self, 

3455 connection: Connection, 

3456 distilled_params: _CoreMultiExecuteParams, 

3457 execution_options: CoreExecuteOptionsParameter, 

3458 ) -> Any: 

3459 util.warn_deprecated( 

3460 "Using the .execute() method to invoke a " 

3461 "DefaultGenerator object is deprecated; please use " 

3462 "the .scalar() method.", 

3463 "2.0", 

3464 ) 

3465 return self._execute_on_scalar( 

3466 connection, distilled_params, execution_options 

3467 ) 

3468 

3469 def _execute_on_scalar( 

3470 self, 

3471 connection: Connection, 

3472 distilled_params: _CoreMultiExecuteParams, 

3473 execution_options: CoreExecuteOptionsParameter, 

3474 ) -> Any: 

3475 return connection._execute_default( 

3476 self, distilled_params, execution_options 

3477 ) 

3478 

3479 

3480class ColumnDefault(DefaultGenerator, ABC): 

3481 """A plain default value on a column. 

3482 

3483 This could correspond to a constant, a callable function, 

3484 or a SQL clause. 

3485 

3486 :class:`.ColumnDefault` is generated automatically 

3487 whenever the ``default``, ``onupdate`` arguments of 

3488 :class:`_schema.Column` are used. A :class:`.ColumnDefault` 

3489 can be passed positionally as well. 

3490 

3491 For example, the following:: 

3492 

3493 Column("foo", Integer, default=50) 

3494 

3495 Is equivalent to:: 

3496 

3497 Column("foo", Integer, ColumnDefault(50)) 

3498 

3499 """ 

3500 

3501 arg: Any 

3502 

3503 @overload 

3504 def __new__( 

3505 cls, arg: Callable[..., Any], for_update: bool = ... 

3506 ) -> CallableColumnDefault: ... 

3507 

3508 @overload 

3509 def __new__( 

3510 cls, arg: ColumnElement[Any], for_update: bool = ... 

3511 ) -> ColumnElementColumnDefault: ... 

3512 

3513 # if I return ScalarElementColumnDefault here, which is what's actually 

3514 # returned, mypy complains that 

3515 # overloads overlap w/ incompatible return types. 

3516 @overload 

3517 def __new__(cls, arg: object, for_update: bool = ...) -> ColumnDefault: ... 

3518 

3519 def __new__( 

3520 cls, arg: Any = None, for_update: bool = False 

3521 ) -> ColumnDefault: 

3522 """Construct a new :class:`.ColumnDefault`. 

3523 

3524 

3525 :param arg: argument representing the default value. 

3526 May be one of the following: 

3527 

3528 * a plain non-callable Python value, such as a 

3529 string, integer, boolean, or other simple type. 

3530 The default value will be used as is each time. 

3531 * a SQL expression, that is one which derives from 

3532 :class:`_expression.ColumnElement`. The SQL expression will 

3533 be rendered into the INSERT or UPDATE statement, 

3534 or in the case of a primary key column when 

3535 RETURNING is not used may be 

3536 pre-executed before an INSERT within a SELECT. 

3537 * A Python callable. The function will be invoked for each 

3538 new row subject to an INSERT or UPDATE. 

3539 The callable must accept exactly 

3540 zero or one positional arguments. The one-argument form 

3541 will receive an instance of the :class:`.ExecutionContext`, 

3542 which provides contextual information as to the current 

3543 :class:`_engine.Connection` in use as well as the current 

3544 statement and parameters. 

3545 

3546 """ 

3547 

3548 if isinstance(arg, FetchedValue): 

3549 raise exc.ArgumentError( 

3550 "ColumnDefault may not be a server-side default type." 

3551 ) 

3552 elif callable(arg): 

3553 cls = CallableColumnDefault 

3554 elif isinstance(arg, ClauseElement): 

3555 cls = ColumnElementColumnDefault 

3556 elif arg is not None: 

3557 cls = ScalarElementColumnDefault 

3558 

3559 return object.__new__(cls) 

3560 

3561 def __repr__(self) -> str: 

3562 return f"{self.__class__.__name__}({self.arg!r})" 

3563 

3564 

3565class ScalarElementColumnDefault(ColumnDefault): 

3566 """default generator for a fixed scalar Python value 

3567 

3568 .. versionadded:: 2.0 

3569 

3570 """ 

3571 

3572 is_scalar = True 

3573 has_arg = True 

3574 

3575 def __init__(self, arg: Any, for_update: bool = False) -> None: 

3576 self.for_update = for_update 

3577 self.arg = arg 

3578 

3579 def _copy(self) -> ScalarElementColumnDefault: 

3580 return ScalarElementColumnDefault( 

3581 arg=self.arg, for_update=self.for_update 

3582 ) 

3583 

3584 

3585class _InsertSentinelColumnDefault(ColumnDefault): 

3586 """Default generator that's specific to the use of a "sentinel" column 

3587 when using the insertmanyvalues feature. 

3588 

3589 This default is used as part of the :func:`_schema.insert_sentinel` 

3590 construct. 

3591 

3592 """ 

3593 

3594 is_sentinel = True 

3595 for_update = False 

3596 arg = None 

3597 

3598 def __new__(cls) -> _InsertSentinelColumnDefault: 

3599 return object.__new__(cls) 

3600 

3601 def __init__(self) -> None: 

3602 pass 

3603 

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

3605 col = cast("Column[Any]", parent) 

3606 if not col._insert_sentinel: 

3607 raise exc.ArgumentError( 

3608 "The _InsertSentinelColumnDefault may only be applied to a " 

3609 "Column marked as insert_sentinel=True" 

3610 ) 

3611 elif not col.nullable: 

3612 raise exc.ArgumentError( 

3613 "The _InsertSentinelColumnDefault may only be applied to a " 

3614 "Column that is nullable" 

3615 ) 

3616 

3617 super()._set_parent(parent, **kw) 

3618 

3619 def _copy(self) -> _InsertSentinelColumnDefault: 

3620 return _InsertSentinelColumnDefault() 

3621 

3622 

3623_SQLExprDefault = Union["ColumnElement[Any]", "TextClause"] 

3624 

3625 

3626class ColumnElementColumnDefault(ColumnDefault): 

3627 """default generator for a SQL expression 

3628 

3629 .. versionadded:: 2.0 

3630 

3631 """ 

3632 

3633 is_clause_element = True 

3634 has_arg = True 

3635 arg: _SQLExprDefault 

3636 

3637 def __init__( 

3638 self, 

3639 arg: _SQLExprDefault, 

3640 for_update: bool = False, 

3641 ) -> None: 

3642 self.for_update = for_update 

3643 self.arg = arg 

3644 

3645 def _copy(self) -> ColumnElementColumnDefault: 

3646 return ColumnElementColumnDefault( 

3647 arg=self.arg, for_update=self.for_update 

3648 ) 

3649 

3650 @util.memoized_property 

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

3652 def _arg_is_typed(self) -> bool: 

3653 sqltypes = util.preloaded.sql_sqltypes 

3654 

3655 return not isinstance(self.arg.type, sqltypes.NullType) 

3656 

3657 

3658class _CallableColumnDefaultProtocol(Protocol): 

3659 def __call__(self, context: ExecutionContext) -> Any: ... 

3660 

3661 

3662class CallableColumnDefault(ColumnDefault): 

3663 """default generator for a callable Python function 

3664 

3665 .. versionadded:: 2.0 

3666 

3667 """ 

3668 

3669 is_callable = True 

3670 arg: _CallableColumnDefaultProtocol 

3671 has_arg = True 

3672 

3673 def __init__( 

3674 self, 

3675 arg: Union[_CallableColumnDefaultProtocol, Callable[[], Any]], 

3676 for_update: bool = False, 

3677 ) -> None: 

3678 self.for_update = for_update 

3679 self.arg = self._maybe_wrap_callable(arg) 

3680 

3681 def _copy(self) -> CallableColumnDefault: 

3682 return CallableColumnDefault(arg=self.arg, for_update=self.for_update) 

3683 

3684 def _maybe_wrap_callable( 

3685 self, fn: Union[_CallableColumnDefaultProtocol, Callable[[], Any]] 

3686 ) -> _CallableColumnDefaultProtocol: 

3687 """Wrap callables that don't accept a context. 

3688 

3689 This is to allow easy compatibility with default callables 

3690 that aren't specific to accepting of a context. 

3691 

3692 """ 

3693 

3694 try: 

3695 argspec = util.get_callable_argspec(fn, no_self=True) 

3696 except TypeError: 

3697 return util.wrap_callable(lambda ctx: fn(), fn) # type: ignore 

3698 

3699 defaulted = argspec[3] is not None and len(argspec[3]) or 0 

3700 positionals = len(argspec[0]) - defaulted 

3701 

3702 if positionals == 0: 

3703 return util.wrap_callable(lambda ctx: fn(), fn) # type: ignore 

3704 

3705 elif positionals == 1: 

3706 return fn # type: ignore 

3707 else: 

3708 raise exc.ArgumentError( 

3709 "ColumnDefault Python function takes zero or one " 

3710 "positional arguments" 

3711 ) 

3712 

3713 

3714class IdentityOptions(DialectKWArgs): 

3715 """Defines options for a named database sequence or an identity column. 

3716 

3717 .. seealso:: 

3718 

3719 :class:`.Sequence` 

3720 

3721 """ 

3722 

3723 def __init__( 

3724 self, 

3725 start: Optional[int] = None, 

3726 increment: Optional[int] = None, 

3727 minvalue: Optional[int] = None, 

3728 maxvalue: Optional[int] = None, 

3729 nominvalue: Optional[bool] = None, 

3730 nomaxvalue: Optional[bool] = None, 

3731 cycle: Optional[bool] = None, 

3732 cache: Optional[int] = None, 

3733 order: Optional[bool] = None, 

3734 **dialect_kw: Any, 

3735 ) -> None: 

3736 """Construct a :class:`.IdentityOptions` object. 

3737 

3738 See the :class:`.Sequence` documentation for a complete description 

3739 of the parameters. 

3740 

3741 :param start: the starting index of the sequence. 

3742 :param increment: the increment value of the sequence. 

3743 :param minvalue: the minimum value of the sequence. 

3744 :param maxvalue: the maximum value of the sequence. 

3745 :param nominvalue: no minimum value of the sequence. 

3746 :param nomaxvalue: no maximum value of the sequence. 

3747 :param cycle: allows the sequence to wrap around when the maxvalue 

3748 or minvalue has been reached. 

3749 :param cache: optional integer value; number of future values in the 

3750 sequence which are calculated in advance. 

3751 :param order: optional boolean value; if ``True``, renders the 

3752 ORDER keyword. 

3753 

3754 .. deprecated:: 2.1 Use ``oracle_order`` instead. 

3755 

3756 """ 

3757 self.start = start 

3758 self.increment = increment 

3759 self.minvalue = minvalue 

3760 self.maxvalue = maxvalue 

3761 self.nominvalue = nominvalue 

3762 self.nomaxvalue = nomaxvalue 

3763 self.cycle = cycle 

3764 self.cache = cache 

3765 if order is not None: 

3766 if "oracle_order" in dialect_kw: 

3767 raise exc.ArgumentError( 

3768 "Cannot specify both 'order' and 'oracle_order'. " 

3769 "Plese use only 'oracle_order'." 

3770 ) 

3771 dialect_kw["oracle_order"] = order 

3772 self._validate_dialect_kwargs(dialect_kw) 

3773 

3774 @property 

3775 def _increment_is_negative(self) -> bool: 

3776 return self.increment is not None and self.increment < 0 

3777 

3778 @property 

3779 def order(self) -> Optional[bool]: 

3780 """Alias of the ``dialect_kwargs`` ``'oracle_order'``. 

3781 

3782 .. deprecated:: 2.1 The 'order' attribute is deprecated. 

3783 """ 

3784 value: Optional[bool] = self.dialect_kwargs.get("oracle_order") 

3785 return value 

3786 

3787 def _as_dict(self) -> Dict[str, Any]: 

3788 return { 

3789 k: v 

3790 for k, v in { 

3791 "start": self.start, 

3792 "increment": self.increment, 

3793 "minvalue": self.minvalue, 

3794 "maxvalue": self.maxvalue, 

3795 "nominvalue": self.nominvalue, 

3796 "nomaxvalue": self.nomaxvalue, 

3797 "cycle": self.cycle, 

3798 "cache": self.cache, 

3799 }.items() 

3800 if v != None 

3801 } 

3802 

3803 

3804class Sequence(HasSchemaAttr, IdentityOptions, DefaultGenerator): 

3805 """Represents a named database sequence. 

3806 

3807 The :class:`.Sequence` object represents the name and configurational 

3808 parameters of a database sequence. It also represents 

3809 a construct that can be "executed" by a SQLAlchemy :class:`_engine.Engine` 

3810 or :class:`_engine.Connection`, 

3811 rendering the appropriate "next value" function 

3812 for the target database and returning a result. 

3813 

3814 The :class:`.Sequence` is typically associated with a primary key column:: 

3815 

3816 some_table = Table( 

3817 "some_table", 

3818 metadata, 

3819 Column( 

3820 "id", 

3821 Integer, 

3822 Sequence("some_table_seq", start=1), 

3823 primary_key=True, 

3824 ), 

3825 ) 

3826 

3827 When CREATE TABLE is emitted for the above :class:`_schema.Table`, if the 

3828 target platform supports sequences, a CREATE SEQUENCE statement will 

3829 be emitted as well. For platforms that don't support sequences, 

3830 the :class:`.Sequence` construct is ignored. 

3831 

3832 .. seealso:: 

3833 

3834 :ref:`defaults_sequences` 

3835 

3836 :class:`.CreateSequence` 

3837 

3838 :class:`.DropSequence` 

3839 

3840 """ 

3841 

3842 __visit_name__ = "sequence" 

3843 

3844 is_sequence = True 

3845 

3846 column: Optional[Column[Any]] 

3847 data_type: Optional[TypeEngine[int]] 

3848 

3849 @util.deprecated_params( 

3850 order=( 

3851 "2.1", 

3852 "This parameter is supported only by Oracle Database, " 

3853 "use ``oracle_order`` instead.", 

3854 ) 

3855 ) 

3856 def __init__( 

3857 self, 

3858 name: str, 

3859 start: Optional[int] = None, 

3860 increment: Optional[int] = None, 

3861 minvalue: Optional[int] = None, 

3862 maxvalue: Optional[int] = None, 

3863 nominvalue: Optional[bool] = None, 

3864 nomaxvalue: Optional[bool] = None, 

3865 cycle: Optional[bool] = None, 

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

3867 cache: Optional[int] = None, 

3868 order: Optional[bool] = None, 

3869 data_type: Optional[_TypeEngineArgument[int]] = None, 

3870 optional: bool = False, 

3871 quote: Optional[bool] = None, 

3872 metadata: Optional[MetaData] = None, 

3873 quote_schema: Optional[bool] = None, 

3874 for_update: bool = False, 

3875 **dialect_kw: Any, 

3876 ) -> None: 

3877 """Construct a :class:`.Sequence` object. 

3878 

3879 :param name: the name of the sequence. 

3880 

3881 :param start: the starting index of the sequence. This value is 

3882 used when the CREATE SEQUENCE command is emitted to the database 

3883 as the value of the "START WITH" clause. If ``None``, the 

3884 clause is omitted, which on most platforms indicates a starting 

3885 value of 1. 

3886 

3887 .. versionchanged:: 2.0 The :paramref:`.Sequence.start` parameter 

3888 is required in order to have DDL emit "START WITH". This is a 

3889 reversal of a change made in version 1.4 which would implicitly 

3890 render "START WITH 1" if the :paramref:`.Sequence.start` were 

3891 not included. See :ref:`change_7211` for more detail. 

3892 

3893 :param increment: the increment value of the sequence. This 

3894 value is used when the CREATE SEQUENCE command is emitted to 

3895 the database as the value of the "INCREMENT BY" clause. If ``None``, 

3896 the clause is omitted, which on most platforms indicates an 

3897 increment of 1. 

3898 :param minvalue: the minimum value of the sequence. This 

3899 value is used when the CREATE SEQUENCE command is emitted to 

3900 the database as the value of the "MINVALUE" clause. If ``None``, 

3901 the clause is omitted, which on most platforms indicates a 

3902 minvalue of 1 and -2^63-1 for ascending and descending sequences, 

3903 respectively. 

3904 

3905 :param maxvalue: the maximum value of the sequence. This 

3906 value is used when the CREATE SEQUENCE command is emitted to 

3907 the database as the value of the "MAXVALUE" clause. If ``None``, 

3908 the clause is omitted, which on most platforms indicates a 

3909 maxvalue of 2^63-1 and -1 for ascending and descending sequences, 

3910 respectively. 

3911 

3912 :param nominvalue: no minimum value of the sequence. This 

3913 value is used when the CREATE SEQUENCE command is emitted to 

3914 the database as the value of the "NO MINVALUE" clause. If ``None``, 

3915 the clause is omitted, which on most platforms indicates a 

3916 minvalue of 1 and -2^63-1 for ascending and descending sequences, 

3917 respectively. 

3918 

3919 :param nomaxvalue: no maximum value of the sequence. This 

3920 value is used when the CREATE SEQUENCE command is emitted to 

3921 the database as the value of the "NO MAXVALUE" clause. If ``None``, 

3922 the clause is omitted, which on most platforms indicates a 

3923 maxvalue of 2^63-1 and -1 for ascending and descending sequences, 

3924 respectively. 

3925 

3926 :param cycle: allows the sequence to wrap around when the maxvalue 

3927 or minvalue has been reached by an ascending or descending sequence 

3928 respectively. This value is used when the CREATE SEQUENCE command 

3929 is emitted to the database as the "CYCLE" clause. If the limit is 

3930 reached, the next number generated will be the minvalue or maxvalue, 

3931 respectively. If cycle=False (the default) any calls to nextval 

3932 after the sequence has reached its maximum value will return an 

3933 error. 

3934 

3935 :param schema: optional schema name for the sequence, if located 

3936 in a schema other than the default. The rules for selecting the 

3937 schema name when a :class:`_schema.MetaData` 

3938 is also present are the same 

3939 as that of :paramref:`_schema.Table.schema`. 

3940 

3941 :param cache: optional integer value; number of future values in the 

3942 sequence which are calculated in advance. Renders the CACHE keyword 

3943 understood by Oracle Database and PostgreSQL. 

3944 

3945 :param order: optional boolean value; if ``True``, renders the 

3946 ORDER keyword, understood by Oracle Database, indicating the sequence 

3947 is definitively ordered. May be necessary to provide deterministic 

3948 ordering using Oracle RAC. 

3949 

3950 :param data_type: The type to be returned by the sequence, for 

3951 dialects that allow us to choose between INTEGER, BIGINT, etc. 

3952 (e.g., mssql). 

3953 

3954 .. versionadded:: 1.4.0 

3955 

3956 :param optional: boolean value, when ``True``, indicates that this 

3957 :class:`.Sequence` object only needs to be explicitly generated 

3958 on backends that don't provide another way to generate primary 

3959 key identifiers. Currently, it essentially means, "don't create 

3960 this sequence on the PostgreSQL backend, where the SERIAL keyword 

3961 creates a sequence for us automatically". 

3962 :param quote: boolean value, when ``True`` or ``False``, explicitly 

3963 forces quoting of the :paramref:`_schema.Sequence.name` on or off. 

3964 When left at its default of ``None``, normal quoting rules based 

3965 on casing and reserved words take place. 

3966 :param quote_schema: Set the quoting preferences for the ``schema`` 

3967 name. 

3968 

3969 :param metadata: optional :class:`_schema.MetaData` object which this 

3970 :class:`.Sequence` will be associated with. A :class:`.Sequence` 

3971 that is associated with a :class:`_schema.MetaData` 

3972 gains the following 

3973 capabilities: 

3974 

3975 * The :class:`.Sequence` will inherit the 

3976 :paramref:`_schema.MetaData.schema` 

3977 parameter specified to the target :class:`_schema.MetaData`, which 

3978 affects the production of CREATE / DROP DDL, if any. 

3979 

3980 * The :meth:`.Sequence.create` and :meth:`.Sequence.drop` methods 

3981 automatically use the engine bound to the :class:`_schema.MetaData` 

3982 object, if any. 

3983 

3984 * The :meth:`_schema.MetaData.create_all` and 

3985 :meth:`_schema.MetaData.drop_all` 

3986 methods will emit CREATE / DROP for this :class:`.Sequence`, 

3987 even if the :class:`.Sequence` is not associated with any 

3988 :class:`_schema.Table` / :class:`_schema.Column` 

3989 that's a member of this 

3990 :class:`_schema.MetaData`. 

3991 

3992 The above behaviors can only occur if the :class:`.Sequence` is 

3993 explicitly associated with the :class:`_schema.MetaData` 

3994 via this parameter. 

3995 

3996 .. seealso:: 

3997 

3998 :ref:`sequence_metadata` - full discussion of the 

3999 :paramref:`.Sequence.metadata` parameter. 

4000 

4001 :param for_update: Indicates this :class:`.Sequence`, when associated 

4002 with a :class:`_schema.Column`, 

4003 should be invoked for UPDATE statements 

4004 on that column's table, rather than for INSERT statements, when 

4005 no value is otherwise present for that column in the statement. 

4006 

4007 """ 

4008 DefaultGenerator.__init__(self, for_update=for_update) 

4009 IdentityOptions.__init__( 

4010 self, 

4011 start=start, 

4012 increment=increment, 

4013 minvalue=minvalue, 

4014 maxvalue=maxvalue, 

4015 nominvalue=nominvalue, 

4016 nomaxvalue=nomaxvalue, 

4017 cycle=cycle, 

4018 cache=cache, 

4019 order=order, 

4020 **dialect_kw, 

4021 ) 

4022 self.column = None 

4023 self.name = quoted_name(name, quote) 

4024 self.optional = optional 

4025 if schema is BLANK_SCHEMA: 

4026 self.schema = schema = None 

4027 elif metadata is not None and schema is None and metadata.schema: 

4028 self.schema = schema = metadata.schema 

4029 else: 

4030 self.schema = quoted_name.construct(schema, quote_schema) 

4031 self.metadata = metadata 

4032 self._key = _get_table_key(name, schema) 

4033 if metadata: 

4034 self._set_metadata(metadata) 

4035 if data_type is not None: 

4036 self.data_type = to_instance(data_type) 

4037 else: 

4038 self.data_type = None 

4039 

4040 @util.preload_module("sqlalchemy.sql.functions") 

4041 def next_value(self) -> Function[int]: 

4042 """Return a :class:`.next_value` function element 

4043 which will render the appropriate increment function 

4044 for this :class:`.Sequence` within any SQL expression. 

4045 

4046 """ 

4047 return util.preloaded.sql_functions.func.next_value(self) 

4048 

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

4050 column = parent 

4051 assert isinstance(column, Column) 

4052 super()._set_parent(column) 

4053 column._on_table_attach(self._set_table) 

4054 

4055 def _copy(self) -> Sequence: 

4056 return Sequence( 

4057 name=self.name, 

4058 schema=self.schema, 

4059 data_type=self.data_type, 

4060 optional=self.optional, 

4061 metadata=self.metadata, 

4062 for_update=self.for_update, 

4063 **self._as_dict(), 

4064 **self.dialect_kwargs, 

4065 ) 

4066 

4067 def _set_table(self, column: Column[Any], table: Table) -> None: 

4068 self._set_metadata(table.metadata) 

4069 

4070 def _set_metadata(self, metadata: MetaData) -> None: 

4071 self.metadata = metadata 

4072 self.metadata._sequences[self._key] = self 

4073 

4074 def create(self, bind: _CreateDropBind, checkfirst: bool = True) -> None: 

4075 """Creates this sequence in the database.""" 

4076 

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

4078 

4079 def drop(self, bind: _CreateDropBind, checkfirst: bool = True) -> None: 

4080 """Drops this sequence from the database.""" 

4081 

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

4083 

4084 def _not_a_column_expr(self) -> NoReturn: 

4085 raise exc.InvalidRequestError( 

4086 f"This {self.__class__.__name__} cannot be used directly " 

4087 "as a column expression. Use func.next_value(sequence) " 

4088 "to produce a 'next value' function that's usable " 

4089 "as a column element." 

4090 ) 

4091 

4092 

4093@inspection._self_inspects 

4094class FetchedValue(SchemaEventTarget): 

4095 """A marker for a transparent database-side default. 

4096 

4097 Use :class:`.FetchedValue` when the database is configured 

4098 to provide some automatic default for a column. 

4099 

4100 E.g.:: 

4101 

4102 Column("foo", Integer, FetchedValue()) 

4103 

4104 Would indicate that some trigger or default generator 

4105 will create a new value for the ``foo`` column during an 

4106 INSERT. 

4107 

4108 .. seealso:: 

4109 

4110 :ref:`triggered_columns` 

4111 

4112 """ 

4113 

4114 is_server_default = True 

4115 reflected = False 

4116 has_argument = False 

4117 is_clause_element = False 

4118 is_identity = False 

4119 

4120 column: Optional[Column[Any]] 

4121 

4122 def __init__(self, for_update: bool = False) -> None: 

4123 self.for_update = for_update 

4124 

4125 def _as_for_update(self, for_update: bool) -> FetchedValue: 

4126 if for_update == self.for_update: 

4127 return self 

4128 else: 

4129 return self._clone(for_update) 

4130 

4131 def _copy(self) -> FetchedValue: 

4132 return FetchedValue(self.for_update) 

4133 

4134 def _clone(self, for_update: bool) -> Self: 

4135 n = self.__class__.__new__(self.__class__) 

4136 n.__dict__.update(self.__dict__) 

4137 n.__dict__.pop("column", None) 

4138 n.for_update = for_update 

4139 return n 

4140 

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

4142 column = parent 

4143 assert isinstance(column, Column) 

4144 self.column = column 

4145 if self.for_update: 

4146 self.column.server_onupdate = self 

4147 else: 

4148 self.column.server_default = self 

4149 

4150 def __repr__(self) -> str: 

4151 return util.generic_repr(self) 

4152 

4153 

4154class DefaultClause(FetchedValue): 

4155 """A DDL-specified DEFAULT column value. 

4156 

4157 :class:`.DefaultClause` is a :class:`.FetchedValue` 

4158 that also generates a "DEFAULT" clause when 

4159 "CREATE TABLE" is emitted. 

4160 

4161 :class:`.DefaultClause` is generated automatically 

4162 whenever the ``server_default``, ``server_onupdate`` arguments of 

4163 :class:`_schema.Column` are used. A :class:`.DefaultClause` 

4164 can be passed positionally as well. 

4165 

4166 For example, the following:: 

4167 

4168 Column("foo", Integer, server_default="50") 

4169 

4170 Is equivalent to:: 

4171 

4172 Column("foo", Integer, DefaultClause("50")) 

4173 

4174 """ 

4175 

4176 has_argument = True 

4177 

4178 def __init__( 

4179 self, 

4180 arg: Union[str, ClauseElement, TextClause], 

4181 for_update: bool = False, 

4182 _reflected: bool = False, 

4183 ) -> None: 

4184 util.assert_arg_type(arg, (str, ClauseElement, TextClause), "arg") 

4185 super().__init__(for_update) 

4186 self.arg = arg 

4187 self.reflected = _reflected 

4188 

4189 def _copy(self) -> DefaultClause: 

4190 return DefaultClause( 

4191 arg=self.arg, for_update=self.for_update, _reflected=self.reflected 

4192 ) 

4193 

4194 def __repr__(self) -> str: 

4195 return "DefaultClause(%r, for_update=%r)" % (self.arg, self.for_update) 

4196 

4197 

4198class Constraint(DialectKWArgs, HasConditionalDDL, SchemaItem): 

4199 """A table-level SQL constraint. 

4200 

4201 :class:`_schema.Constraint` serves as the base class for the series of 

4202 constraint objects that can be associated with :class:`_schema.Table` 

4203 objects, including :class:`_schema.PrimaryKeyConstraint`, 

4204 :class:`_schema.ForeignKeyConstraint` 

4205 :class:`_schema.UniqueConstraint`, and 

4206 :class:`_schema.CheckConstraint`. 

4207 

4208 """ 

4209 

4210 __visit_name__ = "constraint" 

4211 

4212 _creation_order: int 

4213 _column_flag: bool 

4214 

4215 def __init__( 

4216 self, 

4217 name: _ConstraintNameArgument = None, 

4218 deferrable: Optional[bool] = None, 

4219 initially: Optional[str] = None, 

4220 info: Optional[_InfoType] = None, 

4221 comment: Optional[str] = None, 

4222 _create_rule: Optional[Any] = None, 

4223 _type_bound: bool = False, 

4224 **dialect_kw: Any, 

4225 ) -> None: 

4226 r"""Create a SQL constraint. 

4227 

4228 :param name: 

4229 Optional, the in-database name of this ``Constraint``. 

4230 

4231 :param deferrable: 

4232 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

4233 issuing DDL for this constraint. 

4234 

4235 :param initially: 

4236 Optional string. If set, emit INITIALLY <value> when issuing DDL 

4237 for this constraint. 

4238 

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

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

4241 

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

4243 foreign key constraint creation. 

4244 

4245 .. versionadded:: 2.0 

4246 

4247 :param \**dialect_kw: Additional keyword arguments are dialect 

4248 specific, and passed in the form ``<dialectname>_<argname>``. See 

4249 the documentation regarding an individual dialect at 

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

4251 

4252 :param _create_rule: 

4253 used internally by some datatypes that also create constraints. 

4254 

4255 :param _type_bound: 

4256 used internally to indicate that this constraint is associated with 

4257 a specific datatype. 

4258 

4259 """ 

4260 

4261 self.name = name 

4262 self.deferrable = deferrable 

4263 self.initially = initially 

4264 if info: 

4265 self.info = info 

4266 self._create_rule = _create_rule 

4267 self._type_bound = _type_bound 

4268 util.set_creation_order(self) 

4269 self._validate_dialect_kwargs(dialect_kw) 

4270 self.comment = comment 

4271 

4272 def _should_create_for_compiler( 

4273 self, compiler: DDLCompiler, **kw: Any 

4274 ) -> bool: 

4275 if self._create_rule is not None and not self._create_rule(compiler): 

4276 return False 

4277 elif self._ddl_if is not None: 

4278 return self._ddl_if._should_execute( 

4279 ddl.CreateConstraint(self), self, None, compiler=compiler, **kw 

4280 ) 

4281 else: 

4282 return True 

4283 

4284 @property 

4285 def table(self) -> Table: 

4286 try: 

4287 if isinstance(self.parent, Table): 

4288 return self.parent 

4289 except AttributeError: 

4290 pass 

4291 raise exc.InvalidRequestError( 

4292 "This constraint is not bound to a table. Did you " 

4293 "mean to call table.append_constraint(constraint) ?" 

4294 ) 

4295 

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

4297 assert isinstance(parent, (Table, Column)) 

4298 self.parent = parent 

4299 parent.constraints.add(self) 

4300 

4301 @util.deprecated( 

4302 "1.4", 

4303 "The :meth:`_schema.Constraint.copy` method is deprecated " 

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

4305 ) 

4306 def copy(self, **kw: Any) -> Self: 

4307 return self._copy(**kw) 

4308 

4309 def _copy(self, **kw: Any) -> Self: 

4310 raise NotImplementedError() 

4311 

4312 

4313class ColumnCollectionMixin: 

4314 """A :class:`_expression.ColumnCollection` of :class:`_schema.Column` 

4315 objects. 

4316 

4317 This collection represents the columns which are referred to by 

4318 this object. 

4319 

4320 """ 

4321 

4322 _columns: DedupeColumnCollection[Column[Any]] 

4323 

4324 _allow_multiple_tables = False 

4325 

4326 _pending_colargs: List[Optional[Union[str, Column[Any]]]] 

4327 

4328 if TYPE_CHECKING: 

4329 

4330 def _set_parent_with_dispatch( 

4331 self, parent: SchemaEventTarget, **kw: Any 

4332 ) -> None: ... 

4333 

4334 def __init__( 

4335 self, 

4336 *columns: _DDLColumnArgument, 

4337 _autoattach: bool = True, 

4338 _column_flag: bool = False, 

4339 _gather_expressions: Optional[ 

4340 List[Union[str, ColumnElement[Any]]] 

4341 ] = None, 

4342 ) -> None: 

4343 self._column_flag = _column_flag 

4344 self._columns = DedupeColumnCollection() 

4345 

4346 processed_expressions: Optional[ 

4347 List[Union[ColumnElement[Any], str]] 

4348 ] = _gather_expressions 

4349 

4350 if processed_expressions is not None: 

4351 

4352 # this is expected to be an empty list 

4353 assert not processed_expressions 

4354 

4355 self._pending_colargs = [] 

4356 for ( 

4357 expr, 

4358 _, 

4359 _, 

4360 add_element, 

4361 ) in coercions.expect_col_expression_collection( 

4362 roles.DDLConstraintColumnRole, columns 

4363 ): 

4364 self._pending_colargs.append(add_element) 

4365 processed_expressions.append(expr) 

4366 else: 

4367 self._pending_colargs = [ 

4368 coercions.expect(roles.DDLConstraintColumnRole, column) 

4369 for column in columns 

4370 ] 

4371 

4372 if _autoattach and self._pending_colargs: 

4373 self._check_attach() 

4374 

4375 def _check_attach(self, evt: bool = False) -> None: 

4376 col_objs = [c for c in self._pending_colargs if isinstance(c, Column)] 

4377 

4378 cols_w_table = [c for c in col_objs if isinstance(c.table, Table)] 

4379 

4380 cols_wo_table = set(col_objs).difference(cols_w_table) 

4381 if cols_wo_table: 

4382 # feature #3341 - place event listeners for Column objects 

4383 # such that when all those cols are attached, we autoattach. 

4384 assert not evt, "Should not reach here on event call" 

4385 

4386 # issue #3411 - don't do the per-column auto-attach if some of the 

4387 # columns are specified as strings. 

4388 has_string_cols = { 

4389 c for c in self._pending_colargs if c is not None 

4390 }.difference(col_objs) 

4391 if not has_string_cols: 

4392 

4393 def _col_attached(column: Column[Any], table: Table) -> None: 

4394 # this isinstance() corresponds with the 

4395 # isinstance() above; only want to count Table-bound 

4396 # columns 

4397 if isinstance(table, Table): 

4398 cols_wo_table.discard(column) 

4399 if not cols_wo_table: 

4400 self._check_attach(evt=True) 

4401 

4402 self._cols_wo_table = cols_wo_table 

4403 for col in cols_wo_table: 

4404 col._on_table_attach(_col_attached) 

4405 return 

4406 

4407 columns = cols_w_table 

4408 

4409 tables = {c.table for c in columns} 

4410 if len(tables) == 1: 

4411 self._set_parent_with_dispatch(tables.pop()) 

4412 elif len(tables) > 1 and not self._allow_multiple_tables: 

4413 table = columns[0].table 

4414 others = [c for c in columns[1:] if c.table is not table] 

4415 if others: 

4416 # black could not format this inline 

4417 other_str = ", ".join("'%s'" % c for c in others) 

4418 raise exc.ArgumentError( 

4419 f"Column(s) {other_str} " 

4420 f"are not part of table '{table.description}'." 

4421 ) 

4422 

4423 @util.ro_memoized_property 

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

4425 return self._columns.as_readonly() 

4426 

4427 @util.ro_memoized_property 

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

4429 return self._columns.as_readonly() 

4430 

4431 def _col_expressions( 

4432 self, parent: Union[Table, Column[Any]] 

4433 ) -> List[Optional[Column[Any]]]: 

4434 if isinstance(parent, Column): 

4435 result: List[Optional[Column[Any]]] = [ 

4436 c for c in self._pending_colargs if isinstance(c, Column) 

4437 ] 

4438 assert len(result) == len(self._pending_colargs) 

4439 return result 

4440 else: 

4441 try: 

4442 return [ 

4443 parent.c[col] if isinstance(col, str) else col 

4444 for col in self._pending_colargs 

4445 ] 

4446 except KeyError as ke: 

4447 raise exc.ConstraintColumnNotFoundError( 

4448 f"Can't create {self.__class__.__name__} " 

4449 f"on table '{parent.description}': no column " 

4450 f"named '{ke.args[0]}' is present." 

4451 ) from ke 

4452 

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

4454 assert isinstance(parent, (Table, Column)) 

4455 

4456 for col in self._col_expressions(parent): 

4457 if col is not None: 

4458 self._columns.add(col) 

4459 

4460 

4461class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint): 

4462 """A constraint that proxies a ColumnCollection.""" 

4463 

4464 def __init__( 

4465 self, 

4466 *columns: _DDLColumnArgument, 

4467 name: _ConstraintNameArgument = None, 

4468 deferrable: Optional[bool] = None, 

4469 initially: Optional[str] = None, 

4470 info: Optional[_InfoType] = None, 

4471 _autoattach: bool = True, 

4472 _column_flag: bool = False, 

4473 _gather_expressions: Optional[List[_DDLColumnArgument]] = None, 

4474 **dialect_kw: Any, 

4475 ) -> None: 

4476 r""" 

4477 :param \*columns: 

4478 A sequence of column names or Column objects. 

4479 

4480 :param name: 

4481 Optional, the in-database name of this constraint. 

4482 

4483 :param deferrable: 

4484 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

4485 issuing DDL for this constraint. 

4486 

4487 :param initially: 

4488 Optional string. If set, emit INITIALLY <value> when issuing DDL 

4489 for this constraint. 

4490 

4491 :param \**dialect_kw: other keyword arguments including 

4492 dialect-specific arguments are propagated to the :class:`.Constraint` 

4493 superclass. 

4494 

4495 """ 

4496 Constraint.__init__( 

4497 self, 

4498 name=name, 

4499 deferrable=deferrable, 

4500 initially=initially, 

4501 info=info, 

4502 **dialect_kw, 

4503 ) 

4504 ColumnCollectionMixin.__init__( 

4505 self, *columns, _autoattach=_autoattach, _column_flag=_column_flag 

4506 ) 

4507 

4508 columns: ReadOnlyColumnCollection[str, Column[Any]] 

4509 """A :class:`_expression.ColumnCollection` representing the set of columns 

4510 for this constraint. 

4511 

4512 """ 

4513 

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

4515 assert isinstance(parent, (Column, Table)) 

4516 Constraint._set_parent(self, parent) 

4517 ColumnCollectionMixin._set_parent(self, parent) 

4518 

4519 def __contains__(self, x: Any) -> bool: 

4520 return x in self._columns 

4521 

4522 @util.deprecated( 

4523 "1.4", 

4524 "The :meth:`_schema.ColumnCollectionConstraint.copy` method " 

4525 "is deprecated and will be removed in a future release.", 

4526 ) 

4527 def copy( 

4528 self, 

4529 *, 

4530 target_table: Optional[Table] = None, 

4531 **kw: Any, 

4532 ) -> ColumnCollectionConstraint: 

4533 return self._copy(target_table=target_table, **kw) 

4534 

4535 def _copy( 

4536 self, 

4537 *, 

4538 target_table: Optional[Table] = None, 

4539 **kw: Any, 

4540 ) -> ColumnCollectionConstraint: 

4541 # ticket #5276 

4542 constraint_kwargs = {} 

4543 for dialect_name in self.dialect_options: 

4544 dialect_options = self.dialect_options[dialect_name]._non_defaults 

4545 for ( 

4546 dialect_option_key, 

4547 dialect_option_value, 

4548 ) in dialect_options.items(): 

4549 constraint_kwargs[dialect_name + "_" + dialect_option_key] = ( 

4550 dialect_option_value 

4551 ) 

4552 

4553 assert isinstance(self.parent, Table) 

4554 c = self.__class__( 

4555 name=self.name, 

4556 deferrable=self.deferrable, 

4557 initially=self.initially, 

4558 *[ 

4559 _copy_expression(expr, self.parent, target_table) 

4560 for expr in self._columns 

4561 ], 

4562 comment=self.comment, 

4563 **constraint_kwargs, 

4564 ) 

4565 return self._schema_item_copy(c) 

4566 

4567 def contains_column(self, col: Column[Any]) -> bool: 

4568 """Return True if this constraint contains the given column. 

4569 

4570 Note that this object also contains an attribute ``.columns`` 

4571 which is a :class:`_expression.ColumnCollection` of 

4572 :class:`_schema.Column` objects. 

4573 

4574 """ 

4575 

4576 return self._columns.contains_column(col) 

4577 

4578 def __iter__(self) -> Iterator[Column[Any]]: 

4579 return iter(self._columns) 

4580 

4581 def __len__(self) -> int: 

4582 return len(self._columns) 

4583 

4584 

4585class CheckConstraint(ColumnCollectionConstraint): 

4586 """A table- or column-level CHECK constraint. 

4587 

4588 Can be included in the definition of a Table or Column. 

4589 """ 

4590 

4591 _allow_multiple_tables = True 

4592 

4593 __visit_name__ = "table_or_column_check_constraint" 

4594 

4595 @_document_text_coercion( 

4596 "sqltext", 

4597 ":class:`.CheckConstraint`", 

4598 ":paramref:`.CheckConstraint.sqltext`", 

4599 ) 

4600 def __init__( 

4601 self, 

4602 sqltext: _TextCoercedExpressionArgument[Any], 

4603 name: _ConstraintNameArgument = None, 

4604 deferrable: Optional[bool] = None, 

4605 initially: Optional[str] = None, 

4606 table: Optional[Table] = None, 

4607 info: Optional[_InfoType] = None, 

4608 _create_rule: Optional[Any] = None, 

4609 _autoattach: bool = True, 

4610 _type_bound: bool = False, 

4611 **dialect_kw: Any, 

4612 ) -> None: 

4613 r"""Construct a CHECK constraint. 

4614 

4615 :param sqltext: 

4616 A string containing the constraint definition, which will be used 

4617 verbatim, or a SQL expression construct. If given as a string, 

4618 the object is converted to a :func:`_expression.text` object. 

4619 If the textual 

4620 string includes a colon character, escape this using a backslash:: 

4621 

4622 CheckConstraint(r"foo ~ E'a(?\:b|c)d") 

4623 

4624 :param name: 

4625 Optional, the in-database name of the constraint. 

4626 

4627 :param deferrable: 

4628 Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 

4629 issuing DDL for this constraint. 

4630 

4631 :param initially: 

4632 Optional string. If set, emit INITIALLY <value> when issuing DDL 

4633 for this constraint. 

4634 

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

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

4637 

4638 """ 

4639 

4640 self.sqltext = coercions.expect(roles.DDLExpressionRole, sqltext) 

4641 columns: List[Column[Any]] = [] 

4642 visitors.traverse(self.sqltext, {}, {"column": columns.append}) 

4643 

4644 super().__init__( 

4645 name=name, 

4646 deferrable=deferrable, 

4647 initially=initially, 

4648 _create_rule=_create_rule, 

4649 info=info, 

4650 _type_bound=_type_bound, 

4651 _autoattach=_autoattach, 

4652 *columns, 

4653 **dialect_kw, 

4654 ) 

4655 if table is not None: 

4656 self._set_parent_with_dispatch(table) 

4657 

4658 @property 

4659 def is_column_level(self) -> bool: 

4660 return not isinstance(self.parent, Table) 

4661 

4662 @util.deprecated( 

4663 "1.4", 

4664 "The :meth:`_schema.CheckConstraint.copy` method is deprecated " 

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

4666 ) 

4667 def copy( 

4668 self, *, target_table: Optional[Table] = None, **kw: Any 

4669 ) -> CheckConstraint: 

4670 return self._copy(target_table=target_table, **kw) 

4671 

4672 def _copy( 

4673 self, *, target_table: Optional[Table] = None, **kw: Any 

4674 ) -> CheckConstraint: 

4675 if target_table is not None: 

4676 # note that target_table is None for the copy process of 

4677 # a column-bound CheckConstraint, so this path is not reached 

4678 # in that case. 

4679 sqltext = _copy_expression(self.sqltext, self.table, target_table) 

4680 else: 

4681 sqltext = self.sqltext 

4682 c = CheckConstraint( 

4683 sqltext, 

4684 name=self.name, 

4685 initially=self.initially, 

4686 deferrable=self.deferrable, 

4687 _create_rule=self._create_rule, 

4688 table=target_table, 

4689 comment=self.comment, 

4690 _autoattach=False, 

4691 _type_bound=self._type_bound, 

4692 ) 

4693 return self._schema_item_copy(c) 

4694 

4695 

4696class ForeignKeyConstraint(ColumnCollectionConstraint): 

4697 """A table-level FOREIGN KEY constraint. 

4698 

4699 Defines a single column or composite FOREIGN KEY ... REFERENCES 

4700 constraint. For a no-frills, single column foreign key, adding a 

4701 :class:`_schema.ForeignKey` to the definition of a :class:`_schema.Column` 

4702 is a 

4703 shorthand equivalent for an unnamed, single column 

4704 :class:`_schema.ForeignKeyConstraint`. 

4705 

4706 Examples of foreign key configuration are in :ref:`metadata_foreignkeys`. 

4707 

4708 """ 

4709 

4710 __visit_name__ = "foreign_key_constraint" 

4711 

4712 def __init__( 

4713 self, 

4714 columns: _typing_Sequence[_DDLColumnArgument], 

4715 refcolumns: _typing_Sequence[_DDLColumnReferenceArgument], 

4716 name: _ConstraintNameArgument = None, 

4717 onupdate: Optional[str] = None, 

4718 ondelete: Optional[str] = None, 

4719 deferrable: Optional[bool] = None, 

4720 initially: Optional[str] = None, 

4721 use_alter: bool = False, 

4722 link_to_name: bool = False, 

4723 match: Optional[str] = None, 

4724 table: Optional[Table] = None, 

4725 info: Optional[_InfoType] = None, 

4726 comment: Optional[str] = None, 

4727 **dialect_kw: Any, 

4728 ) -> None: 

4729 r"""Construct a composite-capable FOREIGN KEY. 

4730 

4731 :param columns: A sequence of local column names. The named columns 

4732 must be defined and present in the parent Table. The names should 

4733 match the ``key`` given to each column (defaults to the name) unless 

4734 ``link_to_name`` is True. 

4735 

4736 :param refcolumns: A sequence of foreign column names or Column 

4737 objects. The columns must all be located within the same Table. 

4738 

4739 :param name: Optional, the in-database name of the key. 

4740 

4741 :param onupdate: Optional string. If set, emit ON UPDATE <value> when 

4742 issuing DDL for this constraint. Typical values include CASCADE, 

4743 DELETE and RESTRICT. 

4744 

4745 .. seealso:: 

4746 

4747 :ref:`on_update_on_delete` 

4748 

4749 :param ondelete: Optional string. If set, emit ON DELETE <value> when 

4750 issuing DDL for this constraint. Typical values include CASCADE, 

4751 SET NULL and RESTRICT. Some dialects may allow for additional 

4752 syntaxes. 

4753 

4754 .. seealso:: 

4755 

4756 :ref:`on_update_on_delete` 

4757 

4758 :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT 

4759 DEFERRABLE when issuing DDL for this constraint. 

4760 

4761 :param initially: Optional string. If set, emit INITIALLY <value> when 

4762 issuing DDL for this constraint. 

4763 

4764 :param link_to_name: if True, the string name given in ``column`` is 

4765 the rendered name of the referenced column, not its locally assigned 

4766 ``key``. 

4767 

4768 :param use_alter: If True, do not emit the DDL for this constraint as 

4769 part of the CREATE TABLE definition. Instead, generate it via an 

4770 ALTER TABLE statement issued after the full collection of tables 

4771 have been created, and drop it via an ALTER TABLE statement before 

4772 the full collection of tables are dropped. 

4773 

4774 The use of :paramref:`_schema.ForeignKeyConstraint.use_alter` is 

4775 particularly geared towards the case where two or more tables 

4776 are established within a mutually-dependent foreign key constraint 

4777 relationship; however, the :meth:`_schema.MetaData.create_all` and 

4778 :meth:`_schema.MetaData.drop_all` 

4779 methods will perform this resolution 

4780 automatically, so the flag is normally not needed. 

4781 

4782 .. seealso:: 

4783 

4784 :ref:`use_alter` 

4785 

4786 :param match: Optional string. If set, emit MATCH <value> when issuing 

4787 DDL for this constraint. Typical values include SIMPLE, PARTIAL 

4788 and FULL. 

4789 

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

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

4792 

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

4794 foreign key constraint creation. 

4795 

4796 .. versionadded:: 2.0 

4797 

4798 :param \**dialect_kw: Additional keyword arguments are dialect 

4799 specific, and passed in the form ``<dialectname>_<argname>``. See 

4800 the documentation regarding an individual dialect at 

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

4802 

4803 """ 

4804 

4805 Constraint.__init__( 

4806 self, 

4807 name=name, 

4808 deferrable=deferrable, 

4809 initially=initially, 

4810 info=info, 

4811 comment=comment, 

4812 **dialect_kw, 

4813 ) 

4814 self.onupdate = onupdate 

4815 self.ondelete = ondelete 

4816 self.link_to_name = link_to_name 

4817 self.use_alter = use_alter 

4818 self.match = match 

4819 

4820 if len(set(columns)) != len(refcolumns): 

4821 if len(set(columns)) != len(columns): 

4822 # e.g. FOREIGN KEY (a, a) REFERENCES r (b, c) 

4823 raise exc.ArgumentError( 

4824 "ForeignKeyConstraint with duplicate source column " 

4825 "references are not supported." 

4826 ) 

4827 else: 

4828 # e.g. FOREIGN KEY (a) REFERENCES r (b, c) 

4829 # paraphrasing 

4830 # https://www.postgresql.org/docs/current/static/ddl-constraints.html 

4831 raise exc.ArgumentError( 

4832 "ForeignKeyConstraint number " 

4833 "of constrained columns must match the number of " 

4834 "referenced columns." 

4835 ) 

4836 

4837 # standalone ForeignKeyConstraint - create 

4838 # associated ForeignKey objects which will be applied to hosted 

4839 # Column objects (in col.foreign_keys), either now or when attached 

4840 # to the Table for string-specified names 

4841 self.elements = [ 

4842 ForeignKey( 

4843 refcol, 

4844 _constraint=self, 

4845 name=self.name, 

4846 onupdate=self.onupdate, 

4847 ondelete=self.ondelete, 

4848 use_alter=self.use_alter, 

4849 link_to_name=self.link_to_name, 

4850 match=self.match, 

4851 deferrable=self.deferrable, 

4852 initially=self.initially, 

4853 **self.dialect_kwargs, 

4854 ) 

4855 for refcol in refcolumns 

4856 ] 

4857 

4858 ColumnCollectionMixin.__init__(self, *columns) 

4859 if table is not None: 

4860 if hasattr(self, "parent"): 

4861 assert table is self.parent 

4862 self._set_parent_with_dispatch(table) 

4863 

4864 def _append_element(self, column: Column[Any], fk: ForeignKey) -> None: 

4865 self._columns.add(column) 

4866 self.elements.append(fk) 

4867 

4868 columns: ReadOnlyColumnCollection[str, Column[Any]] 

4869 """A :class:`_expression.ColumnCollection` representing the set of columns 

4870 for this constraint. 

4871 

4872 """ 

4873 

4874 elements: List[ForeignKey] 

4875 """A sequence of :class:`_schema.ForeignKey` objects. 

4876 

4877 Each :class:`_schema.ForeignKey` 

4878 represents a single referring column/referred 

4879 column pair. 

4880 

4881 This collection is intended to be read-only. 

4882 

4883 """ 

4884 

4885 @property 

4886 def _elements(self) -> util.OrderedDict[str, ForeignKey]: 

4887 # legacy - provide a dictionary view of (column_key, fk) 

4888 return util.OrderedDict(zip(self.column_keys, self.elements)) 

4889 

4890 @property 

4891 def _referred_schema(self) -> Optional[str]: 

4892 for elem in self.elements: 

4893 return elem._referred_schema 

4894 else: 

4895 return None 

4896 

4897 @property 

4898 def referred_table(self) -> Table: 

4899 """The :class:`_schema.Table` object to which this 

4900 :class:`_schema.ForeignKeyConstraint` references. 

4901 

4902 This is a dynamically calculated attribute which may not be available 

4903 if the constraint and/or parent table is not yet associated with 

4904 a metadata collection that contains the referred table. 

4905 

4906 """ 

4907 return self.elements[0].column.table 

4908 

4909 def _validate_dest_table(self, table: Table) -> None: 

4910 table_keys = { 

4911 elem._table_key_within_construction() for elem in self.elements 

4912 } 

4913 if None not in table_keys and len(table_keys) > 1: 

4914 elem0, elem1 = sorted(table_keys)[0:2] 

4915 raise exc.ArgumentError( 

4916 f"ForeignKeyConstraint on " 

4917 f"{table.fullname}({self._col_description}) refers to " 

4918 f"multiple remote tables: {elem0} and {elem1}" 

4919 ) 

4920 

4921 @property 

4922 def column_keys(self) -> _typing_Sequence[str]: 

4923 """Return a list of string keys representing the local 

4924 columns in this :class:`_schema.ForeignKeyConstraint`. 

4925 

4926 This list is either the original string arguments sent 

4927 to the constructor of the :class:`_schema.ForeignKeyConstraint`, 

4928 or if the constraint has been initialized with :class:`_schema.Column` 

4929 objects, is the string ``.key`` of each element. 

4930 

4931 """ 

4932 if hasattr(self, "parent"): 

4933 return self._columns.keys() 

4934 else: 

4935 return [ 

4936 col.key if isinstance(col, ColumnElement) else str(col) 

4937 for col in self._pending_colargs 

4938 ] 

4939 

4940 @property 

4941 def _col_description(self) -> str: 

4942 return ", ".join(self.column_keys) 

4943 

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

4945 table = parent 

4946 assert isinstance(table, Table) 

4947 Constraint._set_parent(self, table) 

4948 

4949 ColumnCollectionConstraint._set_parent(self, table) 

4950 

4951 for col, fk in zip(self._columns, self.elements): 

4952 if not hasattr(fk, "parent") or fk.parent is not col: 

4953 fk._set_parent_with_dispatch(col) 

4954 

4955 self._validate_dest_table(table) 

4956 

4957 @util.deprecated( 

4958 "1.4", 

4959 "The :meth:`_schema.ForeignKeyConstraint.copy` method is deprecated " 

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

4961 ) 

4962 def copy( 

4963 self, 

4964 *, 

4965 schema: Optional[str] = None, 

4966 target_table: Optional[Table] = None, 

4967 **kw: Any, 

4968 ) -> ForeignKeyConstraint: 

4969 return self._copy(schema=schema, target_table=target_table, **kw) 

4970 

4971 def _copy( 

4972 self, 

4973 *, 

4974 schema: Optional[str] = None, 

4975 target_table: Optional[Table] = None, 

4976 **kw: Any, 

4977 ) -> ForeignKeyConstraint: 

4978 fkc = ForeignKeyConstraint( 

4979 [x.parent.key for x in self.elements], 

4980 [ 

4981 x._get_colspec( 

4982 schema=schema, 

4983 table_name=( 

4984 target_table.name 

4985 if target_table is not None 

4986 and x._table_key_within_construction() 

4987 == x.parent.table.key 

4988 else None 

4989 ), 

4990 _is_copy=True, 

4991 ) 

4992 for x in self.elements 

4993 ], 

4994 name=self.name, 

4995 onupdate=self.onupdate, 

4996 ondelete=self.ondelete, 

4997 use_alter=self.use_alter, 

4998 deferrable=self.deferrable, 

4999 initially=self.initially, 

5000 link_to_name=self.link_to_name, 

5001 match=self.match, 

5002 comment=self.comment, 

5003 ) 

5004 for self_fk, other_fk in zip(self.elements, fkc.elements): 

5005 self_fk._schema_item_copy(other_fk) 

5006 return self._schema_item_copy(fkc) 

5007 

5008 

5009class PrimaryKeyConstraint(ColumnCollectionConstraint): 

5010 """A table-level PRIMARY KEY constraint. 

5011 

5012 The :class:`.PrimaryKeyConstraint` object is present automatically 

5013 on any :class:`_schema.Table` object; it is assigned a set of 

5014 :class:`_schema.Column` objects corresponding to those marked with 

5015 the :paramref:`_schema.Column.primary_key` flag:: 

5016 

5017 >>> my_table = Table( 

5018 ... "mytable", 

5019 ... metadata, 

5020 ... Column("id", Integer, primary_key=True), 

5021 ... Column("version_id", Integer, primary_key=True), 

5022 ... Column("data", String(50)), 

5023 ... ) 

5024 >>> my_table.primary_key 

5025 PrimaryKeyConstraint( 

5026 Column('id', Integer(), table=<mytable>, 

5027 primary_key=True, nullable=False), 

5028 Column('version_id', Integer(), table=<mytable>, 

5029 primary_key=True, nullable=False) 

5030 ) 

5031 

5032 The primary key of a :class:`_schema.Table` can also be specified by using 

5033 a :class:`.PrimaryKeyConstraint` object explicitly; in this mode of usage, 

5034 the "name" of the constraint can also be specified, as well as other 

5035 options which may be recognized by dialects:: 

5036 

5037 my_table = Table( 

5038 "mytable", 

5039 metadata, 

5040 Column("id", Integer), 

5041 Column("version_id", Integer), 

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

5043 PrimaryKeyConstraint("id", "version_id", name="mytable_pk"), 

5044 ) 

5045 

5046 The two styles of column-specification should generally not be mixed. 

5047 An warning is emitted if the columns present in the 

5048 :class:`.PrimaryKeyConstraint` 

5049 don't match the columns that were marked as ``primary_key=True``, if both 

5050 are present; in this case, the columns are taken strictly from the 

5051 :class:`.PrimaryKeyConstraint` declaration, and those columns otherwise 

5052 marked as ``primary_key=True`` are ignored. This behavior is intended to 

5053 be backwards compatible with previous behavior. 

5054 

5055 For the use case where specific options are to be specified on the 

5056 :class:`.PrimaryKeyConstraint`, but the usual style of using 

5057 ``primary_key=True`` flags is still desirable, an empty 

5058 :class:`.PrimaryKeyConstraint` may be specified, which will take on the 

5059 primary key column collection from the :class:`_schema.Table` based on the 

5060 flags:: 

5061 

5062 my_table = Table( 

5063 "mytable", 

5064 metadata, 

5065 Column("id", Integer, primary_key=True), 

5066 Column("version_id", Integer, primary_key=True), 

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

5068 PrimaryKeyConstraint(name="mytable_pk", mssql_clustered=True), 

5069 ) 

5070 

5071 """ 

5072 

5073 __visit_name__ = "primary_key_constraint" 

5074 

5075 def __init__( 

5076 self, 

5077 *columns: _DDLColumnArgument, 

5078 name: Optional[str] = None, 

5079 deferrable: Optional[bool] = None, 

5080 initially: Optional[str] = None, 

5081 info: Optional[_InfoType] = None, 

5082 _implicit_generated: bool = False, 

5083 **dialect_kw: Any, 

5084 ) -> None: 

5085 self._implicit_generated = _implicit_generated 

5086 super().__init__( 

5087 *columns, 

5088 name=name, 

5089 deferrable=deferrable, 

5090 initially=initially, 

5091 info=info, 

5092 **dialect_kw, 

5093 ) 

5094 

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

5096 table = parent 

5097 assert isinstance(table, Table) 

5098 super()._set_parent(table) 

5099 

5100 if table.primary_key is not self: 

5101 table.constraints.discard(table.primary_key) 

5102 table.primary_key = self # type: ignore 

5103 table.constraints.add(self) 

5104 

5105 table_pks = [c for c in table.c if c.primary_key] 

5106 if ( 

5107 self._columns 

5108 and table_pks 

5109 and set(table_pks) != set(self._columns) 

5110 ): 

5111 # black could not format these inline 

5112 table_pk_str = ", ".join("'%s'" % c.name for c in table_pks) 

5113 col_str = ", ".join("'%s'" % c.name for c in self._columns) 

5114 

5115 util.warn( 

5116 f"Table '{table.name}' specifies columns " 

5117 f"{table_pk_str} as " 

5118 f"primary_key=True, " 

5119 f"not matching locally specified columns {col_str}; " 

5120 f"setting the " 

5121 f"current primary key columns to " 

5122 f"{col_str}. " 

5123 f"This warning " 

5124 f"may become an exception in a future release" 

5125 ) 

5126 table_pks[:] = [] 

5127 

5128 for c in self._columns: 

5129 c.primary_key = True 

5130 if c._user_defined_nullable is NULL_UNSPECIFIED: 

5131 c.nullable = False 

5132 if table_pks: 

5133 self._columns.extend(table_pks) 

5134 

5135 def _reload(self, columns: Iterable[Column[Any]]) -> None: 

5136 """repopulate this :class:`.PrimaryKeyConstraint` given 

5137 a set of columns. 

5138 

5139 Existing columns in the table that are marked as primary_key=True 

5140 are maintained. 

5141 

5142 Also fires a new event. 

5143 

5144 This is basically like putting a whole new 

5145 :class:`.PrimaryKeyConstraint` object on the parent 

5146 :class:`_schema.Table` object without actually replacing the object. 

5147 

5148 The ordering of the given list of columns is also maintained; these 

5149 columns will be appended to the list of columns after any which 

5150 are already present. 

5151 

5152 """ 

5153 # set the primary key flag on new columns. 

5154 # note any existing PK cols on the table also have their 

5155 # flag still set. 

5156 for col in columns: 

5157 col.primary_key = True 

5158 

5159 self._columns.extend(columns) 

5160 

5161 PrimaryKeyConstraint._autoincrement_column._reset(self) # type: ignore 

5162 self._set_parent_with_dispatch(self.table) 

5163 

5164 def _replace(self, col: Column[Any]) -> None: 

5165 PrimaryKeyConstraint._autoincrement_column._reset(self) # type: ignore 

5166 self._columns.replace(col) 

5167 

5168 self.dispatch._sa_event_column_added_to_pk_constraint(self, col) 

5169 

5170 @property 

5171 def columns_autoinc_first(self) -> List[Column[Any]]: 

5172 autoinc = self._autoincrement_column 

5173 

5174 if autoinc is not None: 

5175 return [autoinc] + [c for c in self._columns if c is not autoinc] 

5176 else: 

5177 return list(self._columns) 

5178 

5179 @util.ro_memoized_property 

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

5181 def _validate_autoinc(col: Column[Any], autoinc_true: bool) -> bool: 

5182 if col.type._type_affinity is not None and issubclass( 

5183 col.type._type_affinity, type_api.NUMERICTYPE._type_affinity 

5184 ): 

5185 scale = col.type.scale # type: ignore[attr-defined] 

5186 if scale != 0 and autoinc_true: 

5187 raise exc.ArgumentError( 

5188 f"Column type {col.type} with non-zero scale " 

5189 f"{scale} on column '{col}' is not " 

5190 f"compatible with autoincrement=True" 

5191 ) 

5192 elif not autoinc_true: 

5193 return False 

5194 elif col.type._type_affinity is None or not issubclass( 

5195 col.type._type_affinity, type_api.INTEGERTYPE._type_affinity 

5196 ): 

5197 if autoinc_true: 

5198 raise exc.ArgumentError( 

5199 f"Column type {col.type} on column '{col}' is not " 

5200 f"compatible with autoincrement=True" 

5201 ) 

5202 else: 

5203 return False 

5204 elif ( 

5205 col.default is not None 

5206 and not isinstance(col.default, Sequence) 

5207 and not autoinc_true 

5208 ): 

5209 return False 

5210 elif ( 

5211 col.server_default is not None 

5212 and not isinstance(col.server_default, Identity) 

5213 and not autoinc_true 

5214 ): 

5215 return False 

5216 elif col.foreign_keys and col.autoincrement not in ( 

5217 True, 

5218 "ignore_fk", 

5219 ): 

5220 return False 

5221 return True 

5222 

5223 if len(self._columns) == 1: 

5224 col = list(self._columns)[0] 

5225 

5226 if col.autoincrement is True: 

5227 _validate_autoinc(col, True) 

5228 return col 

5229 elif col.autoincrement in ( 

5230 "auto", 

5231 "ignore_fk", 

5232 ) and _validate_autoinc(col, False): 

5233 return col 

5234 else: 

5235 return None 

5236 

5237 else: 

5238 autoinc = None 

5239 for col in self._columns: 

5240 if col.autoincrement is True: 

5241 _validate_autoinc(col, True) 

5242 if autoinc is not None: 

5243 raise exc.ArgumentError( 

5244 f"Only one Column may be marked " 

5245 f"autoincrement=True, found both " 

5246 f"{col.name} and {autoinc.name}." 

5247 ) 

5248 else: 

5249 autoinc = col 

5250 

5251 return autoinc 

5252 

5253 

5254class UniqueConstraint(ColumnCollectionConstraint): 

5255 """A table-level UNIQUE constraint. 

5256 

5257 Defines a single column or composite UNIQUE constraint. For a no-frills, 

5258 single column constraint, adding ``unique=True`` to the ``Column`` 

5259 definition is a shorthand equivalent for an unnamed, single column 

5260 UniqueConstraint. 

5261 """ 

5262 

5263 __visit_name__ = "unique_constraint" 

5264 

5265 

5266class Index( 

5267 DialectKWArgs, ColumnCollectionMixin, HasConditionalDDL, SchemaItem 

5268): 

5269 """A table-level INDEX. 

5270 

5271 Defines a composite (one or more column) INDEX. 

5272 

5273 E.g.:: 

5274 

5275 sometable = Table( 

5276 "sometable", 

5277 metadata, 

5278 Column("name", String(50)), 

5279 Column("address", String(100)), 

5280 ) 

5281 

5282 Index("some_index", sometable.c.name) 

5283 

5284 For a no-frills, single column index, adding 

5285 :class:`_schema.Column` also supports ``index=True``:: 

5286 

5287 sometable = Table( 

5288 "sometable", metadata, Column("name", String(50), index=True) 

5289 ) 

5290 

5291 For a composite index, multiple columns can be specified:: 

5292 

5293 Index("some_index", sometable.c.name, sometable.c.address) 

5294 

5295 Functional indexes are supported as well, typically by using the 

5296 :data:`.func` construct in conjunction with table-bound 

5297 :class:`_schema.Column` objects:: 

5298 

5299 Index("some_index", func.lower(sometable.c.name)) 

5300 

5301 An :class:`.Index` can also be manually associated with a 

5302 :class:`_schema.Table`, 

5303 either through inline declaration or using 

5304 :meth:`_schema.Table.append_constraint`. When this approach is used, 

5305 the names 

5306 of the indexed columns can be specified as strings:: 

5307 

5308 Table( 

5309 "sometable", 

5310 metadata, 

5311 Column("name", String(50)), 

5312 Column("address", String(100)), 

5313 Index("some_index", "name", "address"), 

5314 ) 

5315 

5316 To support functional or expression-based indexes in this form, the 

5317 :func:`_expression.text` construct may be used:: 

5318 

5319 from sqlalchemy import text 

5320 

5321 Table( 

5322 "sometable", 

5323 metadata, 

5324 Column("name", String(50)), 

5325 Column("address", String(100)), 

5326 Index("some_index", text("lower(name)")), 

5327 ) 

5328 

5329 .. seealso:: 

5330 

5331 :ref:`schema_indexes` - General information on :class:`.Index`. 

5332 

5333 :ref:`postgresql_indexes` - PostgreSQL-specific options available for 

5334 the :class:`.Index` construct. 

5335 

5336 :ref:`mysql_indexes` - MySQL-specific options available for the 

5337 :class:`.Index` construct. 

5338 

5339 :ref:`mssql_indexes` - MSSQL-specific options available for the 

5340 :class:`.Index` construct. 

5341 

5342 """ 

5343 

5344 __visit_name__ = "index" 

5345 

5346 table: Optional[Table] 

5347 expressions: _typing_Sequence[Union[str, ColumnElement[Any]]] 

5348 _table_bound_expressions: _typing_Sequence[ColumnElement[Any]] 

5349 

5350 def __init__( 

5351 self, 

5352 name: Optional[str], 

5353 *expressions: _DDLColumnArgument, 

5354 unique: bool = False, 

5355 quote: Optional[bool] = None, 

5356 info: Optional[_InfoType] = None, 

5357 _table: Optional[Table] = None, 

5358 _column_flag: bool = False, 

5359 **dialect_kw: Any, 

5360 ) -> None: 

5361 r"""Construct an index object. 

5362 

5363 :param name: 

5364 The name of the index 

5365 

5366 :param \*expressions: 

5367 Column expressions to include in the index. The expressions 

5368 are normally instances of :class:`_schema.Column`, but may also 

5369 be arbitrary SQL expressions which ultimately refer to a 

5370 :class:`_schema.Column`. 

5371 

5372 :param unique=False: 

5373 Keyword only argument; if True, create a unique index. 

5374 

5375 :param quote=None: 

5376 Keyword only argument; whether to apply quoting to the name of 

5377 the index. Works in the same manner as that of 

5378 :paramref:`_schema.Column.quote`. 

5379 

5380 :param info=None: Optional data dictionary which will be populated 

5381 into the :attr:`.SchemaItem.info` attribute of this object. 

5382 

5383 :param \**dialect_kw: Additional keyword arguments not mentioned above 

5384 are dialect specific, and passed in the form 

5385 ``<dialectname>_<argname>``. See the documentation regarding an 

5386 individual dialect at :ref:`dialect_toplevel` for detail on 

5387 documented arguments. 

5388 

5389 """ 

5390 self.table = table = None 

5391 

5392 self.name = quoted_name.construct(name, quote) 

5393 self.unique = unique 

5394 if info is not None: 

5395 self.info = info 

5396 

5397 # TODO: consider "table" argument being public, but for 

5398 # the purpose of the fix here, it starts as private. 

5399 if _table is not None: 

5400 table = _table 

5401 

5402 self._validate_dialect_kwargs(dialect_kw) 

5403 

5404 self.expressions = [] 

5405 # will call _set_parent() if table-bound column 

5406 # objects are present 

5407 ColumnCollectionMixin.__init__( 

5408 self, 

5409 *expressions, 

5410 _column_flag=_column_flag, 

5411 _gather_expressions=self.expressions, 

5412 ) 

5413 if table is not None: 

5414 self._set_parent(table) 

5415 

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

5417 table = parent 

5418 assert isinstance(table, Table) 

5419 ColumnCollectionMixin._set_parent(self, table) 

5420 

5421 if self.table is not None and table is not self.table: 

5422 raise exc.ArgumentError( 

5423 f"Index '{self.name}' is against table " 

5424 f"'{self.table.description}', and " 

5425 f"cannot be associated with table '{table.description}'." 

5426 ) 

5427 self.table = table 

5428 table.indexes.add(self) 

5429 

5430 expressions = self.expressions 

5431 col_expressions = self._col_expressions(table) 

5432 assert len(expressions) == len(col_expressions) 

5433 

5434 exprs = [] 

5435 for expr, colexpr in zip(expressions, col_expressions): 

5436 if isinstance(expr, ClauseElement): 

5437 exprs.append(expr) 

5438 elif colexpr is not None: 

5439 exprs.append(colexpr) 

5440 else: 

5441 assert False 

5442 self.expressions = self._table_bound_expressions = exprs 

5443 

5444 def create(self, bind: _CreateDropBind, checkfirst: bool = False) -> None: 

5445 """Issue a ``CREATE`` statement for this 

5446 :class:`.Index`, using the given 

5447 :class:`.Connection` or :class:`.Engine`` for connectivity. 

5448 

5449 .. seealso:: 

5450 

5451 :meth:`_schema.MetaData.create_all`. 

5452 

5453 """ 

5454 bind._run_ddl_visitor(ddl.SchemaGenerator, self, checkfirst=checkfirst) 

5455 

5456 def drop(self, bind: _CreateDropBind, checkfirst: bool = False) -> None: 

5457 """Issue a ``DROP`` statement for this 

5458 :class:`.Index`, using the given 

5459 :class:`.Connection` or :class:`.Engine` for connectivity. 

5460 

5461 .. seealso:: 

5462 

5463 :meth:`_schema.MetaData.drop_all`. 

5464 

5465 """ 

5466 bind._run_ddl_visitor(ddl.SchemaDropper, self, checkfirst=checkfirst) 

5467 

5468 def __repr__(self) -> str: 

5469 exprs: _typing_Sequence[Any] # noqa: F842 

5470 

5471 return "Index(%s)" % ( 

5472 ", ".join( 

5473 [repr(self.name)] 

5474 + [repr(e) for e in self.expressions] 

5475 + (self.unique and ["unique=True"] or []) 

5476 ) 

5477 ) 

5478 

5479 

5480_NamingSchemaCallable = Callable[[Constraint, Table], str] 

5481_NamingSchemaDirective = Union[str, _NamingSchemaCallable] 

5482 

5483 

5484class _NamingSchemaTD(TypedDict, total=False): 

5485 fk: _NamingSchemaDirective 

5486 pk: _NamingSchemaDirective 

5487 ix: _NamingSchemaDirective 

5488 ck: _NamingSchemaDirective 

5489 uq: _NamingSchemaDirective 

5490 

5491 

5492_NamingSchemaParameter = Union[ 

5493 # it seems like the TypedDict here is useful for pylance typeahead, 

5494 # and not much else 

5495 _NamingSchemaTD, 

5496 # there is no form that allows Union[Type[Any], str] to work in all 

5497 # cases, including breaking out Mapping[] entries for each combination 

5498 # even, therefore keys must be `Any` (see #10264) 

5499 Mapping[Any, _NamingSchemaDirective], 

5500] 

5501 

5502 

5503DEFAULT_NAMING_CONVENTION: _NamingSchemaParameter = util.immutabledict( 

5504 {"ix": "ix_%(column_0_label)s"} 

5505) 

5506 

5507 

5508class MetaData(HasSchemaAttr): 

5509 """A collection of :class:`_schema.Table` 

5510 objects and their associated schema 

5511 constructs. 

5512 

5513 Holds a collection of :class:`_schema.Table` objects as well as 

5514 an optional binding to an :class:`_engine.Engine` or 

5515 :class:`_engine.Connection`. If bound, the :class:`_schema.Table` objects 

5516 in the collection and their columns may participate in implicit SQL 

5517 execution. 

5518 

5519 The :class:`_schema.Table` objects themselves are stored in the 

5520 :attr:`_schema.MetaData.tables` dictionary. 

5521 

5522 :class:`_schema.MetaData` is a thread-safe object for read operations. 

5523 Construction of new tables within a single :class:`_schema.MetaData` 

5524 object, 

5525 either explicitly or via reflection, may not be completely thread-safe. 

5526 

5527 .. seealso:: 

5528 

5529 :ref:`metadata_describing` - Introduction to database metadata 

5530 

5531 """ 

5532 

5533 __visit_name__ = "metadata" 

5534 

5535 def __init__( 

5536 self, 

5537 schema: Optional[str] = None, 

5538 quote_schema: Optional[bool] = None, 

5539 naming_convention: Optional[_NamingSchemaParameter] = None, 

5540 info: Optional[_InfoType] = None, 

5541 ) -> None: 

5542 """Create a new MetaData object. 

5543 

5544 :param schema: 

5545 The default schema to use for the :class:`_schema.Table`, 

5546 :class:`.Sequence`, and potentially other objects associated with 

5547 this :class:`_schema.MetaData`. Defaults to ``None``. 

5548 

5549 .. seealso:: 

5550 

5551 :ref:`schema_metadata_schema_name` - details on how the 

5552 :paramref:`_schema.MetaData.schema` parameter is used. 

5553 

5554 :paramref:`_schema.Table.schema` 

5555 

5556 :paramref:`.Sequence.schema` 

5557 

5558 :param quote_schema: 

5559 Sets the ``quote_schema`` flag for those :class:`_schema.Table`, 

5560 :class:`.Sequence`, and other objects which make usage of the 

5561 local ``schema`` name. 

5562 

5563 :param info: Optional data dictionary which will be populated into the 

5564 :attr:`.SchemaItem.info` attribute of this object. 

5565 

5566 :param naming_convention: a dictionary referring to values which 

5567 will establish default naming conventions for :class:`.Constraint` 

5568 and :class:`.Index` objects, for those objects which are not given 

5569 a name explicitly. 

5570 

5571 The keys of this dictionary may be: 

5572 

5573 * a constraint or Index class, e.g. the :class:`.UniqueConstraint`, 

5574 :class:`_schema.ForeignKeyConstraint` class, the :class:`.Index` 

5575 class 

5576 

5577 * a string mnemonic for one of the known constraint classes; 

5578 ``"fk"``, ``"pk"``, ``"ix"``, ``"ck"``, ``"uq"`` for foreign key, 

5579 primary key, index, check, and unique constraint, respectively. 

5580 

5581 * the string name of a user-defined "token" that can be used 

5582 to define new naming tokens. 

5583 

5584 The values associated with each "constraint class" or "constraint 

5585 mnemonic" key are string naming templates, such as 

5586 ``"uq_%(table_name)s_%(column_0_name)s"``, 

5587 which describe how the name should be composed. The values 

5588 associated with user-defined "token" keys should be callables of the 

5589 form ``fn(constraint, table)``, which accepts the constraint/index 

5590 object and :class:`_schema.Table` as arguments, returning a string 

5591 result. 

5592 

5593 The built-in names are as follows, some of which may only be 

5594 available for certain types of constraint: 

5595 

5596 * ``%(table_name)s`` - the name of the :class:`_schema.Table` 

5597 object 

5598 associated with the constraint. 

5599 

5600 * ``%(referred_table_name)s`` - the name of the 

5601 :class:`_schema.Table` 

5602 object associated with the referencing target of a 

5603 :class:`_schema.ForeignKeyConstraint`. 

5604 

5605 * ``%(column_0_name)s`` - the name of the :class:`_schema.Column` 

5606 at 

5607 index position "0" within the constraint. 

5608 

5609 * ``%(column_0N_name)s`` - the name of all :class:`_schema.Column` 

5610 objects in order within the constraint, joined without a 

5611 separator. 

5612 

5613 * ``%(column_0_N_name)s`` - the name of all 

5614 :class:`_schema.Column` 

5615 objects in order within the constraint, joined with an 

5616 underscore as a separator. 

5617 

5618 * ``%(column_0_label)s``, ``%(column_0N_label)s``, 

5619 ``%(column_0_N_label)s`` - the label of either the zeroth 

5620 :class:`_schema.Column` or all :class:`.Columns`, separated with 

5621 or without an underscore 

5622 

5623 * ``%(column_0_key)s``, ``%(column_0N_key)s``, 

5624 ``%(column_0_N_key)s`` - the key of either the zeroth 

5625 :class:`_schema.Column` or all :class:`.Columns`, separated with 

5626 or without an underscore 

5627 

5628 * ``%(referred_column_0_name)s``, ``%(referred_column_0N_name)s`` 

5629 ``%(referred_column_0_N_name)s``, ``%(referred_column_0_key)s``, 

5630 ``%(referred_column_0N_key)s``, ... column tokens which 

5631 render the names/keys/labels of columns that are referenced 

5632 by a :class:`_schema.ForeignKeyConstraint`. 

5633 

5634 * ``%(constraint_name)s`` - a special key that refers to the 

5635 existing name given to the constraint. When this key is 

5636 present, the :class:`.Constraint` object's existing name will be 

5637 replaced with one that is composed from template string that 

5638 uses this token. When this token is present, it is required that 

5639 the :class:`.Constraint` is given an explicit name ahead of time. 

5640 

5641 * user-defined: any additional token may be implemented by passing 

5642 it along with a ``fn(constraint, table)`` callable to the 

5643 naming_convention dictionary. 

5644 

5645 .. seealso:: 

5646 

5647 :ref:`constraint_naming_conventions` - for detailed usage 

5648 examples. 

5649 

5650 """ 

5651 if schema is not None and not isinstance(schema, str): 

5652 raise exc.ArgumentError( 

5653 "expected schema argument to be a string, " 

5654 f"got {type(schema)}." 

5655 ) 

5656 self.tables = util.FacadeDict() 

5657 self.schema = quoted_name.construct(schema, quote_schema) 

5658 self.naming_convention = ( 

5659 naming_convention 

5660 if naming_convention 

5661 else DEFAULT_NAMING_CONVENTION 

5662 ) 

5663 if info: 

5664 self.info = info 

5665 self._schemas: Set[str] = set() 

5666 self._sequences: Dict[str, Sequence] = {} 

5667 self._fk_memos: Dict[Tuple[str, Optional[str]], List[ForeignKey]] = ( 

5668 collections.defaultdict(list) 

5669 ) 

5670 

5671 tables: util.FacadeDict[str, Table] 

5672 """A dictionary of :class:`_schema.Table` 

5673 objects keyed to their name or "table key". 

5674 

5675 The exact key is that determined by the :attr:`_schema.Table.key` 

5676 attribute; 

5677 for a table with no :attr:`_schema.Table.schema` attribute, 

5678 this is the same 

5679 as :attr:`_schema.Table.name`. For a table with a schema, 

5680 it is typically of the 

5681 form ``schemaname.tablename``. 

5682 

5683 .. seealso:: 

5684 

5685 :attr:`_schema.MetaData.sorted_tables` 

5686 

5687 """ 

5688 

5689 def __repr__(self) -> str: 

5690 return "MetaData()" 

5691 

5692 def __contains__(self, table_or_key: Union[str, Table]) -> bool: 

5693 if not isinstance(table_or_key, str): 

5694 table_or_key = table_or_key.key 

5695 return table_or_key in self.tables 

5696 

5697 def _add_table( 

5698 self, name: str, schema: Optional[str], table: Table 

5699 ) -> None: 

5700 key = _get_table_key(name, schema) 

5701 self.tables._insert_item(key, table) 

5702 if schema: 

5703 self._schemas.add(schema) 

5704 

5705 def _remove_table(self, name: str, schema: Optional[str]) -> None: 

5706 key = _get_table_key(name, schema) 

5707 removed = dict.pop(self.tables, key, None) 

5708 if removed is not None: 

5709 for fk in removed.foreign_keys: 

5710 fk._remove_from_metadata(self) 

5711 if self._schemas: 

5712 self._schemas = { 

5713 t.schema for t in self.tables.values() if t.schema is not None 

5714 } 

5715 

5716 def __getstate__(self) -> Dict[str, Any]: 

5717 return { 

5718 "tables": self.tables, 

5719 "schema": self.schema, 

5720 "schemas": self._schemas, 

5721 "sequences": self._sequences, 

5722 "fk_memos": self._fk_memos, 

5723 "naming_convention": self.naming_convention, 

5724 } 

5725 

5726 def __setstate__(self, state: Dict[str, Any]) -> None: 

5727 self.tables = state["tables"] 

5728 self.schema = state["schema"] 

5729 self.naming_convention = state["naming_convention"] 

5730 self._sequences = state["sequences"] 

5731 self._schemas = state["schemas"] 

5732 self._fk_memos = state["fk_memos"] 

5733 

5734 def clear(self) -> None: 

5735 """Clear all Table objects from this MetaData.""" 

5736 

5737 dict.clear(self.tables) # type: ignore 

5738 self._schemas.clear() 

5739 self._fk_memos.clear() 

5740 

5741 def remove(self, table: Table) -> None: 

5742 """Remove the given Table object from this MetaData.""" 

5743 

5744 self._remove_table(table.name, table.schema) 

5745 

5746 @property 

5747 def sorted_tables(self) -> List[Table]: 

5748 """Returns a list of :class:`_schema.Table` objects sorted in order of 

5749 foreign key dependency. 

5750 

5751 The sorting will place :class:`_schema.Table` 

5752 objects that have dependencies 

5753 first, before the dependencies themselves, representing the 

5754 order in which they can be created. To get the order in which 

5755 the tables would be dropped, use the ``reversed()`` Python built-in. 

5756 

5757 .. warning:: 

5758 

5759 The :attr:`.MetaData.sorted_tables` attribute cannot by itself 

5760 accommodate automatic resolution of dependency cycles between 

5761 tables, which are usually caused by mutually dependent foreign key 

5762 constraints. When these cycles are detected, the foreign keys 

5763 of these tables are omitted from consideration in the sort. 

5764 A warning is emitted when this condition occurs, which will be an 

5765 exception raise in a future release. Tables which are not part 

5766 of the cycle will still be returned in dependency order. 

5767 

5768 To resolve these cycles, the 

5769 :paramref:`_schema.ForeignKeyConstraint.use_alter` parameter may be 

5770 applied to those constraints which create a cycle. Alternatively, 

5771 the :func:`_schema.sort_tables_and_constraints` function will 

5772 automatically return foreign key constraints in a separate 

5773 collection when cycles are detected so that they may be applied 

5774 to a schema separately. 

5775 

5776 .. seealso:: 

5777 

5778 :func:`_schema.sort_tables` 

5779 

5780 :func:`_schema.sort_tables_and_constraints` 

5781 

5782 :attr:`_schema.MetaData.tables` 

5783 

5784 :meth:`_reflection.Inspector.get_table_names` 

5785 

5786 :meth:`_reflection.Inspector.get_sorted_table_and_fkc_names` 

5787 

5788 

5789 """ 

5790 return ddl.sort_tables( 

5791 sorted(self.tables.values(), key=lambda t: t.key) # type: ignore 

5792 ) 

5793 

5794 # overload needed to work around mypy this mypy 

5795 # https://github.com/python/mypy/issues/17093 

5796 @overload 

5797 def reflect( 

5798 self, 

5799 bind: Engine, 

5800 schema: Optional[str] = ..., 

5801 views: bool = ..., 

5802 only: Union[ 

5803 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

5804 ] = ..., 

5805 extend_existing: bool = ..., 

5806 autoload_replace: bool = ..., 

5807 resolve_fks: bool = ..., 

5808 **dialect_kwargs: Any, 

5809 ) -> None: ... 

5810 

5811 @overload 

5812 def reflect( 

5813 self, 

5814 bind: Connection, 

5815 schema: Optional[str] = ..., 

5816 views: bool = ..., 

5817 only: Union[ 

5818 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

5819 ] = ..., 

5820 extend_existing: bool = ..., 

5821 autoload_replace: bool = ..., 

5822 resolve_fks: bool = ..., 

5823 **dialect_kwargs: Any, 

5824 ) -> None: ... 

5825 

5826 @util.preload_module("sqlalchemy.engine.reflection") 

5827 def reflect( 

5828 self, 

5829 bind: Union[Engine, Connection], 

5830 schema: Optional[str] = None, 

5831 views: bool = False, 

5832 only: Union[ 

5833 _typing_Sequence[str], Callable[[str, MetaData], bool], None 

5834 ] = None, 

5835 extend_existing: bool = False, 

5836 autoload_replace: bool = True, 

5837 resolve_fks: bool = True, 

5838 **dialect_kwargs: Any, 

5839 ) -> None: 

5840 r"""Load all available table definitions from the database. 

5841 

5842 Automatically creates ``Table`` entries in this ``MetaData`` for any 

5843 table available in the database but not yet present in the 

5844 ``MetaData``. May be called multiple times to pick up tables recently 

5845 added to the database, however no special action is taken if a table 

5846 in this ``MetaData`` no longer exists in the database. 

5847 

5848 :param bind: 

5849 A :class:`.Connection` or :class:`.Engine` used to access the 

5850 database. 

5851 

5852 :param schema: 

5853 Optional, query and reflect tables from an alternate schema. 

5854 If None, the schema associated with this :class:`_schema.MetaData` 

5855 is used, if any. 

5856 

5857 :param views: 

5858 If True, also reflect views (materialized and plain). 

5859 

5860 :param only: 

5861 Optional. Load only a sub-set of available named tables. May be 

5862 specified as a sequence of names or a callable. 

5863 

5864 If a sequence of names is provided, only those tables will be 

5865 reflected. An error is raised if a table is requested but not 

5866 available. Named tables already present in this ``MetaData`` are 

5867 ignored. 

5868 

5869 If a callable is provided, it will be used as a boolean predicate to 

5870 filter the list of potential table names. The callable is called 

5871 with a table name and this ``MetaData`` instance as positional 

5872 arguments and should return a true value for any table to reflect. 

5873 

5874 :param extend_existing: Passed along to each :class:`_schema.Table` as 

5875 :paramref:`_schema.Table.extend_existing`. 

5876 

5877 :param autoload_replace: Passed along to each :class:`_schema.Table` 

5878 as 

5879 :paramref:`_schema.Table.autoload_replace`. 

5880 

5881 :param resolve_fks: if True, reflect :class:`_schema.Table` 

5882 objects linked 

5883 to :class:`_schema.ForeignKey` objects located in each 

5884 :class:`_schema.Table`. 

5885 For :meth:`_schema.MetaData.reflect`, 

5886 this has the effect of reflecting 

5887 related tables that might otherwise not be in the list of tables 

5888 being reflected, for example if the referenced table is in a 

5889 different schema or is omitted via the 

5890 :paramref:`.MetaData.reflect.only` parameter. When False, 

5891 :class:`_schema.ForeignKey` objects are not followed to the 

5892 :class:`_schema.Table` 

5893 in which they link, however if the related table is also part of the 

5894 list of tables that would be reflected in any case, the 

5895 :class:`_schema.ForeignKey` object will still resolve to its related 

5896 :class:`_schema.Table` after the :meth:`_schema.MetaData.reflect` 

5897 operation is 

5898 complete. Defaults to True. 

5899 

5900 .. seealso:: 

5901 

5902 :paramref:`_schema.Table.resolve_fks` 

5903 

5904 :param \**dialect_kwargs: Additional keyword arguments not mentioned 

5905 above are dialect specific, and passed in the form 

5906 ``<dialectname>_<argname>``. See the documentation regarding an 

5907 individual dialect at :ref:`dialect_toplevel` for detail on 

5908 documented arguments. 

5909 

5910 .. seealso:: 

5911 

5912 :ref:`metadata_reflection_toplevel` 

5913 

5914 :meth:`_events.DDLEvents.column_reflect` - Event used to customize 

5915 the reflected columns. Usually used to generalize the types using 

5916 :meth:`_types.TypeEngine.as_generic` 

5917 

5918 :ref:`metadata_reflection_dbagnostic_types` - describes how to 

5919 reflect tables using general types. 

5920 

5921 """ 

5922 

5923 with inspection.inspect(bind)._inspection_context() as insp: 

5924 reflect_opts: Any = { 

5925 "autoload_with": insp, 

5926 "extend_existing": extend_existing, 

5927 "autoload_replace": autoload_replace, 

5928 "resolve_fks": resolve_fks, 

5929 "_extend_on": set(), 

5930 } 

5931 

5932 reflect_opts.update(dialect_kwargs) 

5933 

5934 if schema is None: 

5935 schema = self.schema 

5936 

5937 if schema is not None: 

5938 reflect_opts["schema"] = schema 

5939 

5940 kind = util.preloaded.engine_reflection.ObjectKind.TABLE 

5941 available: util.OrderedSet[str] = util.OrderedSet( 

5942 insp.get_table_names(schema) 

5943 ) 

5944 if views: 

5945 kind = util.preloaded.engine_reflection.ObjectKind.ANY 

5946 available.update(insp.get_view_names(schema)) 

5947 try: 

5948 available.update(insp.get_materialized_view_names(schema)) 

5949 except NotImplementedError: 

5950 pass 

5951 

5952 if schema is not None: 

5953 available_w_schema: util.OrderedSet[str] = util.OrderedSet( 

5954 [f"{schema}.{name}" for name in available] 

5955 ) 

5956 else: 

5957 available_w_schema = available 

5958 

5959 current = set(self.tables) 

5960 

5961 if only is None: 

5962 load = [ 

5963 name 

5964 for name, schname in zip(available, available_w_schema) 

5965 if extend_existing or schname not in current 

5966 ] 

5967 elif callable(only): 

5968 load = [ 

5969 name 

5970 for name, schname in zip(available, available_w_schema) 

5971 if (extend_existing or schname not in current) 

5972 and only(name, self) 

5973 ] 

5974 else: 

5975 missing = [name for name in only if name not in available] 

5976 if missing: 

5977 s = schema and (" schema '%s'" % schema) or "" 

5978 missing_str = ", ".join(missing) 

5979 raise exc.InvalidRequestError( 

5980 f"Could not reflect: requested table(s) not available " 

5981 f"in {bind.engine!r}{s}: ({missing_str})" 

5982 ) 

5983 load = [ 

5984 name 

5985 for name in only 

5986 if extend_existing or name not in current 

5987 ] 

5988 # pass the available tables so the inspector can 

5989 # choose to ignore the filter_names 

5990 _reflect_info = insp._get_reflection_info( 

5991 schema=schema, 

5992 filter_names=load, 

5993 available=available, 

5994 kind=kind, 

5995 scope=util.preloaded.engine_reflection.ObjectScope.ANY, 

5996 **dialect_kwargs, 

5997 ) 

5998 reflect_opts["_reflect_info"] = _reflect_info 

5999 

6000 for name in load: 

6001 try: 

6002 Table(name, self, **reflect_opts) 

6003 except exc.UnreflectableTableError as uerr: 

6004 util.warn(f"Skipping table {name}: {uerr}") 

6005 

6006 def create_all( 

6007 self, 

6008 bind: _CreateDropBind, 

6009 tables: Optional[_typing_Sequence[Table]] = None, 

6010 checkfirst: bool = True, 

6011 ) -> None: 

6012 """Create all tables stored in this metadata. 

6013 

6014 Conditional by default, will not attempt to recreate tables already 

6015 present in the target database. 

6016 

6017 :param bind: 

6018 A :class:`.Connection` or :class:`.Engine` used to access the 

6019 database. 

6020 

6021 :param tables: 

6022 Optional list of ``Table`` objects, which is a subset of the total 

6023 tables in the ``MetaData`` (others are ignored). 

6024 

6025 :param checkfirst: 

6026 Defaults to True, don't issue CREATEs for tables already present 

6027 in the target database. 

6028 

6029 """ 

6030 bind._run_ddl_visitor( 

6031 ddl.SchemaGenerator, self, checkfirst=checkfirst, tables=tables 

6032 ) 

6033 

6034 def drop_all( 

6035 self, 

6036 bind: _CreateDropBind, 

6037 tables: Optional[_typing_Sequence[Table]] = None, 

6038 checkfirst: bool = True, 

6039 ) -> None: 

6040 """Drop all tables stored in this metadata. 

6041 

6042 Conditional by default, will not attempt to drop tables not present in 

6043 the target database. 

6044 

6045 :param bind: 

6046 A :class:`.Connection` or :class:`.Engine` used to access the 

6047 database. 

6048 

6049 :param tables: 

6050 Optional list of ``Table`` objects, which is a subset of the 

6051 total tables in the ``MetaData`` (others are ignored). 

6052 

6053 :param checkfirst: 

6054 Defaults to True, only issue DROPs for tables confirmed to be 

6055 present in the target database. 

6056 

6057 """ 

6058 bind._run_ddl_visitor( 

6059 ddl.SchemaDropper, self, checkfirst=checkfirst, tables=tables 

6060 ) 

6061 

6062 

6063class Computed(FetchedValue, SchemaItem): 

6064 """Defines a generated column, i.e. "GENERATED ALWAYS AS" syntax. 

6065 

6066 The :class:`.Computed` construct is an inline construct added to the 

6067 argument list of a :class:`_schema.Column` object:: 

6068 

6069 from sqlalchemy import Computed 

6070 

6071 Table( 

6072 "square", 

6073 metadata_obj, 

6074 Column("side", Float, nullable=False), 

6075 Column("area", Float, Computed("side * side")), 

6076 ) 

6077 

6078 See the linked documentation below for complete details. 

6079 

6080 .. seealso:: 

6081 

6082 :ref:`computed_ddl` 

6083 

6084 """ 

6085 

6086 __visit_name__ = "computed_column" 

6087 

6088 column: Optional[Column[Any]] 

6089 

6090 @_document_text_coercion( 

6091 "sqltext", ":class:`.Computed`", ":paramref:`.Computed.sqltext`" 

6092 ) 

6093 def __init__( 

6094 self, sqltext: _DDLColumnArgument, persisted: Optional[bool] = None 

6095 ) -> None: 

6096 """Construct a GENERATED ALWAYS AS DDL construct to accompany a 

6097 :class:`_schema.Column`. 

6098 

6099 :param sqltext: 

6100 A string containing the column generation expression, which will be 

6101 used verbatim, or a SQL expression construct, such as a 

6102 :func:`_expression.text` 

6103 object. If given as a string, the object is converted to a 

6104 :func:`_expression.text` object. 

6105 

6106 :param persisted: 

6107 Optional, controls how this column should be persisted by the 

6108 database. Possible values are: 

6109 

6110 * ``None``, the default, it will use the default persistence 

6111 defined by the database. 

6112 * ``True``, will render ``GENERATED ALWAYS AS ... STORED``, or the 

6113 equivalent for the target database if supported. 

6114 * ``False``, will render ``GENERATED ALWAYS AS ... VIRTUAL``, or 

6115 the equivalent for the target database if supported. 

6116 

6117 Specifying ``True`` or ``False`` may raise an error when the DDL 

6118 is emitted to the target database if the database does not support 

6119 that persistence option. Leaving this parameter at its default 

6120 of ``None`` is guaranteed to succeed for all databases that support 

6121 ``GENERATED ALWAYS AS``. 

6122 

6123 """ 

6124 self.sqltext = coercions.expect(roles.DDLExpressionRole, sqltext) 

6125 self.persisted = persisted 

6126 self.column = None 

6127 

6128 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

6129 assert isinstance(parent, Column) 

6130 

6131 if not isinstance( 

6132 parent.server_default, (type(None), Computed) 

6133 ) or not isinstance(parent.server_onupdate, (type(None), Computed)): 

6134 raise exc.ArgumentError( 

6135 "A generated column cannot specify a server_default or a " 

6136 "server_onupdate argument" 

6137 ) 

6138 self.column = parent 

6139 parent.computed = self 

6140 self.column.server_onupdate = self 

6141 self.column.server_default = self 

6142 

6143 def _as_for_update(self, for_update: bool) -> FetchedValue: 

6144 return self 

6145 

6146 @util.deprecated( 

6147 "1.4", 

6148 "The :meth:`_schema.Computed.copy` method is deprecated " 

6149 "and will be removed in a future release.", 

6150 ) 

6151 def copy( 

6152 self, *, target_table: Optional[Table] = None, **kw: Any 

6153 ) -> Computed: 

6154 return self._copy(target_table=target_table, **kw) 

6155 

6156 def _copy( 

6157 self, *, target_table: Optional[Table] = None, **kw: Any 

6158 ) -> Computed: 

6159 sqltext = _copy_expression( 

6160 self.sqltext, 

6161 self.column.table if self.column is not None else None, 

6162 target_table, 

6163 ) 

6164 g = Computed(sqltext, persisted=self.persisted) 

6165 

6166 return self._schema_item_copy(g) 

6167 

6168 

6169class Identity(IdentityOptions, FetchedValue, SchemaItem): 

6170 """Defines an identity column, i.e. "GENERATED { ALWAYS | BY DEFAULT } 

6171 AS IDENTITY" syntax. 

6172 

6173 The :class:`.Identity` construct is an inline construct added to the 

6174 argument list of a :class:`_schema.Column` object:: 

6175 

6176 from sqlalchemy import Identity 

6177 

6178 Table( 

6179 "foo", 

6180 metadata_obj, 

6181 Column("id", Integer, Identity()), 

6182 Column("description", Text), 

6183 ) 

6184 

6185 See the linked documentation below for complete details. 

6186 

6187 .. versionadded:: 1.4 

6188 

6189 .. seealso:: 

6190 

6191 :ref:`identity_ddl` 

6192 

6193 """ 

6194 

6195 __visit_name__ = "identity_column" 

6196 

6197 is_identity = True 

6198 

6199 @util.deprecated_params( 

6200 order=( 

6201 "2.1", 

6202 "This parameter is supported only by Oracle Database, " 

6203 "use ``oracle_order`` instead.", 

6204 ), 

6205 on_null=( 

6206 "2.1", 

6207 "This parameter is supported only by Oracle Database, " 

6208 "use ``oracle_on_null`` instead.", 

6209 ), 

6210 ) 

6211 def __init__( 

6212 self, 

6213 always: Optional[bool] = False, 

6214 on_null: Optional[bool] = None, 

6215 start: Optional[int] = None, 

6216 increment: Optional[int] = None, 

6217 minvalue: Optional[int] = None, 

6218 maxvalue: Optional[int] = None, 

6219 nominvalue: Optional[bool] = None, 

6220 nomaxvalue: Optional[bool] = None, 

6221 cycle: Optional[bool] = None, 

6222 cache: Optional[int] = None, 

6223 order: Optional[bool] = None, 

6224 **dialect_kw: Any, 

6225 ) -> None: 

6226 """Construct a GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY DDL 

6227 construct to accompany a :class:`_schema.Column`. 

6228 

6229 See the :class:`.Sequence` documentation for a complete description 

6230 of most parameters. 

6231 

6232 .. note:: 

6233 MSSQL supports this construct as the preferred alternative to 

6234 generate an IDENTITY on a column, but it uses non standard 

6235 syntax that only support :paramref:`_schema.Identity.start` 

6236 and :paramref:`_schema.Identity.increment`. 

6237 All other parameters are ignored. 

6238 

6239 :param always: 

6240 A boolean, that indicates the type of identity column. 

6241 If ``False`` is specified, the default, then the user-specified 

6242 value takes precedence. 

6243 If ``True`` is specified, a user-specified value is not accepted ( 

6244 on some backends, like PostgreSQL, OVERRIDING SYSTEM VALUE, or 

6245 similar, may be specified in an INSERT to override the sequence 

6246 value). 

6247 Some backends also have a default value for this parameter, 

6248 ``None`` can be used to omit rendering this part in the DDL. It 

6249 will be treated as ``False`` if a backend does not have a default 

6250 value. 

6251 

6252 :param on_null: 

6253 Set to ``True`` to specify ON NULL in conjunction with a 

6254 ``always=False`` identity column. This option is only supported on 

6255 some backends, like Oracle Database. 

6256 

6257 :param start: the starting index of the sequence. 

6258 :param increment: the increment value of the sequence. 

6259 :param minvalue: the minimum value of the sequence. 

6260 :param maxvalue: the maximum value of the sequence. 

6261 :param nominvalue: no minimum value of the sequence. 

6262 :param nomaxvalue: no maximum value of the sequence. 

6263 :param cycle: allows the sequence to wrap around when the maxvalue 

6264 or minvalue has been reached. 

6265 :param cache: optional integer value; number of future values in the 

6266 sequence which are calculated in advance. 

6267 :param order: optional boolean value; if true, renders the 

6268 ORDER keyword. 

6269 

6270 """ 

6271 self.dialect_options 

6272 if on_null is not None: 

6273 if "oracle_on_null" in dialect_kw: 

6274 raise exc.ArgumentError( 

6275 "Cannot specify both 'on_null' and 'oracle_on_null'. " 

6276 "Plese use only 'oracle_on_null'." 

6277 ) 

6278 dialect_kw["oracle_on_null"] = on_null 

6279 

6280 IdentityOptions.__init__( 

6281 self, 

6282 start=start, 

6283 increment=increment, 

6284 minvalue=minvalue, 

6285 maxvalue=maxvalue, 

6286 nominvalue=nominvalue, 

6287 nomaxvalue=nomaxvalue, 

6288 cycle=cycle, 

6289 cache=cache, 

6290 order=order, 

6291 **dialect_kw, 

6292 ) 

6293 self.always = always 

6294 self.column = None 

6295 

6296 @property 

6297 def on_null(self) -> Optional[bool]: 

6298 """Alias of the ``dialect_kwargs`` ``'oracle_on_null'``. 

6299 

6300 .. deprecated:: 2.1 The 'on_null' attribute is deprecated. 

6301 """ 

6302 value: Optional[bool] = self.dialect_kwargs.get("oracle_on_null") 

6303 return value 

6304 

6305 def _set_parent(self, parent: SchemaEventTarget, **kw: Any) -> None: 

6306 assert isinstance(parent, Column) 

6307 if not isinstance( 

6308 parent.server_default, (type(None), Identity) 

6309 ) or not isinstance(parent.server_onupdate, type(None)): 

6310 raise exc.ArgumentError( 

6311 "A column with an Identity object cannot specify a " 

6312 "server_default or a server_onupdate argument" 

6313 ) 

6314 if parent.autoincrement is False: 

6315 raise exc.ArgumentError( 

6316 "A column with an Identity object cannot specify " 

6317 "autoincrement=False" 

6318 ) 

6319 self.column = parent 

6320 

6321 parent.identity = self 

6322 if parent._user_defined_nullable is NULL_UNSPECIFIED: 

6323 parent.nullable = False 

6324 

6325 parent.server_default = self 

6326 

6327 def _as_for_update(self, for_update: bool) -> FetchedValue: 

6328 return self 

6329 

6330 @util.deprecated( 

6331 "1.4", 

6332 "The :meth:`_schema.Identity.copy` method is deprecated " 

6333 "and will be removed in a future release.", 

6334 ) 

6335 def copy(self, **kw: Any) -> Identity: 

6336 return self._copy(**kw) 

6337 

6338 def _copy(self, **kw: Any) -> Identity: 

6339 i = Identity(**self._as_dict(), **self.dialect_kwargs) 

6340 

6341 return self._schema_item_copy(i) 

6342 

6343 def _as_dict(self) -> Dict[str, Any]: 

6344 return { 

6345 # always=None means something different than always=False 

6346 "always": self.always, 

6347 **super()._as_dict(), 

6348 }