On 11/24/2015 08:19 PM, Mike Bayer wrote:
> I've bisected it down and this one is going to be tough.
> https://bitbucket.org/zzzeek/sqlalchemy/issues/3593/eager-loading-single-inh-polymorphic-join
> is added.


I've figured out exactly where a simple thing was going wrong with this
and produced a good patch that is safe to commit.    Even though this
use case broke between 0.8.0 and 0.8.1, the new approach begun in 0.8.1
on forward removes most of the guessing from how the ORM joins things
together and this fix just closes up a loose end, whereas the use case
working in 0.8.0 and previously was because the old approach of guessing
how to join things just happened to make the right guess here.

I will try to add the necessary tests for this tomorrow so that it's
good for 1.0.10 at least, feel free to try the patch ahead of time to
confirm it resolves all your issues.




> 
> 
> 
> On 11/24/2015 07:20 PM, Mike Bayer wrote:
>>
>>
>> On 11/24/2015 07:16 PM, Christopher Lee wrote:
>>> The test passes for me in 0.8.0.  (Yes, we have 0.8.0 running in
>>> production, and are finally getting around to upgrading... sigh...)
>>
>>
>> agree.  and it then fails in 0.8.1, so this is something very immediate
>> and old in the 0.8 series  I'll start looking to see the actual
>> condition here.
>>
>>
>>
>>>
>>>
>>> On Tue, Nov 24, 2015 at 4:09 PM, Christopher Lee <c...@sirdodger.net
>>> <mailto:c...@sirdodger.net>> wrote:
>>>
>>>     I'll see if I can nail down the repro; I had to abstract some
>>>     production code that I am migrating between versions, and I may have
>>>     lost some important detail.
>>>
>>>     Looking at the SQL it generates before and after moving the "links"
>>>     relationship, it appears that it is outer joining against the wrong
>>>     target, which explains why the identity map is getting confused.
>>>      (e.g., it is joining against the innermost anon_1 subquery in the
>>>     bad case, and against the todo_elements_1 reference in the good
>>>     case, which is why the good case is forming a nice tree.)
>>>
>>>     On Tue, Nov 24, 2015 at 3:49 PM, Mike Bayer
>>>     <mike...@zzzcomputing.com <mailto:mike...@zzzcomputing.com>> wrote:
>>>
>>>
>>>
>>>         On 11/24/2015 06:14 PM, Christopher Lee wrote:
>>>         >
>>>         > I am having a problem with SQLAlchemy 1.0.9 that cropped up when I
>>>         > upgraded from 0.8.
>>>
>>>         this is a nicely written test but I get the same recursion overflow
>>>         error when I run it in 0.8, 0.9, and 1.0, even back in 0.8.3. 
>>>         Can you
>>>         provide a script that illustrates success in 0.8 and not in 1.0
>>>         ?  thanks.
>>>
>>>
>>>
>>>
>>>
>>>
>>>         >
>>>         > I have the following polymorphic relationship defined.  For
>>>         some reason,
>>>         > when I build a tree, and I try to access the children of the
>>>         middle node
>>>         > of the tree, it is picking up the wrong edge object and going
>>>         into a
>>>         > recursive loop.  (Querying for the children of n2 is picking
>>>         up the edge
>>>         > e12, instead of the edges e23, e24 and e25.)
>>>         >
>>>         > Looking at the identity map, it looks like the query isn't
>>>         populating
>>>         > the correct objects.
>>>         >
>>>         > If I move the "links" relationship from the NodesWithEdges
>>>         class to the
>>>         > base Node class, the query works fine.  Also, if I drop
>>>         join_depth or
>>>         > remove with with_polymorphic mapper arg, it forces multiple
>>>         queries, and
>>>         > the problem doesn't occur.  Is this a bug with the new
>>>         release, or am I
>>>         > doing something bad?
>>>         >
>>>         >
>>>         > from __future__ import print_function, unicode_literals
>>>         >
>>>         > import sqlalchemy as sa
>>>         > import sqlalchemy.orm
>>>         > import sqlalchemy.ext.associationproxy
>>>         > import sqlalchemy.ext.declarative
>>>         > import sqlalchemy.ext.orderinglist
>>>         >
>>>         > Base = sqlalchemy.ext.declarative.declarative_base()
>>>         >
>>>         >
>>>         > class Node(Base):
>>>         > __tablename__ = 'todo_elements'
>>>         >
>>>         > element_id = sa.Column(sa.Integer, nullable=False,
>>>         primary_key=True)
>>>         >     element_type = sa.Column(sa.String(20), nullable=False)
>>>         >
>>>         >     __mapper_args__ = {
>>>         >         'polymorphic_on': element_type,
>>>         > 'with_polymorphic': ('*', None),
>>>         > }
>>>         >
>>>         >
>>>         > class NodeWithEdges(Node):
>>>         > __mapper_args__ = {'polymorphic_identity': 'todo.list'}
>>>         >
>>>         >
>>>         > class LeafNode(Node):
>>>         > __mapper_args__ = {'polymorphic_identity': 'todo.item'}
>>>         >
>>>         >     my_flag = sa.Column(sa.Boolean, default=False)
>>>         >
>>>         >
>>>         > class Edge(Base):
>>>         > __tablename__ = 'todo_links'
>>>         > __table_args__ = (
>>>         >         sa.PrimaryKeyConstraint('parent_id', 'child_id'),
>>>         > sa.ForeignKeyConstraint(['parent_id'], [Node.element_id]),
>>>         > sa.ForeignKeyConstraint(['child_id'], [Node.element_id]),
>>>         > )
>>>         >
>>>         >     parent_id = sa.Column(sa.Integer, nullable=False)
>>>         >     child_id = sa.Column(sa.Integer, nullable=False)
>>>         >
>>>         >
>>>         > Edge.child = sa.orm.relationship(
>>>         >     Node,
>>>         > uselist=False,
>>>         > primaryjoin=Edge.child_id == Node.element_id,
>>>         > lazy=False,
>>>         > cascade='all',
>>>         > passive_updates=False,
>>>         > join_depth=8,
>>>         > )
>>>         >
>>>         >
>>>         > NodeWithEdges.links = sa.orm.relationship(
>>>         >     Edge,
>>>         > primaryjoin=NodeWithEdges.element_id == Edge.parent_id,
>>>         > lazy=False,
>>>         > cascade='all, delete-orphan',
>>>         > single_parent=True,
>>>         > passive_updates=False,
>>>         > join_depth=8,
>>>         > )
>>>         >
>>>         > NodeWithEdges.children =
>>>         sa.ext.associationproxy.association_proxy(
>>>         >     'links', 'child',
>>>         > creator=lambda child: Edge(child_id=child.element_id))
>>>         >
>>>         >
>>>         >
>>>         > engine = sa.create_engine('sqlite:///:memory:', echo=True)
>>>         > Base.metadata.create_all(engine)
>>>         >
>>>         > Session = sa.orm.sessionmaker(bind=engine)
>>>         > session = Session()
>>>         >
>>>         >
>>>         > #
>>>         > # 1 --> 2 --> 3
>>>         > # --> 4
>>>         > # --> 5
>>>         > #
>>>         >
>>>         > n1 = NodeWithEdges(element_id=1)
>>>         > n2 = NodeWithEdges(element_id=2)
>>>         > n3 = LeafNode(element_id=3)
>>>         > n4 = LeafNode(element_id=4, my_flag=True)
>>>         > n5 = LeafNode(element_id=5)
>>>         >
>>>         > e12 = Edge(parent_id=n1.element_id, child_id=n2.element_id)
>>>         > e23 = Edge(parent_id=n2.element_id, child_id=n3.element_id)
>>>         > e24 = Edge(parent_id=n2.element_id, child_id=n4.element_id)
>>>         > e25 = Edge(parent_id=n2.element_id, child_id=n5.element_id)
>>>         >
>>>         > session.add_all([n1, n2, n3, n4, n5, e12, e23, e24, e25])
>>>         > session.commit()
>>>         > session.expunge_all()
>>>         >
>>>         > new_n1 =
>>>         
>>> session.query(NodeWithEdges).filter(NodeWithEdges.element_id==1).first()
>>>         > print(session.identity_map.keys())
>>>         >
>>>         >
>>>         > def traverse(node, f, depth=0):
>>>         > f(node, depth)
>>>         >     if hasattr(node, 'children'):
>>>         > for c in node.children:
>>>         > traverse(c, f, depth + 1)
>>>         >
>>>         > def indent_print(node, depth):
>>>         > print(' ' * depth + str(node.element_id))
>>>         >     if hasattr(node, 'my_flag'):
>>>         > print(node.my_flag)
>>>         >
>>>         > traverse(new_n1, indent_print)
>>>         >
>>>         > --
>>>         > You received this message because you are subscribed to the Google
>>>         > Groups "sqlalchemy" group.
>>>         > To unsubscribe from this group and stop receiving emails from it, 
>>> send
>>>         > an email to sqlalchemy+unsubscr...@googlegroups.com
>>>         <mailto:sqlalchemy%2bunsubscr...@googlegroups.com>
>>>         > <mailto:sqlalchemy+unsubscr...@googlegroups.com
>>>         <mailto:sqlalchemy%2bunsubscr...@googlegroups.com>>.
>>>         > To post to this group, send email to sqlalchemy@googlegroups.com 
>>> <mailto:sqlalchemy@googlegroups.com>
>>>         > <mailto:sqlalchemy@googlegroups.com 
>>> <mailto:sqlalchemy@googlegroups.com>>.
>>>         > Visit this group at http://groups.google.com/group/sqlalchemy.
>>>         > For more options, visit https://groups.google.com/d/optout.
>>>
>>>         --
>>>         You received this message because you are subscribed to the
>>>         Google Groups "sqlalchemy" group.
>>>         To unsubscribe from this group and stop receiving emails from
>>>         it, send an email to sqlalchemy+unsubscr...@googlegroups.com
>>>         <mailto:sqlalchemy%2bunsubscr...@googlegroups.com>.
>>>         To post to this group, send email to sqlalchemy@googlegroups.com
>>>         <mailto:sqlalchemy@googlegroups.com>.
>>>         Visit this group at http://groups.google.com/group/sqlalchemy.
>>>         For more options, visit https://groups.google.com/d/optout.
>>>
>>>
>>>
>>> -- 
>>> You received this message because you are subscribed to the Google
>>> Groups "sqlalchemy" group.
>>> To unsubscribe from this group and stop receiving emails from it, send
>>> an email to sqlalchemy+unsubscr...@googlegroups.com
>>> <mailto:sqlalchemy+unsubscr...@googlegroups.com>.
>>> To post to this group, send email to sqlalchemy@googlegroups.com
>>> <mailto:sqlalchemy@googlegroups.com>.
>>> Visit this group at http://groups.google.com/group/sqlalchemy.
>>> For more options, visit https://groups.google.com/d/optout.
>>
> 

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to