2
0

Add pgx.Tx interface and pseudo nested transaction support

This complicates the idea of a persistent transaction status and error
so that concept was removed.
This commit is contained in:
Jack Christensen
2019-08-17 17:22:14 -05:00
parent 64b4414efc
commit 99e5461522
7 changed files with 267 additions and 143 deletions
+71 -52
View File
@@ -232,102 +232,121 @@ func TestBeginReadOnly(t *testing.T) {
}
}
func TestTxStatus(t *testing.T) {
func TestTxNestedTransactionCommit(t *testing.T) {
t.Parallel()
conn := mustConnectString(t, os.Getenv("PGX_TEST_DATABASE"))
defer closeConn(t, conn)
createSql := `
create temporary table foo(
id integer,
unique (id) initially deferred
);
`
if _, err := conn.Exec(context.Background(), createSql); err != nil {
t.Fatalf("Failed to create table: %v", err)
}
tx, err := conn.Begin(context.Background())
if err != nil {
t.Fatal(err)
}
if status := tx.Status(); status != pgx.TxStatusInProgress {
t.Fatalf("Expected status to be %v, but it was %v", pgx.TxStatusInProgress, status)
_, err = tx.Exec(context.Background(), "insert into foo(id) values (1)")
if err != nil {
t.Fatalf("tx.Exec failed: %v", err)
}
if err := tx.Rollback(context.Background()); err != nil {
nestedTx, err := tx.Begin(context.Background())
if err != nil {
t.Fatal(err)
}
if status := tx.Status(); status != pgx.TxStatusRollbackSuccess {
t.Fatalf("Expected status to be %v, but it was %v", pgx.TxStatusRollbackSuccess, status)
_, err = nestedTx.Exec(context.Background(), "insert into foo(id) values (2)")
if err != nil {
t.Fatalf("nestedTx.Exec failed: %v", err)
}
err = nestedTx.Commit(context.Background())
if err != nil {
t.Fatalf("nestedTx.Commit failed: %v", err)
}
err = tx.Commit(context.Background())
if err != nil {
t.Fatalf("tx.Commit failed: %v", err)
}
var n int64
err = conn.QueryRow(context.Background(), "select count(*) from foo").Scan(&n)
if err != nil {
t.Fatalf("QueryRow Scan failed: %v", err)
}
if n != 2 {
t.Fatalf("Did not receive correct number of rows: %v", n)
}
}
func TestTxStatusErrorInTransactions(t *testing.T) {
func TestTxNestedTransactionRollback(t *testing.T) {
t.Parallel()
conn := mustConnectString(t, os.Getenv("PGX_TEST_DATABASE"))
defer closeConn(t, conn)
createSql := `
create temporary table foo(
id integer,
unique (id) initially deferred
);
`
if _, err := conn.Exec(context.Background(), createSql); err != nil {
t.Fatalf("Failed to create table: %v", err)
}
tx, err := conn.Begin(context.Background())
if err != nil {
t.Fatal(err)
}
if status := tx.Status(); status != pgx.TxStatusInProgress {
t.Fatalf("Expected status to be %v, but it was %v", pgx.TxStatusInProgress, status)
_, err = tx.Exec(context.Background(), "insert into foo(id) values (1)")
if err != nil {
t.Fatalf("tx.Exec failed: %v", err)
}
_, err = tx.Exec(context.Background(), "savepoint s")
nestedTx, err := tx.Begin(context.Background())
if err != nil {
t.Fatal(err)
}
_, err = tx.Exec(context.Background(), "syntax error")
if err == nil {
t.Fatal("expected an error but did not get one")
}
if status := tx.Status(); status != pgx.TxStatusInFailure {
t.Fatalf("Expected status to be %v, but it was %v", pgx.TxStatusInFailure, status)
}
_, err = tx.Exec(context.Background(), "rollback to s")
_, err = nestedTx.Exec(context.Background(), "insert into foo(id) values (2)")
if err != nil {
t.Fatal(err)
t.Fatalf("nestedTx.Exec failed: %v", err)
}
if status := tx.Status(); status != pgx.TxStatusInProgress {
t.Fatalf("Expected status to be %v, but it was %v", pgx.TxStatusInProgress, status)
err = nestedTx.Rollback(context.Background())
if err != nil {
t.Fatalf("nestedTx.Rollback failed: %v", err)
}
if err := tx.Rollback(context.Background()); err != nil {
t.Fatal(err)
_, err = tx.Exec(context.Background(), "insert into foo(id) values (3)")
if err != nil {
t.Fatalf("tx.Exec failed: %v", err)
}
if status := tx.Status(); status != pgx.TxStatusRollbackSuccess {
t.Fatalf("Expected status to be %v, but it was %v", pgx.TxStatusRollbackSuccess, status)
}
}
func TestTxErr(t *testing.T) {
t.Parallel()
conn := mustConnectString(t, os.Getenv("PGX_TEST_DATABASE"))
defer closeConn(t, conn)
tx, err := conn.Begin(context.Background())
err = tx.Commit(context.Background())
if err != nil {
t.Fatal(err)
}
// Purposely break transaction
if _, err := tx.Exec(context.Background(), "syntax error"); err == nil {
t.Fatal("Unexpected success")
}
if err := tx.Commit(context.Background()); err != pgx.ErrTxCommitRollback {
t.Fatalf("Expected error %v, got %v", pgx.ErrTxCommitRollback, err)
t.Fatalf("tx.Commit failed: %v", err)
}
if status := tx.Status(); status != pgx.TxStatusCommitFailure {
t.Fatalf("Expected status to be %v, but it was %v", pgx.TxStatusRollbackSuccess, status)
var n int64
err = conn.QueryRow(context.Background(), "select count(*) from foo").Scan(&n)
if err != nil {
t.Fatalf("QueryRow Scan failed: %v", err)
}
if err := tx.Err(); err != pgx.ErrTxCommitRollback {
t.Fatalf("Expected error %v, got %v", pgx.ErrTxCommitRollback, err)
if n != 2 {
t.Fatalf("Did not receive correct number of rows: %v", n)
}
}