From d97da661d43aa07ef3f9a341dbefc6b48dcacfec Mon Sep 17 00:00:00 2001 From: ajose Date: Mon, 23 Sep 2019 10:49:08 -0700 Subject: [PATCH] Transaction tests --- connection.go | 28 +++++---- driver_go18_test.go | 1 + driver_test.go | 99 ++++++++++++++---------------- rows.go | 1 + statement.go | 3 + transaction.go | 13 +++- transaction_test.go | 144 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 220 insertions(+), 69 deletions(-) diff --git a/connection.go b/connection.go index 72d2ea89..73894c68 100644 --- a/connection.go +++ b/connection.go @@ -44,7 +44,7 @@ type firebirdsqlConn struct { } func (fc *firebirdsqlConn) begin(isolationLevel int) (driver.Tx, error) { - tx, err := newFirebirdsqlTx(fc, isolationLevel, false) + tx, err := newFirebirdsqlTx(fc, isolationLevel, false, true) fc.tx = tx return driver.Tx(tx), err } @@ -65,6 +65,13 @@ func (fc *firebirdsqlConn) Close() (err error) { } func (fc *firebirdsqlConn) prepare(ctx context.Context, query string) (driver.Stmt, error) { + if fc.tx.needBegin { + err := fc.tx.begin() + if err != nil { + return nil, err + } + } + return newFirebirdsqlStmt(fc, query) } @@ -74,13 +81,6 @@ func (fc *firebirdsqlConn) Prepare(query string) (driver.Stmt, error) { func (fc *firebirdsqlConn) exec(ctx context.Context, query string, args []driver.Value) (result driver.Result, err error) { - if fc.tx.needBegin { - err = fc.tx.begin() - if err != nil { - return - } - } - stmt, err := fc.prepare(ctx, query) if err != nil { return @@ -90,10 +90,13 @@ func (fc *firebirdsqlConn) exec(ctx context.Context, query string, args []driver if err != nil { return } + + stmt.Close() + if fc.isAutocommit && fc.tx.isAutocommit { - fc.tx.commitRetainging() + fc.tx.Commit() } - stmt.Close() + return } @@ -102,6 +105,7 @@ func (fc *firebirdsqlConn) Exec(query string, args []driver.Value) (result drive } func (fc *firebirdsqlConn) query(ctx context.Context, query string, args []driver.Value) (rows driver.Rows, err error) { + stmt, err := fc.prepare(ctx, query) if err != nil { return @@ -146,7 +150,7 @@ func newFirebirdsqlConn(dsn string) (fc *firebirdsqlConn, err error) { fc.password = password fc.columnNameToLower = column_name_to_lower fc.isAutocommit = true - fc.tx, err = newFirebirdsqlTx(fc, ISOLATION_LEVEL_READ_COMMITED, fc.isAutocommit) + fc.tx, err = newFirebirdsqlTx(fc, ISOLATION_LEVEL_READ_COMMITED, fc.isAutocommit, false) fc.clientPublic = clientPublic fc.clientSecret = clientSecret @@ -187,7 +191,7 @@ func createFirebirdsqlConn(dsn string) (fc *firebirdsqlConn, err error) { fc.password = password fc.columnNameToLower = column_name_to_lower fc.isAutocommit = true - fc.tx, err = newFirebirdsqlTx(fc, ISOLATION_LEVEL_READ_COMMITED, fc.isAutocommit) + fc.tx, err = newFirebirdsqlTx(fc, ISOLATION_LEVEL_READ_COMMITED, fc.isAutocommit, false) fc.clientPublic = clientPublic fc.clientSecret = clientSecret diff --git a/driver_go18_test.go b/driver_go18_test.go index 72a8e8d6..9bfa3293 100644 --- a/driver_go18_test.go +++ b/driver_go18_test.go @@ -33,6 +33,7 @@ import ( "time" ) + func TestGo18(t *testing.T) { temppath := TempFileName("test_go18_") conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) diff --git a/driver_test.go b/driver_test.go index 731f118d..3329ed08 100644 --- a/driver_test.go +++ b/driver_test.go @@ -31,20 +31,41 @@ import ( "os" "path/filepath" "reflect" + "runtime" "strings" "testing" "time" ) func TempFileName(prefix string) string { + var tmppath string randBytes := make([]byte, 16) rand.Read(randBytes) - return filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes)+".fdb") + + tmppath = filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes)+".fdb") + if runtime.GOOS == "windows" { + tmppath = "/" + tmppath + } + + return tmppath +} + +func GetTestDSN(file string) string { + + retorno := "sysdba:masterkey@localhost:3050" + + if runtime.GOOS == "windows" { + retorno = retorno + "/" + } + + retorno = retorno + TempFileName(file) + + return retorno } func TestBasic(t *testing.T) { temppath := TempFileName("test_basic_") - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error connecting: %v", err) @@ -81,7 +102,7 @@ func TestBasic(t *testing.T) { time.Sleep(1 * time.Second) - conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + conn, err = sql.Open("firebirdsql", "SYSDBA:masterkey@localhost:3050"+temppath) _, err = conn.Exec("CREATE TABLE foo (a INTEGER)") if err == nil { t.Fatalf("Need metadata update error") @@ -179,13 +200,13 @@ func TestReturning(t *testing.T) { func TestInsertBlobsWithParams(t *testing.T) { temppath := TempFileName("test_insert_blobs_with_params") - conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, _ := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) conn.Exec("CREATE TABLE test_blobs (f1 BLOB SUB_TYPE 0, f2 BLOB SUB_TYPE 1)") conn.Close() time.Sleep(1 * time.Second) - conn, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + conn, _ = sql.Open("firebirdsql", "SYSDBA:masterkey@localhost:3050"+temppath) s0 := "Test Text" b0 := []byte{0, 1, 2, 3, 4, 13, 10, 5, 6, 7} @@ -211,7 +232,7 @@ func TestInsertBlobsWithParams(t *testing.T) { func TestError(t *testing.T) { temppath := TempFileName("test_error_") - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error connecting: %v", err) } @@ -226,7 +247,7 @@ func TestError(t *testing.T) { func TestRole(t *testing.T) { temppath := TempFileName("test_role_") - conn1, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn1, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error creating: %v", err) } @@ -248,7 +269,7 @@ func TestRole(t *testing.T) { time.Sleep(1 * time.Second) - conn2, err := sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/"+temppath+"?role=driverrole") + conn2, err := sql.Open("firebirdsql", "SYSDBA:masterkey@localhost:3050"+temppath+"?role=driverrole") if err != nil { t.Fatalf("Error connecting: %v", err) } @@ -266,7 +287,7 @@ func TestRole(t *testing.T) { func TestInsertTimestamp(t *testing.T) { temppath := TempFileName("test_timestamp_") - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error creating: %v", err) } @@ -310,7 +331,7 @@ func TestInsertTimestamp(t *testing.T) { func TestBoolean(t *testing.T) { temppath := TempFileName("test_boolean_") - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error connecting: %v", err) } @@ -365,7 +386,7 @@ func TestBoolean(t *testing.T) { func TestDecFloat(t *testing.T) { temppath := TempFileName("test_decfloat_") - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error connecting: %v", err) } @@ -409,7 +430,7 @@ func TestDecFloat(t *testing.T) { func TestLegacyAuthWireCrypt(t *testing.T) { temppath := TempFileName("test_legacy_atuh_") var n int - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error connecting: %v", err) } @@ -421,7 +442,7 @@ func TestLegacyAuthWireCrypt(t *testing.T) { time.Sleep(1 * time.Second) - conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath+"?auth_plugin_anme=Legacy_Auth") + conn, err = sql.Open("firebirdsql", "SYSDBA:masterkey@localhost:3050"+temppath+"?auth_plugin_anme=Legacy_Auth") if err != nil { t.Fatalf("Error connecting: %v", err) } @@ -431,7 +452,7 @@ func TestLegacyAuthWireCrypt(t *testing.T) { } conn.Close() - conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath+"?wire_crypt=false") + conn, err = sql.Open("firebirdsql", "SYSDBA:masterkey@localhost:3050"+temppath+"?wire_crypt=false") if err != nil { t.Fatalf("Error connecting: %v", err) } @@ -441,7 +462,7 @@ func TestLegacyAuthWireCrypt(t *testing.T) { } conn.Close() - conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath+"?auth_plugin_name=Legacy_Auth&wire_auth=true") + conn, err = sql.Open("firebirdsql", "SYSDBA:masterkey@localhost:3050"+temppath+"?auth_plugin_name=Legacy_Auth&wire_auth=true") if err != nil { t.Fatalf("Error connecting: %v", err) } @@ -451,7 +472,7 @@ func TestLegacyAuthWireCrypt(t *testing.T) { } conn.Close() - conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath+"?auth_plugin_name=Legacy_Auth&wire_auth=false") + conn, err = sql.Open("firebirdsql", "SYSDBA:masterkey@localhost:3050"+temppath+"?auth_plugin_name=Legacy_Auth&wire_auth=false") if err != nil { t.Fatalf("Error connecting: %v", err) } @@ -487,7 +508,7 @@ func TestGoIssue44(t *testing.T) { func TestGoIssue45(t *testing.T) { temppath := TempFileName("test_issue45_") - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error occured at sql.Open()") } @@ -507,7 +528,7 @@ func TestGoIssue45(t *testing.T) { time.Sleep(1 * time.Second) - conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + conn, err = sql.Open("firebirdsql", "SYSDBA:masterkey@localhost:3050"+temppath) // select null value type response struct { @@ -558,7 +579,7 @@ func TestGoIssue45(t *testing.T) { func TestGoIssue49(t *testing.T) { temppath := TempFileName("test_issue49_") - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error occured at sql.Open()") } @@ -619,7 +640,7 @@ func TestGoIssue49(t *testing.T) { func TestGoIssue53(t *testing.T) { timeout := time.Second * 40 temppath := TempFileName("test_issue53_") - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error occured at sql.Open()") } @@ -685,34 +706,9 @@ func TestGoIssue53(t *testing.T) { } } func TestGoIssue65(t *testing.T) { - /*var field01 string - var field02 int - var field03 int - var field04 string - var field05 int - var field06 int - var field07 string - var field08 string - var field09 string - var field10 string - var field11 string - var field12 float32 - var field13 float32 - var field14 float32 - var field15 float32 - var field16 float32 - var field17 float32 - var field18 float32 - var field19 float32 - var field20 string - var field21 string - var field22 string - var field23 string - var field24 float32 - var field25 float32 - */ + temppath := TempFileName("test_issue65_") - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error occured at sql.Open()") } @@ -769,17 +765,12 @@ func TestGoIssue65(t *testing.T) { existData := movtos.Next() if existData == false { t.Fatalf("Expecting Data") - } /*else { - movtos.Scan(&field01, &field02, &field03, &field04, &field05, &field06, &field07, &field08, &field09, &field10, - &field11, &field12, &field13, &field14, &field15, &field16, &field17, &field18, &field19, &field20, &field21, - &field22, &field23, &field24, &field25) - t.Fatalf(field01) - }*/ + } } func TestGoIssue80(t *testing.T) { temppath := TempFileName("test_issue80_") - conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn, err := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050"+temppath) if err != nil { t.Fatalf("Error occured at sql.Open()") } diff --git a/rows.go b/rows.go index 8681917b..66fae4f3 100644 --- a/rows.go +++ b/rows.go @@ -62,6 +62,7 @@ func (rows *firebirdsqlRows) Columns() []string { func (rows *firebirdsqlRows) Close() (er error) { rows.stmt.Close() + return } diff --git a/statement.go b/statement.go index 41bd321f..847781c7 100644 --- a/statement.go +++ b/statement.go @@ -46,6 +46,9 @@ func (stmt *firebirdsqlStmt) Close() (err error) { _, _, _, err = stmt.wp.opResponse() } + if stmt.tx.isAutocommit { + stmt.tx.Commit() + } return } diff --git a/transaction.go b/transaction.go index bf61d9e7..42bfa711 100644 --- a/transaction.go +++ b/transaction.go @@ -80,7 +80,7 @@ func (tx *firebirdsqlTx) begin() (err error) { return } -func (tx *firebirdsqlTx) commitRetainging() (err error) { +func (tx *firebirdsqlTx) commitRetaining() (err error) { tx.fc.wp.opCommitRetaining(tx.transHandle) _, _, _, err = tx.fc.wp.opResponse() tx.isAutocommit = tx.fc.isAutocommit @@ -103,11 +103,18 @@ func (tx *firebirdsqlTx) Rollback() (err error) { return } -func newFirebirdsqlTx(fc *firebirdsqlConn, isolationLevel int, isAutocommit bool) (tx *firebirdsqlTx, err error) { +func newFirebirdsqlTx(fc *firebirdsqlConn, isolationLevel int, isAutocommit bool, withBegin bool) (tx *firebirdsqlTx, err error) { tx = new(firebirdsqlTx) tx.fc = fc tx.isolationLevel = isolationLevel tx.isAutocommit = isAutocommit - tx.begin() + tx.needBegin = false + + if withBegin { + tx.begin() + } else { + tx.needBegin = true + } + return } diff --git a/transaction_test.go b/transaction_test.go index 22686788..b92f4e45 100644 --- a/transaction_test.go +++ b/transaction_test.go @@ -287,3 +287,147 @@ func TestIssue67(t *testing.T) { } } + +func TestIssue89(t *testing.T) { + + var noconn1, numberTrans, numberrelations int + + temppath := TempFileName("test_issue89_") + + // test transaction open on connection open + conn1, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050"+temppath) + conn2, _ := sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + + conn2.QueryRow("select count(*) from mon$transactions where mon$attachment_id <> current_connection").Scan(&numberTrans) + + if numberTrans > 0 { + t.Fatalf("Transaction open without query runned") + } + + conn2.Close() + + // test if are more than 1 transaction open on first query + conn1.QueryRow("select mon$attachment_id from mon$attachments where mon$attachment_id = current_connection").Scan(&noconn1) + + conn2, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/"+temppath) + conn2.QueryRow("select count(*) from mon$transactions where mon$attachment_id <> current_connection").Scan(&numberTrans) + + if numberTrans > 1 { + t.Fatalf("More than 1 transaction open") + } + + conn1.Close() + conn2.Close() + + // test autocommit when rows is closed + conn1, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + + rows, _ := conn1.Query("select first 3 rdb$relation_id from rdb$relations") + + rows.Next() + rows.Next() + + rows.Close() + + conn2, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + conn2.QueryRow("select count(*) from mon$transactions where mon$attachment_id <> current_connection").Scan(&numberTrans) + + if numberTrans > 0 { + t.Fatalf("Autocommit don't work") + } + + conn1.Close() + conn2.Close() + + // test autocommit on prepare statement + conn1, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + stmt, _ := conn1.Prepare("select count(*) from rdb$relations") + err := stmt.QueryRow().Scan(&numberrelations) + + if err != nil { + t.Fatalf("Error QueryRow of Prepare: %v", err) + } + + stmt.Close() + + stmt, _ = conn1.Prepare("select count(*) from rdb$relations") + + rows, _ = stmt.Query("select first 3 rdb$relation_id from rdb$relations") + + rows.Next() + rows.Next() + + rows.Close() + + conn2, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + conn2.QueryRow("select count(*) from mon$transactions where mon$attachment_id <> current_connection").Scan(&numberTrans) + + if numberTrans > 0 { + t.Fatalf("Autocommit in prepare don't work") + } + + // test autocommit on prepare statement + conn1, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + conn1.Exec("create table testprepareinsert (id integer)") + + stmt, _ = conn1.Prepare("insert into testprepareinsert (id) values (?)") + + stmt.Exec(1) + /* _, err = stmt.Exec(2) + if err == nil { + t.Fatalf("Autocommit in prepare don't work") + } + */ + stmt.Close() + + conn2, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + conn2.QueryRow("select count(*) from mon$transactions where mon$attachment_id <> current_connection").Scan(&numberTrans) + + if numberTrans > 0 { + t.Fatalf("Autocommit in prepare don't work") + } + + conn1, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + txp, _ := conn1.Begin() + stmt, _ = txp.Prepare("insert into testprepareinsert (id) values (?)") + + for i := 1; i <= 6; i++ { + _, err = stmt.Exec(i) + if err != nil { + t.Fatalf("Multiple execute of a prepared statement in same transaction don't work: %v", err) + } + } + + txp.Commit() + conn2, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + conn2.QueryRow("select count(*) from mon$transactions where mon$attachment_id <> current_connection").Scan(&numberTrans) + + if numberTrans > 0 { + t.Fatalf("Autocommit in prepare don't work") + } + + // test transaction open after a commit of another transaction + conn1, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + conn2, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + + tx, err := conn1.Begin() + + if err != nil { + t.Fatalf("Error opening new transaction: %v", err) + } + + tx.QueryRow("select mon$attachment_id from mon$attachments where mon$attachment_id = current_connection").Scan(&noconn1) + + tx.Commit() + + conn2, _ = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050"+temppath) + conn2.QueryRow("select count(*) from mon$transactions where mon$attachment_id <> current_connection").Scan(&numberTrans) + + if numberTrans > 0 { + t.Fatalf("Transaction leaved open until close connection") + } + + conn1.Close() + conn2.Close() + +}