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.



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