Skip to content

Commit 708b649

Browse files
committed
Add support for sqlite3_unlock_notify
1 parent 05548ff commit 708b649

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

callback.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
void _unlock_notify_callback(void *arg, int argc)
2+
{
3+
extern void unlock_notify_callback(void *, int);
4+
unlock_notify_callback(arg, argc);
5+
}

callback.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ package sqlite3
2020
2121
void _sqlite3_result_text(sqlite3_context* ctx, const char* s);
2222
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l);
23+
24+
void _unlock_notify_callback(void *arg, int argc);
2325
*/
2426
import "C"
2527

@@ -362,3 +364,35 @@ func callbackSyntheticForTests(v reflect.Value, err error) callbackArgConverter
362364
return v, err
363365
}
364366
}
367+
368+
type unlockNotification struct {
369+
notify chan struct{}
370+
lock sync.Mutex
371+
}
372+
373+
//export unlock_notify_callback
374+
func unlock_notify_callback(pargv unsafe.Pointer, argc C.int) {
375+
argv := *(*uintptr)(pargv)
376+
v := (*[1 << 30]uintptr)(unsafe.Pointer(argv))
377+
for i := 0; i < int(argc); i++ {
378+
un := lookupHandle(v[i]).(unlockNotification)
379+
un.notify <- struct{}{}
380+
}
381+
}
382+
383+
var notifyMutex sync.Mutex
384+
385+
//export unlock_notify_wait
386+
func unlock_notify_wait(db *C.sqlite3) C.int {
387+
var un unlockNotification
388+
389+
un.notify = make(chan struct{})
390+
defer close(un.notify)
391+
392+
argv := [1]uintptr{newHandle(nil, un)}
393+
if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C._unlock_notify_callback), unsafe.Pointer(&argv)); rv != C.SQLITE_OK {
394+
return rv
395+
}
396+
<-un.notify
397+
return C.SQLITE_OK
398+
}

sqlite3.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ package sqlite3
1111
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61
1212
#cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15
1313
#cgo CFLAGS: -DSQLITE_DISABLE_INTRINSIC
14+
#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
1415
#cgo CFLAGS: -Wno-deprecated-declarations
1516
#ifndef USE_LIBSQLITE3
1617
#include <sqlite3-binding.h>
@@ -70,8 +71,25 @@ _sqlite3_exec(sqlite3* db, const char* pcmd, long long* rowid, long long* change
7071
static int
7172
_sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
7273
{
73-
int rv = sqlite3_step(stmt);
74+
extern int unlock_notify_wait(sqlite3 *db);
75+
int rv;
7476
sqlite3* db = sqlite3_db_handle(stmt);
77+
78+
for (;;) {
79+
rv = sqlite3_step(stmt);
80+
if (rv!=SQLITE_LOCKED) {
81+
break;
82+
}
83+
if (sqlite3_extended_errcode(db)!=SQLITE_LOCKED_SHAREDCACHE) {
84+
break;
85+
}
86+
rv = unlock_notify_wait(db);
87+
if (rv != SQLITE_OK) {
88+
break;
89+
}
90+
sqlite3_reset(stmt);
91+
}
92+
7593
*rowid = (long long) sqlite3_last_insert_rowid(db);
7694
*changes = (long long) sqlite3_changes(db);
7795
return rv;
@@ -814,7 +832,19 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er
814832
defer C.free(unsafe.Pointer(pquery))
815833
var s *C.sqlite3_stmt
816834
var tail *C.char
817-
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
835+
var rv C.int
836+
for {
837+
rv = C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
838+
if rv == C.SQLITE_OK {
839+
break
840+
}
841+
if rv == C.SQLITE_LOCKED {
842+
rv = unlock_notify_wait(c.db)
843+
if rv != C.SQLITE_OK {
844+
break
845+
}
846+
}
847+
}
818848
if rv != C.SQLITE_OK {
819849
return nil, c.lastError()
820850
}

0 commit comments

Comments
 (0)