Commit f687a5d8 authored by gwenn's avatar gwenn

Add transaction related methods.

parent 83fee886
...@@ -290,6 +290,39 @@ func (c *Conn) GetAutocommit() bool { ...@@ -290,6 +290,39 @@ func (c *Conn) GetAutocommit() bool {
return C.sqlite3_get_autocommit(c.db) != 0 return C.sqlite3_get_autocommit(c.db) != 0
} }
type TransactionType int
const (
DEFERRED TransactionType = 0
IMMEDIATE TransactionType = 1
EXCLUSIVE TransactionType = 2
)
func (c *Conn) Begin() os.Error {
return c.BeginTransaction(DEFERRED)
}
func (c *Conn) BeginTransaction(t TransactionType) os.Error {
if t == DEFERRED {
return c.Exec("BEGIN")
} else if t == IMMEDIATE {
return c.Exec("BEGIN IMMEDIATE")
} else if t == EXCLUSIVE {
return c.Exec("BEGIN EXCLUSIVE")
}
panic(fmt.Sprintf("Unsupported transaction type: '%#v'", t))
return nil
}
func (c *Conn) Commit() os.Error {
// TODO Check autocommit?
return c.Exec("COMMIT")
}
func (c *Conn) Rollback() os.Error {
// TODO Check autocommit?
return c.Exec("ROLLBACK")
}
// Prepared Statement (sqlite3_stmt) // Prepared Statement (sqlite3_stmt)
type Stmt struct { type Stmt struct {
c *Conn c *Conn
...@@ -525,7 +558,7 @@ func (s *Stmt) ColumnIndex(name string) (int, os.Error) { ...@@ -525,7 +558,7 @@ func (s *Stmt) ColumnIndex(name string) (int, os.Error) {
} }
// Set nullable to false to skip NULL type test. // Set nullable to false to skip NULL type test.
// Returns true when nullable is true and field is null. // Returns true when nullable is true and column is null.
// Calls sqlite3_column_count, sqlite3_column_name and sqlite3_column_(blob|double|int|int64|text) depending on args type. // Calls sqlite3_column_count, sqlite3_column_name and sqlite3_column_(blob|double|int|int64|text) depending on args type.
// http://sqlite.org/c3ref/column_blob.html // http://sqlite.org/c3ref/column_blob.html
func (s *Stmt) NamedScanColumn(name string, value interface{}, nullable bool) (bool, os.Error) { func (s *Stmt) NamedScanColumn(name string, value interface{}, nullable bool) (bool, os.Error) {
...@@ -539,7 +572,7 @@ func (s *Stmt) NamedScanColumn(name string, value interface{}, nullable bool) (b ...@@ -539,7 +572,7 @@ func (s *Stmt) NamedScanColumn(name string, value interface{}, nullable bool) (b
// The leftmost column is number 0. // The leftmost column is number 0.
// Index starts at 0. // Index starts at 0.
// Set nullable to false to skip NULL type test. // Set nullable to false to skip NULL type test.
// Returns true when nullable is true and field is null. // Returns true when nullable is true and column is null.
// Calls sqlite3_column_(blob|double|int|int64|text) depending on args type. // Calls sqlite3_column_(blob|double|int|int64|text) depending on args type.
// http://sqlite.org/c3ref/column_blob.html // http://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ScanColumn(index int, value interface{}, nullable bool) (bool, os.Error) { func (s *Stmt) ScanColumn(index int, value interface{}, nullable bool) (bool, os.Error) {
......
...@@ -95,6 +95,20 @@ func TestCreateTable(t *testing.T) { ...@@ -95,6 +95,20 @@ func TestCreateTable(t *testing.T) {
createTable(db, t) createTable(db, t)
} }
func TestTransaction(t *testing.T) {
db := open(t)
defer db.Close()
if err := db.Begin(); err != nil {
t.Fatalf("Error while beginning transaction: %s", err)
}
if err := db.Begin(); err == nil {
t.Fatalf("Error expected (transaction cannot be nested)")
}
if err := db.Commit(); err != nil {
t.Fatalf("Error while commiting transaction: %s", err)
}
}
func TestExists(t *testing.T) { func TestExists(t *testing.T) {
db := open(t) db := open(t)
defer db.Close() defer db.Close()
...@@ -118,6 +132,7 @@ func TestInsert(t *testing.T) { ...@@ -118,6 +132,7 @@ func TestInsert(t *testing.T) {
db := open(t) db := open(t)
defer db.Close() defer db.Close()
createTable(db, t) createTable(db, t)
db.Begin()
for i := 0; i < 1000; i++ { for i := 0; i < 1000; i++ {
ierr := db.Exec("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)", float64(i)*float64(3.14), i, "hello") ierr := db.Exec("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)", float64(i)*float64(3.14), i, "hello")
if ierr != nil { if ierr != nil {
...@@ -128,6 +143,9 @@ func TestInsert(t *testing.T) { ...@@ -128,6 +143,9 @@ func TestInsert(t *testing.T) {
t.Errorf("insert error: %d <> 1", c) t.Errorf("insert error: %d <> 1", c)
} }
} }
if err := db.Commit(); err != nil {
t.Fatalf("Error: %s", err)
}
lastId := db.LastInsertRowid() lastId := db.LastInsertRowid()
if lastId != 1000 { if lastId != 1000 {
...@@ -180,6 +198,7 @@ func TestInsertWithStatement(t *testing.T) { ...@@ -180,6 +198,7 @@ func TestInsertWithStatement(t *testing.T) {
t.Errorf("bind parameter count error: %d <> 3", paramCount) t.Errorf("bind parameter count error: %d <> 3", paramCount)
} }
db.Begin()
for i := 0; i < 1000; i++ { for i := 0; i < 1000; i++ {
ierr := s.Exec(float64(i)*float64(3.14), i, "hello") ierr := s.Exec(float64(i)*float64(3.14), i, "hello")
if ierr != nil { if ierr != nil {
...@@ -191,6 +210,9 @@ func TestInsertWithStatement(t *testing.T) { ...@@ -191,6 +210,9 @@ func TestInsertWithStatement(t *testing.T) {
} }
} }
s.Finalize() s.Finalize()
if err := db.Commit(); err != nil {
t.Fatalf("Error: %s", err)
}
cs, _ := db.Prepare("SELECT COUNT(*) FROM test") cs, _ := db.Prepare("SELECT COUNT(*) FROM test")
defer cs.Finalize() defer cs.Finalize()
...@@ -466,12 +488,14 @@ func BenchmarkScan(b *testing.B) { ...@@ -466,12 +488,14 @@ func BenchmarkScan(b *testing.B) {
defer db.Close() defer db.Close()
db.Exec("DROP TABLE IF EXISTS test") db.Exec("DROP TABLE IF EXISTS test")
db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, float_num REAL, int_num INTEGER, a_string TEXT)") db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, float_num REAL, int_num INTEGER, a_string TEXT)")
db.Begin()
s, _ := db.Prepare("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)") s, _ := db.Prepare("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)")
for i := 0; i < 1000; i++ { for i := 0; i < 1000; i++ {
s.Exec(float64(i)*float64(3.14), i, "hello") s.Exec(float64(i)*float64(3.14), i, "hello")
} }
s.Finalize() s.Finalize()
db.Commit()
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
...@@ -499,12 +523,14 @@ func BenchmarkNamedScan(b *testing.B) { ...@@ -499,12 +523,14 @@ func BenchmarkNamedScan(b *testing.B) {
defer db.Close() defer db.Close()
db.Exec("DROP TABLE IF EXISTS test") db.Exec("DROP TABLE IF EXISTS test")
db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, float_num REAL, int_num INTEGER, a_string TEXT)") db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, float_num REAL, int_num INTEGER, a_string TEXT)")
db.Begin()
s, _ := db.Prepare("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)") s, _ := db.Prepare("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)")
for i := 0; i < 1000; i++ { for i := 0; i < 1000; i++ {
s.Exec(float64(i)*float64(3.14), i, "hello") s.Exec(float64(i)*float64(3.14), i, "hello")
} }
s.Finalize() s.Finalize()
db.Commit()
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
...@@ -536,7 +562,9 @@ func BenchmarkInsert(b *testing.B) { ...@@ -536,7 +562,9 @@ func BenchmarkInsert(b *testing.B) {
" VALUES (?, ?, ?)") " VALUES (?, ?, ?)")
defer s.Finalize() defer s.Finalize()
db.Begin()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
s.Exec(float64(i)*float64(3.14), i, "hello") s.Exec(float64(i)*float64(3.14), i, "hello")
} }
db.Commit()
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment