update go-sqlite3 & fix tests

This commit is contained in:
Frank Braun
2015-09-27 08:30:08 +02:00
parent 4dc6ba16e8
commit 35afdd14fb
6 changed files with 449 additions and 76 deletions
+1
View File
@@ -1,2 +1,3 @@
language: go
go: 1.5
script: go test -v .
+3 -1
View File
@@ -9,7 +9,7 @@ tracked for changes (maintenance details below):
Update code from https://github.com/mattn/go-sqlite3
----------------------------------------------------
Current HEAD: 3b3f1d01b2696af5501697c35629048c227586ab
Current HEAD: b808f01f660667b1510acf216aa2b9fe7f555ddb
Track files:
@@ -17,6 +17,8 @@ error.go
error_test.go
sqlite3.go (dead code and extension loading coding removed)
sqlite3_other.go
sqlite3_test.go (adjust path)
sqlite3_windows.go
_example/simple/simple.go
sqlite3_test/sqltest.go
+1 -1
View File
@@ -8,7 +8,7 @@ package sqlite3
/*
#cgo CFLAGS: -std=gnu99
#cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>
+427 -71
View File
@@ -1,14 +1,25 @@
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package sqlite3
import (
"./sqltest"
"crypto/rand"
"database/sql"
"database/sql/driver"
"encoding/hex"
"errors"
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/mutecomm/go-sqlcipher/sqlite3_test"
)
func TempFilename() string {
@@ -17,11 +28,17 @@ func TempFilename() string {
return filepath.Join(os.TempDir(), "foo"+hex.EncodeToString(randBytes)+".db")
}
func TestOpen(t *testing.T) {
func doTestOpen(t *testing.T, option string) (string, error) {
var url string
tempFilename := TempFilename()
db, err := sql.Open("sqlite3", tempFilename)
if option != "" {
url = tempFilename + option
} else {
url = tempFilename
}
db, err := sql.Open("sqlite3", url)
if err != nil {
t.Fatal("Failed to open database:", err)
return "Failed to open database:", err
}
defer os.Remove(tempFilename)
defer db.Close()
@@ -29,11 +46,38 @@ func TestOpen(t *testing.T) {
_, err = db.Exec("drop table foo")
_, err = db.Exec("create table foo (id integer)")
if err != nil {
t.Fatal("Failed to create table:", err)
return "Failed to create table:", err
}
if stat, err := os.Stat(tempFilename); err != nil || stat.IsDir() {
t.Error("Failed to create ./foo.db")
return "Failed to create ./foo.db", nil
}
return "", nil
}
func TestOpen(t *testing.T) {
cases := map[string]bool{
"": true,
"?_txlock=immediate": true,
"?_txlock=deferred": true,
"?_txlock=exclusive": true,
"?_txlock=bogus": false,
}
for option, expectedPass := range cases {
result, err := doTestOpen(t, option)
if result == "" {
if !expectedPass {
errmsg := fmt.Sprintf("_txlock error not caught at dbOpen with option: %s", option)
t.Fatal(errmsg)
}
} else if expectedPass {
if err == nil {
t.Fatal(result)
} else {
t.Fatal(result, err)
}
}
}
}
@@ -303,6 +347,7 @@ func TestTimestamp(t *testing.T) {
{"0000-00-00 00:00:00", time.Time{}},
{timestamp1, timestamp1},
{timestamp1.Unix(), timestamp1},
{timestamp1.UnixNano() / int64(time.Millisecond), timestamp1},
{timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1},
{timestamp1.Format("2006-01-02 15:04:05.000"), timestamp1},
{timestamp1.Format("2006-01-02T15:04:05.000"), timestamp1},
@@ -627,78 +672,389 @@ func TestWAL(t *testing.T) {
}
}
func TestTimezoneConversion(t *testing.T) {
zones := []string{"UTC", "US/Central", "US/Pacific", "Local"}
for _, tz := range zones {
tempFilename := TempFilename()
db, err := sql.Open("sqlite3", tempFilename+"?_loc="+url.QueryEscape(tz))
if err != nil {
t.Fatal("Failed to open database:", err)
}
defer os.Remove(tempFilename)
defer db.Close()
_, err = db.Exec("DROP TABLE foo")
_, err = db.Exec("CREATE TABLE foo(id INTEGER, ts TIMESTAMP, dt DATETIME)")
if err != nil {
t.Fatal("Failed to create table:", err)
}
loc, err := time.LoadLocation(tz)
if err != nil {
t.Fatal("Failed to load location:", err)
}
timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC)
timestamp2 := time.Date(2006, time.January, 2, 15, 4, 5, 123456789, time.UTC)
timestamp3 := time.Date(2012, time.November, 4, 0, 0, 0, 0, time.UTC)
tests := []struct {
value interface{}
expected time.Time
}{
{"nonsense", time.Time{}.In(loc)},
{"0000-00-00 00:00:00", time.Time{}.In(loc)},
{timestamp1, timestamp1.In(loc)},
{timestamp1.Unix(), timestamp1.In(loc)},
{timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1.In(loc)},
{timestamp1.Format("2006-01-02 15:04:05.000"), timestamp1.In(loc)},
{timestamp1.Format("2006-01-02T15:04:05.000"), timestamp1.In(loc)},
{timestamp1.Format("2006-01-02 15:04:05"), timestamp1.In(loc)},
{timestamp1.Format("2006-01-02T15:04:05"), timestamp1.In(loc)},
{timestamp2, timestamp2.In(loc)},
{"2006-01-02 15:04:05.123456789", timestamp2.In(loc)},
{"2006-01-02T15:04:05.123456789", timestamp2.In(loc)},
{"2012-11-04", timestamp3.In(loc)},
{"2012-11-04 00:00", timestamp3.In(loc)},
{"2012-11-04 00:00:00", timestamp3.In(loc)},
{"2012-11-04 00:00:00.000", timestamp3.In(loc)},
{"2012-11-04T00:00", timestamp3.In(loc)},
{"2012-11-04T00:00:00", timestamp3.In(loc)},
{"2012-11-04T00:00:00.000", timestamp3.In(loc)},
}
for i := range tests {
_, err = db.Exec("INSERT INTO foo(id, ts, dt) VALUES(?, ?, ?)", i, tests[i].value, tests[i].value)
if err != nil {
t.Fatal("Failed to insert timestamp:", err)
}
}
rows, err := db.Query("SELECT id, ts, dt FROM foo ORDER BY id ASC")
if err != nil {
t.Fatal("Unable to query foo table:", err)
}
defer rows.Close()
seen := 0
for rows.Next() {
var id int
var ts, dt time.Time
if err := rows.Scan(&id, &ts, &dt); err != nil {
t.Error("Unable to scan results:", err)
continue
}
if id < 0 || id >= len(tests) {
t.Error("Bad row id: ", id)
continue
}
seen++
if !tests[id].expected.Equal(ts) {
t.Errorf("Timestamp value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, ts)
}
if !tests[id].expected.Equal(dt) {
t.Errorf("Datetime value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt)
}
if tests[id].expected.Location().String() != ts.Location().String() {
t.Errorf("Location for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected.Location().String(), ts.Location().String())
}
if tests[id].expected.Location().String() != dt.Location().String() {
t.Errorf("Location for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected.Location().String(), dt.Location().String())
}
}
if seen != len(tests) {
t.Errorf("Expected to see %d rows", len(tests))
}
}
}
func TestSuite(t *testing.T) {
db, err := sql.Open("sqlite3", ":memory:")
tempFilename := TempFilename()
db, err := sql.Open("sqlite3", tempFilename+"?_busy_timeout=99999")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tempFilename)
defer db.Close()
sqltest.RunTests(t, db, sqltest.SQLITE)
sqlite3_test.RunTests(t, db, sqlite3_test.SQLITE)
}
// TODO: Execer & Queryer currently disabled
// https://github.com/mattn/go-sqlite3/issues/82
//func TestExecer(t *testing.T) {
// tempFilename := TempFilename()
// db, err := sql.Open("sqlite3", tempFilename)
// if err != nil {
// t.Fatal("Failed to open database:", err)
// }
// defer os.Remove(tempFilename)
// defer db.Close()
//
// _, err = db.Exec(`
// create table foo (id integer);
// insert into foo(id) values(?);
// insert into foo(id) values(?);
// insert into foo(id) values(?);
// `, 1, 2, 3)
// if err != nil {
// t.Error("Failed to call db.Exec:", err)
// }
// if err != nil {
// t.Error("Failed to call res.RowsAffected:", err)
// }
//}
//
//func TestQueryer(t *testing.T) {
// tempFilename := TempFilename()
// db, err := sql.Open("sqlite3", tempFilename)
// if err != nil {
// t.Fatal("Failed to open database:", err)
// }
// defer os.Remove(tempFilename)
// defer db.Close()
//
// _, err = db.Exec(`
// create table foo (id integer);
// `)
// if err != nil {
// t.Error("Failed to call db.Query:", err)
// }
//
// rows, err := db.Query(`
// insert into foo(id) values(?);
// insert into foo(id) values(?);
// insert into foo(id) values(?);
// select id from foo order by id;
// `, 3, 2, 1)
// if err != nil {
// t.Error("Failed to call db.Query:", err)
// }
// defer rows.Close()
// n := 1
// if rows != nil {
// for rows.Next() {
// var id int
// err = rows.Scan(&id)
// if err != nil {
// t.Error("Failed to db.Query:", err)
// }
// if id != n {
// t.Error("Failed to db.Query: not matched results")
// }
// }
// }
//}
func TestExecer(t *testing.T) {
tempFilename := TempFilename()
db, err := sql.Open("sqlite3", tempFilename)
if err != nil {
t.Fatal("Failed to open database:", err)
}
defer os.Remove(tempFilename)
defer db.Close()
_, err = db.Exec(`
create table foo (id integer); -- one comment
insert into foo(id) values(?);
insert into foo(id) values(?);
insert into foo(id) values(?); -- another comment
`, 1, 2, 3)
if err != nil {
t.Error("Failed to call db.Exec:", err)
}
}
func TestQueryer(t *testing.T) {
tempFilename := TempFilename()
db, err := sql.Open("sqlite3", tempFilename)
if err != nil {
t.Fatal("Failed to open database:", err)
}
defer os.Remove(tempFilename)
defer db.Close()
_, err = db.Exec(`
create table foo (id integer);
`)
if err != nil {
t.Error("Failed to call db.Query:", err)
}
rows, err := db.Query(`
insert into foo(id) values(?);
insert into foo(id) values(?);
insert into foo(id) values(?);
select id from foo order by id;
`, 3, 2, 1)
if err != nil {
t.Error("Failed to call db.Query:", err)
}
defer rows.Close()
n := 1
if rows != nil {
for rows.Next() {
var id int
err = rows.Scan(&id)
if err != nil {
t.Error("Failed to db.Query:", err)
}
if id != n {
t.Error("Failed to db.Query: not matched results")
}
}
}
}
func TestStress(t *testing.T) {
tempFilename := TempFilename()
db, err := sql.Open("sqlite3", tempFilename)
if err != nil {
t.Fatal("Failed to open database:", err)
}
db.Exec("CREATE TABLE foo (id int);")
db.Exec("INSERT INTO foo VALUES(1);")
db.Exec("INSERT INTO foo VALUES(2);")
db.Close()
for i := 0; i < 10000; i++ {
db, err := sql.Open("sqlite3", tempFilename)
if err != nil {
t.Fatal("Failed to open database:", err)
}
for j := 0; j < 3; j++ {
rows, err := db.Query("select * from foo where id=1;")
if err != nil {
t.Error("Failed to call db.Query:", err)
}
for rows.Next() {
var i int
if err := rows.Scan(&i); err != nil {
t.Errorf("Scan failed: %v\n", err)
}
}
if err := rows.Err(); err != nil {
t.Errorf("Post-scan failed: %v\n", err)
}
rows.Close()
}
db.Close()
}
}
func TestDateTimeLocal(t *testing.T) {
zone := "Asia/Tokyo"
tempFilename := TempFilename()
db, err := sql.Open("sqlite3", tempFilename+"?_loc="+zone)
if err != nil {
t.Fatal("Failed to open database:", err)
}
db.Exec("CREATE TABLE foo (dt datetime);")
db.Exec("INSERT INTO foo VALUES('2015-03-05 15:16:17');")
row := db.QueryRow("select * from foo")
var d time.Time
err = row.Scan(&d)
if err != nil {
t.Fatal("Failed to scan datetime:", err)
}
if d.Hour() == 15 || !strings.Contains(d.String(), "JST") {
t.Fatal("Result should have timezone", d)
}
db.Close()
db, err = sql.Open("sqlite3", tempFilename)
if err != nil {
t.Fatal("Failed to open database:", err)
}
row = db.QueryRow("select * from foo")
err = row.Scan(&d)
if err != nil {
t.Fatal("Failed to scan datetime:", err)
}
if d.UTC().Hour() != 15 || !strings.Contains(d.String(), "UTC") {
t.Fatalf("Result should not have timezone %v %v", zone, d.String())
}
_, err = db.Exec("DELETE FROM foo")
if err != nil {
t.Fatal("Failed to delete table:", err)
}
dt, err := time.Parse("2006/1/2 15/4/5 -0700 MST", "2015/3/5 15/16/17 +0900 JST")
if err != nil {
t.Fatal("Failed to parse datetime:", err)
}
db.Exec("INSERT INTO foo VALUES(?);", dt)
db.Close()
db, err = sql.Open("sqlite3", tempFilename+"?_loc="+zone)
if err != nil {
t.Fatal("Failed to open database:", err)
}
row = db.QueryRow("select * from foo")
err = row.Scan(&d)
if err != nil {
t.Fatal("Failed to scan datetime:", err)
}
if d.Hour() != 15 || !strings.Contains(d.String(), "JST") {
t.Fatalf("Result should have timezone %v %v", zone, d.String())
}
}
func TestVersion(t *testing.T) {
s, n, id := Version()
if s == "" || n == 0 || id == "" {
t.Errorf("Version failed %q, %d, %q\n", s, n, id)
}
}
func TestNumberNamedParams(t *testing.T) {
tempFilename := TempFilename()
db, err := sql.Open("sqlite3", tempFilename)
if err != nil {
t.Fatal("Failed to open database:", err)
}
defer os.Remove(tempFilename)
defer db.Close()
_, err = db.Exec(`
create table foo (id integer, name text, extra text);
`)
if err != nil {
t.Error("Failed to call db.Query:", err)
}
_, err = db.Exec(`insert into foo(id, name, extra) values($1, $2, $2)`, 1, "foo")
if err != nil {
t.Error("Failed to call db.Exec:", err)
}
row := db.QueryRow(`select id, extra from foo where id = $1 and extra = $2`, 1, "foo")
if row == nil {
t.Error("Failed to call db.QueryRow")
}
var id int
var extra string
err = row.Scan(&id, &extra)
if err != nil {
t.Error("Failed to db.Scan:", err)
}
if id != 1 || extra != "foo" {
t.Error("Failed to db.QueryRow: not matched results")
}
}
func TestStringContainingZero(t *testing.T) {
tempFilename := TempFilename()
db, err := sql.Open("sqlite3", tempFilename)
if err != nil {
t.Fatal("Failed to open database:", err)
}
defer os.Remove(tempFilename)
defer db.Close()
_, err = db.Exec(`
create table foo (id integer, name, extra text);
`)
if err != nil {
t.Error("Failed to call db.Query:", err)
}
const text = "foo\x00bar"
_, err = db.Exec(`insert into foo(id, name, extra) values($1, $2, $2)`, 1, text)
if err != nil {
t.Error("Failed to call db.Exec:", err)
}
row := db.QueryRow(`select id, extra from foo where id = $1 and extra = $2`, 1, text)
if row == nil {
t.Error("Failed to call db.QueryRow")
}
var id int
var extra string
err = row.Scan(&id, &extra)
if err != nil {
t.Error("Failed to db.Scan:", err)
}
if id != 1 || extra != text {
t.Error("Failed to db.QueryRow: not matched results")
}
}
const CurrentTimeStamp = "2006-01-02 15:04:05"
type TimeStamp struct{ *time.Time }
func (t TimeStamp) Scan(value interface{}) error {
var err error
switch v := value.(type) {
case string:
*t.Time, err = time.Parse(CurrentTimeStamp, v)
case []byte:
*t.Time, err = time.Parse(CurrentTimeStamp, string(v))
default:
err = errors.New("invalid type for current_timestamp")
}
return err
}
func (t TimeStamp) Value() (driver.Value, error) {
return t.Time.Format(CurrentTimeStamp), nil
}
func TestDateTimeNow(t *testing.T) {
tempFilename := TempFilename()
db, err := sql.Open("sqlite3", tempFilename)
if err != nil {
t.Fatal("Failed to open database:", err)
}
defer db.Close()
var d time.Time
err = db.QueryRow("SELECT datetime('now')").Scan(TimeStamp{&d})
if err != nil {
t.Fatal("Failed to scan datetime:", err)
}
}
+3 -3
View File
@@ -318,7 +318,7 @@ func BenchmarkQuery(b *testing.B) {
var i int
var f float64
var s string
// var t time.Time
// var t time.Time
if err := db.QueryRow("select null, 1, 1.1, 'foo'").Scan(&n, &i, &f, &s); err != nil {
panic(err)
}
@@ -331,7 +331,7 @@ func BenchmarkParams(b *testing.B) {
var i int
var f float64
var s string
// var t time.Time
// var t time.Time
if err := db.QueryRow("select ?, ?, ?, ?", nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil {
panic(err)
}
@@ -350,7 +350,7 @@ func BenchmarkStmt(b *testing.B) {
var i int
var f float64
var s string
// var t time.Time
// var t time.Time
if err := st.QueryRow(nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil {
panic(err)
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
// +build windows
package sqlite3
/*
#cgo CFLAGS: -I. -fno-stack-check -fno-stack-protector -mno-stack-arg-probe
#cgo windows,386 CFLAGS: -D_localtime32=localtime
#cgo LDFLAGS: -lmingwex -lmingw32
*/
import "C"