Optimize. (#51)

This commit is contained in:
Nuno Cruces
2024-01-11 02:18:12 +00:00
committed by GitHub
parent 97f2b73701
commit 6b0c2c0554
12 changed files with 147 additions and 85 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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
View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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))

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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
View File

@@ -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)
}