Compare commits

..

7 Commits

Author SHA1 Message Date
Nuno Cruces
58df08329d SQLite 3.45.1. 2024-02-03 02:00:45 +00:00
Nuno Cruces
cdab468a92 Flaky tests. 2024-02-03 02:00:40 +00:00
Nuno Cruces
7438fdb664 Busy handlers. 2024-02-03 00:34:15 +00:00
Nuno Cruces
da0e98f17e BSD tests. 2024-02-02 19:10:56 +00:00
Nuno Cruces
bb0c77c6fa Test on M1. 2024-02-02 17:49:46 +00:00
Nuno Cruces
ea8894162b Update dependencies. 2024-02-02 17:43:24 +00:00
Nuno Cruces
9898fbfffa Rename. 2024-02-02 17:40:55 +00:00
22 changed files with 160 additions and 76 deletions

10
.github/workflows/bsd.sh vendored Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bash
echo 'set -euo pipefail' > test.sh
for p in $(go list ./...); do
dir=".${p#github.com/ncruces/go-sqlite3}"
name="$(basename "$p").test"
(cd ${dir}; GOOS=freebsd go test -c)
[ -f "${dir}/${name}" ] && echo "(cd ${dir}; ./${name} -test.v)" >> test.sh
done

View File

@@ -12,13 +12,20 @@ jobs:
with:
lfs: 'true'
- name: Set up
uses: actions/setup-go@v5
with:
go-version: stable
- name: Build
run: .github/workflows/bsd.sh
- name: Test
uses: cross-platform-actions/action@v0.22.0
with:
operating_system: freebsd
version: '13.2'
memory: 8G
shell: bash
sync_files: runner-to-vm
run: |
sudo pkg install -y go121
go121 test -v ./...
run: source test.sh

View File

@@ -18,7 +18,7 @@ jobs:
go-version: stable
- name: Test
run: GOARCH=386 go test -v ./...
run: GOARCH=386 go test -v -short ./...
test-arm:
runs-on: ubuntu-latest
@@ -37,4 +37,20 @@ jobs:
uses: docker/setup-qemu-action@v3
- name: Test
run: GOARCH=arm64 go test -v ./...
run: GOARCH=arm64 go test -v -short ./...
test-m1:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
with:
lfs: 'true'
- name: Set up
uses: actions/setup-go@v5
with:
go-version: stable
- name: Test
run: go test -v ./...

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
echo android ; GOOS=android GOARCH=amd64 go build .
echo darwin ; GOOS=darwin GOARCH=amd64 go build .

41
conn.go
View File

@@ -4,8 +4,10 @@ import (
"context"
"errors"
"fmt"
"math"
"net/url"
"strings"
"time"
"github.com/ncruces/go-sqlite3/internal/util"
"github.com/tetratelabs/wazero/api"
@@ -20,6 +22,7 @@ type Conn struct {
interrupt context.Context
pending *Stmt
busy func(int) bool
log func(xErrorCode, string)
collation func(*Conn, string)
authorizer func(AuthorizerActionCode, string, string, string, string) AuthorizerReturnCode
@@ -322,8 +325,8 @@ func (c *Conn) checkInterrupt() {
}
}
func progressCallback(ctx context.Context, mod api.Module, _ uint32) uint32 {
if c, ok := ctx.Value(connKey{}).(*Conn); ok {
func progressCallback(ctx context.Context, mod api.Module, pDB uint32) 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
}
@@ -331,6 +334,40 @@ func progressCallback(ctx context.Context, mod api.Module, _ uint32) uint32 {
return 0
}
// BusyTimeout sets a busy timeout.
//
// https://sqlite.org/c3ref/busy_timeout.html
func (c *Conn) BusyTimeout(timeout time.Duration) error {
ms := min((timeout+time.Millisecond-1)/time.Millisecond, math.MaxInt32)
r := c.call("sqlite3_busy_timeout", uint64(c.handle), uint64(ms))
return c.error(r)
}
// BusyHandler registers a callback to handle [BUSY] errors.
//
// https://sqlite.org/c3ref/busy_handler.html
func (c *Conn) BusyHandler(cb func(count int) (retry bool)) error {
var enable uint64
if cb != nil {
enable = 1
}
r := c.call("sqlite3_busy_handler_go", uint64(c.handle), enable)
if err := c.error(r); err != nil {
return err
}
c.busy = cb
return nil
}
func busyCallback(ctx context.Context, mod api.Module, pDB, count uint32) uint32 {
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.handle == pDB && c.busy != nil {
if retry := c.busy(int(count)); retry {
return 1
}
}
return 0
}
// Deprecated: executes a PRAGMA statement and returns results.
func (c *Conn) Pragma(str string) ([]string, error) {
stmt, _, err := c.Prepare(`PRAGMA ` + str)

View File

@@ -170,7 +170,7 @@ func (n *connector) Connect(ctx context.Context) (_ driver.Conn, err error) {
defer c.Conn.SetInterrupt(old)
if !n.pragmas {
err = c.Conn.Exec(`PRAGMA busy_timeout=60000`)
err = c.Conn.BusyTimeout(60 * time.Second)
if err != nil {
return nil, err
}

View File

@@ -1,6 +1,6 @@
# Embeddable WASM build of SQLite
This folder includes an embeddable WASM build of SQLite 3.45.0 for use with
This folder includes an embeddable WASM build of SQLite 3.45.1 for use with
[`github.com/ncruces/go-sqlite3`](https://pkg.go.dev/github.com/ncruces/go-sqlite3).
The following optional features are compiled in:

View File

@@ -24,6 +24,8 @@ sqlite3_blob_open
sqlite3_blob_read
sqlite3_blob_reopen
sqlite3_blob_write
sqlite3_busy_handler_go
sqlite3_busy_timeout
sqlite3_changes64
sqlite3_clear_bindings
sqlite3_close

Binary file not shown.

View File

@@ -3,8 +3,8 @@ module github.com/ncruces/go-sqlite3/gormlite
go 1.21
require (
github.com/ncruces/go-sqlite3 v0.12.0
gorm.io/gorm v1.25.5
github.com/ncruces/go-sqlite3 v0.12.1
gorm.io/gorm v1.25.6
)
require (

View File

@@ -2,8 +2,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/ncruces/go-sqlite3 v0.12.0 h1:ZqCziV5XxdwiDOIOChRjhIwJqmMOctSrYwxwyzYx5zw=
github.com/ncruces/go-sqlite3 v0.12.0/go.mod h1:+8dWcBxb2Yar4EcCwav1a21MpKZbztwOYBLSRYt9bMY=
github.com/ncruces/go-sqlite3 v0.12.1 h1:fxNoMQXIiMJ92B4umXyTYbNlk3xyQpZQ2S1Bojz8Z/Y=
github.com/ncruces/go-sqlite3 v0.12.1/go.mod h1:+8dWcBxb2Yar4EcCwav1a21MpKZbztwOYBLSRYt9bMY=
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
@@ -12,5 +12,5 @@ golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.6 h1:V92+vVda1wEISSOMtodHVRcUIOPYa2tgQtyF+DfFx+A=
gorm.io/gorm v1.25.6/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=

View File

@@ -6,7 +6,7 @@ cd -P -- "$(dirname -- "$0")"
go test
rm -rf gorm/ tests/
git clone --branch v1.25.5 --filter=blob:none https://github.com/go-gorm/gorm.git
git clone --branch v1.25.6 --filter=blob:none https://github.com/go-gorm/gorm.git
mv gorm/tests tests
rm -rf gorm/

View File

@@ -289,7 +289,8 @@ func (a *arena) string(s string) uint32 {
}
func exportCallbacks(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
util.ExportFuncII(env, "go_progress", progressCallback)
util.ExportFuncIII(env, "go_busy_handler", busyCallback)
util.ExportFuncII(env, "go_progress_handler", progressCallback)
util.ExportFuncII(env, "go_commit_hook", commitCallback)
util.ExportFuncVI(env, "go_rollback_hook", rollbackCallback)
util.ExportFuncVIIIIJ(env, "go_update_hook", updateCallback)

View File

@@ -3,7 +3,7 @@ set -euo pipefail
cd -P -- "$(dirname -- "$0")"
curl -#OL "https://sqlite.org/2024/sqlite-amalgamation-3450000.zip"
curl -#OL "https://sqlite.org/2024/sqlite-amalgamation-3450100.zip"
unzip -d . sqlite-amalgamation-*.zip
mv sqlite-amalgamation-*/sqlite3* .
rm -rf sqlite-amalgamation-*
@@ -12,25 +12,25 @@ cat *.patch | patch --no-backup-if-mismatch
mkdir -p ext/
cd ext/
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/ext/misc/anycollseq.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/ext/misc/base64.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/ext/misc/decimal.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/ext/misc/ieee754.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/ext/misc/regexp.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/ext/misc/series.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/ext/misc/uint.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/ext/misc/uuid.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/ext/misc/anycollseq.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/ext/misc/base64.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/ext/misc/decimal.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/ext/misc/ieee754.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/ext/misc/regexp.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/ext/misc/series.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/ext/misc/uint.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/ext/misc/uuid.c"
cd ~-
cd ../vfs/tests/mptest/testdata/
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/mptest/mptest.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/mptest/config01.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/mptest/config02.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/mptest/crash01.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/mptest/crash02.subtest"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/mptest/multiwrite01.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/mptest/mptest.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/mptest/config01.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/mptest/config02.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/mptest/crash01.test"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/mptest/crash02.subtest"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/mptest/multiwrite01.test"
cd ~-
cd ../vfs/tests/speedtest1/testdata/
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.0/test/speedtest1.c"
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.45.1/test/speedtest1.c"
cd ~-

View File

@@ -2,7 +2,8 @@
#include "sqlite3.h"
int go_progress(void *);
int go_progress_handler(void *);
int go_busy_handler(void *, int);
int go_commit_hook(void *);
void go_rollback_hook(void *);
@@ -14,7 +15,11 @@ int go_authorizer(void *, int, const char *, const char *, const char *,
void go_log(void *, int, const char *);
void sqlite3_progress_handler_go(sqlite3 *db, int n) {
sqlite3_progress_handler(db, n, go_progress, /*arg=*/db);
sqlite3_progress_handler(db, n, go_progress_handler, /*arg=*/db);
}
int sqlite3_busy_handler_go(sqlite3 *db, bool enable) {
return sqlite3_busy_handler(db, enable ? go_busy_handler : NULL, /*arg=*/db);
}
void sqlite3_commit_hook_go(sqlite3 *db, bool enable) {

View File

@@ -9,7 +9,7 @@
#define SQLITE_VTAB_RENAMER_GO /******/ 0x08
#define SQLITE_VTAB_OVERLOADER_GO /***/ 0x10
#define SQLITE_VTAB_CHECKER_GO /******/ 0x20
#define SQLITE_VTAB_TX_GO /***********/ 0x40
#define SQLITE_VTAB_TXN_GO /**********/ 0x40
#define SQLITE_VTAB_SAVEPOINTER_GO /**/ 0x80
int go_vtab_create(sqlite3_module *, int argc, const char *const *argv,
@@ -193,7 +193,7 @@ int sqlite3_create_module_go(sqlite3 *db, const char *zName, int flags,
if (flags & SQLITE_VTAB_CHECKER_GO) {
mod->base.xIntegrity = go_vtab_integrity_wrapper;
}
if (flags & SQLITE_VTAB_TX_GO) {
if (flags & SQLITE_VTAB_TXN_GO) {
mod->base.xBegin = go_vtab_begin;
mod->base.xSync = go_vtab_sync;
mod->base.xCommit = go_vtab_commit;

View File

@@ -6,6 +6,7 @@ import (
"os/exec"
"path/filepath"
"testing"
"time"
"golang.org/x/sync/errgroup"
@@ -39,10 +40,7 @@ func TestMemory(t *testing.T) {
iter = 5000
}
name := "file:/test.db?vfs=memdb" +
"&_pragma=busy_timeout(10000)" +
"&_pragma=journal_mode(memory)" +
"&_pragma=synchronous(off)"
name := "file:/test.db?vfs=memdb"
testParallel(t, name, iter)
testIntegrity(t, name)
}
@@ -100,10 +98,7 @@ func TestChildProcess(t *testing.T) {
func BenchmarkMemory(b *testing.B) {
memdb.Delete("test.db")
name := "file:/test.db?vfs=memdb" +
"&_pragma=busy_timeout(10000)" +
"&_pragma=journal_mode(memory)" +
"&_pragma=synchronous(off)"
name := "file:/test.db?vfs=memdb"
testParallel(b, name, b.N)
}
@@ -115,6 +110,14 @@ func testParallel(t testing.TB, name string, n int) {
}
defer db.Close()
err = db.BusyHandler(func(count int) (retry bool) {
time.Sleep(time.Millisecond)
return true
})
if err != nil {
return err
}
err = db.Exec(`CREATE TABLE IF NOT EXISTS users (id INT, name VARCHAR(10))`)
if err != nil {
return err
@@ -135,7 +138,7 @@ func testParallel(t testing.TB, name string, n int) {
}
defer db.Close()
err = db.Exec(`PRAGMA busy_timeout=10000`)
err = db.BusyTimeout(10 * time.Second)
if err != nil {
return err
}

16
txn.go
View File

@@ -25,7 +25,7 @@ type Txn struct {
// https://sqlite.org/lang_transaction.html
func (c *Conn) Begin() Txn {
// BEGIN even if interrupted.
err := c.txExecInterrupted(`BEGIN DEFERRED`)
err := c.txnExecInterrupted(`BEGIN DEFERRED`)
if err != nil {
panic(err)
}
@@ -54,7 +54,7 @@ func (c *Conn) BeginExclusive() (Txn, error) {
return Txn{c}, nil
}
// End calls either [Tx.Commit] or [Tx.Rollback]
// End calls either [Txn.Commit] or [Txn.Rollback]
// depending on whether *error points to a nil or non-nil error.
//
// This is meant to be deferred:
@@ -107,7 +107,7 @@ func (tx Txn) Commit() error {
//
// https://sqlite.org/lang_transaction.html
func (tx Txn) Rollback() error {
return tx.c.txExecInterrupted(`ROLLBACK`)
return tx.c.txnExecInterrupted(`ROLLBACK`)
}
// Savepoint is a marker within a transaction
@@ -126,7 +126,7 @@ func (c *Conn) Savepoint() Savepoint {
// Names can be reused; this makes catching bugs more likely.
name := saveptName() + "_" + strconv.Itoa(int(rand.Int31()))
err := c.txExecInterrupted(fmt.Sprintf("SAVEPOINT %q;", name))
err := c.txnExecInterrupted(fmt.Sprintf("SAVEPOINT %q;", name))
if err != nil {
panic(err)
}
@@ -188,7 +188,7 @@ func (s Savepoint) Release(errp *error) {
return
}
// ROLLBACK and RELEASE even if interrupted.
err := s.c.txExecInterrupted(fmt.Sprintf(`
err := s.c.txnExecInterrupted(fmt.Sprintf(`
ROLLBACK TO %[1]q;
RELEASE %[1]q;
`, s.name))
@@ -204,10 +204,10 @@ func (s Savepoint) Release(errp *error) {
// https://sqlite.org/lang_transaction.html
func (s Savepoint) Rollback() error {
// ROLLBACK even if interrupted.
return s.c.txExecInterrupted(fmt.Sprintf("ROLLBACK TO %q;", s.name))
return s.c.txnExecInterrupted(fmt.Sprintf("ROLLBACK TO %q;", s.name))
}
func (c *Conn) txExecInterrupted(sql string) error {
func (c *Conn) txnExecInterrupted(sql string) error {
err := c.Exec(sql)
if errors.Is(err, INTERRUPT) {
old := c.SetInterrupt(context.Background())
@@ -275,7 +275,7 @@ func (c *Conn) UpdateHook(cb func(action AuthorizerActionCode, schema, table str
func commitCallback(ctx context.Context, mod api.Module, pDB uint32) uint32 {
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.handle == pDB && c.commit != nil {
if !c.commit() {
if ok := c.commit(); !ok {
return 1
}
}

View File

@@ -129,6 +129,9 @@ func Test_crash01(t *testing.T) {
if testing.Short() {
t.Skip("skipping in short mode")
}
if os.Getenv("CI") != "" {
t.Skip("skipping in CI")
}
ctx := util.NewContext(newContext(t))
name := filepath.Join(t.TempDir(), "test.db")
@@ -157,10 +160,8 @@ func Test_multiwrite01(t *testing.T) {
func Test_config01_memory(t *testing.T) {
ctx := util.NewContext(newContext(t))
cfg := config(ctx).WithArgs("mptest", "/test.db",
"config01.test",
"--vfs", "memdb",
"--timeout", "1000")
cfg := config(ctx).WithArgs("mptest", "/test.db", "config01.test",
"--vfs", "memdb")
mod, err := rt.InstantiateModule(ctx, module, cfg)
if err != nil {
t.Fatal(err)
@@ -174,10 +175,8 @@ func Test_multiwrite01_memory(t *testing.T) {
}
ctx := util.NewContext(newContext(t))
cfg := config(ctx).WithArgs("mptest", "/test.db",
"multiwrite01.test",
"--vfs", "memdb",
"--timeout", "1000")
cfg := config(ctx).WithArgs("mptest", "/test.db", "multiwrite01.test",
"--vfs", "memdb")
mod, err := rt.InstantiateModule(ctx, module, cfg)
if err != nil {
t.Fatal(err)

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bb763a5cc1c10683441f34ea64253eefc5b7b2d7208f9db6632c5b64da9a50a7
size 520353
oid sha256:1c012cb70dbded801b5241755f2e8c09f6baeda039056f5556b01a3de41e6a6b
size 520334

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a2d0b8b5d044cd993ccec28f3c491d862971d0e2e6ac78d6aa757d252ab63a4b
size 534561
oid sha256:ed1b7711b1246218aaa967ecdc8bf655708b90752ea6b3dd12a5ee307c032416
size 534713

23
vtab.go
View File

@@ -22,7 +22,7 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor
VTAB_RENAMER = 0x08
VTAB_OVERLOADER = 0x10
VTAB_CHECKER = 0x20
VTAB_TX = 0x40
VTAB_TXN = 0x40
VTAB_SAVEPOINTER = 0x80
)
@@ -46,8 +46,8 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor
if implements[VTabChecker](vtab) {
flags |= VTAB_CHECKER
}
if implements[VTabTx](vtab) {
flags |= VTAB_TX
if implements[VTabTxn](vtab) {
flags |= VTAB_TXN
}
if implements[VTabSavepointer](vtab) {
flags |= VTAB_SAVEPOINTER
@@ -187,14 +187,14 @@ type VTabChecker interface {
Integrity(schema, table string, flags int) error
}
// A VTabTx allows a virtual table to implement
// A VTabTxn allows a virtual table to implement
// transactions with two-phase commit.
//
// Anything that is required as part of a commit that may fail
// should be performed in the Sync() callback.
// Current versions of SQLite ignore any errors
// returned by Commit() and Rollback().
type VTabTx interface {
type VTabTxn interface {
VTab
// https://sqlite.org/vtab.html#xBegin
Begin() error
@@ -206,12 +206,15 @@ type VTabTx interface {
Rollback() error
}
// Deprecated: renamed for consistency with [Conn.TxnState].
type VTabTx = VTabTxn
// A VTabSavepointer allows a virtual table to implement
// nested transactions.
//
// https://sqlite.org/vtab.html#xsavepoint
type VTabSavepointer interface {
VTabTx
VTabTxn
Savepoint(id int) error
Release(id int) error
RollbackTo(id int) error
@@ -516,25 +519,25 @@ func vtabIntegrityCallback(ctx context.Context, mod api.Module, pVTab, zSchema,
}
func vtabBeginCallback(ctx context.Context, mod api.Module, pVTab uint32) uint32 {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTx)
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 {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTx)
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 {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTx)
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 {
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTx)
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
err := vtab.Rollback()
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
}