Skip to content

Commit ad29852

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

File tree

3 files changed

+183
-4
lines changed

3 files changed

+183
-4
lines changed

sqlite3.go

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,38 @@ _sqlite3_exec(sqlite3* db, const char* pcmd, long long* rowid, long long* change
7878
return rv;
7979
}
8080
81+
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
82+
extern int sqlite3_step_blocking(sqlite3_stmt *stmt);
83+
extern int _sqlite3_step_blocking(sqlite3_stmt* stmt, long long* rowid, long long* changes);
84+
extern int sqlite3_prepare_v2_blocking(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail);
85+
86+
static int
87+
sqlite3_step_internal(sqlite3_stmt *stmt)
88+
{
89+
return sqlite3_step_blocking(stmt);
90+
}
91+
92+
static int
93+
_sqlite3_step_internal(sqlite3_stmt* stmt, long long* rowid, long long* changes)
94+
{
95+
return _sqlite3_step_blocking(stmt, rowid, changes);
96+
}
97+
8198
static int
82-
_sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
99+
sqlite3_prepare_v2_internal(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail)
100+
{
101+
return sqlite3_prepare_v2_blocking(db, zSql, nBytes, ppStmt, pzTail);
102+
}
103+
104+
#else
105+
static int
106+
sqlite3_step_internal(sqlite3_stmt *stmt)
107+
{
108+
return sqlite3_step(stmt);
109+
}
110+
111+
static int
112+
_sqlite3_step_internal(sqlite3_stmt* stmt, long long* rowid, long long* changes)
83113
{
84114
int rv = sqlite3_step(stmt);
85115
sqlite3* db = sqlite3_db_handle(stmt);
@@ -88,6 +118,13 @@ _sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
88118
return rv;
89119
}
90120
121+
static int
122+
sqlite3_prepare_v2_internal(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail)
123+
{
124+
return sqlite3_prepare_v2(db, zSql, nBytes, ppStmt, pzTail);
125+
}
126+
#endif
127+
91128
void _sqlite3_result_text(sqlite3_context* ctx, const char* s) {
92129
sqlite3_result_text(ctx, s, -1, &free);
93130
}
@@ -1637,7 +1674,7 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er
16371674
defer C.free(unsafe.Pointer(pquery))
16381675
var s *C.sqlite3_stmt
16391676
var tail *C.char
1640-
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
1677+
rv := C.sqlite3_prepare_v2_internal(c.db, pquery, -1, &s, &tail)
16411678
if rv != C.SQLITE_OK {
16421679
return nil, c.lastError()
16431680
}
@@ -1871,7 +1908,7 @@ func (s *SQLiteStmt) exec(ctx context.Context, args []namedValue) (driver.Result
18711908
}
18721909

18731910
var rowid, changes C.longlong
1874-
rv := C._sqlite3_step(s.s, &rowid, &changes)
1911+
rv := C._sqlite3_step_internal(s.s, &rowid, &changes)
18751912
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
18761913
err := s.c.lastError()
18771914
C.sqlite3_reset(s.s)
@@ -1943,7 +1980,7 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
19431980
if rc.s.closed {
19441981
return io.EOF
19451982
}
1946-
rv := C.sqlite3_step(rc.s.s)
1983+
rv := C.sqlite3_step_internal(rc.s.s)
19471984
if rv == C.SQLITE_DONE {
19481985
return io.EOF
19491986
}

sqlite3_opt_unlock_notify.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright (C) 2018 Yasuhiro Matsumoto <[email protected]>.
2+
//
3+
// Use of this source code is governed by an MIT-style
4+
// license that can be found in the LICENSE file.
5+
6+
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
7+
#include <sqlite3-binding.h>
8+
9+
extern int unlock_notify_wait(sqlite3 *db);
10+
11+
void _unlock_notify_callback(void *arg, int argc)
12+
{
13+
extern void unlock_notify_callback(void *, int);
14+
unlock_notify_callback(arg, argc);
15+
}
16+
17+
int
18+
sqlite3_step_blocking(sqlite3_stmt *stmt)
19+
{
20+
int rv;
21+
sqlite3* db = sqlite3_db_handle(stmt);
22+
23+
for (;;) {
24+
rv = sqlite3_step(stmt);
25+
if (rv != SQLITE_LOCKED) {
26+
break;
27+
}
28+
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
29+
break;
30+
}
31+
rv = unlock_notify_wait(db);
32+
if (rv != SQLITE_OK) {
33+
break;
34+
}
35+
sqlite3_reset(stmt);
36+
}
37+
38+
return rv;
39+
}
40+
41+
int
42+
_sqlite3_step_blocking(sqlite3_stmt* stmt, long long* rowid, long long* changes)
43+
{
44+
int rv;
45+
sqlite3* db;
46+
47+
for (;;) {
48+
rv = sqlite3_step(stmt);
49+
if (rv!=SQLITE_LOCKED) {
50+
break;
51+
}
52+
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
53+
break;
54+
}
55+
rv = unlock_notify_wait(db);
56+
if (rv != SQLITE_OK) {
57+
break;
58+
}
59+
sqlite3_reset(stmt);
60+
}
61+
62+
db = sqlite3_db_handle(stmt);
63+
*rowid = (long long) sqlite3_last_insert_rowid(db);
64+
*changes = (long long) sqlite3_changes(db);
65+
return rv;
66+
}
67+
68+
int
69+
sqlite3_prepare_v2_blocking(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail)
70+
{
71+
int rv;
72+
73+
for (;;) {
74+
rv = sqlite3_prepare_v2(db, zSql, nBytes, ppStmt, pzTail);
75+
if (rv!=SQLITE_LOCKED) {
76+
break;
77+
}
78+
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
79+
break;
80+
}
81+
rv = unlock_notify_wait(db);
82+
if (rv != SQLITE_OK) {
83+
break;
84+
}
85+
}
86+
87+
return rv;
88+
}
89+
#endif

sqlite3_opt_unlock_notify.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (C) 2018 Yasuhiro Matsumoto <[email protected]>.
2+
//
3+
// Use of this source code is governed by an MIT-style
4+
// license that can be found in the LICENSE file.
5+
6+
// +build cgo
7+
// +build sqlite_unlock_notify
8+
9+
package sqlite3
10+
11+
/*
12+
#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
13+
14+
#include <sqlite3-binding.h>
15+
16+
extern void _unlock_notify_callback(void *arg, int argc);
17+
*/
18+
import "C"
19+
import (
20+
"sync"
21+
"unsafe"
22+
)
23+
24+
type unlockNotification struct {
25+
notify chan struct{}
26+
lock sync.Mutex
27+
}
28+
29+
//export unlock_notify_callback
30+
func unlock_notify_callback(pargv unsafe.Pointer, argc C.int) {
31+
argv := *(*uintptr)(pargv)
32+
v := (*[1 << 30]uintptr)(unsafe.Pointer(argv))
33+
for i := 0; i < int(argc); i++ {
34+
un := lookupHandle(v[i]).(unlockNotification)
35+
un.notify <- struct{}{}
36+
}
37+
}
38+
39+
var notifyMutex sync.Mutex
40+
41+
//export unlock_notify_wait
42+
func unlock_notify_wait(db *C.sqlite3) C.int {
43+
var un unlockNotification
44+
un.notify = make(chan struct{})
45+
defer close(un.notify)
46+
47+
argv := [1]uintptr{newHandle(nil, un)}
48+
if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C._unlock_notify_callback), unsafe.Pointer(&argv)); rv != C.SQLITE_OK {
49+
return rv
50+
}
51+
<-un.notify
52+
return C.SQLITE_OK
53+
}

0 commit comments

Comments
 (0)