SQLite User Forum

Enhancement Idea: Rollback And Release Savepoint
Login

Enhancement Idea: Rollback And Release Savepoint

(1) By SeverKetor on 2022-02-25 02:40:51 [link] [source]

This would be a minor change, but I think would be a small quality of life improvement: add an alternate form of ROLLBACK that essentially does ROLLBACK TO SavePointName; RELEASE SavePointName;

I added some code that manages its own savepoint which also has no awareness of what's going on above it transaction-wise. I was temporarily confused when ROLLBACK TO still left me in a transaction when the function had started outside of one. Of course, had I read the docs more carefully, I would have known ROLLBACK TO leaves you in the savepoint. I propose adding ROLLBACK AND RELEASE (or some other phrasing, maybe ROLLBACK BEFORE, ROLLBACK PAST, or something?) which would exit that savepoint for two reasons: it removes one extra statement that needs to be done (by no means a big deal to have to put up with though), and since it would be in the railroad diagram it would likely help new and/or oblivious devs find the correct way to rollback a savepoint entirely.

It's not extremely helpful, but if it's simple enough, maybe it would be worth doing.

(2) By Ryan Smith (cuz) on 2022-02-25 08:47:39 in reply to 1 [link] [source]

There are typically Three types of scenarios when using transactions:

  • 1 - You start a transaction, it completes, you commit it.
  • 2 - You start a transaction, it fails at some point, you roll it back.
  • 3 - You start a transaction, checkpoint as you go with the option to roll back to a previous point in order to redo the last section, and then commit or rollback all if need be.

Note that 3 is only worth doing if:

  • The process of building the transaction is processing intensive and takes a lot of time so that redoing everything is tangibly worse than redoing a section.
  • You expect (or assign high likelihood to) failure of the transaction, or specific section(s) thereof.

You are asking, unless I am misunderstanding, for a way to roll back to a savepoint, and then also rollback the entire transaction? This is already possible by just doing one single ROLLBACK. No mess, no fuss.

If your suggestion is to roll back to a savepoint and then commit, well that's the worst transaction design in history, so I'm just waving that past as implausible.

If finally your suggestion is to roll back to another savepoint prior to the last one, that's also already possible by naming your savepoints and rolling back to a specific named one.

So I'm not 100% sure what you are suggesting and maybe hoping you just did not know about some of the above. To that end, see sqlite.org/lang_savepoint.html for the full detail.

(3) By SeverKetor on 2022-02-25 10:48:27 in reply to 2 [link] [source]

"If finally your suggestion is to roll back to another savepoint prior to the last one" It was this one.

The reason why rolling back to a specific savepoint doesn't work is I want the function I wrote to clean up after itself automatically. The simplest way to me is to have it start its own savepoint and release it before its done (possibly with a rollback to it prior to the release), rather than having to save the most recent savepoint name and then provide it to the function whenever it's called. The changes to which SQL statements would be done is mostly trivial (1 statement versus 2), but it's more hand-holdy.

(4) By Ryan Smith (cuz) on 2022-02-25 11:11:45 in reply to 3 [source]

This confuses me even more.

It seems the thing you ask is to have a process which can start it's own part of the transaction (by starting with a savepoint) and then "clean up after itself" by being able to roll back to that point - which is already 100% how it works without the need for naming anything.

If however you say you want to roll back to a point prior to the last savepoint, well, that contradicts your statement that you want a specific process to clean up after itself... if a process rolls back stuff it DID NOT MAKE, you are by definition cleaning up after ANOTHER process that made it, and not "itself".

To try illustrate it:

Transaction Starts
Some initialization SQL perhaps

Process 1 creates Savepoint A, starts doing its bit.
Process 1 finishes its bit and can, if it so chooses, roll back to A

Process 2 creates Savepoint B, starts doing its bit.
Process 2 finishes its bit and can, if it so chooses, roll back to B

Process 3 creates Savepoint C, starts doing its bit.
Process 3 finishes its bit and can, if it so chooses, roll back to C

Process 4 ... rinse and repeat.

Transaction commits or rolls back

Now, process 3 can easily clean up after itself by rolling back to the last savepoint (C), but if process 3 ever wants to roll back to savepoint B, then it technically kills its own doings plus process 2's doings AFTER process 2 already decided NOT to undo what it did.
In what universe would that be the sane choice?

(5) By SeverKetor on 2022-02-25 11:28:37 in reply to 4 [link] [source]

You're misunderstanding. If Process 2 decides to rollback, you end up keeping Savepoint B around. Now, after the "Wait, I'm dumb" moment I just had, this is only an issue in an edge case I walked into last night. If the code can happen both in an existing transaction or in one started by the savepoint it creates (depending on where that function happens to get called in the application logic), then it means it either works just fine or, in the latter case, it leaves an open transaction with no changes unless you release the savepoint or rollback entirely. I was kind of fixated on that last bit because I ran into it by mistake, and managed to get myself thinking it was a more general problem.

(6) By David Raymond (dvdraymond) on 2022-02-25 13:33:08 in reply to 1 [link] [source]

I had a similar learning experience a while back, yeah. I forget the exact symptom, (probably just slowness) but it turned out it was because I was building up hundreds to thousands of savepoints in my transaction because I was just rolling back, thinking that removed the savepoint.

My brain had it as:

savepoint
try to do stuff
if failed: rollback
if succeeded: release

when it should be:

savepoint
try to do stuff
if failed: rollback
in all cases: release

It's perfectly well documented, but alas I either read it wrong, or just assumed.