Commit ecae65ef authored by gwenn's avatar gwenn

Add CommitHook and RollbackHook methods.

parent 8f71d095
...@@ -10,10 +10,22 @@ package sqlite ...@@ -10,10 +10,22 @@ package sqlite
#include <sqlite3.h> #include <sqlite3.h>
#include <stdlib.h> #include <stdlib.h>
extern void goXUpdateHook(void *pArg, int action, char const *db, char const *table, sqlite3_int64 rowId); extern int goXCommitHook(void *udp);
static void goSqlite3UpdateHook(sqlite3 *db, void *pArg) { static void* goSqlite3CommitHook(sqlite3 *db, void *udp) {
sqlite3_update_hook(db, goXUpdateHook, pArg); return sqlite3_commit_hook(db, goXCommitHook, udp);
}
extern void goXRollbackHook(void *udp);
static void* goSqlite3RollbackHook(sqlite3 *db, void *udp) {
return sqlite3_rollback_hook(db, goXRollbackHook, udp);
}
extern void goXUpdateHook(void *udp, int action, char const *dbName, char const *tableName, sqlite3_int64 rowId);
static void* goSqlite3UpdateHook(sqlite3 *db, void *udp) {
return sqlite3_update_hook(db, goXUpdateHook, udp);
} }
*/ */
import "C" import "C"
...@@ -22,26 +34,77 @@ import ( ...@@ -22,26 +34,77 @@ import (
"unsafe" "unsafe"
) )
type UpdateHook func(d interface{}, a Action, db, table string, rowId int64) type CommitHook func(udp interface{}) int
type sqliteCommitHook struct {
f CommitHook
udp interface{}
}
//export goXCommitHook
func goXCommitHook(udp unsafe.Pointer) C.int {
arg := (*sqliteCommitHook)(udp)
return C.int(arg.f(arg.udp))
}
// Calls http://sqlite.org/c3ref/commit_hook.html
func (c *Conn) CommitHook(f CommitHook, udp interface{}) {
if f == nil {
c.commitHook = nil
C.sqlite3_commit_hook(c.db, nil, nil)
return
}
// To make sure it is not gced, keep a reference in the connection.
c.commitHook = &sqliteCommitHook{f, udp}
C.goSqlite3CommitHook(c.db, unsafe.Pointer(c.commitHook))
}
type RollbackHook func(udp interface{})
type sqliteRollbackHook struct {
f RollbackHook
udp interface{}
}
//export goXRollbackHook
func goXRollbackHook(udp unsafe.Pointer) {
arg := (*sqliteRollbackHook)(udp)
arg.f(arg.udp)
}
// Calls http://sqlite.org/c3ref/commit_hook.html
func (c *Conn) RollbackHook(f RollbackHook, udp interface{}) {
if f == nil {
c.rollbackHook = nil
C.sqlite3_rollback_hook(c.db, nil, nil)
return
}
// To make sure it is not gced, keep a reference in the connection.
c.rollbackHook = &sqliteRollbackHook{f, udp}
C.goSqlite3RollbackHook(c.db, unsafe.Pointer(c.rollbackHook))
}
type UpdateHook func(udp interface{}, a Action, dbName, tableName string, rowId int64)
type sqliteUpdateHook struct { type sqliteUpdateHook struct {
f UpdateHook f UpdateHook
d interface{} udp interface{}
} }
//export goXUpdateHook //export goXUpdateHook
func goXUpdateHook(pArg unsafe.Pointer, action C.int, db, table *C.char, rowId C.sqlite3_int64) { func goXUpdateHook(udp unsafe.Pointer, action C.int, dbName, tableName *C.char, rowId C.sqlite3_int64) {
arg := (*sqliteUpdateHook)(pArg) arg := (*sqliteUpdateHook)(udp)
arg.f(arg.d, Action(action), C.GoString(db), C.GoString(table), int64(rowId)) arg.f(arg.udp, Action(action), C.GoString(dbName), C.GoString(tableName), int64(rowId))
} }
// Calls http://sqlite.org/c3ref/update_hook.html // Calls http://sqlite.org/c3ref/update_hook.html
func (c *Conn) UpdateHook(f UpdateHook, arg interface{}) { func (c *Conn) UpdateHook(f UpdateHook, udp interface{}) {
if f == nil { if f == nil {
c.updateHook = nil c.updateHook = nil
C.sqlite3_update_hook(c.db, nil, nil) C.sqlite3_update_hook(c.db, nil, nil)
return
} }
// To make sure it is not gced, keep a reference in the connection. // To make sure it is not gced, keep a reference in the connection.
c.updateHook = &sqliteUpdateHook{f, arg} c.updateHook = &sqliteUpdateHook{f, udp}
C.goSqlite3UpdateHook(c.db, unsafe.Pointer(c.updateHook)) C.goSqlite3UpdateHook(c.db, unsafe.Pointer(c.updateHook))
} }
...@@ -140,6 +140,8 @@ type Conn struct { ...@@ -140,6 +140,8 @@ type Conn struct {
profile *sqliteProfile profile *sqliteProfile
progressHandler *sqliteProgressHandler progressHandler *sqliteProgressHandler
trace *sqliteTrace trace *sqliteTrace
commitHook *sqliteCommitHook
rollbackHook *sqliteRollbackHook
updateHook *sqliteUpdateHook updateHook *sqliteUpdateHook
} }
......
...@@ -10,33 +10,33 @@ package sqlite ...@@ -10,33 +10,33 @@ package sqlite
#include <sqlite3.h> #include <sqlite3.h>
#include <stdlib.h> #include <stdlib.h>
extern void goXTrace(void *pArg, const char *t); extern void goXTrace(void *udp, const char *sql);
static void goSqlite3Trace(sqlite3 *db, void *pArg) { static void goSqlite3Trace(sqlite3 *db, void *udp) {
sqlite3_trace(db, goXTrace, pArg); sqlite3_trace(db, goXTrace, udp);
} }
extern void goXProfile(void *pArg, const char *sql, sqlite3_uint64 nanoseconds); extern void goXProfile(void *udp, const char *sql, sqlite3_uint64 nanoseconds);
static void goSqlite3Profile(sqlite3 *db, void *pArg) { static void goSqlite3Profile(sqlite3 *db, void *udp) {
sqlite3_profile(db, goXProfile, pArg); sqlite3_profile(db, goXProfile, udp);
} }
extern int goXAuth(void *pUserData, int action, const char *arg1, const char *arg2, const char *arg3, const char *arg4); extern int goXAuth(void *udp, int action, const char *arg1, const char *arg2, const char *dbName, const char *triggerName);
static int goSqlite3SetAuthorizer(sqlite3 *db, void *pUserData) { static int goSqlite3SetAuthorizer(sqlite3 *db, void *udp) {
return sqlite3_set_authorizer(db, goXAuth, pUserData); return sqlite3_set_authorizer(db, goXAuth, udp);
} }
extern int goXBusy(void *pArg, int n); extern int goXBusy(void *udp, int count);
static int goSqlite3BusyHandler(sqlite3 *db, void *pArg) { static int goSqlite3BusyHandler(sqlite3 *db, void *udp) {
return sqlite3_busy_handler(db, goXBusy, pArg); return sqlite3_busy_handler(db, goXBusy, udp);
} }
extern int goXProgress(void *pArg); extern int goXProgress(void *udp);
static void goSqlite3ProgressHandler(sqlite3 *db, int freq, void *pArg) { static void goSqlite3ProgressHandler(sqlite3 *db, int numOps, void *udp) {
sqlite3_progress_handler(db, freq, goXProgress, pArg); sqlite3_progress_handler(db, numOps, goXProgress, udp);
} }
// cgo doesn't support varargs // cgo doesn't support varargs
...@@ -51,53 +51,53 @@ import ( ...@@ -51,53 +51,53 @@ import (
"unsafe" "unsafe"
) )
type Tracer func(d interface{}, t string) type Tracer func(udp interface{}, sql string)
type sqliteTrace struct { type sqliteTrace struct {
f Tracer f Tracer
d interface{} udp interface{}
} }
//export goXTrace //export goXTrace
func goXTrace(pArg unsafe.Pointer, t *C.char) { func goXTrace(udp unsafe.Pointer, sql *C.char) {
arg := (*sqliteTrace)(pArg) arg := (*sqliteTrace)(udp)
arg.f(arg.d, C.GoString(t)) arg.f(arg.udp, C.GoString(sql))
} }
// Calls sqlite3_trace, http://sqlite.org/c3ref/profile.html // Calls sqlite3_trace, http://sqlite.org/c3ref/profile.html
func (c *Conn) Trace(f Tracer, arg interface{}) { func (c *Conn) Trace(f Tracer, udp interface{}) {
if f == nil { if f == nil {
c.trace = nil c.trace = nil
C.sqlite3_trace(c.db, nil, nil) C.sqlite3_trace(c.db, nil, nil)
return return
} }
// To make sure it is not gced, keep a reference in the connection. // To make sure it is not gced, keep a reference in the connection.
c.trace = &sqliteTrace{f, arg} c.trace = &sqliteTrace{f, udp}
C.goSqlite3Trace(c.db, unsafe.Pointer(c.trace)) C.goSqlite3Trace(c.db, unsafe.Pointer(c.trace))
} }
type Profiler func(d interface{}, sql string, nanoseconds uint64) type Profiler func(udp interface{}, sql string, nanoseconds uint64)
type sqliteProfile struct { type sqliteProfile struct {
f Profiler f Profiler
d interface{} udp interface{}
} }
//export goXProfile //export goXProfile
func goXProfile(pArg unsafe.Pointer, sql *C.char, nanoseconds C.sqlite3_uint64) { func goXProfile(udp unsafe.Pointer, sql *C.char, nanoseconds C.sqlite3_uint64) {
arg := (*sqliteProfile)(pArg) arg := (*sqliteProfile)(udp)
arg.f(arg.d, C.GoString(sql), uint64(nanoseconds)) arg.f(arg.udp, C.GoString(sql), uint64(nanoseconds))
} }
// Calls sqlite3_profile, http://sqlite.org/c3ref/profile.html // Calls sqlite3_profile, http://sqlite.org/c3ref/profile.html
func (c *Conn) Profile(f Profiler, arg interface{}) { func (c *Conn) Profile(f Profiler, udp interface{}) {
if f == nil { if f == nil {
c.profile = nil c.profile = nil
C.sqlite3_profile(c.db, nil, nil) C.sqlite3_profile(c.db, nil, nil)
return return
} }
// To make sure it is not gced, keep a reference in the connection. // To make sure it is not gced, keep a reference in the connection.
c.profile = &sqliteProfile{f, arg} c.profile = &sqliteProfile{f, udp}
C.goSqlite3Profile(c.db, unsafe.Pointer(c.profile)) C.goSqlite3Profile(c.db, unsafe.Pointer(c.profile))
} }
...@@ -147,82 +147,82 @@ const ( ...@@ -147,82 +147,82 @@ const (
COPY Action = C.SQLITE_COPY COPY Action = C.SQLITE_COPY
) )
type Authorizer func(d interface{}, action Action, arg1, arg2, arg3, arg4 string) Auth type Authorizer func(udp interface{}, action Action, arg1, arg2, dbName, triggerName string) Auth
type sqliteAuthorizer struct { type sqliteAuthorizer struct {
f Authorizer f Authorizer
d interface{} udp interface{}
} }
//export goXAuth //export goXAuth
func goXAuth(pUserData unsafe.Pointer, action C.int, arg1, arg2, arg3, arg4 *C.char) C.int { func goXAuth(udp unsafe.Pointer, action C.int, arg1, arg2, dbName, triggerName *C.char) C.int {
arg := (*sqliteAuthorizer)(pUserData) arg := (*sqliteAuthorizer)(udp)
result := arg.f(arg.d, Action(action), C.GoString(arg1), C.GoString(arg2), C.GoString(arg3), C.GoString(arg4)) result := arg.f(arg.udp, Action(action), C.GoString(arg1), C.GoString(arg2), C.GoString(dbName), C.GoString(triggerName))
return C.int(result) return C.int(result)
} }
// Calls http://sqlite.org/c3ref/set_authorizer.html // Calls http://sqlite.org/c3ref/set_authorizer.html
func (c *Conn) SetAuthorizer(f Authorizer, arg interface{}) os.Error { func (c *Conn) SetAuthorizer(f Authorizer, udp interface{}) os.Error {
if f == nil { if f == nil {
c.authorizer = nil c.authorizer = nil
return c.error(C.sqlite3_set_authorizer(c.db, nil, nil)) return c.error(C.sqlite3_set_authorizer(c.db, nil, nil))
} }
// To make sure it is not gced, keep a reference in the connection. // To make sure it is not gced, keep a reference in the connection.
c.authorizer = &sqliteAuthorizer{f, arg} c.authorizer = &sqliteAuthorizer{f, udp}
return c.error(C.goSqlite3SetAuthorizer(c.db, unsafe.Pointer(c.authorizer))) return c.error(C.goSqlite3SetAuthorizer(c.db, unsafe.Pointer(c.authorizer)))
} }
type BusyHandler func(d interface{}, n int) int type BusyHandler func(udp interface{}, count int) int
type sqliteBusyHandler struct { type sqliteBusyHandler struct {
f BusyHandler f BusyHandler
d interface{} udp interface{}
} }
//export goXBusy //export goXBusy
func goXBusy(pArg unsafe.Pointer, n C.int) C.int { func goXBusy(udp unsafe.Pointer, count C.int) C.int {
arg := (*sqliteBusyHandler)(pArg) arg := (*sqliteBusyHandler)(udp)
result := arg.f(arg.d, int(n)) result := arg.f(arg.udp, int(count))
return C.int(result) return C.int(result)
} }
// TODO NOT TESTED // TODO NOT TESTED
// Calls http://sqlite.org/c3ref/busy_handler.html // Calls http://sqlite.org/c3ref/busy_handler.html
func (c *Conn) BusyHandler(f BusyHandler, arg interface{}) os.Error { func (c *Conn) BusyHandler(f BusyHandler, udp interface{}) os.Error {
if f == nil { if f == nil {
c.busyHandler = nil c.busyHandler = nil
return c.error(C.sqlite3_busy_handler(c.db, nil, nil)) return c.error(C.sqlite3_busy_handler(c.db, nil, nil))
} }
// To make sure it is not gced, keep a reference in the connection. // To make sure it is not gced, keep a reference in the connection.
c.busyHandler = &sqliteBusyHandler{f, arg} c.busyHandler = &sqliteBusyHandler{f, udp}
return c.error(C.goSqlite3BusyHandler(c.db, unsafe.Pointer(c.busyHandler))) return c.error(C.goSqlite3BusyHandler(c.db, unsafe.Pointer(c.busyHandler)))
} }
// Returns non-zero to interrupt. // Returns non-zero to interrupt.
type ProgressHandler func(d interface{}) int type ProgressHandler func(udp interface{}) int
type sqliteProgressHandler struct { type sqliteProgressHandler struct {
f ProgressHandler f ProgressHandler
d interface{} udp interface{}
} }
//export goXProgress //export goXProgress
func goXProgress(pArg unsafe.Pointer) C.int { func goXProgress(udp unsafe.Pointer) C.int {
arg := (*sqliteProgressHandler)(pArg) arg := (*sqliteProgressHandler)(udp)
result := arg.f(arg.d) result := arg.f(arg.udp)
return C.int(result) return C.int(result)
} }
// Calls http://sqlite.org/c3ref/progress_handler.html // Calls http://sqlite.org/c3ref/progress_handler.html
func (c *Conn) ProgressHandler(f ProgressHandler, freq int, arg interface{}) { func (c *Conn) ProgressHandler(f ProgressHandler, numOps int, udp interface{}) {
if f == nil { if f == nil {
c.progressHandler = nil c.progressHandler = nil
C.sqlite3_progress_handler(c.db, 0, nil, nil) C.sqlite3_progress_handler(c.db, 0, nil, nil)
return return
} }
// To make sure it is not gced, keep a reference in the connection. // To make sure it is not gced, keep a reference in the connection.
c.progressHandler = &sqliteProgressHandler{f, arg} c.progressHandler = &sqliteProgressHandler{f, udp}
C.goSqlite3ProgressHandler(c.db, C.int(freq), unsafe.Pointer(c.progressHandler)) C.goSqlite3ProgressHandler(c.db, C.int(numOps), unsafe.Pointer(c.progressHandler))
} }
type StmtStatus int type StmtStatus int
......
...@@ -6,12 +6,12 @@ import ( ...@@ -6,12 +6,12 @@ import (
"testing" "testing"
) )
func trace(d interface{}, t string) { func trace(d interface{}, sql string) {
//fmt.Printf("%s: %s\n", d, t) //fmt.Printf("%s: %s\n", d, sql)
} }
func authorizer(d interface{}, action Action, arg1, arg2, arg3, arg4 string) Auth { func authorizer(d interface{}, action Action, arg1, arg2, dbName, triggerName string) Auth {
//fmt.Printf("%s: %d, %s, %s, %s, %s\n", d, action, arg1, arg2, arg3, arg4) //fmt.Printf("%s: %d, %s, %s, %s, %s\n", d, action, arg1, arg2, dbName, triggerName)
return AUTH_OK return AUTH_OK
} }
...@@ -24,8 +24,17 @@ func progressHandler(d interface{}) int { ...@@ -24,8 +24,17 @@ func progressHandler(d interface{}) int {
return 0 return 0
} }
func update_hook(d interface{}, a Action, db, table string, rowId int64) { func commitHook(d interface{}) int {
fmt.Printf("%s: %d, %s.%s.%d\n", d, a, db, table, rowId) fmt.Printf("%s\n", d)
return 0
}
func rollbackHook(d interface{}) {
fmt.Printf("%s\n", d)
}
func updateHook(d interface{}, a Action, dbName, tableName string, rowId int64) {
fmt.Printf("%s: %d, %s.%s.%d\n", d, a, dbName, tableName, rowId)
} }
func TestNoTrace(t *testing.T) { func TestNoTrace(t *testing.T) {
...@@ -38,6 +47,8 @@ func TestNoTrace(t *testing.T) { ...@@ -38,6 +47,8 @@ func TestNoTrace(t *testing.T) {
db.Profile(nil, nil) db.Profile(nil, nil)
db.ProgressHandler(nil, 0, nil) db.ProgressHandler(nil, 0, nil)
db.BusyHandler(nil, nil) db.BusyHandler(nil, nil)
db.CommitHook(nil, nil)
db.RollbackHook(nil, nil)
db.UpdateHook(nil, nil) db.UpdateHook(nil, nil)
db.Close() db.Close()
} }
...@@ -51,6 +62,8 @@ func TestTrace(t *testing.T) { ...@@ -51,6 +62,8 @@ func TestTrace(t *testing.T) {
} }
db.Profile(profile, "PROFILE") db.Profile(profile, "PROFILE")
db.ProgressHandler(progressHandler, 1, /*20*/ nil) db.ProgressHandler(progressHandler, 1, /*20*/ nil)
db.UpdateHook(update_hook, "TEST") db.CommitHook(commitHook, "CMT")
db.RollbackHook(rollbackHook, "RBK")
db.UpdateHook(updateHook, "UPD")
db.Exists("SELECT 1 WHERE 1 = ?", 1) db.Exists("SELECT 1 WHERE 1 = ?", 1)
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment