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()        

Reply via email to