Commit 67fc1ed7 authored by gwenn's avatar gwenn

Customize to my needs.

parent 8e81aa1b
*.6 *.[568ao]
*.8 [568a].out
*.swp _testmain.go
*~
_obj _obj
*.o
*.out
*.cgo*
_test _test
cgo_* *.swp
_cgo_*
_testmain.go
...@@ -4,15 +4,9 @@ ...@@ -4,15 +4,9 @@
include $(GOROOT)/src/Make.inc include $(GOROOT)/src/Make.inc
TARG=fsqlite TARG=github.com/gwenn/sqlite
CGOFILES=\ CGOFILES=\
fsqlite.go sqlite.go
ifeq ($(GOOS),darwin)
CGO_LDFLAGS=/usr/lib/libsqlite3.0.dylib
else
CGO_LDFLAGS=-lsqlite3
endif
include $(GOROOT)/src/Make.pkg include $(GOROOT)/src/Make.pkg
This is based on Russ Cox's original gosqlite package: Yet another SQLite binding based on:
- original [Russ Cox's][http://code.google.com/p/gosqlite/] implementation,
- the [Patrick Crosby's][https://github.com/patrickxb/fgosqlite/] fork.
http://code.google.com/p/gosqlite/ Conn#Exec handles multiple statements (separated by semicolons) properly.
Stmt#Exec is renamed in Stmt#Bind and a new Stmt#Exec method is introduced to #Bind and #Step.
I added Scan2 and Exec2 which use sqlite api calls to get/bind values instead of the Stmt#Bind uses native sqlite3_bind_x methods and failed if unsupported type.
original which basically converted everything to strings. Stmt#Next returns a (bool, os.Error) couple like Reader#Read. But its use in for loop becomes inelegant...
Stmt#Scan uses native sqlite3_column_x methods.
Scan2 and Exec2 are significantly faster. See the benchmarks in fgosqlite_test.go. Stmt#NamedScan is added. It's compliant with [go-dbi][https://github.com/thomaslee/go-dbi/] API but I think its signature should be improved/modified.
This diff is collapsed.
package fsqlite package sqlite
import ( import (
"testing" "testing"
"fmt" "os"
) )
func TestOpen(t *testing.T) { func open(t *testing.T) *Conn {
db, err := Open("/tmp/test.db") db, err := Open("")
if err != nil { if err != nil {
t.Errorf("couldn't open database file: %s", err) t.Fatalf("couldn't open database file: %s", err)
} }
if db == nil { if db == nil {
t.Error("opened database is nil") t.Fatal("opened database is nil")
} }
db.Close() return db
} }
func TestCreateTable(t *testing.T) { func createTable(db *Conn, t *testing.T) {
db, err := Open("/tmp/test.db") err := db.Exec("DROP TABLE IF EXISTS test;" +
db.Exec("DROP TABLE test") "CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT," +
err = db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, float_num REAL, int_num INTEGER, a_string TEXT)") " float_num REAL, int_num INTEGER, a_string TEXT); -- bim")
if err != nil { if err != nil {
t.Errorf("error creating table: %s", err) t.Fatalf("error creating table: %s", err)
} }
} }
type OutRow struct { func TestOpen(t *testing.T) {
Key int64 db := open(t)
FloatNum float64 db.Close()
IntNum int64 }
AString string
func TestCreateTable(t *testing.T) {
db := open(t)
defer db.Close()
createTable(db, t)
} }
func TestInsert(t *testing.T) { func TestInsert(t *testing.T) {
db, _ := Open("/tmp/test.db") db := open(t)
db.Exec("DROP TABLE test") defer db.Close()
db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, float_num REAL, int_num INTEGER, a_string TEXT)") createTable(db, t)
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 {
t.Errorf("insert error: %s", ierr) t.Fatalf("insert error: %s", ierr)
}
c := db.Changes()
if c != 1 {
t.Errorf("insert error: %d <> 1", c)
} }
} }
cs, _ := db.Prepare("SELECT COUNT(*) FROM test") cs, _ := db.Prepare("SELECT COUNT(*) FROM test")
cs.Exec() defer cs.Finalize()
if !cs.Next() { if ok, err := cs.Next(); !ok {
t.Error("no result for count") if err != nil {
t.Fatalf("error preparing count: %s", err)
}
t.Fatal("no result for count")
} }
var i int var i int
err := cs.Scan(&i) err := cs.Scan(&i)
if err != nil { if err != nil {
t.Errorf("error scanning count: %s", err) t.Fatalf("error scanning count: %s", err)
} }
if i != 1000 { if i != 1000 {
t.Errorf("count should be 1000, but it is %d", i) t.Errorf("count should be 1000, but it is %d", i)
...@@ -59,169 +70,153 @@ func TestInsert(t *testing.T) { ...@@ -59,169 +70,153 @@ func TestInsert(t *testing.T) {
} }
func TestInsertWithStatement(t *testing.T) { func TestInsertWithStatement(t *testing.T) {
db, _ := Open("/tmp/test_is.db") db := open(t)
db.Exec("DROP TABLE test") defer db.Close()
db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, float_num REAL, int_num INTEGER, a_string TEXT)") createTable(db, t)
s, serr := db.Prepare("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)") s, serr := db.Prepare("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)")
if serr != nil { if serr != nil {
t.Errorf("prepare error: %s", serr) t.Fatalf("prepare error: %s", serr)
} }
if s == nil { if s == nil {
t.Error("statement is nil") t.Fatal("statement is nil")
} }
defer s.Finalize()
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 {
t.Errorf("insert error: %s", ierr) t.Fatalf("insert error: %s", ierr)
}
c := db.Changes()
if c != 1 {
t.Errorf("insert error: %d <> 1", c)
} }
s.Next()
} }
s.Finalize()
cs, _ := db.Prepare("SELECT COUNT(*) FROM test") cs, _ := db.Prepare("SELECT COUNT(*) FROM test")
cs.Exec() defer cs.Finalize()
if !cs.Next() { if ok, _ := cs.Next(); !ok {
t.Error("no result for count") t.Fatal("no result for count")
} }
var i int var i int
err := cs.Scan(&i) err := cs.Scan(&i)
if err != nil { if err != nil {
t.Errorf("error scanning count: %s", err) t.Fatalf("error scanning count: %s", err)
} }
if i != 1000 { if i != 1000 {
t.Errorf("count should be 1000, but it is %d", i) t.Errorf("count should be 1000, but it is %d", i)
} }
}
func TestInsertWithStatement2(t *testing.T) { rs, _ := db.Prepare("SELECT float_num, int_num, a_string FROM test ORDER BY int_num LIMIT 2")
db, _ := Open("/tmp/test_is2.db") var fnum float64
db.Exec("DROP TABLE test") var inum int64
db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, float_num REAL, int_num INTEGER, a_string TEXT)") var sstr string
s, serr := db.Prepare("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)") if ok, _ := rs.Next(); ok {
if serr != nil { rs.Scan(&fnum, &inum, &sstr)
t.Errorf("prepare error: %s", serr) if fnum != 0 {
t.Errorf("Expected 0 <> %f\n", fnum)
} }
if s == nil { if inum != 0 {
t.Error("statement is nil") t.Errorf("Expected 0 <> %d\n", inum)
} }
if sstr != "hello" {
for i := 0; i < 1000; i++ { t.Errorf("Expected 'hello' <> %s\n", sstr)
ierr := s.Exec2(float64(i)*float64(3.14), i, "hello")
if ierr != nil {
t.Errorf("insert error: %s", ierr)
} }
s.Next()
} }
s.Finalize() if ok, _ := rs.Next(); ok {
cs, _ := db.Prepare("SELECT COUNT(*) FROM test")
cs.Exec()
if !cs.Next() {
t.Error("no result for count")
}
var i int
err := cs.Scan(&i)
if err != nil {
t.Errorf("error scanning count: %s", err)
}
if i != 1000 {
t.Errorf("count should be 1000, but it is %d", i)
}
rs, _ := db.Prepare("SELECT float_num, int_num, a_string FROM test ORDER BY int_num LIMIT 10")
var fnum float64 var fnum float64
var inum int64 var inum int64
var sstr string var sstr string
for rs.Next() { rs.NamedScan("a_string", &sstr, "float_num", &fnum, "int_num", &inum)
rs.Scan(&fnum, &inum, &sstr) if fnum != 3.14 {
fmt.Printf("fnum = %f, inum = %d, sstre = %s\n", fnum, inum, sstr) t.Errorf("Expected 3.14 <> %f\n", fnum)
}
if inum != 1 {
t.Errorf("Expected 1 <> %d\n", inum)
}
if sstr != "hello" {
t.Errorf("Expected 'hello' <> %s\n", sstr)
}
} }
} }
func BenchmarkScan(b *testing.B) { func BenchmarkScan(b *testing.B) {
b.StopTimer() b.StopTimer()
db, _ := Open("/tmp/test_bs.db") db, _ := Open("")
db.Exec("DROP TABLE test") defer db.Close()
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)")
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.Next()
} }
s.Finalize() s.Finalize()
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
cs, _ := db.Prepare("SELECT float_num, int_num, a_string FROM test") cs, _ := db.Prepare("SELECT float_num, int_num, a_string FROM test")
cs.Exec()
var fnum float64 var fnum float64
var inum int64 var inum int64
var sstr string var sstr string
for cs.Next() { var ok bool
var err os.Error
for ok, err = cs.Next(); ok; ok, err = cs.Next() {
cs.Scan(&fnum, &inum, &sstr) cs.Scan(&fnum, &inum, &sstr)
} }
if err != nil {
panic(err)
}
cs.Finalize()
} }
} }
func BenchmarkScan2(b *testing.B) { func BenchmarkNamedScan(b *testing.B) {
b.StopTimer() b.StopTimer()
db, _ := Open("/tmp/test_bs2.db") db, _ := Open("")
db.Exec("DROP TABLE test") defer db.Close()
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)")
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.Next()
} }
s.Finalize() s.Finalize()
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
cs, _ := db.Prepare("SELECT float_num, int_num, a_string FROM test") cs, _ := db.Prepare("SELECT float_num, int_num, a_string FROM test")
cs.Exec()
var fnum float64 var fnum float64
var inum int64 var inum int64
var sstr string var sstr string
for cs.Next() { var ok bool
cs.Scan2(&fnum, &inum, &sstr) var err os.Error
for ok, err = cs.Next(); ok; ok, err = cs.Next() {
cs.NamedScan("float_num", &fnum, "int_num", &inum, "a_string", &sstr)
}
if err != nil {
panic(err)
} }
cs.Finalize()
} }
} }
func BenchmarkInsert(b *testing.B) { func BenchmarkInsert(b *testing.B) {
db, _ := Open("/tmp/test_bi.db") db, _ := Open("")
db.Exec("DROP TABLE test") defer db.Close()
db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, float_num REAL, int_num INTEGER, a_string TEXT)") db.Exec("DROP TABLE IF EXISTS test")
s, _ := db.Prepare("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)") db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT," +
" float_num REAL, int_num INTEGER, a_string TEXT)")
s, _ := db.Prepare("INSERT INTO test (float_num, int_num, a_string)" +
" VALUES (?, ?, ?)")
defer s.Finalize()
// for x := 0; x < b.N; x++ {
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")
s.Next()
}
// }
s.Finalize()
}
func BenchmarkInsert2(b *testing.B) {
db, _ := Open("/tmp/test_bi2.db")
db.Exec("DROP TABLE test")
db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, float_num REAL, int_num INTEGER, a_string TEXT)")
s, _ := db.Prepare("INSERT INTO test (float_num, int_num, a_string) VALUES (?, ?, ?)")
// for x := 0; x < b.N; x++ {
for i := 0; i < b.N; i++ {
s.Exec2(float64(i)*float64(3.14), i, "hello")
s.Next()
} }
// }
s.Finalize()
} }
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