aboutsummaryrefslogtreecommitdiff
path: root/sqlite3_go18_test.go
diff options
context:
space:
mode:
authorAndrii Zavorotnii <andrii.zavorotnii@gmail.com>2020-08-28 08:43:21 -0700
committerGitHub <noreply@github.com>2020-08-29 00:43:21 +0900
commit862b95943f99f3b40e317a79d41c27ac4b742011 (patch)
tree8ddf5deb99c4466eed725e130060083b29558e55 /sqlite3_go18_test.go
parentUse go-pointer instead of uintptr hacks. (#814) (diff)
downloadgolite-862b95943f99f3b40e317a79d41c27ac4b742011.tar.gz
golite-862b95943f99f3b40e317a79d41c27ac4b742011.tar.xz
Fix "cannot start a transaction within a transaction" issue (#764) (#765)
* Fix "cannot start a transaction within a transaction" issue [why] If db.BeginTx(ctx, nil) context is cancelled too fast, "BEGIN" statement can be completed inside DB, but we still try to cancel it with sqlite3_interrupt. In such case we get context.Cancelled or context.DeadlineExceeded from exec(), but operation really completed. Connection returned into pool, and returns "cannot start a transaction within a transaction" error for next db.BeginTx() call. [how] Handle status code returned from cancelled operation. [testing] Added unit-test which reproduces issue. * Reduce TestQueryRowContextCancelParallel concurrency [why] Tests times out in travis-ci when run with -race option.
Diffstat (limited to 'sqlite3_go18_test.go')
-rw-r--r--sqlite3_go18_test.go40
1 files changed, 39 insertions, 1 deletions
diff --git a/sqlite3_go18_test.go b/sqlite3_go18_test.go
index cfc89b0..5ee3d81 100644
--- a/sqlite3_go18_test.go
+++ b/sqlite3_go18_test.go
@@ -136,6 +136,44 @@ func TestShortTimeout(t *testing.T) {
}
}
+func TestExecContextCancel(t *testing.T) {
+ srcTempFilename := TempFilename(t)
+ defer os.Remove(srcTempFilename)
+
+ db, err := sql.Open("sqlite3", srcTempFilename)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ defer db.Close()
+
+ ts := time.Now()
+ initDatabase(t, db, 1000)
+ spent := time.Since(ts)
+ if spent < 100*time.Millisecond {
+ t.Skip("test will be too racy, as ExecContext below will be too fast.")
+ }
+
+ // expected to be extremely slow query
+ q := `
+INSERT INTO test_table (key1, key_id, key2, key3, key4, key5, key6, data)
+SELECT t1.key1 || t2.key1, t1.key_id || t2.key_id, t1.key2 || t2.key2, t1.key3 || t2.key3, t1.key4 || t2.key4, t1.key5 || t2.key5, t1.key6 || t2.key6, t1.data || t2.data
+FROM test_table t1 LEFT OUTER JOIN test_table t2`
+ // expect query above take ~ same time as setup above
+ ctx, cancel := context.WithTimeout(context.Background(), spent/2)
+ defer cancel()
+ ts = time.Now()
+ r, err := db.ExecContext(ctx, q)
+ // racy check
+ if r != nil {
+ n, err := r.RowsAffected()
+ t.Log(n, err, time.Since(ts))
+ }
+ if err != context.DeadlineExceeded {
+ t.Fatal(err, ctx.Err())
+ }
+}
+
func TestQueryRowContextCancel(t *testing.T) {
srcTempFilename := TempFilename(t)
defer os.Remove(srcTempFilename)
@@ -191,7 +229,7 @@ func TestQueryRowContextCancelParallel(t *testing.T) {
testCtx, cancel := context.WithCancel(context.Background())
defer cancel()
- for i := 0; i < 50; i++ {
+ for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()