diff options
author | A.N <gimpldo@gmail.com> | 2016-09-05 21:58:10 +0300 |
---|---|---|
committer | Yasuhiro Matsumoto <mattn.jp@gmail.com> | 2016-09-07 23:48:06 +0900 |
commit | 0a2fcd29b6b8afa57f230ae11abbd41a34388e67 (patch) | |
tree | b36b11b70602c6bd565143549187eda4933c624c /sqlite3.go | |
parent | Merge pull request #323 from FiloSottile/master (diff) | |
download | golite-0a2fcd29b6b8afa57f230ae11abbd41a34388e67.tar.gz golite-0a2fcd29b6b8afa57f230ae11abbd41a34388e67.tar.xz |
Provide access to sqlite3_trace_v2().
Diffstat (limited to 'sqlite3.go')
-rw-r--r-- | sqlite3.go | 52 |
1 files changed, 52 insertions, 0 deletions
@@ -9,6 +9,7 @@ package sqlite3 #cgo CFLAGS: -std=gnu99 #cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE #cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61 +#cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15 #ifndef USE_LIBSQLITE3 #include <sqlite3-binding.h> #else @@ -99,6 +100,8 @@ int _sqlite3_create_function( void callbackTrampoline(sqlite3_context*, int, sqlite3_value**); void stepTrampoline(sqlite3_context*, int, sqlite3_value**); void doneTrampoline(sqlite3_context*); + +void traceCallbackTrampoline(unsigned traceEventCode, void *ctx, void *p, void *x); */ import "C" import ( @@ -513,6 +516,55 @@ func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool return nil } +// SetTrace installs or removes the trace callback for the given database connection. +// It's not named 'RegisterTrace' because only one callback can be kept and called. +// Calling SetTrace a second time on same database connection +// overrides (cancels) any prior callback and all its settings: +// event mask, etc. +func (c *SQLiteConn) SetTrace(requested *TraceConfig) error { + connHandle := uintptr(unsafe.Pointer(c.db)) + + _, _ = popTraceMapping(connHandle) + + if requested == nil { + // The traceMap entry was deleted already by popTraceMapping(): + // can disable all events now, no need to watch for TraceClose. + err := c.setSQLiteTrace(0) + return err + } + + reqCopy := *requested + + // Disable potentially expensive operations + // if their result will not be used. We are doing this + // just in case the caller provided nonsensical input. + if reqCopy.EventMask&TraceStmt == 0 { + reqCopy.WantExpandedSQL = false + } + + addTraceMapping(connHandle, reqCopy) + + // The callback trampoline function does cleanup on Close event, + // regardless of the presence or absence of the user callback. + // Therefore it needs the Close event to be selected: + actualEventMask := reqCopy.EventMask | TraceClose + err := c.setSQLiteTrace(actualEventMask) + return err +} + +func (c *SQLiteConn) setSQLiteTrace(sqliteEventMask uint) error { + rv := C.sqlite3_trace_v2(c.db, + C.uint(sqliteEventMask), + (*[0]byte)(unsafe.Pointer(C.traceCallbackTrampoline)), + unsafe.Pointer(c.db)) // Fourth arg is same as first: we are + // passing the database connection handle as callback context. + + if rv != C.SQLITE_OK { + return c.lastError() + } + return nil +} + // AutoCommit return which currently auto commit or not. func (c *SQLiteConn) AutoCommit() bool { return int(C.sqlite3_get_autocommit(c.db)) != 0 |