Skip to content

Connection state gets corrupted when an SQL error occurred in nested transactions. #2123

Description

@KeenS

Setup

Versions

  • Rust: rustc 1.36.0 (a53f9df32 2019-07-03)
  • Diesel: 1.4.2
  • Database: PostrgreSQL, psql (11.4 (Ubuntu 11.4-0ubuntu0.19.04.1), server 9.6.13)
  • Operating System Ubuntu 19.04

Feature Flags

  • diesel: "postgres"

Problem Description

When an SQL fails in nested transactions, the connection gets corrupted and all the other transaction running as SERIALIZABLE fails in AlreadyInTransaction.

What are you trying to accomplish?

Just writing an application. Transaction is nested in an accident

What is the expected output?

Ok(1)

What is the actual output?

Err(AlreadyInTransaction)

Are you seeing any additional errors?

postgresql output:

postgresql_1     | ERROR:  column "foo" does not exist at character 8
postgresql_1     | STATEMENT:  SELECT foo
postgresql_1     | ERROR:  current transaction is aborted, commands ignored until end of transaction block
postgresql_1     | STATEMENT:  RELEASE SAVEPOINT diesel_savepoint_1

Steps to reproduce

run code below

Cargo.toml

[package]
name = "diesel-bug-report"
version = "0.1.0"
edition = "2018"

[dependencies]
diesel = {version = "1.4.0", features = ["postgres"]}

src/main.rs

use diesel::pg::PgConnection;
use diesel::prelude::*;
use diesel::result::Error;

fn main() {
    let conn = PgConnection::establish("postgres://user:password@localhost/database").unwrap();
    // fail once
    let ret = conn.transaction(|| {
        conn.transaction(|| {
            // handling error
            match conn.execute("SELECT foo") {
                // do nothing
                Ok(_) => (),
                // ignore the error
                Err(e) => eprintln!("error occurred: {}", e),
            };
            Ok::<_, Error>(())
        })
    });
    println!("{:?}", ret);
    // other transaction
    let ret = conn
        .build_transaction()
        .serializable()
        .run(|| conn.execute("SELECT 1"));
    // must be Ok(1), but get Err(AlreadyInTransaction)
    println!("{:?}", ret);
}

Then, gets output

$ cargo run
error occurred: column "foo" does not exist
Err(DatabaseError(__Unknown, "current transaction is aborted, commands ignored until end of transaction block"))
Err(AlreadyInTransaction)

The error occurs with only when you use .build_transacion().
However, internally, the connection is unsound: TransactionManager's depth is 1 which should be 0 at that point.

Checklist

  • I have already looked over the issue tracker for similar issues.
  • This issue can be reproduced on Rust's stable channel. (Your issue will be
    closed if this is not the case)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions