summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2017-05-22 16:25:20 -0400
committerGerrit Code Review <gerrit@awstats.zzzcomputing.com>2017-05-22 16:25:20 -0400
commit92f789eba4a46a5c33c807c2f02c45b03cf9ee79 (patch)
treea316e2c64039f7d6fd40f827e7dcea4d18de2228
parent9f0fb6c601829cb7c9f449d57e12e8b95dab51f5 (diff)
parent0a67c1305266ba9c4558e371fa9b193788c65bea (diff)
downloadsqlalchemy-92f789eba4a46a5c33c807c2f02c45b03cf9ee79.tar.gz
Merge "Detect no params w/ manual version_id counter and set to itself"
-rw-r--r--doc/build/changelog/changelog_12.rst14
-rw-r--r--lib/sqlalchemy/orm/persistence.py7
-rw-r--r--test/orm/test_versioning.py62
3 files changed, 83 insertions, 0 deletions
diff --git a/doc/build/changelog/changelog_12.rst b/doc/build/changelog/changelog_12.rst
index a96436aaf..8cc8cd862 100644
--- a/doc/build/changelog/changelog_12.rst
+++ b/doc/build/changelog/changelog_12.rst
@@ -13,6 +13,20 @@
.. changelog::
:version: 1.2.0b1
+ .. change:: 3996
+ :tags: bug, orm
+ :tickets: 3996
+
+ Fixed bug where programmatic version_id counter in conjunction with
+ joined table inheritance would fail if the version_id counter
+ were not actually incremented and no other values on the base table
+ were modified, as the UPDATE would have an empty SET clause. Since
+ programmatic version_id where version counter is not incremented
+ is a documented use case, this specific condition is now detected
+ and the UPDATE now sets the version_id value to itself, so that
+ concurrency checks still take place.
+
+
.. change:: 3796
:tags: bug, orm
:tickets: 3796
diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py
index 588a1d696..86125d6f2 100644
--- a/lib/sqlalchemy/orm/persistence.py
+++ b/lib/sqlalchemy/orm/persistence.py
@@ -511,12 +511,19 @@ def _collect_update_commands(
continue
col = mapper.version_id_col
+ no_params = not params and not value_params
params[col._label] = update_version_id
if (bulk or col.key not in params) and \
mapper.version_id_generator is not False:
val = mapper.version_id_generator(update_version_id)
params[col.key] = val
+ elif mapper.version_id_generator is False and no_params:
+ # no version id generator, no values set on the table,
+ # and version id wasn't manually incremented.
+ # set version id to itself so we get an UPDATE
+ # statement
+ params[col.key] = update_version_id
elif not (params or value_params):
continue
diff --git a/test/orm/test_versioning.py b/test/orm/test_versioning.py
index 40b373097..4c339d3bb 100644
--- a/test/orm/test_versioning.py
+++ b/test/orm/test_versioning.py
@@ -1284,3 +1284,65 @@ class ManualVersionTest(fixtures.MappedTest):
sess.commit()
eq_(a1.vid, 2)
+
+
+class ManualInheritanceVersionTest(fixtures.MappedTest):
+ run_define_tables = 'each'
+ __backend__ = True
+
+ @classmethod
+ def define_tables(cls, metadata):
+ Table(
+ "a", metadata,
+ Column(
+ 'id', Integer, primary_key=True,
+ test_needs_autoincrement=True),
+ Column('data', String(30)),
+ Column('vid', Integer, nullable=False)
+ )
+
+ Table(
+ "b", metadata,
+ Column(
+ 'id', Integer, ForeignKey('a.id'), primary_key=True),
+ Column('b_data', String(30)),
+ )
+
+ @classmethod
+ def setup_classes(cls):
+ class A(cls.Basic):
+ pass
+
+ class B(A):
+ pass
+
+ @classmethod
+ def setup_mappers(cls):
+ mapper(
+ cls.classes.A, cls.tables.a, version_id_col=cls.tables.a.c.vid,
+ version_id_generator=False)
+
+ mapper(
+ cls.classes.B, cls.tables.b, inherits=cls.classes.A)
+
+ def test_no_increment(self):
+ sess = Session()
+ b1 = self.classes.B()
+
+ b1.vid = 1
+ b1.data = 'd1'
+ sess.add(b1)
+ sess.commit()
+
+ # change col on subtable only without
+ # incrementing version id
+ b1.b_data = 'bd2'
+ sess.commit()
+
+ eq_(b1.vid, 1)
+
+ b1.b_data = 'd3'
+ b1.vid = 2
+ sess.commit()
+
+ eq_(b1.vid, 2)