Michael Bayer wrote:
The only way I could have the slightest idea whats going wrong would be to
run it (well, to see the output of the UOW dump also but thats never
enough)....and since I am short on time this week it would be massively
helpful if you could provide a complete working example of the problem,
since otherwise I have to resurrect such an example myself (or if anyone
else on the list thinks they have an idea.)
No worries, I've come up with a test that fails (attached). I also included a
very similar test that passes (this highlights one of the strange quirks of the
bug).
Note, this test only fails on a database that enforces referential integrity (i.e. not sqlite).
However, when running it on sqlite you can see that the "d" row is deleted before it's
parent "c" row, which should throw a referential integrity error.
This is a very strange bug. I believe it may even be intermittent. The test I
have attached seems to fail every single time on my machine, but when I added
doc strings to the tests they both passed...very odd. However, it is
encouraging to me that I was able to reproduce this bug at home since I
originally discovered it at work with a totally different setup. Let me know if
you need anything else.
~ Daniel
"""Test complex relationships"""
import testbase
import unittest, sys, datetime
db = testbase.db
from sqlalchemy import *
class RelationTest(testbase.PersistTest):
def setUpAll(self):
testbase.db.tables.clear()
global tbl_a
global tbl_b
global tbl_c
global tbl_d
tbl_a = Table("tbl_a", db,
Column("id", Integer, primary_key=True),
Column("name", String),
)
tbl_b = Table("tbl_b", db,
Column("id", Integer, primary_key=True),
Column("name", String),
)
tbl_c = Table("tbl_c", db,
Column("id", Integer, primary_key=True),
Column("tbl_a_id", Integer, ForeignKey("tbl_a.id"), nullable=False),
Column("name", String),
)
tbl_d = Table("tbl_d", db,
Column("id", Integer, primary_key=True),
Column("tbl_c_id", Integer, ForeignKey("tbl_c.id"), nullable=False),
Column("tbl_b_id", Integer, ForeignKey("tbl_b.id")),
Column("name", String),
)
def setUp(self):
tbl_a.create()
tbl_b.create()
tbl_c.create()
tbl_d.create()
objectstore.clear()
clear_mappers()
class A(object):
pass
class B(object):
pass
class C(object):
pass
class D(object):
pass
D.mapper = mapper(D, tbl_d)
C.mapper = mapper(C, tbl_c, properties=dict(
d_rows=relation(D, private=True, backref="c_row"),
))
B.mapper = mapper(B, tbl_b)
A.mapper = mapper(A, tbl_a, properties=dict(
c_rows=relation(C, private=True, backref="a_row"),
))
D.mapper.add_property("b_row", relation(B))
global a
global c
a = A(); a.name = "a1"
b = B(); b.name = "b1"
c = C(); c.name = "c1"; c.a_row = a
# we must have more than one d row or it won't fail
d = D(); d.name = "d1"; d.b_row = b; d.c_row = c
d = D(); d.name = "d2"; d.b_row = b; d.c_row = c
d = D(); d.name = "d3"; d.b_row = b; d.c_row = c
def tearDown(self):
tbl_d.drop()
tbl_c.drop()
tbl_b.drop()
tbl_a.drop()
def testDeleteRootTable(self):
session = objectstore.get_session()
session.commit()
session.delete(a) # works as expected
session.commit()
def testDeleteMiddleTable(self):
session = objectstore.get_session()
session.commit()
session.delete(c) # fails
session.commit()
if __name__ == "__main__":
testbase.main()