here is your patch:

diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 3e7372fac7..ec3c9790f2 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -595,6 +595,9 @@ class LazyLoader(AbstractRelationshipLoader,
util.MemoizedSlots):

         def visit_bindparam(bindparam):
             bindparam.unique = False
+        visitors.traverse(criterion, {}, {"bindparam": visit_bindparam})
+
+        def visit_bindparam(bindparam):
             if bindparam._identifying_key in bind_to_col:
                 params.append(
                     (


the "unique=False" flag is set before the bindparam() is ever cloned,
so the string key of the parameter stays constant.

On Tue, Feb 19, 2019 at 7:30 PM Mike Bayer <[email protected]> wrote:
>
> that was actually quite easy!
>
> https://github.com/sqlalchemy/sqlalchemy/issues/4507
>
> On Tue, Feb 19, 2019 at 7:18 PM Mike Bayer <[email protected]> wrote:
> >
> > this will be moving to a github issue, and also I will attempt to
> > create a proof of concept.
> >
> > Everything that happens inside of _memoized_attr__simple_lazy_clause
> > involves creating copies of things and the state of the loader
> > strategy is not modified until it's done.  There is one "unique=False"
> > flag set on existing bindparam objects, however if multiple threads
> > all did that at the same time, it doesn't change the outcome.    The
> > two elements of the tuple returned, "crtierion" and "params", need to
> > match, however these are returned as a tuple and that's what's
> > assigned; if two different threads both ran the method at the same
> > time, one would replace the other....but I guess the baked query is
> > getting the state of the earlier one cached in some way, but, I don't
> > see how the two generations are meaningfully different....but that's
> > where something would need to be failing.      Best option would be if
> > it's not a problem for this code to run concurrently, however we can
> > use the mapper._CONFIGURE_MUTEX for this, but there are probably a lot
> > of other places where this kind of thing can happen if the
> > introduction of baked + memoized attrs has this issue.
> >
> > On Tue, Feb 19, 2019 at 4:03 PM Krzysztof Sulejczak
> > <[email protected]> wrote:
> > >
> > > Hi,
> > >
> > > I'm maintaining a multi-threaded application which uses sqlalchemy to 
> > > access mysql db. Some time ago we decided to upgrade
> > > sqlalchemy version from 1.1.18 to 1.2.14 and since then we started 
> > > observing strange problems, the application started
> > > throwing IntegrityError in code like that:
> > >
> > > translation = item.translation  # translation is a relation
> > > if translation is None:
> > >     session.add(Translation(item=item))  # this throws error
> > >
> > > Strange thing was that these errors happened rather rarely, there were a 
> > > few hundred application processes running and only
> > > a few of them were throwing such errors. Restarting those processed made 
> > > the errors vanish.
> > > I started debugging faulty processes and noticed that sql query generated 
> > > looked like this:
> > >
> > > SELECT <truncated list of columns>
> > > FROM ebay_translations
> > > WHERE NULL = ebay_translations.item_id
> > >
> > > Further debugging led me to LazyLoader._emit_lazyload and BackedQuery 
> > > thingy where I believe problem lays:
> > > if a thread switch occurs inside _memoized_attr__simple_lazy_clause it 
> > > could happen that BindParameter keys and
> > > cached relation query will not match each other.
> > >
> > > Since that discovery I've been running the application with patched 
> > > version of sqlalchemy for two months now,
> > > IntegrityErrors are gone.
> > >
> > > Can you please take a look at this patch? Or maybe this issue is known 
> > > and there exists workaround for it although I searched
> > > the mailing list archive and found nothing.
> > >
> > > best regards
> > > Krzysztof Sulejczak
> > >
> > > --
> > > SQLAlchemy -
> > > The Python SQL Toolkit and Object Relational Mapper
> > >
> > > http://www.sqlalchemy.org/
> > >
> > > To post example code, please provide an MCVE: Minimal, Complete, and 
> > > Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> > > description.
> > > ---
> > > 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 [email protected].
> > > To post to this group, send email to [email protected].
> > > Visit this group at https://groups.google.com/group/sqlalchemy.
> > > For more options, visit https://groups.google.com/d/optout.

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to