Repository: diesel-rs/diesel
File: diesel/src/connection/transaction_manager.rs (Rust)

Code before:

        let rollback_sql = match transaction_state.in_transaction {
            Some(ref mut in_transaction) => match in_transaction.transaction_depth.get() {
                1 => Cow::Borrowed("ROLLBACK"),
                depth_gt1 => Cow::Owned(format!(
                    "ROLLBACK TO SAVEPOINT diesel_savepoint_{}",
                    depth_gt1 - 1
                )),
            },
            None => return Err(Error::NotInTransaction),
        };

        match conn.batch_execute(&rollback_sql) {
            Ok(()) => {
                let tm_status = &mut Self::get_transaction_state(conn)?;
                if let ValidTransactionManagerStatus {
                    in_transaction:
                        Some(InTransactionStatus {
                            ref mut top_level_transaction_requires_rollback,
                            ..
                        }),
                } = tm_status
                {
                    // rolling back the save point did work, even if the connection
                    // was marked to require a top level rollback. This likely means that
                    // we recovered the transaction state and we are able to perform
                    // normal operations from now on. Therefore we remove the
                    // `top_level_transaction_requires_rollback` flag.
                    if *top_level_transaction_requires_rollback {
                        *top_level_transaction_requires_rollback = false;
                    }
                }
                tm_status.change_transaction_depth(TransactionDepthChange::DecreaseDepth)?;
                Ok(())
            }
            Err(rollback_error) => {
                let tm_status = Self::transaction_manager_status_mut(conn);
                match tm_status {
                    TransactionManagerStatus::Valid(ValidTransactionManagerStatus {
                        in_transaction:
                            Some(InTransactionStatus {
                                transaction_depth,
                                top_level_transaction_requires_rollback,
                                ..
                            }),
                    }) if transaction_depth.get() > 1 => {
                        // A savepoint failed to rollback - we may still attempt to repair
                        // the connection by rolling back top-level transaction.
                        *transaction_depth = NonZeroU32::new(transaction_depth.get() - 1)
                            .expect("Depth was checked to be > 1");
                        if *top_level_transaction_requires_rollback {

Review comment (suggestion):
So I've tested this (on pg) and actually it seems to not be true :(

Conn1:
```sql
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
SELECT * FROM users;
INSERT INTO users(name) VALUES ('u1');
SAVEPOINT sp1;
```

Conn2:
```sql
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
SELECT * FROM users;
INSERT INTO users(name) VALUES ('u2');
COMMIT;
```

Conn1:
```sql
SELECT * FROM users; -- errors
ROLLBACK TO SAVEPOINT sp1; -- succeeds
SELECT * FROM users; -- still errors
```

Code after:
                        false,
                    ),
                },
                in_transaction.requires_rollback_maybe_up_to_top_level,
            ),
            None => return Err(Error::NotInTransaction),
        };

        match conn.batch_execute(&rollback_sql) {
            Ok(()) => {
                match Self::get_transaction_state(conn)?
                    .change_transaction_depth(TransactionDepthChange::DecreaseDepth)
                {
                    Ok(()) => {}
                    Err(Error::NotInTransaction) if rolling_back_top_level => {
                        // Transaction exit may have already been detected by connection
                        // implementation. It's fine.
                    }
                    Err(e) => return Err(e),
                }
                Ok(())
            }
            Err(rollback_error) => {
                let tm_status = Self::transaction_manager_status_mut(conn);
                match tm_status {
                    TransactionManagerStatus::Valid(ValidTransactionManagerStatus {
                        in_transaction:
                            Some(InTransactionStatus {
                                transaction_depth,
                                requires_rollback_maybe_up_to_top_level,
                                ..
                            }),
                    }) if transaction_depth.get() > 1 => {
                        // A savepoint failed to rollback - we may still attempt to repair
                        // the connection by rolling back higher levels.

                        // To make it easier on the user (that they don't have to really
                        // look at actual transaction depth and can just rely on the number
                        // of times they have called begin/commit/rollback) we still
                        // decrement here:
                        *transaction_depth = NonZeroU32::new(transaction_depth.get() - 1)
                            .expect("Depth was checked to be > 1");
                        *requires_rollback_maybe_up_to_top_level = true;
                        if requires_rollback_maybe_up_to_top_level_before_execute {
                            // In that case, we tolerate that savepoint releases fail
                            // -> we should ignore errors
                            return Ok(());
                        }
                    }
                    TransactionManagerStatus::Valid(ValidTransactionManagerStatus {
                        in_transaction: None,