Skip to content

Commit 60b4183

Browse files
typelessMura Li
authored andcommitted
Add support for sqlite3_unlock_notify
1 parent 43064d7 commit 60b4183

File tree

3 files changed

+136
-3
lines changed

3 files changed

+136
-3
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: 33 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

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

sqlite3.go

Lines changed: 98 additions & 3 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
@@ -88,6 +89,100 @@ _sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
8889
return rv;
8990
}
9091
92+
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
93+
static int
94+
sqlite3_step_internal(sqlite3_stmt *stmt)
95+
{
96+
extern int unlock_notify_wait(sqlite3 *db);
97+
int rv;
98+
sqlite3* db = sqlite3_db_handle(stmt);
99+
100+
for (;;) {
101+
rv = sqlite3_step(stmt);
102+
if (rv!=SQLITE_LOCKED) {
103+
break;
104+
}
105+
if (sqlite3_extended_errcode(db)!=SQLITE_LOCKED_SHAREDCACHE) {
106+
break;
107+
}
108+
rv = unlock_notify_wait(db);
109+
if (rv != SQLITE_OK) {
110+
break;
111+
}
112+
sqlite3_reset(stmt);
113+
}
114+
115+
return rv;
116+
}
117+
118+
static int
119+
_sqlite3_step_internal(sqlite3_stmt* stmt, long long* rowid, long long* changes)
120+
{
121+
extern int unlock_notify_wait(sqlite3 *db);
122+
int rv;
123+
sqlite3* db = sqlite3_db_handle(stmt);
124+
125+
for (;;) {
126+
rv = _sqlite3_step(stmt, rowid, changes);
127+
if (rv!=SQLITE_LOCKED) {
128+
break;
129+
}
130+
if (sqlite3_extended_errcode(db)!=SQLITE_LOCKED_SHAREDCACHE) {
131+
break;
132+
}
133+
rv = unlock_notify_wait(db);
134+
if (rv != SQLITE_OK) {
135+
break;
136+
}
137+
sqlite3_reset(stmt);
138+
}
139+
140+
return rv;
141+
}
142+
143+
static int
144+
sqlite3_prepare_v2_internal(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail)
145+
{
146+
extern int unlock_notify_wait(sqlite3 *db);
147+
int rv;
148+
149+
for (;;) {
150+
rv = sqlite3_prepare_v2(db, zSql, nBytes, ppStmt, pzTail);
151+
if (rv==SQLITE_OK) {
152+
break;
153+
} else if (rv==SQLITE_LOCKED) {
154+
rv = unlock_notify_wait(db);
155+
if (rv != SQLITE_OK) {
156+
break;
157+
}
158+
} else {
159+
break;
160+
}
161+
}
162+
163+
return rv;
164+
}
165+
#else
166+
167+
static int
168+
sqlite3_step_internal(sqlite3_stmt *stmt)
169+
{
170+
return sqlite3_step(stmt);
171+
}
172+
173+
static int
174+
_sqlite3_step_internal(sqlite3_stmt* stmt, long long* rowid, long long* changes)
175+
{
176+
return _sqlite3_step(stmt, rowid, changes);
177+
}
178+
179+
static int
180+
sqlite3_prepare_v2_internal(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail)
181+
{
182+
return sqlite3_prepare_v2(db, zSql, nBytes, ppStmt, pzTail);
183+
}
184+
#endif
185+
91186
void _sqlite3_result_text(sqlite3_context* ctx, const char* s) {
92187
sqlite3_result_text(ctx, s, -1, &free);
93188
}
@@ -1637,7 +1732,7 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er
16371732
defer C.free(unsafe.Pointer(pquery))
16381733
var s *C.sqlite3_stmt
16391734
var tail *C.char
1640-
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
1735+
rv := C.sqlite3_prepare_v2_internal(c.db, pquery, -1, &s, &tail)
16411736
if rv != C.SQLITE_OK {
16421737
return nil, c.lastError()
16431738
}
@@ -1871,7 +1966,7 @@ func (s *SQLiteStmt) exec(ctx context.Context, args []namedValue) (driver.Result
18711966
}
18721967

18731968
var rowid, changes C.longlong
1874-
rv := C._sqlite3_step(s.s, &rowid, &changes)
1969+
rv := C._sqlite3_step_internal(s.s, &rowid, &changes)
18751970
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
18761971
err := s.c.lastError()
18771972
C.sqlite3_reset(s.s)
@@ -1943,7 +2038,7 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
19432038
if rc.s.closed {
19442039
return io.EOF
19452040
}
1946-
rv := C.sqlite3_step(rc.s.s)
2041+
rv := C.sqlite3_step_internal(rc.s.s)
19472042
if rv == C.SQLITE_DONE {
19482043
return io.EOF
19492044
}

0 commit comments

Comments
 (0)