From 348128fdcf102af8b9f51fb26ae41c4d7438f1ca Mon Sep 17 00:00:00 2001 From: Jonathan Stacks Date: Tue, 26 Nov 2024 09:16:45 -0600 Subject: [PATCH 1/4] Upgrade upload-artifact action action/upload-artifact@v1 has been deprecated for a while. It seems like GitHub Actions will now cancel workflows if it is still using v1 of the action. This upgrades to the latest v4 of the action. See https://github.blog/news-insights/product-news/get-started-with-v4-of-github-actions-artifacts/ for details. --- .github/workflows/cifuzz.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cifuzz.yaml b/.github/workflows/cifuzz.yaml index e198c526..f9237457 100644 --- a/.github/workflows/cifuzz.yaml +++ b/.github/workflows/cifuzz.yaml @@ -22,7 +22,7 @@ jobs: dry-run: false sanitizer: ${{ matrix.sanitizer }} - name: Upload Crash - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 if: failure() with: name: ${{ matrix.sanitizer }}-artifacts From ab13d63ae7ac3bf4ace391fbbde6bfb12d7bdf2e Mon Sep 17 00:00:00 2001 From: Sam Jewell <2903904+samjewell@users.noreply.github.com> Date: Thu, 5 Dec 2024 01:38:50 +0000 Subject: [PATCH 2/4] Remove suggestion that CGO isn't always needed (#1290) Fixes #855 --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 1804a89a..c0da33bc 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,6 @@ This package can be installed with the `go get` command: _go-sqlite3_ is *cgo* package. If you want to build your app using go-sqlite3, you need gcc. -However, after you have built and installed _go-sqlite3_ with `go install github.com/mattn/go-sqlite3` (which requires gcc), you can build your app without relying on gcc in future. ***Important: because this is a `CGO` enabled package, you are required to set the environment variable `CGO_ENABLED=1` and have a `gcc` compiler present within your path.*** From c61eeb5d1d1c99a2bf613fcc598a63a10a707efa Mon Sep 17 00:00:00 2001 From: Charlie Vieth Date: Sat, 7 Dec 2024 20:23:58 -0500 Subject: [PATCH 3/4] remove superfluous use of runtime.SetFinalizer on SQLiteRows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit removes the use of runtime.SetFinalizer to finalize SQLiteRows since only serves to close the associated SQLiteStmt which already has a registered finalizer. It also fixes a race and potential panic in SQLiteRows.Close around the SQLiteRows.s field (*SQLiteStmt) which is accessed without a mutex being held, but modified with it held (null'd out). Further the mutex we are holding is that of the SQLiteStmt so a subsequent call to Close will cause a panic sine it'll attempt to dereference a nil field. The fix here is to add a mutex for closing to SQLiteRows. Since we now also set the s field to nil when closing this commit removes the "closed" field (since checking if s is nil is the same) and also changes the type of "nc" (number of columns) to an int32 so that we can pack the nc and cls fields, and add the close mutex without making the struct any bigger. ``` goos: darwin goarch: arm64 pkg: github.com/charlievieth/go-sqlite3 cpu: Apple M4 Pro │ x1.txt │ x4.txt │ │ sec/op │ sec/op vs base │ Suite/BenchmarkExec/Params-14 719.2n ± 2% 716.9n ± 1% ~ (p=0.897 n=10) Suite/BenchmarkExec/NoParams-14 506.5n ± 3% 500.1n ± 0% -1.25% (p=0.002 n=10) Suite/BenchmarkExecContext/Params-14 1.584µ ± 0% 1.567µ ± 1% -1.07% (p=0.007 n=10) Suite/BenchmarkExecContext/NoParams-14 1.524µ ± 1% 1.524µ ± 1% ~ (p=0.539 n=10) Suite/BenchmarkExecStep-14 443.9µ ± 3% 441.4µ ± 0% -0.55% (p=0.011 n=10) Suite/BenchmarkExecContextStep-14 447.8µ ± 1% 442.9µ ± 0% -1.10% (p=0.000 n=10) Suite/BenchmarkExecTx-14 1.643µ ± 1% 1.640µ ± 0% ~ (p=0.642 n=10) Suite/BenchmarkQuery-14 1.968µ ± 3% 1.821µ ± 1% -7.52% (p=0.000 n=10) Suite/BenchmarkQuerySimple-14 1.207µ ± 2% 1.040µ ± 1% -13.84% (p=0.000 n=10) Suite/BenchmarkQueryContext/Background-14 2.400µ ± 1% 2.320µ ± 0% -3.31% (p=0.000 n=10) Suite/BenchmarkQueryContext/WithCancel-14 8.847µ ± 5% 8.512µ ± 4% -3.79% (p=0.007 n=10) Suite/BenchmarkParams-14 2.131µ ± 2% 1.967µ ± 1% -7.70% (p=0.000 n=10) Suite/BenchmarkStmt-14 1.444µ ± 1% 1.359µ ± 1% -5.89% (p=0.000 n=10) Suite/BenchmarkRows-14 61.57µ ± 1% 60.24µ ± 1% -2.16% (p=0.000 n=10) Suite/BenchmarkStmtRows-14 60.15µ ± 1% 59.08µ ± 1% -1.78% (p=0.000 n=10) Suite/BenchmarkQueryParallel-14 960.9n ± 1% 420.8n ± 2% -56.21% (p=0.000 n=10) geomean 4.795µ 4.430µ -7.62% ``` --- sqlite3.go | 48 +++++++++++++++++++++++++----------------------- sqlite3_test.go | 18 ++++++++++++++++++ 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/sqlite3.go b/sqlite3.go index ce985ec8..3025a500 100644 --- a/sqlite3.go +++ b/sqlite3.go @@ -381,7 +381,7 @@ type SQLiteStmt struct { s *C.sqlite3_stmt t string closed bool - cls bool + cls bool // True if the statement was created by SQLiteConn.Query } // SQLiteResult implements sql.Result. @@ -393,12 +393,12 @@ type SQLiteResult struct { // SQLiteRows implements driver.Rows. type SQLiteRows struct { s *SQLiteStmt - nc int + nc int32 // Number of columns + cls bool // True if we need to close the parent statement in Close cols []string decltype []string - cls bool - closed bool ctx context.Context // no better alternative to pass context into Next() method + closemu sync.Mutex } type functionInfo struct { @@ -2008,14 +2008,12 @@ func (s *SQLiteStmt) query(ctx context.Context, args []driver.NamedValue) (drive rows := &SQLiteRows{ s: s, - nc: int(C.sqlite3_column_count(s.s)), + nc: int32(C.sqlite3_column_count(s.s)), + cls: s.cls, cols: nil, decltype: nil, - cls: s.cls, - closed: false, ctx: ctx, } - runtime.SetFinalizer(rows, (*SQLiteRows).Close) return rows, nil } @@ -2112,24 +2110,28 @@ func (s *SQLiteStmt) Readonly() bool { // Close the rows. func (rc *SQLiteRows) Close() error { - rc.s.mu.Lock() - if rc.s.closed || rc.closed { - rc.s.mu.Unlock() + rc.closemu.Lock() + defer rc.closemu.Unlock() + s := rc.s + if s == nil { + return nil + } + rc.s = nil // remove reference to SQLiteStmt + s.mu.Lock() + if s.closed { + s.mu.Unlock() return nil } - rc.closed = true if rc.cls { - rc.s.mu.Unlock() - return rc.s.Close() + s.mu.Unlock() + return s.Close() } - rv := C.sqlite3_reset(rc.s.s) + rv := C.sqlite3_reset(s.s) if rv != C.SQLITE_OK { - rc.s.mu.Unlock() - return rc.s.c.lastError() + s.mu.Unlock() + return s.c.lastError() } - rc.s.mu.Unlock() - rc.s = nil - runtime.SetFinalizer(rc, nil) + s.mu.Unlock() return nil } @@ -2137,9 +2139,9 @@ func (rc *SQLiteRows) Close() error { func (rc *SQLiteRows) Columns() []string { rc.s.mu.Lock() defer rc.s.mu.Unlock() - if rc.s.s != nil && rc.nc != len(rc.cols) { + if rc.s.s != nil && int(rc.nc) != len(rc.cols) { rc.cols = make([]string, rc.nc) - for i := 0; i < rc.nc; i++ { + for i := 0; i < int(rc.nc); i++ { rc.cols[i] = C.GoString(C.sqlite3_column_name(rc.s.s, C.int(i))) } } @@ -2149,7 +2151,7 @@ func (rc *SQLiteRows) Columns() []string { func (rc *SQLiteRows) declTypes() []string { if rc.s.s != nil && rc.decltype == nil { rc.decltype = make([]string, rc.nc) - for i := 0; i < rc.nc; i++ { + for i := 0; i < int(rc.nc); i++ { rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i)))) } } diff --git a/sqlite3_test.go b/sqlite3_test.go index 63c939d3..94de7386 100644 --- a/sqlite3_test.go +++ b/sqlite3_test.go @@ -2111,6 +2111,7 @@ var benchmarks = []testing.InternalBenchmark{ {Name: "BenchmarkStmt", F: benchmarkStmt}, {Name: "BenchmarkRows", F: benchmarkRows}, {Name: "BenchmarkStmtRows", F: benchmarkStmtRows}, + {Name: "BenchmarkQueryParallel", F: benchmarkQueryParallel}, } func (db *TestDB) mustExec(sql string, args ...any) sql.Result { @@ -2568,3 +2569,20 @@ func benchmarkStmtRows(b *testing.B) { } } } + +func benchmarkQueryParallel(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + db.SetMaxOpenConns(runtime.NumCPU()) + defer db.Close() + var i int64 + for pb.Next() { + if err := db.QueryRow("SELECT 1, 2, 3, 4").Scan(&i, &i, &i, &i); err != nil { + panic(err) + } + } + }) +} From 7658c06970ecf5588d8cd930ed1f2de7223f1010 Mon Sep 17 00:00:00 2001 From: nina Date: Mon, 9 Dec 2024 05:36:34 +0100 Subject: [PATCH 4/4] Fix sqlite3_opt_unlock_notify with USE_LIBSQLITE3 (#1262) A valid sqlite header must always be included (like in the other files) but sqlite3-binding.h explicitly guards against the system library case. --- sqlite3_opt_unlock_notify.c | 4 ++++ sqlite3_opt_unlock_notify.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/sqlite3_opt_unlock_notify.c b/sqlite3_opt_unlock_notify.c index fc37b336..3a00f43d 100644 --- a/sqlite3_opt_unlock_notify.c +++ b/sqlite3_opt_unlock_notify.c @@ -5,7 +5,11 @@ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY #include +#ifndef USE_LIBSQLITE3 #include "sqlite3-binding.h" +#else +#include +#endif extern int unlock_notify_wait(sqlite3 *db); diff --git a/sqlite3_opt_unlock_notify.go b/sqlite3_opt_unlock_notify.go index 76f7bbfb..3ac8050a 100644 --- a/sqlite3_opt_unlock_notify.go +++ b/sqlite3_opt_unlock_notify.go @@ -12,7 +12,11 @@ package sqlite3 #cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY #include +#ifndef USE_LIBSQLITE3 #include "sqlite3-binding.h" +#else +#include +#endif extern void unlock_notify_callback(void *arg, int argc); */