mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Use finalizers to detect unclosed connections.
This commit is contained in:
@@ -59,7 +59,7 @@ As a work around for other Unixes, you can use [`nolock=1`](https://www.sqlite.o
|
||||
- [ ] snapshots
|
||||
- [ ] session extension
|
||||
- [ ] resumable bulk update
|
||||
- [ ] shared cache mode
|
||||
- [ ] shared-cache mode
|
||||
- [ ] unlock-notify
|
||||
- [ ] custom SQL functions
|
||||
- [ ] custom VFSes
|
||||
|
||||
1
blob.go
1
blob.go
@@ -8,7 +8,6 @@ import "io"
|
||||
type ZeroBlob int64
|
||||
|
||||
// Blob is a handle to an open BLOB.
|
||||
//
|
||||
// It implements [io.ReadWriteSeeker] for incremental BLOB I/O.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/blob.html
|
||||
|
||||
16
conn.go
16
conn.go
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
@@ -30,8 +31,8 @@ type Conn struct {
|
||||
}
|
||||
|
||||
// Open calls [OpenFlags] with [OPEN_READWRITE], [OPEN_CREATE] and [OPEN_URI].
|
||||
func Open(filename string) (conn *Conn, err error) {
|
||||
return OpenFlags(filename, OPEN_READWRITE|OPEN_CREATE|OPEN_URI)
|
||||
func Open(filename string) (*Conn, error) {
|
||||
return openFlags(filename, OPEN_READWRITE|OPEN_CREATE|OPEN_URI)
|
||||
}
|
||||
|
||||
// OpenFlags opens an SQLite database file as specified by the filename argument.
|
||||
@@ -41,7 +42,11 @@ func Open(filename string) (conn *Conn, err error) {
|
||||
// sqlite3.Open("file:demo.db?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)")
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/open.html
|
||||
func OpenFlags(filename string, flags OpenFlag) (conn *Conn, err error) {
|
||||
func OpenFlags(filename string, flags OpenFlag) (*Conn, error) {
|
||||
return openFlags(filename, flags)
|
||||
}
|
||||
|
||||
func openFlags(filename string, flags OpenFlag) (conn *Conn, err error) {
|
||||
ctx := context.Background()
|
||||
module, err := sqlite3.instantiateModule(ctx)
|
||||
if err != nil {
|
||||
@@ -50,6 +55,8 @@ func OpenFlags(filename string, flags OpenFlag) (conn *Conn, err error) {
|
||||
defer func() {
|
||||
if conn == nil {
|
||||
module.Close(ctx)
|
||||
} else {
|
||||
runtime.SetFinalizer(conn, finalizer[Conn](3))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -109,6 +116,7 @@ func (c *Conn) Close() error {
|
||||
}
|
||||
|
||||
c.handle = 0
|
||||
runtime.SetFinalizer(c, nil)
|
||||
return c.mem.mod.Close(c.ctx)
|
||||
}
|
||||
|
||||
@@ -133,9 +141,11 @@ func (c *Conn) MustPrepare(sql string) *Stmt {
|
||||
panic(err)
|
||||
}
|
||||
if s == nil {
|
||||
s.Close()
|
||||
panic(emptyErr)
|
||||
}
|
||||
if !emptyStatement(tail) {
|
||||
s.Close()
|
||||
panic(tailErr)
|
||||
}
|
||||
return s
|
||||
|
||||
9
error.go
9
error.go
@@ -1,6 +1,7 @@
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -215,3 +216,11 @@ func assertErr() errorString {
|
||||
}
|
||||
return errorString(msg)
|
||||
}
|
||||
|
||||
func finalizer[T any](skip int) func(*T) {
|
||||
msg := fmt.Sprintf("sqlite3: %T not closed", new(T))
|
||||
if _, file, line, ok := runtime.Caller(skip + 1); ok && skip >= 0 {
|
||||
msg += " (" + file + ":" + strconv.Itoa(line) + ")"
|
||||
}
|
||||
return func(*T) { panic(errorString(msg)) }
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ func TestConn_Transaction_exec(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
if stmt.Step() {
|
||||
return stmt.ColumnInt(0)
|
||||
}
|
||||
@@ -117,6 +118,7 @@ func TestConn_Transaction_panic(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
if stmt.Step() {
|
||||
got := stmt.ColumnInt(0)
|
||||
if got != 1 {
|
||||
@@ -275,6 +277,7 @@ func TestConn_Savepoint_exec(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
if stmt.Step() {
|
||||
return stmt.ColumnInt(0)
|
||||
}
|
||||
@@ -361,6 +364,7 @@ func TestConn_Savepoint_panic(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
if stmt.Step() {
|
||||
got := stmt.ColumnInt(0)
|
||||
if got != 1 {
|
||||
|
||||
Reference in New Issue
Block a user