Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/dml.py: 45%
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
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
1# sql/dml.py
2# Copyright (C) 2009-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"""
8Provide :class:`_expression.Insert`, :class:`_expression.Update` and
9:class:`_expression.Delete`.
11"""
12from __future__ import annotations
14import collections.abc as collections_abc
15import operator
16from typing import Any
17from typing import cast
18from typing import Dict
19from typing import Iterable
20from typing import List
21from typing import Literal
22from typing import MutableMapping
23from typing import NoReturn
24from typing import Optional
25from typing import overload
26from typing import Sequence
27from typing import Set
28from typing import Tuple
29from typing import Type
30from typing import TYPE_CHECKING
31from typing import TypeGuard
32from typing import TypeVar
33from typing import Union
35from . import coercions
36from . import roles
37from . import util as sql_util
38from ._typing import _unexpected_kw
39from ._typing import is_column_element
40from ._typing import is_named_from_clause
41from .base import _entity_namespace_key
42from .base import _exclusive_against
43from .base import _from_objects
44from .base import _generative
45from .base import _select_iterables
46from .base import ColumnCollection
47from .base import ColumnSet
48from .base import CompileState
49from .base import DialectKWArgs
50from .base import Executable
51from .base import Generative
52from .base import HasCompileState
53from .base import HasSyntaxExtensions
54from .base import SyntaxExtension
55from .elements import BooleanClauseList
56from .elements import ClauseElement
57from .elements import ColumnClause
58from .elements import ColumnElement
59from .elements import Null
60from .selectable import Alias
61from .selectable import ExecutableReturnsRows
62from .selectable import FromClause
63from .selectable import HasCTE
64from .selectable import HasPrefixes
65from .selectable import Join
66from .selectable import SelectLabelStyle
67from .selectable import TableClause
68from .selectable import TypedReturnsRows
69from .sqltypes import NullType
70from .visitors import InternalTraversal
71from .. import exc
72from .. import util
73from ..util.typing import Self
74from ..util.typing import TupleAny
75from ..util.typing import TypeVarTuple
76from ..util.typing import Unpack
79if TYPE_CHECKING:
80 from ._typing import _ColumnExpressionArgument
81 from ._typing import _ColumnsClauseArgument
82 from ._typing import _DMLColumnArgument
83 from ._typing import _DMLColumnKeyMapping
84 from ._typing import _DMLTableArgument
85 from ._typing import _T0 # noqa
86 from ._typing import _T1 # noqa
87 from ._typing import _T2 # noqa
88 from ._typing import _T3 # noqa
89 from ._typing import _T4 # noqa
90 from ._typing import _T5 # noqa
91 from ._typing import _T6 # noqa
92 from ._typing import _T7 # noqa
93 from ._typing import _TypedColumnClauseArgument as _TCCA # noqa
94 from .base import ReadOnlyColumnCollection
95 from .compiler import SQLCompiler
96 from .elements import KeyedColumnElement
97 from .selectable import _ColumnsClauseElement
98 from .selectable import _SelectIterable
99 from .selectable import Select
100 from .selectable import Selectable
102 def isupdate(dml: DMLState) -> TypeGuard[UpdateDMLState]: ...
104 def isdelete(dml: DMLState) -> TypeGuard[DeleteDMLState]: ...
106 def isinsert(dml: DMLState) -> TypeGuard[InsertDMLState]: ...
108else:
109 isupdate = operator.attrgetter("isupdate")
110 isdelete = operator.attrgetter("isdelete")
111 isinsert = operator.attrgetter("isinsert")
114_T = TypeVar("_T", bound=Any)
115_Ts = TypeVarTuple("_Ts")
117_DMLColumnElement = Union[str, ColumnClause[Any]]
118_DMLTableElement = Union[TableClause, Alias, Join]
121class DMLState(CompileState):
122 _no_parameters = True
123 _dict_parameters: Optional[MutableMapping[_DMLColumnElement, Any]] = None
124 _multi_parameters: Optional[
125 List[MutableMapping[_DMLColumnElement, Any]]
126 ] = None
127 _maintain_values_ordering: bool = False
128 _primary_table: FromClause
129 _supports_implicit_returning = True
131 isupdate = False
132 isdelete = False
133 isinsert = False
135 statement: UpdateBase
137 def __init__(
138 self, statement: UpdateBase, compiler: SQLCompiler, **kw: Any
139 ):
140 raise NotImplementedError()
142 @classmethod
143 def get_entity_description(cls, statement: UpdateBase) -> Dict[str, Any]:
144 return {
145 "name": (
146 statement.table.name
147 if is_named_from_clause(statement.table)
148 else None
149 ),
150 "table": statement.table,
151 }
153 @classmethod
154 def get_returning_column_descriptions(
155 cls, statement: UpdateBase
156 ) -> List[Dict[str, Any]]:
157 return [
158 {
159 "name": c.key,
160 "type": c.type,
161 "expr": c,
162 }
163 for c in statement._all_selected_columns
164 ]
166 @property
167 def dml_table(self) -> _DMLTableElement:
168 return self.statement.table
170 if TYPE_CHECKING:
172 @classmethod
173 def get_plugin_class(cls, statement: Executable) -> Type[DMLState]: ...
175 @classmethod
176 def _get_multi_crud_kv_pairs(
177 cls,
178 statement: UpdateBase,
179 multi_kv_iterator: Iterable[Dict[_DMLColumnArgument, Any]],
180 ) -> List[Dict[_DMLColumnElement, Any]]:
181 return [
182 {
183 coercions.expect(roles.DMLColumnRole, k): v
184 for k, v in mapping.items()
185 }
186 for mapping in multi_kv_iterator
187 ]
189 @classmethod
190 def _get_crud_kv_pairs(
191 cls,
192 statement: UpdateBase,
193 kv_iterator: Iterable[Tuple[_DMLColumnArgument, Any]],
194 needs_to_be_cacheable: bool,
195 ) -> List[Tuple[_DMLColumnElement, Any]]:
196 return [
197 (
198 coercions.expect(roles.DMLColumnRole, k),
199 (
200 v
201 if not needs_to_be_cacheable
202 else coercions.expect(
203 roles.ExpressionElementRole,
204 v,
205 type_=NullType(),
206 is_crud=True,
207 )
208 ),
209 )
210 for k, v in kv_iterator
211 ]
213 def _make_extra_froms(
214 self, statement: DMLWhereBase
215 ) -> Tuple[FromClause, List[FromClause]]:
216 froms: List[FromClause] = []
218 all_tables = list(sql_util.tables_from_leftmost(statement.table))
219 primary_table = all_tables[0]
220 seen = {primary_table}
222 consider = statement._where_criteria
223 if self._dict_parameters:
224 consider += tuple(self._dict_parameters.values())
226 for crit in consider:
227 for item in _from_objects(crit):
228 if not seen.intersection(item._cloned_set):
229 froms.append(item)
230 seen.update(item._cloned_set)
232 froms.extend(all_tables[1:])
233 return primary_table, froms
235 def _process_values(self, statement: ValuesBase) -> None:
236 if self._no_parameters:
237 self._dict_parameters = statement._values
238 self._no_parameters = False
240 def _process_select_values(self, statement: ValuesBase) -> None:
241 assert statement._select_names is not None
242 parameters: MutableMapping[_DMLColumnElement, Any] = {
243 name: Null() for name in statement._select_names
244 }
246 if self._no_parameters:
247 self._no_parameters = False
248 self._dict_parameters = parameters
249 else:
250 # this condition normally not reachable as the Insert
251 # does not allow this construction to occur
252 assert False, "This statement already has parameters"
254 def _no_multi_values_supported(self, statement: ValuesBase) -> NoReturn:
255 raise exc.InvalidRequestError(
256 "%s construct does not support "
257 "multiple parameter sets." % statement.__visit_name__.upper()
258 )
260 def _cant_mix_formats_error(self) -> NoReturn:
261 raise exc.InvalidRequestError(
262 "Can't mix single and multiple VALUES "
263 "formats in one INSERT statement; one style appends to a "
264 "list while the other replaces values, so the intent is "
265 "ambiguous."
266 )
269@CompileState.plugin_for("default", "insert")
270class InsertDMLState(DMLState):
271 isinsert = True
273 include_table_with_column_exprs = False
275 _has_multi_parameters = False
277 def __init__(
278 self,
279 statement: Insert,
280 compiler: SQLCompiler,
281 disable_implicit_returning: bool = False,
282 **kw: Any,
283 ):
284 self.statement = statement
285 self._primary_table = statement.table
287 if disable_implicit_returning:
288 self._supports_implicit_returning = False
290 self.isinsert = True
291 if statement._select_names:
292 self._process_select_values(statement)
293 if statement._values is not None:
294 self._process_values(statement)
295 if statement._multi_values:
296 self._process_multi_values(statement)
298 @util.memoized_property
299 def _insert_col_keys(self) -> List[str]:
300 # this is also done in crud.py -> _key_getters_for_crud_column
301 return [
302 coercions.expect(roles.DMLColumnRole, col, as_key=True)
303 for col in self._dict_parameters or ()
304 ]
306 def _process_values(self, statement: ValuesBase) -> None:
307 if self._no_parameters:
308 self._has_multi_parameters = False
309 self._dict_parameters = statement._values
310 self._no_parameters = False
311 elif self._has_multi_parameters:
312 self._cant_mix_formats_error()
314 def _process_multi_values(self, statement: ValuesBase) -> None:
315 for parameters in statement._multi_values:
316 multi_parameters: List[MutableMapping[_DMLColumnElement, Any]] = [
317 (
318 {
319 c.key: value
320 for c, value in zip(statement.table.c, parameter_set)
321 }
322 if isinstance(parameter_set, collections_abc.Sequence)
323 else parameter_set
324 )
325 for parameter_set in parameters
326 ]
328 if self._no_parameters:
329 self._no_parameters = False
330 self._has_multi_parameters = True
331 self._multi_parameters = multi_parameters
332 self._dict_parameters = self._multi_parameters[0]
333 elif not self._has_multi_parameters:
334 self._cant_mix_formats_error()
335 else:
336 assert self._multi_parameters
337 self._multi_parameters.extend(multi_parameters)
340@CompileState.plugin_for("default", "update")
341class UpdateDMLState(DMLState):
342 isupdate = True
344 include_table_with_column_exprs = False
346 def __init__(self, statement: Update, compiler: SQLCompiler, **kw: Any):
347 self.statement = statement
349 self.isupdate = True
350 if statement._maintain_values_ordering:
351 self._process_ordered_values(statement)
352 elif statement._values is not None:
353 self._process_values(statement)
354 elif statement._multi_values:
355 self._no_multi_values_supported(statement)
356 t, ef = self._make_extra_froms(statement)
357 self._primary_table = t
358 self._extra_froms = ef
360 self.is_multitable = mt = ef
361 self.include_table_with_column_exprs = bool(
362 mt and compiler.render_table_with_column_in_update_from
363 )
365 def _process_ordered_values(self, statement: ValuesBase) -> None:
366 parameters = statement._values
367 if self._no_parameters:
368 self._no_parameters = False
369 assert parameters is not None
370 self._dict_parameters = dict(parameters)
371 self._maintain_values_ordering = True
372 else:
373 raise exc.InvalidRequestError(
374 "Can only invoke ordered_values() once, and not mixed "
375 "with any other values() call"
376 )
379@CompileState.plugin_for("default", "delete")
380class DeleteDMLState(DMLState):
381 isdelete = True
383 def __init__(self, statement: Delete, compiler: SQLCompiler, **kw: Any):
384 self.statement = statement
386 self.isdelete = True
387 t, ef = self._make_extra_froms(statement)
388 self._primary_table = t
389 self._extra_froms = ef
390 self.is_multitable = ef
393class UpdateBase(
394 roles.DMLRole,
395 HasCTE,
396 HasCompileState,
397 DialectKWArgs,
398 HasPrefixes,
399 Generative,
400 ExecutableReturnsRows,
401 ClauseElement,
402):
403 """Form the base for ``INSERT``, ``UPDATE``, and ``DELETE`` statements."""
405 __visit_name__ = "update_base"
407 _hints: util.immutabledict[Tuple[_DMLTableElement, str], str] = (
408 util.EMPTY_DICT
409 )
410 named_with_column = False
412 _label_style: SelectLabelStyle = (
413 SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY
414 )
415 table: _DMLTableElement
417 _return_defaults = False
418 _return_defaults_columns: Optional[Tuple[_ColumnsClauseElement, ...]] = (
419 None
420 )
421 _supplemental_returning: Optional[Tuple[_ColumnsClauseElement, ...]] = None
422 _returning: Tuple[_ColumnsClauseElement, ...] = ()
424 is_dml = True
426 def _generate_fromclause_column_proxies(
427 self,
428 fromclause: FromClause,
429 columns: ColumnCollection[str, KeyedColumnElement[Any]],
430 primary_key: ColumnSet,
431 foreign_keys: Set[KeyedColumnElement[Any]],
432 ) -> None:
433 prox = [
434 c._make_proxy(
435 fromclause,
436 key=proxy_key,
437 name=required_label_name,
438 name_is_truncatable=True,
439 primary_key=primary_key,
440 foreign_keys=foreign_keys,
441 )
442 for (
443 required_label_name,
444 proxy_key,
445 fallback_label_name,
446 c,
447 repeated,
448 ) in (self._generate_columns_plus_names(False))
449 if is_column_element(c)
450 ]
452 columns._populate_separate_keys(prox)
454 def params(self, *arg: Any, **kw: Any) -> NoReturn:
455 """Set the parameters for the statement.
457 This method raises ``NotImplementedError`` on the base class,
458 and is overridden by :class:`.ValuesBase` to provide the
459 SET/VALUES clause of UPDATE and INSERT.
461 """
462 raise NotImplementedError(
463 "params() is not supported for INSERT/UPDATE/DELETE statements."
464 " To set the values for an INSERT or UPDATE statement, use"
465 " stmt.values(**parameters)."
466 )
468 @_generative
469 def with_dialect_options(self, **opt: Any) -> Self:
470 """Add dialect options to this INSERT/UPDATE/DELETE object.
472 e.g.::
474 upd = table.update().dialect_options(mysql_limit=10)
476 .. versionadded:: 1.4 - this method supersedes the dialect options
477 associated with the constructor.
480 """
481 self._validate_dialect_kwargs(opt)
482 return self
484 @_generative
485 def return_defaults(
486 self,
487 *cols: _DMLColumnArgument,
488 supplemental_cols: Optional[Iterable[_DMLColumnArgument]] = None,
489 sort_by_parameter_order: bool = False,
490 ) -> Self:
491 """Make use of a :term:`RETURNING` clause for the purpose
492 of fetching server-side expressions and defaults, for supporting
493 backends only.
495 .. deepalchemy::
497 The :meth:`.UpdateBase.return_defaults` method is used by the ORM
498 for its internal work in fetching newly generated primary key
499 and server default values, in particular to provide the underyling
500 implementation of the :paramref:`_orm.Mapper.eager_defaults`
501 ORM feature as well as to allow RETURNING support with bulk
502 ORM inserts. Its behavior is fairly idiosyncratic
503 and is not really intended for general use. End users should
504 stick with using :meth:`.UpdateBase.returning` in order to
505 add RETURNING clauses to their INSERT, UPDATE and DELETE
506 statements.
508 Normally, a single row INSERT statement will automatically populate the
509 :attr:`.CursorResult.inserted_primary_key` attribute when executed,
510 which stores the primary key of the row that was just inserted in the
511 form of a :class:`.Row` object with column names as named tuple keys
512 (and the :attr:`.Row._mapping` view fully populated as well). The
513 dialect in use chooses the strategy to use in order to populate this
514 data; if it was generated using server-side defaults and / or SQL
515 expressions, dialect-specific approaches such as ``cursor.lastrowid``
516 or ``RETURNING`` are typically used to acquire the new primary key
517 value.
519 However, when the statement is modified by calling
520 :meth:`.UpdateBase.return_defaults` before executing the statement,
521 additional behaviors take place **only** for backends that support
522 RETURNING and for :class:`.Table` objects that maintain the
523 :paramref:`.Table.implicit_returning` parameter at its default value of
524 ``True``. In these cases, when the :class:`.CursorResult` is returned
525 from the statement's execution, not only will
526 :attr:`.CursorResult.inserted_primary_key` be populated as always, the
527 :attr:`.CursorResult.returned_defaults` attribute will also be
528 populated with a :class:`.Row` named-tuple representing the full range
529 of server generated
530 values from that single row, including values for any columns that
531 specify :paramref:`_schema.Column.server_default` or which make use of
532 :paramref:`_schema.Column.default` using a SQL expression.
534 When invoking INSERT statements with multiple rows using
535 :ref:`insertmanyvalues <engine_insertmanyvalues>`, the
536 :meth:`.UpdateBase.return_defaults` modifier will have the effect of
537 the :attr:`_engine.CursorResult.inserted_primary_key_rows` and
538 :attr:`_engine.CursorResult.returned_defaults_rows` attributes being
539 fully populated with lists of :class:`.Row` objects representing newly
540 inserted primary key values as well as newly inserted server generated
541 values for each row inserted. The
542 :attr:`.CursorResult.inserted_primary_key` and
543 :attr:`.CursorResult.returned_defaults` attributes will also continue
544 to be populated with the first row of these two collections.
546 If the backend does not support RETURNING or the :class:`.Table` in use
547 has disabled :paramref:`.Table.implicit_returning`, then no RETURNING
548 clause is added and no additional data is fetched, however the
549 INSERT, UPDATE or DELETE statement proceeds normally.
551 E.g.::
553 stmt = table.insert().values(data="newdata").return_defaults()
555 result = connection.execute(stmt)
557 server_created_at = result.returned_defaults["created_at"]
559 When used against an UPDATE statement
560 :meth:`.UpdateBase.return_defaults` instead looks for columns that
561 include :paramref:`_schema.Column.onupdate` or
562 :paramref:`_schema.Column.server_onupdate` parameters assigned, when
563 constructing the columns that will be included in the RETURNING clause
564 by default if explicit columns were not specified. When used against a
565 DELETE statement, no columns are included in RETURNING by default, they
566 instead must be specified explicitly as there are no columns that
567 normally change values when a DELETE statement proceeds.
569 .. versionadded:: 2.0 :meth:`.UpdateBase.return_defaults` is supported
570 for DELETE statements also and has been moved from
571 :class:`.ValuesBase` to :class:`.UpdateBase`.
573 The :meth:`.UpdateBase.return_defaults` method is mutually exclusive
574 against the :meth:`.UpdateBase.returning` method and errors will be
575 raised during the SQL compilation process if both are used at the same
576 time on one statement. The RETURNING clause of the INSERT, UPDATE or
577 DELETE statement is therefore controlled by only one of these methods
578 at a time.
580 The :meth:`.UpdateBase.return_defaults` method differs from
581 :meth:`.UpdateBase.returning` in these ways:
583 1. :meth:`.UpdateBase.return_defaults` method causes the
584 :attr:`.CursorResult.returned_defaults` collection to be populated
585 with the first row from the RETURNING result. This attribute is not
586 populated when using :meth:`.UpdateBase.returning`.
588 2. :meth:`.UpdateBase.return_defaults` is compatible with existing
589 logic used to fetch auto-generated primary key values that are then
590 populated into the :attr:`.CursorResult.inserted_primary_key`
591 attribute. By contrast, using :meth:`.UpdateBase.returning` will
592 have the effect of the :attr:`.CursorResult.inserted_primary_key`
593 attribute being left unpopulated.
595 3. :meth:`.UpdateBase.return_defaults` can be called against any
596 backend. Backends that don't support RETURNING will skip the usage
597 of the feature, rather than raising an exception, *unless*
598 ``supplemental_cols`` is passed. The return value
599 of :attr:`_engine.CursorResult.returned_defaults` will be ``None``
600 for backends that don't support RETURNING or for which the target
601 :class:`.Table` sets :paramref:`.Table.implicit_returning` to
602 ``False``.
604 4. An INSERT statement invoked with executemany() is supported if the
605 backend database driver supports the
606 :ref:`insertmanyvalues <engine_insertmanyvalues>`
607 feature which is now supported by most SQLAlchemy-included backends.
608 When executemany is used, the
609 :attr:`_engine.CursorResult.returned_defaults_rows` and
610 :attr:`_engine.CursorResult.inserted_primary_key_rows` accessors
611 will return the inserted defaults and primary keys.
613 .. versionadded:: 1.4 Added
614 :attr:`_engine.CursorResult.returned_defaults_rows` and
615 :attr:`_engine.CursorResult.inserted_primary_key_rows` accessors.
616 In version 2.0, the underlying implementation which fetches and
617 populates the data for these attributes was generalized to be
618 supported by most backends, whereas in 1.4 they were only
619 supported by the ``psycopg2`` driver.
622 :param cols: optional list of column key names or
623 :class:`_schema.Column` that acts as a filter for those columns that
624 will be fetched.
625 :param supplemental_cols: optional list of RETURNING expressions,
626 in the same form as one would pass to the
627 :meth:`.UpdateBase.returning` method. When present, the additional
628 columns will be included in the RETURNING clause, and the
629 :class:`.CursorResult` object will be "rewound" when returned, so
630 that methods like :meth:`.CursorResult.all` will return new rows
631 mostly as though the statement used :meth:`.UpdateBase.returning`
632 directly. However, unlike when using :meth:`.UpdateBase.returning`
633 directly, the **order of the columns is undefined**, so can only be
634 targeted using names or :attr:`.Row._mapping` keys; they cannot
635 reliably be targeted positionally.
637 .. versionadded:: 2.0
639 :param sort_by_parameter_order: for a batch INSERT that is being
640 executed against multiple parameter sets, organize the results of
641 RETURNING so that the returned rows correspond to the order of
642 parameter sets passed in. This applies only to an :term:`executemany`
643 execution for supporting dialects and typically makes use of the
644 :term:`insertmanyvalues` feature.
646 .. versionadded:: 2.0.10
648 .. seealso::
650 :ref:`engine_insertmanyvalues_returning_order` - background on
651 sorting of RETURNING rows for bulk INSERT
653 .. seealso::
655 :meth:`.UpdateBase.returning`
657 :attr:`_engine.CursorResult.returned_defaults`
659 :attr:`_engine.CursorResult.returned_defaults_rows`
661 :attr:`_engine.CursorResult.inserted_primary_key`
663 :attr:`_engine.CursorResult.inserted_primary_key_rows`
665 """
667 if self._return_defaults:
668 # note _return_defaults_columns = () means return all columns,
669 # so if we have been here before, only update collection if there
670 # are columns in the collection
671 if self._return_defaults_columns and cols:
672 self._return_defaults_columns = tuple(
673 util.OrderedSet(self._return_defaults_columns).union(
674 coercions.expect(roles.ColumnsClauseRole, c)
675 for c in cols
676 )
677 )
678 else:
679 # set for all columns
680 self._return_defaults_columns = ()
681 else:
682 self._return_defaults_columns = tuple(
683 coercions.expect(roles.ColumnsClauseRole, c) for c in cols
684 )
685 self._return_defaults = True
686 if sort_by_parameter_order:
687 if not self.is_insert:
688 raise exc.ArgumentError(
689 "The 'sort_by_parameter_order' argument to "
690 "return_defaults() only applies to INSERT statements"
691 )
692 self._sort_by_parameter_order = True
693 if supplemental_cols:
694 # uniquifying while also maintaining order (the maintain of order
695 # is for test suites but also for vertical splicing
696 supplemental_col_tup = (
697 coercions.expect(roles.ColumnsClauseRole, c)
698 for c in supplemental_cols
699 )
701 if self._supplemental_returning is None:
702 self._supplemental_returning = tuple(
703 util.unique_list(supplemental_col_tup)
704 )
705 else:
706 self._supplemental_returning = tuple(
707 util.unique_list(
708 self._supplemental_returning
709 + tuple(supplemental_col_tup)
710 )
711 )
713 return self
715 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
716 """Return ``True`` if this :class:`.ReturnsRows` is
717 'derived' from the given :class:`.FromClause`.
719 Since these are DMLs, we dont want such statements ever being adapted
720 so we return False for derives.
722 """
723 return False
725 @_generative
726 def returning(
727 self,
728 *cols: _ColumnsClauseArgument[Any],
729 sort_by_parameter_order: bool = False,
730 **__kw: Any,
731 ) -> UpdateBase:
732 r"""Add a :term:`RETURNING` or equivalent clause to this statement.
734 e.g.:
736 .. sourcecode:: pycon+sql
738 >>> stmt = (
739 ... table.update()
740 ... .where(table.c.data == "value")
741 ... .values(status="X")
742 ... .returning(table.c.server_flag, table.c.updated_timestamp)
743 ... )
744 >>> print(stmt)
745 {printsql}UPDATE some_table SET status=:status
746 WHERE some_table.data = :data_1
747 RETURNING some_table.server_flag, some_table.updated_timestamp
749 The method may be invoked multiple times to add new entries to the
750 list of expressions to be returned.
752 .. versionadded:: 1.4.0b2 The method may be invoked multiple times to
753 add new entries to the list of expressions to be returned.
755 The given collection of column expressions should be derived from the
756 table that is the target of the INSERT, UPDATE, or DELETE. While
757 :class:`_schema.Column` objects are typical, the elements can also be
758 expressions:
760 .. sourcecode:: pycon+sql
762 >>> stmt = table.insert().returning(
763 ... (table.c.first_name + " " + table.c.last_name).label("fullname")
764 ... )
765 >>> print(stmt)
766 {printsql}INSERT INTO some_table (first_name, last_name)
767 VALUES (:first_name, :last_name)
768 RETURNING some_table.first_name || :first_name_1 || some_table.last_name AS fullname
770 Upon compilation, a RETURNING clause, or database equivalent,
771 will be rendered within the statement. For INSERT and UPDATE,
772 the values are the newly inserted/updated values. For DELETE,
773 the values are those of the rows which were deleted.
775 Upon execution, the values of the columns to be returned are made
776 available via the result set and can be iterated using
777 :meth:`_engine.CursorResult.fetchone` and similar.
778 For DBAPIs which do not
779 natively support returning values (i.e. cx_oracle), SQLAlchemy will
780 approximate this behavior at the result level so that a reasonable
781 amount of behavioral neutrality is provided.
783 Note that not all databases/DBAPIs
784 support RETURNING. For those backends with no support,
785 an exception is raised upon compilation and/or execution.
786 For those who do support it, the functionality across backends
787 varies greatly, including restrictions on executemany()
788 and other statements which return multiple rows. Please
789 read the documentation notes for the database in use in
790 order to determine the availability of RETURNING.
792 :param \*cols: series of columns, SQL expressions, or whole tables
793 entities to be returned.
794 :param sort_by_parameter_order: for a batch INSERT that is being
795 executed against multiple parameter sets, organize the results of
796 RETURNING so that the returned rows correspond to the order of
797 parameter sets passed in. This applies only to an :term:`executemany`
798 execution for supporting dialects and typically makes use of the
799 :term:`insertmanyvalues` feature.
801 .. versionadded:: 2.0.10
803 .. seealso::
805 :ref:`engine_insertmanyvalues_returning_order` - background on
806 sorting of RETURNING rows for bulk INSERT (Core level discussion)
808 :ref:`orm_queryguide_bulk_insert_returning_ordered` - example of
809 use with :ref:`orm_queryguide_bulk_insert` (ORM level discussion)
811 .. seealso::
813 :meth:`.UpdateBase.return_defaults` - an alternative method tailored
814 towards efficient fetching of server-side defaults and triggers
815 for single-row INSERTs or UPDATEs.
817 :ref:`tutorial_insert_returning` - in the :ref:`unified_tutorial`
819 """ # noqa: E501
820 if __kw:
821 raise _unexpected_kw("UpdateBase.returning()", __kw)
822 if self._return_defaults:
823 raise exc.InvalidRequestError(
824 "return_defaults() is already configured on this statement"
825 )
826 self._returning += tuple(
827 coercions.expect(roles.ColumnsClauseRole, c) for c in cols
828 )
829 if sort_by_parameter_order:
830 if not self.is_insert:
831 raise exc.ArgumentError(
832 "The 'sort_by_parameter_order' argument to returning() "
833 "only applies to INSERT statements"
834 )
835 self._sort_by_parameter_order = True
836 return self
838 def corresponding_column(
839 self, column: KeyedColumnElement[Any], require_embedded: bool = False
840 ) -> Optional[ColumnElement[Any]]:
841 return self.exported_columns.corresponding_column(
842 column, require_embedded=require_embedded
843 )
845 @util.ro_memoized_property
846 def _all_selected_columns(self) -> _SelectIterable:
847 return [c for c in _select_iterables(self._returning)]
849 @util.ro_memoized_property
850 def exported_columns(
851 self,
852 ) -> ReadOnlyColumnCollection[Optional[str], ColumnElement[Any]]:
853 """Return the RETURNING columns as a column collection for this
854 statement.
856 .. versionadded:: 1.4
858 """
859 return ColumnCollection(
860 (c.key, c)
861 for c in self._all_selected_columns
862 if is_column_element(c)
863 ).as_readonly()
865 @_generative
866 def with_hint(
867 self,
868 text: str,
869 selectable: Optional[_DMLTableArgument] = None,
870 dialect_name: str = "*",
871 ) -> Self:
872 """Add a table hint for a single table to this
873 INSERT/UPDATE/DELETE statement.
875 .. note::
877 :meth:`.UpdateBase.with_hint` currently applies only to
878 Microsoft SQL Server. For MySQL INSERT/UPDATE/DELETE hints, use
879 :meth:`.UpdateBase.prefix_with`.
881 The text of the hint is rendered in the appropriate
882 location for the database backend in use, relative
883 to the :class:`_schema.Table` that is the subject of this
884 statement, or optionally to that of the given
885 :class:`_schema.Table` passed as the ``selectable`` argument.
887 The ``dialect_name`` option will limit the rendering of a particular
888 hint to a particular backend. Such as, to add a hint
889 that only takes effect for SQL Server::
891 mytable.insert().with_hint("WITH (PAGLOCK)", dialect_name="mssql")
893 :param text: Text of the hint.
894 :param selectable: optional :class:`_schema.Table` that specifies
895 an element of the FROM clause within an UPDATE or DELETE
896 to be the subject of the hint - applies only to certain backends.
897 :param dialect_name: defaults to ``*``, if specified as the name
898 of a particular dialect, will apply these hints only when
899 that dialect is in use.
900 """
901 if selectable is None:
902 selectable = self.table
903 else:
904 selectable = coercions.expect(roles.DMLTableRole, selectable)
905 self._hints = self._hints.union({(selectable, dialect_name): text})
906 return self
908 @property
909 def entity_description(self) -> Dict[str, Any]:
910 """Return a :term:`plugin-enabled` description of the table and/or
911 entity which this DML construct is operating against.
913 This attribute is generally useful when using the ORM, as an
914 extended structure which includes information about mapped
915 entities is returned. The section :ref:`queryguide_inspection`
916 contains more background.
918 For a Core statement, the structure returned by this accessor
919 is derived from the :attr:`.UpdateBase.table` attribute, and
920 refers to the :class:`.Table` being inserted, updated, or deleted::
922 >>> stmt = insert(user_table)
923 >>> stmt.entity_description
924 {
925 "name": "user_table",
926 "table": Table("user_table", ...)
927 }
929 .. versionadded:: 1.4.33
931 .. seealso::
933 :attr:`.UpdateBase.returning_column_descriptions`
935 :attr:`.Select.column_descriptions` - entity information for
936 a :func:`.select` construct
938 :ref:`queryguide_inspection` - ORM background
940 """
941 meth = DMLState.get_plugin_class(self).get_entity_description
942 return meth(self)
944 @property
945 def returning_column_descriptions(self) -> List[Dict[str, Any]]:
946 """Return a :term:`plugin-enabled` description of the columns
947 which this DML construct is RETURNING against, in other words
948 the expressions established as part of :meth:`.UpdateBase.returning`.
950 This attribute is generally useful when using the ORM, as an
951 extended structure which includes information about mapped
952 entities is returned. The section :ref:`queryguide_inspection`
953 contains more background.
955 For a Core statement, the structure returned by this accessor is
956 derived from the same objects that are returned by the
957 :attr:`.UpdateBase.exported_columns` accessor::
959 >>> stmt = insert(user_table).returning(user_table.c.id, user_table.c.name)
960 >>> stmt.entity_description
961 [
962 {
963 "name": "id",
964 "type": Integer,
965 "expr": Column("id", Integer(), table=<user>, ...)
966 },
967 {
968 "name": "name",
969 "type": String(),
970 "expr": Column("name", String(), table=<user>, ...)
971 },
972 ]
974 .. versionadded:: 1.4.33
976 .. seealso::
978 :attr:`.UpdateBase.entity_description`
980 :attr:`.Select.column_descriptions` - entity information for
981 a :func:`.select` construct
983 :ref:`queryguide_inspection` - ORM background
985 """ # noqa: E501
986 meth = DMLState.get_plugin_class(
987 self
988 ).get_returning_column_descriptions
989 return meth(self)
992class ValuesBase(UpdateBase):
993 """Supplies support for :meth:`.ValuesBase.values` to
994 INSERT and UPDATE constructs."""
996 __visit_name__ = "values_base"
998 _supports_multi_parameters = False
1000 select: Optional[Select[Unpack[TupleAny]]] = None
1001 """SELECT statement for INSERT .. FROM SELECT"""
1003 _post_values_clause: Optional[ClauseElement] = None
1004 """used by extensions to Insert etc. to add additional syntactical
1005 constructs, e.g. ON CONFLICT etc."""
1007 _values: Optional[util.immutabledict[_DMLColumnElement, Any]] = None
1008 _multi_values: Tuple[
1009 Union[
1010 Sequence[Dict[_DMLColumnElement, Any]],
1011 Sequence[Sequence[Any]],
1012 ],
1013 ...,
1014 ] = ()
1016 _maintain_values_ordering: bool = False
1018 _select_names: Optional[List[str]] = None
1019 _inline: bool = False
1021 def __init__(self, table: _DMLTableArgument):
1022 self.table = coercions.expect(
1023 roles.DMLTableRole, table, apply_propagate_attrs=self
1024 )
1026 @_generative
1027 @_exclusive_against(
1028 "_select_names",
1029 "_maintain_values_ordering",
1030 msgs={
1031 "_select_names": "This construct already inserts from a SELECT",
1032 "_maintain_values_ordering": "This statement already has ordered "
1033 "values present",
1034 },
1035 defaults={"_maintain_values_ordering": False},
1036 )
1037 def values(
1038 self,
1039 *args: Union[
1040 _DMLColumnKeyMapping[Any],
1041 Sequence[Any],
1042 ],
1043 **kwargs: Any,
1044 ) -> Self:
1045 r"""Specify a fixed VALUES clause for an INSERT statement, or the SET
1046 clause for an UPDATE.
1048 Note that the :class:`_expression.Insert` and
1049 :class:`_expression.Update`
1050 constructs support
1051 per-execution time formatting of the VALUES and/or SET clauses,
1052 based on the arguments passed to :meth:`_engine.Connection.execute`.
1053 However, the :meth:`.ValuesBase.values` method can be used to "fix" a
1054 particular set of parameters into the statement.
1056 Multiple calls to :meth:`.ValuesBase.values` will produce a new
1057 construct, each one with the parameter list modified to include
1058 the new parameters sent. In the typical case of a single
1059 dictionary of parameters, the newly passed keys will replace
1060 the same keys in the previous construct. In the case of a list-based
1061 "multiple values" construct, each new list of values is extended
1062 onto the existing list of values.
1064 :param \**kwargs: key value pairs representing the string key
1065 of a :class:`_schema.Column`
1066 mapped to the value to be rendered into the
1067 VALUES or SET clause::
1069 users.insert().values(name="some name")
1071 users.update().where(users.c.id == 5).values(name="some name")
1073 :param \*args: As an alternative to passing key/value parameters,
1074 a dictionary, tuple, or list of dictionaries or tuples can be passed
1075 as a single positional argument in order to form the VALUES or
1076 SET clause of the statement. The forms that are accepted vary
1077 based on whether this is an :class:`_expression.Insert` or an
1078 :class:`_expression.Update` construct.
1080 For either an :class:`_expression.Insert` or
1081 :class:`_expression.Update`
1082 construct, a single dictionary can be passed, which works the same as
1083 that of the kwargs form::
1085 users.insert().values({"name": "some name"})
1087 users.update().values({"name": "some new name"})
1089 Also for either form but more typically for the
1090 :class:`_expression.Insert` construct, a tuple that contains an
1091 entry for every column in the table is also accepted::
1093 users.insert().values((5, "some name"))
1095 The :class:`_expression.Insert` construct also supports being
1096 passed a list of dictionaries or full-table-tuples, which on the
1097 server will render the less common SQL syntax of "multiple values" -
1098 this syntax is supported on backends such as SQLite, PostgreSQL,
1099 MySQL, but not necessarily others::
1101 users.insert().values(
1102 [
1103 {"name": "some name"},
1104 {"name": "some other name"},
1105 {"name": "yet another name"},
1106 ]
1107 )
1109 The above form would render a multiple VALUES statement similar to:
1111 .. sourcecode:: sql
1113 INSERT INTO users (name) VALUES
1114 (:name_1),
1115 (:name_2),
1116 (:name_3)
1118 It is essential to note that **passing multiple values is
1119 NOT the same as using traditional executemany() form**. The above
1120 syntax is a **special** syntax not typically used. To emit an
1121 INSERT statement against multiple rows, the normal method is
1122 to pass a multiple values list to the
1123 :meth:`_engine.Connection.execute`
1124 method, which is supported by all database backends and is generally
1125 more efficient for a very large number of parameters.
1127 .. seealso::
1129 :ref:`tutorial_multiple_parameters` - an introduction to
1130 the traditional Core method of multiple parameter set
1131 invocation for INSERTs and other statements.
1133 The UPDATE construct also supports rendering the SET parameters
1134 in a specific order. For this feature refer to the
1135 :meth:`_expression.Update.ordered_values` method.
1137 .. seealso::
1139 :meth:`_expression.Update.ordered_values`
1142 """
1143 if args:
1144 # positional case. this is currently expensive. we don't
1145 # yet have positional-only args so we have to check the length.
1146 # then we need to check multiparams vs. single dictionary.
1147 # since the parameter format is needed in order to determine
1148 # a cache key, we need to determine this up front.
1149 arg = args[0]
1151 if kwargs:
1152 raise exc.ArgumentError(
1153 "Can't pass positional and kwargs to values() "
1154 "simultaneously"
1155 )
1156 elif len(args) > 1:
1157 raise exc.ArgumentError(
1158 "Only a single dictionary/tuple or list of "
1159 "dictionaries/tuples is accepted positionally."
1160 )
1162 elif isinstance(arg, collections_abc.Sequence):
1163 if arg and isinstance(arg[0], dict):
1164 multi_kv_generator = DMLState.get_plugin_class(
1165 self
1166 )._get_multi_crud_kv_pairs
1167 self._multi_values += (multi_kv_generator(self, arg),)
1168 return self
1170 if arg and isinstance(arg[0], (list, tuple)):
1171 self._multi_values += (arg,)
1172 return self
1174 if TYPE_CHECKING:
1175 # crud.py raises during compilation if this is not the
1176 # case
1177 assert isinstance(self, Insert)
1179 # tuple values
1180 arg = {c.key: value for c, value in zip(self.table.c, arg)}
1182 else:
1183 # kwarg path. this is the most common path for non-multi-params
1184 # so this is fairly quick.
1185 arg = cast("Dict[_DMLColumnArgument, Any]", kwargs)
1186 if args:
1187 raise exc.ArgumentError(
1188 "Only a single dictionary/tuple or list of "
1189 "dictionaries/tuples is accepted positionally."
1190 )
1192 # for top level values(), convert literals to anonymous bound
1193 # parameters at statement construction time, so that these values can
1194 # participate in the cache key process like any other ClauseElement.
1195 # crud.py now intercepts bound parameters with unique=True from here
1196 # and ensures they get the "crud"-style name when rendered.
1198 kv_generator = DMLState.get_plugin_class(self)._get_crud_kv_pairs
1199 coerced_arg = dict(kv_generator(self, arg.items(), True))
1200 if self._values:
1201 self._values = self._values.union(coerced_arg)
1202 else:
1203 self._values = util.immutabledict(coerced_arg)
1204 return self
1207class Insert(ValuesBase, HasSyntaxExtensions[Literal["post_values"]]):
1208 """Represent an INSERT construct.
1210 The :class:`_expression.Insert` object is created using the
1211 :func:`_expression.insert()` function.
1213 Available extension points:
1215 * ``post_values``: applies additional logic after the ``VALUES`` clause.
1217 """
1219 __visit_name__ = "insert"
1221 _supports_multi_parameters = True
1223 select = None
1224 include_insert_from_select_defaults = False
1226 _sort_by_parameter_order: bool = False
1228 is_insert = True
1230 table: TableClause
1232 _traverse_internals = (
1233 [
1234 ("table", InternalTraversal.dp_clauseelement),
1235 ("_inline", InternalTraversal.dp_boolean),
1236 ("_select_names", InternalTraversal.dp_string_list),
1237 ("_values", InternalTraversal.dp_dml_values),
1238 ("_multi_values", InternalTraversal.dp_dml_multi_values),
1239 ("select", InternalTraversal.dp_clauseelement),
1240 ("_post_values_clause", InternalTraversal.dp_clauseelement),
1241 ("_returning", InternalTraversal.dp_clauseelement_tuple),
1242 ("_hints", InternalTraversal.dp_table_hint_list),
1243 ("_return_defaults", InternalTraversal.dp_boolean),
1244 (
1245 "_return_defaults_columns",
1246 InternalTraversal.dp_clauseelement_tuple,
1247 ),
1248 ("_sort_by_parameter_order", InternalTraversal.dp_boolean),
1249 ]
1250 + HasPrefixes._has_prefixes_traverse_internals
1251 + DialectKWArgs._dialect_kwargs_traverse_internals
1252 + Executable._executable_traverse_internals
1253 + HasCTE._has_ctes_traverse_internals
1254 )
1256 _position_map = util.immutabledict(
1257 {
1258 "post_values": "_post_values_clause",
1259 }
1260 )
1262 _post_values_clause: Optional[ClauseElement] = None
1263 """extension point for a ClauseElement that will be compiled directly
1264 after the VALUES portion of the :class:`.Insert` statement
1266 """
1268 def __init__(self, table: _DMLTableArgument):
1269 super().__init__(table)
1271 def _apply_syntax_extension_to_self(
1272 self, extension: SyntaxExtension
1273 ) -> None:
1274 extension.apply_to_insert(self)
1276 @_generative
1277 def inline(self) -> Self:
1278 """Make this :class:`_expression.Insert` construct "inline" .
1280 When set, no attempt will be made to retrieve the
1281 SQL-generated default values to be provided within the statement;
1282 in particular,
1283 this allows SQL expressions to be rendered 'inline' within the
1284 statement without the need to pre-execute them beforehand; for
1285 backends that support "returning", this turns off the "implicit
1286 returning" feature for the statement.
1289 .. versionchanged:: 1.4 the :paramref:`_expression.Insert.inline`
1290 parameter
1291 is now superseded by the :meth:`_expression.Insert.inline` method.
1293 """
1294 self._inline = True
1295 return self
1297 @_generative
1298 def from_select(
1299 self,
1300 names: Sequence[_DMLColumnArgument],
1301 select: Selectable,
1302 include_defaults: bool = True,
1303 ) -> Self:
1304 """Return a new :class:`_expression.Insert` construct which represents
1305 an ``INSERT...FROM SELECT`` statement.
1307 e.g.::
1309 sel = select(table1.c.a, table1.c.b).where(table1.c.c > 5)
1310 ins = table2.insert().from_select(["a", "b"], sel)
1312 :param names: a sequence of string column names or
1313 :class:`_schema.Column`
1314 objects representing the target columns.
1315 :param select: a :func:`_expression.select` construct,
1316 :class:`_expression.FromClause`
1317 or other construct which resolves into a
1318 :class:`_expression.FromClause`,
1319 such as an ORM :class:`_query.Query` object, etc. The order of
1320 columns returned from this FROM clause should correspond to the
1321 order of columns sent as the ``names`` parameter; while this
1322 is not checked before passing along to the database, the database
1323 would normally raise an exception if these column lists don't
1324 correspond.
1325 :param include_defaults: if True, non-server default values and
1326 SQL expressions as specified on :class:`_schema.Column` objects
1327 (as documented in :ref:`metadata_defaults_toplevel`) not
1328 otherwise specified in the list of names will be rendered
1329 into the INSERT and SELECT statements, so that these values are also
1330 included in the data to be inserted.
1332 .. note:: A Python-side default that uses a Python callable function
1333 will only be invoked **once** for the whole statement, and **not
1334 per row**.
1336 """
1338 if self._values:
1339 raise exc.InvalidRequestError(
1340 "This construct already inserts value expressions"
1341 )
1343 self._select_names = [
1344 coercions.expect(roles.DMLColumnRole, name, as_key=True)
1345 for name in names
1346 ]
1347 self._inline = True
1348 self.include_insert_from_select_defaults = include_defaults
1349 self.select = coercions.expect(roles.DMLSelectRole, select)
1350 return self
1352 if TYPE_CHECKING:
1353 # START OVERLOADED FUNCTIONS self.returning ReturningInsert 1-8 ", *, sort_by_parameter_order: bool = False" # noqa: E501
1355 # code within this block is **programmatically,
1356 # statically generated** by tools/generate_tuple_map_overloads.py
1358 @overload
1359 def returning(
1360 self,
1361 __ent0: _TCCA[_T0],
1362 /,
1363 *,
1364 sort_by_parameter_order: bool = False,
1365 ) -> ReturningInsert[_T0]: ...
1367 @overload
1368 def returning(
1369 self,
1370 __ent0: _TCCA[_T0],
1371 __ent1: _TCCA[_T1],
1372 /,
1373 *,
1374 sort_by_parameter_order: bool = False,
1375 ) -> ReturningInsert[_T0, _T1]: ...
1377 @overload
1378 def returning(
1379 self,
1380 __ent0: _TCCA[_T0],
1381 __ent1: _TCCA[_T1],
1382 __ent2: _TCCA[_T2],
1383 /,
1384 *,
1385 sort_by_parameter_order: bool = False,
1386 ) -> ReturningInsert[_T0, _T1, _T2]: ...
1388 @overload
1389 def returning(
1390 self,
1391 __ent0: _TCCA[_T0],
1392 __ent1: _TCCA[_T1],
1393 __ent2: _TCCA[_T2],
1394 __ent3: _TCCA[_T3],
1395 /,
1396 *,
1397 sort_by_parameter_order: bool = False,
1398 ) -> ReturningInsert[_T0, _T1, _T2, _T3]: ...
1400 @overload
1401 def returning(
1402 self,
1403 __ent0: _TCCA[_T0],
1404 __ent1: _TCCA[_T1],
1405 __ent2: _TCCA[_T2],
1406 __ent3: _TCCA[_T3],
1407 __ent4: _TCCA[_T4],
1408 /,
1409 *,
1410 sort_by_parameter_order: bool = False,
1411 ) -> ReturningInsert[_T0, _T1, _T2, _T3, _T4]: ...
1413 @overload
1414 def returning(
1415 self,
1416 __ent0: _TCCA[_T0],
1417 __ent1: _TCCA[_T1],
1418 __ent2: _TCCA[_T2],
1419 __ent3: _TCCA[_T3],
1420 __ent4: _TCCA[_T4],
1421 __ent5: _TCCA[_T5],
1422 /,
1423 *,
1424 sort_by_parameter_order: bool = False,
1425 ) -> ReturningInsert[_T0, _T1, _T2, _T3, _T4, _T5]: ...
1427 @overload
1428 def returning(
1429 self,
1430 __ent0: _TCCA[_T0],
1431 __ent1: _TCCA[_T1],
1432 __ent2: _TCCA[_T2],
1433 __ent3: _TCCA[_T3],
1434 __ent4: _TCCA[_T4],
1435 __ent5: _TCCA[_T5],
1436 __ent6: _TCCA[_T6],
1437 /,
1438 *,
1439 sort_by_parameter_order: bool = False,
1440 ) -> ReturningInsert[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ...
1442 @overload
1443 def returning(
1444 self,
1445 __ent0: _TCCA[_T0],
1446 __ent1: _TCCA[_T1],
1447 __ent2: _TCCA[_T2],
1448 __ent3: _TCCA[_T3],
1449 __ent4: _TCCA[_T4],
1450 __ent5: _TCCA[_T5],
1451 __ent6: _TCCA[_T6],
1452 __ent7: _TCCA[_T7],
1453 /,
1454 *entities: _ColumnsClauseArgument[Any],
1455 sort_by_parameter_order: bool = False,
1456 ) -> ReturningInsert[
1457 _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]
1458 ]: ...
1460 # END OVERLOADED FUNCTIONS self.returning
1462 @overload
1463 def returning(
1464 self,
1465 *cols: _ColumnsClauseArgument[Any],
1466 sort_by_parameter_order: bool = False,
1467 **__kw: Any,
1468 ) -> ReturningInsert[Any]: ...
1470 def returning(
1471 self,
1472 *cols: _ColumnsClauseArgument[Any],
1473 sort_by_parameter_order: bool = False,
1474 **__kw: Any,
1475 ) -> ReturningInsert[Any]: ...
1478class ReturningInsert(Insert, TypedReturnsRows[Unpack[_Ts]]):
1479 """Typing-only class that establishes a generic type form of
1480 :class:`.Insert` which tracks returned column types.
1482 This datatype is delivered when calling the
1483 :meth:`.Insert.returning` method.
1485 .. versionadded:: 2.0
1487 """
1490# note: if not for MRO issues, this class should extend
1491# from HasSyntaxExtensions[Literal["post_criteria"]]
1492class DMLWhereBase:
1493 table: _DMLTableElement
1494 _where_criteria: Tuple[ColumnElement[Any], ...] = ()
1496 _post_criteria_clause: Optional[ClauseElement] = None
1497 """used by extensions to Update/Delete etc. to add additional syntacitcal
1498 constructs, e.g. LIMIT etc.
1500 .. versionadded:: 2.1
1502 """
1504 # can't put position_map here either without HasSyntaxExtensions
1505 # _position_map = util.immutabledict(
1506 # {"post_criteria": "_post_criteria_clause"}
1507 # )
1509 @_generative
1510 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self:
1511 """Return a new construct with the given expression(s) added to
1512 its WHERE clause, joined to the existing clause via AND, if any.
1514 Both :meth:`_dml.Update.where` and :meth:`_dml.Delete.where`
1515 support multiple-table forms, including database-specific
1516 ``UPDATE...FROM`` as well as ``DELETE..USING``. For backends that
1517 don't have multiple-table support, a backend agnostic approach
1518 to using multiple tables is to make use of correlated subqueries.
1519 See the linked tutorial sections below for examples.
1521 .. seealso::
1523 :ref:`tutorial_correlated_updates`
1525 :ref:`tutorial_update_from`
1527 :ref:`tutorial_multi_table_deletes`
1529 """
1531 for criterion in whereclause:
1532 where_criteria: ColumnElement[Any] = coercions.expect(
1533 roles.WhereHavingRole, criterion, apply_propagate_attrs=self
1534 )
1535 self._where_criteria += (where_criteria,)
1536 return self
1538 def filter(self, *criteria: roles.ExpressionElementRole[Any]) -> Self:
1539 """A synonym for the :meth:`_dml.DMLWhereBase.where` method.
1541 .. versionadded:: 1.4
1543 """
1545 return self.where(*criteria)
1547 def _filter_by_zero(self) -> _DMLTableElement:
1548 return self.table
1550 def filter_by(self, **kwargs: Any) -> Self:
1551 r"""apply the given filtering criterion as a WHERE clause
1552 to this select.
1554 """
1555 from_entity = self._filter_by_zero()
1557 clauses = [
1558 _entity_namespace_key(from_entity, key) == value
1559 for key, value in kwargs.items()
1560 ]
1561 return self.filter(*clauses)
1563 @property
1564 def whereclause(self) -> Optional[ColumnElement[Any]]:
1565 """Return the completed WHERE clause for this :class:`.DMLWhereBase`
1566 statement.
1568 This assembles the current collection of WHERE criteria
1569 into a single :class:`_expression.BooleanClauseList` construct.
1572 .. versionadded:: 1.4
1574 """
1576 return BooleanClauseList._construct_for_whereclause(
1577 self._where_criteria
1578 )
1581class Update(
1582 DMLWhereBase, ValuesBase, HasSyntaxExtensions[Literal["post_criteria"]]
1583):
1584 """Represent an Update construct.
1586 The :class:`_expression.Update` object is created using the
1587 :func:`_expression.update()` function.
1589 Available extension points:
1591 * ``post_criteria``: applies additional logic after the ``WHERE`` clause.
1593 """
1595 __visit_name__ = "update"
1597 is_update = True
1599 _traverse_internals = (
1600 [
1601 ("table", InternalTraversal.dp_clauseelement),
1602 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple),
1603 ("_inline", InternalTraversal.dp_boolean),
1604 ("_maintain_values_ordering", InternalTraversal.dp_boolean),
1605 ("_values", InternalTraversal.dp_dml_values),
1606 ("_returning", InternalTraversal.dp_clauseelement_tuple),
1607 ("_hints", InternalTraversal.dp_table_hint_list),
1608 ("_return_defaults", InternalTraversal.dp_boolean),
1609 ("_post_criteria_clause", InternalTraversal.dp_clauseelement),
1610 (
1611 "_return_defaults_columns",
1612 InternalTraversal.dp_clauseelement_tuple,
1613 ),
1614 ]
1615 + HasPrefixes._has_prefixes_traverse_internals
1616 + DialectKWArgs._dialect_kwargs_traverse_internals
1617 + Executable._executable_traverse_internals
1618 + HasCTE._has_ctes_traverse_internals
1619 )
1621 _position_map = util.immutabledict(
1622 {"post_criteria": "_post_criteria_clause"}
1623 )
1625 def __init__(self, table: _DMLTableArgument):
1626 super().__init__(table)
1628 def ordered_values(self, *args: Tuple[_DMLColumnArgument, Any]) -> Self:
1629 """Specify the VALUES clause of this UPDATE statement with an explicit
1630 parameter ordering that will be maintained in the SET clause of the
1631 resulting UPDATE statement.
1633 E.g.::
1635 stmt = table.update().ordered_values(("name", "ed"), ("ident", "foo"))
1637 .. seealso::
1639 :ref:`tutorial_parameter_ordered_updates` - full example of the
1640 :meth:`_expression.Update.ordered_values` method.
1642 .. versionchanged:: 1.4 The :meth:`_expression.Update.ordered_values`
1643 method
1644 supersedes the
1645 :paramref:`_expression.update.preserve_parameter_order`
1646 parameter, which will be removed in SQLAlchemy 2.0.
1648 """ # noqa: E501
1649 if self._values:
1650 raise exc.ArgumentError(
1651 "This statement already has "
1652 f"{'ordered ' if self._maintain_values_ordering else ''}"
1653 "values present"
1654 )
1656 self = self.values(dict(args))
1657 self._maintain_values_ordering = True
1658 return self
1660 @_generative
1661 def inline(self) -> Self:
1662 """Make this :class:`_expression.Update` construct "inline" .
1664 When set, SQL defaults present on :class:`_schema.Column`
1665 objects via the
1666 ``default`` keyword will be compiled 'inline' into the statement and
1667 not pre-executed. This means that their values will not be available
1668 in the dictionary returned from
1669 :meth:`_engine.CursorResult.last_updated_params`.
1671 .. versionchanged:: 1.4 the :paramref:`_expression.update.inline`
1672 parameter
1673 is now superseded by the :meth:`_expression.Update.inline` method.
1675 """
1676 self._inline = True
1677 return self
1679 def _apply_syntax_extension_to_self(
1680 self, extension: SyntaxExtension
1681 ) -> None:
1682 extension.apply_to_update(self)
1684 if TYPE_CHECKING:
1685 # START OVERLOADED FUNCTIONS self.returning ReturningUpdate 1-8
1687 # code within this block is **programmatically,
1688 # statically generated** by tools/generate_tuple_map_overloads.py
1690 @overload
1691 def returning(self, __ent0: _TCCA[_T0], /) -> ReturningUpdate[_T0]: ...
1693 @overload
1694 def returning(
1695 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], /
1696 ) -> ReturningUpdate[_T0, _T1]: ...
1698 @overload
1699 def returning(
1700 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2], /
1701 ) -> ReturningUpdate[_T0, _T1, _T2]: ...
1703 @overload
1704 def returning(
1705 self,
1706 __ent0: _TCCA[_T0],
1707 __ent1: _TCCA[_T1],
1708 __ent2: _TCCA[_T2],
1709 __ent3: _TCCA[_T3],
1710 /,
1711 ) -> ReturningUpdate[_T0, _T1, _T2, _T3]: ...
1713 @overload
1714 def returning(
1715 self,
1716 __ent0: _TCCA[_T0],
1717 __ent1: _TCCA[_T1],
1718 __ent2: _TCCA[_T2],
1719 __ent3: _TCCA[_T3],
1720 __ent4: _TCCA[_T4],
1721 /,
1722 ) -> ReturningUpdate[_T0, _T1, _T2, _T3, _T4]: ...
1724 @overload
1725 def returning(
1726 self,
1727 __ent0: _TCCA[_T0],
1728 __ent1: _TCCA[_T1],
1729 __ent2: _TCCA[_T2],
1730 __ent3: _TCCA[_T3],
1731 __ent4: _TCCA[_T4],
1732 __ent5: _TCCA[_T5],
1733 /,
1734 ) -> ReturningUpdate[_T0, _T1, _T2, _T3, _T4, _T5]: ...
1736 @overload
1737 def returning(
1738 self,
1739 __ent0: _TCCA[_T0],
1740 __ent1: _TCCA[_T1],
1741 __ent2: _TCCA[_T2],
1742 __ent3: _TCCA[_T3],
1743 __ent4: _TCCA[_T4],
1744 __ent5: _TCCA[_T5],
1745 __ent6: _TCCA[_T6],
1746 /,
1747 ) -> ReturningUpdate[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ...
1749 @overload
1750 def returning(
1751 self,
1752 __ent0: _TCCA[_T0],
1753 __ent1: _TCCA[_T1],
1754 __ent2: _TCCA[_T2],
1755 __ent3: _TCCA[_T3],
1756 __ent4: _TCCA[_T4],
1757 __ent5: _TCCA[_T5],
1758 __ent6: _TCCA[_T6],
1759 __ent7: _TCCA[_T7],
1760 /,
1761 *entities: _ColumnsClauseArgument[Any],
1762 ) -> ReturningUpdate[
1763 _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]
1764 ]: ...
1766 # END OVERLOADED FUNCTIONS self.returning
1768 @overload
1769 def returning(
1770 self, *cols: _ColumnsClauseArgument[Any], **__kw: Any
1771 ) -> ReturningUpdate[Any]: ...
1773 def returning(
1774 self, *cols: _ColumnsClauseArgument[Any], **__kw: Any
1775 ) -> ReturningUpdate[Any]: ...
1778class ReturningUpdate(Update, TypedReturnsRows[Unpack[_Ts]]):
1779 """Typing-only class that establishes a generic type form of
1780 :class:`.Update` which tracks returned column types.
1782 This datatype is delivered when calling the
1783 :meth:`.Update.returning` method.
1785 .. versionadded:: 2.0
1787 """
1790class Delete(
1791 DMLWhereBase, UpdateBase, HasSyntaxExtensions[Literal["post_criteria"]]
1792):
1793 """Represent a DELETE construct.
1795 The :class:`_expression.Delete` object is created using the
1796 :func:`_expression.delete()` function.
1798 Available extension points:
1800 * ``post_criteria``: applies additional logic after the ``WHERE`` clause.
1802 """
1804 __visit_name__ = "delete"
1806 is_delete = True
1808 _traverse_internals = (
1809 [
1810 ("table", InternalTraversal.dp_clauseelement),
1811 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple),
1812 ("_returning", InternalTraversal.dp_clauseelement_tuple),
1813 ("_hints", InternalTraversal.dp_table_hint_list),
1814 ("_post_criteria_clause", InternalTraversal.dp_clauseelement),
1815 ]
1816 + HasPrefixes._has_prefixes_traverse_internals
1817 + DialectKWArgs._dialect_kwargs_traverse_internals
1818 + Executable._executable_traverse_internals
1819 + HasCTE._has_ctes_traverse_internals
1820 )
1822 _position_map = util.immutabledict(
1823 {"post_criteria": "_post_criteria_clause"}
1824 )
1826 def __init__(self, table: _DMLTableArgument):
1827 self.table = coercions.expect(
1828 roles.DMLTableRole, table, apply_propagate_attrs=self
1829 )
1831 def _apply_syntax_extension_to_self(
1832 self, extension: SyntaxExtension
1833 ) -> None:
1834 extension.apply_to_delete(self)
1836 if TYPE_CHECKING:
1837 # START OVERLOADED FUNCTIONS self.returning ReturningDelete 1-8
1839 # code within this block is **programmatically,
1840 # statically generated** by tools/generate_tuple_map_overloads.py
1842 @overload
1843 def returning(self, __ent0: _TCCA[_T0], /) -> ReturningDelete[_T0]: ...
1845 @overload
1846 def returning(
1847 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], /
1848 ) -> ReturningDelete[_T0, _T1]: ...
1850 @overload
1851 def returning(
1852 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2], /
1853 ) -> ReturningDelete[_T0, _T1, _T2]: ...
1855 @overload
1856 def returning(
1857 self,
1858 __ent0: _TCCA[_T0],
1859 __ent1: _TCCA[_T1],
1860 __ent2: _TCCA[_T2],
1861 __ent3: _TCCA[_T3],
1862 /,
1863 ) -> ReturningDelete[_T0, _T1, _T2, _T3]: ...
1865 @overload
1866 def returning(
1867 self,
1868 __ent0: _TCCA[_T0],
1869 __ent1: _TCCA[_T1],
1870 __ent2: _TCCA[_T2],
1871 __ent3: _TCCA[_T3],
1872 __ent4: _TCCA[_T4],
1873 /,
1874 ) -> ReturningDelete[_T0, _T1, _T2, _T3, _T4]: ...
1876 @overload
1877 def returning(
1878 self,
1879 __ent0: _TCCA[_T0],
1880 __ent1: _TCCA[_T1],
1881 __ent2: _TCCA[_T2],
1882 __ent3: _TCCA[_T3],
1883 __ent4: _TCCA[_T4],
1884 __ent5: _TCCA[_T5],
1885 /,
1886 ) -> ReturningDelete[_T0, _T1, _T2, _T3, _T4, _T5]: ...
1888 @overload
1889 def returning(
1890 self,
1891 __ent0: _TCCA[_T0],
1892 __ent1: _TCCA[_T1],
1893 __ent2: _TCCA[_T2],
1894 __ent3: _TCCA[_T3],
1895 __ent4: _TCCA[_T4],
1896 __ent5: _TCCA[_T5],
1897 __ent6: _TCCA[_T6],
1898 /,
1899 ) -> ReturningDelete[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ...
1901 @overload
1902 def returning(
1903 self,
1904 __ent0: _TCCA[_T0],
1905 __ent1: _TCCA[_T1],
1906 __ent2: _TCCA[_T2],
1907 __ent3: _TCCA[_T3],
1908 __ent4: _TCCA[_T4],
1909 __ent5: _TCCA[_T5],
1910 __ent6: _TCCA[_T6],
1911 __ent7: _TCCA[_T7],
1912 /,
1913 *entities: _ColumnsClauseArgument[Any],
1914 ) -> ReturningDelete[
1915 _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]
1916 ]: ...
1918 # END OVERLOADED FUNCTIONS self.returning
1920 @overload
1921 def returning(
1922 self, *cols: _ColumnsClauseArgument[Any], **__kw: Any
1923 ) -> ReturningDelete[Unpack[TupleAny]]: ...
1925 def returning(
1926 self, *cols: _ColumnsClauseArgument[Any], **__kw: Any
1927 ) -> ReturningDelete[Unpack[TupleAny]]: ...
1930class ReturningDelete(Update, TypedReturnsRows[Unpack[_Ts]]):
1931 """Typing-only class that establishes a generic type form of
1932 :class:`.Delete` which tracks returned column types.
1934 This datatype is delivered when calling the
1935 :meth:`.Delete.returning` method.
1937 .. versionadded:: 2.0
1939 """