mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Optimize. (#51)
This commit is contained in:
@@ -89,6 +89,7 @@ sqlite3_value_dup
|
||||
sqlite3_value_free
|
||||
sqlite3_value_int64
|
||||
sqlite3_value_nochange
|
||||
sqlite3_value_numeric_type
|
||||
sqlite3_value_pointer_go
|
||||
sqlite3_value_text
|
||||
sqlite3_value_type
|
||||
|
||||
Binary file not shown.
6
error.go
6
error.go
@@ -138,14 +138,14 @@ func (e ExtendedErrorCode) Timeout() bool {
|
||||
|
||||
func errorCode(err error, def ErrorCode) (msg string, code uint32) {
|
||||
switch code := err.(type) {
|
||||
case nil:
|
||||
return "", _OK
|
||||
case ErrorCode:
|
||||
return "", uint32(code)
|
||||
case ExtendedErrorCode:
|
||||
case xErrorCode:
|
||||
return "", uint32(code)
|
||||
case *Error:
|
||||
return code.msg, uint32(code.code)
|
||||
case nil:
|
||||
return "", _OK
|
||||
}
|
||||
|
||||
var ecode ErrorCode
|
||||
|
||||
@@ -96,13 +96,13 @@ func (fn *variance) Value(ctx sqlite3.Context) {
|
||||
}
|
||||
|
||||
func (fn *variance) Step(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
if a := arg[0]; a.Type() != sqlite3.NULL {
|
||||
if a := arg[0]; a.NumericType() != sqlite3.NULL {
|
||||
fn.enqueue(a.Float())
|
||||
}
|
||||
}
|
||||
|
||||
func (fn *variance) Inverse(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
if a := arg[0]; a.Type() != sqlite3.NULL {
|
||||
if a := arg[0]; a.NumericType() != sqlite3.NULL {
|
||||
fn.dequeue(a.Float())
|
||||
}
|
||||
}
|
||||
@@ -150,14 +150,14 @@ func (fn *covariance) Value(ctx sqlite3.Context) {
|
||||
|
||||
func (fn *covariance) Step(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
a, b := arg[0], arg[1]
|
||||
if a.Type() != sqlite3.NULL && b.Type() != sqlite3.NULL {
|
||||
if a.NumericType() != sqlite3.NULL && b.NumericType() != sqlite3.NULL {
|
||||
fn.enqueue(a.Float(), b.Float())
|
||||
}
|
||||
}
|
||||
|
||||
func (fn *covariance) Inverse(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
a, b := arg[0], arg[1]
|
||||
if a.Type() != sqlite3.NULL && b.Type() != sqlite3.NULL {
|
||||
if a.NumericType() != sqlite3.NULL && b.NumericType() != sqlite3.NULL {
|
||||
fn.dequeue(a.Float(), b.Float())
|
||||
}
|
||||
}
|
||||
|
||||
63
func.go
63
func.go
@@ -111,80 +111,59 @@ func compareCallback(ctx context.Context, mod api.Module, pApp, nKey1, pKey1, nK
|
||||
return uint32(fn(util.View(mod, pKey1, uint64(nKey1)), util.View(mod, pKey2, uint64(nKey2))))
|
||||
}
|
||||
|
||||
func funcCallback(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {
|
||||
func funcCallback(ctx context.Context, mod api.Module, pCtx, pApp, nArg, pArg uint32) {
|
||||
args := getFuncArgs()
|
||||
defer putFuncArgs(args)
|
||||
db := ctx.Value(connKey{}).(*Conn)
|
||||
fn := userDataHandle(db, pCtx).(ScalarFunction)
|
||||
fn := util.GetHandle(db.ctx, pApp).(ScalarFunction)
|
||||
callbackArgs(db, args[:nArg], pArg)
|
||||
fn(Context{db, pCtx}, args[:nArg]...)
|
||||
}
|
||||
|
||||
func stepCallback(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {
|
||||
func stepCallback(ctx context.Context, mod api.Module, pCtx, pAgg, pApp, nArg, pArg uint32) {
|
||||
args := getFuncArgs()
|
||||
defer putFuncArgs(args)
|
||||
db := ctx.Value(connKey{}).(*Conn)
|
||||
fn := aggregateCtxHandle(db, pCtx, nil)
|
||||
callbackArgs(db, args[:nArg], pArg)
|
||||
fn, _ := callbackAggregate(db, pAgg, pApp)
|
||||
fn.Step(Context{db, pCtx}, args[:nArg]...)
|
||||
}
|
||||
|
||||
func finalCallback(ctx context.Context, mod api.Module, pCtx uint32) {
|
||||
var handle uint32
|
||||
func finalCallback(ctx context.Context, mod api.Module, pCtx, pAgg, pApp uint32) {
|
||||
db := ctx.Value(connKey{}).(*Conn)
|
||||
fn := aggregateCtxHandle(db, pCtx, &handle)
|
||||
fn, handle := callbackAggregate(db, pAgg, pApp)
|
||||
fn.Value(Context{db, pCtx})
|
||||
if err := util.DelHandle(ctx, handle); err != nil {
|
||||
Context{db, pCtx}.ResultError(err)
|
||||
}
|
||||
util.DelHandle(ctx, handle)
|
||||
}
|
||||
|
||||
func valueCallback(ctx context.Context, mod api.Module, pCtx uint32) {
|
||||
func valueCallback(ctx context.Context, mod api.Module, pCtx, pAgg uint32) {
|
||||
db := ctx.Value(connKey{}).(*Conn)
|
||||
fn := aggregateCtxHandle(db, pCtx, nil)
|
||||
fn := util.GetHandle(db.ctx, pAgg).(AggregateFunction)
|
||||
fn.Value(Context{db, pCtx})
|
||||
}
|
||||
|
||||
func inverseCallback(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {
|
||||
func inverseCallback(ctx context.Context, mod api.Module, pCtx, pAgg, nArg, pArg uint32) {
|
||||
args := getFuncArgs()
|
||||
defer putFuncArgs(args)
|
||||
db := ctx.Value(connKey{}).(*Conn)
|
||||
fn := aggregateCtxHandle(db, pCtx, nil).(WindowFunction)
|
||||
callbackArgs(db, args[:nArg], pArg)
|
||||
fn := util.GetHandle(db.ctx, pAgg).(WindowFunction)
|
||||
fn.Inverse(Context{db, pCtx}, args[:nArg]...)
|
||||
}
|
||||
|
||||
func userDataHandle(db *Conn, pCtx uint32) any {
|
||||
pApp := uint32(db.call("sqlite3_user_data", uint64(pCtx)))
|
||||
return util.GetHandle(db.ctx, pApp)
|
||||
}
|
||||
|
||||
func aggregateCtxHandle(db *Conn, pCtx uint32, close *uint32) AggregateFunction {
|
||||
// On close, we're getting rid of the aggregate.
|
||||
// Don't allocate space to store it.
|
||||
var size uint64
|
||||
if close == nil {
|
||||
size = ptrlen
|
||||
}
|
||||
ptr := uint32(db.call("sqlite3_aggregate_context", uint64(pCtx), size))
|
||||
|
||||
// If we already have an aggregate, return it.
|
||||
if ptr != 0 {
|
||||
if handle := util.ReadUint32(db.mod, ptr); handle != 0 {
|
||||
fn := util.GetHandle(db.ctx, handle).(AggregateFunction)
|
||||
if close != nil {
|
||||
*close = handle
|
||||
}
|
||||
return fn
|
||||
}
|
||||
func callbackAggregate(db *Conn, pAgg, pApp uint32) (AggregateFunction, uint32) {
|
||||
if pApp == 0 {
|
||||
handle := util.ReadUint32(db.mod, pAgg)
|
||||
return util.GetHandle(db.ctx, handle).(AggregateFunction), handle
|
||||
}
|
||||
|
||||
// Create a new aggregate, and store it if needed.
|
||||
fn := userDataHandle(db, pCtx).(func() AggregateFunction)()
|
||||
if ptr != 0 {
|
||||
util.WriteUint32(db.mod, ptr, util.AddHandle(db.ctx, fn))
|
||||
// We need to create the aggregate.
|
||||
fn := util.GetHandle(db.ctx, pApp).(func() AggregateFunction)()
|
||||
handle := util.AddHandle(db.ctx, fn)
|
||||
if pAgg != 0 {
|
||||
util.WriteUint32(db.mod, pAgg, handle)
|
||||
}
|
||||
return fn
|
||||
return fn, handle
|
||||
}
|
||||
|
||||
func callbackArgs(db *Conn, arg []Value, pArg uint32) {
|
||||
|
||||
@@ -23,6 +23,19 @@ func ExportFuncVI[T0 i32](mod wazero.HostModuleBuilder, name string, fn func(con
|
||||
Export(name)
|
||||
}
|
||||
|
||||
type funcVII[T0, T1 i32] func(context.Context, api.Module, T0, T1)
|
||||
|
||||
func (fn funcVII[T0, T1]) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
fn(ctx, mod, T0(stack[0]), T1(stack[1]))
|
||||
}
|
||||
|
||||
func ExportFuncVII[T0, T1 i32](mod wazero.HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1)) {
|
||||
mod.NewFunctionBuilder().
|
||||
WithGoModuleFunction(funcVII[T0, T1](fn),
|
||||
[]api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, nil).
|
||||
Export(name)
|
||||
}
|
||||
|
||||
type funcVIII[T0, T1, T2 i32] func(context.Context, api.Module, T0, T1, T2)
|
||||
|
||||
func (fn funcVIII[T0, T1, T2]) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
@@ -36,6 +49,32 @@ func ExportFuncVIII[T0, T1, T2 i32](mod wazero.HostModuleBuilder, name string, f
|
||||
Export(name)
|
||||
}
|
||||
|
||||
type funcVIIII[T0, T1, T2, T3 i32] func(context.Context, api.Module, T0, T1, T2, T3)
|
||||
|
||||
func (fn funcVIIII[T0, T1, T2, T3]) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
fn(ctx, mod, T0(stack[0]), T1(stack[1]), T2(stack[2]), T3(stack[3]))
|
||||
}
|
||||
|
||||
func ExportFuncVIIII[T0, T1, T2, T3 i32](mod wazero.HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2, T3)) {
|
||||
mod.NewFunctionBuilder().
|
||||
WithGoModuleFunction(funcVIIII[T0, T1, T2, T3](fn),
|
||||
[]api.ValueType{api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32}, nil).
|
||||
Export(name)
|
||||
}
|
||||
|
||||
type funcVIIIII[T0, T1, T2, T3, T4 i32] func(context.Context, api.Module, T0, T1, T2, T3, T4)
|
||||
|
||||
func (fn funcVIIIII[T0, T1, T2, T3, T4]) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
fn(ctx, mod, T0(stack[0]), T1(stack[1]), T2(stack[2]), T3(stack[3]), T4(stack[4]))
|
||||
}
|
||||
|
||||
func ExportFuncVIIIII[T0, T1, T2, T3, T4 i32](mod wazero.HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2, T3, T4)) {
|
||||
mod.NewFunctionBuilder().
|
||||
WithGoModuleFunction(funcVIIIII[T0, T1, T2, T3, T4](fn),
|
||||
[]api.ValueType{api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32}, nil).
|
||||
Export(name)
|
||||
}
|
||||
|
||||
type funcII[TR, T0 i32] func(context.Context, api.Module, T0) TR
|
||||
|
||||
func (fn funcII[TR, T0]) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
|
||||
10
sqlite.go
10
sqlite.go
@@ -284,11 +284,11 @@ func exportCallbacks(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
|
||||
util.ExportFuncII(env, "go_progress", progressCallback)
|
||||
util.ExportFuncVIII(env, "go_log", logCallback)
|
||||
util.ExportFuncVI(env, "go_destroy", destroyCallback)
|
||||
util.ExportFuncVIII(env, "go_func", funcCallback)
|
||||
util.ExportFuncVIII(env, "go_step", stepCallback)
|
||||
util.ExportFuncVI(env, "go_final", finalCallback)
|
||||
util.ExportFuncVI(env, "go_value", valueCallback)
|
||||
util.ExportFuncVIII(env, "go_inverse", inverseCallback)
|
||||
util.ExportFuncVIIII(env, "go_func", funcCallback)
|
||||
util.ExportFuncVIIIII(env, "go_step", stepCallback)
|
||||
util.ExportFuncVIII(env, "go_final", finalCallback)
|
||||
util.ExportFuncVII(env, "go_value", valueCallback)
|
||||
util.ExportFuncVIIII(env, "go_inverse", inverseCallback)
|
||||
util.ExportFuncIIIIII(env, "go_compare", compareCallback)
|
||||
util.ExportFuncIIIIII(env, "go_vtab_create", vtabModuleCallback(0))
|
||||
util.ExportFuncIIIIII(env, "go_vtab_connect", vtabModuleCallback(1))
|
||||
|
||||
@@ -3,14 +3,47 @@
|
||||
#include "include.h"
|
||||
#include "sqlite3.h"
|
||||
|
||||
void go_func(sqlite3_context *, int, sqlite3_value **);
|
||||
void go_step(sqlite3_context *, int, sqlite3_value **);
|
||||
void go_final(sqlite3_context *);
|
||||
void go_value(sqlite3_context *);
|
||||
void go_inverse(sqlite3_context *, int, sqlite3_value **);
|
||||
|
||||
int go_compare(go_handle, int, const void *, int, const void *);
|
||||
|
||||
void go_func(sqlite3_context *, go_handle, int, sqlite3_value **);
|
||||
|
||||
void go_step(sqlite3_context *, go_handle *, go_handle, int, sqlite3_value **);
|
||||
void go_final(sqlite3_context *, go_handle, go_handle);
|
||||
void go_value(sqlite3_context *, go_handle);
|
||||
void go_inverse(sqlite3_context *, go_handle *, int, sqlite3_value **);
|
||||
|
||||
void go_func_wrapper(sqlite3_context *ctx, int nArg, sqlite3_value **pArg) {
|
||||
go_func(ctx, sqlite3_user_data(ctx), nArg, pArg);
|
||||
}
|
||||
|
||||
void go_step_wrapper(sqlite3_context *ctx, int nArg, sqlite3_value **pArg) {
|
||||
go_handle *agg = sqlite3_aggregate_context(ctx, 4);
|
||||
go_handle data = NULL;
|
||||
if (agg == NULL || *agg == NULL) {
|
||||
data = sqlite3_user_data(ctx);
|
||||
}
|
||||
go_step(ctx, agg, data, nArg, pArg);
|
||||
}
|
||||
|
||||
void go_final_wrapper(sqlite3_context *ctx) {
|
||||
go_handle *agg = sqlite3_aggregate_context(ctx, 0);
|
||||
go_handle data = NULL;
|
||||
if (agg == NULL || *agg == NULL) {
|
||||
data = sqlite3_user_data(ctx);
|
||||
}
|
||||
go_final(ctx, agg, data);
|
||||
}
|
||||
|
||||
void go_value_wrapper(sqlite3_context *ctx) {
|
||||
go_handle *agg = sqlite3_aggregate_context(ctx, 4);
|
||||
go_value(ctx, *agg);
|
||||
}
|
||||
|
||||
void go_inverse_wrapper(sqlite3_context *ctx, int nArg, sqlite3_value **pArg) {
|
||||
go_handle *agg = sqlite3_aggregate_context(ctx, 4);
|
||||
go_inverse(ctx, *agg, nArg, pArg);
|
||||
}
|
||||
|
||||
int sqlite3_create_collation_go(sqlite3 *db, const char *name, go_handle app) {
|
||||
int rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF8, app, go_compare,
|
||||
go_destroy);
|
||||
@@ -21,22 +54,22 @@ int sqlite3_create_collation_go(sqlite3 *db, const char *name, go_handle app) {
|
||||
int sqlite3_create_function_go(sqlite3 *db, const char *name, int argc,
|
||||
int flags, go_handle app) {
|
||||
return sqlite3_create_function_v2(db, name, argc, SQLITE_UTF8 | flags, app,
|
||||
go_func, /*step=*/NULL, /*final=*/NULL,
|
||||
go_destroy);
|
||||
go_func_wrapper, /*step=*/NULL,
|
||||
/*final=*/NULL, go_destroy);
|
||||
}
|
||||
|
||||
int sqlite3_create_aggregate_function_go(sqlite3 *db, const char *name,
|
||||
int argc, int flags, go_handle app) {
|
||||
return sqlite3_create_window_function(db, name, argc, SQLITE_UTF8 | flags,
|
||||
app, go_step, go_final, /*value=*/NULL,
|
||||
/*inverse=*/NULL, go_destroy);
|
||||
return sqlite3_create_function_v2(db, name, argc, SQLITE_UTF8 | flags, app,
|
||||
/*func=*/NULL, go_step_wrapper,
|
||||
go_final_wrapper, go_destroy);
|
||||
}
|
||||
|
||||
int sqlite3_create_window_function_go(sqlite3 *db, const char *name, int argc,
|
||||
int flags, go_handle app) {
|
||||
return sqlite3_create_window_function(db, name, argc, SQLITE_UTF8 | flags,
|
||||
app, go_step, go_final, go_value,
|
||||
go_inverse, go_destroy);
|
||||
return sqlite3_create_window_function(
|
||||
db, name, argc, SQLITE_UTF8 | flags, app, go_step_wrapper,
|
||||
go_final_wrapper, go_value_wrapper, go_inverse_wrapper, go_destroy);
|
||||
}
|
||||
|
||||
void sqlite3_set_auxdata_go(sqlite3_context *ctx, int i, go_handle aux) {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
void go_log(void*, int, const char*);
|
||||
void go_log(void *, int, const char *);
|
||||
|
||||
int sqlite3_config_log_go(bool enable) {
|
||||
return sqlite3_config(SQLITE_CONFIG_LOG, enable ? go_log : NULL, NULL);
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,7 @@ static int go_vtab_find_function_wrapper(
|
||||
go_handle handle;
|
||||
int rc = go_vtab_find_function(pVTab, nArg, zName, &handle);
|
||||
if (rc) {
|
||||
*pxFunc = go_func;
|
||||
*pxFunc = go_func_wrapper;
|
||||
*ppArg = handle;
|
||||
}
|
||||
return rc;
|
||||
|
||||
10
value.go
10
value.go
@@ -50,7 +50,7 @@ func (dup *Value) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type returns the initial [Datatype] of the value.
|
||||
// Type returns the initial datatype of the value.
|
||||
//
|
||||
// https://sqlite.org/c3ref/value_blob.html
|
||||
func (v Value) Type() Datatype {
|
||||
@@ -58,6 +58,14 @@ func (v Value) Type() Datatype {
|
||||
return Datatype(r)
|
||||
}
|
||||
|
||||
// Type returns the numeric datatype of the value.
|
||||
//
|
||||
// https://sqlite.org/c3ref/value_blob.html
|
||||
func (v Value) NumericType() Datatype {
|
||||
r := v.c.call("sqlite3_value_numeric_type", v.protected())
|
||||
return Datatype(r)
|
||||
}
|
||||
|
||||
// Bool returns the value as a bool.
|
||||
// SQLite does not have a separate boolean storage class.
|
||||
// Instead, boolean values are retrieved as integers,
|
||||
|
||||
28
vtab.go
28
vtab.go
@@ -168,7 +168,7 @@ type VTabOverloader interface {
|
||||
}
|
||||
|
||||
// A VTabChecker allows a virtual table to report errors
|
||||
// to the PRAGMA integrity_check PRAGMA quick_check commands.
|
||||
// to the PRAGMA integrity_check and PRAGMA quick_check commands.
|
||||
//
|
||||
// Integrity should return an error if it finds problems in the content of the virtual table,
|
||||
// but should avoid returning a (wrapped) [Error], [ErrorCode] or [ExtendedErrorCode],
|
||||
@@ -283,8 +283,8 @@ type IndexConstraintUsage struct {
|
||||
func (idx *IndexInfo) RHSValue(column int) (Value, error) {
|
||||
defer idx.c.arena.mark()()
|
||||
valPtr := idx.c.arena.new(ptrlen)
|
||||
r := idx.c.call("sqlite3_vtab_rhs_value",
|
||||
uint64(idx.handle), uint64(column), uint64(valPtr))
|
||||
r := idx.c.call("sqlite3_vtab_rhs_value", uint64(idx.handle),
|
||||
uint64(column), uint64(valPtr))
|
||||
if err := idx.c.error(r); err != nil {
|
||||
return Value{}, err
|
||||
}
|
||||
@@ -298,8 +298,8 @@ func (idx *IndexInfo) RHSValue(column int) (Value, error) {
|
||||
//
|
||||
// https://sqlite.org/c3ref/vtab_collation.html
|
||||
func (idx *IndexInfo) Collation(column int) string {
|
||||
r := idx.c.call("sqlite3_vtab_collation",
|
||||
uint64(idx.handle), uint64(column))
|
||||
r := idx.c.call("sqlite3_vtab_collation", uint64(idx.handle),
|
||||
uint64(column))
|
||||
return util.ReadString(idx.c.mod, uint32(r), _MAX_NAME)
|
||||
}
|
||||
|
||||
@@ -315,7 +315,8 @@ func (idx *IndexInfo) Distinct() int {
|
||||
//
|
||||
// https://sqlite.org/c3ref/vtab_in.html
|
||||
func (idx *IndexInfo) In(column, handle int) bool {
|
||||
r := idx.c.call("sqlite3_vtab_in", uint64(idx.handle), uint64(column), uint64(handle))
|
||||
r := idx.c.call("sqlite3_vtab_in", uint64(idx.handle),
|
||||
uint64(column), uint64(handle))
|
||||
return r != 0
|
||||
}
|
||||
|
||||
@@ -483,13 +484,14 @@ func vtabRenameCallback(ctx context.Context, mod api.Module, pVTab, zNew uint32)
|
||||
|
||||
func vtabFindFuncCallback(ctx context.Context, mod api.Module, pVTab, nArg, zName, pxFunc uint32) uint32 {
|
||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabOverloader)
|
||||
fn, op := vtab.FindFunction(int(nArg), util.ReadString(mod, zName, _MAX_NAME))
|
||||
if fn != nil {
|
||||
handle := util.AddHandle(ctx, fn)
|
||||
util.WriteUint32(mod, pxFunc, handle)
|
||||
if op == 0 {
|
||||
op = 1
|
||||
}
|
||||
f, op := vtab.FindFunction(int(nArg), util.ReadString(mod, zName, _MAX_NAME))
|
||||
if op != 0 {
|
||||
var wrapper uint32
|
||||
wrapper = util.AddHandle(ctx, func(c Context, arg ...Value) {
|
||||
defer util.DelHandle(ctx, wrapper)
|
||||
f(c, arg...)
|
||||
})
|
||||
util.WriteUint32(mod, pxFunc, wrapper)
|
||||
}
|
||||
return uint32(op)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user