@@ -328,7 +328,7 @@ type SQLiteRows struct {
328328 decltype []string
329329 cls bool
330330 closed bool
331- done chan struct {}
331+ ctx context. Context // no better alternative to pass context into Next() method
332332}
333333
334334type functionInfo struct {
@@ -1846,22 +1846,7 @@ func (s *SQLiteStmt) query(ctx context.Context, args []namedValue) (driver.Rows,
18461846 decltype : nil ,
18471847 cls : s .cls ,
18481848 closed : false ,
1849- done : make (chan struct {}),
1850- }
1851-
1852- if ctxdone := ctx .Done (); ctxdone != nil {
1853- go func (db * C.sqlite3 ) {
1854- select {
1855- case <- ctxdone :
1856- select {
1857- case <- rows .done :
1858- default :
1859- C .sqlite3_interrupt (db )
1860- rows .Close ()
1861- }
1862- case <- rows .done :
1863- }
1864- }(s .c .db )
1849+ ctx : ctx ,
18651850 }
18661851
18671852 return rows , nil
@@ -1889,29 +1874,43 @@ func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) {
18891874 return s .exec (context .Background (), list )
18901875}
18911876
1877+ // exec executes a query that doesn't return rows. Attempts to honor context timeout.
18921878func (s * SQLiteStmt ) exec (ctx context.Context , args []namedValue ) (driver.Result , error ) {
1879+ if ctx .Done () == nil {
1880+ return s .execSync (args )
1881+ }
1882+
1883+ type result struct {
1884+ r driver.Result
1885+ err error
1886+ }
1887+ resultCh := make (chan result )
1888+ go func () {
1889+ r , err := s .execSync (args )
1890+ resultCh <- result {r , err }
1891+ }()
1892+ select {
1893+ case rv := <- resultCh :
1894+ return rv .r , rv .err
1895+ case <- ctx .Done ():
1896+ select {
1897+ case <- resultCh : // no need to interrupt
1898+ default :
1899+ // this is still racy and can be no-op if executed between sqlite3_* calls in execSync.
1900+ C .sqlite3_interrupt (s .c .db )
1901+ <- resultCh // ensure goroutine completed
1902+ }
1903+ return nil , ctx .Err ()
1904+ }
1905+ }
1906+
1907+ func (s * SQLiteStmt ) execSync (args []namedValue ) (driver.Result , error ) {
18931908 if err := s .bind (args ); err != nil {
18941909 C .sqlite3_reset (s .s )
18951910 C .sqlite3_clear_bindings (s .s )
18961911 return nil , err
18971912 }
18981913
1899- if ctxdone := ctx .Done (); ctxdone != nil {
1900- done := make (chan struct {})
1901- defer close (done )
1902- go func (db * C.sqlite3 ) {
1903- select {
1904- case <- done :
1905- case <- ctxdone :
1906- select {
1907- case <- done :
1908- default :
1909- C .sqlite3_interrupt (db )
1910- }
1911- }
1912- }(s .c .db )
1913- }
1914-
19151914 var rowid , changes C.longlong
19161915 rv := C ._sqlite3_step_row_internal (s .s , & rowid , & changes )
19171916 if rv != C .SQLITE_ROW && rv != C .SQLITE_OK && rv != C .SQLITE_DONE {
@@ -1932,9 +1931,6 @@ func (rc *SQLiteRows) Close() error {
19321931 return nil
19331932 }
19341933 rc .closed = true
1935- if rc .done != nil {
1936- close (rc .done )
1937- }
19381934 if rc .cls {
19391935 rc .s .mu .Unlock ()
19401936 return rc .s .Close ()
@@ -1978,13 +1974,39 @@ func (rc *SQLiteRows) DeclTypes() []string {
19781974 return rc .declTypes ()
19791975}
19801976
1981- // Next move cursor to next.
1977+ // Next move cursor to next. Attempts to honor context timeout from QueryContext call.
19821978func (rc * SQLiteRows ) Next (dest []driver.Value ) error {
19831979 rc .s .mu .Lock ()
19841980 defer rc .s .mu .Unlock ()
1981+
19851982 if rc .s .closed {
19861983 return io .EOF
19871984 }
1985+
1986+ if rc .ctx .Done () == nil {
1987+ return rc .nextSyncLocked (dest )
1988+ }
1989+ resultCh := make (chan error )
1990+ go func () {
1991+ resultCh <- rc .nextSyncLocked (dest )
1992+ }()
1993+ select {
1994+ case err := <- resultCh :
1995+ return err
1996+ case <- rc .ctx .Done ():
1997+ select {
1998+ case <- resultCh : // no need to interrupt
1999+ default :
2000+ // this is still racy and can be no-op if executed between sqlite3_* calls in nextSyncLocked.
2001+ C .sqlite3_interrupt (rc .s .c .db )
2002+ <- resultCh // ensure goroutine completed
2003+ }
2004+ return rc .ctx .Err ()
2005+ }
2006+ }
2007+
2008+ // nextSyncLocked moves cursor to next; must be called with locked mutex.
2009+ func (rc * SQLiteRows ) nextSyncLocked (dest []driver.Value ) error {
19882010 rv := C ._sqlite3_step_internal (rc .s .s )
19892011 if rv == C .SQLITE_DONE {
19902012 return io .EOF
0 commit comments