Race conditions can happen at any time, not just when the system is under heavy load. You only need 2 requests to arrive at approximately the same time to trigger a race condition.
On Tue, Sep 3, 2013 at 12:49 PM, herzaso <herz...@gmail.com> wrote: > Another important thing - I don't think it's a race condition - the load on > the system isn't that high and users getting this error continue to get it > all the time > > > On Tuesday, September 3, 2013 2:47:26 PM UTC+3, herzaso wrote: >> >> I've added session.close in my get method just to see if it solves the >> issue and it doesn't! >> I'm so frustrated with this issue... not only do I feel helpless, I don't >> have any clue on how to get around it ... >> >> What if I make the change without the session? Would the session pick up >> the changes on its first query? >> >> On Monday, September 2, 2013 3:58:02 PM UTC+3, Simon King wrote: >>> >>> I'm no expert on isolation levels - I was just trying to help you >>> understand what the problem was :-) >>> >>> Fixing it really depends on how your application is supposed to work >>> in the face of concurrent requests. For this specific part of the >>> application, you probably want to be able to see the Foo object that >>> was created by the other transaction. Reducing the transaction >>> isolation is probably the easiest way to do that, but might have >>> knock-on effects in your application, so you ought to think carefully >>> before doing it. >>> >>> The alternative is to discard the existing session state when you get >>> into this situation (via session.close) and start a new transaction. >>> However, it wouldn't be appropriate to do this inside your "get" >>> method - "session lifecycle" operations like this really belong at an >>> outer scope, so making a change like this may require a certain amount >>> of restructuring. >>> >>> Basically, dealing with concurrent operations is hard, and SQLAlchemy >>> isn't going to magically make it any easier I'm afraid. >>> >>> Simon >>> >>> On Mon, Sep 2, 2013 at 1:40 PM, herzaso <her...@gmail.com> wrote: >>> > I'm sorry, it was a misunderstanding on my part regarding the >>> > transactions. >>> > So what are you saying? that I should replace the transaction isolation >>> > level? >>> > >>> > >>> > On Monday, September 2, 2013 3:29:25 PM UTC+3, Simon King wrote: >>> >> >>> >> What exactly do you mean by not using transactions? The Session always >>> >> works within a transaction: >>> >> >>> >> >>> >> >>> >> http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#managing-transactions >>> >> >>> >> I assume you are also using InnoDB tables. >>> >> >>> >> On Mon, Sep 2, 2013 at 1:19 PM, herzaso <her...@gmail.com> wrote: >>> >> > I do have it set as REPEATABLE READ. >>> >> > However, I don't use transactions in sqlalchemy >>> >> > >>> >> > >>> >> > On Monday, September 2, 2013 3:08:58 PM UTC+3, Simon King wrote: >>> >> >> >>> >> >> Do you know what transaction isolation level you are running at? >>> >> >> The >>> >> >> default apparently is "REPEATABLE READ": >>> >> >> >>> >> >> >>> >> >> >>> >> >> >>> >> >> http://dev.mysql.com/doc/refman/5.6/en/set-transaction.html#isolevel_repeatable-read >>> >> >> >>> >> >> The important sentence in that link is: >>> >> >> >>> >> >> All consistent reads within the same transaction read the >>> >> >> snapshot >>> >> >> established by the first read >>> >> >> >>> >> >> When you query the database for the first time, to see if the >>> >> >> entity >>> >> >> already exists, you are setting that initial snapshot. If you run >>> >> >> the >>> >> >> same query again (such as in your exception handler), you will get >>> >> >> the >>> >> >> same results, whether or not another connection has inserted a >>> >> >> matching row in the meantime. >>> >> >> >>> >> >> Simon >>> >> >> >>> >> >> On Mon, Sep 2, 2013 at 12:54 PM, herzaso <her...@gmail.com> wrote: >>> >> >> > I'm not sure what to make of the results: >>> >> >> > On the first connection, I ran BEGIN and INSERT and both were >>> >> >> > successful, >>> >> >> > but when I tried the INSERT statement on the second connection, I >>> >> >> > got >>> >> >> > "ERROR >>> >> >> > 1205 (HY000): Lock wait timeout exceeded; try restarting >>> >> >> > transaction". >>> >> >> > Running the same query on the first connection produced the >>> >> >> > required >>> >> >> > result >>> >> >> > which is "ERROR 1062 (23000): Duplicate entry" >>> >> >> > After the ROLLBACK on the first connection, the INSERT statement >>> >> >> > worked >>> >> >> > well >>> >> >> > on the second connection >>> >> >> > >>> >> >> > Regarding your second remark, the answer is yes, the error was >>> >> >> > due to >>> >> >> > the >>> >> >> > unique constraint on those columns >>> >> >> > >>> >> >> > BTW: I'm working on MySQL >>> >> >> > >>> >> >> > On Monday, September 2, 2013 1:31:12 PM UTC+3, Simon King wrote: >>> >> >> >> >>> >> >> >> I don't really know the answer, but I'd be interested in the >>> >> >> >> results >>> >> >> >> of this experiment: >>> >> >> >> >>> >> >> >> Forget about SQLAlchemy for the moment, and start 2 plain SQL >>> >> >> >> connections to your database. In the first, type something like >>> >> >> >> the >>> >> >> >> following: >>> >> >> >> >>> >> >> >> BEGIN; >>> >> >> >> INSERT foo(bar, baz, qux) VALUES(1, 1, 1); >>> >> >> >> >>> >> >> >> Now in the second connection do the same. I assume it'll fail >>> >> >> >> because >>> >> >> >> of the duplicate values. >>> >> >> >> >>> >> >> >> Now in the first connection issue a "ROLLBACK". You should now >>> >> >> >> be in >>> >> >> >> a >>> >> >> >> state where no matching row exists in the database, even though >>> >> >> >> you >>> >> >> >> received an error about constraint violations. >>> >> >> >> >>> >> >> >> The results you see may be different, depending on your >>> >> >> >> transaction >>> >> >> >> isolation level. (It may be that you don't get the constraint >>> >> >> >> violation at all until you try to commit the second connection). >>> >> >> >> >>> >> >> >> Another thing you could look at: are you sure that the error you >>> >> >> >> are >>> >> >> >> getting is due to the unique constraint on bar/baz/qux, and not >>> >> >> >> some >>> >> >> >> other constraint in the database? >>> >> >> >> >>> >> >> >> Simon >>> >> >> >> >>> >> >> >> On Mon, Sep 2, 2013 at 8:45 AM, herzaso <her...@gmail.com> >>> >> >> >> wrote: >>> >> >> >> > I'm afraid it didn't solve my problem. >>> >> >> >> > >>> >> >> >> > Here is my updated method: >>> >> >> >> > @classmethod >>> >> >> >> > def get(cls, bar=None, baz=None, qux=None, **kwargs): >>> >> >> >> > query = session.query(cls).\ >>> >> >> >> > filter(cls.bar == bar).\ >>> >> >> >> > filter(cls.baz == baz).\ >>> >> >> >> > filter(cls.qux == qux) >>> >> >> >> > >>> >> >> >> > item = query.first() >>> >> >> >> > updated = False >>> >> >> >> > >>> >> >> >> > if not item: >>> >> >> >> > try: >>> >> >> >> > with session.begin_nested(): # run inside a >>> >> >> >> > SAVEPOINT >>> >> >> >> > updated = True >>> >> >> >> > item = cls(bar=bar, baz=baz, qux=qux, >>> >> >> >> > **kwargs) >>> >> >> >> > session.add(item) >>> >> >> >> > session.flush() >>> >> >> >> > except sa.exc.IntegrityError: >>> >> >> >> > item = query.first() >>> >> >> >> > if not item: >>> >> >> >> > raise Exception("invalidIntegrityError") >>> >> >> >> > except: >>> >> >> >> > raise >>> >> >> >> > >>> >> >> >> > if not updated: >>> >> >> >> > for k, v in kwargs.iteritems(): >>> >> >> >> > if getattr(item, k) != v: >>> >> >> >> > setattr(item, k, v) >>> >> >> >> > >>> >> >> >> > return item >>> >> >> >> > >>> >> >> >> > With this code, i'm getting invalidIntegrityError. How is it >>> >> >> >> > possible? >>> >> >> >> > (it's also worth pointing out that this solution requires SA >>> >> >> >> > 0.8.2 >>> >> >> >> > (otherwise, there is a problem with session.begin_nested) >>> >> >> >> > >>> >> >> >> > >>> >> >> >> > On Tuesday, August 27, 2013 6:40:03 PM UTC+3, Michael Bayer >>> >> >> >> > wrote: >>> >> >> >> >> >>> >> >> >> >> I'm not a fan of catching integrity errors, i prefer to try >>> >> >> >> >> to >>> >> >> >> >> make >>> >> >> >> >> sure >>> >> >> >> >> they aren't going to happen, or if they are, they aren't a >>> >> >> >> >> normal >>> >> >> >> >> occurrence >>> >> >> >> >> and the system is such that the particular operation can just >>> >> >> >> >> fail >>> >> >> >> >> (of >>> >> >> >> >> course it depends on what it is). A problem with catching >>> >> >> >> >> the >>> >> >> >> >> integrity >>> >> >> >> >> error due to concurrent, conflicting operations is that >>> >> >> >> >> depending >>> >> >> >> >> on >>> >> >> >> >> backend >>> >> >> >> >> and isolation level, you can't be totally sure when the error >>> >> >> >> >> is >>> >> >> >> >> going >>> >> >> >> >> to >>> >> >> >> >> get raised (e.g. serializable isolation vs. non). Also on a >>> >> >> >> >> backend >>> >> >> >> >> like >>> >> >> >> >> Postgresql, the database can't recover the transaction after >>> >> >> >> >> an >>> >> >> >> >> integrity >>> >> >> >> >> error unless you used a savepoint. >>> >> >> >> >> >>> >> >> >> >> But here you're doing the "concurrent transactions need row >>> >> >> >> >> identity >>> >> >> >> >> X", >>> >> >> >> >> so maybe it is appropriate here. Here is a rough idea of a >>> >> >> >> >> transactional >>> >> >> >> >> pattern for that, noting this isn't tested: >>> >> >> >> >> >>> >> >> >> >> try: >>> >> >> >> >> my_object = Session.query(MyClass).filter(....).one() >>> >> >> >> >> except NoResultFound: >>> >> >> >> >> try: >>> >> >> >> >> with Session.begin_nested(): # run inside a >>> >> >> >> >> SAVEPOINT >>> >> >> >> >> my_object = MyClass(...) >>> >> >> >> >> Session.add(my_object) >>> >> >> >> >> Session.flush() >>> >> >> >> >> except IntegrityError: >>> >> >> >> >> my_object = Session.query(MyClass).filter(....).one() >>> >> >> >> >> >>> >> >> >> >> >>> >> >> >> >> >>> >> >> >> >> >>> >> >> >> >> >>> >> >> >> >> On Aug 27, 2013, at 11:13 AM, herzaso <her...@gmail.com> >>> >> >> >> >> wrote: >>> >> >> >> >> >>> >> >> >> >> Suppose we are looking at a race condition, do you also think >>> >> >> >> >> this >>> >> >> >> >> should >>> >> >> >> >> be handled by catching the IntegrityError? >>> >> >> >> >> If so, what should I do? only flush and do the operation >>> >> >> >> >> again? >>> >> >> >> >> >>> >> >> >> >> On Tuesday, August 27, 2013 5:42:23 PM UTC+3, Michael Bayer >>> >> >> >> >> wrote: >>> >> >> >> >>> >>> >> >> >> >>> the word "occasional" is very meaningful. It usually >>> >> >> >> >>> suggests >>> >> >> >> >>> race >>> >> >> >> >>> conditions. Then with the word "tornado", the baysean >>> >> >> >> >>> filters >>> >> >> >> >>> are >>> >> >> >> >>> strongly leaning towards "race condition" at that point :). >>> >> >> >> >>> >>> >> >> >> >>> if an error is occurring only under volume then you have to >>> >> >> >> >>> revisit >>> >> >> >> >>> where >>> >> >> >> >>> race conditions can occur. >>> >> >> >> >>> >>> >> >> >> >>> On Aug 27, 2013, at 10:32 AM, herzaso <her...@gmail.com> >>> >> >> >> >>> wrote: >>> >> >> >> >>> >>> >> >> >> >>> I'm running a Tornado server without redundancy (only one >>> >> >> >> >>> process, >>> >> >> >> >>> requests can arrive at the same time but will be handled one >>> >> >> >> >>> at >>> >> >> >> >>> a >>> >> >> >> >>> time) >>> >> >> >> >>> I do agree that for large volumes, catching the >>> >> >> >> >>> IntegrityError >>> >> >> >> >>> would >>> >> >> >> >>> be >>> >> >> >> >>> better, but currently I am handling a single request at a >>> >> >> >> >>> time >>> >> >> >> >>> and >>> >> >> >> >>> I >>> >> >> >> >>> want to >>> >> >> >> >>> fix this problem before I move on ... >>> >> >> >> >>> >>> >> >> >> >>> >>> >> >> >> >>> On Tuesday, August 27, 2013 5:24:07 PM UTC+3, Simon King >>> >> >> >> >>> wrote: >>> >> >> >> >>>> >>> >> >> >> >>>> On Tue, Aug 27, 2013 at 2:31 PM, herzaso <her...@gmail.com> >>> >> >> >> >>>> wrote: >>> >> >> >> >>>> > On Tuesday, August 27, 2013 3:55:50 PM UTC+3, Simon King >>> >> >> >> >>>> > wrote: >>> >> >> >> >>>> >> >>> >> >> >> >>>> >> On Tue, Aug 27, 2013 at 1:40 PM, herzaso >>> >> >> >> >>>> >> <her...@gmail.com> >>> >> >> >> >>>> >> wrote: >>> >> >> >> >>>> >> > I have a model with an ID column set as the primary >>> >> >> >> >>>> >> > key, >>> >> >> >> >>>> >> > though >>> >> >> >> >>>> >> > i'd >>> >> >> >> >>>> >> > like >>> >> >> >> >>>> >> > to >>> >> >> >> >>>> >> > be able to identify records by 3 other columns. >>> >> >> >> >>>> >> > For this situation, I've added a classmethod that will >>> >> >> >> >>>> >> > fetch >>> >> >> >> >>>> >> > the >>> >> >> >> >>>> >> > record >>> >> >> >> >>>> >> > if >>> >> >> >> >>>> >> > found or a new record if not. >>> >> >> >> >>>> >> > The problem i'm having is that every once in a while, >>> >> >> >> >>>> >> > I >>> >> >> >> >>>> >> > get >>> >> >> >> >>>> >> > IntegrityError >>> >> >> >> >>>> >> > trying to flush a change >>> >> >> >> >>>> >> > >>> >> >> >> >>>> >> > class Foo(Base): >>> >> >> >> >>>> >> > __table_args__ = (sa.UniqueConstraint('bar', >>> >> >> >> >>>> >> > 'baz', >>> >> >> >> >>>> >> > 'qux'),) >>> >> >> >> >>>> >> > >>> >> >> >> >>>> >> > id = sa.Column(Identifier, sa.Sequence('%s_id_seq' >>> >> >> >> >>>> >> > % >>> >> >> >> >>>> >> > __tablename__), >>> >> >> >> >>>> >> > nullable=False, primary_key=True) >>> >> >> >> >>>> >> > bar = sa.Column(sa.BigInteger) >>> >> >> >> >>>> >> > baz = sa.Column(sa.BigInteger) >>> >> >> >> >>>> >> > qux = sa.Column(sa.BigInteger) >>> >> >> >> >>>> >> > a1 = sa.Column(sa.BigInteger) >>> >> >> >> >>>> >> > a2 = sa.Column(sa.BigInteger) >>> >> >> >> >>>> >> > >>> >> >> >> >>>> >> > @classmethod >>> >> >> >> >>>> >> > def get(cls, bar=None, baz=None, qux=None, >>> >> >> >> >>>> >> > **kwargs): >>> >> >> >> >>>> >> > item = session.query(cls).\ >>> >> >> >> >>>> >> > filter(cls.bar== bar).\ >>> >> >> >> >>>> >> > filter(cls.baz == baz).\ >>> >> >> >> >>>> >> > filter(cls.qux == qux).\ >>> >> >> >> >>>> >> > first() >>> >> >> >> >>>> >> > >>> >> >> >> >>>> >> > if item: >>> >> >> >> >>>> >> > for k, v in kwargs.iteritems(): >>> >> >> >> >>>> >> > if getattr(item, k) != v: >>> >> >> >> >>>> >> > setattr(item, k, v) >>> >> >> >> >>>> >> > else: >>> >> >> >> >>>> >> > item = cls(bar=bar, baz=baz, qux=qux, >>> >> >> >> >>>> >> > **kwargs) >>> >> >> >> >>>> >> > >>> >> >> >> >>>> >> > return item >>> >> >> >> >>>> >> > >>> >> >> >> >>>> >> > This is the code I use to add/update records: >>> >> >> >> >>>> >> > >>> >> >> >> >>>> >> > foo = Foo.get(**item) >>> >> >> >> >>>> >> > session.merge(foo) >>> >> >> >> >>>> >> > >>> >> >> >> >>>> >> > I'm struggling with this problem for some time now, >>> >> >> >> >>>> >> > and >>> >> >> >> >>>> >> > would >>> >> >> >> >>>> >> > appreciate >>> >> >> >> >>>> >> > any >>> >> >> >> >>>> >> > help ... >>> >> >> >> >>>> >> > >>> >> >> >> >>>> >> >>> >> >> >> >>>> >> I'm not sure of the exact problem, but there are a >>> >> >> >> >>>> >> couple of >>> >> >> >> >>>> >> things >>> >> >> >> >>>> >> that you could investigate. >>> >> >> >> >>>> >> >>> >> >> >> >>>> >> Firstly, session.merge returns a copy of the object, >>> >> >> >> >>>> >> rather >>> >> >> >> >>>> >> than >>> >> >> >> >>>> >> adding the object that you supplied into the session. >>> >> >> >> >>>> >> See >>> >> >> >> >>>> >> >>> >> >> >> >>>> >> >>> >> >> >> >>>> >> http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#merging >>> >> >> >> >>>> >> for >>> >> >> >> >>>> >> details. >>> >> >> >> >>>> >> >>> >> >> >> >>>> >> Secondly, your "get" method sometimes returns objects >>> >> >> >> >>>> >> that >>> >> >> >> >>>> >> are >>> >> >> >> >>>> >> already >>> >> >> >> >>>> >> part of the session (if they were in the database), and >>> >> >> >> >>>> >> sometimes >>> >> >> >> >>>> >> objects that are not in the session. It would probably >>> >> >> >> >>>> >> be >>> >> >> >> >>>> >> more >>> >> >> >> >>>> >> consistent to always return objects that are part of the >>> >> >> >> >>>> >> session, >>> >> >> >> >>>> >> by >>> >> >> >> >>>> >> putting "session.add(item)" in your "else" clause. This >>> >> >> >> >>>> >> would >>> >> >> >> >>>> >> get >>> >> >> >> >>>> >> rid >>> >> >> >> >>>> >> of the need for session.merge(). (If you want to be able >>> >> >> >> >>>> >> to >>> >> >> >> >>>> >> use >>> >> >> >> >>>> >> the >>> >> >> >> >>>> >> "get" with non-global sessions, pass the session as a >>> >> >> >> >>>> >> parameter.) >>> >> >> >> >>>> >> >>> >> >> >> >>>> >> Finally, if your session isn't auto-flushing, it would >>> >> >> >> >>>> >> be >>> >> >> >> >>>> >> possible >>> >> >> >> >>>> >> for >>> >> >> >> >>>> >> you to call "get" twice with the same parameters and get >>> >> >> >> >>>> >> 2 >>> >> >> >> >>>> >> different >>> >> >> >> >>>> >> objects back. >>> >> >> >> >>>> >> >>> >> >> >> >>>> >> You may want to look at the UniqueObject recipe in the >>> >> >> >> >>>> >> wiki: >>> >> >> >> >>>> >> >>> >> >> >> >>>> >> >>> >> >> >> >>>> >> http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject >>> >> >> >> >>>> >> >>> >> >> >> >>>> > Hi Simon, >>> >> >> >> >>>> > Thanks for the fast reply. >>> >> >> >> >>>> > >>> >> >> >> >>>> > I tried adding session.add(item) and session.flush() in >>> >> >> >> >>>> > the >>> >> >> >> >>>> > else >>> >> >> >> >>>> > clause in >>> >> >> >> >>>> > the past but that didn't solve my problem. >>> >> >> >> >>>> > I didn't however remove the merge, do you think that >>> >> >> >> >>>> > might be >>> >> >> >> >>>> > the >>> >> >> >> >>>> > problem? >>> >> >> >> >>>> > >>> >> >> >> >>>> > Regarding the flush, this code is part of an API server >>> >> >> >> >>>> > where >>> >> >> >> >>>> > a >>> >> >> >> >>>> > scoped_session is committed after each change. I haven't >>> >> >> >> >>>> > changed >>> >> >> >> >>>> > the >>> >> >> >> >>>> > autoflush parameter, and as I understand the default >>> >> >> >> >>>> > value is >>> >> >> >> >>>> > True >>> >> >> >> >>>> > making a >>> >> >> >> >>>> > flush before each commit or query. >>> >> >> >> >>>> > >>> >> >> >> >>>> > As for the UniqueObject recipe, thanks! Amazing that I >>> >> >> >> >>>> > never >>> >> >> >> >>>> > found >>> >> >> >> >>>> > it >>> >> >> >> >>>> > searching for a cure. As I see it basically does the same >>> >> >> >> >>>> > ... >>> >> >> >> >>>> > >>> >> >> >> >>>> > I never managed to reproduce this bug on my development >>> >> >> >> >>>> > environment. >>> >> >> >> >>>> > It only >>> >> >> >> >>>> > happens in my production environment. >>> >> >> >> >>>> > Do you suppose adding a session.add and removing the >>> >> >> >> >>>> > merge >>> >> >> >> >>>> > will >>> >> >> >> >>>> > solve >>> >> >> >> >>>> > this >>> >> >> >> >>>> > issue? >>> >> >> >> >>>> > >>> >> >> >> >>>> > Thanks, >>> >> >> >> >>>> > Ofir >>> >> >> >> >>>> >>> >> >> >> >>>> It's difficult to say without knowing more about your >>> >> >> >> >>>> system. >>> >> >> >> >>>> For >>> >> >> >> >>>> example, does your production system get multiple >>> >> >> >> >>>> concurrent >>> >> >> >> >>>> API >>> >> >> >> >>>> requests, or are they serialised? If 2 requests can come in >>> >> >> >> >>>> at >>> >> >> >> >>>> approximately the same time and are handled by 2 different >>> >> >> >> >>>> threads >>> >> >> >> >>>> (or >>> >> >> >> >>>> processes), then it is easy to imagine that the first >>> >> >> >> >>>> handler >>> >> >> >> >>>> will >>> >> >> >> >>>> check the database, find that an entry doesn't exist, and >>> >> >> >> >>>> create >>> >> >> >> >>>> it. >>> >> >> >> >>>> But before it flushes the change to the database (or even >>> >> >> >> >>>> after >>> >> >> >> >>>> it >>> >> >> >> >>>> flushes, but before it commits, depending on your >>> >> >> >> >>>> transaction >>> >> >> >> >>>> isolation), the second handler will check for the same >>> >> >> >> >>>> object, >>> >> >> >> >>>> find >>> >> >> >> >>>> it >>> >> >> >> >>>> missing, and so create it. >>> >> >> >> >>>> >>> >> >> >> >>>> To track down problems like this, you could ensure that >>> >> >> >> >>>> your >>> >> >> >> >>>> development environment has the same thread/process >>> >> >> >> >>>> behaviour >>> >> >> >> >>>> as >>> >> >> >> >>>> the >>> >> >> >> >>>> production environment, then try submitting multiple >>> >> >> >> >>>> concurrent >>> >> >> >> >>>> requests to it. If you add "time.sleep" statements >>> >> >> >> >>>> somewhere >>> >> >> >> >>>> between >>> >> >> >> >>>> the creation of the object and the commit of the >>> >> >> >> >>>> transaction >>> >> >> >> >>>> you >>> >> >> >> >>>> will >>> >> >> >> >>>> probably find it easier to trigger. >>> >> >> >> >>>> >>> >> >> >> >>>> To actually fix the problem, you could choose to only >>> >> >> >> >>>> handle a >>> >> >> >> >>>> single >>> >> >> >> >>>> request at a time (fine if you don't expect a high volume >>> >> >> >> >>>> of >>> >> >> >> >>>> requests). If that's not acceptable, you could catch the >>> >> >> >> >>>> IntegrityError and then re-process the request. >>> >> >> >> >>>> >>> >> >> >> >>>> Hope that helps, >>> >> >> >> >>>> >>> >> >> >> >>>> Simon >>> >> >> >> >>> >>> >> > >>> >> > -- >>> >> > 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+...@googlegroups.com. >>> >> > To post to this group, send email to sqlal...@googlegroups.com. >>> >> > Visit this group at http://groups.google.com/group/sqlalchemy. >>> >> > For more options, visit https://groups.google.com/groups/opt_out. >>> > >>> > -- >>> > 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+...@googlegroups.com. >>> > To post to this group, send email to sqlal...@googlegroups.com. >>> > Visit this group at http://groups.google.com/group/sqlalchemy. >>> > For more options, visit https://groups.google.com/groups/opt_out. > > -- > 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/groups/opt_out. -- 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/groups/opt_out.