Add support for sqlite3_unlock_notify
diff --git a/callback.c b/callback.c
new file mode 100644
index 0000000..95b7ecb
--- /dev/null
+++ b/callback.c
@@ -0,0 +1,5 @@
+void _unlock_notify_callback(void *arg, int argc)
+{
+ extern void unlock_notify_callback(void *, int);
+ unlock_notify_callback(arg, argc);
+}
diff --git a/callback.go b/callback.go
index 29ece3d..e9d614c 100644
--- a/callback.go
+++ b/callback.go
@@ -20,6 +20,8 @@
void _sqlite3_result_text(sqlite3_context* ctx, const char* s);
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l);
+
+void _unlock_notify_callback(void *arg, int argc);
*/
import "C"
@@ -362,3 +364,35 @@
return v, err
}
}
+
+type unlockNotification struct {
+ notify chan struct{}
+ lock sync.Mutex
+}
+
+//export unlock_notify_callback
+func unlock_notify_callback(pargv unsafe.Pointer, argc C.int) {
+ argv := *(*uintptr)(pargv)
+ v := (*[1 << 30]uintptr)(unsafe.Pointer(argv))
+ for i := 0; i < int(argc); i++ {
+ un := lookupHandle(v[i]).(unlockNotification)
+ un.notify <- struct{}{}
+ }
+}
+
+var notifyMutex sync.Mutex
+
+//export unlock_notify_wait
+func unlock_notify_wait(db *C.sqlite3) C.int {
+ var un unlockNotification
+
+ un.notify = make(chan struct{})
+ defer close(un.notify)
+
+ argv := [1]uintptr{newHandle(nil, un)}
+ if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C._unlock_notify_callback), unsafe.Pointer(&argv)); rv != C.SQLITE_OK {
+ return rv
+ }
+ <-un.notify
+ return C.SQLITE_OK
+}
diff --git a/sqlite3.go b/sqlite3.go
index 1ff58c3..41a05ec 100644
--- a/sqlite3.go
+++ b/sqlite3.go
@@ -11,6 +11,7 @@
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61
#cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15
#cgo CFLAGS: -DSQLITE_DISABLE_INTRINSIC
+#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
#cgo CFLAGS: -Wno-deprecated-declarations
#ifndef USE_LIBSQLITE3
#include <sqlite3-binding.h>
@@ -70,8 +71,25 @@
static int
_sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
{
- int rv = sqlite3_step(stmt);
+ extern int unlock_notify_wait(sqlite3 *db);
+ int rv;
sqlite3* db = sqlite3_db_handle(stmt);
+
+ for (;;) {
+ rv = sqlite3_step(stmt);
+ if (rv!=SQLITE_LOCKED) {
+ break;
+ }
+ if (sqlite3_extended_errcode(db)!=SQLITE_LOCKED_SHAREDCACHE) {
+ break;
+ }
+ rv = unlock_notify_wait(db);
+ if (rv != SQLITE_OK) {
+ break;
+ }
+ sqlite3_reset(stmt);
+ }
+
*rowid = (long long) sqlite3_last_insert_rowid(db);
*changes = (long long) sqlite3_changes(db);
return rv;
@@ -814,7 +832,19 @@
defer C.free(unsafe.Pointer(pquery))
var s *C.sqlite3_stmt
var tail *C.char
- rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
+ var rv C.int
+ for {
+ rv = C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
+ if rv == C.SQLITE_OK {
+ break
+ }
+ if rv == C.SQLITE_LOCKED {
+ rv = unlock_notify_wait(c.db)
+ if rv != C.SQLITE_OK {
+ break
+ }
+ }
+ }
if rv != C.SQLITE_OK {
return nil, c.lastError()
}