Fix race in ExecContext

When the context is cancelled, an interrupt should only be made if the
operation is still ongoing.
This commit is contained in:
Niklas Janlert 2017-11-21 13:40:00 +01:00
parent c41df79ec0
commit 58004848f1
2 changed files with 27 additions and 2 deletions

View File

@ -1171,9 +1171,13 @@ func (s *SQLiteStmt) exec(ctx context.Context, args []namedValue) (driver.Result
defer close(done) defer close(done)
go func(db *C.sqlite3) { go func(db *C.sqlite3) {
select { select {
case <-ctx.Done():
C.sqlite3_interrupt(db)
case <-done: case <-done:
case <-ctx.Done():
select {
case <-done:
default:
C.sqlite3_interrupt(db)
}
} }
}(s.c.db) }(s.c.db)

View File

@ -134,3 +134,24 @@ func TestShortTimeout(t *testing.T) {
t.Fatal(ctx.Err()) t.Fatal(ctx.Err())
} }
} }
func TestExecCancel(t *testing.T) {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
if _, err = db.Exec("create table foo (id integer primary key)"); err != nil {
t.Fatal(err)
}
for n := 0; n < 100; n++ {
ctx, cancel := context.WithCancel(context.Background())
_, err = db.ExecContext(ctx, "insert into foo (id) values (?)", n)
cancel()
if err != nil {
t.Fatal(err)
}
}
}