@@ -396,7 +396,7 @@ type SQLiteStmt struct {
396396 s * C.sqlite3_stmt
397397 t string
398398 closed bool
399- cls bool
399+ cls bool // True if the statement was created by SQLiteConn.Query
400400}
401401
402402// SQLiteResult implements sql.Result.
@@ -408,12 +408,12 @@ type SQLiteResult struct {
408408// SQLiteRows implements driver.Rows.
409409type SQLiteRows struct {
410410 s * SQLiteStmt
411- nc int
411+ nc int32 // Number of columns
412+ cls bool // True if we need to close the parent statement in Close
412413 cols []string
413414 decltype []string
414- cls bool
415- closed bool
416415 ctx context.Context // no better alternative to pass context into Next() method
416+ closemu sync.Mutex
417417}
418418
419419type functionInfo struct {
@@ -1891,6 +1891,9 @@ func (c *SQLiteConn) SetLimit(id int, newVal int) int {
18911891// This method is not thread-safe as the returned error code can be changed by
18921892// another call if invoked concurrently.
18931893//
1894+ // Use SetFileControlInt64 instead if the argument for the opcode is documented
1895+ // as a pointer to a sqlite3_int64.
1896+ //
18941897// See: sqlite3_file_control, https://www.sqlite.org/c3ref/file_control.html
18951898func (c * SQLiteConn ) SetFileControlInt (dbName string , op int , arg int ) error {
18961899 if dbName == "" {
@@ -1918,6 +1921,34 @@ func (c *SQLiteConn) DBConfigNoCkptOnClose() error {
19181921 return nil
19191922}
19201923
1924+ // SetFileControlInt64 invokes the xFileControl method on a given database. The
1925+ // dbName is the name of the database. It will default to "main" if left blank.
1926+ // The op is one of the opcodes prefixed by "SQLITE_FCNTL_". The arg argument
1927+ // and return code are both opcode-specific. Please see the SQLite documentation.
1928+ //
1929+ // This method is not thread-safe as the returned error code can be changed by
1930+ // another call if invoked concurrently.
1931+ //
1932+ // Only use this method if the argument for the opcode is documented as a pointer
1933+ // to a sqlite3_int64.
1934+ //
1935+ // See: sqlite3_file_control, https://www.sqlite.org/c3ref/file_control.html
1936+ func (c * SQLiteConn ) SetFileControlInt64 (dbName string , op int , arg int64 ) error {
1937+ if dbName == "" {
1938+ dbName = "main"
1939+ }
1940+
1941+ cDBName := C .CString (dbName )
1942+ defer C .free (unsafe .Pointer (cDBName ))
1943+
1944+ cArg := C .sqlite3_int64 (arg )
1945+ rv := C .sqlite3_file_control (c .db , cDBName , C .int (op ), unsafe .Pointer (& cArg ))
1946+ if rv != C .SQLITE_OK {
1947+ return c .lastError ()
1948+ }
1949+ return nil
1950+ }
1951+
19211952// Close the statement.
19221953func (s * SQLiteStmt ) Close () error {
19231954 s .mu .Lock ()
@@ -2033,14 +2064,12 @@ func (s *SQLiteStmt) query(ctx context.Context, args []driver.NamedValue) (drive
20332064
20342065 rows := & SQLiteRows {
20352066 s : s ,
2036- nc : int (C .sqlite3_column_count (s .s )),
2067+ nc : int32 (C .sqlite3_column_count (s .s )),
2068+ cls : s .cls ,
20372069 cols : nil ,
20382070 decltype : nil ,
2039- cls : s .cls ,
2040- closed : false ,
20412071 ctx : ctx ,
20422072 }
2043- runtime .SetFinalizer (rows , (* SQLiteRows ).Close )
20442073
20452074 return rows , nil
20462075}
@@ -2137,34 +2166,38 @@ func (s *SQLiteStmt) Readonly() bool {
21372166
21382167// Close the rows.
21392168func (rc * SQLiteRows ) Close () error {
2140- rc .s .mu .Lock ()
2141- if rc .s .closed || rc .closed {
2142- rc .s .mu .Unlock ()
2169+ rc .closemu .Lock ()
2170+ defer rc .closemu .Unlock ()
2171+ s := rc .s
2172+ if s == nil {
2173+ return nil
2174+ }
2175+ rc .s = nil // remove reference to SQLiteStmt
2176+ s .mu .Lock ()
2177+ if s .closed {
2178+ s .mu .Unlock ()
21432179 return nil
21442180 }
2145- rc .closed = true
21462181 if rc .cls {
2147- rc . s .mu .Unlock ()
2148- return rc . s .Close ()
2182+ s .mu .Unlock ()
2183+ return s .Close ()
21492184 }
2150- rv := C .sqlite3_reset (rc . s .s )
2185+ rv := C .sqlite3_reset (s .s )
21512186 if rv != C .SQLITE_OK {
2152- rc . s .mu .Unlock ()
2153- return rc . s .c .lastError ()
2187+ s .mu .Unlock ()
2188+ return s .c .lastError ()
21542189 }
2155- rc .s .mu .Unlock ()
2156- rc .s = nil
2157- runtime .SetFinalizer (rc , nil )
2190+ s .mu .Unlock ()
21582191 return nil
21592192}
21602193
21612194// Columns return column names.
21622195func (rc * SQLiteRows ) Columns () []string {
21632196 rc .s .mu .Lock ()
21642197 defer rc .s .mu .Unlock ()
2165- if rc .s .s != nil && rc .nc != len (rc .cols ) {
2198+ if rc .s .s != nil && int ( rc .nc ) != len (rc .cols ) {
21662199 rc .cols = make ([]string , rc .nc )
2167- for i := 0 ; i < rc .nc ; i ++ {
2200+ for i := 0 ; i < int ( rc .nc ) ; i ++ {
21682201 rc .cols [i ] = C .GoString (C .sqlite3_column_name (rc .s .s , C .int (i )))
21692202 }
21702203 }
@@ -2174,7 +2207,7 @@ func (rc *SQLiteRows) Columns() []string {
21742207func (rc * SQLiteRows ) declTypes () []string {
21752208 if rc .s .s != nil && rc .decltype == nil {
21762209 rc .decltype = make ([]string , rc .nc )
2177- for i := 0 ; i < rc .nc ; i ++ {
2210+ for i := 0 ; i < int ( rc .nc ) ; i ++ {
21782211 rc .decltype [i ] = strings .ToLower (C .GoString (C .sqlite3_column_decltype (rc .s .s , C .int (i ))))
21792212 }
21802213 }
0 commit comments