mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 22:19:14 +00:00
Compare commits
3 Commits
gormlite/v
...
gormlite/v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce4386604d | ||
|
|
26b62c520d | ||
|
|
738714bf32 |
11
README.md
11
README.md
@@ -31,16 +31,11 @@ This has benefits, but also comes with some drawbacks.
|
||||
Because WASM does not support shared memory,
|
||||
[WAL](https://www.sqlite.org/wal.html) support is [limited](https://www.sqlite.org/wal.html#noshm).
|
||||
|
||||
To work around this limitation, SQLite is compiled with
|
||||
[`SQLITE_DEFAULT_LOCKING_MODE=1`](https://www.sqlite.org/compile.html#default_locking_mode),
|
||||
making `EXCLUSIVE` the default locking mode.
|
||||
For non-WAL databases, `NORMAL` locking mode can be activated with
|
||||
[`PRAGMA locking_mode=NORMAL`](https://www.sqlite.org/pragma.html#pragma_locking_mode).
|
||||
To work around this limitation, SQLite is [patched](sqlite3/locking_mode.patch)
|
||||
to always use `EXCLUSIVE` locking mode for WAL databases.
|
||||
|
||||
Because connection pooling is incompatible with `EXCLUSIVE` locking mode,
|
||||
the `database/sql` driver defaults to `NORMAL` locking mode.
|
||||
To open WAL databases, or use `EXCLUSIVE` locking mode,
|
||||
disable connection pooling by calling
|
||||
to open WAL databases you should disable connection pooling by calling
|
||||
[`db.SetMaxOpenConns(1)`](https://pkg.go.dev/database/sql#DB.SetMaxOpenConns).
|
||||
|
||||
#### POSIX Advisory Locks
|
||||
|
||||
6
conn.go
6
conn.go
@@ -39,7 +39,7 @@ func Open(filename string) (*Conn, error) {
|
||||
// If none of the required flags is used, a combination of [OPEN_READWRITE] and [OPEN_CREATE] is used.
|
||||
// If a URI filename is used, PRAGMA statements to execute can be specified using "_pragma":
|
||||
//
|
||||
// sqlite3.Open("file:demo.db?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)")
|
||||
// sqlite3.Open("file:demo.db?_pragma=busy_timeout(10000)")
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/open.html
|
||||
func OpenFlags(filename string, flags OpenFlag) (*Conn, error) {
|
||||
@@ -278,7 +278,7 @@ func (c *Conn) SetInterrupt(ctx context.Context) (old context.Context) {
|
||||
break
|
||||
|
||||
case <-ctx.Done(): // Done was closed.
|
||||
const isInterruptedOffset = 280
|
||||
const isInterruptedOffset = 288
|
||||
buf := util.View(c.mod, c.handle+isInterruptedOffset, 4)
|
||||
(*atomic.Uint32)(unsafe.Pointer(&buf[0])).Store(1)
|
||||
// Wait for the next call to SetInterrupt.
|
||||
@@ -295,7 +295,7 @@ func (c *Conn) checkInterrupt() bool {
|
||||
if c.interrupt == nil || c.interrupt.Err() == nil {
|
||||
return false
|
||||
}
|
||||
const isInterruptedOffset = 280
|
||||
const isInterruptedOffset = 288
|
||||
buf := util.View(c.mod, c.handle+isInterruptedOffset, 4)
|
||||
(*atomic.Uint32)(unsafe.Pointer(&buf[0])).Store(1)
|
||||
return true
|
||||
|
||||
@@ -14,10 +14,9 @@
|
||||
//
|
||||
// [PRAGMA] statements can be specified using "_pragma":
|
||||
//
|
||||
// sql.Open("sqlite3", "file:demo.db?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)")
|
||||
// sql.Open("sqlite3", "file:demo.db?_pragma=busy_timeout(10000)")
|
||||
//
|
||||
// If no PRAGMAs are specified, a busy timeout of 1 minute
|
||||
// and normal locking mode are used.
|
||||
// If no PRAGMAs are specified, a busy timeout of 1 minute is set.
|
||||
//
|
||||
// Order matters:
|
||||
// busy timeout and locking mode should be the first PRAGMAs set, in that order.
|
||||
@@ -54,8 +53,8 @@ func (sqlite) Open(name string) (_ driver.Conn, err error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pragmas bool
|
||||
c.txBegin = "BEGIN"
|
||||
var pragmas []string
|
||||
if strings.HasPrefix(name, "file:") {
|
||||
if _, after, ok := strings.Cut(name, "?"); ok {
|
||||
query, _ := url.ParseQuery(after)
|
||||
@@ -70,14 +69,11 @@ func (sqlite) Open(name string) (_ driver.Conn, err error) {
|
||||
return nil, fmt.Errorf("sqlite3: invalid _txlock: %s", s)
|
||||
}
|
||||
|
||||
pragmas = query["_pragma"]
|
||||
pragmas = len(query["_pragma"]) > 0
|
||||
}
|
||||
}
|
||||
if len(pragmas) == 0 {
|
||||
err := c.Conn.Exec(`
|
||||
PRAGMA busy_timeout=60000;
|
||||
PRAGMA locking_mode=normal;
|
||||
`)
|
||||
if !pragmas {
|
||||
err := c.Conn.Exec(`PRAGMA busy_timeout=60000`)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
|
||||
@@ -4,7 +4,7 @@ set -euo pipefail
|
||||
cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
ROOT=../
|
||||
BINARYEN="$ROOT/tools/binaryen-version_113/bin"
|
||||
BINARYEN="$ROOT/tools/binaryen-version_114/bin"
|
||||
WASI_SDK="$ROOT/tools/wasi-sdk-20.0/bin"
|
||||
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -flto -g0 -O2 \
|
||||
@@ -18,6 +18,7 @@ WASI_SDK="$ROOT/tools/wasi-sdk-20.0/bin"
|
||||
-Wl,--initial-memory=327680 \
|
||||
-Wl,--stack-first \
|
||||
-Wl,--import-undefined \
|
||||
-D_HAVE_SQLITE_CONFIG_H \
|
||||
$(awk '{print "-Wl,--export="$0}' exports.txt)
|
||||
|
||||
trap 'rm -f sqlite3.tmp' EXIT
|
||||
|
||||
@@ -46,4 +46,27 @@ sqlite3_uri_parameter
|
||||
sqlite3_uri_key
|
||||
sqlite3_changes64
|
||||
sqlite3_last_insert_rowid
|
||||
sqlite3_get_autocommit
|
||||
sqlite3_get_autocommit
|
||||
sqlite3_anycollseq_init
|
||||
sqlite3_create_go_collation
|
||||
sqlite3_create_go_function
|
||||
sqlite3_create_go_window_function
|
||||
sqlite3_create_go_aggregate_function
|
||||
sqlite3_aggregate_context
|
||||
sqlite3_user_data
|
||||
sqlite3_value_type
|
||||
sqlite3_value_int64
|
||||
sqlite3_value_double
|
||||
sqlite3_value_text
|
||||
sqlite3_value_blob
|
||||
sqlite3_value_bytes
|
||||
sqlite3_result_null
|
||||
sqlite3_result_int64
|
||||
sqlite3_result_double
|
||||
sqlite3_result_text64
|
||||
sqlite3_result_blob64
|
||||
sqlite3_result_zeroblob64
|
||||
sqlite3_result_error
|
||||
sqlite3_result_error_code
|
||||
sqlite3_result_error_nomem
|
||||
sqlite3_result_error_toobig
|
||||
Binary file not shown.
36
func.go
Normal file
36
func.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
func exportHostFunctions(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
|
||||
util.ExportFuncVI(env, "go_destroy", cbDestroy)
|
||||
util.ExportFuncIIIIII(env, "go_compare", cbCompare)
|
||||
util.ExportFuncVIII(env, "go_func", cbFunc)
|
||||
util.ExportFuncVIII(env, "go_step", cbStep)
|
||||
util.ExportFuncVI(env, "go_final", cbFinal)
|
||||
util.ExportFuncVI(env, "go_value", cbValue)
|
||||
util.ExportFuncVIII(env, "go_inverse", cbInverse)
|
||||
return env
|
||||
}
|
||||
|
||||
func cbDestroy(ctx context.Context, mod api.Module, pArg uint32) {}
|
||||
|
||||
func cbCompare(ctx context.Context, mod api.Module, pArg, nKey1, pKey1, nKey2, pKey2 uint32) uint32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func cbFunc(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {}
|
||||
|
||||
func cbStep(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {}
|
||||
|
||||
func cbFinal(ctx context.Context, mod api.Module, pCtx uint32) {}
|
||||
|
||||
func cbValue(ctx context.Context, mod api.Module, pCtx uint32) {}
|
||||
|
||||
func cbInverse(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {}
|
||||
@@ -21,6 +21,6 @@ Checkout [https://gorm.io](https://gorm.io) for details.
|
||||
Foreign-key constraint is disabled by default in SQLite. To activate it, use connection URL parameter:
|
||||
```go
|
||||
db, err := gorm.Open(gormlite.Open(
|
||||
"file:gorm.db?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)&_pragma=foreign_keys(1)"),
|
||||
"file:gorm.db?_pragma=busy_timeout(10000)&_pragma=foreign_keys(1)"),
|
||||
&gorm.Config{})
|
||||
```
|
||||
@@ -15,7 +15,7 @@ func (dialector Dialector) Translate(err error) error {
|
||||
return gorm.ErrDuplicatedKey
|
||||
case
|
||||
errors.Is(err, sqlite3.CONSTRAINT_FOREIGNKEY):
|
||||
return err // gorm.ErrForeignKeyViolated (gorm v1.25.2)
|
||||
return gorm.ErrForeignKeyViolated
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ module github.com/ncruces/go-sqlite3/gormlite
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/ncruces/go-sqlite3 v0.8.0
|
||||
gorm.io/gorm v1.25.1
|
||||
github.com/ncruces/go-sqlite3 v0.8.1
|
||||
gorm.io/gorm v1.25.2
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -2,13 +2,13 @@ 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.8.0 h1:9FsLTTPqHE/GyW42dGqe9KUXDt4QHRaKf67Lk7jvdIQ=
|
||||
github.com/ncruces/go-sqlite3 v0.8.0/go.mod h1:EhHe1qvG6Zc/8ffYMzre8n//rTRs1YNN5dUD1f1mEGc=
|
||||
github.com/ncruces/go-sqlite3 v0.8.1 h1:e1Y7uHu96xC4fWKsCVWprbTi8vAaQX9R+8kgkxOHWaY=
|
||||
github.com/ncruces/go-sqlite3 v0.8.1/go.mod h1:EhHe1qvG6Zc/8ffYMzre8n//rTRs1YNN5dUD1f1mEGc=
|
||||
github.com/ncruces/julianday v0.1.5 h1:hDJ9ejiMp3DHsoZ5KW4c1lwfMjbARS7u/gbYcd0FBZk=
|
||||
github.com/ncruces/julianday v0.1.5/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
|
||||
github.com/tetratelabs/wazero v1.2.1 h1:J4X2hrGzJvt+wqltuvcSjHQ7ujQxA9gb6PeMs4qlUWs=
|
||||
github.com/tetratelabs/wazero v1.2.1/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64=
|
||||
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||
gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
|
||||
gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||
|
||||
@@ -3,8 +3,8 @@ set -euo pipefail
|
||||
|
||||
cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
rm -rf gorm/ tests/
|
||||
git clone --filter=blob:none --branch=v1.25.1 https://github.com/go-gorm/gorm.git
|
||||
rm -rf gorm/ tests/ $TMPDIR/gorm.db
|
||||
git clone --filter=blob:none https://github.com/go-gorm/gorm.git
|
||||
mv gorm/tests tests
|
||||
rm -rf gorm/
|
||||
|
||||
@@ -14,5 +14,5 @@ cd tests
|
||||
go mod tidy && go work use . && go test
|
||||
|
||||
cd ..
|
||||
rm -rf tests/
|
||||
rm -rf tests/ $TMPDIR/gorm.db
|
||||
go work use -r .
|
||||
@@ -1,51 +1,30 @@
|
||||
diff --git a/tests/.gitignore b/tests/.gitignore
|
||||
index 08cb523..72e8ffc 100644
|
||||
--- a/tests/.gitignore
|
||||
+++ b/tests/.gitignore
|
||||
@@ -1 +1 @@
|
||||
-go.sum
|
||||
+*
|
||||
diff --git a/tests/go.mod b/tests/go.mod
|
||||
index f47d175..84b80c2 100644
|
||||
--- a/tests/go.mod
|
||||
+++ b/tests/go.mod
|
||||
@@ -7,13 +7,13 @@ require (
|
||||
@@ -7,12 +7,12 @@ require (
|
||||
github.com/jackc/pgx/v5 v5.3.1 // indirect
|
||||
github.com/jinzhu/now v1.1.5
|
||||
github.com/lib/pq v1.10.8
|
||||
- github.com/mattn/go-sqlite3 v1.14.16 // indirect
|
||||
+ github.com/ncruces/go-sqlite3 v0.7.2
|
||||
+ github.com/ncruces/go-sqlite3/gormlite v0.0.0
|
||||
golang.org/x/crypto v0.8.0 // indirect
|
||||
gorm.io/driver/mysql v1.5.0
|
||||
gorm.io/driver/postgres v1.5.0
|
||||
- gorm.io/driver/sqlite v1.5.0
|
||||
gorm.io/driver/sqlserver v1.4.3
|
||||
- gorm.io/gorm v1.25.0
|
||||
+ gorm.io/gorm v1.25.1
|
||||
gorm.io/driver/sqlserver v1.5.1
|
||||
- gorm.io/gorm v1.25.1
|
||||
+ gorm.io/gorm v1.25.2
|
||||
)
|
||||
|
||||
-replace gorm.io/gorm => ../
|
||||
+replace github.com/ncruces/go-sqlite3/gormlite => ../
|
||||
diff --git a/tests/scanner_valuer_test.go b/tests/scanner_valuer_test.go
|
||||
index 1412169..472434b 100644
|
||||
--- a/tests/scanner_valuer_test.go
|
||||
+++ b/tests/scanner_valuer_test.go
|
||||
@@ -170,10 +170,10 @@ func (data *EncryptedData) Scan(value interface{}) error {
|
||||
return errors.New("Too short")
|
||||
}
|
||||
|
||||
- *data = b[3:]
|
||||
+ *data = append((*data)[0:], b[3:]...)
|
||||
return nil
|
||||
} else if s, ok := value.(string); ok {
|
||||
- *data = []byte(s)[3:]
|
||||
+ *data = []byte(s[3:])
|
||||
return nil
|
||||
}
|
||||
|
||||
diff --git a/tests/tests_test.go b/tests/tests_test.go
|
||||
index 90eb847..cd9af43 100644
|
||||
--- a/tests/tests_test.go
|
||||
+++ b/tests/tests_test.go
|
||||
@@ -7,9 +7,11 @@ import (
|
||||
|
||||
@@ -10,6 +10,32 @@ import (
|
||||
type i32 interface{ ~int32 | ~uint32 }
|
||||
type i64 interface{ ~int64 | ~uint64 }
|
||||
|
||||
type funcVI[T0 i32] func(context.Context, api.Module, T0)
|
||||
|
||||
func (fn funcVI[T0]) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
fn(ctx, mod, T0(stack[0]))
|
||||
}
|
||||
|
||||
func ExportFuncVI[T0 i32](mod wazero.HostModuleBuilder, name string, fn func(context.Context, api.Module, T0)) {
|
||||
mod.NewFunctionBuilder().
|
||||
WithGoModuleFunction(funcVI[T0](fn),
|
||||
[]api.ValueType{api.ValueTypeI32}, nil).
|
||||
Export(name)
|
||||
}
|
||||
|
||||
type funcVIII[T0, T1, T2 i32] func(context.Context, api.Module, T0, T1, T2)
|
||||
|
||||
func (fn funcVIII[T0, T1, T2]) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
fn(ctx, mod, T0(stack[0]), T1(stack[1]), T2(stack[2]))
|
||||
}
|
||||
|
||||
func ExportFuncVIII[T0, T1, T2 i32](mod wazero.HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2)) {
|
||||
mod.NewFunctionBuilder().
|
||||
WithGoModuleFunction(funcVIII[T0, T1, T2](fn),
|
||||
[]api.ValueType{api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32}, nil).
|
||||
Export(name)
|
||||
}
|
||||
|
||||
type funcII[TR, T0 i32] func(context.Context, api.Module, T0) TR
|
||||
|
||||
func (fn funcII[TR, T0]) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||
|
||||
@@ -53,7 +53,9 @@ func compileModule() {
|
||||
ctx := context.Background()
|
||||
sqlite3.runtime = wazero.NewRuntime(ctx)
|
||||
|
||||
env := vfs.ExportHostFunctions(sqlite3.runtime.NewHostModuleBuilder("env"))
|
||||
env := sqlite3.runtime.NewHostModuleBuilder("env")
|
||||
env = vfs.ExportHostFunctions(env)
|
||||
env = exportHostFunctions(env)
|
||||
_, sqlite3.err = env.Instantiate(ctx)
|
||||
if sqlite3.err != nil {
|
||||
return
|
||||
|
||||
1
sqlite3/.gitignore
vendored
1
sqlite3/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
ext/
|
||||
sqlite3.c
|
||||
sqlite3.h
|
||||
sqlite3ext.h
|
||||
@@ -8,9 +8,9 @@ unzip -d . sqlite-amalgamation-*.zip
|
||||
mv sqlite-amalgamation-*/sqlite3* .
|
||||
rm -rf sqlite-amalgamation-*
|
||||
|
||||
patch < vfs_find.patch
|
||||
patch < deserialize.patch
|
||||
cat *.patch | patch
|
||||
|
||||
mkdir -p ext/
|
||||
cd ext/
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/decimal.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/uint.c"
|
||||
@@ -18,6 +18,7 @@ curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/uuid.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/base64.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/regexp.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/series.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/anycollseq.c"
|
||||
cd ~-
|
||||
|
||||
cd ../vfs/tests/mptest/testdata/
|
||||
|
||||
1
sqlite3/ext/.gitignore
vendored
1
sqlite3/ext/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
*.c
|
||||
36
sqlite3/func.c
Normal file
36
sqlite3/func.c
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
int go_compare(void *, int, const void *, int, const void *);
|
||||
void go_func(sqlite3_context *, int, sqlite3_value **);
|
||||
void go_step(sqlite3_context *, int, sqlite3_value **);
|
||||
void go_final(sqlite3_context *);
|
||||
void go_value(sqlite3_context *);
|
||||
void go_inverse(sqlite3_context *, int, sqlite3_value **);
|
||||
void go_destroy(void *);
|
||||
|
||||
int sqlite3_create_go_collation(sqlite3 *db, const char *zName, void *pApp) {
|
||||
return sqlite3_create_collation_v2(db, zName, SQLITE_UTF8, pApp, go_compare,
|
||||
go_destroy);
|
||||
}
|
||||
|
||||
int sqlite3_create_go_function(sqlite3 *db, const char *zName, int nArg,
|
||||
int flags, void *pApp) {
|
||||
return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8 | flags, pApp,
|
||||
go_func, NULL, NULL, go_destroy);
|
||||
}
|
||||
|
||||
int sqlite3_create_go_window_function(sqlite3 *db, const char *zName, int nArg,
|
||||
int flags, void *pApp) {
|
||||
return sqlite3_create_window_function(db, zName, nArg, SQLITE_UTF8 | flags,
|
||||
pApp, go_step, go_final, NULL, NULL,
|
||||
go_destroy);
|
||||
}
|
||||
|
||||
int sqlite3_create_go_aggregate_function(sqlite3 *db, const char *zName,
|
||||
int nArg, int flags, void *pApp) {
|
||||
return sqlite3_create_window_function(db, zName, nArg, SQLITE_UTF8 | flags,
|
||||
pApp, go_step, go_final, go_value,
|
||||
go_inverse, go_destroy);
|
||||
}
|
||||
14
sqlite3/locking_mode.patch
Normal file
14
sqlite3/locking_mode.patch
Normal file
@@ -0,0 +1,14 @@
|
||||
# Use exclusive locking mode for WAL databases with v1 VFSes.
|
||||
--- sqlite3.c.orig
|
||||
+++ sqlite3.c
|
||||
@@ -63210,7 +63210,9 @@
|
||||
SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
|
||||
const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
|
||||
if( pPager->noLock ) return 0;
|
||||
- return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
|
||||
+ if( pMethods->iVersion>=2 && pMethods->xShmMap ) return 1;
|
||||
+ pPager->exclusiveMode = 1;
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1,19 +1,19 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Configuration
|
||||
#include "sqlite_cfg.h"
|
||||
// Amalgamation
|
||||
#include "sqlite3.c"
|
||||
// VFS
|
||||
#include "vfs.c"
|
||||
// Extensions
|
||||
#include "ext/anycollseq.c"
|
||||
#include "ext/base64.c"
|
||||
#include "ext/decimal.c"
|
||||
#include "ext/regexp.c"
|
||||
#include "ext/series.c"
|
||||
#include "ext/uint.c"
|
||||
#include "ext/uuid.c"
|
||||
#include "func.c"
|
||||
#include "time.c"
|
||||
|
||||
__attribute__((constructor)) void init() {
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
# Allow the VFS to force memory journal mode
|
||||
# regardless of SQLITE_OMIT_DESERIALIZE.
|
||||
--- sqlite3.c.orig
|
||||
+++ sqlite3.c
|
||||
@@ -60425,7 +60425,7 @@
|
||||
@@ -60425,11 +60425,7 @@
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int tempFile = 0; /* True for temp files (incl. in-memory files) */
|
||||
int memDb = 0; /* True if this is an in-memory file */
|
||||
-#ifndef SQLITE_OMIT_DESERIALIZE
|
||||
+#if 1
|
||||
int memJM = 0; /* Memory journal mode */
|
||||
#else
|
||||
# define memJM 0
|
||||
@@ -60628,7 +60628,7 @@
|
||||
-#else
|
||||
-# define memJM 0
|
||||
-#endif
|
||||
int readOnly = 0; /* True if this is a read-only file */
|
||||
int journalFileSize; /* Bytes to allocate for each journal fd */
|
||||
char *zPathname = 0; /* Full path to database file */
|
||||
@@ -60628,9 +60624,7 @@
|
||||
int fout = 0; /* VFS flags returned by xOpen() */
|
||||
rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
|
||||
assert( !memDb );
|
||||
-#ifndef SQLITE_OMIT_DESERIALIZE
|
||||
+#if 1
|
||||
pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
|
||||
#endif
|
||||
-#endif
|
||||
readOnly = (fout&SQLITE_OPEN_READONLY)!=0;
|
||||
|
||||
/* If the file was successfully opened for read/write access,
|
||||
@@ -36,12 +36,9 @@
|
||||
|
||||
// Because WASM does not support shared memory,
|
||||
// SQLite disables WAL for WASM builds.
|
||||
// We set the default locking mode to EXCLUSIVE instead.
|
||||
// We patch SQLite to use exclusive locking mode instead.
|
||||
// https://www.sqlite.org/wal.html#noshm
|
||||
#undef SQLITE_OMIT_WAL
|
||||
#ifndef SQLITE_DEFAULT_LOCKING_MODE
|
||||
#define SQLITE_DEFAULT_LOCKING_MODE 1
|
||||
#endif
|
||||
|
||||
// Amalgamated Extensions
|
||||
|
||||
|
||||
@@ -134,4 +134,4 @@ sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName) {
|
||||
|
||||
static_assert(offsetof(struct go_file, handle) == 4, "Unexpected offset");
|
||||
static_assert(offsetof(sqlite3_vfs, zName) == 16, "Unexpected offset");
|
||||
static_assert(offsetof(sqlite3, u1.isInterrupted) == 280, "Unexpected offset");
|
||||
static_assert(offsetof(sqlite3, u1.isInterrupted) == 288, "Unexpected offset");
|
||||
@@ -1,3 +1,4 @@
|
||||
# Wrap sqlite3_vfs_find.
|
||||
--- sqlite3.c.orig
|
||||
+++ sqlite3.c
|
||||
@@ -25394,7 +25394,7 @@
|
||||
|
||||
@@ -43,7 +43,7 @@ func (t params) mustExec(sql string, args ...interface{}) sql.Result {
|
||||
func (sqliteDB) RunTest(t *testing.T, fn func(params)) {
|
||||
db, err := sql.Open("sqlite3", "file:"+
|
||||
filepath.Join(t.TempDir(), "foo.db")+
|
||||
"?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)&_pragma=synchronous(off)")
|
||||
"?_pragma=busy_timeout(10000)&_pragma=synchronous(off)")
|
||||
if err != nil {
|
||||
t.Fatalf("foo.db open fail: %v", err)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/ncruces/go-sqlite3"
|
||||
_ "github.com/ncruces/go-sqlite3/embed"
|
||||
_ "github.com/ncruces/go-sqlite3/vfs/memdb"
|
||||
)
|
||||
|
||||
//go:embed testdata/wal.db
|
||||
var waldb []byte
|
||||
|
||||
func TestDB_memory(t *testing.T) {
|
||||
t.Parallel()
|
||||
testDB(t, ":memory:")
|
||||
@@ -19,6 +25,16 @@ func TestDB_file(t *testing.T) {
|
||||
testDB(t, filepath.Join(t.TempDir(), "test.db"))
|
||||
}
|
||||
|
||||
func TestDB_wal(t *testing.T) {
|
||||
t.Parallel()
|
||||
wal := filepath.Join(t.TempDir(), "test.db")
|
||||
err := os.WriteFile(wal, waldb, 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testDB(t, wal)
|
||||
}
|
||||
|
||||
func TestDB_vfs(t *testing.T) {
|
||||
testDB(t, "file:test.db?vfs=memdb")
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ func TestParallel(t *testing.T) {
|
||||
name := "file:" +
|
||||
filepath.Join(t.TempDir(), "test.db") +
|
||||
"?_pragma=busy_timeout(10000)" +
|
||||
"&_pragma=locking_mode(normal)" +
|
||||
"&_pragma=journal_mode(truncate)" +
|
||||
"&_pragma=synchronous(off)"
|
||||
testParallel(t, name, iter)
|
||||
@@ -42,7 +41,6 @@ func TestMemory(t *testing.T) {
|
||||
|
||||
name := "file:/test.db?vfs=memdb" +
|
||||
"&_pragma=busy_timeout(10000)" +
|
||||
"&_pragma=locking_mode(normal)" +
|
||||
"&_pragma=journal_mode(memory)" +
|
||||
"&_pragma=synchronous(off)"
|
||||
testParallel(t, name, iter)
|
||||
@@ -59,7 +57,6 @@ func TestMultiProcess(t *testing.T) {
|
||||
|
||||
name := "file:" + file +
|
||||
"?_pragma=busy_timeout(10000)" +
|
||||
"&_pragma=locking_mode(normal)" +
|
||||
"&_pragma=journal_mode(truncate)" +
|
||||
"&_pragma=synchronous(off)"
|
||||
|
||||
@@ -93,7 +90,6 @@ func TestChildProcess(t *testing.T) {
|
||||
|
||||
name := "file:" + file +
|
||||
"?_pragma=busy_timeout(10000)" +
|
||||
"&_pragma=locking_mode(normal)" +
|
||||
"&_pragma=journal_mode(truncate)" +
|
||||
"&_pragma=synchronous(off)"
|
||||
|
||||
@@ -128,10 +124,7 @@ func testParallel(t *testing.T, name string, n int) {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
err = db.Exec(`
|
||||
PRAGMA busy_timeout=10000;
|
||||
PRAGMA locking_mode=normal;
|
||||
`)
|
||||
err = db.Exec(`PRAGMA busy_timeout=10000`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
BIN
tests/testdata/wal.db
vendored
Normal file
BIN
tests/testdata/wal.db
vendored
Normal file
Binary file not shown.
3
vfs/tests/mptest/testdata/build.sh
vendored
3
vfs/tests/mptest/testdata/build.sh
vendored
@@ -4,7 +4,7 @@ set -euo pipefail
|
||||
cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
ROOT=../../../../
|
||||
BINARYEN="$ROOT/tools/binaryen-version_113/bin"
|
||||
BINARYEN="$ROOT/tools/binaryen-version_114/bin"
|
||||
WASI_SDK="$ROOT/tools/wasi-sdk-20.0/bin"
|
||||
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -flto -g0 -O2 \
|
||||
@@ -16,6 +16,7 @@ WASI_SDK="$ROOT/tools/wasi-sdk-20.0/bin"
|
||||
-fno-stack-protector -fno-stack-clash-protection \
|
||||
-Wl,--stack-first \
|
||||
-Wl,--import-undefined \
|
||||
-D_HAVE_SQLITE_CONFIG_H \
|
||||
-DSQLITE_DEFAULT_SYNCHRONOUS=0 \
|
||||
-DSQLITE_DEFAULT_LOCKING_MODE=0 \
|
||||
-DHAVE_USLEEP -DSQLITE_NO_SYNC \
|
||||
|
||||
2
vfs/tests/mptest/testdata/main.c
vendored
2
vfs/tests/mptest/testdata/main.c
vendored
@@ -1,8 +1,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Configuration
|
||||
#include "sqlite_cfg.h"
|
||||
// Amalgamation
|
||||
#include "sqlite3.c"
|
||||
// VFS
|
||||
|
||||
4
vfs/tests/mptest/testdata/mptest.wasm
vendored
4
vfs/tests/mptest/testdata/mptest.wasm
vendored
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:26d10a9ba084caf25512803607466bb7224515f616af9e1eb3bf5d234898597e
|
||||
size 1417255
|
||||
oid sha256:d23b37d507077cdcbb616852185370a227278b599187dc134200ed274a7a3a02
|
||||
size 1441194
|
||||
|
||||
5
vfs/tests/speedtest1/testdata/build.sh
vendored
5
vfs/tests/speedtest1/testdata/build.sh
vendored
@@ -4,7 +4,7 @@ set -euo pipefail
|
||||
cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
ROOT=../../../../
|
||||
BINARYEN="$ROOT/tools/binaryen-version_113/bin"
|
||||
BINARYEN="$ROOT/tools/binaryen-version_114/bin"
|
||||
WASI_SDK="$ROOT/tools/wasi-sdk-20.0/bin"
|
||||
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -flto -g0 -O2 \
|
||||
@@ -15,7 +15,8 @@ WASI_SDK="$ROOT/tools/wasi-sdk-20.0/bin"
|
||||
-mnontrapping-fptoint -msign-ext \
|
||||
-fno-stack-protector -fno-stack-clash-protection \
|
||||
-Wl,--stack-first \
|
||||
-Wl,--import-undefined
|
||||
-Wl,--import-undefined \
|
||||
-D_HAVE_SQLITE_CONFIG_H
|
||||
|
||||
"$BINARYEN/wasm-opt" -g --strip -c -O3 \
|
||||
speedtest1.wasm -o speedtest1.tmp \
|
||||
|
||||
2
vfs/tests/speedtest1/testdata/main.c
vendored
2
vfs/tests/speedtest1/testdata/main.c
vendored
@@ -1,8 +1,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Configuration
|
||||
#include "sqlite_cfg.h"
|
||||
// Amalgamation
|
||||
#include "sqlite3.c"
|
||||
// VFS
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e7b58aeeecd691b546c1da531bfea0a67bb33e1c835f06a94d3bd8723ab275d2
|
||||
size 1457505
|
||||
oid sha256:83d67feda51cc974634e245ac2b072f9587c607c7ad97321f2de9dde2188e63a
|
||||
size 1481348
|
||||
|
||||
Reference in New Issue
Block a user