mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-19 00:49:13 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12034c4f0b | ||
|
|
b4e5d1a213 | ||
|
|
b06c7dda6c | ||
|
|
5e1909a20e | ||
|
|
77d74baca5 | ||
|
|
4142680d5a | ||
|
|
9f4fe6f27c | ||
|
|
7870ce0690 | ||
|
|
ec3226e16e | ||
|
|
4dd7bd0ff2 | ||
|
|
975feb2fd4 | ||
|
|
58f8c2d33e | ||
|
|
019660eed6 | ||
|
|
30c1bcdbe9 | ||
|
|
9b4002f5ac | ||
|
|
2a78d4bc2b | ||
|
|
c09623a903 |
7
.github/actions/vmactions/template.yml
vendored
7
.github/actions/vmactions/template.yml
vendored
@@ -1,11 +1,6 @@
|
||||
name: VM Actions matrix
|
||||
description: VM Actions matrix template
|
||||
|
||||
inputs:
|
||||
run:
|
||||
description: The CI command to run
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
@@ -13,4 +8,4 @@ runs:
|
||||
with:
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: ${{inputs.run}}
|
||||
run: . ./test.sh
|
||||
6
.github/workflows/repro.sh
vendored
6
.github/workflows/repro.sh
vendored
@@ -3,13 +3,13 @@ set -euo pipefail
|
||||
|
||||
if [[ "$OSTYPE" == "linux"* ]]; then
|
||||
WASI_SDK="https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz"
|
||||
BINARYEN="https://github.com/WebAssembly/binaryen/releases/download/version_121/binaryen-version_121-x86_64-linux.tar.gz"
|
||||
BINARYEN="https://github.com/WebAssembly/binaryen/releases/download/version_122/binaryen-version_122-x86_64-linux.tar.gz"
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
WASI_SDK="https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-arm64-macos.tar.gz"
|
||||
BINARYEN="https://github.com/WebAssembly/binaryen/releases/download/version_121/binaryen-version_121-arm64-macos.tar.gz"
|
||||
BINARYEN="https://github.com/WebAssembly/binaryen/releases/download/version_122/binaryen-version_122-arm64-macos.tar.gz"
|
||||
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then
|
||||
WASI_SDK="https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-windows.tar.gz"
|
||||
BINARYEN="https://github.com/WebAssembly/binaryen/releases/download/version_121/binaryen-version_121-x86_64-windows.tar.gz"
|
||||
BINARYEN="https://github.com/WebAssembly/binaryen/releases/download/version_122/binaryen-version_122-x86_64-windows.tar.gz"
|
||||
fi
|
||||
|
||||
# Download tools
|
||||
|
||||
12
.github/workflows/test.yml
vendored
12
.github/workflows/test.yml
vendored
@@ -7,12 +7,14 @@ on:
|
||||
- '**.go'
|
||||
- '**.mod'
|
||||
- '**.wasm'
|
||||
- '**.yml'
|
||||
pull_request:
|
||||
branches: [ 'main' ]
|
||||
paths:
|
||||
- '**.go'
|
||||
- '**.mod'
|
||||
- '**.wasm'
|
||||
- '**.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -70,7 +72,9 @@ jobs:
|
||||
if: matrix.os != 'windows-latest'
|
||||
|
||||
- name: Collect coverage
|
||||
run: go run github.com/dave/courtney@latest
|
||||
run: |
|
||||
go get -tool github.com/dave/courtney@v0.4.4
|
||||
go tool courtney
|
||||
if: |
|
||||
github.event_name == 'push' &&
|
||||
matrix.os == 'ubuntu-latest'
|
||||
@@ -158,10 +162,6 @@ jobs:
|
||||
|
||||
- name: Test
|
||||
uses: ./.github/actions/vmactions
|
||||
with:
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: . ./test.sh
|
||||
|
||||
test-wasip1:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -174,7 +174,7 @@ jobs:
|
||||
with: { go-version: stable }
|
||||
|
||||
- name: Set path
|
||||
run: echo "$(go env GOROOT)/misc/wasm" >> "$GITHUB_PATH"
|
||||
run: echo "$(go env GOROOT)/lib/wasm" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Test wasmtime
|
||||
env:
|
||||
|
||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -5,9 +5,6 @@
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Go workspace
|
||||
go.work*
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
@@ -16,4 +13,11 @@ go.work*
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
tools
|
||||
tools
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
go.work.sum
|
||||
|
||||
# env file
|
||||
.env
|
||||
@@ -45,7 +45,7 @@ func (c *Conn) Config(op DBConfig, arg ...bool) (bool, error) {
|
||||
|
||||
rc := res_t(c.call("sqlite3_db_config", stk_t(c.handle),
|
||||
stk_t(op), stk_t(argsPtr)))
|
||||
return util.Read32[uint32](c.mod, argsPtr) != 0, c.error(rc)
|
||||
return util.ReadBool(c.mod, argsPtr), c.error(rc)
|
||||
}
|
||||
|
||||
// ConfigLog sets up the error logging callback for the connection.
|
||||
@@ -116,7 +116,7 @@ func (c *Conn) FileControl(schema string, op FcntlOpcode, arg ...any) (any, erro
|
||||
rc = res_t(c.call("sqlite3_file_control",
|
||||
stk_t(c.handle), stk_t(schemaPtr),
|
||||
stk_t(op), stk_t(ptr)))
|
||||
ret = util.Read32[uint32](c.mod, ptr) != 0
|
||||
ret = util.ReadBool(c.mod, ptr)
|
||||
|
||||
case FCNTL_CHUNK_SIZE:
|
||||
util.Write32(c.mod, ptr, int32(arg[0].(int)))
|
||||
|
||||
6
conn.go
6
conn.go
@@ -492,9 +492,9 @@ func (c *Conn) TableColumnMetadata(schema, table, column string) (declType, coll
|
||||
if ptr := util.Read32[ptr_t](c.mod, collSeqPtr); ptr != 0 {
|
||||
collSeq = util.ReadString(c.mod, ptr, _MAX_NAME)
|
||||
}
|
||||
notNull = util.Read32[uint32](c.mod, notNullPtr) != 0
|
||||
autoInc = util.Read32[uint32](c.mod, autoIncPtr) != 0
|
||||
primaryKey = util.Read32[uint32](c.mod, primaryKeyPtr) != 0
|
||||
notNull = util.ReadBool(c.mod, notNullPtr)
|
||||
autoInc = util.ReadBool(c.mod, autoIncPtr)
|
||||
primaryKey = util.ReadBool(c.mod, primaryKeyPtr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
5
const.go
5
const.go
@@ -259,7 +259,10 @@ const (
|
||||
DBCONFIG_TRUSTED_SCHEMA DBConfig = 1017
|
||||
DBCONFIG_STMT_SCANSTATUS DBConfig = 1018
|
||||
DBCONFIG_REVERSE_SCANORDER DBConfig = 1019
|
||||
// DBCONFIG_MAX DBConfig = 1019
|
||||
DBCONFIG_ENABLE_ATTACH_CREATE DBConfig = 1020
|
||||
DBCONFIG_ENABLE_ATTACH_WRITE DBConfig = 1021
|
||||
DBCONFIG_ENABLE_COMMENTS DBConfig = 1022
|
||||
// DBCONFIG_MAX DBConfig = 1022
|
||||
)
|
||||
|
||||
// FcntlOpcode are the available opcodes for [Conn.FileControl].
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Embeddable Wasm build of SQLite
|
||||
|
||||
This folder includes an embeddable Wasm build of SQLite 3.49.0 for use with
|
||||
This folder includes an embeddable Wasm build of SQLite 3.49.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:
|
||||
|
||||
Binary file not shown.
@@ -53,7 +53,7 @@ func Test_bcw2(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if version != "3.49.0" {
|
||||
if version != "3.50.0" {
|
||||
t.Error(version)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ mkdir -p build/ext/
|
||||
cp "$ROOT"/sqlite3/*.[ch] build/
|
||||
cp "$ROOT"/sqlite3/*.patch build/
|
||||
|
||||
# https://sqlite.org/src/info/cc3ce784b0feea2f
|
||||
curl -# https://sqlite.org/src/tarball/sqlite.tar.gz?r=cc3ce784 | tar xz
|
||||
# https://sqlite.org/src/info/c09656c62155a6e8
|
||||
curl -# https://sqlite.org/src/tarball/sqlite.tar.gz?r=c09656c6 | tar xz
|
||||
|
||||
cd sqlite
|
||||
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
module github.com/ncruces/go-sqlite3/embed/bcw2
|
||||
|
||||
go 1.22
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.23.0
|
||||
toolchain go1.24.0
|
||||
|
||||
require github.com/ncruces/go-sqlite3 v0.22.0
|
||||
require github.com/ncruces/go-sqlite3 v0.23.1
|
||||
|
||||
require (
|
||||
github.com/ncruces/julianday v1.0.0 // indirect
|
||||
github.com/ncruces/sort v0.1.2 // indirect
|
||||
github.com/tetratelabs/wazero v1.8.2 // indirect
|
||||
github.com/ncruces/sort v0.1.5 // indirect
|
||||
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
github.com/ncruces/go-sqlite3 v0.22.0 h1:FkGSBhd0TY6e66k1LVhyEpA+RnG/8QkQNed5pjIk4cs=
|
||||
github.com/ncruces/go-sqlite3 v0.22.0/go.mod h1:ueXOZXYZS2OFQirCU3mHneDwJm5fGKHrtccYBeGEV7M=
|
||||
github.com/ncruces/go-sqlite3 v0.23.1 h1:zGAd76q+Tr18z/xKGatUlzBQdjR3J+rexfANUcjAgkY=
|
||||
github.com/ncruces/go-sqlite3 v0.23.1/go.mod h1:Xg3FyAZl25HcBSFmcbymdfoTqD7jRnBUmv1jSrbIjdE=
|
||||
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
|
||||
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
|
||||
github.com/ncruces/sort v0.1.2 h1:zKQ9CA4fpHPF6xsUhRTfi5EEryspuBpe/QA4VWQOV1U=
|
||||
github.com/ncruces/sort v0.1.2/go.mod h1:vEJUTBJtebIuCMmXD18GKo5GJGhsay+xZFOoBEIXFmE=
|
||||
github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4=
|
||||
github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
|
||||
github.com/ncruces/sort v0.1.5 h1:fiFWXXAqKI8QckPf/6hu/bGFwcEPrirIOFaJqWujs4k=
|
||||
github.com/ncruces/sort v0.1.5/go.mod h1:obJToO4rYr6VWP0Uw5FYymgYGt3Br4RXcs/JdKaXAPk=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
|
||||
@@ -19,7 +19,7 @@ func Test_init(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if version != "3.49.0" {
|
||||
if version != "3.49.1" {
|
||||
t.Error(version)
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -36,4 +36,13 @@ you can load into your database connections.
|
||||
- [`github.com/ncruces/go-sqlite3/ext/uuid`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/uuid)
|
||||
generates [UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier).
|
||||
- [`github.com/ncruces/go-sqlite3/ext/zorder`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/zorder)
|
||||
maps multidimensional data to one dimension.
|
||||
maps multidimensional data to one dimension.
|
||||
|
||||
### Pakages
|
||||
|
||||
These packages may also be useful to work with SQLite:
|
||||
|
||||
- [`github.com/ncruces/decimal`](https://pkg.go.dev/github.com/ncruces/decimal)
|
||||
decimal arithmetic.
|
||||
- [`github.com/ncruces/julianday`](https://pkg.go.dev/github.com/ncruces/julianday)
|
||||
Julian day math.
|
||||
@@ -8,17 +8,21 @@ import (
|
||||
"github.com/ncruces/go-sqlite3/vfs"
|
||||
)
|
||||
|
||||
const vfsName = "github.com/ncruces/go-sqlite3/ext/serdes.sliceVFS"
|
||||
|
||||
func init() {
|
||||
vfs.Register(vfsName, sliceVFS{})
|
||||
}
|
||||
|
||||
var fileToOpen = make(chan *sliceFile, 1)
|
||||
|
||||
// Serialize backs up a database into a byte slice.
|
||||
//
|
||||
// https://sqlite.org/c3ref/serialize.html
|
||||
func Serialize(db *sqlite3.Conn, schema string) ([]byte, error) {
|
||||
var file sliceFile
|
||||
fileToOpen <- &file
|
||||
err := db.Backup(schema, "file:db?vfs="+vfsName)
|
||||
err := db.Backup(schema, "file:serdes.db?vfs="+vfsName)
|
||||
return file.data, err
|
||||
}
|
||||
|
||||
@@ -38,21 +42,21 @@ func Serialize(db *sqlite3.Conn, schema string) ([]byte, error) {
|
||||
// ["reader"]: https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/readervfs
|
||||
func Deserialize(db *sqlite3.Conn, schema string, data []byte) error {
|
||||
fileToOpen <- &sliceFile{data}
|
||||
return db.Restore(schema, "file:db?vfs="+vfsName)
|
||||
return db.Restore(schema, "file:serdes.db?vfs="+vfsName)
|
||||
}
|
||||
|
||||
var fileToOpen = make(chan *sliceFile, 1)
|
||||
|
||||
const vfsName = "github.com/ncruces/go-sqlite3/ext/deserialize.sliceVFS"
|
||||
|
||||
type sliceVFS struct{}
|
||||
|
||||
func (sliceVFS) Open(name string, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, error) {
|
||||
if flags&vfs.OPEN_MAIN_DB == 0 {
|
||||
// notest // OPEN_MEMORY
|
||||
if flags&vfs.OPEN_MAIN_DB == 0 || name != "serdes.db" {
|
||||
return nil, flags, sqlite3.CANTOPEN
|
||||
}
|
||||
return <-fileToOpen, flags | vfs.OPEN_MEMORY, nil
|
||||
select {
|
||||
case file := <-fileToOpen:
|
||||
return file, flags | vfs.OPEN_MEMORY, nil
|
||||
default:
|
||||
return nil, flags, sqlite3.MISUSE
|
||||
}
|
||||
}
|
||||
|
||||
func (sliceVFS) Delete(name string, dirSync bool) error {
|
||||
@@ -61,7 +65,7 @@ func (sliceVFS) Delete(name string, dirSync bool) error {
|
||||
}
|
||||
|
||||
func (sliceVFS) Access(name string, flag vfs.AccessFlag) (bool, error) {
|
||||
return name == "db", nil
|
||||
return name == "serdes.db", nil
|
||||
}
|
||||
|
||||
func (sliceVFS) FullPathname(name string) (string, error) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package serdes_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -66,3 +67,21 @@ func httpGet() ([]byte, error) {
|
||||
defer res.Body.Close()
|
||||
return io.ReadAll(res.Body)
|
||||
}
|
||||
|
||||
func TestOpen_errors(t *testing.T) {
|
||||
_, err := sqlite3.Open("file:test.db?vfs=github.com/ncruces/go-sqlite3/ext/serdes.sliceVFS")
|
||||
if err == nil {
|
||||
t.Error("want error")
|
||||
}
|
||||
if !errors.Is(err, sqlite3.CANTOPEN) {
|
||||
t.Errorf("got %v, want sqlite3.CANTOPEN", err)
|
||||
}
|
||||
|
||||
_, err = sqlite3.Open("file:serdes.db?vfs=github.com/ncruces/go-sqlite3/ext/serdes.sliceVFS")
|
||||
if err == nil {
|
||||
t.Error("want error")
|
||||
}
|
||||
if !errors.Is(err, sqlite3.MISUSE) {
|
||||
t.Errorf("got %v, want sqlite3.MISUSE", err)
|
||||
}
|
||||
}
|
||||
|
||||
25
func.go
25
func.go
@@ -2,6 +2,7 @@ package sqlite3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
@@ -85,12 +86,18 @@ func (c *Conn) CreateWindowFunction(name string, nArg int, flag FunctionFlag, fn
|
||||
var funcPtr ptr_t
|
||||
defer c.arena.mark()()
|
||||
namePtr := c.arena.string(name)
|
||||
if fn != nil {
|
||||
funcPtr = util.AddHandle(c.ctx, fn)
|
||||
}
|
||||
call := "sqlite3_create_aggregate_function_go"
|
||||
if _, ok := fn().(WindowFunction); ok {
|
||||
call = "sqlite3_create_window_function_go"
|
||||
if fn != nil {
|
||||
agg := fn()
|
||||
if c, ok := agg.(io.Closer); ok {
|
||||
if err := c.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, ok := agg.(WindowFunction); ok {
|
||||
call = "sqlite3_create_window_function_go"
|
||||
}
|
||||
funcPtr = util.AddHandle(c.ctx, fn)
|
||||
}
|
||||
rc := res_t(c.call(call,
|
||||
stk_t(c.handle), stk_t(namePtr), stk_t(nArg),
|
||||
@@ -172,7 +179,13 @@ func finalCallback(ctx context.Context, mod api.Module, pCtx, pAgg, pApp ptr_t)
|
||||
db := ctx.Value(connKey{}).(*Conn)
|
||||
fn, handle := callbackAggregate(db, pAgg, pApp)
|
||||
fn.Value(Context{db, pCtx})
|
||||
if err := util.DelHandle(ctx, handle); err != nil {
|
||||
var err error
|
||||
if handle != 0 {
|
||||
err = util.DelHandle(ctx, handle)
|
||||
} else if c, ok := fn.(io.Closer); ok {
|
||||
err = c.Close()
|
||||
}
|
||||
if err != nil {
|
||||
Context{db, pCtx}.ResultError(err)
|
||||
return // notest
|
||||
}
|
||||
|
||||
11
go.mod
11
go.mod
@@ -1,13 +1,13 @@
|
||||
module github.com/ncruces/go-sqlite3
|
||||
|
||||
go 1.22
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.23.0
|
||||
toolchain go1.24.0
|
||||
|
||||
require (
|
||||
github.com/ncruces/julianday v1.0.0
|
||||
github.com/ncruces/sort v0.1.5
|
||||
github.com/tetratelabs/wazero v1.8.2
|
||||
github.com/tetratelabs/wazero v1.9.0
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/sys v0.30.0
|
||||
)
|
||||
@@ -21,4 +21,7 @@ require (
|
||||
lukechampine.com/adiantum v1.1.1 // vfs/adiantum
|
||||
)
|
||||
|
||||
retract v0.4.0 // tagged from the wrong branch
|
||||
retract (
|
||||
v0.23.2 // tagged from the wrong branch
|
||||
v0.4.0 // tagged from the wrong branch
|
||||
)
|
||||
|
||||
4
go.sum
4
go.sum
@@ -8,8 +8,8 @@ github.com/ncruces/sort v0.1.5 h1:fiFWXXAqKI8QckPf/6hu/bGFwcEPrirIOFaJqWujs4k=
|
||||
github.com/ncruces/sort v0.1.5/go.mod h1:obJToO4rYr6VWP0Uw5FYymgYGt3Br4RXcs/JdKaXAPk=
|
||||
github.com/psanford/httpreadat v0.1.0 h1:VleW1HS2zO7/4c7c7zNl33fO6oYACSagjJIyMIwZLUE=
|
||||
github.com/psanford/httpreadat v0.1.0/go.mod h1:Zg7P+TlBm3bYbyHTKv/EdtSJZn3qwbPwpfZ/I9GKCRE=
|
||||
github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4=
|
||||
github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
module github.com/ncruces/go-sqlite3/gormlite
|
||||
|
||||
go 1.22
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.23.0
|
||||
toolchain go1.24.0
|
||||
|
||||
require (
|
||||
github.com/ncruces/go-sqlite3 v0.22.0
|
||||
github.com/ncruces/go-sqlite3 v0.23.1
|
||||
gorm.io/gorm v1.25.12
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@ require (
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/ncruces/julianday v1.0.0 // indirect
|
||||
github.com/tetratelabs/wazero v1.8.2 // indirect
|
||||
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
)
|
||||
|
||||
@@ -2,12 +2,12 @@ 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.22.0 h1:FkGSBhd0TY6e66k1LVhyEpA+RnG/8QkQNed5pjIk4cs=
|
||||
github.com/ncruces/go-sqlite3 v0.22.0/go.mod h1:ueXOZXYZS2OFQirCU3mHneDwJm5fGKHrtccYBeGEV7M=
|
||||
github.com/ncruces/go-sqlite3 v0.23.1 h1:zGAd76q+Tr18z/xKGatUlzBQdjR3J+rexfANUcjAgkY=
|
||||
github.com/ncruces/go-sqlite3 v0.23.1/go.mod h1:Xg3FyAZl25HcBSFmcbymdfoTqD7jRnBUmv1jSrbIjdE=
|
||||
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.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4=
|
||||
github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
|
||||
@@ -7,18 +7,12 @@ import (
|
||||
"github.com/tetratelabs/wazero"
|
||||
|
||||
"github.com/ncruces/go-sqlite3"
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
)
|
||||
|
||||
// notest
|
||||
|
||||
func init() {
|
||||
if util.CompilerSupported() {
|
||||
sqlite3.RuntimeConfig = wazero.NewRuntimeConfigCompiler()
|
||||
} else {
|
||||
sqlite3.RuntimeConfig = wazero.NewRuntimeConfigInterpreter()
|
||||
}
|
||||
sqlite3.RuntimeConfig = sqlite3.RuntimeConfig.WithMemoryLimitPages(512)
|
||||
sqlite3.RuntimeConfig = wazero.NewRuntimeConfig().WithMemoryLimitPages(512)
|
||||
if os.Getenv("CI") != "" {
|
||||
path := filepath.Join(os.TempDir(), "wazero")
|
||||
if err := os.MkdirAll(path, 0777); err == nil {
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
func CompilerSupported() bool {
|
||||
switch runtime.GOOS {
|
||||
case "linux", "android",
|
||||
"windows", "darwin",
|
||||
"freebsd", "netbsd", "dragonfly",
|
||||
"solaris", "illumos":
|
||||
break
|
||||
default:
|
||||
return false
|
||||
}
|
||||
switch runtime.GOARCH {
|
||||
case "amd64":
|
||||
return cpu.X86.HasSSE41
|
||||
case "arm64":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -26,9 +26,6 @@ func View(mod api.Module, ptr Ptr_t, size int64) []byte {
|
||||
if ptr == 0 {
|
||||
panic(NilErr)
|
||||
}
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
if uint64(size) > math.MaxUint32 {
|
||||
panic(RangeErr)
|
||||
}
|
||||
@@ -110,6 +107,18 @@ func WriteFloat64(mod api.Module, ptr Ptr_t, v float64) {
|
||||
Write64(mod, ptr, math.Float64bits(v))
|
||||
}
|
||||
|
||||
func ReadBool(mod api.Module, ptr Ptr_t) bool {
|
||||
return Read32[int32](mod, ptr) != 0
|
||||
}
|
||||
|
||||
func WriteBool(mod api.Module, ptr Ptr_t, v bool) {
|
||||
var i int32
|
||||
if v {
|
||||
i = 1
|
||||
}
|
||||
Write32(mod, ptr, i)
|
||||
}
|
||||
|
||||
func ReadString(mod api.Module, ptr Ptr_t, maxlen int64) string {
|
||||
if ptr == 0 {
|
||||
panic(NilErr)
|
||||
|
||||
@@ -47,11 +47,7 @@ func compileSQLite() {
|
||||
ctx := context.Background()
|
||||
cfg := RuntimeConfig
|
||||
if cfg == nil {
|
||||
if util.CompilerSupported() {
|
||||
cfg = wazero.NewRuntimeConfigCompiler()
|
||||
} else {
|
||||
cfg = wazero.NewRuntimeConfigInterpreter()
|
||||
}
|
||||
cfg = wazero.NewRuntimeConfig()
|
||||
if bits.UintSize < 64 {
|
||||
cfg = cfg.WithMemoryLimitPages(512) // 32MB
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# handle, and interrupt, sqlite3_busy_timeout.
|
||||
--- sqlite3.c.orig
|
||||
+++ sqlite3.c
|
||||
@@ -183054,7 +183054,7 @@
|
||||
@@ -183355,7 +183355,7 @@
|
||||
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
||||
#endif
|
||||
if( ms>0 ){
|
||||
|
||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
||||
|
||||
cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
curl -#OL "https://sqlite.org/2025/sqlite-amalgamation-3490000.zip"
|
||||
curl -#OL "https://sqlite.org/2025/sqlite-amalgamation-3490100.zip"
|
||||
unzip -d . sqlite-amalgamation-*.zip
|
||||
mv sqlite-amalgamation-*/sqlite3.c .
|
||||
mv sqlite-amalgamation-*/sqlite3.h .
|
||||
@@ -19,30 +19,30 @@ rm -rf sqlite-amalgamation-*
|
||||
|
||||
mkdir -p ext/
|
||||
cd ext/
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/ext/misc/anycollseq.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/ext/misc/base64.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/ext/misc/decimal.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/ext/misc/ieee754.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/ext/misc/regexp.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/ext/misc/series.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/ext/misc/spellfix.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/ext/misc/uint.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/ext/misc/anycollseq.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/ext/misc/base64.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/ext/misc/decimal.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/ext/misc/ieee754.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/ext/misc/regexp.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/ext/misc/series.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/ext/misc/spellfix.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/ext/misc/uint.c"
|
||||
cd ~-
|
||||
|
||||
cd ../vfs/tests/mptest/testdata/
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/mptest/config01.test"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/mptest/config02.test"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/mptest/crash01.test"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/mptest/crash02.subtest"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/mptest/multiwrite01.test"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/mptest/config01.test"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/mptest/config02.test"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/mptest/crash01.test"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/mptest/crash02.subtest"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/mptest/multiwrite01.test"
|
||||
cd ~-
|
||||
|
||||
cd ../vfs/tests/mptest/wasm/
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/mptest/mptest.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/mptest/mptest.c"
|
||||
cd ~-
|
||||
|
||||
cd ../vfs/tests/speedtest1/wasm/
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.0/test/speedtest1.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.49.1/test/speedtest1.c"
|
||||
cd ~-
|
||||
|
||||
cat *.patch | patch -p0 --no-backup-if-mismatch
|
||||
@@ -1,7 +1,7 @@
|
||||
# Remove VFS registration. Go handles it.
|
||||
--- sqlite3.c.orig
|
||||
+++ sqlite3.c
|
||||
@@ -26623,7 +26623,7 @@
|
||||
@@ -26725,7 +26725,7 @@
|
||||
sqlite3_free(p);
|
||||
return sqlite3_os_init();
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
/*
|
||||
** The list of all registered VFS implementations.
|
||||
*/
|
||||
@@ -26720,7 +26720,7 @@
|
||||
@@ -26822,7 +26822,7 @@
|
||||
sqlite3_mutex_leave(mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -130,10 +130,6 @@ func Test_sqlite_newBytes(t *testing.T) {
|
||||
if ptr == 0 {
|
||||
t.Fatal("got nullptr, want a pointer")
|
||||
}
|
||||
|
||||
if got := util.View(sqlite.mod, ptr, 0); got != nil {
|
||||
t.Errorf("got %q, want nil", got)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_sqlite_newString(t *testing.T) {
|
||||
|
||||
11
vfs/cksm.go
11
vfs/cksm.go
@@ -47,11 +47,12 @@ type cksmFlags struct {
|
||||
|
||||
func (c cksmFile) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
n, err = c.File.ReadAt(p, off)
|
||||
p = p[:n]
|
||||
|
||||
// SQLite is reading the header of a database file.
|
||||
if c.isDB && off == 0 && len(p) >= 100 &&
|
||||
bytes.HasPrefix(p, []byte("SQLite format 3\000")) {
|
||||
c.init(p)
|
||||
c.init((*[100]byte)(p))
|
||||
}
|
||||
|
||||
// Verify checksums.
|
||||
@@ -69,7 +70,7 @@ func (c cksmFile) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
// SQLite is writing the first page of a database file.
|
||||
if c.isDB && off == 0 && len(p) >= 100 &&
|
||||
bytes.HasPrefix(p, []byte("SQLite format 3\000")) {
|
||||
c.init(p)
|
||||
c.init((*[100]byte)(p))
|
||||
}
|
||||
|
||||
// Compute checksums.
|
||||
@@ -122,12 +123,16 @@ func (c cksmFile) fileControl(ctx context.Context, mod api.Module, op _FcntlOpco
|
||||
return vfsFileControlImpl(ctx, mod, c.File, op, pArg)
|
||||
}
|
||||
|
||||
func (f *cksmFlags) init(header []byte) {
|
||||
func (f *cksmFlags) init(header *[100]byte) {
|
||||
f.pageSize = 256 * int(binary.LittleEndian.Uint16(header[16:18]))
|
||||
if r := header[20] == 8; r != f.computeCksm {
|
||||
f.computeCksm = r
|
||||
f.verifyCksm = r
|
||||
}
|
||||
if !sql3util.ValidPageSize(f.pageSize) {
|
||||
f.computeCksm = false
|
||||
f.verifyCksm = false
|
||||
}
|
||||
}
|
||||
|
||||
func cksmCompute(a []byte) (cksm [8]byte) {
|
||||
|
||||
@@ -31,6 +31,7 @@ const (
|
||||
_READONLY _ErrorCode = util.READONLY
|
||||
_IOERR _ErrorCode = util.IOERR
|
||||
_NOTFOUND _ErrorCode = util.NOTFOUND
|
||||
_FULL _ErrorCode = util.FULL
|
||||
_CANTOPEN _ErrorCode = util.CANTOPEN
|
||||
_IOERR_READ _ErrorCode = util.IOERR_READ
|
||||
_IOERR_SHORT_READ _ErrorCode = util.IOERR_SHORT_READ
|
||||
@@ -57,10 +58,12 @@ const (
|
||||
_IOERR_COMMIT_ATOMIC _ErrorCode = util.IOERR_COMMIT_ATOMIC
|
||||
_IOERR_ROLLBACK_ATOMIC _ErrorCode = util.IOERR_ROLLBACK_ATOMIC
|
||||
_IOERR_DATA _ErrorCode = util.IOERR_DATA
|
||||
_IOERR_CORRUPTFS _ErrorCode = util.IOERR_CORRUPTFS
|
||||
_BUSY_SNAPSHOT _ErrorCode = util.BUSY_SNAPSHOT
|
||||
_CANTOPEN_FULLPATH _ErrorCode = util.CANTOPEN_FULLPATH
|
||||
_CANTOPEN_ISDIR _ErrorCode = util.CANTOPEN_ISDIR
|
||||
_READONLY_CANTINIT _ErrorCode = util.READONLY_CANTINIT
|
||||
_READONLY_DIRECTORY _ErrorCode = util.READONLY_DIRECTORY
|
||||
_OK_SYMLINK _ErrorCode = util.OK_SYMLINK
|
||||
)
|
||||
|
||||
|
||||
23
vfs/file.go
23
vfs/file.go
@@ -88,10 +88,13 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error
|
||||
oflags |= os.O_RDWR
|
||||
}
|
||||
|
||||
isCreate := flags&(OPEN_CREATE) != 0
|
||||
isJournl := flags&(OPEN_MAIN_JOURNAL|OPEN_SUPER_JOURNAL|OPEN_WAL) != 0
|
||||
|
||||
var err error
|
||||
var f *os.File
|
||||
if name == nil {
|
||||
f, err = os.CreateTemp("", "*.db")
|
||||
f, err = os.CreateTemp(os.Getenv("SQLITE_TMPDIR"), "*.db")
|
||||
} else {
|
||||
f, err = osutil.OpenFile(name.String(), oflags, 0666)
|
||||
}
|
||||
@@ -102,6 +105,10 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error
|
||||
if errors.Is(err, syscall.EISDIR) {
|
||||
return nil, flags, _CANTOPEN_ISDIR
|
||||
}
|
||||
if isCreate && isJournl && errors.Is(err, fs.ErrPermission) &&
|
||||
osAccess(name.String(), ACCESS_EXISTS) != nil {
|
||||
return nil, flags, _READONLY_DIRECTORY
|
||||
}
|
||||
return nil, flags, err
|
||||
}
|
||||
|
||||
@@ -119,10 +126,8 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error
|
||||
File: f,
|
||||
psow: true,
|
||||
readOnly: flags&OPEN_READONLY != 0,
|
||||
syncDir: canSyncDirs &&
|
||||
flags&(OPEN_MAIN_JOURNAL|OPEN_SUPER_JOURNAL|OPEN_WAL) != 0 &&
|
||||
flags&(OPEN_CREATE) != 0,
|
||||
shm: NewSharedMemory(name.String()+"-shm", flags),
|
||||
syncDir: canSyncDirs && isCreate && isJournl,
|
||||
shm: NewSharedMemory(name.String()+"-shm", flags),
|
||||
}
|
||||
return &file, flags, nil
|
||||
}
|
||||
@@ -154,6 +159,14 @@ func (f *vfsFile) Close() error {
|
||||
return f.File.Close()
|
||||
}
|
||||
|
||||
func (f *vfsFile) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
return osReadAt(f.File, p, off)
|
||||
}
|
||||
|
||||
func (f *vfsFile) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
return osWriteAt(f.File, p, off)
|
||||
}
|
||||
|
||||
func (f *vfsFile) Sync(flags SyncFlag) error {
|
||||
dataonly := (flags & SYNC_DATAONLY) != 0
|
||||
fullsync := (flags & 0x0f) == SYNC_FULL
|
||||
|
||||
@@ -47,14 +47,14 @@ func Test_vfsLock(t *testing.T) {
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got != LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); got {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got != LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); got {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
|
||||
@@ -74,14 +74,14 @@ func Test_vfsLock(t *testing.T) {
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got != LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); got {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got != LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); got {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
|
||||
@@ -105,14 +105,14 @@ func Test_vfsLock(t *testing.T) {
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got == LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); !got {
|
||||
t.Log("file wasn't locked, locking is incompatible with SQLite")
|
||||
}
|
||||
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got == LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); !got {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
|
||||
@@ -132,14 +132,14 @@ func Test_vfsLock(t *testing.T) {
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got == LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); !got {
|
||||
t.Log("file wasn't locked, locking is incompatible with SQLite")
|
||||
}
|
||||
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got == LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); !got {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
rc = vfsFileControl(ctx, mod, pFile2, _FCNTL_LOCKSTATE, pOutput)
|
||||
@@ -159,14 +159,14 @@ func Test_vfsLock(t *testing.T) {
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got == LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); !got {
|
||||
t.Log("file wasn't locked, locking is incompatible with SQLite")
|
||||
}
|
||||
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got == LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); !got {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
rc = vfsFileControl(ctx, mod, pFile1, _FCNTL_LOCKSTATE, pOutput)
|
||||
@@ -186,14 +186,14 @@ func Test_vfsLock(t *testing.T) {
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got != LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); got {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
rc = vfsCheckReservedLock(ctx, mod, pFile2, pOutput)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[LockLevel](mod, pOutput); got != LOCK_NONE {
|
||||
if got := util.ReadBool(mod, pOutput); got {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
|
||||
|
||||
13
vfs/os_std_rw.go
Normal file
13
vfs/os_std_rw.go
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build !unix && (!windows || sqlite3_dotlk)
|
||||
|
||||
package vfs
|
||||
|
||||
import "os"
|
||||
|
||||
func osReadAt(file *os.File, p []byte, off int64) (int, error) {
|
||||
return file.ReadAt(p, off)
|
||||
}
|
||||
|
||||
func osWriteAt(file *os.File, p []byte, off int64) (int, error) {
|
||||
return file.WriteAt(p, off)
|
||||
}
|
||||
@@ -25,6 +25,28 @@ func osAccess(path string, flags AccessFlag) error {
|
||||
return unix.Access(path, access)
|
||||
}
|
||||
|
||||
func osReadAt(file *os.File, p []byte, off int64) (int, error) {
|
||||
n, err := file.ReadAt(p, off)
|
||||
if errno, ok := err.(unix.Errno); ok {
|
||||
switch errno {
|
||||
case
|
||||
unix.ERANGE,
|
||||
unix.EIO,
|
||||
unix.ENXIO:
|
||||
return n, _IOERR_CORRUPTFS
|
||||
}
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func osWriteAt(file *os.File, p []byte, off int64) (int, error) {
|
||||
n, err := file.WriteAt(p, off)
|
||||
if errno, ok := err.(unix.Errno); ok && errno == unix.ENOSPC {
|
||||
return n, _FULL
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func osSetMode(file *os.File, modeof string) error {
|
||||
fi, err := os.Stat(modeof)
|
||||
if err != nil {
|
||||
|
||||
@@ -9,6 +9,23 @@ import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func osReadAt(file *os.File, p []byte, off int64) (int, error) {
|
||||
return file.ReadAt(p, off)
|
||||
}
|
||||
|
||||
func osWriteAt(file *os.File, p []byte, off int64) (int, error) {
|
||||
n, err := file.WriteAt(p, off)
|
||||
if errno, ok := err.(windows.Errno); ok {
|
||||
switch errno {
|
||||
case
|
||||
windows.ERROR_HANDLE_DISK_FULL,
|
||||
windows.ERROR_DISK_FULL:
|
||||
return n, _FULL
|
||||
}
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func osGetSharedLock(file *os.File) _ErrorCode {
|
||||
// Acquire the PENDING lock temporarily before acquiring a new SHARED lock.
|
||||
rc := osReadLock(file, _PENDING_BYTE, 1, 0)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
51
vfs/vfs.go
51
vfs/vfs.go
@@ -58,13 +58,8 @@ func vfsFind(ctx context.Context, mod api.Module, zVfsName ptr_t) uint32 {
|
||||
}
|
||||
|
||||
func vfsLocaltime(ctx context.Context, mod api.Module, pTm ptr_t, t int64) _ErrorCode {
|
||||
tm := time.Unix(t, 0)
|
||||
var isdst int32
|
||||
if tm.IsDST() {
|
||||
isdst = 1
|
||||
}
|
||||
|
||||
const size = 32 / 8
|
||||
tm := time.Unix(t, 0)
|
||||
// https://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html
|
||||
util.Write32(mod, pTm+0*size, int32(tm.Second()))
|
||||
util.Write32(mod, pTm+1*size, int32(tm.Minute()))
|
||||
@@ -74,7 +69,7 @@ func vfsLocaltime(ctx context.Context, mod api.Module, pTm ptr_t, t int64) _Erro
|
||||
util.Write32(mod, pTm+5*size, int32(tm.Year()-1900))
|
||||
util.Write32(mod, pTm+6*size, int32(tm.Weekday()-time.Sunday))
|
||||
util.Write32(mod, pTm+7*size, int32(tm.YearDay()-1))
|
||||
util.Write32(mod, pTm+8*size, isdst)
|
||||
util.WriteBool(mod, pTm+8*size, tm.IsDST())
|
||||
return _OK
|
||||
}
|
||||
|
||||
@@ -123,11 +118,7 @@ func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, flags Acc
|
||||
path := util.ReadString(mod, zPath, _MAX_PATHNAME)
|
||||
|
||||
ok, err := vfs.Access(path, flags)
|
||||
var res int32
|
||||
if ok {
|
||||
res = 1
|
||||
}
|
||||
util.Write32(mod, pResOut, res)
|
||||
util.WriteBool(mod, pResOut, ok)
|
||||
return vfsErrorCode(err, _IOERR_ACCESS)
|
||||
}
|
||||
|
||||
@@ -151,9 +142,8 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile ptr_t, flag
|
||||
file.SetPowersafeOverwrite(b)
|
||||
}
|
||||
}
|
||||
if file, ok := file.(FileSharedMemory); ok &&
|
||||
pOutVFS != 0 && file.SharedMemory() != nil {
|
||||
util.Write32(mod, pOutVFS, int32(1))
|
||||
if file, ok := file.(FileSharedMemory); ok && pOutVFS != 0 {
|
||||
util.WriteBool(mod, pOutVFS, file.SharedMemory() != nil)
|
||||
}
|
||||
if pOutFlags != 0 {
|
||||
util.Write32(mod, pOutFlags, flags)
|
||||
@@ -225,12 +215,7 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel
|
||||
func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut ptr_t) _ErrorCode {
|
||||
file := vfsFileGet(ctx, mod, pFile).(File)
|
||||
locked, err := file.CheckReservedLock()
|
||||
|
||||
var res int32
|
||||
if locked {
|
||||
res = 1
|
||||
}
|
||||
util.Write32(mod, pResOut, res)
|
||||
util.WriteBool(mod, pResOut, locked)
|
||||
return vfsErrorCode(err, _IOERR_CHECKRESERVEDLOCK)
|
||||
}
|
||||
|
||||
@@ -254,24 +239,20 @@ func vfsFileControlImpl(ctx context.Context, mod api.Module, file File, op _Fcnt
|
||||
|
||||
case _FCNTL_PERSIST_WAL:
|
||||
if file, ok := file.(FilePersistWAL); ok {
|
||||
if i := util.Read32[int32](mod, pArg); i >= 0 {
|
||||
file.SetPersistWAL(i != 0)
|
||||
} else if file.PersistWAL() {
|
||||
util.Write32(mod, pArg, int32(1))
|
||||
if i := util.Read32[int32](mod, pArg); i < 0 {
|
||||
util.WriteBool(mod, pArg, file.PersistWAL())
|
||||
} else {
|
||||
util.Write32(mod, pArg, int32(0))
|
||||
file.SetPersistWAL(i != 0)
|
||||
}
|
||||
return _OK
|
||||
}
|
||||
|
||||
case _FCNTL_POWERSAFE_OVERWRITE:
|
||||
if file, ok := file.(FilePowersafeOverwrite); ok {
|
||||
if i := util.Read32[int32](mod, pArg); i >= 0 {
|
||||
file.SetPowersafeOverwrite(i != 0)
|
||||
} else if file.PowersafeOverwrite() {
|
||||
util.Write32(mod, pArg, int32(1))
|
||||
if i := util.Read32[int32](mod, pArg); i < 0 {
|
||||
util.WriteBool(mod, pArg, file.PowersafeOverwrite())
|
||||
} else {
|
||||
util.Write32(mod, pArg, int32(0))
|
||||
file.SetPowersafeOverwrite(i != 0)
|
||||
}
|
||||
return _OK
|
||||
}
|
||||
@@ -293,11 +274,7 @@ func vfsFileControlImpl(ctx context.Context, mod api.Module, file File, op _Fcnt
|
||||
case _FCNTL_HAS_MOVED:
|
||||
if file, ok := file.(FileHasMoved); ok {
|
||||
moved, err := file.HasMoved()
|
||||
var val uint32
|
||||
if moved {
|
||||
val = 1
|
||||
}
|
||||
util.Write32(mod, pArg, val)
|
||||
util.WriteBool(mod, pArg, moved)
|
||||
return vfsErrorCode(err, _IOERR_FSTAT)
|
||||
}
|
||||
|
||||
@@ -394,7 +371,7 @@ func vfsFileControlImpl(ctx context.Context, mod api.Module, file File, op _Fcnt
|
||||
case _FCNTL_LOCK_TIMEOUT:
|
||||
if file, ok := file.(FileSharedMemory); ok {
|
||||
if shm, ok := file.SharedMemory().(blockingSharedMemory); ok {
|
||||
shm.shmEnableBlocking(util.Read32[uint32](mod, pArg) != 0)
|
||||
shm.shmEnableBlocking(util.ReadBool(mod, pArg))
|
||||
return _OK
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ func Test_vfsAccess(t *testing.T) {
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[int32](mod, 4); got != 1 {
|
||||
if got := util.ReadBool(mod, 4); !got {
|
||||
t.Error("directory did not exist")
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ func Test_vfsAccess(t *testing.T) {
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[int32](mod, 4); got != 1 {
|
||||
if got := util.ReadBool(mod, 4); !got {
|
||||
t.Error("can't access directory")
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ func Test_vfsAccess(t *testing.T) {
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[int32](mod, 4); got != 1 {
|
||||
if got := util.ReadBool(mod, 4); !got {
|
||||
t.Error("can't access file")
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ func Test_vfsAccess(t *testing.T) {
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
if got := util.Read32[int32](mod, 4); got != 0 {
|
||||
if got := util.ReadBool(mod, 4); got {
|
||||
t.Error("can access file")
|
||||
}
|
||||
}
|
||||
|
||||
4
vtab.go
4
vtab.go
@@ -399,10 +399,10 @@ func (idx *IndexInfo) save() {
|
||||
util.Write32(mod, ptr+20, int32(idx.IdxNum))
|
||||
if idx.IdxStr != "" {
|
||||
util.Write32(mod, ptr+24, idx.c.newString(idx.IdxStr))
|
||||
util.Write32(mod, ptr+28, int32(1)) // needToFreeIdxStr
|
||||
util.WriteBool(mod, ptr+28, true) // needToFreeIdxStr
|
||||
}
|
||||
if idx.OrderByConsumed {
|
||||
util.Write32(mod, ptr+32, int32(1))
|
||||
util.WriteBool(mod, ptr+32, true)
|
||||
}
|
||||
util.WriteFloat64(mod, ptr+40, idx.EstimatedCost)
|
||||
util.Write64(mod, ptr+48, idx.EstimatedRows)
|
||||
|
||||
Reference in New Issue
Block a user