fix build
This commit is contained in:
parent
467e3720d8
commit
bf2cfc371a
183
sqlite3.go
183
sqlite3.go
|
@ -98,15 +98,6 @@ int _sqlite3_create_function(
|
||||||
}
|
}
|
||||||
|
|
||||||
void callbackTrampoline(sqlite3_context*, int, sqlite3_value**);
|
void callbackTrampoline(sqlite3_context*, int, sqlite3_value**);
|
||||||
void stepTrampoline(sqlite3_context*, int, sqlite3_value**);
|
|
||||||
void doneTrampoline(sqlite3_context*);
|
|
||||||
|
|
||||||
int
|
|
||||||
_sqlite3_trace_v2(sqlite3* db, unsigned mask, int(*xc)(unsigned,void*,void*,void*), void *ctx) {
|
|
||||||
return sqlite3_trace_v2(db, mask, xc, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void traceCallbackTrampoline(unsigned traceEventCode, void *ctx, void *p, void *x);
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
@ -396,180 +387,6 @@ func (c *SQLiteConn) RegisterFunc(name string, impl interface{}, pure bool) erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterAggregator makes a Go type available as a SQLite aggregation function.
|
|
||||||
//
|
|
||||||
// Because aggregation is incremental, it's implemented in Go with a
|
|
||||||
// type that has 2 methods: func Step(values) accumulates one row of
|
|
||||||
// data into the accumulator, and func Done() ret finalizes and
|
|
||||||
// returns the aggregate value. "values" and "ret" may be any type
|
|
||||||
// supported by RegisterFunc.
|
|
||||||
//
|
|
||||||
// RegisterAggregator takes as implementation a constructor function
|
|
||||||
// that constructs an instance of the aggregator type each time an
|
|
||||||
// aggregation begins. The constructor must return a pointer to a
|
|
||||||
// type, or an interface that implements Step() and Done().
|
|
||||||
//
|
|
||||||
// The constructor function and the Step/Done methods may optionally
|
|
||||||
// return an error in addition to their other return values.
|
|
||||||
//
|
|
||||||
// See _example/go_custom_funcs for a detailed example.
|
|
||||||
func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool) error {
|
|
||||||
var ai aggInfo
|
|
||||||
ai.constructor = reflect.ValueOf(impl)
|
|
||||||
t := ai.constructor.Type()
|
|
||||||
if t.Kind() != reflect.Func {
|
|
||||||
return errors.New("non-function passed to RegisterAggregator")
|
|
||||||
}
|
|
||||||
if t.NumOut() != 1 && t.NumOut() != 2 {
|
|
||||||
return errors.New("SQLite aggregator constructors must return 1 or 2 values")
|
|
||||||
}
|
|
||||||
if t.NumOut() == 2 && !t.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
|
||||||
return errors.New("Second return value of SQLite function must be error")
|
|
||||||
}
|
|
||||||
if t.NumIn() != 0 {
|
|
||||||
return errors.New("SQLite aggregator constructors must not have arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
agg := t.Out(0)
|
|
||||||
switch agg.Kind() {
|
|
||||||
case reflect.Ptr, reflect.Interface:
|
|
||||||
default:
|
|
||||||
return errors.New("SQlite aggregator constructor must return a pointer object")
|
|
||||||
}
|
|
||||||
stepFn, found := agg.MethodByName("Step")
|
|
||||||
if !found {
|
|
||||||
return errors.New("SQlite aggregator doesn't have a Step() function")
|
|
||||||
}
|
|
||||||
step := stepFn.Type
|
|
||||||
if step.NumOut() != 0 && step.NumOut() != 1 {
|
|
||||||
return errors.New("SQlite aggregator Step() function must return 0 or 1 values")
|
|
||||||
}
|
|
||||||
if step.NumOut() == 1 && !step.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
|
||||||
return errors.New("type of SQlite aggregator Step() return value must be error")
|
|
||||||
}
|
|
||||||
|
|
||||||
stepNArgs := step.NumIn()
|
|
||||||
start := 0
|
|
||||||
if agg.Kind() == reflect.Ptr {
|
|
||||||
// Skip over the method receiver
|
|
||||||
stepNArgs--
|
|
||||||
start++
|
|
||||||
}
|
|
||||||
if step.IsVariadic() {
|
|
||||||
stepNArgs--
|
|
||||||
}
|
|
||||||
for i := start; i < start+stepNArgs; i++ {
|
|
||||||
conv, err := callbackArg(step.In(i))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ai.stepArgConverters = append(ai.stepArgConverters, conv)
|
|
||||||
}
|
|
||||||
if step.IsVariadic() {
|
|
||||||
conv, err := callbackArg(t.In(start + stepNArgs).Elem())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ai.stepVariadicConverter = conv
|
|
||||||
// Pass -1 to sqlite so that it allows any number of
|
|
||||||
// arguments. The call helper verifies that the minimum number
|
|
||||||
// of arguments is present for variadic functions.
|
|
||||||
stepNArgs = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
doneFn, found := agg.MethodByName("Done")
|
|
||||||
if !found {
|
|
||||||
return errors.New("SQlite aggregator doesn't have a Done() function")
|
|
||||||
}
|
|
||||||
done := doneFn.Type
|
|
||||||
doneNArgs := done.NumIn()
|
|
||||||
if agg.Kind() == reflect.Ptr {
|
|
||||||
// Skip over the method receiver
|
|
||||||
doneNArgs--
|
|
||||||
}
|
|
||||||
if doneNArgs != 0 {
|
|
||||||
return errors.New("SQlite aggregator Done() function must have no arguments")
|
|
||||||
}
|
|
||||||
if done.NumOut() != 1 && done.NumOut() != 2 {
|
|
||||||
return errors.New("SQLite aggregator Done() function must return 1 or 2 values")
|
|
||||||
}
|
|
||||||
if done.NumOut() == 2 && !done.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
|
||||||
return errors.New("second return value of SQLite aggregator Done() function must be error")
|
|
||||||
}
|
|
||||||
|
|
||||||
conv, err := callbackRet(done.Out(0))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ai.doneRetConverter = conv
|
|
||||||
ai.active = make(map[int64]reflect.Value)
|
|
||||||
ai.next = 1
|
|
||||||
|
|
||||||
// ai must outlast the database connection, or we'll have dangling pointers.
|
|
||||||
c.aggregators = append(c.aggregators, &ai)
|
|
||||||
|
|
||||||
cname := C.CString(name)
|
|
||||||
defer C.free(unsafe.Pointer(cname))
|
|
||||||
opts := C.SQLITE_UTF8
|
|
||||||
if pure {
|
|
||||||
opts |= C.SQLITE_DETERMINISTIC
|
|
||||||
}
|
|
||||||
rv := C._sqlite3_create_function(c.db, cname, C.int(stepNArgs), C.int(opts), C.uintptr_t(newHandle(c, &ai)), nil, (*[0]byte)(unsafe.Pointer(C.stepTrampoline)), (*[0]byte)(unsafe.Pointer(C.doneTrampoline)))
|
|
||||||
if rv != C.SQLITE_OK {
|
|
||||||
return c.lastError()
|
|
||||||
}
|
|
||||||
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.
|
// AutoCommit return which currently auto commit or not.
|
||||||
func (c *SQLiteConn) AutoCommit() bool {
|
func (c *SQLiteConn) AutoCommit() bool {
|
||||||
return int(C.sqlite3_get_autocommit(c.db)) != 0
|
return int(C.sqlite3_get_autocommit(c.db)) != 0
|
||||||
|
|
187
tracecallback.go
187
tracecallback.go
|
@ -3,6 +3,7 @@
|
||||||
//
|
//
|
||||||
// Use of this source code is governed by an MIT-style
|
// Use of this source code is governed by an MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
// +build trace
|
||||||
|
|
||||||
package sqlite3
|
package sqlite3
|
||||||
|
|
||||||
|
@ -13,11 +14,23 @@ package sqlite3
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
#endif
|
#endif
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void stepTrampoline(sqlite3_context*, int, sqlite3_value**);
|
||||||
|
void doneTrampoline(sqlite3_context*);
|
||||||
|
|
||||||
|
int
|
||||||
|
_sqlite3_trace_v2(sqlite3* db, unsigned mask, int(*xc)(unsigned,void*,void*,void*), void *ctx) {
|
||||||
|
return sqlite3_trace_v2(db, mask, xc, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void traceCallbackTrampoline(unsigned traceEventCode, void *ctx, void *p, void *x);
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -232,3 +245,177 @@ func popTraceMapping(connHandle uintptr) (TraceConfig, bool) {
|
||||||
}
|
}
|
||||||
return entryCopy.config, found
|
return entryCopy.config, found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterAggregator makes a Go type available as a SQLite aggregation function.
|
||||||
|
//
|
||||||
|
// Because aggregation is incremental, it's implemented in Go with a
|
||||||
|
// type that has 2 methods: func Step(values) accumulates one row of
|
||||||
|
// data into the accumulator, and func Done() ret finalizes and
|
||||||
|
// returns the aggregate value. "values" and "ret" may be any type
|
||||||
|
// supported by RegisterFunc.
|
||||||
|
//
|
||||||
|
// RegisterAggregator takes as implementation a constructor function
|
||||||
|
// that constructs an instance of the aggregator type each time an
|
||||||
|
// aggregation begins. The constructor must return a pointer to a
|
||||||
|
// type, or an interface that implements Step() and Done().
|
||||||
|
//
|
||||||
|
// The constructor function and the Step/Done methods may optionally
|
||||||
|
// return an error in addition to their other return values.
|
||||||
|
//
|
||||||
|
// See _example/go_custom_funcs for a detailed example.
|
||||||
|
func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool) error {
|
||||||
|
var ai aggInfo
|
||||||
|
ai.constructor = reflect.ValueOf(impl)
|
||||||
|
t := ai.constructor.Type()
|
||||||
|
if t.Kind() != reflect.Func {
|
||||||
|
return errors.New("non-function passed to RegisterAggregator")
|
||||||
|
}
|
||||||
|
if t.NumOut() != 1 && t.NumOut() != 2 {
|
||||||
|
return errors.New("SQLite aggregator constructors must return 1 or 2 values")
|
||||||
|
}
|
||||||
|
if t.NumOut() == 2 && !t.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||||
|
return errors.New("Second return value of SQLite function must be error")
|
||||||
|
}
|
||||||
|
if t.NumIn() != 0 {
|
||||||
|
return errors.New("SQLite aggregator constructors must not have arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
agg := t.Out(0)
|
||||||
|
switch agg.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Interface:
|
||||||
|
default:
|
||||||
|
return errors.New("SQlite aggregator constructor must return a pointer object")
|
||||||
|
}
|
||||||
|
stepFn, found := agg.MethodByName("Step")
|
||||||
|
if !found {
|
||||||
|
return errors.New("SQlite aggregator doesn't have a Step() function")
|
||||||
|
}
|
||||||
|
step := stepFn.Type
|
||||||
|
if step.NumOut() != 0 && step.NumOut() != 1 {
|
||||||
|
return errors.New("SQlite aggregator Step() function must return 0 or 1 values")
|
||||||
|
}
|
||||||
|
if step.NumOut() == 1 && !step.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||||
|
return errors.New("type of SQlite aggregator Step() return value must be error")
|
||||||
|
}
|
||||||
|
|
||||||
|
stepNArgs := step.NumIn()
|
||||||
|
start := 0
|
||||||
|
if agg.Kind() == reflect.Ptr {
|
||||||
|
// Skip over the method receiver
|
||||||
|
stepNArgs--
|
||||||
|
start++
|
||||||
|
}
|
||||||
|
if step.IsVariadic() {
|
||||||
|
stepNArgs--
|
||||||
|
}
|
||||||
|
for i := start; i < start+stepNArgs; i++ {
|
||||||
|
conv, err := callbackArg(step.In(i))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ai.stepArgConverters = append(ai.stepArgConverters, conv)
|
||||||
|
}
|
||||||
|
if step.IsVariadic() {
|
||||||
|
conv, err := callbackArg(t.In(start + stepNArgs).Elem())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ai.stepVariadicConverter = conv
|
||||||
|
// Pass -1 to sqlite so that it allows any number of
|
||||||
|
// arguments. The call helper verifies that the minimum number
|
||||||
|
// of arguments is present for variadic functions.
|
||||||
|
stepNArgs = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
doneFn, found := agg.MethodByName("Done")
|
||||||
|
if !found {
|
||||||
|
return errors.New("SQlite aggregator doesn't have a Done() function")
|
||||||
|
}
|
||||||
|
done := doneFn.Type
|
||||||
|
doneNArgs := done.NumIn()
|
||||||
|
if agg.Kind() == reflect.Ptr {
|
||||||
|
// Skip over the method receiver
|
||||||
|
doneNArgs--
|
||||||
|
}
|
||||||
|
if doneNArgs != 0 {
|
||||||
|
return errors.New("SQlite aggregator Done() function must have no arguments")
|
||||||
|
}
|
||||||
|
if done.NumOut() != 1 && done.NumOut() != 2 {
|
||||||
|
return errors.New("SQLite aggregator Done() function must return 1 or 2 values")
|
||||||
|
}
|
||||||
|
if done.NumOut() == 2 && !done.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||||
|
return errors.New("second return value of SQLite aggregator Done() function must be error")
|
||||||
|
}
|
||||||
|
|
||||||
|
conv, err := callbackRet(done.Out(0))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ai.doneRetConverter = conv
|
||||||
|
ai.active = make(map[int64]reflect.Value)
|
||||||
|
ai.next = 1
|
||||||
|
|
||||||
|
// ai must outlast the database connection, or we'll have dangling pointers.
|
||||||
|
c.aggregators = append(c.aggregators, &ai)
|
||||||
|
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
opts := C.SQLITE_UTF8
|
||||||
|
if pure {
|
||||||
|
opts |= C.SQLITE_DETERMINISTIC
|
||||||
|
}
|
||||||
|
rv := C._sqlite3_create_function(c.db, cname, C.int(stepNArgs), C.int(opts), C.uintptr_t(newHandle(c, &ai)), nil, (*[0]byte)(unsafe.Pointer(C.stepTrampoline)), (*[0]byte)(unsafe.Pointer(C.doneTrampoline)))
|
||||||
|
if rv != C.SQLITE_OK {
|
||||||
|
return c.lastError()
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue