Skip to content

Commit 4f27a02

Browse files
committed
make sure Close always removes the runtime finalizer
This commit fixes a bug in {SQLiteConn,SQLiteStmt}.Close that would lead to the runtime finalizer not being removed if there was an error closing the connection or statement. This commit also makes it safe to call SQLiteConn.Close multiple times.
1 parent 7658c06 commit 4f27a02

9 files changed

+111
-78
lines changed

backup.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ func (destConn *SQLiteConn) Backup(dest string, srcConn *SQLiteConn, src string)
3636
runtime.SetFinalizer(bb, (*SQLiteBackup).Finish)
3737
return bb, nil
3838
}
39-
return nil, destConn.lastError()
39+
if destConn.db != nil {
40+
return nil, destConn.lastError(int(C.sqlite3_extended_errcode(destConn.db)))
41+
}
42+
return nil, Error{Code: 1, ExtendedCode: 1, err: "backup: destination connection is nil"}
4043
}
4144

4245
// Step to backs up for one step. Calls the underlying `sqlite3_backup_step`

error.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@ package sqlite3
1313
#endif
1414
*/
1515
import "C"
16-
import "syscall"
16+
import (
17+
"sync"
18+
"syscall"
19+
)
1720

1821
// ErrNo inherit errno.
1922
type ErrNo int
2023

2124
// ErrNoMask is mask code.
22-
const ErrNoMask C.int = 0xff
25+
const ErrNoMask = 0xff
2326

2427
// ErrNoExtended is extended errno.
2528
type ErrNoExtended int
@@ -85,7 +88,7 @@ func (err Error) Error() string {
8588
if err.err != "" {
8689
str = err.err
8790
} else {
88-
str = C.GoString(C.sqlite3_errstr(C.int(err.Code)))
91+
str = errorString(int(err.Code))
8992
}
9093
if err.SystemErrno != 0 {
9194
str += ": " + err.SystemErrno.Error()
@@ -148,3 +151,18 @@ var (
148151
ErrNoticeRecoverRollback = ErrNotice.Extend(2)
149152
ErrWarningAutoIndex = ErrWarning.Extend(1)
150153
)
154+
155+
var errStrCache sync.Map // int => string
156+
157+
// errorString returns the result of sqlite3_errstr for result code
158+
// rv which may be cached.
159+
func errorString(rv int) string {
160+
if v, ok := errStrCache.Load(rv); ok {
161+
return v.(string)
162+
}
163+
s := C.GoString(C.sqlite3_errstr(C.int(rv)))
164+
if v, loaded := errStrCache.LoadOrStore(rv, s); loaded {
165+
return v.(string)
166+
}
167+
return s
168+
}

sqlite3.go

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ func (c *SQLiteConn) RegisterCollation(name string, cmp func(string, string) int
540540
defer C.free(unsafe.Pointer(cname))
541541
rv := C.sqlite3_create_collation(c.db, cname, C.SQLITE_UTF8, handle, (*[0]byte)(unsafe.Pointer(C.compareTrampoline)))
542542
if rv != C.SQLITE_OK {
543-
return c.lastError()
543+
return c.lastError(int(rv))
544544
}
545545
return nil
546546
}
@@ -675,7 +675,7 @@ func (c *SQLiteConn) RegisterFunc(name string, impl any, pure bool) error {
675675
}
676676
rv := sqlite3CreateFunction(c.db, cname, C.int(numArgs), C.int(opts), newHandle(c, &fi), C.callbackTrampoline, nil, nil)
677677
if rv != C.SQLITE_OK {
678-
return c.lastError()
678+
return c.lastError(int(rv))
679679
}
680680
return nil
681681
}
@@ -804,7 +804,7 @@ func (c *SQLiteConn) RegisterAggregator(name string, impl any, pure bool) error
804804
}
805805
rv := sqlite3CreateFunction(c.db, cname, C.int(stepNArgs), C.int(opts), newHandle(c, &ai), nil, C.stepTrampoline, C.doneTrampoline)
806806
if rv != C.SQLITE_OK {
807-
return c.lastError()
807+
return c.lastError(int(rv))
808808
}
809809
return nil
810810
}
@@ -816,32 +816,38 @@ func (c *SQLiteConn) AutoCommit() bool {
816816
return int(C.sqlite3_get_autocommit(c.db)) != 0
817817
}
818818

819-
func (c *SQLiteConn) lastError() error {
820-
return lastError(c.db)
819+
func (c *SQLiteConn) lastError(rv int) error {
820+
return lastError(c.db, rv)
821821
}
822822

823-
// Note: may be called with db == nil
824-
func lastError(db *C.sqlite3) error {
825-
rv := C.sqlite3_errcode(db) // returns SQLITE_NOMEM if db == nil
826-
if rv == C.SQLITE_OK {
823+
func lastError(db *C.sqlite3, rv int) error {
824+
if rv == SQLITE_OK {
827825
return nil
828826
}
829-
extrv := C.sqlite3_extended_errcode(db) // returns SQLITE_NOMEM if db == nil
830-
errStr := C.GoString(C.sqlite3_errmsg(db)) // returns "out of memory" if db == nil
827+
extrv := rv
828+
// Convert the extended result code to a basic result code.
829+
rv &= ErrNoMask
831830

832831
// https://www.sqlite.org/c3ref/system_errno.html
833832
// sqlite3_system_errno is only meaningful if the error code was SQLITE_CANTOPEN,
834833
// or it was SQLITE_IOERR and the extended code was not SQLITE_IOERR_NOMEM
835834
var systemErrno syscall.Errno
836-
if rv == C.SQLITE_CANTOPEN || (rv == C.SQLITE_IOERR && extrv != C.SQLITE_IOERR_NOMEM) {
835+
if db != nil && (rv == C.SQLITE_CANTOPEN ||
836+
(rv == C.SQLITE_IOERR && extrv != C.SQLITE_IOERR_NOMEM)) {
837837
systemErrno = syscall.Errno(C.sqlite3_system_errno(db))
838838
}
839839

840+
var msg string
841+
if db != nil {
842+
msg = C.GoString(C.sqlite3_errmsg(db))
843+
} else {
844+
msg = errorString(extrv)
845+
}
840846
return Error{
841847
Code: ErrNo(rv),
842848
ExtendedCode: ErrNoExtended(extrv),
843849
SystemErrno: systemErrno,
844-
err: errStr,
850+
err: msg,
845851
}
846852
}
847853

@@ -1467,7 +1473,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
14671473
if rv != 0 {
14681474
// Save off the error _before_ closing the database.
14691475
// This is safe even if db is nil.
1470-
err := lastError(db)
1476+
err := lastError(db, int(rv))
14711477
if db != nil {
14721478
C.sqlite3_close_v2(db)
14731479
}
@@ -1476,13 +1482,18 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
14761482
if db == nil {
14771483
return nil, errors.New("sqlite succeeded without returning a database")
14781484
}
1485+
rv = C.sqlite3_extended_result_codes(db, 1)
1486+
if rv != SQLITE_OK {
1487+
C.sqlite3_close_v2(db)
1488+
return nil, lastError(db, int(rv))
1489+
}
14791490

14801491
exec := func(s string) error {
14811492
cs := C.CString(s)
14821493
rv := C.sqlite3_exec(db, cs, nil, nil, nil)
14831494
C.free(unsafe.Pointer(cs))
14841495
if rv != C.SQLITE_OK {
1485-
return lastError(db)
1496+
return lastError(db, int(rv))
14861497
}
14871498
return nil
14881499
}
@@ -1782,26 +1793,20 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
17821793
}
17831794

17841795
// Close the connection.
1785-
func (c *SQLiteConn) Close() error {
1796+
func (c *SQLiteConn) Close() (err error) {
1797+
c.mu.Lock()
1798+
defer c.mu.Unlock()
1799+
if c.db == nil {
1800+
return nil // Already closed
1801+
}
1802+
runtime.SetFinalizer(c, nil)
17861803
rv := C.sqlite3_close_v2(c.db)
17871804
if rv != C.SQLITE_OK {
1788-
return c.lastError()
1805+
err = lastError(nil, int(rv))
17891806
}
17901807
deleteHandles(c)
1791-
c.mu.Lock()
17921808
c.db = nil
1793-
c.mu.Unlock()
1794-
runtime.SetFinalizer(c, nil)
1795-
return nil
1796-
}
1797-
1798-
func (c *SQLiteConn) dbConnOpen() bool {
1799-
if c == nil {
1800-
return false
1801-
}
1802-
c.mu.Lock()
1803-
defer c.mu.Unlock()
1804-
return c.db != nil
1809+
return err
18051810
}
18061811

18071812
// Prepare the query string. Return a new statement.
@@ -1816,7 +1821,7 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er
18161821
var tail *C.char
18171822
rv := C._sqlite3_prepare_v2_internal(c.db, pquery, C.int(-1), &s, &tail)
18181823
if rv != C.SQLITE_OK {
1819-
return nil, c.lastError()
1824+
return nil, c.lastError(int(rv))
18201825
}
18211826
var t string
18221827
if tail != nil && *tail != '\000' {
@@ -1888,7 +1893,7 @@ func (c *SQLiteConn) SetFileControlInt(dbName string, op int, arg int) error {
18881893
cArg := C.int(arg)
18891894
rv := C.sqlite3_file_control(c.db, cDBName, C.int(op), unsafe.Pointer(&cArg))
18901895
if rv != C.SQLITE_OK {
1891-
return c.lastError()
1896+
return c.lastError(int(rv))
18921897
}
18931898
return nil
18941899
}
@@ -1901,16 +1906,15 @@ func (s *SQLiteStmt) Close() error {
19011906
return nil
19021907
}
19031908
s.closed = true
1904-
if !s.c.dbConnOpen() {
1905-
return errors.New("sqlite statement with already closed database connection")
1906-
}
1907-
rv := C.sqlite3_finalize(s.s)
1909+
conn := s.c
1910+
stmt := s.s
1911+
s.c = nil
19081912
s.s = nil
1913+
runtime.SetFinalizer(s, nil)
1914+
rv := C.sqlite3_finalize(stmt)
19091915
if rv != C.SQLITE_OK {
1910-
return s.c.lastError()
1916+
return conn.lastError(int(rv))
19111917
}
1912-
s.c = nil
1913-
runtime.SetFinalizer(s, nil)
19141918
return nil
19151919
}
19161920

@@ -1924,7 +1928,7 @@ var placeHolder = []byte{0}
19241928
func (s *SQLiteStmt) bind(args []driver.NamedValue) error {
19251929
rv := C.sqlite3_reset(s.s)
19261930
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
1927-
return s.c.lastError()
1931+
return s.c.lastError(int(rv))
19281932
}
19291933

19301934
bindIndices := make([][3]int, len(args))
@@ -1982,7 +1986,7 @@ func (s *SQLiteStmt) bind(args []driver.NamedValue) error {
19821986
rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
19831987
}
19841988
if rv != C.SQLITE_OK {
1985-
return s.c.lastError()
1989+
return s.c.lastError(int(rv))
19861990
}
19871991
}
19881992
}
@@ -2092,7 +2096,7 @@ func (s *SQLiteStmt) execSync(args []driver.NamedValue) (driver.Result, error) {
20922096
var rowid, changes C.longlong
20932097
rv := C._sqlite3_step_row_internal(s.s, &rowid, &changes)
20942098
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
2095-
err := s.c.lastError()
2099+
err := s.c.lastError(int(rv))
20962100
C.sqlite3_reset(s.s)
20972101
C.sqlite3_clear_bindings(s.s)
20982102
return nil, err
@@ -2128,8 +2132,8 @@ func (rc *SQLiteRows) Close() error {
21282132
}
21292133
rv := C.sqlite3_reset(s.s)
21302134
if rv != C.SQLITE_OK {
2131-
s.mu.Unlock()
2132-
return s.c.lastError()
2135+
rc.s.mu.Unlock()
2136+
return rc.s.c.lastError(int(rv))
21332137
}
21342138
s.mu.Unlock()
21352139
return nil
@@ -2206,7 +2210,7 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
22062210
if rv != C.SQLITE_ROW {
22072211
rv = C.sqlite3_reset(rc.s.s)
22082212
if rv != C.SQLITE_OK {
2209-
return rc.s.c.lastError()
2213+
return rc.s.c.lastError(int(rv))
22102214
}
22112215
return nil
22122216
}

sqlite3_opt_unlock_notify.c

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
// license that can be found in the LICENSE file.
55

66
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
7-
#include <stdio.h>
87
#ifndef USE_LIBSQLITE3
98
#include "sqlite3-binding.h"
109
#else
@@ -13,6 +12,10 @@
1312

1413
extern int unlock_notify_wait(sqlite3 *db);
1514

15+
static inline int is_locked(int rv) {
16+
return rv == SQLITE_LOCKED || rv == SQLITE_LOCKED_SHAREDCACHE;
17+
}
18+
1619
int
1720
_sqlite3_step_blocking(sqlite3_stmt *stmt)
1821
{
@@ -22,10 +25,7 @@ _sqlite3_step_blocking(sqlite3_stmt *stmt)
2225
db = sqlite3_db_handle(stmt);
2326
for (;;) {
2427
rv = sqlite3_step(stmt);
25-
if (rv != SQLITE_LOCKED) {
26-
break;
27-
}
28-
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
28+
if (!is_locked(rv)) {
2929
break;
3030
}
3131
rv = unlock_notify_wait(db);
@@ -47,10 +47,7 @@ _sqlite3_step_row_blocking(sqlite3_stmt* stmt, long long* rowid, long long* chan
4747
db = sqlite3_db_handle(stmt);
4848
for (;;) {
4949
rv = sqlite3_step(stmt);
50-
if (rv!=SQLITE_LOCKED) {
51-
break;
52-
}
53-
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
50+
if (!is_locked(rv)) {
5451
break;
5552
}
5653
rv = unlock_notify_wait(db);
@@ -72,10 +69,7 @@ _sqlite3_prepare_v2_blocking(sqlite3 *db, const char *zSql, int nBytes, sqlite3_
7269

7370
for (;;) {
7471
rv = sqlite3_prepare_v2(db, zSql, nBytes, ppStmt, pzTail);
75-
if (rv!=SQLITE_LOCKED) {
76-
break;
77-
}
78-
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
72+
if (!is_locked(rv)) {
7973
break;
8074
}
8175
rv = unlock_notify_wait(db);

0 commit comments

Comments
 (0)