sqlite icon indicating copy to clipboard operation
sqlite copied to clipboard

Introduce transaction and savepoint objects

Open duelafn opened this issue 3 years ago • 3 comments

Hello, would you be willing to include transaction and savepoints? The structures here will automatically rollback when dropped.

Thanks for the package and for considering this addition!

duelafn avatar Mar 04 '21 15:03 duelafn

Thank you for the pull request! I am not sure if this is needed, as it can be achieved via queries.

IvanUkhov avatar Mar 20 '21 12:03 IvanUkhov

Hello, thanks for considering.

I admit, it is not strictly necessary, but the logic for rollback gets ugly without something that does a rollback on Drop. In particular, using the ? shorthand pretty much needs something scope-protected.

Example:

fn do_something(connection: Connection) -> Result<(), Error> {
    let mut txn = connection.begin()?;
    connection.execute(...)?; // On Err(), ROLLBACK called automatically
    connection.execute(...)?;
    connection.execute(...)?;
    txn.commit()?;
}

Compared to some construction like one of these:

fn do_something(connection: Connection) -> Result<(), Error> {
    connection.execute("BEGIN")?;
    if let Ok(_) = connection.execute(...) {
        if let Ok(_) = connection.execute(...) {
            if let Ok(_) = connection.execute(...) {
                if let Ok(_) = connection.execute("COMMIT") {
                    return Ok(());
                }
            }
        }
    }
    connection.execute("ROLLBACK")?;
    return Err(...);
}

fn do_something(connection: Connection) -> Result<(), Error> {
    connection.execute("BEGIN")?;
    if let Err(e) = connection.execute(...) {
        connection.execute("ROLLBACK")?;
        return Err(...);
    }
    if let Err(e) = connection.execute(...) {
        connection.execute("ROLLBACK")?;
        return Err(...);
    }
    if let Err(e) = connection.execute(...) {
        connection.execute("ROLLBACK")?;
        return Err(...);
    }
    if let Err(e) = connection.execute("COMMIT") {
        connection.execute("ROLLBACK")?;
        return Err(...);
    }
    return Ok(());
}

fn do_something(connection: Connection) -> Result<(), Error> {
    connection.execute("BEGIN")?;
    let mut res = _really_do_something(connection);
    if res.is_ok() {
        res = connection.execute("COMMIT");
    }
    if res.is_err() {
        connection.execute("ROLLBACK")?;
        return res;
    }
    return Ok(());
}
fn _really_do_something(connection: Connection) -> Result<(), Error> {
    connection.execute(...)?;
    connection.execute(...)?;
    connection.execute(...)?;
}

duelafn avatar Mar 21 '21 16:03 duelafn

I do notice that I should have added more tests than just the documentation test. If this is something you'd like, I'm happy to write some tests for it.

duelafn avatar Mar 21 '21 16:03 duelafn

Thank you for the PR! I am closing this.

IvanUkhov avatar Oct 22 '22 12:10 IvanUkhov

This was not merged, right? What's the supported approach for handling transactions?

WhyNotHugo avatar Feb 09 '24 14:02 WhyNotHugo