@@ -328,7 +328,7 @@ type SQLiteRows struct {
328
328
decltype []string
329
329
cls bool
330
330
closed bool
331
- done chan struct {}
331
+ ctx context. Context // no better alternative to pass context into Next() method
332
332
}
333
333
334
334
type functionInfo struct {
@@ -1847,22 +1847,7 @@ func (s *SQLiteStmt) query(ctx context.Context, args []namedValue) (driver.Rows,
1847
1847
decltype : nil ,
1848
1848
cls : s .cls ,
1849
1849
closed : false ,
1850
- done : make (chan struct {}),
1851
- }
1852
-
1853
- if ctxdone := ctx .Done (); ctxdone != nil {
1854
- go func (db * C.sqlite3 ) {
1855
- select {
1856
- case <- ctxdone :
1857
- select {
1858
- case <- rows .done :
1859
- default :
1860
- C .sqlite3_interrupt (db )
1861
- rows .Close ()
1862
- }
1863
- case <- rows .done :
1864
- }
1865
- }(s .c .db )
1850
+ ctx : ctx ,
1866
1851
}
1867
1852
1868
1853
return rows , nil
@@ -1890,29 +1875,43 @@ func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) {
1890
1875
return s .exec (context .Background (), list )
1891
1876
}
1892
1877
1878
+ // exec executes a query that doesn't return rows. Attempts to honor context timeout.
1893
1879
func (s * SQLiteStmt ) exec (ctx context.Context , args []namedValue ) (driver.Result , error ) {
1880
+ if ctx .Done () == nil {
1881
+ return s .execSync (args )
1882
+ }
1883
+
1884
+ type result struct {
1885
+ r driver.Result
1886
+ err error
1887
+ }
1888
+ resultCh := make (chan result )
1889
+ go func () {
1890
+ r , err := s .execSync (args )
1891
+ resultCh <- result {r , err }
1892
+ }()
1893
+ select {
1894
+ case rv := <- resultCh :
1895
+ return rv .r , rv .err
1896
+ case <- ctx .Done ():
1897
+ select {
1898
+ case <- resultCh : // no need to interrupt
1899
+ default :
1900
+ // this is still racy and can be no-op if executed between sqlite3_* calls in execSync.
1901
+ C .sqlite3_interrupt (s .c .db )
1902
+ <- resultCh // ensure goroutine completed
1903
+ }
1904
+ return nil , ctx .Err ()
1905
+ }
1906
+ }
1907
+
1908
+ func (s * SQLiteStmt ) execSync (args []namedValue ) (driver.Result , error ) {
1894
1909
if err := s .bind (args ); err != nil {
1895
1910
C .sqlite3_reset (s .s )
1896
1911
C .sqlite3_clear_bindings (s .s )
1897
1912
return nil , err
1898
1913
}
1899
1914
1900
- if ctxdone := ctx .Done (); ctxdone != nil {
1901
- done := make (chan struct {})
1902
- defer close (done )
1903
- go func (db * C.sqlite3 ) {
1904
- select {
1905
- case <- done :
1906
- case <- ctxdone :
1907
- select {
1908
- case <- done :
1909
- default :
1910
- C .sqlite3_interrupt (db )
1911
- }
1912
- }
1913
- }(s .c .db )
1914
- }
1915
-
1916
1915
var rowid , changes C.longlong
1917
1916
rv := C ._sqlite3_step_row_internal (s .s , & rowid , & changes )
1918
1917
if rv != C .SQLITE_ROW && rv != C .SQLITE_OK && rv != C .SQLITE_DONE {
@@ -1933,9 +1932,6 @@ func (rc *SQLiteRows) Close() error {
1933
1932
return nil
1934
1933
}
1935
1934
rc .closed = true
1936
- if rc .done != nil {
1937
- close (rc .done )
1938
- }
1939
1935
if rc .cls {
1940
1936
rc .s .mu .Unlock ()
1941
1937
return rc .s .Close ()
@@ -1979,13 +1975,39 @@ func (rc *SQLiteRows) DeclTypes() []string {
1979
1975
return rc .declTypes ()
1980
1976
}
1981
1977
1982
- // Next move cursor to next.
1978
+ // Next move cursor to next. Attempts to honor context timeout from QueryContext call.
1983
1979
func (rc * SQLiteRows ) Next (dest []driver.Value ) error {
1984
1980
rc .s .mu .Lock ()
1985
1981
defer rc .s .mu .Unlock ()
1982
+
1986
1983
if rc .s .closed {
1987
1984
return io .EOF
1988
1985
}
1986
+
1987
+ if rc .ctx .Done () == nil {
1988
+ return rc .nextSyncLocked (dest )
1989
+ }
1990
+ resultCh := make (chan error )
1991
+ go func () {
1992
+ resultCh <- rc .nextSyncLocked (dest )
1993
+ }()
1994
+ select {
1995
+ case err := <- resultCh :
1996
+ return err
1997
+ case <- rc .ctx .Done ():
1998
+ select {
1999
+ case <- resultCh : // no need to interrupt
2000
+ default :
2001
+ // this is still racy and can be no-op if executed between sqlite3_* calls in nextSyncLocked.
2002
+ C .sqlite3_interrupt (rc .s .c .db )
2003
+ <- resultCh // ensure goroutine completed
2004
+ }
2005
+ return rc .ctx .Err ()
2006
+ }
2007
+ }
2008
+
2009
+ // nextSyncLocked moves cursor to next; must be called with locked mutex.
2010
+ func (rc * SQLiteRows ) nextSyncLocked (dest []driver.Value ) error {
1989
2011
rv := C ._sqlite3_step_internal (rc .s .s )
1990
2012
if rv == C .SQLITE_DONE {
1991
2013
return io .EOF
0 commit comments