Skip to content

Commit b145008

Browse files
committed
Merge remote-tracking branch 'mattn/master' into merge-upstream-20250418
2 parents 126033a + f76bae4 commit b145008

File tree

7 files changed

+8965
-5264
lines changed

7 files changed

+8965
-5264
lines changed

callback.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,8 @@ func callbackRetText(ctx *C.sqlite3_context, v reflect.Value) error {
345345
if v.Type().Kind() != reflect.String {
346346
return fmt.Errorf("cannot convert %s to TEXT", v.Type())
347347
}
348-
C._sqlite3_result_text(ctx, C.CString(v.Interface().(string)))
348+
cstr := C.CString(v.Interface().(string))
349+
C._sqlite3_result_text(ctx, cstr)
349350
return nil
350351
}
351352

sqlite3-binding.c

Lines changed: 8510 additions & 5090 deletions
Large diffs are not rendered by default.

sqlite3-binding.h

Lines changed: 344 additions & 150 deletions
Large diffs are not rendered by default.

sqlite3.go

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
409409
type 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

419419
type 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
18951898
func (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.
19221953
func (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.
21392168
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()
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.
21622195
func (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 {
21742207
func (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
}

sqlite3_opt_unlock_notify.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55

66
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
77
#include <stdio.h>
8+
#ifndef USE_LIBSQLITE3
89
#include "sqlite3-binding.h"
10+
#else
11+
#include <sqlite3.h>
12+
#endif
913

1014
extern int unlock_notify_wait(sqlite3 *db);
1115

sqlite3_opt_unlock_notify.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ package sqlite3
1212
#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
1313
1414
#include <stdlib.h>
15+
#ifndef USE_LIBSQLITE3
1516
#include "sqlite3-binding.h"
17+
#else
18+
#include <sqlite3.h>
19+
#endif
1620
1721
extern void unlock_notify_callback(void *arg, int argc);
1822
*/

sqlite3_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,6 +1865,7 @@ func TestSetFileControlInt(t *testing.T) {
18651865
})
18661866
}
18671867

1868+
<<<<<<< HEAD
18681869
func TestDBConfigNoCkptOnClose(t *testing.T) {
18691870
fname := TempFilename(t)
18701871
defer os.Remove(fname)
@@ -1951,6 +1952,32 @@ func TestDBConfigNoCkptOnClose(t *testing.T) {
19511952
}
19521953
}
19531954

1955+
func TestSetFileControlInt64(t *testing.T) {
1956+
const GiB = 1024 * 1024 * 1024
1957+
1958+
t.Run("", func(t *testing.T) {
1959+
1960+
sql.Register("sqlite3_FCNTL_SIZE_LIMIT", &SQLiteDriver{
1961+
ConnectHook: func(conn *SQLiteConn) error {
1962+
if err := conn.SetFileControlInt64("", SQLITE_FCNTL_SIZE_LIMIT, 4*GiB); err != nil {
1963+
return fmt.Errorf("Unexpected error from SetFileControlInt64(): %w", err)
1964+
}
1965+
return nil
1966+
},
1967+
})
1968+
1969+
db, err := sql.Open("sqlite3", "file:/dbname?vfs=memdb")
1970+
if err != nil {
1971+
t.Fatal("Failed to open database:", err)
1972+
}
1973+
err = db.Ping()
1974+
if err != nil {
1975+
t.Fatal("Failed to ping", err)
1976+
}
1977+
db.Close()
1978+
})
1979+
}
1980+
19541981
func TestNonColumnString(t *testing.T) {
19551982
db, err := sql.Open("sqlite3", ":memory:")
19561983
if err != nil {
@@ -2198,6 +2225,7 @@ var benchmarks = []testing.InternalBenchmark{
21982225
{Name: "BenchmarkStmt", F: benchmarkStmt},
21992226
{Name: "BenchmarkRows", F: benchmarkRows},
22002227
{Name: "BenchmarkStmtRows", F: benchmarkStmtRows},
2228+
{Name: "BenchmarkQueryParallel", F: benchmarkQueryParallel},
22012229
}
22022230

22032231
func (db *TestDB) mustExec(sql string, args ...any) sql.Result {
@@ -2655,3 +2683,20 @@ func benchmarkStmtRows(b *testing.B) {
26552683
}
26562684
}
26572685
}
2686+
2687+
func benchmarkQueryParallel(b *testing.B) {
2688+
b.RunParallel(func(pb *testing.PB) {
2689+
db, err := sql.Open("sqlite3", ":memory:")
2690+
if err != nil {
2691+
panic(err)
2692+
}
2693+
db.SetMaxOpenConns(runtime.NumCPU())
2694+
defer db.Close()
2695+
var i int64
2696+
for pb.Next() {
2697+
if err := db.QueryRow("SELECT 1, 2, 3, 4").Scan(&i, &i, &i, &i); err != nil {
2698+
panic(err)
2699+
}
2700+
}
2701+
})
2702+
}

0 commit comments

Comments
 (0)