aboutsummaryrefslogtreecommitdiff
path: root/sqlite3.go
diff options
context:
space:
mode:
authorA.N <gimpldo@gmail.com>2016-09-05 21:58:10 +0300
committerYasuhiro Matsumoto <mattn.jp@gmail.com>2016-09-07 23:48:06 +0900
commit0a2fcd29b6b8afa57f230ae11abbd41a34388e67 (patch)
treeb36b11b70602c6bd565143549187eda4933c624c /sqlite3.go
parentMerge pull request #323 from FiloSottile/master (diff)
downloadgolite-0a2fcd29b6b8afa57f230ae11abbd41a34388e67.tar.gz
golite-0a2fcd29b6b8afa57f230ae11abbd41a34388e67.tar.xz
Provide access to sqlite3_trace_v2().
Diffstat (limited to 'sqlite3.go')
-rw-r--r--sqlite3.go52
1 files changed, 52 insertions, 0 deletions
diff --git a/sqlite3.go b/sqlite3.go
index f3c1226..eb016d7 100644
--- a/sqlite3.go
+++ b/sqlite3.go
@@ -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