Commit ecae65ef authored by gwenn's avatar gwenn

Add CommitHook and RollbackHook methods.

parent 8f71d095
......@@ -10,10 +10,22 @@ package sqlite
#include <sqlite3.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) {
sqlite3_update_hook(db, goXUpdateHook, pArg);
static void* goSqlite3CommitHook(sqlite3 *db, void *udp) {
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"
......@@ -22,26 +34,77 @@ import (
"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 {
f UpdateHook
d interface{}
f UpdateHook
udp interface{}
}
//export goXUpdateHook
func goXUpdateHook(pArg unsafe.Pointer, action C.int, db, table *C.char, rowId C.sqlite3_int64) {
arg := (*sqliteUpdateHook)(pArg)
arg.f(arg.d, Action(action), C.GoString(db), C.GoString(table), int64(rowId))
func goXUpdateHook(udp unsafe.Pointer, action C.int, dbName, tableName *C.char, rowId C.sqlite3_int64) {
arg := (*sqliteUpdateHook)(udp)
arg.f(arg.udp, Action(action), C.GoString(dbName), C.GoString(tableName), int64(rowId))
}
// 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 {
c.updateHook = nil
C.sqlite3_update_hook(c.db, nil, nil)
return
}
// 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))
}
......@@ -140,6 +140,8 @@ type Conn struct {
profile *sqliteProfile
progressHandler *sqliteProgressHandler
trace *sqliteTrace
commitHook *sqliteCommitHook
rollbackHook *sqliteRollbackHook
updateHook *sqliteUpdateHook
}
......
......@@ -10,33 +10,33 @@ package sqlite
#include <sqlite3.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) {
sqlite3_trace(db, goXTrace, pArg);
static void goSqlite3Trace(sqlite3 *db, void *udp) {
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) {
sqlite3_profile(db, goXProfile, pArg);
static void goSqlite3Profile(sqlite3 *db, void *udp) {
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) {
return sqlite3_set_authorizer(db, goXAuth, pUserData);
static int goSqlite3SetAuthorizer(sqlite3 *db, void *udp) {
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) {
return sqlite3_busy_handler(db, goXBusy, pArg);
static int goSqlite3BusyHandler(sqlite3 *db, void *udp) {
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) {
sqlite3_progress_handler(db, freq, goXProgress, pArg);
static void goSqlite3ProgressHandler(sqlite3 *db, int numOps, void *udp) {
sqlite3_progress_handler(db, numOps, goXProgress, udp);
}
// cgo doesn't support varargs
......@@ -51,53 +51,53 @@ import (
"unsafe"
)
type Tracer func(d interface{}, t string)
type Tracer func(udp interface{}, sql string)
type sqliteTrace struct {
f Tracer
d interface{}
f Tracer
udp interface{}
}
//export goXTrace
func goXTrace(pArg unsafe.Pointer, t *C.char) {
arg := (*sqliteTrace)(pArg)
arg.f(arg.d, C.GoString(t))
func goXTrace(udp unsafe.Pointer, sql *C.char) {
arg := (*sqliteTrace)(udp)
arg.f(arg.udp, C.GoString(sql))
}
// 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 {
c.trace = nil
C.sqlite3_trace(c.db, nil, nil)
return
}
// 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))
}
type Profiler func(d interface{}, sql string, nanoseconds uint64)
type Profiler func(udp interface{}, sql string, nanoseconds uint64)
type sqliteProfile struct {
f Profiler
d interface{}
f Profiler
udp interface{}
}
//export goXProfile
func goXProfile(pArg unsafe.Pointer, sql *C.char, nanoseconds C.sqlite3_uint64) {
arg := (*sqliteProfile)(pArg)
arg.f(arg.d, C.GoString(sql), uint64(nanoseconds))
func goXProfile(udp unsafe.Pointer, sql *C.char, nanoseconds C.sqlite3_uint64) {
arg := (*sqliteProfile)(udp)
arg.f(arg.udp, C.GoString(sql), uint64(nanoseconds))
}
// 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 {
c.profile = nil
C.sqlite3_profile(c.db, nil, nil)
return
}
// 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))
}
......@@ -147,82 +147,82 @@ const (
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 {
f Authorizer
d interface{}
f Authorizer
udp interface{}
}
//export goXAuth
func goXAuth(pUserData unsafe.Pointer, action C.int, arg1, arg2, arg3, arg4 *C.char) C.int {
arg := (*sqliteAuthorizer)(pUserData)
result := arg.f(arg.d, Action(action), C.GoString(arg1), C.GoString(arg2), C.GoString(arg3), C.GoString(arg4))
func goXAuth(udp unsafe.Pointer, action C.int, arg1, arg2, dbName, triggerName *C.char) C.int {
arg := (*sqliteAuthorizer)(udp)
result := arg.f(arg.udp, Action(action), C.GoString(arg1), C.GoString(arg2), C.GoString(dbName), C.GoString(triggerName))
return C.int(result)
}
// 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 {
c.authorizer = 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.
c.authorizer = &sqliteAuthorizer{f, arg}
c.authorizer = &sqliteAuthorizer{f, udp}
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 {
f BusyHandler
d interface{}
f BusyHandler
udp interface{}
}
//export goXBusy
func goXBusy(pArg unsafe.Pointer, n C.int) C.int {
arg := (*sqliteBusyHandler)(pArg)
result := arg.f(arg.d, int(n))
func goXBusy(udp unsafe.Pointer, count C.int) C.int {
arg := (*sqliteBusyHandler)(udp)
result := arg.f(arg.udp, int(count))
return C.int(result)
}
// TODO NOT TESTED
// 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 {
c.busyHandler = 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.
c.busyHandler = &sqliteBusyHandler{f, arg}
c.busyHandler = &sqliteBusyHandler{f, udp}
return c.error(C.goSqlite3BusyHandler(c.db, unsafe.Pointer(c.busyHandler)))
}
// Returns non-zero to interrupt.
type ProgressHandler func(d interface{}) int
type ProgressHandler func(udp interface{}) int
type sqliteProgressHandler struct {
f ProgressHandler
d interface{}
f ProgressHandler
udp interface{}
}
//export goXProgress
func goXProgress(pArg unsafe.Pointer) C.int {
arg := (*sqliteProgressHandler)(pArg)
result := arg.f(arg.d)
func goXProgress(udp unsafe.Pointer) C.int {
arg := (*sqliteProgressHandler)(udp)
result := arg.f(arg.udp)
return C.int(result)
}
// 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 {
c.progressHandler = nil
C.sqlite3_progress_handler(c.db, 0, nil, nil)
return
}
// To make sure it is not gced, keep a reference in the connection.
c.progressHandler = &sqliteProgressHandler{f, arg}
C.goSqlite3ProgressHandler(c.db, C.int(freq), unsafe.Pointer(c.progressHandler))
c.progressHandler = &sqliteProgressHandler{f, udp}
C.goSqlite3ProgressHandler(c.db, C.int(numOps), unsafe.Pointer(c.progressHandler))
}
type StmtStatus int
......
......@@ -6,12 +6,12 @@ import (
"testing"
)
func trace(d interface{}, t string) {
//fmt.Printf("%s: %s\n", d, t)
func trace(d interface{}, sql string) {
//fmt.Printf("%s: %s\n", d, sql)
}
func authorizer(d interface{}, action Action, arg1, arg2, arg3, arg4 string) Auth {
//fmt.Printf("%s: %d, %s, %s, %s, %s\n", d, action, arg1, arg2, arg3, arg4)
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, dbName, triggerName)
return AUTH_OK
}
......@@ -24,8 +24,17 @@ func progressHandler(d interface{}) int {
return 0
}
func update_hook(d interface{}, a Action, db, table string, rowId int64) {
fmt.Printf("%s: %d, %s.%s.%d\n", d, a, db, table, rowId)
func commitHook(d interface{}) int {
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) {
......@@ -38,6 +47,8 @@ func TestNoTrace(t *testing.T) {
db.Profile(nil, nil)
db.ProgressHandler(nil, 0, nil)
db.BusyHandler(nil, nil)
db.CommitHook(nil, nil)
db.RollbackHook(nil, nil)
db.UpdateHook(nil, nil)
db.Close()
}
......@@ -51,6 +62,8 @@ func TestTrace(t *testing.T) {
}
db.Profile(profile, "PROFILE")
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)
}
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