mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-28 11:35:19 -04:00
- Fixed regression in 1.0 where new feature of using "executemany"
for UPDATE statements in the ORM (e.g. :ref:`feature_updatemany`) would break on Postgresql and other RETURNING backends when using server-side version generation schemes, as the server side value is retrieved via RETURNING which is not supported with executemany. fixes #3556
This commit is contained in:
Vendored
+12
@@ -18,6 +18,18 @@
|
||||
.. changelog::
|
||||
:version: 1.0.9
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm, postgresql
|
||||
:versions: 1.1.0b1
|
||||
:tickets: 3556
|
||||
|
||||
Fixed regression in 1.0 where new feature of using "executemany"
|
||||
for UPDATE statements in the ORM (e.g. :ref:`feature_updatemany`)
|
||||
would break on Postgresql and other RETURNING backends
|
||||
when using server-side version generation
|
||||
schemes, as the server side value is retrieved via RETURNING which
|
||||
is not supported with executemany.
|
||||
|
||||
.. change::
|
||||
:tags: feature, ext
|
||||
:versions: 1.1.0b1
|
||||
|
||||
@@ -643,7 +643,7 @@ def _emit_update_statements(base_mapper, uowtransaction,
|
||||
assert_singlerow = connection.dialect.supports_sane_rowcount
|
||||
assert_multirow = assert_singlerow and \
|
||||
connection.dialect.supports_sane_multi_rowcount
|
||||
allow_multirow = not needs_version_id or assert_multirow
|
||||
allow_multirow = assert_multirow and not needs_version_id
|
||||
|
||||
if hasvalue:
|
||||
for state, state_dict, params, mapper, \
|
||||
|
||||
@@ -112,6 +112,24 @@ class VersioningTest(fixtures.MappedTest):
|
||||
else:
|
||||
s1.commit()
|
||||
|
||||
def test_multiple_updates(self):
|
||||
Foo = self.classes.Foo
|
||||
|
||||
s1 = self._fixture()
|
||||
f1 = Foo(value='f1')
|
||||
f2 = Foo(value='f2')
|
||||
s1.add_all((f1, f2))
|
||||
s1.commit()
|
||||
|
||||
f1.value = 'f1rev2'
|
||||
f2.value = 'f2rev2'
|
||||
s1.commit()
|
||||
|
||||
eq_(
|
||||
s1.query(Foo.id, Foo.value, Foo.version_id).order_by(Foo.id).all(),
|
||||
[(f1.id, 'f1rev2', 2), (f2.id, 'f2rev2', 2)]
|
||||
)
|
||||
|
||||
@testing.emits_warning_on(
|
||||
'+zxjdbc', r'.*does not support (update|delete)d rowcount')
|
||||
def test_bump_version(self):
|
||||
@@ -952,6 +970,76 @@ class ServerVersioningTest(fixtures.MappedTest):
|
||||
)
|
||||
self.assert_sql_execution(testing.db, sess.flush, *statements)
|
||||
|
||||
def test_multi_update(self):
|
||||
sess = self._fixture()
|
||||
|
||||
f1 = self.classes.Foo(value='f1')
|
||||
f2 = self.classes.Foo(value='f2')
|
||||
f3 = self.classes.Foo(value='f3')
|
||||
sess.add_all([f1, f2, f3])
|
||||
sess.flush()
|
||||
|
||||
f1.value = 'f1a'
|
||||
f2.value = 'f2a'
|
||||
f3.value = 'f3a'
|
||||
|
||||
statements = [
|
||||
# note that the assertsql tests the rule against
|
||||
# "default" - on a "returning" backend, the statement
|
||||
# includes "RETURNING"
|
||||
CompiledSQL(
|
||||
"UPDATE version_table SET version_id=2, value=:value "
|
||||
"WHERE version_table.id = :version_table_id AND "
|
||||
"version_table.version_id = :version_table_version_id",
|
||||
lambda ctx: [
|
||||
{
|
||||
"version_table_id": 1,
|
||||
"version_table_version_id": 1, "value": "f1a"}]
|
||||
),
|
||||
CompiledSQL(
|
||||
"UPDATE version_table SET version_id=2, value=:value "
|
||||
"WHERE version_table.id = :version_table_id AND "
|
||||
"version_table.version_id = :version_table_version_id",
|
||||
lambda ctx: [
|
||||
{
|
||||
"version_table_id": 2,
|
||||
"version_table_version_id": 1, "value": "f2a"}]
|
||||
),
|
||||
CompiledSQL(
|
||||
"UPDATE version_table SET version_id=2, value=:value "
|
||||
"WHERE version_table.id = :version_table_id AND "
|
||||
"version_table.version_id = :version_table_version_id",
|
||||
lambda ctx: [
|
||||
{
|
||||
"version_table_id": 3,
|
||||
"version_table_version_id": 1, "value": "f3a"}]
|
||||
)
|
||||
]
|
||||
if not testing.db.dialect.implicit_returning:
|
||||
# DBs without implicit returning, we must immediately
|
||||
# SELECT for the new version id
|
||||
statements.extend([
|
||||
CompiledSQL(
|
||||
"SELECT version_table.version_id "
|
||||
"AS version_table_version_id "
|
||||
"FROM version_table WHERE version_table.id = :param_1",
|
||||
lambda ctx: [{"param_1": 1}]
|
||||
),
|
||||
CompiledSQL(
|
||||
"SELECT version_table.version_id "
|
||||
"AS version_table_version_id "
|
||||
"FROM version_table WHERE version_table.id = :param_1",
|
||||
lambda ctx: [{"param_1": 2}]
|
||||
),
|
||||
CompiledSQL(
|
||||
"SELECT version_table.version_id "
|
||||
"AS version_table_version_id "
|
||||
"FROM version_table WHERE version_table.id = :param_1",
|
||||
lambda ctx: [{"param_1": 3}]
|
||||
)
|
||||
])
|
||||
self.assert_sql_execution(testing.db, sess.flush, *statements)
|
||||
|
||||
def test_delete_col(self):
|
||||
sess = self._fixture()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user