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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

509 statements  

1# sql/dml.py 

2# Copyright (C) 2009-2026 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# 

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

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

7""" 

8Provide :class:`_expression.Insert`, :class:`_expression.Update` and 

9:class:`_expression.Delete`. 

10 

11""" 

12 

13from __future__ import annotations 

14 

15import collections.abc as collections_abc 

16import operator 

17from typing import Any 

18from typing import cast 

19from typing import Dict 

20from typing import Iterable 

21from typing import List 

22from typing import Literal 

23from typing import MutableMapping 

24from typing import NoReturn 

25from typing import Optional 

26from typing import overload 

27from typing import Sequence 

28from typing import Set 

29from typing import Tuple 

30from typing import Type 

31from typing import TYPE_CHECKING 

32from typing import TypeGuard 

33from typing import TypeVar 

34from typing import Union 

35 

36from . import coercions 

37from . import roles 

38from . import util as sql_util 

39from ._typing import _unexpected_kw 

40from ._typing import is_column_element 

41from ._typing import is_named_from_clause 

42from .base import _entity_namespace_key_search_all 

43from .base import _exclusive_against 

44from .base import _from_objects 

45from .base import _generative 

46from .base import _select_iterables 

47from .base import ColumnSet 

48from .base import CompileState 

49from .base import DialectKWArgs 

50from .base import Executable 

51from .base import ExecutableStatement 

52from .base import Generative 

53from .base import HasCompileState 

54from .base import HasSyntaxExtensions 

55from .base import SyntaxExtension 

56from .base import WriteableColumnCollection 

57from .elements import BooleanClauseList 

58from .elements import ClauseElement 

59from .elements import ColumnClause 

60from .elements import ColumnElement 

61from .elements import Null 

62from .selectable import Alias 

63from .selectable import ExecutableReturnsRows 

64from .selectable import FromClause 

65from .selectable import HasCTE 

66from .selectable import HasPrefixes 

67from .selectable import Join 

68from .selectable import SelectLabelStyle 

69from .selectable import TableClause 

70from .selectable import TypedReturnsRows 

71from .sqltypes import NullType 

72from .visitors import InternalTraversal 

73from .. import exc 

74from .. import util 

75from ..util.typing import Self 

76from ..util.typing import TupleAny 

77from ..util.typing import TypeVarTuple 

78from ..util.typing import Unpack 

79 

80if TYPE_CHECKING: 

81 from ._typing import _ColumnExpressionArgument 

82 from ._typing import _ColumnsClauseArgument 

83 from ._typing import _DMLColumnArgument 

84 from ._typing import _DMLColumnKeyMapping 

85 from ._typing import _DMLTableArgument 

86 from ._typing import _FromClauseArgument 

87 from ._typing import _T0 # noqa 

88 from ._typing import _T1 # noqa 

89 from ._typing import _T2 # noqa 

90 from ._typing import _T3 # noqa 

91 from ._typing import _T4 # noqa 

92 from ._typing import _T5 # noqa 

93 from ._typing import _T6 # noqa 

94 from ._typing import _T7 # noqa 

95 from ._typing import _TypedColumnClauseArgument as _TCCA # noqa 

96 from .base import ReadOnlyColumnCollection 

97 from .compiler import SQLCompiler 

98 from .elements import KeyedColumnElement 

99 from .selectable import _ColumnsClauseElement 

100 from .selectable import _SelectIterable 

101 from .selectable import Select 

102 from .selectable import Selectable 

103 

104 def isupdate(dml: DMLState) -> TypeGuard[UpdateDMLState]: ... 

105 

106 def isdelete(dml: DMLState) -> TypeGuard[DeleteDMLState]: ... 

107 

108 def isinsert(dml: DMLState) -> TypeGuard[InsertDMLState]: ... 

109 

110else: 

111 isupdate = operator.attrgetter("isupdate") 

112 isdelete = operator.attrgetter("isdelete") 

113 isinsert = operator.attrgetter("isinsert") 

114 

115 

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

117_Ts = TypeVarTuple("_Ts") 

118 

119_DMLColumnElement = Union[str, ColumnClause[Any]] 

120_DMLTableElement = Union[TableClause, Alias, Join] 

121 

122 

123class DMLState(CompileState): 

124 _no_parameters = True 

125 _dict_parameters: Optional[MutableMapping[_DMLColumnElement, Any]] = None 

126 _multi_parameters: Optional[ 

127 List[MutableMapping[_DMLColumnElement, Any]] 

128 ] = None 

129 _maintain_values_ordering: bool = False 

130 _primary_table: FromClause 

131 _supports_implicit_returning = True 

132 

133 isupdate = False 

134 isdelete = False 

135 isinsert = False 

136 

137 statement: UpdateBase 

138 

139 def __init__( 

140 self, statement: UpdateBase, compiler: SQLCompiler, **kw: Any 

141 ): 

142 raise NotImplementedError() 

143 

144 @classmethod 

145 def get_entity_description(cls, statement: UpdateBase) -> Dict[str, Any]: 

146 return { 

147 "name": ( 

148 statement.table.name 

149 if is_named_from_clause(statement.table) 

150 else None 

151 ), 

152 "table": statement.table, 

153 } 

154 

155 @classmethod 

156 def get_returning_column_descriptions( 

157 cls, statement: UpdateBase 

158 ) -> List[Dict[str, Any]]: 

159 return [ 

160 { 

161 "name": c.key, 

162 "type": c.type, 

163 "expr": c, 

164 } 

165 for c in statement._all_selected_columns 

166 ] 

167 

168 @property 

169 def dml_table(self) -> _DMLTableElement: 

170 return self.statement.table 

171 

172 if TYPE_CHECKING: 

173 

174 @classmethod 

175 def get_plugin_class(cls, statement: Executable) -> Type[DMLState]: ... 

176 

177 @classmethod 

178 def _get_multi_crud_kv_pairs( 

179 cls, 

180 statement: UpdateBase, 

181 multi_kv_iterator: Iterable[Dict[_DMLColumnArgument, Any]], 

182 ) -> List[Dict[_DMLColumnElement, Any]]: 

183 return [ 

184 { 

185 coercions.expect(roles.DMLColumnRole, k): v 

186 for k, v in mapping.items() 

187 } 

188 for mapping in multi_kv_iterator 

189 ] 

190 

191 @classmethod 

192 def _get_crud_kv_pairs( 

193 cls, 

194 statement: UpdateBase, 

195 kv_iterator: Iterable[Tuple[_DMLColumnArgument, Any]], 

196 needs_to_be_cacheable: bool, 

197 ) -> List[Tuple[_DMLColumnElement, Any]]: 

198 return [ 

199 ( 

200 coercions.expect(roles.DMLColumnRole, k), 

201 ( 

202 v 

203 if not needs_to_be_cacheable 

204 else coercions.expect( 

205 roles.ExpressionElementRole, 

206 v, 

207 type_=NullType(), 

208 is_crud=True, 

209 ) 

210 ), 

211 ) 

212 for k, v in kv_iterator 

213 ] 

214 

215 def _make_extra_froms( 

216 self, 

217 statement: DMLWhereBase, 

218 explicit_froms: Sequence[FromClause] = (), 

219 ) -> Tuple[FromClause, List[FromClause]]: 

220 froms: List[FromClause] = [] 

221 

222 all_tables = list(sql_util.tables_from_leftmost(statement.table)) 

223 primary_table = all_tables[0] 

224 seen = {primary_table} 

225 

226 def _consider_from( 

227 from_: FromClause, include_surface_selectables: bool = False 

228 ) -> None: 

229 if not seen.intersection(from_._cloned_set): 

230 froms.append(from_) 

231 seen.update(from_._cloned_set) 

232 if include_surface_selectables: 

233 for elem in sql_util.surface_selectables_only(from_): 

234 seen.update(elem._cloned_set) 

235 

236 for from_ in explicit_froms: 

237 _consider_from(from_, include_surface_selectables=True) 

238 

239 consider = statement._where_criteria 

240 if self._dict_parameters: 

241 consider += tuple(self._dict_parameters.values()) 

242 

243 for crit in consider: 

244 for item in _from_objects(crit): 

245 _consider_from(item) 

246 

247 froms.extend(all_tables[1:]) 

248 return primary_table, froms 

249 

250 def _process_values(self, statement: ValuesBase) -> None: 

251 if self._no_parameters: 

252 self._dict_parameters = statement._values 

253 self._no_parameters = False 

254 

255 def _process_select_values(self, statement: ValuesBase) -> None: 

256 assert statement._select_names is not None 

257 parameters: MutableMapping[_DMLColumnElement, Any] = { 

258 name: Null() for name in statement._select_names 

259 } 

260 

261 if self._no_parameters: 

262 self._no_parameters = False 

263 self._dict_parameters = parameters 

264 else: 

265 # this condition normally not reachable as the Insert 

266 # does not allow this construction to occur 

267 assert False, "This statement already has parameters" 

268 

269 def _no_multi_values_supported(self, statement: ValuesBase) -> NoReturn: 

270 raise exc.InvalidRequestError( 

271 "%s construct does not support " 

272 "multiple parameter sets." % statement.__visit_name__.upper() 

273 ) 

274 

275 def _cant_mix_formats_error(self) -> NoReturn: 

276 raise exc.InvalidRequestError( 

277 "Can't mix single and multiple VALUES " 

278 "formats in one INSERT statement; one style appends to a " 

279 "list while the other replaces values, so the intent is " 

280 "ambiguous." 

281 ) 

282 

283 

284@CompileState.plugin_for("default", "insert") 

285class InsertDMLState(DMLState): 

286 isinsert = True 

287 

288 include_table_with_column_exprs = False 

289 

290 _has_multi_parameters = False 

291 

292 def __init__( 

293 self, 

294 statement: Insert, 

295 compiler: SQLCompiler, 

296 disable_implicit_returning: bool = False, 

297 **kw: Any, 

298 ): 

299 self.statement = statement 

300 self._primary_table = statement.table 

301 

302 if disable_implicit_returning: 

303 self._supports_implicit_returning = False 

304 

305 self.isinsert = True 

306 if statement._select_names: 

307 self._process_select_values(statement) 

308 if statement._values is not None: 

309 self._process_values(statement) 

310 if statement._multi_values: 

311 self._process_multi_values(statement) 

312 

313 @util.memoized_property 

314 def _insert_col_keys(self) -> List[str]: 

315 # this is also done in crud.py -> _key_getters_for_crud_column 

316 return [ 

317 coercions.expect(roles.DMLColumnRole, col, as_key=True) 

318 for col in self._dict_parameters or () 

319 ] 

320 

321 def _process_values(self, statement: ValuesBase) -> None: 

322 if self._no_parameters: 

323 self._has_multi_parameters = False 

324 self._dict_parameters = statement._values 

325 self._no_parameters = False 

326 elif self._has_multi_parameters: 

327 self._cant_mix_formats_error() 

328 

329 def _process_multi_values(self, statement: ValuesBase) -> None: 

330 for parameters in statement._multi_values: 

331 multi_parameters: List[MutableMapping[_DMLColumnElement, Any]] = [ 

332 ( 

333 { 

334 c.key: value 

335 for c, value in zip(statement.table.c, parameter_set) 

336 } 

337 if isinstance(parameter_set, collections_abc.Sequence) 

338 else parameter_set 

339 ) 

340 for parameter_set in parameters 

341 ] 

342 

343 if self._no_parameters: 

344 self._no_parameters = False 

345 self._has_multi_parameters = True 

346 self._multi_parameters = multi_parameters 

347 self._dict_parameters = self._multi_parameters[0] 

348 elif not self._has_multi_parameters: 

349 self._cant_mix_formats_error() 

350 else: 

351 assert self._multi_parameters 

352 self._multi_parameters.extend(multi_parameters) 

353 

354 

355@CompileState.plugin_for("default", "update") 

356class UpdateDMLState(DMLState): 

357 isupdate = True 

358 

359 include_table_with_column_exprs = False 

360 

361 def __init__(self, statement: Update, compiler: SQLCompiler, **kw: Any): 

362 self.statement = statement 

363 

364 self.isupdate = True 

365 if statement._maintain_values_ordering: 

366 self._process_ordered_values(statement) 

367 elif statement._values is not None: 

368 self._process_values(statement) 

369 elif statement._multi_values: 

370 self._no_multi_values_supported(statement) 

371 t, ef = self._make_extra_froms(statement) 

372 self._primary_table = t 

373 self._extra_froms = ef 

374 

375 self.is_multitable = mt = ef 

376 self.include_table_with_column_exprs = bool( 

377 mt and compiler.render_table_with_column_in_update_from 

378 ) 

379 

380 def _process_ordered_values(self, statement: ValuesBase) -> None: 

381 parameters = statement._values 

382 if self._no_parameters: 

383 self._no_parameters = False 

384 assert parameters is not None 

385 self._dict_parameters = dict(parameters) 

386 self._maintain_values_ordering = True 

387 else: 

388 raise exc.InvalidRequestError( 

389 "Can only invoke ordered_values() once, and not mixed " 

390 "with any other values() call" 

391 ) 

392 

393 

394@CompileState.plugin_for("default", "delete") 

395class DeleteDMLState(DMLState): 

396 isdelete = True 

397 

398 def __init__(self, statement: Delete, compiler: SQLCompiler, **kw: Any): 

399 self.statement = statement 

400 

401 self.isdelete = True 

402 t, ef = self._make_extra_froms(statement, statement._extra_froms) 

403 self._primary_table = t 

404 self._extra_froms = ef 

405 self.is_multitable = ef 

406 

407 

408class UpdateBase( 

409 roles.DMLRole, 

410 HasCTE, 

411 HasCompileState, 

412 DialectKWArgs, 

413 HasPrefixes, 

414 Generative, 

415 ExecutableReturnsRows, 

416 ClauseElement, 

417): 

418 """Form the base for ``INSERT``, ``UPDATE``, and ``DELETE`` statements.""" 

419 

420 __visit_name__ = "update_base" 

421 

422 _hints: util.immutabledict[Tuple[_DMLTableElement, str], str] = ( 

423 util.EMPTY_DICT 

424 ) 

425 named_with_column = False 

426 

427 _label_style: SelectLabelStyle = ( 

428 SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY 

429 ) 

430 table: _DMLTableElement 

431 

432 _return_defaults = False 

433 _return_defaults_columns: Optional[Tuple[_ColumnsClauseElement, ...]] = ( 

434 None 

435 ) 

436 _supplemental_returning: Optional[Tuple[_ColumnsClauseElement, ...]] = None 

437 _returning: Tuple[_ColumnsClauseElement, ...] = () 

438 

439 is_dml = True 

440 

441 def _generate_fromclause_column_proxies( 

442 self, 

443 fromclause: FromClause, 

444 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

445 primary_key: ColumnSet, 

446 foreign_keys: Set[KeyedColumnElement[Any]], 

447 ) -> None: 

448 prox = [ 

449 c._make_proxy( 

450 fromclause, 

451 key=proxy_key, 

452 name=required_label_name, 

453 name_is_truncatable=True, 

454 primary_key=primary_key, 

455 foreign_keys=foreign_keys, 

456 ) 

457 for ( 

458 required_label_name, 

459 proxy_key, 

460 fallback_label_name, 

461 c, 

462 repeated, 

463 ) in (self._generate_columns_plus_names(False)) 

464 if is_column_element(c) 

465 ] 

466 

467 columns._populate_separate_keys(prox) 

468 

469 def params(self, *arg: Any, **kw: Any) -> NoReturn: 

470 """Set the parameters for the statement. 

471 

472 This method raises ``NotImplementedError`` on the base class, 

473 and is overridden by :class:`.ValuesBase` to provide the 

474 SET/VALUES clause of UPDATE and INSERT. 

475 

476 """ 

477 raise NotImplementedError( 

478 "params() is not supported for INSERT/UPDATE/DELETE statements." 

479 " To set the values for an INSERT or UPDATE statement, use" 

480 " stmt.values(**parameters)." 

481 ) 

482 

483 @_generative 

484 def with_dialect_options(self, **opt: Any) -> Self: 

485 """Add dialect options to this INSERT/UPDATE/DELETE object. 

486 

487 e.g.:: 

488 

489 upd = table.update().dialect_options(mysql_limit=10) 

490 

491 .. versionadded:: 1.4 - this method supersedes the dialect options 

492 associated with the constructor. 

493 

494 

495 """ 

496 self._validate_dialect_kwargs(opt) 

497 return self 

498 

499 @_generative 

500 def return_defaults( 

501 self, 

502 *cols: _DMLColumnArgument, 

503 supplemental_cols: Optional[Iterable[_DMLColumnArgument]] = None, 

504 sort_by_parameter_order: bool = False, 

505 ) -> Self: 

506 """Make use of a :term:`RETURNING` clause for the purpose 

507 of fetching server-side expressions and defaults, for supporting 

508 backends only. 

509 

510 .. deepalchemy:: 

511 

512 The :meth:`.UpdateBase.return_defaults` method is used by the ORM 

513 for its internal work in fetching newly generated primary key 

514 and server default values, in particular to provide the underlying 

515 implementation of the :paramref:`_orm.Mapper.eager_defaults` 

516 ORM feature as well as to allow RETURNING support with bulk 

517 ORM inserts. Its behavior is fairly idiosyncratic 

518 and is not really intended for general use. End users should 

519 stick with using :meth:`.UpdateBase.returning` in order to 

520 add RETURNING clauses to their INSERT, UPDATE and DELETE 

521 statements. 

522 

523 Normally, a single row INSERT statement will automatically populate the 

524 :attr:`.CursorResult.inserted_primary_key` attribute when executed, 

525 which stores the primary key of the row that was just inserted in the 

526 form of a :class:`.Row` object with column names as named tuple keys 

527 (and the :attr:`.Row._mapping` view fully populated as well). The 

528 dialect in use chooses the strategy to use in order to populate this 

529 data; if it was generated using server-side defaults and / or SQL 

530 expressions, dialect-specific approaches such as ``cursor.lastrowid`` 

531 or ``RETURNING`` are typically used to acquire the new primary key 

532 value. 

533 

534 However, when the statement is modified by calling 

535 :meth:`.UpdateBase.return_defaults` before executing the statement, 

536 additional behaviors take place **only** for backends that support 

537 RETURNING and for :class:`.Table` objects that maintain the 

538 :paramref:`.Table.implicit_returning` parameter at its default value of 

539 ``True``. In these cases, when the :class:`.CursorResult` is returned 

540 from the statement's execution, not only will 

541 :attr:`.CursorResult.inserted_primary_key` be populated as always, the 

542 :attr:`.CursorResult.returned_defaults` attribute will also be 

543 populated with a :class:`.Row` named-tuple representing the full range 

544 of server generated 

545 values from that single row, including values for any columns that 

546 specify :paramref:`_schema.Column.server_default` or which make use of 

547 :paramref:`_schema.Column.default` using a SQL expression. 

548 

549 When invoking INSERT statements with multiple rows using 

550 :ref:`insertmanyvalues <engine_insertmanyvalues>`, the 

551 :meth:`.UpdateBase.return_defaults` modifier will have the effect of 

552 the :attr:`_engine.CursorResult.inserted_primary_key_rows` and 

553 :attr:`_engine.CursorResult.returned_defaults_rows` attributes being 

554 fully populated with lists of :class:`.Row` objects representing newly 

555 inserted primary key values as well as newly inserted server generated 

556 values for each row inserted. The 

557 :attr:`.CursorResult.inserted_primary_key` and 

558 :attr:`.CursorResult.returned_defaults` attributes will also continue 

559 to be populated with the first row of these two collections. 

560 

561 If the backend does not support RETURNING or the :class:`.Table` in use 

562 has disabled :paramref:`.Table.implicit_returning`, then no RETURNING 

563 clause is added and no additional data is fetched, however the 

564 INSERT, UPDATE or DELETE statement proceeds normally. 

565 

566 E.g.:: 

567 

568 stmt = table.insert().values(data="newdata").return_defaults() 

569 

570 result = connection.execute(stmt) 

571 

572 server_created_at = result.returned_defaults["created_at"] 

573 

574 When used against an UPDATE statement 

575 :meth:`.UpdateBase.return_defaults` instead looks for columns that 

576 include :paramref:`_schema.Column.onupdate` or 

577 :paramref:`_schema.Column.server_onupdate` parameters assigned, when 

578 constructing the columns that will be included in the RETURNING clause 

579 by default if explicit columns were not specified. When used against a 

580 DELETE statement, no columns are included in RETURNING by default, they 

581 instead must be specified explicitly as there are no columns that 

582 normally change values when a DELETE statement proceeds. 

583 

584 .. versionadded:: 2.0 :meth:`.UpdateBase.return_defaults` is supported 

585 for DELETE statements also and has been moved from 

586 :class:`.ValuesBase` to :class:`.UpdateBase`. 

587 

588 The :meth:`.UpdateBase.return_defaults` method is mutually exclusive 

589 against the :meth:`.UpdateBase.returning` method and errors will be 

590 raised during the SQL compilation process if both are used at the same 

591 time on one statement. The RETURNING clause of the INSERT, UPDATE or 

592 DELETE statement is therefore controlled by only one of these methods 

593 at a time. 

594 

595 The :meth:`.UpdateBase.return_defaults` method differs from 

596 :meth:`.UpdateBase.returning` in these ways: 

597 

598 1. :meth:`.UpdateBase.return_defaults` method causes the 

599 :attr:`.CursorResult.returned_defaults` collection to be populated 

600 with the first row from the RETURNING result. This attribute is not 

601 populated when using :meth:`.UpdateBase.returning`. 

602 

603 2. :meth:`.UpdateBase.return_defaults` is compatible with existing 

604 logic used to fetch auto-generated primary key values that are then 

605 populated into the :attr:`.CursorResult.inserted_primary_key` 

606 attribute. By contrast, using :meth:`.UpdateBase.returning` will 

607 have the effect of the :attr:`.CursorResult.inserted_primary_key` 

608 attribute being left unpopulated. 

609 

610 3. :meth:`.UpdateBase.return_defaults` can be called against any 

611 backend. Backends that don't support RETURNING will skip the usage 

612 of the feature, rather than raising an exception, *unless* 

613 ``supplemental_cols`` is passed. The return value 

614 of :attr:`_engine.CursorResult.returned_defaults` will be ``None`` 

615 for backends that don't support RETURNING or for which the target 

616 :class:`.Table` sets :paramref:`.Table.implicit_returning` to 

617 ``False``. 

618 

619 4. An INSERT statement invoked with executemany() is supported if the 

620 backend database driver supports the 

621 :ref:`insertmanyvalues <engine_insertmanyvalues>` 

622 feature which is now supported by most SQLAlchemy-included backends. 

623 When executemany is used, the 

624 :attr:`_engine.CursorResult.returned_defaults_rows` and 

625 :attr:`_engine.CursorResult.inserted_primary_key_rows` accessors 

626 will return the inserted defaults and primary keys. 

627 

628 .. versionadded:: 1.4 Added 

629 :attr:`_engine.CursorResult.returned_defaults_rows` and 

630 :attr:`_engine.CursorResult.inserted_primary_key_rows` accessors. 

631 In version 2.0, the underlying implementation which fetches and 

632 populates the data for these attributes was generalized to be 

633 supported by most backends, whereas in 1.4 they were only 

634 supported by the ``psycopg2`` driver. 

635 

636 

637 :param cols: optional list of column key names or 

638 :class:`_schema.Column` that acts as a filter for those columns that 

639 will be fetched. 

640 :param supplemental_cols: optional list of RETURNING expressions, 

641 in the same form as one would pass to the 

642 :meth:`.UpdateBase.returning` method. When present, the additional 

643 columns will be included in the RETURNING clause, and the 

644 :class:`.CursorResult` object will be "rewound" when returned, so 

645 that methods like :meth:`.CursorResult.all` will return new rows 

646 mostly as though the statement used :meth:`.UpdateBase.returning` 

647 directly. However, unlike when using :meth:`.UpdateBase.returning` 

648 directly, the **order of the columns is undefined**, so can only be 

649 targeted using names or :attr:`.Row._mapping` keys; they cannot 

650 reliably be targeted positionally. 

651 

652 .. versionadded:: 2.0 

653 

654 :param sort_by_parameter_order: for a batch INSERT that is being 

655 executed against multiple parameter sets, organize the results of 

656 RETURNING so that the returned rows correspond to the order of 

657 parameter sets passed in. This applies only to an :term:`executemany` 

658 execution for supporting dialects and typically makes use of the 

659 :term:`insertmanyvalues` feature. 

660 

661 .. versionadded:: 2.0.10 

662 

663 .. seealso:: 

664 

665 :ref:`engine_insertmanyvalues_returning_order` - background on 

666 sorting of RETURNING rows for bulk INSERT 

667 

668 .. seealso:: 

669 

670 :meth:`.UpdateBase.returning` 

671 

672 :attr:`_engine.CursorResult.returned_defaults` 

673 

674 :attr:`_engine.CursorResult.returned_defaults_rows` 

675 

676 :attr:`_engine.CursorResult.inserted_primary_key` 

677 

678 :attr:`_engine.CursorResult.inserted_primary_key_rows` 

679 

680 """ 

681 

682 if self._return_defaults: 

683 # note _return_defaults_columns = () means return all columns, 

684 # so if we have been here before, only update collection if there 

685 # are columns in the collection 

686 if self._return_defaults_columns and cols: 

687 self._return_defaults_columns = tuple( 

688 util.OrderedSet(self._return_defaults_columns).union( 

689 coercions.expect(roles.ColumnsClauseRole, c) 

690 for c in cols 

691 ) 

692 ) 

693 else: 

694 # set for all columns 

695 self._return_defaults_columns = () 

696 else: 

697 self._return_defaults_columns = tuple( 

698 coercions.expect(roles.ColumnsClauseRole, c) for c in cols 

699 ) 

700 self._return_defaults = True 

701 if sort_by_parameter_order: 

702 if not self.is_insert: 

703 raise exc.ArgumentError( 

704 "The 'sort_by_parameter_order' argument to " 

705 "return_defaults() only applies to INSERT statements" 

706 ) 

707 self._sort_by_parameter_order = True 

708 if supplemental_cols: 

709 # uniquifying while also maintaining order (the maintain of order 

710 # is for test suites but also for vertical splicing 

711 supplemental_col_tup = ( 

712 coercions.expect(roles.ColumnsClauseRole, c) 

713 for c in supplemental_cols 

714 ) 

715 

716 if self._supplemental_returning is None: 

717 self._supplemental_returning = tuple( 

718 util.unique_list(supplemental_col_tup) 

719 ) 

720 else: 

721 self._supplemental_returning = tuple( 

722 util.unique_list( 

723 self._supplemental_returning 

724 + tuple(supplemental_col_tup) 

725 ) 

726 ) 

727 

728 return self 

729 

730 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

731 """Return ``True`` if this :class:`.ReturnsRows` is 

732 'derived' from the given :class:`.FromClause`. 

733 

734 Since these are DMLs, we dont want such statements ever being adapted 

735 so we return False for derives. 

736 

737 """ 

738 return False 

739 

740 @_generative 

741 def returning( 

742 self, 

743 *cols: _ColumnsClauseArgument[Any], 

744 sort_by_parameter_order: bool = False, 

745 **__kw: Any, 

746 ) -> UpdateBase: 

747 r"""Add a :term:`RETURNING` or equivalent clause to this statement. 

748 

749 e.g.: 

750 

751 .. sourcecode:: pycon+sql 

752 

753 >>> stmt = ( 

754 ... table.update() 

755 ... .where(table.c.data == "value") 

756 ... .values(status="X") 

757 ... .returning(table.c.server_flag, table.c.updated_timestamp) 

758 ... ) 

759 >>> print(stmt) 

760 {printsql}UPDATE some_table SET status=:status 

761 WHERE some_table.data = :data_1 

762 RETURNING some_table.server_flag, some_table.updated_timestamp 

763 

764 The method may be invoked multiple times to add new entries to the 

765 list of expressions to be returned. 

766 

767 .. versionadded:: 1.4.0b2 The method may be invoked multiple times to 

768 add new entries to the list of expressions to be returned. 

769 

770 The given collection of column expressions should be derived from the 

771 table that is the target of the INSERT, UPDATE, or DELETE. While 

772 :class:`_schema.Column` objects are typical, the elements can also be 

773 expressions: 

774 

775 .. sourcecode:: pycon+sql 

776 

777 >>> stmt = table.insert().returning( 

778 ... (table.c.first_name + " " + table.c.last_name).label("fullname") 

779 ... ) 

780 >>> print(stmt) 

781 {printsql}INSERT INTO some_table (first_name, last_name) 

782 VALUES (:first_name, :last_name) 

783 RETURNING some_table.first_name || :first_name_1 || some_table.last_name AS fullname 

784 

785 Upon compilation, a RETURNING clause, or database equivalent, 

786 will be rendered within the statement. For INSERT and UPDATE, 

787 the values are the newly inserted/updated values. For DELETE, 

788 the values are those of the rows which were deleted. 

789 

790 Upon execution, the values of the columns to be returned are made 

791 available via the result set and can be iterated using 

792 :meth:`_engine.CursorResult.fetchone` and similar. 

793 For DBAPIs which do not 

794 natively support returning values (i.e. cx_oracle), SQLAlchemy will 

795 approximate this behavior at the result level so that a reasonable 

796 amount of behavioral neutrality is provided. 

797 

798 Note that not all databases/DBAPIs 

799 support RETURNING. For those backends with no support, 

800 an exception is raised upon compilation and/or execution. 

801 For those who do support it, the functionality across backends 

802 varies greatly, including restrictions on executemany() 

803 and other statements which return multiple rows. Please 

804 read the documentation notes for the database in use in 

805 order to determine the availability of RETURNING. 

806 

807 :param \*cols: series of columns, SQL expressions, or whole tables 

808 entities to be returned. 

809 :param sort_by_parameter_order: for a batch INSERT that is being 

810 executed against multiple parameter sets, organize the results of 

811 RETURNING so that the returned rows correspond to the order of 

812 parameter sets passed in. This applies only to an :term:`executemany` 

813 execution for supporting dialects and typically makes use of the 

814 :term:`insertmanyvalues` feature. 

815 

816 .. versionadded:: 2.0.10 

817 

818 .. seealso:: 

819 

820 :ref:`engine_insertmanyvalues_returning_order` - background on 

821 sorting of RETURNING rows for bulk INSERT (Core level discussion) 

822 

823 :ref:`orm_queryguide_bulk_insert_returning_ordered` - example of 

824 use with :ref:`orm_queryguide_bulk_insert` (ORM level discussion) 

825 

826 .. seealso:: 

827 

828 :meth:`.UpdateBase.return_defaults` - an alternative method tailored 

829 towards efficient fetching of server-side defaults and triggers 

830 for single-row INSERTs or UPDATEs. 

831 

832 :ref:`tutorial_insert_returning` - in the :ref:`unified_tutorial` 

833 

834 """ # noqa: E501 

835 if __kw: 

836 raise _unexpected_kw("UpdateBase.returning()", __kw) 

837 if self._return_defaults: 

838 raise exc.InvalidRequestError( 

839 "return_defaults() is already configured on this statement" 

840 ) 

841 self._returning += tuple( 

842 coercions.expect(roles.ColumnsClauseRole, c) for c in cols 

843 ) 

844 if sort_by_parameter_order: 

845 if not self.is_insert: 

846 raise exc.ArgumentError( 

847 "The 'sort_by_parameter_order' argument to returning() " 

848 "only applies to INSERT statements" 

849 ) 

850 self._sort_by_parameter_order = True 

851 return self 

852 

853 def corresponding_column( 

854 self, column: KeyedColumnElement[Any], require_embedded: bool = False 

855 ) -> Optional[ColumnElement[Any]]: 

856 return self.exported_columns.corresponding_column( 

857 column, require_embedded=require_embedded 

858 ) 

859 

860 @util.ro_memoized_property 

861 def _all_selected_columns(self) -> _SelectIterable: 

862 return [c for c in _select_iterables(self._returning)] 

863 

864 @util.ro_memoized_property 

865 def exported_columns( 

866 self, 

867 ) -> ReadOnlyColumnCollection[Optional[str], ColumnElement[Any]]: 

868 """Return the RETURNING columns as a column collection for this 

869 statement. 

870 

871 .. versionadded:: 1.4 

872 

873 """ 

874 return WriteableColumnCollection( 

875 (c.key, c) 

876 for c in self._all_selected_columns 

877 if is_column_element(c) 

878 ).as_readonly() 

879 

880 @_generative 

881 def with_hint( 

882 self, 

883 text: str, 

884 selectable: Optional[_DMLTableArgument] = None, 

885 dialect_name: str = "*", 

886 ) -> Self: 

887 """Add a table hint for a single table to this 

888 INSERT/UPDATE/DELETE statement. 

889 

890 .. note:: 

891 

892 :meth:`.UpdateBase.with_hint` currently applies only to 

893 Microsoft SQL Server. For MySQL INSERT/UPDATE/DELETE hints, use 

894 :meth:`.UpdateBase.prefix_with`. 

895 

896 The text of the hint is rendered in the appropriate 

897 location for the database backend in use, relative 

898 to the :class:`_schema.Table` that is the subject of this 

899 statement, or optionally to that of the given 

900 :class:`_schema.Table` passed as the ``selectable`` argument. 

901 

902 The ``dialect_name`` option will limit the rendering of a particular 

903 hint to a particular backend. Such as, to add a hint 

904 that only takes effect for SQL Server:: 

905 

906 mytable.insert().with_hint("WITH (PAGLOCK)", dialect_name="mssql") 

907 

908 :param text: Text of the hint. 

909 :param selectable: optional :class:`_schema.Table` that specifies 

910 an element of the FROM clause within an UPDATE or DELETE 

911 to be the subject of the hint - applies only to certain backends. 

912 :param dialect_name: defaults to ``*``, if specified as the name 

913 of a particular dialect, will apply these hints only when 

914 that dialect is in use. 

915 """ 

916 if selectable is None: 

917 selectable = self.table 

918 else: 

919 selectable = coercions.expect(roles.DMLTableRole, selectable) 

920 self._hints = self._hints.union({(selectable, dialect_name): text}) 

921 return self 

922 

923 @property 

924 def entity_description(self) -> Dict[str, Any]: 

925 """Return a :term:`plugin-enabled` description of the table and/or 

926 entity which this DML construct is operating against. 

927 

928 This attribute is generally useful when using the ORM, as an 

929 extended structure which includes information about mapped 

930 entities is returned. The section :ref:`queryguide_inspection` 

931 contains more background. 

932 

933 For a Core statement, the structure returned by this accessor 

934 is derived from the :attr:`.UpdateBase.table` attribute, and 

935 refers to the :class:`.Table` being inserted, updated, or deleted:: 

936 

937 >>> stmt = insert(user_table) 

938 >>> stmt.entity_description 

939 { 

940 "name": "user_table", 

941 "table": Table("user_table", ...) 

942 } 

943 

944 .. versionadded:: 1.4.33 

945 

946 .. seealso:: 

947 

948 :attr:`.UpdateBase.returning_column_descriptions` 

949 

950 :attr:`.Select.column_descriptions` - entity information for 

951 a :func:`.select` construct 

952 

953 :ref:`queryguide_inspection` - ORM background 

954 

955 """ 

956 meth = DMLState.get_plugin_class(self).get_entity_description 

957 return meth(self) 

958 

959 @property 

960 def returning_column_descriptions(self) -> List[Dict[str, Any]]: 

961 """Return a :term:`plugin-enabled` description of the columns 

962 which this DML construct is RETURNING against, in other words 

963 the expressions established as part of :meth:`.UpdateBase.returning`. 

964 

965 This attribute is generally useful when using the ORM, as an 

966 extended structure which includes information about mapped 

967 entities is returned. The section :ref:`queryguide_inspection` 

968 contains more background. 

969 

970 For a Core statement, the structure returned by this accessor is 

971 derived from the same objects that are returned by the 

972 :attr:`.UpdateBase.exported_columns` accessor:: 

973 

974 >>> stmt = insert(user_table).returning(user_table.c.id, user_table.c.name) 

975 >>> stmt.entity_description 

976 [ 

977 { 

978 "name": "id", 

979 "type": Integer, 

980 "expr": Column("id", Integer(), table=<user>, ...) 

981 }, 

982 { 

983 "name": "name", 

984 "type": String(), 

985 "expr": Column("name", String(), table=<user>, ...) 

986 }, 

987 ] 

988 

989 .. versionadded:: 1.4.33 

990 

991 .. seealso:: 

992 

993 :attr:`.UpdateBase.entity_description` 

994 

995 :attr:`.Select.column_descriptions` - entity information for 

996 a :func:`.select` construct 

997 

998 :ref:`queryguide_inspection` - ORM background 

999 

1000 """ # noqa: E501 

1001 meth = DMLState.get_plugin_class( 

1002 self 

1003 ).get_returning_column_descriptions 

1004 return meth(self) 

1005 

1006 

1007class ValuesBase(UpdateBase): 

1008 """Supplies support for :meth:`.ValuesBase.values` to 

1009 INSERT and UPDATE constructs.""" 

1010 

1011 __visit_name__ = "values_base" 

1012 

1013 _supports_multi_parameters = False 

1014 

1015 select: Optional[Select[Unpack[TupleAny]]] = None 

1016 """SELECT statement for INSERT .. FROM SELECT""" 

1017 

1018 _post_values_clause: Optional[ClauseElement] = None 

1019 """used by extensions to Insert etc. to add additional syntactical 

1020 constructs, e.g. ON CONFLICT etc.""" 

1021 

1022 _values: Optional[util.immutabledict[_DMLColumnElement, Any]] = None 

1023 _multi_values: Tuple[ 

1024 Union[ 

1025 Sequence[Dict[_DMLColumnElement, Any]], 

1026 Sequence[Sequence[Any]], 

1027 ], 

1028 ..., 

1029 ] = () 

1030 

1031 _maintain_values_ordering: bool = False 

1032 

1033 _select_names: Optional[List[str]] = None 

1034 _inline: bool = False 

1035 

1036 def __init__(self, table: _DMLTableArgument): 

1037 self.table = coercions.expect( 

1038 roles.DMLTableRole, table, apply_propagate_attrs=self 

1039 ) 

1040 

1041 @_generative 

1042 @_exclusive_against( 

1043 "_select_names", 

1044 "_maintain_values_ordering", 

1045 msgs={ 

1046 "_select_names": "This construct already inserts from a SELECT", 

1047 "_maintain_values_ordering": "This statement already has ordered " 

1048 "values present", 

1049 }, 

1050 defaults={"_maintain_values_ordering": False}, 

1051 ) 

1052 def values( 

1053 self, 

1054 *args: Union[ 

1055 _DMLColumnKeyMapping[Any], 

1056 Sequence[Any], 

1057 ], 

1058 **kwargs: Any, 

1059 ) -> Self: 

1060 r"""Specify a fixed VALUES clause for an INSERT statement, or the SET 

1061 clause for an UPDATE. 

1062 

1063 Note that the :class:`_expression.Insert` and 

1064 :class:`_expression.Update` 

1065 constructs support 

1066 per-execution time formatting of the VALUES and/or SET clauses, 

1067 based on the arguments passed to :meth:`_engine.Connection.execute`. 

1068 However, the :meth:`.ValuesBase.values` method can be used to "fix" a 

1069 particular set of parameters into the statement. 

1070 

1071 Multiple calls to :meth:`.ValuesBase.values` will produce a new 

1072 construct, each one with the parameter list modified to include 

1073 the new parameters sent. In the typical case of a single 

1074 dictionary of parameters, the newly passed keys will replace 

1075 the same keys in the previous construct. In the case of a list-based 

1076 "multiple values" construct, each new list of values is extended 

1077 onto the existing list of values. 

1078 

1079 :param \**kwargs: key value pairs representing the string key 

1080 of a :class:`_schema.Column` 

1081 mapped to the value to be rendered into the 

1082 VALUES or SET clause:: 

1083 

1084 users.insert().values(name="some name") 

1085 

1086 users.update().where(users.c.id == 5).values(name="some name") 

1087 

1088 :param \*args: As an alternative to passing key/value parameters, 

1089 a dictionary, tuple, or list of dictionaries or tuples can be passed 

1090 as a single positional argument in order to form the VALUES or 

1091 SET clause of the statement. The forms that are accepted vary 

1092 based on whether this is an :class:`_expression.Insert` or an 

1093 :class:`_expression.Update` construct. 

1094 

1095 For either an :class:`_expression.Insert` or 

1096 :class:`_expression.Update` 

1097 construct, a single dictionary can be passed, which works the same as 

1098 that of the kwargs form:: 

1099 

1100 users.insert().values({"name": "some name"}) 

1101 

1102 users.update().values({"name": "some new name"}) 

1103 

1104 Also for either form but more typically for the 

1105 :class:`_expression.Insert` construct, a tuple that contains an 

1106 entry for every column in the table is also accepted:: 

1107 

1108 users.insert().values((5, "some name")) 

1109 

1110 The :class:`_expression.Insert` construct also supports being 

1111 passed a list of dictionaries or full-table-tuples, which on the 

1112 server will render the less common SQL syntax of "multiple values" - 

1113 this syntax is supported on backends such as SQLite, PostgreSQL, 

1114 MySQL, but not necessarily others:: 

1115 

1116 users.insert().values( 

1117 [ 

1118 {"name": "some name"}, 

1119 {"name": "some other name"}, 

1120 {"name": "yet another name"}, 

1121 ] 

1122 ) 

1123 

1124 The above form would render a multiple VALUES statement similar to: 

1125 

1126 .. sourcecode:: sql 

1127 

1128 INSERT INTO users (name) VALUES 

1129 (:name_1), 

1130 (:name_2), 

1131 (:name_3) 

1132 

1133 It is essential to note that **passing multiple values is 

1134 NOT the same as using traditional executemany() form**. The above 

1135 syntax is a **special** syntax not typically used. To emit an 

1136 INSERT statement against multiple rows, the normal method is 

1137 to pass a multiple values list to the 

1138 :meth:`_engine.Connection.execute` 

1139 method, which is supported by all database backends and is generally 

1140 more efficient for a very large number of parameters. 

1141 

1142 .. seealso:: 

1143 

1144 :ref:`tutorial_multiple_parameters` - an introduction to 

1145 the traditional Core method of multiple parameter set 

1146 invocation for INSERTs and other statements. 

1147 

1148 :ref:`tutorial_core_insert_values_clause` - Insert tutorial 

1149 detailing alternatives to the multiple values syntax. 

1150 

1151 The UPDATE construct also supports rendering the SET parameters 

1152 in a specific order. For this feature refer to the 

1153 :meth:`_expression.Update.ordered_values` method. 

1154 

1155 .. seealso:: 

1156 

1157 :meth:`_expression.Update.ordered_values` 

1158 

1159 

1160 """ 

1161 if args: 

1162 # positional case. this is currently expensive. we don't 

1163 # yet have positional-only args so we have to check the length. 

1164 # then we need to check multiparams vs. single dictionary. 

1165 # since the parameter format is needed in order to determine 

1166 # a cache key, we need to determine this up front. 

1167 arg = args[0] 

1168 

1169 if kwargs: 

1170 raise exc.ArgumentError( 

1171 "Can't pass positional and kwargs to values() " 

1172 "simultaneously" 

1173 ) 

1174 elif len(args) > 1: 

1175 raise exc.ArgumentError( 

1176 "Only a single dictionary/tuple or list of " 

1177 "dictionaries/tuples is accepted positionally." 

1178 ) 

1179 

1180 elif isinstance(arg, collections_abc.Sequence): 

1181 if arg and isinstance(arg[0], dict): 

1182 multi_kv_generator = DMLState.get_plugin_class( 

1183 self 

1184 )._get_multi_crud_kv_pairs 

1185 self._multi_values += (multi_kv_generator(self, arg),) 

1186 return self 

1187 

1188 if arg and isinstance(arg[0], (list, tuple)): 

1189 self._multi_values += (arg,) 

1190 return self 

1191 

1192 if TYPE_CHECKING: 

1193 # crud.py raises during compilation if this is not the 

1194 # case 

1195 assert isinstance(self, Insert) 

1196 

1197 # tuple values 

1198 arg = {c.key: value for c, value in zip(self.table.c, arg)} 

1199 

1200 else: 

1201 # kwarg path. this is the most common path for non-multi-params 

1202 # so this is fairly quick. 

1203 arg = cast("Dict[_DMLColumnArgument, Any]", kwargs) 

1204 if args: 

1205 raise exc.ArgumentError( 

1206 "Only a single dictionary/tuple or list of " 

1207 "dictionaries/tuples is accepted positionally." 

1208 ) 

1209 

1210 # for top level values(), convert literals to anonymous bound 

1211 # parameters at statement construction time, so that these values can 

1212 # participate in the cache key process like any other ClauseElement. 

1213 # crud.py now intercepts bound parameters with unique=True from here 

1214 # and ensures they get the "crud"-style name when rendered. 

1215 

1216 kv_generator = DMLState.get_plugin_class(self)._get_crud_kv_pairs 

1217 coerced_arg = dict(kv_generator(self, arg.items(), True)) 

1218 if self._values: 

1219 self._values = self._values.union(coerced_arg) 

1220 else: 

1221 self._values = util.immutabledict(coerced_arg) 

1222 return self 

1223 

1224 

1225class Insert(ValuesBase, HasSyntaxExtensions[Literal["post_values"]]): 

1226 """Represent an INSERT construct. 

1227 

1228 The :class:`_expression.Insert` object is created using the 

1229 :func:`_expression.insert()` function. 

1230 

1231 Available extension points: 

1232 

1233 * ``post_values``: applies additional logic after the ``VALUES`` clause. 

1234 

1235 """ 

1236 

1237 __visit_name__ = "insert" 

1238 

1239 _supports_multi_parameters = True 

1240 

1241 select = None 

1242 include_insert_from_select_defaults = False 

1243 

1244 _sort_by_parameter_order: bool = False 

1245 

1246 is_insert = True 

1247 

1248 table: TableClause 

1249 

1250 _traverse_internals = ( 

1251 [ 

1252 ("table", InternalTraversal.dp_clauseelement), 

1253 ("_inline", InternalTraversal.dp_boolean), 

1254 ("_select_names", InternalTraversal.dp_string_list), 

1255 ("_values", InternalTraversal.dp_dml_values), 

1256 ("_multi_values", InternalTraversal.dp_dml_multi_values), 

1257 ("select", InternalTraversal.dp_clauseelement), 

1258 ("_post_values_clause", InternalTraversal.dp_clauseelement), 

1259 ("_returning", InternalTraversal.dp_clauseelement_tuple), 

1260 ("_hints", InternalTraversal.dp_table_hint_list), 

1261 ("_return_defaults", InternalTraversal.dp_boolean), 

1262 ( 

1263 "_return_defaults_columns", 

1264 InternalTraversal.dp_clauseelement_tuple, 

1265 ), 

1266 ("_sort_by_parameter_order", InternalTraversal.dp_boolean), 

1267 ] 

1268 + HasPrefixes._has_prefixes_traverse_internals 

1269 + DialectKWArgs._dialect_kwargs_traverse_internals 

1270 + ExecutableStatement._executable_traverse_internals 

1271 + HasCTE._has_ctes_traverse_internals 

1272 ) 

1273 

1274 _position_map = util.immutabledict( 

1275 { 

1276 "post_values": "_post_values_clause", 

1277 } 

1278 ) 

1279 

1280 _post_values_clause: Optional[ClauseElement] = None 

1281 """extension point for a ClauseElement that will be compiled directly 

1282 after the VALUES portion of the :class:`.Insert` statement 

1283 

1284 """ 

1285 

1286 def __init__(self, table: _DMLTableArgument): 

1287 super().__init__(table) 

1288 

1289 def _apply_syntax_extension_to_self( 

1290 self, extension: SyntaxExtension 

1291 ) -> None: 

1292 extension.apply_to_insert(self) 

1293 

1294 @_generative 

1295 def inline(self) -> Self: 

1296 """Make this :class:`_expression.Insert` construct "inline" . 

1297 

1298 When set, no attempt will be made to retrieve the 

1299 SQL-generated default values to be provided within the statement; 

1300 in particular, 

1301 this allows SQL expressions to be rendered 'inline' within the 

1302 statement without the need to pre-execute them beforehand; for 

1303 backends that support "returning", this turns off the "implicit 

1304 returning" feature for the statement. 

1305 

1306 

1307 .. versionchanged:: 1.4 the :paramref:`_expression.Insert.inline` 

1308 parameter 

1309 is now superseded by the :meth:`_expression.Insert.inline` method. 

1310 

1311 """ 

1312 self._inline = True 

1313 return self 

1314 

1315 @_generative 

1316 def from_select( 

1317 self, 

1318 names: Sequence[_DMLColumnArgument], 

1319 select: Selectable, 

1320 include_defaults: bool = True, 

1321 ) -> Self: 

1322 """Return a new :class:`_expression.Insert` construct which represents 

1323 an ``INSERT...FROM SELECT`` statement. 

1324 

1325 e.g.:: 

1326 

1327 sel = select(table1.c.a, table1.c.b).where(table1.c.c > 5) 

1328 ins = table2.insert().from_select(["a", "b"], sel) 

1329 

1330 :param names: a sequence of string column names or 

1331 :class:`_schema.Column` 

1332 objects representing the target columns. 

1333 :param select: a :func:`_expression.select` construct, 

1334 :class:`_expression.FromClause` 

1335 or other construct which resolves into a 

1336 :class:`_expression.FromClause`, 

1337 such as an ORM :class:`_query.Query` object, etc. The order of 

1338 columns returned from this FROM clause should correspond to the 

1339 order of columns sent as the ``names`` parameter; while this 

1340 is not checked before passing along to the database, the database 

1341 would normally raise an exception if these column lists don't 

1342 correspond. 

1343 :param include_defaults: if True, non-server default values and 

1344 SQL expressions as specified on :class:`_schema.Column` objects 

1345 (as documented in :ref:`metadata_defaults_toplevel`) not 

1346 otherwise specified in the list of names will be rendered 

1347 into the INSERT and SELECT statements, so that these values are also 

1348 included in the data to be inserted. 

1349 

1350 .. note:: A Python-side default that uses a Python callable function 

1351 will only be invoked **once** for the whole statement, and **not 

1352 per row**. 

1353 

1354 """ 

1355 

1356 if self._values: 

1357 raise exc.InvalidRequestError( 

1358 "This construct already inserts value expressions" 

1359 ) 

1360 

1361 self._select_names = [ 

1362 coercions.expect(roles.DMLColumnRole, name, as_key=True) 

1363 for name in names 

1364 ] 

1365 self._inline = True 

1366 self.include_insert_from_select_defaults = include_defaults 

1367 self.select = coercions.expect(roles.DMLSelectRole, select) 

1368 return self 

1369 

1370 if TYPE_CHECKING: 

1371 # START OVERLOADED FUNCTIONS self.returning ReturningInsert 1-8 ", *, sort_by_parameter_order: bool = False" # noqa: E501 

1372 

1373 # code within this block is **programmatically, 

1374 # statically generated** by tools/generate_tuple_map_overloads.py 

1375 

1376 @overload 

1377 def returning( 

1378 self, 

1379 __ent0: _TCCA[_T0], 

1380 /, 

1381 *, 

1382 sort_by_parameter_order: bool = False, 

1383 ) -> ReturningInsert[_T0]: ... 

1384 

1385 @overload 

1386 def returning( 

1387 self, 

1388 __ent0: _TCCA[_T0], 

1389 __ent1: _TCCA[_T1], 

1390 /, 

1391 *, 

1392 sort_by_parameter_order: bool = False, 

1393 ) -> ReturningInsert[_T0, _T1]: ... 

1394 

1395 @overload 

1396 def returning( 

1397 self, 

1398 __ent0: _TCCA[_T0], 

1399 __ent1: _TCCA[_T1], 

1400 __ent2: _TCCA[_T2], 

1401 /, 

1402 *, 

1403 sort_by_parameter_order: bool = False, 

1404 ) -> ReturningInsert[_T0, _T1, _T2]: ... 

1405 

1406 @overload 

1407 def returning( 

1408 self, 

1409 __ent0: _TCCA[_T0], 

1410 __ent1: _TCCA[_T1], 

1411 __ent2: _TCCA[_T2], 

1412 __ent3: _TCCA[_T3], 

1413 /, 

1414 *, 

1415 sort_by_parameter_order: bool = False, 

1416 ) -> ReturningInsert[_T0, _T1, _T2, _T3]: ... 

1417 

1418 @overload 

1419 def returning( 

1420 self, 

1421 __ent0: _TCCA[_T0], 

1422 __ent1: _TCCA[_T1], 

1423 __ent2: _TCCA[_T2], 

1424 __ent3: _TCCA[_T3], 

1425 __ent4: _TCCA[_T4], 

1426 /, 

1427 *, 

1428 sort_by_parameter_order: bool = False, 

1429 ) -> ReturningInsert[_T0, _T1, _T2, _T3, _T4]: ... 

1430 

1431 @overload 

1432 def returning( 

1433 self, 

1434 __ent0: _TCCA[_T0], 

1435 __ent1: _TCCA[_T1], 

1436 __ent2: _TCCA[_T2], 

1437 __ent3: _TCCA[_T3], 

1438 __ent4: _TCCA[_T4], 

1439 __ent5: _TCCA[_T5], 

1440 /, 

1441 *, 

1442 sort_by_parameter_order: bool = False, 

1443 ) -> ReturningInsert[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

1444 

1445 @overload 

1446 def returning( 

1447 self, 

1448 __ent0: _TCCA[_T0], 

1449 __ent1: _TCCA[_T1], 

1450 __ent2: _TCCA[_T2], 

1451 __ent3: _TCCA[_T3], 

1452 __ent4: _TCCA[_T4], 

1453 __ent5: _TCCA[_T5], 

1454 __ent6: _TCCA[_T6], 

1455 /, 

1456 *, 

1457 sort_by_parameter_order: bool = False, 

1458 ) -> ReturningInsert[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

1459 

1460 @overload 

1461 def returning( 

1462 self, 

1463 __ent0: _TCCA[_T0], 

1464 __ent1: _TCCA[_T1], 

1465 __ent2: _TCCA[_T2], 

1466 __ent3: _TCCA[_T3], 

1467 __ent4: _TCCA[_T4], 

1468 __ent5: _TCCA[_T5], 

1469 __ent6: _TCCA[_T6], 

1470 __ent7: _TCCA[_T7], 

1471 /, 

1472 *entities: _ColumnsClauseArgument[Any], 

1473 sort_by_parameter_order: bool = False, 

1474 ) -> ReturningInsert[ 

1475 _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny] 

1476 ]: ... 

1477 

1478 # END OVERLOADED FUNCTIONS self.returning 

1479 

1480 @overload 

1481 def returning( 

1482 self, 

1483 *cols: _ColumnsClauseArgument[Any], 

1484 sort_by_parameter_order: bool = False, 

1485 **__kw: Any, 

1486 ) -> ReturningInsert[Any]: ... 

1487 

1488 def returning( 

1489 self, 

1490 *cols: _ColumnsClauseArgument[Any], 

1491 sort_by_parameter_order: bool = False, 

1492 **__kw: Any, 

1493 ) -> ReturningInsert[Any]: ... 

1494 

1495 

1496class ReturningInsert(Insert, TypedReturnsRows[Unpack[_Ts]]): 

1497 """Typing-only class that establishes a generic type form of 

1498 :class:`.Insert` which tracks returned column types. 

1499 

1500 This datatype is delivered when calling the 

1501 :meth:`.Insert.returning` method. 

1502 

1503 .. versionadded:: 2.0 

1504 

1505 """ 

1506 

1507 

1508# note: if not for MRO issues, this class should extend 

1509# from HasSyntaxExtensions[Literal["post_criteria"]] 

1510class DMLWhereBase: 

1511 table: _DMLTableElement 

1512 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

1513 

1514 _post_criteria_clause: Optional[ClauseElement] = None 

1515 """used by extensions to Update/Delete etc. to add additional syntacitcal 

1516 constructs, e.g. LIMIT etc. 

1517 

1518 .. versionadded:: 2.1 

1519 

1520 """ 

1521 

1522 # can't put position_map here either without HasSyntaxExtensions 

1523 # _position_map = util.immutabledict( 

1524 # {"post_criteria": "_post_criteria_clause"} 

1525 # ) 

1526 

1527 @_generative 

1528 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

1529 """Return a new construct with the given expression(s) added to 

1530 its WHERE clause, joined to the existing clause via AND, if any. 

1531 

1532 Both :meth:`_dml.Update.where` and :meth:`_dml.Delete.where` 

1533 support multiple-table forms, including database-specific 

1534 ``UPDATE...FROM`` as well as ``DELETE..USING``. For backends that 

1535 don't have multiple-table support, a backend agnostic approach 

1536 to using multiple tables is to make use of correlated subqueries. 

1537 See the linked tutorial sections below for examples. 

1538 

1539 .. seealso:: 

1540 

1541 :ref:`tutorial_correlated_updates` 

1542 

1543 :ref:`tutorial_update_from` 

1544 

1545 :ref:`tutorial_multi_table_deletes` 

1546 

1547 """ 

1548 

1549 for criterion in whereclause: 

1550 where_criteria: ColumnElement[Any] = coercions.expect( 

1551 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

1552 ) 

1553 self._where_criteria += (where_criteria,) 

1554 return self 

1555 

1556 def filter(self, *criteria: roles.ExpressionElementRole[Any]) -> Self: 

1557 """A synonym for the :meth:`.where` method. 

1558 

1559 .. versionadded:: 1.4 

1560 

1561 """ 

1562 

1563 return self.where(*criteria) 

1564 

1565 def filter_by(self, **kwargs: Any) -> Self: 

1566 r"""Apply the given filtering criterion as a WHERE clause 

1567 to this DML statement, using keyword expressions. 

1568 

1569 E.g.:: 

1570 

1571 stmt = update(User).filter_by(name="some name").values(fullname="New Name") 

1572 

1573 Multiple criteria may be specified as comma separated; the effect 

1574 is that they will be joined together using the :func:`.and_` 

1575 function:: 

1576 

1577 stmt = delete(User).filter_by(name="some name", id=5) 

1578 

1579 The keyword expressions are extracted by searching across **all 

1580 entities present in the FROM clause** of the statement. 

1581 

1582 .. versionchanged:: 2.1 

1583 

1584 :meth:`.DMLWhereBase.filter_by` now searches across all FROM clause 

1585 entities, consistent with :meth:`_sql.Select.filter_by`. 

1586 

1587 .. seealso:: 

1588 

1589 :meth:`.where` - filter on SQL expressions. 

1590 

1591 :meth:`_sql.Select.filter_by` 

1592 

1593 """ # noqa: E501 

1594 

1595 entities: set[Any] 

1596 

1597 if not isinstance(self.table, TableClause): 

1598 entities = set( 

1599 sql_util.find_tables( 

1600 self.table, check_columns=False, include_joins=False 

1601 ) 

1602 ) 

1603 else: 

1604 entities = {self.table} 

1605 

1606 if self.whereclause is not None: 

1607 entities.update(self.whereclause._from_objects) 

1608 

1609 clauses = [ 

1610 _entity_namespace_key_search_all(entities, key) == value 

1611 for key, value in kwargs.items() 

1612 ] 

1613 return self.filter(*clauses) 

1614 

1615 @property 

1616 def whereclause(self) -> Optional[ColumnElement[Any]]: 

1617 """Return the completed WHERE clause for this :class:`.DMLWhereBase` 

1618 statement. 

1619 

1620 This assembles the current collection of WHERE criteria 

1621 into a single :class:`_expression.BooleanClauseList` construct. 

1622 

1623 

1624 .. versionadded:: 1.4 

1625 

1626 """ 

1627 

1628 return BooleanClauseList._construct_for_whereclause( 

1629 self._where_criteria 

1630 ) 

1631 

1632 

1633class Update( 

1634 DMLWhereBase, ValuesBase, HasSyntaxExtensions[Literal["post_criteria"]] 

1635): 

1636 """Represent an Update construct. 

1637 

1638 The :class:`_expression.Update` object is created using the 

1639 :func:`_expression.update()` function. 

1640 

1641 Available extension points: 

1642 

1643 * ``post_criteria``: applies additional logic after the ``WHERE`` clause. 

1644 

1645 """ 

1646 

1647 __visit_name__ = "update" 

1648 

1649 is_update = True 

1650 

1651 _traverse_internals = ( 

1652 [ 

1653 ("table", InternalTraversal.dp_clauseelement), 

1654 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

1655 ("_inline", InternalTraversal.dp_boolean), 

1656 ("_maintain_values_ordering", InternalTraversal.dp_boolean), 

1657 ("_values", InternalTraversal.dp_dml_values), 

1658 ("_returning", InternalTraversal.dp_clauseelement_tuple), 

1659 ("_hints", InternalTraversal.dp_table_hint_list), 

1660 ("_return_defaults", InternalTraversal.dp_boolean), 

1661 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

1662 ( 

1663 "_return_defaults_columns", 

1664 InternalTraversal.dp_clauseelement_tuple, 

1665 ), 

1666 ] 

1667 + HasPrefixes._has_prefixes_traverse_internals 

1668 + DialectKWArgs._dialect_kwargs_traverse_internals 

1669 + ExecutableStatement._executable_traverse_internals 

1670 + HasCTE._has_ctes_traverse_internals 

1671 ) 

1672 

1673 _position_map = util.immutabledict( 

1674 {"post_criteria": "_post_criteria_clause"} 

1675 ) 

1676 

1677 def __init__(self, table: _DMLTableArgument): 

1678 super().__init__(table) 

1679 

1680 def ordered_values(self, *args: Tuple[_DMLColumnArgument, Any]) -> Self: 

1681 """Specify the VALUES clause of this UPDATE statement with an explicit 

1682 parameter ordering that will be maintained in the SET clause of the 

1683 resulting UPDATE statement. 

1684 

1685 E.g.:: 

1686 

1687 stmt = table.update().ordered_values(("name", "ed"), ("ident", "foo")) 

1688 

1689 .. seealso:: 

1690 

1691 :ref:`tutorial_parameter_ordered_updates` - full example of the 

1692 :meth:`_expression.Update.ordered_values` method. 

1693 

1694 .. versionchanged:: 1.4 The :meth:`_expression.Update.ordered_values` 

1695 method 

1696 supersedes the 

1697 :paramref:`_expression.update.preserve_parameter_order` 

1698 parameter, which will be removed in SQLAlchemy 2.0. 

1699 

1700 """ # noqa: E501 

1701 if self._values: 

1702 raise exc.ArgumentError( 

1703 "This statement already has " 

1704 f"{'ordered ' if self._maintain_values_ordering else ''}" 

1705 "values present" 

1706 ) 

1707 

1708 self = self.values(dict(args)) 

1709 self._maintain_values_ordering = True 

1710 return self 

1711 

1712 @_generative 

1713 def inline(self) -> Self: 

1714 """Make this :class:`_expression.Update` construct "inline" . 

1715 

1716 When set, SQL defaults present on :class:`_schema.Column` 

1717 objects via the 

1718 ``default`` keyword will be compiled 'inline' into the statement and 

1719 not pre-executed. This means that their values will not be available 

1720 in the dictionary returned from 

1721 :meth:`_engine.CursorResult.last_updated_params`. 

1722 

1723 .. versionchanged:: 1.4 the :paramref:`_expression.update.inline` 

1724 parameter 

1725 is now superseded by the :meth:`_expression.Update.inline` method. 

1726 

1727 """ 

1728 self._inline = True 

1729 return self 

1730 

1731 def _apply_syntax_extension_to_self( 

1732 self, extension: SyntaxExtension 

1733 ) -> None: 

1734 extension.apply_to_update(self) 

1735 

1736 if TYPE_CHECKING: 

1737 # START OVERLOADED FUNCTIONS self.returning ReturningUpdate 1-8 

1738 

1739 # code within this block is **programmatically, 

1740 # statically generated** by tools/generate_tuple_map_overloads.py 

1741 

1742 @overload 

1743 def returning(self, __ent0: _TCCA[_T0], /) -> ReturningUpdate[_T0]: ... 

1744 

1745 @overload 

1746 def returning( 

1747 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], / 

1748 ) -> ReturningUpdate[_T0, _T1]: ... 

1749 

1750 @overload 

1751 def returning( 

1752 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2], / 

1753 ) -> ReturningUpdate[_T0, _T1, _T2]: ... 

1754 

1755 @overload 

1756 def returning( 

1757 self, 

1758 __ent0: _TCCA[_T0], 

1759 __ent1: _TCCA[_T1], 

1760 __ent2: _TCCA[_T2], 

1761 __ent3: _TCCA[_T3], 

1762 /, 

1763 ) -> ReturningUpdate[_T0, _T1, _T2, _T3]: ... 

1764 

1765 @overload 

1766 def returning( 

1767 self, 

1768 __ent0: _TCCA[_T0], 

1769 __ent1: _TCCA[_T1], 

1770 __ent2: _TCCA[_T2], 

1771 __ent3: _TCCA[_T3], 

1772 __ent4: _TCCA[_T4], 

1773 /, 

1774 ) -> ReturningUpdate[_T0, _T1, _T2, _T3, _T4]: ... 

1775 

1776 @overload 

1777 def returning( 

1778 self, 

1779 __ent0: _TCCA[_T0], 

1780 __ent1: _TCCA[_T1], 

1781 __ent2: _TCCA[_T2], 

1782 __ent3: _TCCA[_T3], 

1783 __ent4: _TCCA[_T4], 

1784 __ent5: _TCCA[_T5], 

1785 /, 

1786 ) -> ReturningUpdate[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

1787 

1788 @overload 

1789 def returning( 

1790 self, 

1791 __ent0: _TCCA[_T0], 

1792 __ent1: _TCCA[_T1], 

1793 __ent2: _TCCA[_T2], 

1794 __ent3: _TCCA[_T3], 

1795 __ent4: _TCCA[_T4], 

1796 __ent5: _TCCA[_T5], 

1797 __ent6: _TCCA[_T6], 

1798 /, 

1799 ) -> ReturningUpdate[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

1800 

1801 @overload 

1802 def returning( 

1803 self, 

1804 __ent0: _TCCA[_T0], 

1805 __ent1: _TCCA[_T1], 

1806 __ent2: _TCCA[_T2], 

1807 __ent3: _TCCA[_T3], 

1808 __ent4: _TCCA[_T4], 

1809 __ent5: _TCCA[_T5], 

1810 __ent6: _TCCA[_T6], 

1811 __ent7: _TCCA[_T7], 

1812 /, 

1813 *entities: _ColumnsClauseArgument[Any], 

1814 ) -> ReturningUpdate[ 

1815 _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny] 

1816 ]: ... 

1817 

1818 # END OVERLOADED FUNCTIONS self.returning 

1819 

1820 @overload 

1821 def returning( 

1822 self, *cols: _ColumnsClauseArgument[Any], **__kw: Any 

1823 ) -> ReturningUpdate[Any]: ... 

1824 

1825 def returning( 

1826 self, *cols: _ColumnsClauseArgument[Any], **__kw: Any 

1827 ) -> ReturningUpdate[Any]: ... 

1828 

1829 

1830class ReturningUpdate(Update, TypedReturnsRows[Unpack[_Ts]]): 

1831 """Typing-only class that establishes a generic type form of 

1832 :class:`.Update` which tracks returned column types. 

1833 

1834 This datatype is delivered when calling the 

1835 :meth:`.Update.returning` method. 

1836 

1837 .. versionadded:: 2.0 

1838 

1839 """ 

1840 

1841 

1842class Delete( 

1843 DMLWhereBase, UpdateBase, HasSyntaxExtensions[Literal["post_criteria"]] 

1844): 

1845 """Represent a DELETE construct. 

1846 

1847 The :class:`_expression.Delete` object is created using the 

1848 :func:`_expression.delete()` function. 

1849 

1850 Available extension points: 

1851 

1852 * ``post_criteria``: applies additional logic after the ``WHERE`` clause. 

1853 

1854 """ 

1855 

1856 __visit_name__ = "delete" 

1857 

1858 is_delete = True 

1859 

1860 _traverse_internals = ( 

1861 [ 

1862 ("table", InternalTraversal.dp_clauseelement), 

1863 ("_extra_froms", InternalTraversal.dp_clauseelement_tuple), 

1864 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

1865 ("_returning", InternalTraversal.dp_clauseelement_tuple), 

1866 ("_hints", InternalTraversal.dp_table_hint_list), 

1867 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

1868 ] 

1869 + HasPrefixes._has_prefixes_traverse_internals 

1870 + DialectKWArgs._dialect_kwargs_traverse_internals 

1871 + ExecutableStatement._executable_traverse_internals 

1872 + HasCTE._has_ctes_traverse_internals 

1873 ) 

1874 

1875 _position_map = util.immutabledict( 

1876 {"post_criteria": "_post_criteria_clause"} 

1877 ) 

1878 

1879 _extra_froms: Tuple[FromClause, ...] = () 

1880 

1881 def __init__(self, table: _DMLTableArgument): 

1882 self.table = coercions.expect( 

1883 roles.DMLTableRole, table, apply_propagate_attrs=self 

1884 ) 

1885 

1886 @_generative 

1887 def using(self, *froms: _FromClauseArgument) -> Self: 

1888 r"""Add one or more explicit ``USING`` expressions to this DELETE. 

1889 

1890 This method may be used for backend-specific multiple-table DELETE 

1891 forms where the secondary FROM expression needs to be stated 

1892 explicitly, such as MySQL's ``DELETE FROM table USING <join>`` form. 

1893 

1894 .. versionadded:: 2.1 

1895 

1896 .. seealso:: 

1897 

1898 :ref:`tutorial_multi_table_deletes` 

1899 

1900 """ 

1901 

1902 self._extra_froms += tuple( 

1903 coercions.expect( 

1904 roles.FromClauseRole, from_, apply_propagate_attrs=self 

1905 ) 

1906 for from_ in froms 

1907 ) 

1908 return self 

1909 

1910 def _apply_syntax_extension_to_self( 

1911 self, extension: SyntaxExtension 

1912 ) -> None: 

1913 extension.apply_to_delete(self) 

1914 

1915 if TYPE_CHECKING: 

1916 # START OVERLOADED FUNCTIONS self.returning ReturningDelete 1-8 

1917 

1918 # code within this block is **programmatically, 

1919 # statically generated** by tools/generate_tuple_map_overloads.py 

1920 

1921 @overload 

1922 def returning(self, __ent0: _TCCA[_T0], /) -> ReturningDelete[_T0]: ... 

1923 

1924 @overload 

1925 def returning( 

1926 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], / 

1927 ) -> ReturningDelete[_T0, _T1]: ... 

1928 

1929 @overload 

1930 def returning( 

1931 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2], / 

1932 ) -> ReturningDelete[_T0, _T1, _T2]: ... 

1933 

1934 @overload 

1935 def returning( 

1936 self, 

1937 __ent0: _TCCA[_T0], 

1938 __ent1: _TCCA[_T1], 

1939 __ent2: _TCCA[_T2], 

1940 __ent3: _TCCA[_T3], 

1941 /, 

1942 ) -> ReturningDelete[_T0, _T1, _T2, _T3]: ... 

1943 

1944 @overload 

1945 def returning( 

1946 self, 

1947 __ent0: _TCCA[_T0], 

1948 __ent1: _TCCA[_T1], 

1949 __ent2: _TCCA[_T2], 

1950 __ent3: _TCCA[_T3], 

1951 __ent4: _TCCA[_T4], 

1952 /, 

1953 ) -> ReturningDelete[_T0, _T1, _T2, _T3, _T4]: ... 

1954 

1955 @overload 

1956 def returning( 

1957 self, 

1958 __ent0: _TCCA[_T0], 

1959 __ent1: _TCCA[_T1], 

1960 __ent2: _TCCA[_T2], 

1961 __ent3: _TCCA[_T3], 

1962 __ent4: _TCCA[_T4], 

1963 __ent5: _TCCA[_T5], 

1964 /, 

1965 ) -> ReturningDelete[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

1966 

1967 @overload 

1968 def returning( 

1969 self, 

1970 __ent0: _TCCA[_T0], 

1971 __ent1: _TCCA[_T1], 

1972 __ent2: _TCCA[_T2], 

1973 __ent3: _TCCA[_T3], 

1974 __ent4: _TCCA[_T4], 

1975 __ent5: _TCCA[_T5], 

1976 __ent6: _TCCA[_T6], 

1977 /, 

1978 ) -> ReturningDelete[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

1979 

1980 @overload 

1981 def returning( 

1982 self, 

1983 __ent0: _TCCA[_T0], 

1984 __ent1: _TCCA[_T1], 

1985 __ent2: _TCCA[_T2], 

1986 __ent3: _TCCA[_T3], 

1987 __ent4: _TCCA[_T4], 

1988 __ent5: _TCCA[_T5], 

1989 __ent6: _TCCA[_T6], 

1990 __ent7: _TCCA[_T7], 

1991 /, 

1992 *entities: _ColumnsClauseArgument[Any], 

1993 ) -> ReturningDelete[ 

1994 _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny] 

1995 ]: ... 

1996 

1997 # END OVERLOADED FUNCTIONS self.returning 

1998 

1999 @overload 

2000 def returning( 

2001 self, *cols: _ColumnsClauseArgument[Any], **__kw: Any 

2002 ) -> ReturningDelete[Unpack[TupleAny]]: ... 

2003 

2004 def returning( 

2005 self, *cols: _ColumnsClauseArgument[Any], **__kw: Any 

2006 ) -> ReturningDelete[Unpack[TupleAny]]: ... 

2007 

2008 

2009class ReturningDelete(Update, TypedReturnsRows[Unpack[_Ts]]): 

2010 """Typing-only class that establishes a generic type form of 

2011 :class:`.Delete` which tracks returned column types. 

2012 

2013 This datatype is delivered when calling the 

2014 :meth:`.Delete.returning` method. 

2015 

2016 .. versionadded:: 2.0 

2017 

2018 """