diff --git a/.github/workflows/repro.sh b/.github/workflows/repro.sh index fcf02d7..665364e 100755 --- a/.github/workflows/repro.sh +++ b/.github/workflows/repro.sh @@ -29,5 +29,10 @@ embed/build.sh util/vtabutil/parse/download.sh util/vtabutil/parse/build.sh +# Download and build the bedrock branch (bcw2 patches) +if [[ "$OSTYPE" == "linux"* ]]; then + embed/bcw2/build.sh +fi + # Check diffs git diff --exit-code \ No newline at end of file diff --git a/.github/workflows/repro.yml b/.github/workflows/repro.yml index b249d1c..7510d3f 100644 --- a/.github/workflows/repro.yml +++ b/.github/workflows/repro.yml @@ -28,4 +28,5 @@ jobs: with: subject-path: | embed/sqlite3.wasm + embed/bcw2/bcw2.wasm util/vtabutil/parse/sql3parse_table.wasm \ No newline at end of file diff --git a/embed/bcw2/bcw2.wasm b/embed/bcw2/bcw2.wasm new file mode 100755 index 0000000..914f1a1 Binary files /dev/null and b/embed/bcw2/bcw2.wasm differ diff --git a/embed/bcw2/bcw2_test.go b/embed/bcw2/bcw2_test.go new file mode 100644 index 0000000..1c77222 --- /dev/null +++ b/embed/bcw2/bcw2_test.go @@ -0,0 +1,40 @@ +package bcw2_test + +import ( + "path/filepath" + "testing" + + "github.com/ncruces/go-sqlite3/driver" + _ "github.com/ncruces/go-sqlite3/embed/bcw2" + "github.com/ncruces/go-sqlite3/vfs" +) + +func Test_bcw2(t *testing.T) { + if !vfs.SupportsSharedMemory { + t.Skip("skipping without shared memory") + } + + tmp := filepath.ToSlash(filepath.Join(t.TempDir(), "test.db")) + + db, err := driver.Open("file:" + tmp + "?_pragma=journal_mode(wal2)&_txlock=concurrent") + if err != nil { + t.Fatal(err) + } + defer db.Close() + + tx, err := db.Begin() + if err != nil { + t.Fatal(err) + } + defer tx.Rollback() + + _, err = tx.Exec(`CREATE TABLE test (col)`) + if err != nil { + t.Fatal(err) + } + + err = tx.Commit() + if err != nil { + t.Fatal(err) + } +} diff --git a/embed/bcw2/build.sh b/embed/bcw2/build.sh new file mode 100755 index 0000000..87de031 --- /dev/null +++ b/embed/bcw2/build.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd -P -- "$(dirname -- "$0")" + +ROOT=../../ +BINARYEN="$ROOT/tools/binaryen/bin" +WASI_SDK="$ROOT/tools/wasi-sdk/bin" + +trap 'rm -rf build sqlite bcw2.tmp' EXIT + +mkdir -p build/ext/ +cp "$ROOT"/sqlite3/*.[ch] build/ +cp "$ROOT"/sqlite3/*.patch build/ + +curl -# https://www.sqlite.org/src/tarball/sqlite.tar.gz?r=bedrock-3.46 | tar xz + +cd sqlite +sh configure +make sqlite3.c +cd ~- + +mv sqlite/sqlite3.c build/ +mv sqlite/sqlite3.h build/ +mv sqlite/sqlite3ext.h build/ +mv sqlite/ext/misc/anycollseq.c build/ext/ +mv sqlite/ext/misc/base64.c build/ext/ +mv sqlite/ext/misc/decimal.c build/ext/ +mv sqlite/ext/misc/ieee754.c build/ext/ +mv sqlite/ext/misc/regexp.c build/ext/ +mv sqlite/ext/misc/series.c build/ext/ +mv sqlite/ext/misc/uint.c build/ext/ + +cd build +cat *.patch | patch --no-backup-if-mismatch +cd ~- + +"$WASI_SDK/clang" --target=wasm32-wasi -std=c23 -g0 -O2 \ + -Wall -Wextra -Wno-unused-parameter -Wno-unused-function \ + -o bcw2.wasm "build/main.c" \ + -I"build" \ + -mexec-model=reactor \ + -matomics -msimd128 -mmutable-globals \ + -mbulk-memory -mreference-types \ + -mnontrapping-fptoint -msign-ext \ + -fno-stack-protector -fno-stack-clash-protection \ + -Wl,--stack-first \ + -Wl,--import-undefined \ + -Wl,--initial-memory=327680 \ + -D_HAVE_SQLITE_CONFIG_H \ + -DSQLITE_CUSTOM_INCLUDE=sqlite_opt.h \ + $(awk '{print "-Wl,--export="$0}' ../exports.txt) + +"$BINARYEN/wasm-ctor-eval" -g -c _initialize bcw2.wasm -o bcw2.tmp +"$BINARYEN/wasm-opt" -g --strip --strip-producers -c -O3 \ + bcw2.tmp -o bcw2.wasm \ + --enable-simd --enable-mutable-globals --enable-multivalue \ + --enable-bulk-memory --enable-reference-types \ + --enable-nontrapping-float-to-int --enable-sign-ext \ No newline at end of file diff --git a/embed/bcw2/init.go b/embed/bcw2/init.go new file mode 100644 index 0000000..4c674ec --- /dev/null +++ b/embed/bcw2/init.go @@ -0,0 +1,23 @@ +// Package bcw2 embeds SQLite into your application. +// +// Importing package bcw2 initializes the [sqlite3.Binary] variable +// with a build of SQLite that includes the [BEGIN CONCURRENT] and [Wal2] patches: +// +// import _ "github.com/ncruces/go-sqlite3/embed/bcw2" +// +// [BEGIN CONCURRENT]: https://sqlite.org/src/doc/begin-concurrent/doc/begin_concurrent.md +// [Wal2]: https://www.sqlite.org/cgi/src/doc/wal2/doc/wal2.md +package bcw2 + +import ( + _ "embed" + + "github.com/ncruces/go-sqlite3" +) + +//go:embed bcw2.wasm +var binary []byte + +func init() { + sqlite3.Binary = binary +} diff --git a/vfs/memdb/api.go b/vfs/memdb/api.go index 78fc351..8434889 100644 --- a/vfs/memdb/api.go +++ b/vfs/memdb/api.go @@ -42,8 +42,9 @@ func Create(name string, data []byte) { size: int64(len(data)), } - // Convert data from WAL to rollback journal. - if len(data) >= 20 && data[18] == 2 && data[19] == 2 { + // Convert data from WAL/2 to rollback journal. + if len(data) >= 20 && (data[18] == 2 && data[19] == 2 || + data[18] == 3 && data[19] == 3) { data[18] = 1 data[19] = 1 }