where one is to be deleted from ON DELETE CASCADE succeeds; the check here makes that fail.
We will need to add an option to enable/disable this check per mapping, will likely
do this in next version
Fixed ORM bug where changing the primary key of an object, then marking
it for DELETE would fail to target the correct row for DELETE.
- Then to compound matters, basic "number of rows matched" checks were
- not being performed. Both issues are fixed, however note that the
- "rows matched" check requires so-called "sane multi-row count"
- functionality; the DBAPI's executemany() method must count up the
- rows matched by individual statements and SQLAlchemy's dialect must
- mark this feature as supported, currently applies to some mysql dialects,
- psycopg2, sqlite only.
+ Note that we cannot currently check "number of rows matched" in general
+ for DELETE statements as we can't be sure that a self-referential
+ ON DELETE CASCADE has gotten there first.
.. change::
:tags: feature, postgresql
rows_matched = -1
if connection.dialect.supports_sane_multi_rowcount:
c = connection.execute(statement, del_objects)
- rows_matched = c.rowcount
+
+ # only do a row check if we have versioning turned on.
+ # unfortunately, we *cannot* do a check on the number of
+ # rows matched here in general, as there is the edge case
+ # of a table that has a self-referential foreign key with
+ # ON DELETE CASCADE on it, see #2403. I'm not sure how we can
+ # resolve this, unless we require special configuration
+ # to enable "count rows" for certain mappings, or to disable
+ # it, or to based on it relationship(), not sure.
+ if need_version_id:
+ rows_matched = c.rowcount
+
elif need_version_id:
if connection.dialect.supports_sane_rowcount:
rows_matched = 0
A = self.classes.A
session = Session(testing.db)
- a1, a2 = A(id=1),A(id=2, parent_id=1)
+ a1, a2 = A(id=1), A(id=2, parent_id=1)
session.add_all([a1, a2])
session.flush()
sess.delete(p1)
sess.delete(p2)
- assert_raises_message(
- orm_exc.StaleDataError,
- "DELETE statement on table 'parent' expected to "
- "delete 2 row\(s\); 0 were matched.",
- sess.flush
- )
+ sess.flush()
+
+ # see issue #2403 - we *cannot* use rowcount here, as
+ # self-referential DELETE CASCADE could have deleted rows
+ #assert_raises_message(
+ # orm_exc.StaleDataError,
+ # "DELETE statement on table 'parent' expected to "
+ # "delete 2 row\(s\); 0 were matched.",
+ # sess.flush
+ #)
class BatchInsertsTest(fixtures.MappedTest, testing.AssertsExecutionResults):