diff options
Diffstat (limited to 'all_test_windows.go')
-rw-r--r-- | all_test_windows.go | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/all_test_windows.go b/all_test_windows.go new file mode 100644 index 0000000..34f5349 --- /dev/null +++ b/all_test_windows.go @@ -0,0 +1,494 @@ +// Copyright 2017 The Sqlite Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sqlite + +import ( + "bytes" + "database/sql" + "flag" + "fmt" + "io" + "io/ioutil" + "os" + "path" + "path/filepath" + "runtime" + "sort" + "strings" + "testing" + "time" + + "github.com/cznic/virtual" +) + +func caller(s string, va ...interface{}) { + if s == "" { + s = strings.Repeat("%v ", len(va)) + } + _, fn, fl, _ := runtime.Caller(2) + fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) + fmt.Fprintf(os.Stderr, s, va...) + fmt.Fprintln(os.Stderr) + _, fn, fl, _ = runtime.Caller(1) + fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) + fmt.Fprintln(os.Stderr) + os.Stderr.Sync() +} + +func dbg(s string, va ...interface{}) { + if s == "" { + s = strings.Repeat("%v ", len(va)) + } + _, fn, fl, _ := runtime.Caller(1) + fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) + fmt.Fprintf(os.Stderr, s, va...) + fmt.Fprintln(os.Stderr) + os.Stderr.Sync() +} + +func TODO(...interface{}) string { //TODOOK + _, fn, fl, _ := runtime.Caller(1) + return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK +} + +func use(...interface{}) {} + +func init() { + use(caller, dbg, TODO) //TODOOK +} + +// ============================================================================ + +var ( + // Add "-tags virtual.profile" to the command. + profileAll = flag.Bool("profile", false, "") + profileFunctions = flag.Bool("profile_functions", false, "") + profileInstructions = flag.Bool("profile_instructions", false, "") + profileLines = flag.Bool("profile_lines", false, "") + profileRate = flag.Int("profile_rate", 1000, "") + recsPerSec = flag.Bool("recs_per_sec_as_mbps", false, "Show records per second as MB/s.") +) + +func tempDB(t testing.TB) (string, *sql.DB) { + dir, err := ioutil.TempDir("", "sqlite-test-") + if err != nil { + t.Fatal(err) + } + + db, err := sql.Open(driverName, filepath.Join(dir, "tmp.db")) + if err != nil { + os.RemoveAll(dir) + t.Fatal(err) + } + + return dir, db +} + +func TestScalar(t *testing.T) { + dir, db := tempDB(t) + + defer func() { + db.Close() + os.RemoveAll(dir) + }() + + t1 := time.Date(2017, 4, 20, 1, 2, 3, 56789, time.UTC) + t2 := time.Date(2018, 5, 21, 2, 3, 4, 98765, time.UTC) + r, err := db.Exec(` + create table t(i int, f double, b bool, s text, t time); + insert into t values(12, 3.14, ?, "foo", ?), (34, 2.78, ?, "bar", ?); + `, + true, t1, + false, t2, + ) + if err != nil { + t.Fatal(err) + } + + n, err := r.RowsAffected() + if err != nil { + t.Fatal(err) + } + + if g, e := n, int64(2); g != e { + t.Fatal(g, e) + } + + rows, err := db.Query("select * from t") + if err != nil { + t.Fatal(err) + } + + type rec struct { + i int + f float64 + b bool + s string + t string + } + var a []rec + for rows.Next() { + var r rec + if err := rows.Scan(&r.i, &r.f, &r.b, &r.s, &r.t); err != nil { + t.Fatal(err) + } + + a = append(a, r) + } + if err := rows.Err(); err != nil { + t.Fatal(err) + } + + if g, e := len(a), 2; g != e { + t.Fatal(g, e) + } + + if g, e := a[0], (rec{12, 3.14, true, "foo", t1.String()}); g != e { + t.Fatal(g, e) + } + + if g, e := a[1], (rec{34, 2.78, false, "bar", t2.String()}); g != e { + t.Fatal(g, e) + } +} + +func TestBlob(t *testing.T) { + dir, db := tempDB(t) + + defer func() { + db.Close() + os.RemoveAll(dir) + }() + + b1 := []byte(time.Now().String()) + b2 := []byte("\x00foo\x00bar\x00") + if _, err := db.Exec(` + create table t(b blob); + insert into t values(?), (?); + `, b1, b2, + ); err != nil { + t.Fatal(err) + } + + rows, err := db.Query("select * from t") + if err != nil { + t.Fatal(err) + } + + type rec struct { + b []byte + } + var a []rec + for rows.Next() { + var r rec + if err := rows.Scan(&r.b); err != nil { + t.Fatal(err) + } + + a = append(a, r) + } + if err := rows.Err(); err != nil { + t.Fatal(err) + } + + if g, e := len(a), 2; g != e { + t.Fatal(g, e) + } + + if g, e := a[0].b, b1; !bytes.Equal(g, e) { + t.Fatal(g, e) + } + + if g, e := a[1].b, b2; !bytes.Equal(g, e) { + t.Fatal(g, e) + } +} + +func profile(t testing.TB, d time.Duration, w io.Writer, format string, arg ...interface{}) { + rate := vm.ProfileRate + if rate == 0 { + rate = 1 + } + if len(vm.ProfileFunctions)+len(vm.ProfileLines)+len(vm.ProfileInstructions) != 0 { + fmt.Fprintf(w, "# %v\n", os.Args[1:]) + } + if len(vm.ProfileFunctions) != 0 { + fmt.Fprintf(w, format, arg...) + type u struct { + virtual.PCInfo + n int + } + var s int64 + var a []u + var wi int + for k, v := range vm.ProfileFunctions { + a = append(a, u{k, v}) + s += int64(v) + if n := len(k.Name.String()); n > wi { + wi = n + } + } + sort.Slice(a, func(i, j int) bool { + if a[i].n < a[j].n { + return true + } + + if a[i].n > a[j].n { + return false + } + + return a[i].Name < a[j].Name + }) + fmt.Fprintf(w, "---- Profile functions, %v samples in %v, %.3f MIPS, %v/sample\n", s, d, float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d), time.Duration(float64(d)/float64(s))) + if x, ok := t.(*testing.B); ok { + fmt.Fprintf(w, "\t%v samples/1 [samples/b.N]\n", s/int64(x.N)) + } + var c int64 + for i := len(a) - 1; i >= 0; i-- { + c += int64(a[i].n) + fmt.Fprintf( + w, + "%*v\t%10v%10.2f%%%10.2f%%\n", + -wi, a[i].Name, a[i].n, + 100*float64(a[i].n)/float64(s), + 100*float64(c)/float64(s), + ) + } + } + if len(vm.ProfileLines) != 0 { + fmt.Fprintf(w, format, arg...) + type u struct { + virtual.PCInfo + n int + } + var s int64 + var a []u + for k, v := range vm.ProfileLines { + a = append(a, u{k, v}) + s += int64(v) + } + sort.Slice(a, func(i, j int) bool { + if a[i].n < a[j].n { + return true + } + + if a[i].n > a[j].n { + return false + } + + if a[i].Name < a[j].Name { + return true + } + + if a[i].Name > a[j].Name { + return false + } + + return a[i].Line < a[j].Line + }) + fmt.Fprintf(w, "---- Profile lines, %v samples in %v, %.3f MIPS, %v/sample\n", s, d, float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d), time.Duration(float64(d)/float64(s))) + if x, ok := t.(*testing.B); ok { + fmt.Fprintf(w, "\t%v samples/1 [samples/b.N]\n", s/int64(x.N)) + } + var c int64 + for i := len(a) - 1; i >= 0; i-- { + c += int64(a[i].n) + fmt.Fprintf( + w, + "%v:%v:\t%10v%10.2f%%%10.2f%%\n", + a[i].Name, a[i].Line, a[i].n, + 100*float64(a[i].n)/float64(s), + 100*float64(c)/float64(s), + ) + } + } + if len(vm.ProfileInstructions) != 0 { + fmt.Fprintf(w, format, arg...) + type u struct { + virtual.Opcode + n int + } + var s int64 + var a []u + var wi int + for k, v := range vm.ProfileInstructions { + a = append(a, u{k, v}) + s += int64(v) + if n := len(k.String()); n > wi { + wi = n + } + } + sort.Slice(a, func(i, j int) bool { + if a[i].n < a[j].n { + return true + } + + if a[i].n > a[j].n { + return false + } + + return a[i].Opcode < a[j].Opcode + }) + fmt.Fprintf(w, "---- Profile instructions, %v samples in %v, %.3f MIPS, %v/sample\n", s, d, float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d), time.Duration(float64(d)/float64(s))) + if x, ok := t.(*testing.B); ok { + fmt.Fprintf(w, "\t%v samples/1 [samples/b.N]\n", s/int64(x.N)) + } + var c int64 + for i := len(a) - 1; i >= 0; i-- { + c += int64(a[i].n) + fmt.Fprintf( + w, + "%*s%10v%10.2f%%\t%10.2f%%\n", + -wi, a[i].Opcode, a[i].n, + 100*float64(a[i].n)/float64(s), + 100*float64(c)/float64(s), + ) + } + } +} + +func BenchmarkInsertMemory(b *testing.B) { + db, err := sql.Open(driverName, "file::memory:") + if err != nil { + b.Fatal(err) + } + + defer func() { + db.Close() + }() + + if _, err := db.Exec(` + create table t(i int); + begin; + `); err != nil { + b.Fatal(err) + } + + s, err := db.Prepare("insert into t values(?)") + if err != nil { + b.Fatal(err) + } + + if *profileAll || *profileFunctions { + vm.ProfileFunctions = map[virtual.PCInfo]int{} + } + if *profileAll || *profileLines { + vm.ProfileLines = map[virtual.PCInfo]int{} + } + if *profileAll || *profileInstructions { + vm.ProfileInstructions = map[virtual.Opcode]int{} + } + vm.ProfileRate = int(*profileRate) + t0 := time.Now() + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := s.Exec(int64(i)); err != nil { + b.Fatal(err) + } + } + b.StopTimer() + if *recsPerSec { + b.SetBytes(1e6) + } + d := time.Since(t0) + if _, err := db.Exec(`commit;`); err != nil { + b.Fatal(err) + } + + profile(b, d, os.Stderr, "==== BenchmarkInsertMemory b.N %v\n", b.N) +} + +func BenchmarkNextMemory(b *testing.B) { + db, err := sql.Open(driverName, "file::memory:") + if err != nil { + b.Fatal(err) + } + + defer func() { + db.Close() + }() + + if _, err := db.Exec(` + create table t(i int); + begin; + `); err != nil { + b.Fatal(err) + } + + s, err := db.Prepare("insert into t values(?)") + if err != nil { + b.Fatal(err) + } + + defer s.Close() + + for i := 0; i < b.N; i++ { + if _, err := s.Exec(int64(i)); err != nil { + b.Fatal(err) + } + } + if _, err := db.Exec("commit"); err != nil { + b.Fatal(err) + } + + r, err := db.Query("select * from t") + if err != nil { + + } + + defer r.Close() + + if *profileAll || *profileFunctions { + vm.ProfileFunctions = map[virtual.PCInfo]int{} + } + if *profileAll || *profileLines { + vm.ProfileLines = map[virtual.PCInfo]int{} + } + if *profileAll || *profileInstructions { + vm.ProfileInstructions = map[virtual.Opcode]int{} + } + vm.ProfileRate = int(*profileRate) + t0 := time.Now() + b.ResetTimer() + for i := 0; i < b.N; i++ { + if !r.Next() { + b.Fatal(err) + } + } + b.StopTimer() + if *recsPerSec { + b.SetBytes(1e6) + } + d := time.Since(t0) + profile(b, d, os.Stderr, "==== BenchmarkNextMemory b.N %v\n", b.N) +} + +// https://github.com/cznic/sqlite/issues/11 +func TestIssue11(t *testing.T) { + const N = 6570 + dir, db := tempDB(t) + + defer func() { + db.Close() + os.RemoveAll(dir) + }() + + if _, err := db.Exec(` + CREATE TABLE t1 (t INT); + BEGIN; +`, + ); err != nil { + panic(err) + } + + for i := 0; i < N; i++ { + if _, err := db.Exec("INSERT INTO t1 (t) VALUES (?)", i); err != nil { + t.Fatalf("#%v: %v", i, err) + } + } + if _, err := db.Exec("COMMIT;"); err != nil { + t.Fatal(err) + } +} |