How to do transactions, especially nested hga@xxxxxx (18 Sep 2019 01:22 UTC)
Re: How to do transactions, especially nested Peter Bex (18 Sep 2019 06:05 UTC)
Re: How to do transactions, especially nested Lassi Kortela (18 Sep 2019 07:41 UTC)
Re: How to do transactions, especially nested Peter Bex (18 Sep 2019 07:58 UTC)
Re: How to do transactions, especially nested Lassi Kortela (18 Sep 2019 08:26 UTC)
Re: How to do transactions, especially nested Alaric Snell-Pym (18 Sep 2019 10:27 UTC)
Re: How to do transactions, especially nested Alaric Snell-Pym (18 Sep 2019 10:26 UTC)
Re: How to do transactions, especially nested hga@xxxxxx (18 Sep 2019 15:54 UTC)

Re: How to do transactions, especially nested hga@xxxxxx 18 Sep 2019 15:54 UTC

> From: Peter Bex <xxxxxx@more-magic.net>
> Date: Wednesday, September 18, 2019 1:05 AM
>
> On Tue, Sep 17, 2019 at 08:21:52PM -0500, xxxxxx@ancell-ent.com wrote:
>
>>> [...]
>>
>> So you'd do it like http://wiki.call-cc.org/eggref/5/postgresql
>
> Right, that's one part of the API I like a lot.
>
>>> (with-transaction CONN THUNK [isolation: LEVEL] [access: MODE])
>>>
>>> Execute THUNK within a BEGIN TRANSACTION block, and return the value
>>> of thunk.
>>>
>>> The transaction is committed if thunk returns a true value. If an
>>> exception occurs during thunk, or thunk returns #f, or the commit
>>> fails, the transaction will be rolled back. If this rollback fails,
>>> that is a critical error and you should likely abort.
>>>
>>> Nested applications of with-transaction are supported -- only those
>>> statements executed within THUNK are committed or rolled back by any
>>> with-transaction call, as you would expect.
>>
>> Without looking at any code, what are the mechanics of rolling back
>> an inner savepoint?  Do you execute a bare statement (ugly) and then
>> return non-#f from the inner with-transaction's thunk?
>
> I don't understand what you mean by "do you execute a bare statement".

I meant something like (execute db "ROLLBACK TO SAVEPOINT savepoint_name").

> Usually you'll only want to roll back when an exception occurs.  If you
> want to explicitly roll back, you can just return #f from the thunk which
> should be rolled back.  e.g.,
>
> (with-transaction db
>   (lambda ()
>     (query db "INSERT INTO foo (bar, qux) VALUES (1, 2)")
>
>     (with-transaction
>       (lambda ()
>         (query db "INSERT INTO foo (bar, qux) VALUES (3, 4)")
>         ;; Oops, decide to roll this back
>         #f))
>
>     (query db "INSERT INTO foo (bar, qux) VALUES (5, 6)")))
>
> When this returns, foo will contain the tuples 1,2 and 5,6.

This satisfies my concern about excessive ugliness; I should have
trying writing out code before complaining.  While the following
syntactic sugar suggested by Alric would make it prettier:

> (with-transaction BODY...) ==> (call-with-transaction (lambda () BODY...))

It's not worth it.

>> [...]
>>
>> A further argument is that if my above partly aesthetic claim is
>> correct, the ugly ceremony required will to an extent discourage the
>> use of transactions, which would be bad....
>
> I don't see this is very different from with-input-from-port (which
> I consider super-Schemely because it's in the standard), or in my
> http-client library with-input-from-request.  Maybe our personal
> styles of how we write Scheme just differ?

with-input-from-port involves a mode change, where the code in the thunk
is going do something fundamentally different while taking input from
the supplied port.  The individual statements inside a transaction don't
really know they're inside one, it's automagically handled with the
connection handle ("db").  The user only has to do special stuff if he
wants to do an explicit rollback, and that's outside of the normal
statements.  Although as subsequently discussed, how to do a rollback is
problematic, return value vs. exception.

> Let's please avoid macros unless absolutely necessary!  Macros don't
> compose, but procedures do.

Agreed.

- Harold