mirror of https://github.com/mattn/go-sqlite3.git
Add support for sqlite3_unlock_notify
This commit is contained in:
parent
05548ff555
commit
cf9f5ca0ef
|
@ -0,0 +1,5 @@
|
||||||
|
void _unlock_notify_callback(void *arg, int argc)
|
||||||
|
{
|
||||||
|
extern void unlock_notify_callback(void *, int);
|
||||||
|
unlock_notify_callback(arg, argc);
|
||||||
|
}
|
34
callback.go
34
callback.go
|
@ -20,6 +20,8 @@ package sqlite3
|
||||||
|
|
||||||
void _sqlite3_result_text(sqlite3_context* ctx, const char* s);
|
void _sqlite3_result_text(sqlite3_context* ctx, const char* s);
|
||||||
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l);
|
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l);
|
||||||
|
|
||||||
|
void _unlock_notify_callback(void *arg, int argc);
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
|
@ -362,3 +364,35 @@ func callbackSyntheticForTests(v reflect.Value, err error) callbackArgConverter
|
||||||
return v, err
|
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
|
||||||
|
}
|
||||||
|
|
34
sqlite3.go
34
sqlite3.go
|
@ -11,6 +11,7 @@ package sqlite3
|
||||||
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61
|
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61
|
||||||
#cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15
|
#cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15
|
||||||
#cgo CFLAGS: -DSQLITE_DISABLE_INTRINSIC
|
#cgo CFLAGS: -DSQLITE_DISABLE_INTRINSIC
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
|
||||||
#cgo CFLAGS: -Wno-deprecated-declarations
|
#cgo CFLAGS: -Wno-deprecated-declarations
|
||||||
#ifndef USE_LIBSQLITE3
|
#ifndef USE_LIBSQLITE3
|
||||||
#include <sqlite3-binding.h>
|
#include <sqlite3-binding.h>
|
||||||
|
@ -70,8 +71,25 @@ _sqlite3_exec(sqlite3* db, const char* pcmd, long long* rowid, long long* change
|
||||||
static int
|
static int
|
||||||
_sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
|
_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);
|
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);
|
*rowid = (long long) sqlite3_last_insert_rowid(db);
|
||||||
*changes = (long long) sqlite3_changes(db);
|
*changes = (long long) sqlite3_changes(db);
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -814,7 +832,19 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er
|
||||||
defer C.free(unsafe.Pointer(pquery))
|
defer C.free(unsafe.Pointer(pquery))
|
||||||
var s *C.sqlite3_stmt
|
var s *C.sqlite3_stmt
|
||||||
var tail *C.char
|
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 {
|
if rv != C.SQLITE_OK {
|
||||||
return nil, c.lastError()
|
return nil, c.lastError()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue