Fork me on GitHub
#sql
<
2023-01-20
>
stopa21:01:39

Hey team Hey team, a bit of an noob question: Is there a way to return the last value, from a transaction I am executing with BEGIN and COMMIT? i.e:

(sql/execute! db/pool 
              ["BEGIN; 
                ...
                SELECT * FROM foo; 
                COMMIT;"])
I would love for the SELECT before COMMIT to be returned.

stopa21:01:42

Hmm…Looks like I either need to write a pg function, or re-express the transaction as a CTE https://stackoverflow.com/questions/12463846/get-values-from-returning-within-a-transaction

hiredman22:01:14

I would take several steps back

hiredman22:01:54

I believe your example up above would not be valid with most jdbc drivers

stopa22:01:35

Wow — why not?

hiredman22:01:37

what they take to execute is a single sql statement

hiredman22:01:58

something ending in ';'

hiredman22:01:22

and you don't need to include the ';' because they only execute a single statement at a time

stopa22:01:08

Ah, that’s interesting! I knew about jdbc/with-transaction, etc, but I didn’t know that I had to send one statement at a time.

hiredman22:01:25

begin/commit is for running transactions, which there are existing tools for like with-transaction

stopa22:01:37

I wanted to write it in one go, to avoid the following kind of bug: Clojure sends the request “BEGIN;” Some stuff happens, then clojure crashes Now, postgres would be hung up on this transaction, forever waiting on “COMMIT;”

hiredman22:01:15

I could be wrong, but I used to work with someone who wrote a migration library, and he wanted to express migrations as .sql files potentially containing multiple bits of sql, and he had a devil of a time splitting the sql in such a way as to be able to feed it to a jdbc driver

👍 2
hiredman22:01:08

I am not super familiar with postgres internals, but I believe if the client's connection dies that aborts any outstanding transactions for that connection

❤️ 2
stopa22:01:14

Okay, I think you may be right! Thank you @U0NCTKEV8. I’ll do some more research on transactions in jdbc

stopa22:01:32

Perhaps the best approach would be to create one giant CTE. At least this way there won’t be too many round trips

dpsutton22:01:19

we used that migration lib at previous job. and comments could throw off the whole thing when it no longer could figure out the boundaries between statements. migratus?

seancorfield23:01:46

@U0C5DE6RK Use with-transaction instead of trying to write your own in SQL 🙂

stopa00:01:04

Learned something new today, thanks team! So, my mental model right now: • postgres processes one statement at time • This means that for a transaction, there are multiple round trips. There’s a small chance that a gc pause or something could lock up the transaction for a bit. But crashes mean transactions are abandoned • Given this, if I can express a transaction as a CTE, it’s a better idea to do that, as it means one round trip. Does this sound right?

seancorfield00:01:39

It's up to the driver whether there actually are multiple round-trips or not -- and that's really not relevant in the real world.

seancorfield00:01:42

I mean, obviously you don't want a transaction to span a "long" period of time, but unless you have a pretty insane level of DB ops, a little GC pause is unlucky to have much impact.

❤️ 2
stopa00:01:25

Gotcha, makes sense! Thank you Sean.

seancorfield00:01:37

Like a lot of things, the "simple, obvious" approach will just work up to a fairly reasonable scale. It's better to do things the right/idiomatic way in general unless you have a very specific situation that needs a "hack".

❤️ 4
seancorfield00:01:34

You indicated that you hadn't encountered with-transaction before today(?) so I will ask: is there something I can improve in the next.jdbc docs that would have made that more visible or obvious @U0C5DE6RK?

stopa04:01:57

@U04V70XH6 I love the next.jdbc docs and have seen + used with-transaction before. Here my confusion was more about how sending statements to postgres worked. My mental model was something like: • with-transaction is great if I also want to access intermediate results inside clojure • But if I want to do a fast transaction, I should use begin commit in one string, as that only means one round trip Turns out the second bullet was mistaken, and it’s not appreciably faster.

seancorfield04:01:58

Ah, interesting. I have to be honest: that is not a line of thinking that would have occurred to me!😁

stopa14:01:46

😆 — sometimes I build a whole world in my head, and forget check if the setting for gravity was correct. Thanks for the help team.