diff --git a/embed/sqlite3.wasm b/embed/sqlite3.wasm index 70c9aff..dcef898 100755 Binary files a/embed/sqlite3.wasm and b/embed/sqlite3.wasm differ diff --git a/sqlite3/deserialize.patch b/sqlite3/deserialize.patch new file mode 100644 index 0000000..a384614 --- /dev/null +++ b/sqlite3/deserialize.patch @@ -0,0 +1,20 @@ +--- sqlite3.c.orig ++++ sqlite3.c +@@ -60425,7 +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 @@ + 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 + readOnly = (fout&SQLITE_OPEN_READONLY)!=0; diff --git a/sqlite3/download.sh b/sqlite3/download.sh index 3000a6c..23ea00c 100755 --- a/sqlite3/download.sh +++ b/sqlite3/download.sh @@ -8,6 +8,9 @@ unzip -d . sqlite-amalgamation-*.zip mv sqlite-amalgamation-*/sqlite3* . rm -rf sqlite-amalgamation-* +patch < vfs_find.patch +patch < deserialize.patch + 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" diff --git a/sqlite3/sqlite_cfg.h b/sqlite3/sqlite_cfg.h index 4eac59f..e86e0e5 100644 --- a/sqlite3/sqlite_cfg.h +++ b/sqlite3/sqlite_cfg.h @@ -30,6 +30,9 @@ // Other Options #define SQLITE_ALLOW_URI_AUTHORITY +#define SQLITE_ENABLE_BATCH_ATOMIC_WRITE +#define SQLITE_ENABLE_ATOMIC_WRITE +#define SQLITE_OMIT_DESERIALIZE // Because WASM does not support shared memory, // SQLite disables WAL for WASM builds. @@ -55,16 +58,5 @@ // #define SQLITE_ENABLE_SESSION // #define SQLITE_ENABLE_PREUPDATE_HOOK -// https://stackoverflow.com/a/50616684 -#define SECOND(...) SECOND_I(__VA_ARGS__, , ) -#define SECOND_I(A, B, ...) B -#define GLUE(A, B) GLUE_I(A, B) -#define GLUE_I(A, B) A##_##B -#define CREATE_REPLACER(A) SECOND(GLUE(A, __LINE__), A) -#define REPLACE_AT_LINE(A) , A - // Implemented in vfs.c. -int localtime_s(struct tm *const pTm, time_t const *const pTime); - -#define sqlite3_vfs_find CREATE_REPLACER(sqlite3_vfs_find_wrapper) -#define sqlite3_vfs_find_wrapper_25397 REPLACE_AT_LINE(sqlite3_vfs_find) \ No newline at end of file +int localtime_s(struct tm *const pTm, time_t const *const pTime); \ No newline at end of file diff --git a/sqlite3/vfs.c b/sqlite3/vfs.c index 5043f7b..73b0a26 100644 --- a/sqlite3/vfs.c +++ b/sqlite3/vfs.c @@ -87,8 +87,7 @@ int localtime_s(struct tm *const pTm, time_t const *const pTime) { return go_localtime(pTm, (sqlite3_int64)*pTime); } -#undef sqlite3_vfs_find -sqlite3_vfs *sqlite3_vfs_find_wrapper(const char *zVfsName) { +sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName) { if (zVfsName) { static sqlite3_vfs *go_vfs_list; sqlite3_vfs *found = NULL; @@ -130,7 +129,7 @@ sqlite3_vfs *sqlite3_vfs_find_wrapper(const char *zVfsName) { return go_vfs_list; } } - return sqlite3_vfs_find(zVfsName); + return sqlite3_vfs_find_orig(zVfsName); } static_assert(offsetof(struct go_file, handle) == 4, "Unexpected offset"); diff --git a/sqlite3/vfs_find.patch b/sqlite3/vfs_find.patch new file mode 100644 index 0000000..8b4d318 --- /dev/null +++ b/sqlite3/vfs_find.patch @@ -0,0 +1,11 @@ +--- sqlite3.c.orig ++++ sqlite3.c +@@ -25394,7 +25394,7 @@ + ** Locate a VFS by name. If no name is given, simply return the + ** first VFS on the list. + */ +-SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){ ++SQLITE_API sqlite3_vfs *sqlite3_vfs_find_orig(const char *zVfs){ + sqlite3_vfs *pVfs = 0; + #if SQLITE_THREADSAFE + sqlite3_mutex *mutex; diff --git a/sqlite3vfs/example_test.go b/sqlite3vfs/example_test.go index 3c9efec..fb526a1 100644 --- a/sqlite3vfs/example_test.go +++ b/sqlite3vfs/example_test.go @@ -22,7 +22,7 @@ func ExampleMemoryVFS_embed() { "test.db": sqlite3vfs.NewMemoryDB(testDB), }) - db, err := sql.Open("sqlite3", "file:test.db?vfs=memory&_pragma=journal_mode(memory)") + db, err := sql.Open("sqlite3", "file:test.db?vfs=memory") if err != nil { log.Fatal(err) } diff --git a/sqlite3vfs/memory.go b/sqlite3vfs/memory.go index 3f7b745..9721921 100644 --- a/sqlite3vfs/memory.go +++ b/sqlite3vfs/memory.go @@ -21,7 +21,7 @@ func (vfs MemoryVFS) Open(name string, flags OpenFlag) (File, OpenFlag, error) { return &memoryFile{ MemoryDB: db, readOnly: flags&OPEN_READONLY != 0, - }, flags, nil + }, flags | OPEN_MEMORY, nil } return nil, flags, _CANTOPEN } @@ -45,8 +45,7 @@ const memSectorSize = 65536 // A MemoryDB is a [MemoryVFS] database. // -// A MemoryDB is safe to access concurrently from multiple SQLite connections. -// It requires journal mode MEMORY or OFF. +// A MemoryDB is safe to access concurrently through multiple SQLite connections. type MemoryDB struct { MaxSize int64 @@ -60,16 +59,16 @@ type MemoryDB struct { shared int } -// NewMemoryDB creates a new MemoryDB using buf as its initial contents. -// The new MemoryDB takes ownership of buf, and the caller should not use buf after this call. -func NewMemoryDB(buf []byte) *MemoryDB { +// NewMemoryDB creates a new MemoryDB using mem as its initial contents. +// The new MemoryDB takes ownership of mem, and the caller should not use mem after this call. +func NewMemoryDB(mem []byte) *MemoryDB { m := new(MemoryDB) - m.size = int64(len(buf)) + m.size = int64(len(mem)) sectors := divRoundUp(m.size, memSectorSize) m.data = make([]*[memSectorSize]byte, sectors) for i := range m.data { - sector := buf[i*memSectorSize:] + sector := mem[i*memSectorSize:] if len(sector) >= memSectorSize { m.data[i] = (*[memSectorSize]byte)(sector) } else { diff --git a/sqlite3vfs/tests/mptest/testdata/mptest.wasm b/sqlite3vfs/tests/mptest/testdata/mptest.wasm index 1185235..83ef723 100644 --- a/sqlite3vfs/tests/mptest/testdata/mptest.wasm +++ b/sqlite3vfs/tests/mptest/testdata/mptest.wasm @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aafb873c26d32dbf7498e4c4dd243eb6411c056432818121463d8cb49bc15f70 -size 1479293 +oid sha256:fab92aa470cc311d0cda364e21594ac57f25efce679920f65dd681f027ec9629 +size 1477051 diff --git a/sqlite3vfs/tests/speedtest1/testdata/speedtest1.wasm b/sqlite3vfs/tests/speedtest1/testdata/speedtest1.wasm index 29060df..55790ae 100644 --- a/sqlite3vfs/tests/speedtest1/testdata/speedtest1.wasm +++ b/sqlite3vfs/tests/speedtest1/testdata/speedtest1.wasm @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2638f5458f93b60f97006456f60e3e294cffb9ac22b20dba748fbd12e34f056d -size 1515841 +oid sha256:61adff257e8f6035c3fc7fd6371f4ac14c66ae5622202f6567244d18757375b2 +size 1513558 diff --git a/tests/db_test.go b/tests/db_test.go index f5bcb95..d51da16 100644 --- a/tests/db_test.go +++ b/tests/db_test.go @@ -24,7 +24,7 @@ func TestDB_VFS(t *testing.T) { "test.db": &sqlite3vfs.MemoryDB{}, }) defer sqlite3vfs.Unregister("memvfs") - testDB(t, "file:test.db?vfs=memvfs&_pragma=journal_mode(memory)") + testDB(t, "file:test.db?vfs=memvfs") } func testDB(t *testing.T, name string) { diff --git a/tests/vfs_test.go b/tests/vfs_test.go index ef45c80..2be7d7e 100644 --- a/tests/vfs_test.go +++ b/tests/vfs_test.go @@ -31,34 +31,13 @@ func TestMemoryVFS_Open_notfound(t *testing.T) { } } -func TestMemoryVFS_Open_journal(t *testing.T) { - sqlite3vfs.Register("memory", sqlite3vfs.MemoryVFS{ - "test.db": &sqlite3vfs.MemoryDB{}, - }) - defer sqlite3vfs.Unregister("memory") - - db, err := sqlite3.Open("file:test.db?vfs=memory") - if err != nil { - t.Fatal(err) - } - defer db.Close() - - err = db.Exec(`CREATE TABLE IF NOT EXISTS test (col)`) - if err == nil { - t.Error("want error") - } - if !errors.Is(err, sqlite3.CANTOPEN) { - t.Errorf("got %v, want sqlite3.CANTOPEN", err) - } -} - func TestMemoryVFS_Open_errors(t *testing.T) { sqlite3vfs.Register("memory", sqlite3vfs.MemoryVFS{ "test.db": &sqlite3vfs.MemoryDB{MaxSize: 65536}, }) defer sqlite3vfs.Unregister("memory") - db, err := sqlite3.Open("file:test.db?vfs=memory&_pragma=journal_mode(memory)") + db, err := sqlite3.Open("file:test.db?vfs=memory") if err != nil { t.Fatal(err) }