|
|
|
|
@ -2,6 +2,7 @@ package sqlite3
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"context" |
|
|
|
|
"errors" |
|
|
|
|
"reflect" |
|
|
|
|
|
|
|
|
|
"github.com/tetratelabs/wazero/api" |
|
|
|
|
@ -58,15 +59,15 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor
|
|
|
|
|
flags |= VTAB_SHADOWTABS |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var modulePtr uint32 |
|
|
|
|
var modulePtr ptr_t |
|
|
|
|
defer db.arena.mark()() |
|
|
|
|
namePtr := db.arena.string(name) |
|
|
|
|
if connect != nil { |
|
|
|
|
modulePtr = util.AddHandle(db.ctx, module[T]{create, connect}) |
|
|
|
|
} |
|
|
|
|
r := db.call("sqlite3_create_module_go", uint64(db.handle), |
|
|
|
|
uint64(namePtr), uint64(flags), uint64(modulePtr)) |
|
|
|
|
return db.error(r) |
|
|
|
|
rc := res_t(db.call("sqlite3_create_module_go", stk_t(db.handle), |
|
|
|
|
stk_t(namePtr), stk_t(flags), stk_t(modulePtr))) |
|
|
|
|
return db.error(rc) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func implements[T any](typ reflect.Type) bool { |
|
|
|
|
@ -80,8 +81,8 @@ func implements[T any](typ reflect.Type) bool {
|
|
|
|
|
func (c *Conn) DeclareVTab(sql string) error { |
|
|
|
|
defer c.arena.mark()() |
|
|
|
|
sqlPtr := c.arena.string(sql) |
|
|
|
|
r := c.call("sqlite3_declare_vtab", uint64(c.handle), uint64(sqlPtr)) |
|
|
|
|
return c.error(r) |
|
|
|
|
rc := res_t(c.call("sqlite3_declare_vtab", stk_t(c.handle), stk_t(sqlPtr))) |
|
|
|
|
return c.error(rc) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// VTabConflictMode is a virtual table conflict resolution mode.
|
|
|
|
|
@ -101,8 +102,7 @@ const (
|
|
|
|
|
//
|
|
|
|
|
// https://sqlite.org/c3ref/vtab_on_conflict.html
|
|
|
|
|
func (c *Conn) VTabOnConflict() VTabConflictMode { |
|
|
|
|
r := c.call("sqlite3_vtab_on_conflict", uint64(c.handle)) |
|
|
|
|
return VTabConflictMode(r) |
|
|
|
|
return VTabConflictMode(c.call("sqlite3_vtab_on_conflict", stk_t(c.handle))) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// VTabConfigOption is a virtual table configuration option.
|
|
|
|
|
@ -121,14 +121,14 @@ const (
|
|
|
|
|
//
|
|
|
|
|
// https://sqlite.org/c3ref/vtab_config.html
|
|
|
|
|
func (c *Conn) VTabConfig(op VTabConfigOption, args ...any) error { |
|
|
|
|
var i uint64 |
|
|
|
|
var i int32 |
|
|
|
|
if op == VTAB_CONSTRAINT_SUPPORT && len(args) > 0 { |
|
|
|
|
if b, ok := args[0].(bool); ok && b { |
|
|
|
|
i = 1 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
r := c.call("sqlite3_vtab_config_go", uint64(c.handle), uint64(op), i) |
|
|
|
|
return c.error(r) |
|
|
|
|
rc := res_t(c.call("sqlite3_vtab_config_go", stk_t(c.handle), stk_t(op), stk_t(i))) |
|
|
|
|
return c.error(rc) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// VTabConstructor is a virtual table constructor function.
|
|
|
|
|
@ -263,7 +263,7 @@ type IndexInfo struct {
|
|
|
|
|
// Inputs
|
|
|
|
|
Constraint []IndexConstraint |
|
|
|
|
OrderBy []IndexOrderBy |
|
|
|
|
ColumnsUsed int64 |
|
|
|
|
ColumnsUsed uint64 |
|
|
|
|
// Outputs
|
|
|
|
|
ConstraintUsage []IndexConstraintUsage |
|
|
|
|
IdxNum int |
|
|
|
|
@ -274,7 +274,7 @@ type IndexInfo struct {
|
|
|
|
|
EstimatedRows int64 |
|
|
|
|
// Internal
|
|
|
|
|
c *Conn |
|
|
|
|
handle uint32 |
|
|
|
|
handle ptr_t |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// An IndexConstraint describes virtual table indexing constraint information.
|
|
|
|
|
@ -309,14 +309,14 @@ 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)) |
|
|
|
|
if err := idx.c.error(r); err != nil { |
|
|
|
|
rc := res_t(idx.c.call("sqlite3_vtab_rhs_value", stk_t(idx.handle), |
|
|
|
|
stk_t(column), stk_t(valPtr))) |
|
|
|
|
if err := idx.c.error(rc); err != nil { |
|
|
|
|
return Value{}, err |
|
|
|
|
} |
|
|
|
|
return Value{ |
|
|
|
|
c: idx.c, |
|
|
|
|
handle: util.ReadUint32(idx.c.mod, valPtr), |
|
|
|
|
handle: util.Read32[ptr_t](idx.c.mod, valPtr), |
|
|
|
|
}, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -324,26 +324,26 @@ 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)) |
|
|
|
|
return util.ReadString(idx.c.mod, uint32(r), _MAX_NAME) |
|
|
|
|
ptr := ptr_t(idx.c.call("sqlite3_vtab_collation", stk_t(idx.handle), |
|
|
|
|
stk_t(column))) |
|
|
|
|
return util.ReadString(idx.c.mod, ptr, _MAX_NAME) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Distinct determines if a virtual table query is DISTINCT.
|
|
|
|
|
//
|
|
|
|
|
// https://sqlite.org/c3ref/vtab_distinct.html
|
|
|
|
|
func (idx *IndexInfo) Distinct() int { |
|
|
|
|
r := idx.c.call("sqlite3_vtab_distinct", uint64(idx.handle)) |
|
|
|
|
return int(r) |
|
|
|
|
i := int32(idx.c.call("sqlite3_vtab_distinct", stk_t(idx.handle))) |
|
|
|
|
return int(i) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// In identifies and handles IN constraints.
|
|
|
|
|
//
|
|
|
|
|
// 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)) |
|
|
|
|
return r != 0 |
|
|
|
|
b := int32(idx.c.call("sqlite3_vtab_in", stk_t(idx.handle), |
|
|
|
|
stk_t(column), stk_t(handle))) |
|
|
|
|
return b != 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (idx *IndexInfo) load() { |
|
|
|
|
@ -351,34 +351,35 @@ func (idx *IndexInfo) load() {
|
|
|
|
|
mod := idx.c.mod |
|
|
|
|
ptr := idx.handle |
|
|
|
|
|
|
|
|
|
idx.Constraint = make([]IndexConstraint, util.ReadUint32(mod, ptr+0)) |
|
|
|
|
idx.ConstraintUsage = make([]IndexConstraintUsage, util.ReadUint32(mod, ptr+0)) |
|
|
|
|
idx.OrderBy = make([]IndexOrderBy, util.ReadUint32(mod, ptr+8)) |
|
|
|
|
nConstraint := util.Read32[int32](mod, ptr+0) |
|
|
|
|
idx.Constraint = make([]IndexConstraint, nConstraint) |
|
|
|
|
idx.ConstraintUsage = make([]IndexConstraintUsage, nConstraint) |
|
|
|
|
idx.OrderBy = make([]IndexOrderBy, util.Read32[int32](mod, ptr+8)) |
|
|
|
|
|
|
|
|
|
constraintPtr := util.ReadUint32(mod, ptr+4) |
|
|
|
|
constraintPtr := util.Read32[ptr_t](mod, ptr+4) |
|
|
|
|
constraint := idx.Constraint |
|
|
|
|
for i := range idx.Constraint { |
|
|
|
|
constraint[i] = IndexConstraint{ |
|
|
|
|
Column: int(int32(util.ReadUint32(mod, constraintPtr+0))), |
|
|
|
|
Op: IndexConstraintOp(util.ReadUint8(mod, constraintPtr+4)), |
|
|
|
|
Usable: util.ReadUint8(mod, constraintPtr+5) != 0, |
|
|
|
|
Column: int(util.Read32[int32](mod, constraintPtr+0)), |
|
|
|
|
Op: util.Read[IndexConstraintOp](mod, constraintPtr+4), |
|
|
|
|
Usable: util.Read[byte](mod, constraintPtr+5) != 0, |
|
|
|
|
} |
|
|
|
|
constraintPtr += 12 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
orderByPtr := util.ReadUint32(mod, ptr+12) |
|
|
|
|
orderByPtr := util.Read32[ptr_t](mod, ptr+12) |
|
|
|
|
orderBy := idx.OrderBy |
|
|
|
|
for i := range orderBy { |
|
|
|
|
orderBy[i] = IndexOrderBy{ |
|
|
|
|
Column: int(int32(util.ReadUint32(mod, orderByPtr+0))), |
|
|
|
|
Desc: util.ReadUint8(mod, orderByPtr+4) != 0, |
|
|
|
|
Column: int(util.Read32[int32](mod, orderByPtr+0)), |
|
|
|
|
Desc: util.Read[byte](mod, orderByPtr+4) != 0, |
|
|
|
|
} |
|
|
|
|
orderByPtr += 8 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
idx.EstimatedCost = util.ReadFloat64(mod, ptr+40) |
|
|
|
|
idx.EstimatedRows = int64(util.ReadUint64(mod, ptr+48)) |
|
|
|
|
idx.ColumnsUsed = int64(util.ReadUint64(mod, ptr+64)) |
|
|
|
|
idx.EstimatedRows = util.Read64[int64](mod, ptr+48) |
|
|
|
|
idx.ColumnsUsed = util.Read64[uint64](mod, ptr+64) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (idx *IndexInfo) save() { |
|
|
|
|
@ -386,26 +387,26 @@ func (idx *IndexInfo) save() {
|
|
|
|
|
mod := idx.c.mod |
|
|
|
|
ptr := idx.handle |
|
|
|
|
|
|
|
|
|
usagePtr := util.ReadUint32(mod, ptr+16) |
|
|
|
|
usagePtr := util.Read32[ptr_t](mod, ptr+16) |
|
|
|
|
for _, usage := range idx.ConstraintUsage { |
|
|
|
|
util.WriteUint32(mod, usagePtr+0, uint32(usage.ArgvIndex)) |
|
|
|
|
util.Write32(mod, usagePtr+0, int32(usage.ArgvIndex)) |
|
|
|
|
if usage.Omit { |
|
|
|
|
util.WriteUint8(mod, usagePtr+4, 1) |
|
|
|
|
util.Write(mod, usagePtr+4, int8(1)) |
|
|
|
|
} |
|
|
|
|
usagePtr += 8 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
util.WriteUint32(mod, ptr+20, uint32(idx.IdxNum)) |
|
|
|
|
util.Write32(mod, ptr+20, int32(idx.IdxNum)) |
|
|
|
|
if idx.IdxStr != "" { |
|
|
|
|
util.WriteUint32(mod, ptr+24, idx.c.newString(idx.IdxStr)) |
|
|
|
|
util.WriteUint32(mod, ptr+28, 1) // needToFreeIdxStr
|
|
|
|
|
util.Write32(mod, ptr+24, idx.c.newString(idx.IdxStr)) |
|
|
|
|
util.Write32(mod, ptr+28, int32(1)) // needToFreeIdxStr
|
|
|
|
|
} |
|
|
|
|
if idx.OrderByConsumed { |
|
|
|
|
util.WriteUint32(mod, ptr+32, 1) |
|
|
|
|
util.Write32(mod, ptr+32, int32(1)) |
|
|
|
|
} |
|
|
|
|
util.WriteFloat64(mod, ptr+40, idx.EstimatedCost) |
|
|
|
|
util.WriteUint64(mod, ptr+48, uint64(idx.EstimatedRows)) |
|
|
|
|
util.WriteUint32(mod, ptr+56, uint32(idx.IdxFlags)) |
|
|
|
|
util.Write64(mod, ptr+48, idx.EstimatedRows) |
|
|
|
|
util.Write32(mod, ptr+56, idx.IdxFlags) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// IndexConstraintOp is a virtual table constraint operator code.
|
|
|
|
|
@ -442,42 +443,39 @@ const (
|
|
|
|
|
INDEX_SCAN_UNIQUE IndexScanFlag = 1 |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func vtabModuleCallback(i vtabConstructor) func(_ context.Context, _ api.Module, _, _, _, _, _ uint32) uint32 { |
|
|
|
|
return func(ctx context.Context, mod api.Module, pMod, nArg, pArg, ppVTab, pzErr uint32) uint32 { |
|
|
|
|
func vtabModuleCallback(i vtabConstructor) func(_ context.Context, _ api.Module, _ ptr_t, _ int32, _, _, _ ptr_t) res_t { |
|
|
|
|
return func(ctx context.Context, mod api.Module, pMod ptr_t, nArg int32, pArg, ppVTab, pzErr ptr_t) res_t { |
|
|
|
|
arg := make([]reflect.Value, 1+nArg) |
|
|
|
|
arg[0] = reflect.ValueOf(ctx.Value(connKey{})) |
|
|
|
|
|
|
|
|
|
for i := uint32(0); i < nArg; i++ { |
|
|
|
|
ptr := util.ReadUint32(mod, pArg+i*ptrlen) |
|
|
|
|
for i := range nArg { |
|
|
|
|
ptr := util.Read32[ptr_t](mod, pArg+ptr_t(i)*ptrlen) |
|
|
|
|
arg[i+1] = reflect.ValueOf(util.ReadString(mod, ptr, _MAX_SQL_LENGTH)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
module := vtabGetHandle(ctx, mod, pMod) |
|
|
|
|
res := reflect.ValueOf(module).Index(int(i)).Call(arg) |
|
|
|
|
err, _ := res[1].Interface().(error) |
|
|
|
|
val := reflect.ValueOf(module).Index(int(i)).Call(arg) |
|
|
|
|
err, _ := val[1].Interface().(error) |
|
|
|
|
if err == nil { |
|
|
|
|
vtabPutHandle(ctx, mod, ppVTab, res[0].Interface()) |
|
|
|
|
vtabPutHandle(ctx, mod, ppVTab, val[0].Interface()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return vtabError(ctx, mod, pzErr, _PTR_ERROR, err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabDisconnectCallback(ctx context.Context, mod api.Module, pVTab uint32) uint32 { |
|
|
|
|
func vtabDisconnectCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { |
|
|
|
|
err := vtabDelHandle(ctx, mod, pVTab) |
|
|
|
|
return vtabError(ctx, mod, 0, _PTR_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabDestroyCallback(ctx context.Context, mod api.Module, pVTab uint32) uint32 { |
|
|
|
|
func vtabDestroyCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabDestroyer) |
|
|
|
|
err := vtab.Destroy() |
|
|
|
|
if cerr := vtabDelHandle(ctx, mod, pVTab); err == nil { |
|
|
|
|
err = cerr |
|
|
|
|
} |
|
|
|
|
err := errors.Join(vtab.Destroy(), vtabDelHandle(ctx, mod, pVTab)) |
|
|
|
|
return vtabError(ctx, mod, 0, _PTR_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabBestIndexCallback(ctx context.Context, mod api.Module, pVTab, pIdxInfo uint32) uint32 { |
|
|
|
|
func vtabBestIndexCallback(ctx context.Context, mod api.Module, pVTab, pIdxInfo ptr_t) res_t { |
|
|
|
|
var info IndexInfo |
|
|
|
|
info.handle = pIdxInfo |
|
|
|
|
info.c = ctx.Value(connKey{}).(*Conn) |
|
|
|
|
@ -490,7 +488,7 @@ func vtabBestIndexCallback(ctx context.Context, mod api.Module, pVTab, pIdxInfo
|
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabUpdateCallback(ctx context.Context, mod api.Module, pVTab, nArg, pArg, pRowID uint32) uint32 { |
|
|
|
|
func vtabUpdateCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, pArg, pRowID ptr_t) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabUpdater) |
|
|
|
|
|
|
|
|
|
db := ctx.Value(connKey{}).(*Conn) |
|
|
|
|
@ -498,33 +496,33 @@ func vtabUpdateCallback(ctx context.Context, mod api.Module, pVTab, nArg, pArg,
|
|
|
|
|
callbackArgs(db, args, pArg) |
|
|
|
|
rowID, err := vtab.Update(args...) |
|
|
|
|
if err == nil { |
|
|
|
|
util.WriteUint64(mod, pRowID, uint64(rowID)) |
|
|
|
|
util.Write64(mod, pRowID, rowID) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabRenameCallback(ctx context.Context, mod api.Module, pVTab, zNew uint32) uint32 { |
|
|
|
|
func vtabRenameCallback(ctx context.Context, mod api.Module, pVTab, zNew ptr_t) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabRenamer) |
|
|
|
|
err := vtab.Rename(util.ReadString(mod, zNew, _MAX_NAME)) |
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabFindFuncCallback(ctx context.Context, mod api.Module, pVTab uint32, nArg int32, zName, pxFunc uint32) uint32 { |
|
|
|
|
func vtabFindFuncCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, zName, pxFunc ptr_t) int32 { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabOverloader) |
|
|
|
|
f, op := vtab.FindFunction(int(nArg), util.ReadString(mod, zName, _MAX_NAME)) |
|
|
|
|
if op != 0 { |
|
|
|
|
var wrapper uint32 |
|
|
|
|
var wrapper ptr_t |
|
|
|
|
wrapper = util.AddHandle(ctx, func(c Context, arg ...Value) { |
|
|
|
|
defer util.DelHandle(ctx, wrapper) |
|
|
|
|
f(c, arg...) |
|
|
|
|
}) |
|
|
|
|
util.WriteUint32(mod, pxFunc, wrapper) |
|
|
|
|
util.Write32(mod, pxFunc, wrapper) |
|
|
|
|
} |
|
|
|
|
return uint32(op) |
|
|
|
|
return int32(op) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabIntegrityCallback(ctx context.Context, mod api.Module, pVTab, zSchema, zTabName, mFlags, pzErr uint32) uint32 { |
|
|
|
|
func vtabIntegrityCallback(ctx context.Context, mod api.Module, pVTab, zSchema, zTabName ptr_t, mFlags uint32, pzErr ptr_t) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabChecker) |
|
|
|
|
schema := util.ReadString(mod, zSchema, _MAX_NAME) |
|
|
|
|
table := util.ReadString(mod, zTabName, _MAX_NAME) |
|
|
|
|
@ -536,49 +534,49 @@ func vtabIntegrityCallback(ctx context.Context, mod api.Module, pVTab, zSchema,
|
|
|
|
|
return code |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabBeginCallback(ctx context.Context, mod api.Module, pVTab uint32) uint32 { |
|
|
|
|
func vtabBeginCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn) |
|
|
|
|
err := vtab.Begin() |
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabSyncCallback(ctx context.Context, mod api.Module, pVTab uint32) uint32 { |
|
|
|
|
func vtabSyncCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn) |
|
|
|
|
err := vtab.Sync() |
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabCommitCallback(ctx context.Context, mod api.Module, pVTab uint32) uint32 { |
|
|
|
|
func vtabCommitCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn) |
|
|
|
|
err := vtab.Commit() |
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabRollbackCallback(ctx context.Context, mod api.Module, pVTab uint32) uint32 { |
|
|
|
|
func vtabRollbackCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn) |
|
|
|
|
err := vtab.Rollback() |
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabSavepointCallback(ctx context.Context, mod api.Module, pVTab uint32, id int32) uint32 { |
|
|
|
|
func vtabSavepointCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer) |
|
|
|
|
err := vtab.Savepoint(int(id)) |
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabReleaseCallback(ctx context.Context, mod api.Module, pVTab uint32, id int32) uint32 { |
|
|
|
|
func vtabReleaseCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer) |
|
|
|
|
err := vtab.Release(int(id)) |
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabRollbackToCallback(ctx context.Context, mod api.Module, pVTab uint32, id int32) uint32 { |
|
|
|
|
func vtabRollbackToCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer) |
|
|
|
|
err := vtab.RollbackTo(int(id)) |
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func cursorOpenCallback(ctx context.Context, mod api.Module, pVTab, ppCur uint32) uint32 { |
|
|
|
|
func cursorOpenCallback(ctx context.Context, mod api.Module, pVTab, ppCur ptr_t) res_t { |
|
|
|
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTab) |
|
|
|
|
|
|
|
|
|
cursor, err := vtab.Open() |
|
|
|
|
@ -589,12 +587,12 @@ func cursorOpenCallback(ctx context.Context, mod api.Module, pVTab, ppCur uint32
|
|
|
|
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func cursorCloseCallback(ctx context.Context, mod api.Module, pCur uint32) uint32 { |
|
|
|
|
func cursorCloseCallback(ctx context.Context, mod api.Module, pCur ptr_t) res_t { |
|
|
|
|
err := vtabDelHandle(ctx, mod, pCur) |
|
|
|
|
return vtabError(ctx, mod, 0, _VTAB_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func cursorFilterCallback(ctx context.Context, mod api.Module, pCur uint32, idxNum int32, idxStr, nArg, pArg uint32) uint32 { |
|
|
|
|
func cursorFilterCallback(ctx context.Context, mod api.Module, pCur ptr_t, idxNum int32, idxStr ptr_t, nArg int32, pArg ptr_t) res_t { |
|
|
|
|
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor) |
|
|
|
|
db := ctx.Value(connKey{}).(*Conn) |
|
|
|
|
args := make([]Value, nArg) |
|
|
|
|
@ -607,7 +605,7 @@ func cursorFilterCallback(ctx context.Context, mod api.Module, pCur uint32, idxN
|
|
|
|
|
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func cursorEOFCallback(ctx context.Context, mod api.Module, pCur uint32) uint32 { |
|
|
|
|
func cursorEOFCallback(ctx context.Context, mod api.Module, pCur ptr_t) int32 { |
|
|
|
|
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor) |
|
|
|
|
if cursor.EOF() { |
|
|
|
|
return 1 |
|
|
|
|
@ -615,25 +613,25 @@ func cursorEOFCallback(ctx context.Context, mod api.Module, pCur uint32) uint32
|
|
|
|
|
return 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func cursorNextCallback(ctx context.Context, mod api.Module, pCur uint32) uint32 { |
|
|
|
|
func cursorNextCallback(ctx context.Context, mod api.Module, pCur ptr_t) res_t { |
|
|
|
|
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor) |
|
|
|
|
err := cursor.Next() |
|
|
|
|
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func cursorColumnCallback(ctx context.Context, mod api.Module, pCur, pCtx uint32, n int32) uint32 { |
|
|
|
|
func cursorColumnCallback(ctx context.Context, mod api.Module, pCur, pCtx ptr_t, n int32) res_t { |
|
|
|
|
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor) |
|
|
|
|
db := ctx.Value(connKey{}).(*Conn) |
|
|
|
|
err := cursor.Column(Context{db, pCtx}, int(n)) |
|
|
|
|
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func cursorRowIDCallback(ctx context.Context, mod api.Module, pCur, pRowID uint32) uint32 { |
|
|
|
|
func cursorRowIDCallback(ctx context.Context, mod api.Module, pCur, pRowID ptr_t) res_t { |
|
|
|
|
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor) |
|
|
|
|
|
|
|
|
|
rowID, err := cursor.RowID() |
|
|
|
|
if err == nil { |
|
|
|
|
util.WriteUint64(mod, pRowID, uint64(rowID)) |
|
|
|
|
util.Write64(mod, pRowID, rowID) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err) |
|
|
|
|
@ -645,7 +643,7 @@ const (
|
|
|
|
|
_CURSOR_ERROR |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func vtabError(ctx context.Context, mod api.Module, ptr, kind uint32, err error) uint32 { |
|
|
|
|
func vtabError(ctx context.Context, mod api.Module, ptr ptr_t, kind uint32, err error) res_t { |
|
|
|
|
const zErrMsgOffset = 8 |
|
|
|
|
msg, code := errorCode(err, ERROR) |
|
|
|
|
if msg != "" && ptr != 0 { |
|
|
|
|
@ -653,32 +651,32 @@ func vtabError(ctx context.Context, mod api.Module, ptr, kind uint32, err error)
|
|
|
|
|
case _VTAB_ERROR: |
|
|
|
|
ptr = ptr + zErrMsgOffset // zErrMsg
|
|
|
|
|
case _CURSOR_ERROR: |
|
|
|
|
ptr = util.ReadUint32(mod, ptr) + zErrMsgOffset // pVTab->zErrMsg
|
|
|
|
|
ptr = util.Read32[ptr_t](mod, ptr) + zErrMsgOffset // pVTab->zErrMsg
|
|
|
|
|
} |
|
|
|
|
db := ctx.Value(connKey{}).(*Conn) |
|
|
|
|
if ptr := util.ReadUint32(mod, ptr); ptr != 0 { |
|
|
|
|
if ptr := util.Read32[ptr_t](mod, ptr); ptr != 0 { |
|
|
|
|
db.free(ptr) |
|
|
|
|
} |
|
|
|
|
util.WriteUint32(mod, ptr, db.newString(msg)) |
|
|
|
|
util.Write32(mod, ptr, db.newString(msg)) |
|
|
|
|
} |
|
|
|
|
return code |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabGetHandle(ctx context.Context, mod api.Module, ptr uint32) any { |
|
|
|
|
func vtabGetHandle(ctx context.Context, mod api.Module, ptr ptr_t) any { |
|
|
|
|
const handleOffset = 4 |
|
|
|
|
handle := util.ReadUint32(mod, ptr-handleOffset) |
|
|
|
|
handle := util.Read32[ptr_t](mod, ptr-handleOffset) |
|
|
|
|
return util.GetHandle(ctx, handle) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabDelHandle(ctx context.Context, mod api.Module, ptr uint32) error { |
|
|
|
|
func vtabDelHandle(ctx context.Context, mod api.Module, ptr ptr_t) error { |
|
|
|
|
const handleOffset = 4 |
|
|
|
|
handle := util.ReadUint32(mod, ptr-handleOffset) |
|
|
|
|
handle := util.Read32[ptr_t](mod, ptr-handleOffset) |
|
|
|
|
return util.DelHandle(ctx, handle) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func vtabPutHandle(ctx context.Context, mod api.Module, pptr uint32, val any) { |
|
|
|
|
func vtabPutHandle(ctx context.Context, mod api.Module, pptr ptr_t, val any) { |
|
|
|
|
const handleOffset = 4 |
|
|
|
|
handle := util.AddHandle(ctx, val) |
|
|
|
|
ptr := util.ReadUint32(mod, pptr) |
|
|
|
|
util.WriteUint32(mod, ptr-handleOffset, handle) |
|
|
|
|
ptr := util.Read32[ptr_t](mod, pptr) |
|
|
|
|
util.Write32(mod, ptr-handleOffset, handle) |
|
|
|
|
} |
|
|
|
|
|