Skip to content

Commit e5c24c6

Browse files
typelessMura Li
authored andcommitted
Add support for sqlite3_unlock_notify
1 parent 5a7d2e2 commit e5c24c6

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-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: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package sqlite3
2121
#cgo CFLAGS: -DSQLITE_DISABLE_INTRINSIC
2222
#cgo CFLAGS: -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1
2323
#cgo CFLAGS: -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT
24+
#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
2425
#cgo CFLAGS: -Wno-deprecated-declarations
2526
#cgo linux,!android CFLAGS: -DHAVE_PREAD64=1 -DHAVE_PWRITE64=1
2627
#ifndef USE_LIBSQLITE3
@@ -81,8 +82,25 @@ _sqlite3_exec(sqlite3* db, const char* pcmd, long long* rowid, long long* change
8182
static int
8283
_sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
8384
{
84-
int rv = sqlite3_step(stmt);
85+
extern int unlock_notify_wait(sqlite3 *db);
86+
int rv;
8587
sqlite3* db = sqlite3_db_handle(stmt);
88+
89+
for (;;) {
90+
rv = sqlite3_step(stmt);
91+
if (rv!=SQLITE_LOCKED) {
92+
break;
93+
}
94+
if (sqlite3_extended_errcode(db)!=SQLITE_LOCKED_SHAREDCACHE) {
95+
break;
96+
}
97+
rv = unlock_notify_wait(db);
98+
if (rv != SQLITE_OK) {
99+
break;
100+
}
101+
sqlite3_reset(stmt);
102+
}
103+
86104
*rowid = (long long) sqlite3_last_insert_rowid(db);
87105
*changes = (long long) sqlite3_changes(db);
88106
return rv;
@@ -1399,7 +1417,20 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er
13991417
defer C.free(unsafe.Pointer(pquery))
14001418
var s *C.sqlite3_stmt
14011419
var tail *C.char
1402-
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
1420+
var rv C.int
1421+
for {
1422+
rv = C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
1423+
if rv == C.SQLITE_OK {
1424+
break
1425+
} else if rv == C.SQLITE_LOCKED {
1426+
rv = unlock_notify_wait(c.db)
1427+
if rv != C.SQLITE_OK {
1428+
break
1429+
}
1430+
} else {
1431+
break
1432+
}
1433+
}
14031434
if rv != C.SQLITE_OK {
14041435
return nil, c.lastError()
14051436
}

0 commit comments

Comments
 (0)