@@ -396,7 +396,7 @@ type SQLiteStmt struct {
396
396
s * C.sqlite3_stmt
397
397
t string
398
398
closed bool
399
- cls bool
399
+ cls bool // True if the statement was created by SQLiteConn.Query
400
400
}
401
401
402
402
// SQLiteResult implements sql.Result.
@@ -408,12 +408,12 @@ type SQLiteResult struct {
408
408
// SQLiteRows implements driver.Rows.
409
409
type SQLiteRows struct {
410
410
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
412
413
cols []string
413
414
decltype []string
414
- cls bool
415
- closed bool
416
415
ctx context.Context // no better alternative to pass context into Next() method
416
+ closemu sync.Mutex
417
417
}
418
418
419
419
type functionInfo struct {
@@ -1891,6 +1891,9 @@ func (c *SQLiteConn) SetLimit(id int, newVal int) int {
1891
1891
// This method is not thread-safe as the returned error code can be changed by
1892
1892
// another call if invoked concurrently.
1893
1893
//
1894
+ // Use SetFileControlInt64 instead if the argument for the opcode is documented
1895
+ // as a pointer to a sqlite3_int64.
1896
+ //
1894
1897
// See: sqlite3_file_control, https://www.sqlite.org/c3ref/file_control.html
1895
1898
func (c * SQLiteConn ) SetFileControlInt (dbName string , op int , arg int ) error {
1896
1899
if dbName == "" {
@@ -1918,6 +1921,34 @@ func (c *SQLiteConn) DBConfigNoCkptOnClose() error {
1918
1921
return nil
1919
1922
}
1920
1923
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
+
1921
1952
// Close the statement.
1922
1953
func (s * SQLiteStmt ) Close () error {
1923
1954
s .mu .Lock ()
@@ -2033,14 +2064,12 @@ func (s *SQLiteStmt) query(ctx context.Context, args []driver.NamedValue) (drive
2033
2064
2034
2065
rows := & SQLiteRows {
2035
2066
s : s ,
2036
- nc : int (C .sqlite3_column_count (s .s )),
2067
+ nc : int32 (C .sqlite3_column_count (s .s )),
2068
+ cls : s .cls ,
2037
2069
cols : nil ,
2038
2070
decltype : nil ,
2039
- cls : s .cls ,
2040
- closed : false ,
2041
2071
ctx : ctx ,
2042
2072
}
2043
- runtime .SetFinalizer (rows , (* SQLiteRows ).Close )
2044
2073
2045
2074
return rows , nil
2046
2075
}
@@ -2137,34 +2166,38 @@ func (s *SQLiteStmt) Readonly() bool {
2137
2166
2138
2167
// Close the rows.
2139
2168
func (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 ()
2143
2179
return nil
2144
2180
}
2145
- rc .closed = true
2146
2181
if rc .cls {
2147
- rc . s .mu .Unlock ()
2148
- return rc . s .Close ()
2182
+ s .mu .Unlock ()
2183
+ return s .Close ()
2149
2184
}
2150
- rv := C .sqlite3_reset (rc . s .s )
2185
+ rv := C .sqlite3_reset (s .s )
2151
2186
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 ()
2154
2189
}
2155
- rc .s .mu .Unlock ()
2156
- rc .s = nil
2157
- runtime .SetFinalizer (rc , nil )
2190
+ s .mu .Unlock ()
2158
2191
return nil
2159
2192
}
2160
2193
2161
2194
// Columns return column names.
2162
2195
func (rc * SQLiteRows ) Columns () []string {
2163
2196
rc .s .mu .Lock ()
2164
2197
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 ) {
2166
2199
rc .cols = make ([]string , rc .nc )
2167
- for i := 0 ; i < rc .nc ; i ++ {
2200
+ for i := 0 ; i < int ( rc .nc ) ; i ++ {
2168
2201
rc .cols [i ] = C .GoString (C .sqlite3_column_name (rc .s .s , C .int (i )))
2169
2202
}
2170
2203
}
@@ -2174,7 +2207,7 @@ func (rc *SQLiteRows) Columns() []string {
2174
2207
func (rc * SQLiteRows ) declTypes () []string {
2175
2208
if rc .s .s != nil && rc .decltype == nil {
2176
2209
rc .decltype = make ([]string , rc .nc )
2177
- for i := 0 ; i < rc .nc ; i ++ {
2210
+ for i := 0 ; i < int ( rc .nc ) ; i ++ {
2178
2211
rc .decltype [i ] = strings .ToLower (C .GoString (C .sqlite3_column_decltype (rc .s .s , C .int (i ))))
2179
2212
}
2180
2213
}
0 commit comments