This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# sql/dml.py
|
||||
# Copyright (C) 2009-2025 the SQLAlchemy authors and contributors
|
||||
# Copyright (C) 2009-2023 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
@@ -23,7 +23,6 @@ from typing import NoReturn
|
||||
from typing import Optional
|
||||
from typing import overload
|
||||
from typing import Sequence
|
||||
from typing import Set
|
||||
from typing import Tuple
|
||||
from typing import Type
|
||||
from typing import TYPE_CHECKING
|
||||
@@ -43,7 +42,6 @@ from .base import _from_objects
|
||||
from .base import _generative
|
||||
from .base import _select_iterables
|
||||
from .base import ColumnCollection
|
||||
from .base import ColumnSet
|
||||
from .base import CompileState
|
||||
from .base import DialectKWArgs
|
||||
from .base import Executable
|
||||
@@ -93,11 +91,14 @@ if TYPE_CHECKING:
|
||||
from .selectable import Select
|
||||
from .selectable import Selectable
|
||||
|
||||
def isupdate(dml: DMLState) -> TypeGuard[UpdateDMLState]: ...
|
||||
def isupdate(dml: DMLState) -> TypeGuard[UpdateDMLState]:
|
||||
...
|
||||
|
||||
def isdelete(dml: DMLState) -> TypeGuard[DeleteDMLState]: ...
|
||||
def isdelete(dml: DMLState) -> TypeGuard[DeleteDMLState]:
|
||||
...
|
||||
|
||||
def isinsert(dml: DMLState) -> TypeGuard[InsertDMLState]: ...
|
||||
def isinsert(dml: DMLState) -> TypeGuard[InsertDMLState]:
|
||||
...
|
||||
|
||||
else:
|
||||
isupdate = operator.attrgetter("isupdate")
|
||||
@@ -136,11 +137,9 @@ class DMLState(CompileState):
|
||||
@classmethod
|
||||
def get_entity_description(cls, statement: UpdateBase) -> Dict[str, Any]:
|
||||
return {
|
||||
"name": (
|
||||
statement.table.name
|
||||
if is_named_from_clause(statement.table)
|
||||
else None
|
||||
),
|
||||
"name": statement.table.name
|
||||
if is_named_from_clause(statement.table)
|
||||
else None,
|
||||
"table": statement.table,
|
||||
}
|
||||
|
||||
@@ -164,7 +163,8 @@ class DMLState(CompileState):
|
||||
if TYPE_CHECKING:
|
||||
|
||||
@classmethod
|
||||
def get_plugin_class(cls, statement: Executable) -> Type[DMLState]: ...
|
||||
def get_plugin_class(cls, statement: Executable) -> Type[DMLState]:
|
||||
...
|
||||
|
||||
@classmethod
|
||||
def _get_multi_crud_kv_pairs(
|
||||
@@ -190,15 +190,13 @@ class DMLState(CompileState):
|
||||
return [
|
||||
(
|
||||
coercions.expect(roles.DMLColumnRole, k),
|
||||
(
|
||||
v
|
||||
if not needs_to_be_cacheable
|
||||
else coercions.expect(
|
||||
roles.ExpressionElementRole,
|
||||
v,
|
||||
type_=NullType(),
|
||||
is_crud=True,
|
||||
)
|
||||
v
|
||||
if not needs_to_be_cacheable
|
||||
else coercions.expect(
|
||||
roles.ExpressionElementRole,
|
||||
v,
|
||||
type_=NullType(),
|
||||
is_crud=True,
|
||||
),
|
||||
)
|
||||
for k, v in kv_iterator
|
||||
@@ -308,14 +306,12 @@ class InsertDMLState(DMLState):
|
||||
def _process_multi_values(self, statement: ValuesBase) -> None:
|
||||
for parameters in statement._multi_values:
|
||||
multi_parameters: List[MutableMapping[_DMLColumnElement, Any]] = [
|
||||
(
|
||||
{
|
||||
c.key: value
|
||||
for c, value in zip(statement.table.c, parameter_set)
|
||||
}
|
||||
if isinstance(parameter_set, collections_abc.Sequence)
|
||||
else parameter_set
|
||||
)
|
||||
{
|
||||
c.key: value
|
||||
for c, value in zip(statement.table.c, parameter_set)
|
||||
}
|
||||
if isinstance(parameter_set, collections_abc.Sequence)
|
||||
else parameter_set
|
||||
for parameter_set in parameters
|
||||
]
|
||||
|
||||
@@ -400,9 +396,9 @@ class UpdateBase(
|
||||
|
||||
__visit_name__ = "update_base"
|
||||
|
||||
_hints: util.immutabledict[Tuple[_DMLTableElement, str], str] = (
|
||||
util.EMPTY_DICT
|
||||
)
|
||||
_hints: util.immutabledict[
|
||||
Tuple[_DMLTableElement, str], str
|
||||
] = util.EMPTY_DICT
|
||||
named_with_column = False
|
||||
|
||||
_label_style: SelectLabelStyle = (
|
||||
@@ -411,25 +407,19 @@ class UpdateBase(
|
||||
table: _DMLTableElement
|
||||
|
||||
_return_defaults = False
|
||||
_return_defaults_columns: Optional[Tuple[_ColumnsClauseElement, ...]] = (
|
||||
None
|
||||
)
|
||||
_return_defaults_columns: Optional[
|
||||
Tuple[_ColumnsClauseElement, ...]
|
||||
] = None
|
||||
_supplemental_returning: Optional[Tuple[_ColumnsClauseElement, ...]] = None
|
||||
_returning: Tuple[_ColumnsClauseElement, ...] = ()
|
||||
|
||||
is_dml = True
|
||||
|
||||
def _generate_fromclause_column_proxies(
|
||||
self,
|
||||
fromclause: FromClause,
|
||||
columns: ColumnCollection[str, KeyedColumnElement[Any]],
|
||||
primary_key: ColumnSet,
|
||||
foreign_keys: Set[KeyedColumnElement[Any]],
|
||||
self, fromclause: FromClause
|
||||
) -> None:
|
||||
columns._populate_separate_keys(
|
||||
col._make_proxy(
|
||||
fromclause, primary_key=primary_key, foreign_keys=foreign_keys
|
||||
)
|
||||
fromclause._columns._populate_separate_keys(
|
||||
col._make_proxy(fromclause)
|
||||
for col in self._all_selected_columns
|
||||
if is_column_element(col)
|
||||
)
|
||||
@@ -533,11 +523,11 @@ class UpdateBase(
|
||||
|
||||
E.g.::
|
||||
|
||||
stmt = table.insert().values(data="newdata").return_defaults()
|
||||
stmt = table.insert().values(data='newdata').return_defaults()
|
||||
|
||||
result = connection.execute(stmt)
|
||||
|
||||
server_created_at = result.returned_defaults["created_at"]
|
||||
server_created_at = result.returned_defaults['created_at']
|
||||
|
||||
When used against an UPDATE statement
|
||||
:meth:`.UpdateBase.return_defaults` instead looks for columns that
|
||||
@@ -695,16 +685,6 @@ class UpdateBase(
|
||||
|
||||
return self
|
||||
|
||||
def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
|
||||
"""Return ``True`` if this :class:`.ReturnsRows` is
|
||||
'derived' from the given :class:`.FromClause`.
|
||||
|
||||
Since these are DMLs, we dont want such statements ever being adapted
|
||||
so we return False for derives.
|
||||
|
||||
"""
|
||||
return False
|
||||
|
||||
@_generative
|
||||
def returning(
|
||||
self,
|
||||
@@ -1050,7 +1030,7 @@ class ValuesBase(UpdateBase):
|
||||
|
||||
users.insert().values(name="some name")
|
||||
|
||||
users.update().where(users.c.id == 5).values(name="some name")
|
||||
users.update().where(users.c.id==5).values(name="some name")
|
||||
|
||||
:param \*args: As an alternative to passing key/value parameters,
|
||||
a dictionary, tuple, or list of dictionaries or tuples can be passed
|
||||
@@ -1080,17 +1060,13 @@ class ValuesBase(UpdateBase):
|
||||
this syntax is supported on backends such as SQLite, PostgreSQL,
|
||||
MySQL, but not necessarily others::
|
||||
|
||||
users.insert().values(
|
||||
[
|
||||
{"name": "some name"},
|
||||
{"name": "some other name"},
|
||||
{"name": "yet another name"},
|
||||
]
|
||||
)
|
||||
users.insert().values([
|
||||
{"name": "some name"},
|
||||
{"name": "some other name"},
|
||||
{"name": "yet another name"},
|
||||
])
|
||||
|
||||
The above form would render a multiple VALUES statement similar to:
|
||||
|
||||
.. sourcecode:: sql
|
||||
The above form would render a multiple VALUES statement similar to::
|
||||
|
||||
INSERT INTO users (name) VALUES
|
||||
(:name_1),
|
||||
@@ -1268,7 +1244,7 @@ class Insert(ValuesBase):
|
||||
e.g.::
|
||||
|
||||
sel = select(table1.c.a, table1.c.b).where(table1.c.c > 5)
|
||||
ins = table2.insert().from_select(["a", "b"], sel)
|
||||
ins = table2.insert().from_select(['a', 'b'], sel)
|
||||
|
||||
:param names: a sequence of string column names or
|
||||
:class:`_schema.Column`
|
||||
@@ -1319,7 +1295,8 @@ class Insert(ValuesBase):
|
||||
@overload
|
||||
def returning(
|
||||
self, __ent0: _TCCA[_T0], *, sort_by_parameter_order: bool = False
|
||||
) -> ReturningInsert[Tuple[_T0]]: ...
|
||||
) -> ReturningInsert[Tuple[_T0]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1328,7 +1305,8 @@ class Insert(ValuesBase):
|
||||
__ent1: _TCCA[_T1],
|
||||
*,
|
||||
sort_by_parameter_order: bool = False,
|
||||
) -> ReturningInsert[Tuple[_T0, _T1]]: ...
|
||||
) -> ReturningInsert[Tuple[_T0, _T1]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1338,7 +1316,8 @@ class Insert(ValuesBase):
|
||||
__ent2: _TCCA[_T2],
|
||||
*,
|
||||
sort_by_parameter_order: bool = False,
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2]]: ...
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1349,7 +1328,8 @@ class Insert(ValuesBase):
|
||||
__ent3: _TCCA[_T3],
|
||||
*,
|
||||
sort_by_parameter_order: bool = False,
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2, _T3]]: ...
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2, _T3]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1361,7 +1341,8 @@ class Insert(ValuesBase):
|
||||
__ent4: _TCCA[_T4],
|
||||
*,
|
||||
sort_by_parameter_order: bool = False,
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2, _T3, _T4]]: ...
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2, _T3, _T4]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1374,7 +1355,8 @@ class Insert(ValuesBase):
|
||||
__ent5: _TCCA[_T5],
|
||||
*,
|
||||
sort_by_parameter_order: bool = False,
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ...
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1388,7 +1370,8 @@ class Insert(ValuesBase):
|
||||
__ent6: _TCCA[_T6],
|
||||
*,
|
||||
sort_by_parameter_order: bool = False,
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ...
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1403,9 +1386,8 @@ class Insert(ValuesBase):
|
||||
__ent7: _TCCA[_T7],
|
||||
*,
|
||||
sort_by_parameter_order: bool = False,
|
||||
) -> ReturningInsert[
|
||||
Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]
|
||||
]: ...
|
||||
) -> ReturningInsert[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]:
|
||||
...
|
||||
|
||||
# END OVERLOADED FUNCTIONS self.returning
|
||||
|
||||
@@ -1415,14 +1397,16 @@ class Insert(ValuesBase):
|
||||
*cols: _ColumnsClauseArgument[Any],
|
||||
sort_by_parameter_order: bool = False,
|
||||
**__kw: Any,
|
||||
) -> ReturningInsert[Any]: ...
|
||||
) -> ReturningInsert[Any]:
|
||||
...
|
||||
|
||||
def returning(
|
||||
self,
|
||||
*cols: _ColumnsClauseArgument[Any],
|
||||
sort_by_parameter_order: bool = False,
|
||||
**__kw: Any,
|
||||
) -> ReturningInsert[Any]: ...
|
||||
) -> ReturningInsert[Any]:
|
||||
...
|
||||
|
||||
|
||||
class ReturningInsert(Insert, TypedReturnsRows[_TP]):
|
||||
@@ -1557,7 +1541,9 @@ class Update(DMLWhereBase, ValuesBase):
|
||||
|
||||
E.g.::
|
||||
|
||||
stmt = table.update().ordered_values(("name", "ed"), ("ident", "foo"))
|
||||
stmt = table.update().ordered_values(
|
||||
("name", "ed"), ("ident": "foo")
|
||||
)
|
||||
|
||||
.. seealso::
|
||||
|
||||
@@ -1570,7 +1556,7 @@ class Update(DMLWhereBase, ValuesBase):
|
||||
:paramref:`_expression.update.preserve_parameter_order`
|
||||
parameter, which will be removed in SQLAlchemy 2.0.
|
||||
|
||||
""" # noqa: E501
|
||||
"""
|
||||
if self._values:
|
||||
raise exc.ArgumentError(
|
||||
"This statement already has values present"
|
||||
@@ -1610,19 +1596,20 @@ class Update(DMLWhereBase, ValuesBase):
|
||||
# statically generated** by tools/generate_tuple_map_overloads.py
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
self, __ent0: _TCCA[_T0]
|
||||
) -> ReturningUpdate[Tuple[_T0]]: ...
|
||||
def returning(self, __ent0: _TCCA[_T0]) -> ReturningUpdate[Tuple[_T0]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1]
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1]]: ...
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2]
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2]]: ...
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1631,7 +1618,8 @@ class Update(DMLWhereBase, ValuesBase):
|
||||
__ent1: _TCCA[_T1],
|
||||
__ent2: _TCCA[_T2],
|
||||
__ent3: _TCCA[_T3],
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2, _T3]]: ...
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2, _T3]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1641,7 +1629,8 @@ class Update(DMLWhereBase, ValuesBase):
|
||||
__ent2: _TCCA[_T2],
|
||||
__ent3: _TCCA[_T3],
|
||||
__ent4: _TCCA[_T4],
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2, _T3, _T4]]: ...
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2, _T3, _T4]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1652,7 +1641,8 @@ class Update(DMLWhereBase, ValuesBase):
|
||||
__ent3: _TCCA[_T3],
|
||||
__ent4: _TCCA[_T4],
|
||||
__ent5: _TCCA[_T5],
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ...
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1664,7 +1654,8 @@ class Update(DMLWhereBase, ValuesBase):
|
||||
__ent4: _TCCA[_T4],
|
||||
__ent5: _TCCA[_T5],
|
||||
__ent6: _TCCA[_T6],
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ...
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1677,20 +1668,21 @@ class Update(DMLWhereBase, ValuesBase):
|
||||
__ent5: _TCCA[_T5],
|
||||
__ent6: _TCCA[_T6],
|
||||
__ent7: _TCCA[_T7],
|
||||
) -> ReturningUpdate[
|
||||
Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]
|
||||
]: ...
|
||||
) -> ReturningUpdate[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]:
|
||||
...
|
||||
|
||||
# END OVERLOADED FUNCTIONS self.returning
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
self, *cols: _ColumnsClauseArgument[Any], **__kw: Any
|
||||
) -> ReturningUpdate[Any]: ...
|
||||
) -> ReturningUpdate[Any]:
|
||||
...
|
||||
|
||||
def returning(
|
||||
self, *cols: _ColumnsClauseArgument[Any], **__kw: Any
|
||||
) -> ReturningUpdate[Any]: ...
|
||||
) -> ReturningUpdate[Any]:
|
||||
...
|
||||
|
||||
|
||||
class ReturningUpdate(Update, TypedReturnsRows[_TP]):
|
||||
@@ -1742,19 +1734,20 @@ class Delete(DMLWhereBase, UpdateBase):
|
||||
# statically generated** by tools/generate_tuple_map_overloads.py
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
self, __ent0: _TCCA[_T0]
|
||||
) -> ReturningDelete[Tuple[_T0]]: ...
|
||||
def returning(self, __ent0: _TCCA[_T0]) -> ReturningDelete[Tuple[_T0]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1]
|
||||
) -> ReturningDelete[Tuple[_T0, _T1]]: ...
|
||||
) -> ReturningDelete[Tuple[_T0, _T1]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2]
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2]]: ...
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1763,7 +1756,8 @@ class Delete(DMLWhereBase, UpdateBase):
|
||||
__ent1: _TCCA[_T1],
|
||||
__ent2: _TCCA[_T2],
|
||||
__ent3: _TCCA[_T3],
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2, _T3]]: ...
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2, _T3]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1773,7 +1767,8 @@ class Delete(DMLWhereBase, UpdateBase):
|
||||
__ent2: _TCCA[_T2],
|
||||
__ent3: _TCCA[_T3],
|
||||
__ent4: _TCCA[_T4],
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2, _T3, _T4]]: ...
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2, _T3, _T4]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1784,7 +1779,8 @@ class Delete(DMLWhereBase, UpdateBase):
|
||||
__ent3: _TCCA[_T3],
|
||||
__ent4: _TCCA[_T4],
|
||||
__ent5: _TCCA[_T5],
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ...
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1796,7 +1792,8 @@ class Delete(DMLWhereBase, UpdateBase):
|
||||
__ent4: _TCCA[_T4],
|
||||
__ent5: _TCCA[_T5],
|
||||
__ent6: _TCCA[_T6],
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ...
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
@@ -1809,20 +1806,21 @@ class Delete(DMLWhereBase, UpdateBase):
|
||||
__ent5: _TCCA[_T5],
|
||||
__ent6: _TCCA[_T6],
|
||||
__ent7: _TCCA[_T7],
|
||||
) -> ReturningDelete[
|
||||
Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]
|
||||
]: ...
|
||||
) -> ReturningDelete[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]:
|
||||
...
|
||||
|
||||
# END OVERLOADED FUNCTIONS self.returning
|
||||
|
||||
@overload
|
||||
def returning(
|
||||
self, *cols: _ColumnsClauseArgument[Any], **__kw: Any
|
||||
) -> ReturningDelete[Any]: ...
|
||||
) -> ReturningDelete[Any]:
|
||||
...
|
||||
|
||||
def returning(
|
||||
self, *cols: _ColumnsClauseArgument[Any], **__kw: Any
|
||||
) -> ReturningDelete[Any]: ...
|
||||
) -> ReturningDelete[Any]:
|
||||
...
|
||||
|
||||
|
||||
class ReturningDelete(Update, TypedReturnsRows[_TP]):
|
||||
|
||||
Reference in New Issue
Block a user