From d862f47d95d522fb7a63aacf1259714aff986d46 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Thu, 30 Nov 2023 17:52:35 +0000 Subject: [PATCH] Deoptimize. --- backup.go | 12 +-- blob.go | 18 ++-- conn.go | 24 ++--- context.go | 40 ++++---- error_test.go | 4 +- func.go | 14 +-- internal/util/error.go | 5 +- sqlite.go | 208 +++-------------------------------------- sqlite_test.go | 2 +- stmt.go | 63 ++++++------- value.go | 14 +-- vtab.go | 8 +- 12 files changed, 115 insertions(+), 297 deletions(-) diff --git a/backup.go b/backup.go index e38cccc..5fc5cf1 100644 --- a/backup.go +++ b/backup.go @@ -71,12 +71,12 @@ func (c *Conn) backupInit(dst uint32, dstName string, src uint32, srcName string other = src } - r := c.call(c.api.backupInit, + r := c.call("sqlite3_backup_init", uint64(dst), uint64(dstPtr), uint64(src), uint64(srcPtr)) if r == 0 { defer c.closeDB(other) - r = c.call(c.api.errcode, uint64(dst)) + r = c.call("sqlite3_errcode", uint64(dst)) return nil, c.sqlite.error(r, dst) } @@ -97,7 +97,7 @@ func (b *Backup) Close() error { return nil } - r := b.c.call(b.c.api.backupFinish, uint64(b.handle)) + r := b.c.call("sqlite3_backup_finish", uint64(b.handle)) b.c.closeDB(b.otherc) b.handle = 0 return b.c.error(r) @@ -108,7 +108,7 @@ func (b *Backup) Close() error { // // https://sqlite.org/c3ref/backup_finish.html#sqlite3backupstep func (b *Backup) Step(nPage int) (done bool, err error) { - r := b.c.call(b.c.api.backupStep, uint64(b.handle), uint64(nPage)) + r := b.c.call("sqlite3_backup_step", uint64(b.handle), uint64(nPage)) if r == _DONE { return true, nil } @@ -120,7 +120,7 @@ func (b *Backup) Step(nPage int) (done bool, err error) { // // https://sqlite.org/c3ref/backup_finish.html#sqlite3backupremaining func (b *Backup) Remaining() int { - r := b.c.call(b.c.api.backupRemaining, uint64(b.handle)) + r := b.c.call("sqlite3_backup_remaining", uint64(b.handle)) return int(r) } @@ -129,6 +129,6 @@ func (b *Backup) Remaining() int { // // https://sqlite.org/c3ref/backup_finish.html#sqlite3backuppagecount func (b *Backup) PageCount() int { - r := b.c.call(b.c.api.backupPageCount, uint64(b.handle)) + r := b.c.call("sqlite3_backup_pagecount", uint64(b.handle)) return int(r) } diff --git a/blob.go b/blob.go index e977cad..bb10c5f 100644 --- a/blob.go +++ b/blob.go @@ -41,7 +41,7 @@ func (c *Conn) OpenBlob(db, table, column string, row int64, write bool) (*Blob, flags = 1 } - r := c.call(c.api.blobOpen, uint64(c.handle), + r := c.call("sqlite3_blob_open", uint64(c.handle), uint64(dbPtr), uint64(tablePtr), uint64(columnPtr), uint64(row), flags, uint64(blobPtr)) @@ -51,7 +51,7 @@ func (c *Conn) OpenBlob(db, table, column string, row int64, write bool) (*Blob, blob := Blob{c: c} blob.handle = util.ReadUint32(c.mod, blobPtr) - blob.bytes = int64(c.call(c.api.blobBytes, uint64(blob.handle))) + blob.bytes = int64(c.call("sqlite3_blob_bytes", uint64(blob.handle))) return &blob, nil } @@ -65,7 +65,7 @@ func (b *Blob) Close() error { return nil } - r := b.c.call(b.c.api.blobClose, uint64(b.handle)) + r := b.c.call("sqlite3_blob_close", uint64(b.handle)) b.handle = 0 return b.c.error(r) @@ -95,7 +95,7 @@ func (b *Blob) Read(p []byte) (n int, err error) { defer b.c.arena.mark()() ptr := b.c.arena.new(uint64(want)) - r := b.c.call(b.c.api.blobRead, uint64(b.handle), + r := b.c.call("sqlite3_blob_read", uint64(b.handle), uint64(ptr), uint64(want), uint64(b.offset)) err = b.c.error(r) if err != nil { @@ -128,7 +128,7 @@ func (b *Blob) WriteTo(w io.Writer) (n int64, err error) { ptr := b.c.arena.new(uint64(want)) for want > 0 { - r := b.c.call(b.c.api.blobRead, uint64(b.handle), + r := b.c.call("sqlite3_blob_read", uint64(b.handle), uint64(ptr), uint64(want), uint64(b.offset)) err = b.c.error(r) if err != nil { @@ -161,7 +161,7 @@ func (b *Blob) Write(p []byte) (n int, err error) { defer b.c.arena.mark()() ptr := b.c.arena.bytes(p) - r := b.c.call(b.c.api.blobWrite, uint64(b.handle), + r := b.c.call("sqlite3_blob_write", uint64(b.handle), uint64(ptr), uint64(len(p)), uint64(b.offset)) err = b.c.error(r) if err != nil { @@ -194,7 +194,7 @@ func (b *Blob) ReadFrom(r io.Reader) (n int64, err error) { mem := util.View(b.c.mod, ptr, uint64(want)) m, err := r.Read(mem[:want]) if m > 0 { - r := b.c.call(b.c.api.blobWrite, uint64(b.handle), + r := b.c.call("sqlite3_blob_write", uint64(b.handle), uint64(ptr), uint64(m), uint64(b.offset)) err := b.c.error(r) if err != nil { @@ -243,8 +243,8 @@ func (b *Blob) Seek(offset int64, whence int) (int64, error) { // // https://sqlite.org/c3ref/blob_reopen.html func (b *Blob) Reopen(row int64) error { - err := b.c.error(b.c.call(b.c.api.blobReopen, uint64(b.handle), uint64(row))) - b.bytes = int64(b.c.call(b.c.api.blobBytes, uint64(b.handle))) + err := b.c.error(b.c.call("sqlite3_blob_reopen", uint64(b.handle), uint64(row))) + b.bytes = int64(b.c.call("sqlite3_blob_bytes", uint64(b.handle))) b.offset = 0 return err } diff --git a/conn.go b/conn.go index 2f50fa6..d637033 100644 --- a/conn.go +++ b/conn.go @@ -77,7 +77,7 @@ func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) { namePtr := c.arena.string(filename) flags |= OPEN_EXRESCODE - r := c.call(c.api.open, uint64(namePtr), uint64(connPtr), uint64(flags), 0) + r := c.call("sqlite3_open_v2", uint64(namePtr), uint64(connPtr), uint64(flags), 0) handle := util.ReadUint32(c.mod, connPtr) if err := c.sqlite.error(r, handle); err != nil { @@ -97,7 +97,7 @@ func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) { } pragmaPtr := c.arena.string(pragmas.String()) - r := c.call(c.api.exec, uint64(handle), uint64(pragmaPtr), 0, 0, 0) + r := c.call("sqlite3_exec", uint64(handle), uint64(pragmaPtr), 0, 0, 0) if err := c.sqlite.error(r, handle, pragmas.String()); err != nil { if errors.Is(err, ERROR) { err = fmt.Errorf("sqlite3: invalid _pragma: %w", err) @@ -111,7 +111,7 @@ func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) { } func (c *Conn) closeDB(handle uint32) { - r := c.call(c.api.closeZombie, uint64(handle)) + r := c.call("sqlite3_close_v2", uint64(handle)) if err := c.sqlite.error(r, handle); err != nil { panic(err) } @@ -134,7 +134,7 @@ func (c *Conn) Close() error { c.pending.Close() c.pending = nil - r := c.call(c.api.close, uint64(c.handle)) + r := c.call("sqlite3_close", uint64(c.handle)) if err := c.error(r); err != nil { return err } @@ -153,7 +153,7 @@ func (c *Conn) Exec(sql string) error { defer c.arena.mark()() sqlPtr := c.arena.string(sql) - r := c.call(c.api.exec, uint64(c.handle), uint64(sqlPtr), 0, 0, 0) + r := c.call("sqlite3_exec", uint64(c.handle), uint64(sqlPtr), 0, 0, 0) return c.error(r, sql) } @@ -178,7 +178,7 @@ func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail str tailPtr := c.arena.new(ptrlen) sqlPtr := c.arena.string(sql) - r := c.call(c.api.prepare, uint64(c.handle), + r := c.call("sqlite3_prepare_v3", uint64(c.handle), uint64(sqlPtr), uint64(len(sql)+1), uint64(flags), uint64(stmtPtr), uint64(tailPtr)) @@ -201,7 +201,7 @@ func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail str // // https://sqlite.org/c3ref/get_autocommit.html func (c *Conn) GetAutocommit() bool { - r := c.call(c.api.autocommit, uint64(c.handle)) + r := c.call("sqlite3_get_autocommit", uint64(c.handle)) return r != 0 } @@ -210,7 +210,7 @@ func (c *Conn) GetAutocommit() bool { // // https://sqlite.org/c3ref/last_insert_rowid.html func (c *Conn) LastInsertRowID() int64 { - r := c.call(c.api.lastRowid, uint64(c.handle)) + r := c.call("sqlite3_last_insert_rowid", uint64(c.handle)) return int64(r) } @@ -220,7 +220,7 @@ func (c *Conn) LastInsertRowID() int64 { // // https://sqlite.org/c3ref/changes.html func (c *Conn) Changes() int64 { - r := c.call(c.api.changes, uint64(c.handle)) + r := c.call("sqlite3_changes64", uint64(c.handle)) return int64(r) } @@ -256,12 +256,12 @@ func (c *Conn) SetInterrupt(ctx context.Context) (old context.Context) { c.interrupt = ctx // Remove the handler if the context can't be canceled. if ctx == nil || ctx.Done() == nil { - c.call(c.api.progressHandler, uint64(c.handle), 0) + c.call("sqlite3_progress_handler_go", uint64(c.handle), 0) return old } c.pending.Step() - c.call(c.api.progressHandler, uint64(c.handle), 100) + c.call("sqlite3_progress_handler_go", uint64(c.handle), 100) return old } @@ -276,7 +276,7 @@ func progressCallback(ctx context.Context, mod api.Module, _ uint32) uint32 { func (c *Conn) checkInterrupt() { if c.interrupt != nil && c.interrupt.Err() != nil { - c.call(c.api.interrupt, uint64(c.handle)) + c.call("sqlite3_interrupt", uint64(c.handle)) } } diff --git a/context.go b/context.go index 3ee1d2b..6ea97ad 100644 --- a/context.go +++ b/context.go @@ -32,14 +32,14 @@ func (ctx Context) Conn() *Conn { // https://sqlite.org/c3ref/get_auxdata.html func (ctx Context) SetAuxData(n int, data any) { ptr := util.AddHandle(ctx.c.ctx, data) - ctx.c.call(ctx.c.api.setAuxData, uint64(ctx.handle), uint64(n), uint64(ptr)) + ctx.c.call("sqlite3_set_auxdata_go", uint64(ctx.handle), uint64(n), uint64(ptr)) } // GetAuxData returns metadata for argument n of the function. // // https://sqlite.org/c3ref/get_auxdata.html func (ctx Context) GetAuxData(n int) any { - ptr := uint32(ctx.c.call(ctx.c.api.getAuxData, uint64(ctx.handle), uint64(n))) + ptr := uint32(ctx.c.call("sqlite3_get_auxdata", uint64(ctx.handle), uint64(n))) return util.GetHandle(ctx.c.ctx, ptr) } @@ -67,7 +67,7 @@ func (ctx Context) ResultInt(value int) { // // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultInt64(value int64) { - ctx.c.call(ctx.c.api.resultInteger, + ctx.c.call("sqlite3_result_int64", uint64(ctx.handle), uint64(value)) } @@ -75,7 +75,7 @@ func (ctx Context) ResultInt64(value int64) { // // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultFloat(value float64) { - ctx.c.call(ctx.c.api.resultFloat, + ctx.c.call("sqlite3_result_double", uint64(ctx.handle), math.Float64bits(value)) } @@ -84,9 +84,9 @@ func (ctx Context) ResultFloat(value float64) { // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultText(value string) { ptr := ctx.c.newString(value) - ctx.c.call(ctx.c.api.resultText, + ctx.c.call("sqlite3_result_text64", uint64(ctx.handle), uint64(ptr), uint64(len(value)), - uint64(ctx.c.api.destructor), _UTF8) + uint64(ctx.c.freer), _UTF8) } // ResultRawText sets the text result of the function to a []byte. @@ -94,9 +94,9 @@ func (ctx Context) ResultText(value string) { // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultRawText(value []byte) { ptr := ctx.c.newBytes(value) - ctx.c.call(ctx.c.api.resultText, + ctx.c.call("sqlite3_result_text64", uint64(ctx.handle), uint64(ptr), uint64(len(value)), - uint64(ctx.c.api.destructor), _UTF8) + uint64(ctx.c.freer), _UTF8) } // ResultBlob sets the result of the function to a []byte. @@ -105,16 +105,16 @@ func (ctx Context) ResultRawText(value []byte) { // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultBlob(value []byte) { ptr := ctx.c.newBytes(value) - ctx.c.call(ctx.c.api.resultBlob, + ctx.c.call("sqlite3_result_blob64", uint64(ctx.handle), uint64(ptr), uint64(len(value)), - uint64(ctx.c.api.destructor)) + uint64(ctx.c.freer)) } // ResultZeroBlob sets the result of the function to a zero-filled, length n BLOB. // // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultZeroBlob(n int64) { - ctx.c.call(ctx.c.api.resultZeroBlob, + ctx.c.call("sqlite3_result_zeroblob64", uint64(ctx.handle), uint64(n)) } @@ -122,7 +122,7 @@ func (ctx Context) ResultZeroBlob(n int64) { // // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultNull() { - ctx.c.call(ctx.c.api.resultNull, + ctx.c.call("sqlite3_result_null", uint64(ctx.handle)) } @@ -153,9 +153,9 @@ func (ctx Context) resultRFC3339Nano(value time.Time) { buf := util.View(ctx.c.mod, ptr, maxlen) buf = value.AppendFormat(buf[:0], time.RFC3339Nano) - ctx.c.call(ctx.c.api.resultText, + ctx.c.call("sqlite3_result_text64", uint64(ctx.handle), uint64(ptr), uint64(len(buf)), - uint64(ctx.c.api.destructor), _UTF8) + uint64(ctx.c.freer), _UTF8) } // ResultPointer sets the result of the function to NULL, just like [Context.ResultNull], @@ -165,7 +165,7 @@ func (ctx Context) resultRFC3339Nano(value time.Time) { // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultPointer(ptr any) { valPtr := util.AddHandle(ctx.c.ctx, ptr) - ctx.c.call(ctx.c.api.resultPointer, uint64(valPtr)) + ctx.c.call("sqlite3_result_pointer_go", uint64(valPtr)) } // ResultJSON sets the result of the function to the JSON encoding of value. @@ -188,7 +188,7 @@ func (ctx Context) ResultValue(value Value) { ctx.ResultError(MISUSE) return } - ctx.c.call(ctx.c.api.resultValue, + ctx.c.call("sqlite3_result_value", uint64(ctx.handle), uint64(value.handle)) } @@ -197,12 +197,12 @@ func (ctx Context) ResultValue(value Value) { // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultError(err error) { if errors.Is(err, NOMEM) { - ctx.c.call(ctx.c.api.resultErrorMem, uint64(ctx.handle)) + ctx.c.call("sqlite3_result_error_nomem", uint64(ctx.handle)) return } if errors.Is(err, TOOBIG) { - ctx.c.call(ctx.c.api.resultErrorBig, uint64(ctx.handle)) + ctx.c.call("sqlite3_result_error_toobig", uint64(ctx.handle)) return } @@ -210,11 +210,11 @@ func (ctx Context) ResultError(err error) { if msg != "" { defer ctx.c.arena.mark()() ptr := ctx.c.arena.string(msg) - ctx.c.call(ctx.c.api.resultError, + ctx.c.call("sqlite3_result_error", uint64(ctx.handle), uint64(ptr), uint64(len(msg))) } if code != _OK { - ctx.c.call(ctx.c.api.resultErrorCode, + ctx.c.call("sqlite3_result_error_code", uint64(ctx.handle), uint64(code)) } } diff --git a/error_test.go b/error_test.go index f4df1e7..1404a41 100644 --- a/error_test.go +++ b/error_test.go @@ -135,7 +135,7 @@ func Test_ErrorCode_Error(t *testing.T) { // Test all error codes. for i := 0; i == int(ErrorCode(i)); i++ { want := "sqlite3: " - r := db.call(db.api.errstr, uint64(i)) + r := db.call("sqlite3_errstr", uint64(i)) want += util.ReadString(db.mod, uint32(r), _MAX_NAME) got := ErrorCode(i).Error() @@ -157,7 +157,7 @@ func Test_ExtendedErrorCode_Error(t *testing.T) { // Test all extended error codes. for i := 0; i == int(ExtendedErrorCode(i)); i++ { want := "sqlite3: " - r := db.call(db.api.errstr, uint64(i)) + r := db.call("sqlite3_errstr", uint64(i)) want += util.ReadString(db.mod, uint32(r), _MAX_NAME) got := ExtendedErrorCode(i).Error() diff --git a/func.go b/func.go index 7322beb..2a8b5e4 100644 --- a/func.go +++ b/func.go @@ -14,7 +14,7 @@ import ( // This can be used to load schemas that contain // one or more unknown collating sequences. func (c *Conn) AnyCollationNeeded() { - c.call(c.api.anyCollation, uint64(c.handle), 0, 0) + c.call("sqlite3_anycollseq_init", uint64(c.handle), 0, 0) } // CreateCollation defines a new collating sequence. @@ -24,7 +24,7 @@ func (c *Conn) CreateCollation(name string, fn func(a, b []byte) int) error { defer c.arena.mark()() namePtr := c.arena.string(name) funcPtr := util.AddHandle(c.ctx, fn) - r := c.call(c.api.createCollation, + r := c.call("sqlite3_create_collation_go", uint64(c.handle), uint64(namePtr), uint64(funcPtr)) return c.error(r) } @@ -36,7 +36,7 @@ func (c *Conn) CreateFunction(name string, nArg int, flag FunctionFlag, fn func( defer c.arena.mark()() namePtr := c.arena.string(name) funcPtr := util.AddHandle(c.ctx, fn) - r := c.call(c.api.createFunction, + r := c.call("sqlite3_create_function_go", uint64(c.handle), uint64(namePtr), uint64(nArg), uint64(flag), uint64(funcPtr)) return c.error(r) @@ -49,11 +49,11 @@ func (c *Conn) CreateFunction(name string, nArg int, flag FunctionFlag, fn func( // https://sqlite.org/c3ref/create_function.html func (c *Conn) CreateWindowFunction(name string, nArg int, flag FunctionFlag, fn func() AggregateFunction) error { defer c.arena.mark()() - call := c.api.createAggregate + call := "sqlite3_create_aggregate_function_go" namePtr := c.arena.string(name) funcPtr := util.AddHandle(c.ctx, fn) if _, ok := fn().(WindowFunction); ok { - call = c.api.createWindow + call = "sqlite3_create_window_function_go" } r := c.call(call, uint64(c.handle), uint64(namePtr), uint64(nArg), @@ -128,7 +128,7 @@ func inverseCallback(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint3 } func userDataHandle(db *Conn, pCtx uint32) any { - pApp := uint32(db.call(db.api.userData, uint64(pCtx))) + pApp := uint32(db.call("sqlite3_user_data", uint64(pCtx))) return util.GetHandle(db.ctx, pApp) } @@ -139,7 +139,7 @@ func aggregateCtxHandle(db *Conn, pCtx uint32, close *uint32) AggregateFunction if close == nil { size = ptrlen } - ptr := uint32(db.call(db.api.aggregateCtx, uint64(pCtx), size)) + ptr := uint32(db.call("sqlite3_aggregate_context", uint64(pCtx), size)) // If we already have an aggregate, return it. if ptr != 0 { diff --git a/internal/util/error.go b/internal/util/error.go index c2b4e21..20f80ac 100644 --- a/internal/util/error.go +++ b/internal/util/error.go @@ -15,9 +15,8 @@ const ( OOMErr = ErrorString("sqlite3: out of memory") RangeErr = ErrorString("sqlite3: index out of range") NoNulErr = ErrorString("sqlite3: missing NUL terminator") - NoGlobalErr = ErrorString("sqlite3: could not find global: ") - NoFuncErr = ErrorString("sqlite3: could not find function: ") - BinaryErr = ErrorString("sqlite3: no SQLite binary embed/set/loaded") + NoBinaryErr = ErrorString("sqlite3: no SQLite binary embed/set/loaded") + BadBinaryErr = ErrorString("sqlite3: invalid SQLite binary embed/set/loaded") TimeErr = ErrorString("sqlite3: invalid time value") WhenceErr = ErrorString("sqlite3: invalid whence") OffsetErr = ErrorString("sqlite3: invalid offset") diff --git a/sqlite.go b/sqlite.go index b51f701..3a6af73 100644 --- a/sqlite.go +++ b/sqlite.go @@ -57,7 +57,7 @@ func compileSQLite() { } } if bin == nil { - instance.err = util.BinaryErr + instance.err = util.NoBinaryErr return } @@ -67,7 +67,7 @@ func compileSQLite() { type sqlite struct { ctx context.Context mod api.Module - api sqliteAPI + freer uint32 stack [8]uint64 } @@ -86,110 +86,12 @@ func instantiateSQLite() (sqlt *sqlite, err error) { return nil, err } - getFun := func(name string) api.Function { - f := sqlt.mod.ExportedFunction(name) - if f == nil { - err = util.NoFuncErr + util.ErrorString(name) - return nil - } - return f + global := sqlt.mod.ExportedGlobal("malloc_destructor") + if global == nil { + return nil, util.BadBinaryErr } - getVal := func(name string) uint32 { - g := sqlt.mod.ExportedGlobal(name) - if g == nil { - err = util.NoGlobalErr + util.ErrorString(name) - return 0 - } - return util.ReadUint32(sqlt.mod, uint32(g.Get())) - } - - sqlt.api = sqliteAPI{ - free: getFun("free"), - malloc: getFun("malloc"), - destructor: getVal("malloc_destructor"), - errcode: getFun("sqlite3_errcode"), - errstr: getFun("sqlite3_errstr"), - errmsg: getFun("sqlite3_errmsg"), - erroff: getFun("sqlite3_error_offset"), - open: getFun("sqlite3_open_v2"), - close: getFun("sqlite3_close"), - closeZombie: getFun("sqlite3_close_v2"), - prepare: getFun("sqlite3_prepare_v3"), - finalize: getFun("sqlite3_finalize"), - reset: getFun("sqlite3_reset"), - step: getFun("sqlite3_step"), - exec: getFun("sqlite3_exec"), - interrupt: getFun("sqlite3_interrupt"), - progressHandler: getFun("sqlite3_progress_handler_go"), - clearBindings: getFun("sqlite3_clear_bindings"), - bindCount: getFun("sqlite3_bind_parameter_count"), - bindIndex: getFun("sqlite3_bind_parameter_index"), - bindName: getFun("sqlite3_bind_parameter_name"), - bindNull: getFun("sqlite3_bind_null"), - bindInteger: getFun("sqlite3_bind_int64"), - bindFloat: getFun("sqlite3_bind_double"), - bindText: getFun("sqlite3_bind_text64"), - bindBlob: getFun("sqlite3_bind_blob64"), - bindZeroBlob: getFun("sqlite3_bind_zeroblob64"), - bindPointer: getFun("sqlite3_bind_pointer_go"), - bindValue: getFun("sqlite3_bind_value"), - columnCount: getFun("sqlite3_column_count"), - columnName: getFun("sqlite3_column_name"), - columnType: getFun("sqlite3_column_type"), - columnInteger: getFun("sqlite3_column_int64"), - columnFloat: getFun("sqlite3_column_double"), - columnText: getFun("sqlite3_column_text"), - columnBlob: getFun("sqlite3_column_blob"), - columnBytes: getFun("sqlite3_column_bytes"), - columnValue: getFun("sqlite3_column_value"), - blobOpen: getFun("sqlite3_blob_open"), - blobClose: getFun("sqlite3_blob_close"), - blobReopen: getFun("sqlite3_blob_reopen"), - blobBytes: getFun("sqlite3_blob_bytes"), - blobRead: getFun("sqlite3_blob_read"), - blobWrite: getFun("sqlite3_blob_write"), - backupInit: getFun("sqlite3_backup_init"), - backupStep: getFun("sqlite3_backup_step"), - backupFinish: getFun("sqlite3_backup_finish"), - backupRemaining: getFun("sqlite3_backup_remaining"), - backupPageCount: getFun("sqlite3_backup_pagecount"), - changes: getFun("sqlite3_changes64"), - lastRowid: getFun("sqlite3_last_insert_rowid"), - autocommit: getFun("sqlite3_get_autocommit"), - anyCollation: getFun("sqlite3_anycollseq_init"), - createCollation: getFun("sqlite3_create_collation_go"), - createFunction: getFun("sqlite3_create_function_go"), - createAggregate: getFun("sqlite3_create_aggregate_function_go"), - createWindow: getFun("sqlite3_create_window_function_go"), - aggregateCtx: getFun("sqlite3_aggregate_context"), - userData: getFun("sqlite3_user_data"), - setAuxData: getFun("sqlite3_set_auxdata_go"), - getAuxData: getFun("sqlite3_get_auxdata"), - valueType: getFun("sqlite3_value_type"), - valueInteger: getFun("sqlite3_value_int64"), - valueFloat: getFun("sqlite3_value_double"), - valueText: getFun("sqlite3_value_text"), - valueBlob: getFun("sqlite3_value_blob"), - valueBytes: getFun("sqlite3_value_bytes"), - valuePointer: getFun("sqlite3_value_pointer_go"), - resultNull: getFun("sqlite3_result_null"), - resultInteger: getFun("sqlite3_result_int64"), - resultFloat: getFun("sqlite3_result_double"), - resultText: getFun("sqlite3_result_text64"), - resultBlob: getFun("sqlite3_result_blob64"), - resultZeroBlob: getFun("sqlite3_result_zeroblob64"), - resultPointer: getFun("sqlite3_result_pointer_go"), - resultValue: getFun("sqlite3_result_value"), - resultError: getFun("sqlite3_result_error"), - resultErrorCode: getFun("sqlite3_result_error_code"), - resultErrorMem: getFun("sqlite3_result_error_nomem"), - resultErrorBig: getFun("sqlite3_result_error_toobig"), - createModule: getFun("sqlite3_create_module_go"), - declareVTab: getFun("sqlite3_declare_vtab"), - vtabConfig: getFun("sqlite3_vtab_config_go"), - vtabRHSValue: getFun("sqlite3_vtab_rhs_value"), - } + sqlt.freer = util.ReadUint32(sqlt.mod, uint32(global.Get())) if err != nil { return nil, err } @@ -211,17 +113,17 @@ func (sqlt *sqlite) error(rc uint64, handle uint32, sql ...string) error { panic(util.OOMErr) } - if r := sqlt.call(sqlt.api.errstr, rc); r != 0 { + if r := sqlt.call("sqlite3_errstr", rc); r != 0 { err.str = util.ReadString(sqlt.mod, uint32(r), _MAX_NAME) } if handle != 0 { - if r := sqlt.call(sqlt.api.errmsg, uint64(handle)); r != 0 { + if r := sqlt.call("sqlite3_errmsg", uint64(handle)); r != 0 { err.msg = util.ReadString(sqlt.mod, uint32(r), _MAX_NAME) } if sql != nil { - if r := sqlt.call(sqlt.api.erroff, uint64(handle)); r != math.MaxUint32 { + if r := sqlt.call("sqlite3_error_offset", uint64(handle)); r != math.MaxUint32 { err.sql = sql[0][r:] } } @@ -234,8 +136,9 @@ func (sqlt *sqlite) error(rc uint64, handle uint32, sql ...string) error { return &err } -func (sqlt *sqlite) call(fn api.Function, params ...uint64) uint64 { +func (sqlt *sqlite) call(name string, params ...uint64) uint64 { copy(sqlt.stack[:], params) + fn := sqlt.mod.ExportedFunction(name) err := fn.CallWithStack(sqlt.ctx, sqlt.stack[:]) if err != nil { panic(err) @@ -247,14 +150,14 @@ func (sqlt *sqlite) free(ptr uint32) { if ptr == 0 { return } - sqlt.call(sqlt.api.free, uint64(ptr)) + sqlt.call("free", uint64(ptr)) } func (sqlt *sqlite) new(size uint64) uint32 { if size > _MAX_ALLOCATION_SIZE { panic(util.OOMErr) } - ptr := uint32(sqlt.call(sqlt.api.malloc, size)) + ptr := uint32(sqlt.call("malloc", size)) if ptr == 0 && size != 0 { panic(util.OOMErr) } @@ -342,90 +245,7 @@ func (a *arena) string(s string) uint32 { } type sqliteAPI struct { - free api.Function - malloc api.Function - errcode api.Function - errstr api.Function - errmsg api.Function - erroff api.Function - open api.Function - close api.Function - closeZombie api.Function - prepare api.Function - finalize api.Function - reset api.Function - step api.Function - exec api.Function - interrupt api.Function - progressHandler api.Function - clearBindings api.Function - bindCount api.Function - bindIndex api.Function - bindName api.Function - bindNull api.Function - bindInteger api.Function - bindFloat api.Function - bindText api.Function - bindBlob api.Function - bindZeroBlob api.Function - bindPointer api.Function - bindValue api.Function - columnCount api.Function - columnName api.Function - columnType api.Function - columnInteger api.Function - columnFloat api.Function - columnText api.Function - columnBlob api.Function - columnBytes api.Function - columnValue api.Function - blobOpen api.Function - blobClose api.Function - blobReopen api.Function - blobBytes api.Function - blobRead api.Function - blobWrite api.Function - backupInit api.Function - backupStep api.Function - backupFinish api.Function - backupRemaining api.Function - backupPageCount api.Function - changes api.Function - lastRowid api.Function - autocommit api.Function - anyCollation api.Function - createCollation api.Function - createFunction api.Function - createAggregate api.Function - createWindow api.Function - aggregateCtx api.Function - userData api.Function - setAuxData api.Function - getAuxData api.Function - valueType api.Function - valueInteger api.Function - valueFloat api.Function - valueText api.Function - valueBlob api.Function - valueBytes api.Function - valuePointer api.Function - resultNull api.Function - resultInteger api.Function - resultFloat api.Function - resultText api.Function - resultBlob api.Function - resultZeroBlob api.Function - resultPointer api.Function - resultValue api.Function - resultError api.Function - resultErrorCode api.Function - resultErrorMem api.Function - resultErrorBig api.Function - createModule api.Function - declareVTab api.Function - vtabConfig api.Function - vtabRHSValue api.Function - destructor uint32 + destructor uint32 } func exportCallbacks(env wazero.HostModuleBuilder) wazero.HostModuleBuilder { diff --git a/sqlite_test.go b/sqlite_test.go index bd10cb2..99538ea 100644 --- a/sqlite_test.go +++ b/sqlite_test.go @@ -37,7 +37,7 @@ func Test_sqlite_call_closed(t *testing.T) { sqlite.close() defer func() { _ = recover() }() - sqlite.call(sqlite.api.free) + sqlite.call("free") t.Error("want panic") } diff --git a/stmt.go b/stmt.go index e4cfb72..cb220e3 100644 --- a/stmt.go +++ b/stmt.go @@ -28,7 +28,7 @@ func (s *Stmt) Close() error { return nil } - r := s.c.call(s.c.api.finalize, uint64(s.handle)) + r := s.c.call("sqlite3_finalize", uint64(s.handle)) s.handle = 0 return s.c.error(r) @@ -38,7 +38,7 @@ func (s *Stmt) Close() error { // // https://sqlite.org/c3ref/reset.html func (s *Stmt) Reset() error { - r := s.c.call(s.c.api.reset, uint64(s.handle)) + r := s.c.call("sqlite3_reset", uint64(s.handle)) s.err = nil return s.c.error(r) } @@ -47,7 +47,7 @@ func (s *Stmt) Reset() error { // // https://sqlite.org/c3ref/clear_bindings.html func (s *Stmt) ClearBindings() error { - r := s.c.call(s.c.api.clearBindings, uint64(s.handle)) + r := s.c.call("sqlite3_clear_bindings", uint64(s.handle)) return s.c.error(r) } @@ -62,8 +62,7 @@ func (s *Stmt) ClearBindings() error { // https://sqlite.org/c3ref/step.html func (s *Stmt) Step() bool { s.c.checkInterrupt() - step := s.c.mod.ExportedFunction("sqlite3_step") - r := s.c.call(step, uint64(s.handle)) + r := s.c.call("sqlite3_step", uint64(s.handle)) switch r { case _ROW: return true @@ -95,7 +94,7 @@ func (s *Stmt) Exec() error { // // https://sqlite.org/c3ref/bind_parameter_count.html func (s *Stmt) BindCount() int { - r := s.c.call(s.c.api.bindCount, + r := s.c.call("sqlite3_bind_parameter_count", uint64(s.handle)) return int(r) } @@ -107,7 +106,7 @@ func (s *Stmt) BindCount() int { func (s *Stmt) BindIndex(name string) int { defer s.c.arena.mark()() namePtr := s.c.arena.string(name) - r := s.c.call(s.c.api.bindIndex, + r := s.c.call("sqlite3_bind_parameter_index", uint64(s.handle), uint64(namePtr)) return int(r) } @@ -117,7 +116,7 @@ func (s *Stmt) BindIndex(name string) int { // // https://sqlite.org/c3ref/bind_parameter_name.html func (s *Stmt) BindName(param int) string { - r := s.c.call(s.c.api.bindName, + r := s.c.call("sqlite3_bind_parameter_name", uint64(s.handle), uint64(param)) ptr := uint32(r) @@ -154,7 +153,7 @@ func (s *Stmt) BindInt(param int, value int) error { // // https://sqlite.org/c3ref/bind_blob.html func (s *Stmt) BindInt64(param int, value int64) error { - r := s.c.call(s.c.api.bindInteger, + r := s.c.call("sqlite3_bind_int64", uint64(s.handle), uint64(param), uint64(value)) return s.c.error(r) } @@ -164,7 +163,7 @@ func (s *Stmt) BindInt64(param int, value int64) error { // // https://sqlite.org/c3ref/bind_blob.html func (s *Stmt) BindFloat(param int, value float64) error { - r := s.c.call(s.c.api.bindFloat, + r := s.c.call("sqlite3_bind_double", uint64(s.handle), uint64(param), math.Float64bits(value)) return s.c.error(r) } @@ -178,10 +177,10 @@ func (s *Stmt) BindText(param int, value string) error { return TOOBIG } ptr := s.c.newString(value) - r := s.c.call(s.c.api.bindText, + r := s.c.call("sqlite3_bind_text64", uint64(s.handle), uint64(param), uint64(ptr), uint64(len(value)), - uint64(s.c.api.destructor), _UTF8) + uint64(s.c.freer), _UTF8) return s.c.error(r) } @@ -194,10 +193,10 @@ func (s *Stmt) BindRawText(param int, value []byte) error { return TOOBIG } ptr := s.c.newBytes(value) - r := s.c.call(s.c.api.bindText, + r := s.c.call("sqlite3_bind_text64", uint64(s.handle), uint64(param), uint64(ptr), uint64(len(value)), - uint64(s.c.api.destructor), _UTF8) + uint64(s.c.freer), _UTF8) return s.c.error(r) } @@ -211,10 +210,10 @@ func (s *Stmt) BindBlob(param int, value []byte) error { return TOOBIG } ptr := s.c.newBytes(value) - r := s.c.call(s.c.api.bindBlob, + r := s.c.call("sqlite3_bind_blob64", uint64(s.handle), uint64(param), uint64(ptr), uint64(len(value)), - uint64(s.c.api.destructor)) + uint64(s.c.freer)) return s.c.error(r) } @@ -223,7 +222,7 @@ func (s *Stmt) BindBlob(param int, value []byte) error { // // https://sqlite.org/c3ref/bind_blob.html func (s *Stmt) BindZeroBlob(param int, n int64) error { - r := s.c.call(s.c.api.bindZeroBlob, + r := s.c.call("sqlite3_bind_zeroblob64", uint64(s.handle), uint64(param), uint64(n)) return s.c.error(r) } @@ -233,7 +232,7 @@ func (s *Stmt) BindZeroBlob(param int, n int64) error { // // https://sqlite.org/c3ref/bind_blob.html func (s *Stmt) BindNull(param int) error { - r := s.c.call(s.c.api.bindNull, + r := s.c.call("sqlite3_bind_null", uint64(s.handle), uint64(param)) return s.c.error(r) } @@ -266,10 +265,10 @@ func (s *Stmt) bindRFC3339Nano(param int, value time.Time) error { buf := util.View(s.c.mod, ptr, maxlen) buf = value.AppendFormat(buf[:0], time.RFC3339Nano) - r := s.c.call(s.c.api.bindText, + r := s.c.call("sqlite3_bind_text64", uint64(s.handle), uint64(param), uint64(ptr), uint64(len(buf)), - uint64(s.c.api.destructor), _UTF8) + uint64(s.c.freer), _UTF8) return s.c.error(r) } @@ -281,7 +280,7 @@ func (s *Stmt) bindRFC3339Nano(param int, value time.Time) error { // https://sqlite.org/c3ref/bind_blob.html func (s *Stmt) BindPointer(param int, ptr any) error { valPtr := util.AddHandle(s.c.ctx, ptr) - r := s.c.call(s.c.api.bindPointer, + r := s.c.call("sqlite3_bind_pointer_go", uint64(s.handle), uint64(param), uint64(valPtr)) return s.c.error(r) } @@ -306,7 +305,7 @@ func (s *Stmt) BindValue(param int, value Value) error { if value.sqlite != s.c.sqlite { return MISUSE } - r := s.c.call(s.c.api.bindValue, + r := s.c.call("sqlite3_bind_value", uint64(s.handle), uint64(param), uint64(value.handle)) return s.c.error(r) } @@ -315,7 +314,7 @@ func (s *Stmt) BindValue(param int, value Value) error { // // https://sqlite.org/c3ref/column_count.html func (s *Stmt) ColumnCount() int { - r := s.c.call(s.c.api.columnCount, + r := s.c.call("sqlite3_column_count", uint64(s.handle)) return int(r) } @@ -325,7 +324,7 @@ func (s *Stmt) ColumnCount() int { // // https://sqlite.org/c3ref/column_name.html func (s *Stmt) ColumnName(col int) string { - r := s.c.call(s.c.api.columnName, + r := s.c.call("sqlite3_column_name", uint64(s.handle), uint64(col)) ptr := uint32(r) @@ -340,7 +339,7 @@ func (s *Stmt) ColumnName(col int) string { // // https://sqlite.org/c3ref/column_blob.html func (s *Stmt) ColumnType(col int) Datatype { - r := s.c.call(s.c.api.columnType, + r := s.c.call("sqlite3_column_type", uint64(s.handle), uint64(col)) return Datatype(r) } @@ -372,7 +371,7 @@ func (s *Stmt) ColumnInt(col int) int { // // https://sqlite.org/c3ref/column_blob.html func (s *Stmt) ColumnInt64(col int) int64 { - r := s.c.call(s.c.api.columnInteger, + r := s.c.call("sqlite3_column_int64", uint64(s.handle), uint64(col)) return int64(r) } @@ -382,7 +381,7 @@ func (s *Stmt) ColumnInt64(col int) int64 { // // https://sqlite.org/c3ref/column_blob.html func (s *Stmt) ColumnFloat(col int) float64 { - r := s.c.call(s.c.api.columnFloat, + r := s.c.call("sqlite3_column_double", uint64(s.handle), uint64(col)) return math.Float64frombits(r) } @@ -436,7 +435,7 @@ func (s *Stmt) ColumnBlob(col int, buf []byte) []byte { // // https://sqlite.org/c3ref/column_blob.html func (s *Stmt) ColumnRawText(col int) []byte { - r := s.c.call(s.c.api.columnText, + r := s.c.call("sqlite3_column_text", uint64(s.handle), uint64(col)) return s.columnRawBytes(col, uint32(r)) } @@ -448,19 +447,19 @@ func (s *Stmt) ColumnRawText(col int) []byte { // // https://sqlite.org/c3ref/column_blob.html func (s *Stmt) ColumnRawBlob(col int) []byte { - r := s.c.call(s.c.api.columnBlob, + r := s.c.call("sqlite3_column_blob", uint64(s.handle), uint64(col)) return s.columnRawBytes(col, uint32(r)) } func (s *Stmt) columnRawBytes(col int, ptr uint32) []byte { if ptr == 0 { - r := s.c.call(s.c.api.errcode, uint64(s.c.handle)) + r := s.c.call("sqlite3_errcode", uint64(s.c.handle)) s.err = s.c.error(r) return nil } - r := s.c.call(s.c.api.columnBytes, + r := s.c.call("sqlite3_column_bytes", uint64(s.handle), uint64(col)) return util.View(s.c.mod, ptr, r) } @@ -494,7 +493,7 @@ func (s *Stmt) ColumnJSON(col int, ptr any) error { // // https://sqlite.org/c3ref/column_blob.html func (s *Stmt) ColumnValue(col int) Value { - r := s.c.call(s.c.api.columnValue, + r := s.c.call("sqlite3_column_value", uint64(s.handle), uint64(col)) return Value{ unprot: true, diff --git a/value.go b/value.go index 1fae899..0426aad 100644 --- a/value.go +++ b/value.go @@ -29,7 +29,7 @@ func (v Value) protected() uint64 { // // https://sqlite.org/c3ref/value_blob.html func (v Value) Type() Datatype { - r := v.call(v.api.valueType, v.protected()) + r := v.call("sqlite3_value_type", v.protected()) return Datatype(r) } @@ -57,7 +57,7 @@ func (v Value) Int() int { // // https://sqlite.org/c3ref/value_blob.html func (v Value) Int64() int64 { - r := v.call(v.api.valueInteger, v.protected()) + r := v.call("sqlite3_value_int64", v.protected()) return int64(r) } @@ -65,7 +65,7 @@ func (v Value) Int64() int64 { // // https://sqlite.org/c3ref/value_blob.html func (v Value) Float() float64 { - r := v.call(v.api.valueFloat, v.protected()) + r := v.call("sqlite3_value_double", v.protected()) return math.Float64frombits(r) } @@ -111,7 +111,7 @@ func (v Value) Blob(buf []byte) []byte { // // https://sqlite.org/c3ref/value_blob.html func (v Value) RawText() []byte { - r := v.call(v.api.valueText, v.protected()) + r := v.call("sqlite3_value_text", v.protected()) return v.rawBytes(uint32(r)) } @@ -121,7 +121,7 @@ func (v Value) RawText() []byte { // // https://sqlite.org/c3ref/value_blob.html func (v Value) RawBlob() []byte { - r := v.call(v.api.valueBlob, v.protected()) + r := v.call("sqlite3_value_blob", v.protected()) return v.rawBytes(uint32(r)) } @@ -130,14 +130,14 @@ func (v Value) rawBytes(ptr uint32) []byte { return nil } - r := v.call(v.api.valueBytes, v.protected()) + r := v.call("sqlite3_value_bytes", v.protected()) return util.View(v.mod, ptr, r) } // Pointer gets the pointer associated with this value, // or nil if it has no associated pointer. func (v Value) Pointer() any { - r := v.call(v.api.valuePointer, v.protected()) + r := v.call("sqlite3_value_pointer_go", v.protected()) return util.GetHandle(v.ctx, uint32(r)) } diff --git a/vtab.go b/vtab.go index d260043..928a6d9 100644 --- a/vtab.go +++ b/vtab.go @@ -56,7 +56,7 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor defer db.arena.mark()() namePtr := db.arena.string(name) modulePtr := util.AddHandle(db.ctx, module[T]{create, connect}) - r := db.call(db.api.createModule, uint64(db.handle), + r := db.call("sqlite3_create_module_go", uint64(db.handle), uint64(namePtr), uint64(flags), uint64(modulePtr)) return db.error(r) } @@ -72,7 +72,7 @@ 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(c.api.declareVTab, uint64(c.handle), uint64(sqlPtr)) + r := c.call("sqlite3_declare_vtab", uint64(c.handle), uint64(sqlPtr)) return c.error(r) } @@ -98,7 +98,7 @@ func (c *Conn) VtabConfig(op VtabConfigOption, args ...any) error { i = 1 } } - r := c.call(c.api.vtabConfig, uint64(c.handle), uint64(op), i) + r := c.call("sqlite3_vtab_config_go", uint64(c.handle), uint64(op), i) return c.error(r) } @@ -257,7 +257,7 @@ 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(idx.c.api.vtabRHSValue, + 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