mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
WAL and vacuum hooks.
This commit is contained in:
67
config.go
67
config.go
@@ -82,7 +82,7 @@ func (c *Conn) SetAuthorizer(cb func(action AuthorizerActionCode, name3rd, name4
|
||||
|
||||
}
|
||||
|
||||
func authorizerCallback(ctx context.Context, mod api.Module, pDB uint32, action AuthorizerActionCode, zName3rd, zName4th, zSchema, zNameInner uint32) AuthorizerReturnCode {
|
||||
func authorizerCallback(ctx context.Context, mod api.Module, pDB uint32, action AuthorizerActionCode, zName3rd, zName4th, zSchema, zNameInner uint32) (rc AuthorizerReturnCode) {
|
||||
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.handle == pDB && c.authorizer != nil {
|
||||
var name3rd, name4th, schema, nameInner string
|
||||
if zName3rd != 0 {
|
||||
@@ -97,7 +97,68 @@ func authorizerCallback(ctx context.Context, mod api.Module, pDB uint32, action
|
||||
if zNameInner != 0 {
|
||||
nameInner = util.ReadString(mod, zNameInner, _MAX_NAME)
|
||||
}
|
||||
return c.authorizer(action, name3rd, name4th, schema, nameInner)
|
||||
rc = c.authorizer(action, name3rd, name4th, schema, nameInner)
|
||||
}
|
||||
return AUTH_OK
|
||||
return rc
|
||||
}
|
||||
|
||||
// WalCheckpoint checkpoints a WAL database.
|
||||
//
|
||||
// https://sqlite.org/c3ref/wal_checkpoint_v2.html
|
||||
func (c *Conn) WalCheckpoint(schema string, mode CheckpointMode) (nLog, nCkpt int, err error) {
|
||||
defer c.arena.mark()()
|
||||
nLogPtr := c.arena.new(ptrlen)
|
||||
nCkptPtr := c.arena.new(ptrlen)
|
||||
schemaPtr := c.arena.string(schema)
|
||||
r := c.call("sqlite3_wal_checkpoint_v2",
|
||||
uint64(c.handle), uint64(schemaPtr), uint64(mode),
|
||||
uint64(nLogPtr), uint64(nCkptPtr))
|
||||
nLog = int(int32(util.ReadUint32(c.mod, nLogPtr)))
|
||||
nCkpt = int(int32(util.ReadUint32(c.mod, nCkptPtr)))
|
||||
return nLog, nCkpt, c.error(r)
|
||||
}
|
||||
|
||||
// WalAutoCheckpoint configures WAL auto-checkpoints.
|
||||
//
|
||||
// https://sqlite.org/c3ref/wal_autocheckpoint.html
|
||||
func (c *Conn) WalAutoCheckpoint(pages int) error {
|
||||
r := c.call("sqlite3_wal_autocheckpoint", uint64(c.handle), uint64(pages))
|
||||
return c.error(r)
|
||||
}
|
||||
|
||||
// WalHook registers a callback function to be invoked
|
||||
// each time data is committed to a database in WAL mode.
|
||||
//
|
||||
// https://sqlite.org/c3ref/wal_hook.html
|
||||
func (c *Conn) WalHook(cb func(db *Conn, schema string, pages int) error) {
|
||||
var enable uint64
|
||||
if cb != nil {
|
||||
enable = 1
|
||||
}
|
||||
c.call("sqlite3_wal_hook_go", uint64(c.handle), enable)
|
||||
c.wal = cb
|
||||
}
|
||||
|
||||
func walCallback(ctx context.Context, mod api.Module, _, pDB, zSchema uint32, pages int32) (rc uint32) {
|
||||
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.handle == pDB && c.wal != nil {
|
||||
schema := util.ReadString(mod, zSchema, _MAX_NAME)
|
||||
err := c.wal(c, schema, int(pages))
|
||||
_, rc = errorCode(err, ERROR)
|
||||
}
|
||||
return rc
|
||||
}
|
||||
|
||||
// AutoVacuumPages registers a autovacuum compaction amount callback.
|
||||
//
|
||||
// https://sqlite.org/c3ref/autovacuum_pages.html
|
||||
func (c *Conn) AutoVacuumPages(cb func(schema string, dbPages, freePages, bytesPerPage uint) uint) error {
|
||||
funcPtr := util.AddHandle(c.ctx, cb)
|
||||
r := c.call("sqlite3_autovacuum_pages_go", uint64(c.handle), uint64(funcPtr))
|
||||
return c.error(r)
|
||||
}
|
||||
|
||||
func autoVacuumCallback(ctx context.Context, mod api.Module, pApp, zSchema, nDbPage, nFreePage, nBytePerPage uint32) uint32 {
|
||||
fn := util.GetHandle(ctx, pApp).(func(schema string, dbPages, freePages, bytesPerPage uint) uint)
|
||||
schema := util.ReadString(mod, zSchema, _MAX_NAME)
|
||||
return uint32(fn(schema, uint(nDbPage), uint(nFreePage), uint(nBytePerPage)))
|
||||
}
|
||||
|
||||
21
conn.go
21
conn.go
@@ -29,6 +29,7 @@ type Conn struct {
|
||||
update func(AuthorizerActionCode, string, string, int64)
|
||||
commit func() bool
|
||||
rollback func()
|
||||
wal func(*Conn, string, int) error
|
||||
arena arena
|
||||
|
||||
handle uint32
|
||||
@@ -281,6 +282,12 @@ func (c *Conn) ReleaseMemory() error {
|
||||
return c.error(r)
|
||||
}
|
||||
|
||||
// GetInterrupt gets the context set with [Conn.SetInterrupt],
|
||||
// or nil if none was set.
|
||||
func (c *Conn) GetInterrupt() context.Context {
|
||||
return c.interrupt
|
||||
}
|
||||
|
||||
// SetInterrupt interrupts a long-running query when a context is done.
|
||||
//
|
||||
// Subsequent uses of the connection will return [INTERRUPT]
|
||||
@@ -325,13 +332,13 @@ func (c *Conn) checkInterrupt() {
|
||||
}
|
||||
}
|
||||
|
||||
func progressCallback(ctx context.Context, mod api.Module, pDB uint32) uint32 {
|
||||
func progressCallback(ctx context.Context, mod api.Module, pDB uint32) (interrupt uint32) {
|
||||
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.handle == pDB && c.commit != nil {
|
||||
if c.interrupt != nil && c.interrupt.Err() != nil {
|
||||
return 1
|
||||
interrupt = 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
return interrupt
|
||||
}
|
||||
|
||||
// BusyTimeout sets a busy timeout.
|
||||
@@ -359,13 +366,13 @@ func (c *Conn) BusyHandler(cb func(count int) (retry bool)) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func busyCallback(ctx context.Context, mod api.Module, pDB, count uint32) uint32 {
|
||||
func busyCallback(ctx context.Context, mod api.Module, pDB uint32, count int32) (retry uint32) {
|
||||
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.handle == pDB && c.busy != nil {
|
||||
if retry := c.busy(int(count)); retry {
|
||||
return 1
|
||||
if c.busy(int(count)) {
|
||||
retry = 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
return retry
|
||||
}
|
||||
|
||||
func (c *Conn) error(rc uint64, sql ...string) error {
|
||||
|
||||
12
const.go
12
const.go
@@ -305,6 +305,18 @@ const (
|
||||
AUTH_IGNORE AuthorizerReturnCode = 2 /* Don't allow access, but don't generate an error */
|
||||
)
|
||||
|
||||
// CheckpointMode are all the checkpoint mode values.
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_checkpoint_full.html
|
||||
type CheckpointMode uint32
|
||||
|
||||
const (
|
||||
CHECKPOINT_PASSIVE CheckpointMode = 0 /* Do as much as possible w/o blocking */
|
||||
CHECKPOINT_FULL CheckpointMode = 1 /* Wait for writers, then checkpoint */
|
||||
CHECKPOINT_RESTART CheckpointMode = 2 /* Like FULL but wait for readers */
|
||||
CHECKPOINT_TRUNCATE CheckpointMode = 3 /* Like RESTART but also truncate WAL */
|
||||
)
|
||||
|
||||
// TxnState are the allowed return values from [Conn.TxnState].
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_txn_none.html
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Embeddable Wasm build of SQLite
|
||||
|
||||
This folder includes an embeddable Wasm build of SQLite 3.45.1 for use with
|
||||
This folder includes an embeddable Wasm build of SQLite 3.45.2 for use with
|
||||
[`github.com/ncruces/go-sqlite3`](https://pkg.go.dev/github.com/ncruces/go-sqlite3).
|
||||
|
||||
The following optional features are compiled in:
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
aligned_alloc
|
||||
free
|
||||
malloc
|
||||
malloc_destructor
|
||||
aligned_alloc
|
||||
sqlite3_anycollseq_init
|
||||
sqlite3_autovacuum_pages_go
|
||||
sqlite3_backup_finish
|
||||
sqlite3_backup_init
|
||||
sqlite3_backup_pagecount
|
||||
@@ -115,4 +116,7 @@ sqlite3_vtab_in_first
|
||||
sqlite3_vtab_in_next
|
||||
sqlite3_vtab_nochange
|
||||
sqlite3_vtab_on_conflict
|
||||
sqlite3_vtab_rhs_value
|
||||
sqlite3_vtab_rhs_value
|
||||
sqlite3_wal_autocheckpoint
|
||||
sqlite3_wal_checkpoint_v2
|
||||
sqlite3_wal_hook_go
|
||||
Binary file not shown.
@@ -334,7 +334,7 @@ type _Index struct {
|
||||
// GetIndexes return Indexes []gorm.Index and execErr error,
|
||||
// See the [doc]
|
||||
//
|
||||
// [doc]: https://www.sqlite.org/pragma.html#pragma_index_list
|
||||
// [doc]: https://sqlite.org/pragma.html#pragma_index_list
|
||||
func (m _Migrator) GetIndexes(value interface{}) ([]gorm.Index, error) {
|
||||
indexes := make([]gorm.Index, 0)
|
||||
err := m.RunWithValue(value, func(stmt *gorm.Statement) error {
|
||||
|
||||
@@ -294,6 +294,8 @@ func exportCallbacks(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
|
||||
util.ExportFuncII(env, "go_commit_hook", commitCallback)
|
||||
util.ExportFuncVI(env, "go_rollback_hook", rollbackCallback)
|
||||
util.ExportFuncVIIIIJ(env, "go_update_hook", updateCallback)
|
||||
util.ExportFuncIIIII(env, "go_wal_hook", walCallback)
|
||||
util.ExportFuncIIIIII(env, "go_autovacuum_pages", autoVacuumCallback)
|
||||
util.ExportFuncIIIIIII(env, "go_authorizer", authorizerCallback)
|
||||
util.ExportFuncVIII(env, "go_log", logCallback)
|
||||
util.ExportFuncVI(env, "go_destroy", destroyCallback)
|
||||
|
||||
@@ -8,12 +8,16 @@ int go_busy_handler(void *, int);
|
||||
int go_commit_hook(void *);
|
||||
void go_rollback_hook(void *);
|
||||
void go_update_hook(void *, int, char const *, char const *, sqlite3_int64);
|
||||
int go_wal_hook(void *, sqlite3 *, const char *, int);
|
||||
|
||||
int go_authorizer(void *, int, const char *, const char *, const char *,
|
||||
const char *);
|
||||
|
||||
void go_log(void *, int, const char *);
|
||||
|
||||
unsigned int go_autovacuum_pages(void *, const char *, unsigned int,
|
||||
unsigned int, unsigned int);
|
||||
|
||||
void sqlite3_progress_handler_go(sqlite3 *db, int n) {
|
||||
sqlite3_progress_handler(db, n, go_progress_handler, /*arg=*/db);
|
||||
}
|
||||
@@ -34,6 +38,10 @@ void sqlite3_update_hook_go(sqlite3 *db, bool enable) {
|
||||
sqlite3_update_hook(db, enable ? go_update_hook : NULL, /*arg=*/db);
|
||||
}
|
||||
|
||||
void sqlite3_wal_hook_go(sqlite3 *db, bool enable) {
|
||||
sqlite3_wal_hook(db, enable ? go_wal_hook : NULL, /*arg=*/NULL);
|
||||
}
|
||||
|
||||
int sqlite3_set_authorizer_go(sqlite3 *db, bool enable) {
|
||||
return sqlite3_set_authorizer(db, enable ? go_authorizer : NULL, /*arg=*/db);
|
||||
}
|
||||
@@ -41,4 +49,10 @@ int sqlite3_set_authorizer_go(sqlite3 *db, bool enable) {
|
||||
int sqlite3_config_log_go(bool enable) {
|
||||
return sqlite3_config(SQLITE_CONFIG_LOG, enable ? go_log : NULL,
|
||||
/*arg=*/NULL);
|
||||
}
|
||||
|
||||
int sqlite3_autovacuum_pages_go(sqlite3 *db, go_handle app) {
|
||||
int rc = sqlite3_autovacuum_pages(db, go_autovacuum_pages, app, go_destroy);
|
||||
if (rc) go_destroy(app);
|
||||
return rc;
|
||||
}
|
||||
8
stmt.go
8
stmt.go
@@ -120,7 +120,7 @@ func (s *Stmt) Status(op StmtStatus, reset bool) int {
|
||||
}
|
||||
r := s.c.call("sqlite3_stmt_status", uint64(s.handle),
|
||||
uint64(op), i)
|
||||
return int(r)
|
||||
return int(int32(r))
|
||||
}
|
||||
|
||||
// ClearBindings resets all bindings on the prepared statement.
|
||||
@@ -137,7 +137,7 @@ func (s *Stmt) ClearBindings() error {
|
||||
func (s *Stmt) BindCount() int {
|
||||
r := s.c.call("sqlite3_bind_parameter_count",
|
||||
uint64(s.handle))
|
||||
return int(r)
|
||||
return int(int32(r))
|
||||
}
|
||||
|
||||
// BindIndex returns the index of a parameter in the prepared statement
|
||||
@@ -149,7 +149,7 @@ func (s *Stmt) BindIndex(name string) int {
|
||||
namePtr := s.c.arena.string(name)
|
||||
r := s.c.call("sqlite3_bind_parameter_index",
|
||||
uint64(s.handle), uint64(namePtr))
|
||||
return int(r)
|
||||
return int(int32(r))
|
||||
}
|
||||
|
||||
// BindName returns the name of a parameter in the prepared statement.
|
||||
@@ -357,7 +357,7 @@ func (s *Stmt) BindValue(param int, value Value) error {
|
||||
func (s *Stmt) ColumnCount() int {
|
||||
r := s.c.call("sqlite3_column_count",
|
||||
uint64(s.handle))
|
||||
return int(r)
|
||||
return int(int32(r))
|
||||
}
|
||||
|
||||
// ColumnName returns the name of the result column.
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/ncruces/go-sqlite3"
|
||||
_ "github.com/ncruces/go-sqlite3/embed"
|
||||
_ "github.com/ncruces/go-sqlite3/vfs/memdb"
|
||||
)
|
||||
|
||||
func TestConn_Open_dir(t *testing.T) {
|
||||
@@ -449,3 +450,35 @@ func TestConn_DBName(t *testing.T) {
|
||||
t.Errorf("got %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConn_AutoVacuumPages(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := sqlite3.Open("file:test.db?vfs=memdb&_pragma=auto_vacuum(FULL)")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
err = db.AutoVacuumPages(func(schema string, dbPages, freePages, bytesPerPage uint) uint {
|
||||
return freePages
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = db.Exec(`CREATE TABLE test (col)`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = db.Exec(`INSERT INTO test VALUES (zeroblob(1024*1024))`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = db.Exec(`DROP TABLE test`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,3 +31,34 @@ func TestWAL_enter_exit(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConn_WalCheckpoint(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
file := filepath.Join(t.TempDir(), "test.db")
|
||||
|
||||
db, err := sqlite3.Open(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
err = db.WalAutoCheckpoint(1000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
db.WalHook(func(db *sqlite3.Conn, schema string, pages int) error {
|
||||
log, ckpt, err := db.WalCheckpoint(schema, sqlite3.CHECKPOINT_FULL)
|
||||
t.Log(log, ckpt, err)
|
||||
return err
|
||||
})
|
||||
|
||||
err = db.Exec(`
|
||||
PRAGMA journal_mode=WAL;
|
||||
CREATE TABLE test (col);
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
10
txn.go
10
txn.go
@@ -257,7 +257,7 @@ func (c *Conn) RollbackHook(cb func()) {
|
||||
c.rollback = cb
|
||||
}
|
||||
|
||||
// RollbackHook registers a callback function to be invoked
|
||||
// UpdateHook registers a callback function to be invoked
|
||||
// whenever a row is updated, inserted or deleted in a rowid table.
|
||||
//
|
||||
// https://sqlite.org/c3ref/update_hook.html
|
||||
@@ -270,13 +270,13 @@ func (c *Conn) UpdateHook(cb func(action AuthorizerActionCode, schema, table str
|
||||
c.update = cb
|
||||
}
|
||||
|
||||
func commitCallback(ctx context.Context, mod api.Module, pDB uint32) uint32 {
|
||||
func commitCallback(ctx context.Context, mod api.Module, pDB uint32) (rollback uint32) {
|
||||
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.handle == pDB && c.commit != nil {
|
||||
if ok := c.commit(); !ok {
|
||||
return 1
|
||||
if !c.commit() {
|
||||
rollback = 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
return rollback
|
||||
}
|
||||
|
||||
func rollbackCallback(ctx context.Context, mod api.Module, pDB uint32) {
|
||||
|
||||
@@ -117,11 +117,9 @@ func (f *vfsFile) Unlock(lock LockLevel) error {
|
||||
|
||||
switch lock {
|
||||
case LOCK_SHARED:
|
||||
if rc := osDowngradeLock(f.File, f.lock); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
rc := osDowngradeLock(f.File, f.lock)
|
||||
f.lock = LOCK_SHARED
|
||||
return nil
|
||||
return rc
|
||||
|
||||
case LOCK_NONE:
|
||||
rc := osReleaseLock(f.File, f.lock)
|
||||
|
||||
4
vfs/tests/mptest/testdata/mptest.wasm.bz2
vendored
4
vfs/tests/mptest/testdata/mptest.wasm.bz2
vendored
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:523b3640c6de9accf3f6b01e7da2098faba12eec0168b67a78c56fef0716c7ae
|
||||
size 469261
|
||||
oid sha256:40b56dfd62584e32da7191c664ecfdd28dca419de05b9e46f4b36f7919a36d3e
|
||||
size 468861
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:855720cce2881c98d09c15eddf9cab0d5974a2a82f7f67987a28b97414629345
|
||||
size 483463
|
||||
oid sha256:6be5a0accea1a62ecdaf2055388f02ab52ea13323b90c36dd5833d8a4717c7c1
|
||||
size 483476
|
||||
|
||||
12
vtab.go
12
vtab.go
@@ -489,7 +489,7 @@ func vtabRenameCallback(ctx context.Context, mod api.Module, pVTab, zNew uint32)
|
||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
||||
}
|
||||
|
||||
func vtabFindFuncCallback(ctx context.Context, mod api.Module, pVTab, nArg, zName, pxFunc uint32) uint32 {
|
||||
func vtabFindFuncCallback(ctx context.Context, mod api.Module, pVTab uint32, nArg int32, zName, pxFunc uint32) uint32 {
|
||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabOverloader)
|
||||
f, op := vtab.FindFunction(int(nArg), util.ReadString(mod, zName, _MAX_NAME))
|
||||
if op != 0 {
|
||||
@@ -539,19 +539,19 @@ func vtabRollbackCallback(ctx context.Context, mod api.Module, pVTab uint32) uin
|
||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
||||
}
|
||||
|
||||
func vtabSavepointCallback(ctx context.Context, mod api.Module, pVTab, id uint32) uint32 {
|
||||
func vtabSavepointCallback(ctx context.Context, mod api.Module, pVTab uint32, id int32) uint32 {
|
||||
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, id uint32) uint32 {
|
||||
func vtabReleaseCallback(ctx context.Context, mod api.Module, pVTab uint32, id int32) uint32 {
|
||||
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, id uint32) uint32 {
|
||||
func vtabRollbackToCallback(ctx context.Context, mod api.Module, pVTab uint32, id int32) uint32 {
|
||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer)
|
||||
err := vtab.RollbackTo(int(id))
|
||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
||||
@@ -573,7 +573,7 @@ func cursorCloseCallback(ctx context.Context, mod api.Module, pCur uint32) uint3
|
||||
return vtabError(ctx, mod, 0, _VTAB_ERROR, err)
|
||||
}
|
||||
|
||||
func cursorFilterCallback(ctx context.Context, mod api.Module, pCur, idxNum, idxStr, nArg, pArg uint32) uint32 {
|
||||
func cursorFilterCallback(ctx context.Context, mod api.Module, pCur uint32, idxNum int32, idxStr, nArg, pArg uint32) uint32 {
|
||||
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
|
||||
db := ctx.Value(connKey{}).(*Conn)
|
||||
args := make([]Value, nArg)
|
||||
@@ -600,7 +600,7 @@ func cursorNextCallback(ctx context.Context, mod api.Module, pCur uint32) uint32
|
||||
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err)
|
||||
}
|
||||
|
||||
func cursorColumnCallback(ctx context.Context, mod api.Module, pCur, pCtx, n uint32) uint32 {
|
||||
func cursorColumnCallback(ctx context.Context, mod api.Module, pCur, pCtx uint32, n int32) uint32 {
|
||||
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
|
||||
db := ctx.Value(connKey{}).(*Conn)
|
||||
err := cursor.Column(&Context{db, pCtx}, int(n))
|
||||
|
||||
Reference in New Issue
Block a user