@@ -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 {
@@ -1846,22 +1846,7 @@ func (s *SQLiteStmt) query(ctx context.Context, args []namedValue) (driver.Rows,
1846
1846
decltype : nil ,
1847
1847
cls : s .cls ,
1848
1848
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 ,
1865
1850
}
1866
1851
1867
1852
return rows , nil
@@ -1889,29 +1874,43 @@ func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) {
1889
1874
return s .exec (context .Background (), list )
1890
1875
}
1891
1876
1877
+ // exec executes a query that doesn't return rows. Attempts to honor context timeout.
1892
1878
func (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 ) {
1893
1908
if err := s .bind (args ); err != nil {
1894
1909
C .sqlite3_reset (s .s )
1895
1910
C .sqlite3_clear_bindings (s .s )
1896
1911
return nil , err
1897
1912
}
1898
1913
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
-
1915
1914
var rowid , changes C.longlong
1916
1915
rv := C ._sqlite3_step_row_internal (s .s , & rowid , & changes )
1917
1916
if rv != C .SQLITE_ROW && rv != C .SQLITE_OK && rv != C .SQLITE_DONE {
@@ -1932,9 +1931,6 @@ func (rc *SQLiteRows) Close() error {
1932
1931
return nil
1933
1932
}
1934
1933
rc .closed = true
1935
- if rc .done != nil {
1936
- close (rc .done )
1937
- }
1938
1934
if rc .cls {
1939
1935
rc .s .mu .Unlock ()
1940
1936
return rc .s .Close ()
@@ -1978,13 +1974,39 @@ func (rc *SQLiteRows) DeclTypes() []string {
1978
1974
return rc .declTypes ()
1979
1975
}
1980
1976
1981
- // Next move cursor to next.
1977
+ // Next move cursor to next. Attempts to honor context timeout from QueryContext call.
1982
1978
func (rc * SQLiteRows ) Next (dest []driver.Value ) error {
1983
1979
rc .s .mu .Lock ()
1984
1980
defer rc .s .mu .Unlock ()
1981
+
1985
1982
if rc .s .closed {
1986
1983
return io .EOF
1987
1984
}
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 {
1988
2010
rv := C ._sqlite3_step_internal (rc .s .s )
1989
2011
if rv == C .SQLITE_DONE {
1990
2012
return io .EOF
0 commit comments