Skip to content

Commit 29fac6b

Browse files
committed
Add support for sqlite3_unlock_notify
1 parent 3198c77 commit 29fac6b

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

@@ -372,3 +374,35 @@ func callbackSyntheticForTests(v reflect.Value, err error) callbackArgConverter
372374
return v, err
373375
}
374376
}
377+
378+
type unlockNotification struct {
379+
notify chan struct{}
380+
lock sync.Mutex
381+
}
382+
383+
//export unlock_notify_callback
384+
func unlock_notify_callback(pargv unsafe.Pointer, argc C.int) {
385+
argv := *(*uintptr)(pargv)
386+
v := (*[1 << 30]uintptr)(unsafe.Pointer(argv))
387+
for i := 0; i < int(argc); i++ {
388+
un := lookupHandle(v[i]).(unlockNotification)
389+
un.notify <- struct{}{}
390+
}
391+
}
392+
393+
var notifyMutex sync.Mutex
394+
395+
//export unlock_notify_wait
396+
func unlock_notify_wait(db *C.sqlite3) C.int {
397+
var un unlockNotification
398+
399+
un.notify = make(chan struct{})
400+
defer close(un.notify)
401+
402+
argv := [1]uintptr{newHandle(nil, un)}
403+
if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C._unlock_notify_callback), unsafe.Pointer(&argv)); rv != C.SQLITE_OK {
404+
return rv
405+
}
406+
<-un.notify
407+
return C.SQLITE_OK
408+
}

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;
@@ -1582,7 +1600,20 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er
15821600
defer C.free(unsafe.Pointer(pquery))
15831601
var s *C.sqlite3_stmt
15841602
var tail *C.char
1585-
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
1603+
var rv C.int
1604+
for {
1605+
rv = C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
1606+
if rv == C.SQLITE_OK {
1607+
break
1608+
} else if rv == C.SQLITE_LOCKED {
1609+
rv = unlock_notify_wait(c.db)
1610+
if rv != C.SQLITE_OK {
1611+
break
1612+
}
1613+
} else {
1614+
break
1615+
}
1616+
}
15861617
if rv != C.SQLITE_OK {
15871618
return nil, c.lastError()
15881619
}

0 commit comments

Comments
 (0)