1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-14 00:22:38 +03:00

Merge trunk into wasi-patches branch to clean up the diff view.

FossilOrigin-Name: 95de6742d3d96d2b21eec57195dc7a2236d3f61640633ae1baa36bf142a3485b
This commit is contained in:
stephan
2022-11-21 16:03:19 +00:00
23 changed files with 903 additions and 450 deletions

View File

@@ -20,6 +20,14 @@
# above-listed o? target names.
#
# clean = clean up
#
# Required tools beyond those needed for the canonical builds:
#
# - Emscripten SDK: https://emscripten.org/docs/getting_started/downloads.html
# - The bash shell
# - GNU make, GNU sed, GNU awk, GNU grep (all in the $PATH)
# - wasm-strip for release builds: https://github.com/WebAssembly/wabt
# - InfoZip for 'dist' zip file
########################################################################
SHELL := $(shell which bash 2>/dev/null)
MAKEFILE := $(lastword $(MAKEFILE_LIST))
@@ -71,17 +79,19 @@ dir.jacc := jaccwabyt
dir.common := common
dir.fiddle := fiddle
dir.tool := $(dir.top)/tool
CLEAN_FILES += *~ $(dir.jacc)/*~ $(dir.api)/*~ $(dir.common)/*~ $(dir.fiddle)/*~
########################################################################
# dir.dout = output dir for deliverables.
#
# MAINTENANCE REMINDER: the output .js and .wasm files of emcc must be
# in _this_ dir, rather than a subdir, or else parts of the generated
# code get confused and cannot load property. Specifically, when X.js
# loads X.wasm, whether or not X.js uses the correct path for X.wasm
# depends on how it's loaded: an HTML script tag will resolve it
# intuitively, whereas a Worker's call to importScripts() will not.
# That's a fundamental incompatibility with how URL resolution in
# JS happens between those two contexts. See:
# MAINTENANCE REMINDER: the output .js and .wasm files of certain emcc
# buildables must be in _this_ dir, rather than a subdir, or else
# parts of the generated code get confused and cannot load
# property. Specifically, when X.js loads X.wasm, whether or not X.js
# uses the correct path for X.wasm depends on how it's loaded: an HTML
# script tag will resolve it intuitively, whereas a Worker's call to
# importScripts() will not. That's a fundamental incompatibility with
# how URL resolution in JS happens between those two contexts. See:
#
# https://zzz.buzz/2017/03/14/relative-uris-in-web-development/
#
@@ -104,11 +114,10 @@ ifeq (,$(wildcard $(dir.tmp)))
dir._tmp := $(shell mkdir -p $(dir.tmp))
endif
cflags.common := -I. -I.. -I$(dir.top)
CLEAN_FILES += *~ $(dir.jacc)/*~ $(dir.api)/*~ $(dir.common)/*~
emcc.WASM_BIGINT ?= 1
sqlite3.c := $(dir.top)/sqlite3.c
sqlite3.h := $(dir.top)/sqlite3.h
# Most SQLITE_OPT flags are set in sqlite3-wasm.c but we need them
# made explicit here for building speedtest1.c.
SQLITE_OPT = \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_RTREE \
@@ -130,43 +139,6 @@ SQLITE_OPT = \
'-DSQLITE_DEFAULT_UNIX_VFS="unix-none"' \
-DSQLITE_USE_URI=1 \
-DSQLITE_WASM_ENABLE_C_TESTS
# ^^^ most flags are set in sqlite3-wasm.c but we need them
# made explicit here for building speedtest1.c.
ifneq (,$(filter release,$(MAKECMDGOALS)))
emcc_opt ?= -Oz -flto
else
emcc_opt ?= -O0
# ^^^^ build times for -O levels higher than 0 are painful at
# dev-time.
endif
# When passing emcc_opt from the CLI, += and re-assignment have no
# effect, so emcc_opt+=-g3 doesn't work. So...
emcc_opt_full := $(emcc_opt) -g3
# ^^^ ALWAYS use -g3. See below for why.
#
# ^^^ -flto improves runtime speed at -O0 considerably but doubles
# build time.
#
# ^^^^ -O3, -Oz, -Os minify symbol names and there appears to be no
# way around that except to use -g3, but -g3 causes the binary file
# size to absolutely explode (approx. 5x larger). This minification
# utterly breaks the resulting module, making it unsable except as
# self-contained/self-referential-only code, as ALL of the exported
# symbols get minified names.
#
# However, we have an option for using -Oz or -Os:
#
# Build with (-Os -g3) or (-Oz -g3) then use wasm-strip, from the wabt
# tools package (https://github.com/WebAssembly/wabt), to strip the
# debugging symbols. That results in a small build with unmangled
# symbol names. -Oz gives ever-so-slightly better compression than
# -Os: not quite 1% in some completely unscientific tests. Runtime
# speed for the unit tests is all over the place either way so it's
# difficult to say whether -Os gives any speed benefit over -Oz.
#
# (Much later: -O2 consistently gives the best speeds.)
########################################################################
$(sqlite3.c) $(sqlite3.h):
$(MAKE) -C $(dir.top) sqlite3.c
@@ -186,13 +158,20 @@ else
$(info Development build. Use '$(MAKE) release' for a smaller release build.)
endif
# bin.version-info = binary to output various sqlite3 version info for
# embedding in the JS files and in building the distribution zip file.
# It must NOT be in $(dir.tmp) because we need it to survive the
# cleanup process for the dist build to work properly.
bin.version-info := $(dir.wasm)/version-info
# ^^^^ NOT in $(dir.tmp) because we need it to survive the cleanup
# process for the dist build to work properly.
$(bin.version-info): $(dir.wasm)/version-info.c $(sqlite3.h) $(MAKEFILE)
$(CC) -O0 -I$(dir.top) -o $@ $<
DISTCLEAN_FILES += $(bin.version-info)
# bin.stripcomments is used for stripping C/C++-style comments from JS
# files. The JS files contain large chunks of documentation which we
# don't need for all builds. That app's -k flag is of particular
# importance here, as it allows us to retain the opening comment
# blocks, which contain the license header and version info.
bin.stripccomments := $(dir.tool)/stripccomments
$(bin.stripccomments): $(bin.stripccomments).c $(MAKEFILE)
$(CC) -o $@ $<
@@ -200,7 +179,8 @@ DISTCLEAN_FILES += $(bin.stripccomments)
########################################################################
# Transform $(1) to $(2) via ./c-pp -f $(1) ...
# C-PP.FILTER: a $(call)able to transform $(1) to $(2) via ./c-pp -f
# $(1) ...
#
# Historical notes:
#
@@ -226,27 +206,78 @@ DISTCLEAN_FILES += $(bin.stripccomments)
bin.c-pp := ./c-pp
$(bin.c-pp): c-pp.c $(sqlite3.c) $(MAKEFILE)
$(CC) -O0 -o $@ c-pp.c $(sqlite3.c) '-DCMPP_DEFAULT_DELIM="//#"' -I$(dir.top)
define C-PP.JS
# $1 c-pp -D... flags
# $2 = c-pp -f X.js
# $3 = c-pp -o X.js
$(3): $(2) $$(MAKEFILE) $$(bin.c-pp)
$$(bin.c-pp) -f $(2) -o $$@ $(1)
CLEAN_FILES += $(3)
define C-PP.FILTER
# Create $2 from $1 using $(bin.c-pp)
# $1 = Input file: c-pp -f $(1).js
# $2 = Output file: c-pp -o $(2).js
# $3 = optional c-pp -D... flags
$(2): $(1) $$(MAKEFILE) $$(bin.c-pp)
$$(bin.c-pp) -f $(1) -o $$@ $(3)
CLEAN_FILES += $(2)
endef
c-pp.D.vanilla ?=
c-pp.D.esm ?= -Dsqlite3-es6-module-build
# /end CPP-of-JS bits
c-pp.D.esm ?= -Dtarget=es6-module
# /end C-PP.FILTER
########################################################################
# cflags.common = C compiler flags for all builds
cflags.common := -I. -I.. -I$(dir.top)
# emcc.WASM_BIGINT = 1 for BigInt (C int64) support, else 0. The API
# disables certain features if BigInt is not enabled and such builds
# _are not tested_ on any regular basis.
emcc.WASM_BIGINT ?= 1
# emcc_opt = optimization-related flags. These are primarily used by
# the various oX targets. build times for -O levels higher than 0 are
# painful at dev-time.
emcc_opt ?= -O0
# When passing emcc_opt from the CLI, += and re-assignment have no
# effect, so emcc_opt+=-g3 doesn't work. So...
emcc_opt_full := $(emcc_opt) -g3
# ^^^ ALWAYS use -g3. See below for why.
#
# ^^^ -flto improves runtime speed at -O0 considerably but doubles
# build time.
#
# ^^^^ -O3, -Oz, -Os minify symbol names and there appears to be no
# way around that except to use -g3, but -g3 causes the binary file
# size to absolutely explode (approx. 5x larger). This minification
# utterly breaks the resulting module, making it unsable except as
# self-contained/self-referential-only code, as ALL of the exported
# symbols get minified names.
#
# However, we have an option for using -Oz or -Os:
#
# Build with (-Os -g3) or (-Oz -g3) then use wasm-strip, from the wabt
# tools package (https://github.com/WebAssembly/wabt), to strip the
# debugging symbols. That results in a small build with unmangled
# symbol names. -Oz gives ever-so-slightly better compression than
# -Os: not quite 1% in some completely unscientific tests. Runtime
# speed for the unit tests is all over the place either way so it's
# difficult to say whether -Os gives any speed benefit over -Oz.
#
# Much practice has demonstrated that -O2 consistently gives the best
# runtime speeds, but not by a large enough factor to rule out use of
# -Oz when small deliverable size is a priority.
########################################################################
# EXPORTED_FUNCTIONS.* = files for use with Emscripten's
# -sEXPORTED_FUNCTION flag.
EXPORTED_FUNCTIONS.api.in := $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api)
EXPORTED_FUNCTIONS.api := $(dir.tmp)/EXPORTED_FUNCTIONS.api
$(EXPORTED_FUNCTIONS.api): $(EXPORTED_FUNCTIONS.api.in) $(MAKEFILE)
cat $(EXPORTED_FUNCTIONS.api.in) > $@
cp $(EXPORTED_FUNCTIONS.api.in) $@
# sqlite3-license-version.js = generated JS file with the license
# header and version info.
sqlite3-license-version.js := $(dir.tmp)/sqlite3-license-version.js
# sqlite3-license-version-header.js = JS file containing only the
# license header.
sqlite3-license-version-header.js := $(dir.api)/sqlite3-license-version-header.js
# sqlite3-api-build-version.js = generated JS file which populates the
# sqlite3.version object using $(bin.version-info).
sqlite3-api-build-version.js := $(dir.tmp)/sqlite3-api-build-version.js
# sqlite3-api.jses = the list of JS files which make up $(sqlite3-api.js), in
# the order they need to be assembled.
@@ -266,6 +297,8 @@ sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
SOAP.js := $(dir.api)/sqlite3-opfs-async-proxy.js
sqlite3-worker1.js := $(dir.api)/sqlite3-worker1.js
sqlite3-worker1-promiser.js := $(dir.api)/sqlite3-worker1-promiser.js
# COPY_XAPI = a $(call)able function to copy $1 to $(dir.dout), where
# $1 must be one of the "external" JS API files.
define COPY_XAPI
sqlite3-api.ext.jses += $$(dir.dout)/$$(notdir $(1))
$$(dir.dout)/$$(notdir $(1)): $(1) $$(MAKEFILE)
@@ -275,6 +308,9 @@ $(foreach X,$(SOAP.js) $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js),\
$(eval $(call COPY_XAPI,$(X))))
all: $(sqlite3-api.ext.jses)
# sqlite3-api.js.in = the generated sqlite3-api.js before it gets
# preprocessed. It contains all of $(sqlite3-api.jses) but none of the
# Emscripten-specific headers and footers.
sqlite3-api.js.in := $(dir.tmp)/sqlite3-api.c-pp.js
$(sqlite3-api.js.in): $(sqlite3-api.jses) $(MAKEFILE)
@echo "Making $@..."
@@ -293,15 +329,27 @@ $(sqlite3-api-build-version.js): $(bin.version-info) $(MAKEFILE)
echo ';'; \
echo '});'; \
} > $@
$(sqlite3-license-version.js): $(sqlite3.h) $(sqlite3-license-version-header.js) \
$(MAKEFILE)
@echo "Making $@..."; { \
cat $(sqlite3-license-version-header.js); \
echo '/*'; \
echo '** This code was built from sqlite3 version...'; \
echo "** "; \
awk -e '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' \
-e '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
echo '*/'; \
} > $@
########################################################################
# --post-js and --pre-js are emcc flags we use to append/prepend JS to
# the generated emscripten module file.
# the generated emscripten module file. The following rules generate
# various versions of those files for the vanilla and ESM builds.
pre-js.js.in := $(dir.api)/pre-js.js
pre-js.js.esm := $(dir.tmp)/pre-js.esm.js
pre-js.js.vanilla := $(dir.tmp)/pre-js.vanilla.js
$(eval $(call C-PP.JS,$(c-pp.D.vanilla),$(pre-js.js.in),$(pre-js.js.vanilla)))
$(eval $(call C-PP.JS,$(c-pp.D.esm),$(pre-js.js.in),$(pre-js.js.esm)))
$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.vanilla),$(c-pp.D.vanilla)))
$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.esm),$(c-pp.D.esm)))
post-js.js.in := $(dir.tmp)/post-js.js
post-js.js.vanilla := $(dir.tmp)/post-js.vanilla.js
post-js.js.esm := $(dir.tmp)/post-js.esm.js
@@ -316,17 +364,21 @@ $(post-js.js.in): $(post-jses.js) $(MAKEFILE)
cat $$i; \
echo "/* END FILE: $$i */"; \
done > $@
$(eval $(call C-PP.JS,$(c-pp.D.vanilla),$(post-js.js.in),$(post-js.js.vanilla)))
$(eval $(call C-PP.JS,$(c-pp.D.esm),$(post-js.js.in),$(post-js.js.esm)))
$(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.vanilla),$(c-pp.D.vanilla)))
$(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.esm),$(c-pp.D.esm)))
# extern-post-js* and extern-pre-js* are files for use with
# Emscripten's --extern-pre-js and --extern-post-js flags. These
# rules make different copies for the vanilla and ESM builds.
extern-post-js.js.in := $(dir.api)/extern-post-js.js
extern-post-js.js.vanilla := $(dir.tmp)/extern-post-js.vanilla.js
extern-post-js.js.esm := $(dir.tmp)/extern-post-js.esm.js
$(eval $(call C-PP.JS,$(c-pp.D.vanilla),$(extern-post-js.js.in),$(extern-post-js.js.vanilla)))
$(eval $(call C-PP.JS,$(c-pp.D.esm),$(extern-post-js.js.in),$(extern-post-js.js.esm)))
$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.vanilla),$(c-pp.D.vanilla)))
$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.esm),$(c-pp.D.esm)))
extern-pre-js.js := $(dir.api)/extern-pre-js.js
# Emscripten flags for --[extern-][pre|post]-js=...
# Emscripten flags for --[extern-][pre|post]-js=... for the
# various builds.
pre-post-common.flags := \
--extern-pre-js=$(sqlite3-license-version.js)
pre-post-common.flags.vanilla := \
@@ -338,26 +390,21 @@ pre-post-common.flags.esm := \
--post-js=$(post-js.js.esm) \
--extern-post-js=$(extern-post-js.js.esm)
# pre-post-jses.deps.* = a list of dependencies for the
# --[extern-][pre/post]-js files.
pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)
pre-post-jses.deps.vanilla := $(pre-post-jses.deps.common) \
$(post-js.js.vanilla) $(extern-post-js.js.vanilla)
pre-post-jses.deps.esm := $(pre-post-jses.deps.common) \
$(post-js.js.esm) $(extern-post-js.js.esm)
$(sqlite3-license-version.js): $(sqlite3.h) $(sqlite3-license-version-header.js) $(MAKEFILE)
@echo "Making $@..."; { \
cat $(sqlite3-license-version-header.js); \
echo '/*'; \
echo '** This code was built from sqlite3 version...'; \
echo "** "; \
awk -e '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' \
-e '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
echo '*/'; \
} > $@
########################################################################
# call-make-pre-js creates rules for pre-js-$(1).js. $1 = the base
# name of the JS file on whose behalf this pre-js is for. $2 is the
# build mode: one of (vanilla, esm).
# call-make-pre-js is a $(call)able which creates rules for
# pre-js-$(1).js. $1 = the base name of the JS file on whose behalf
# this pre-js is for. $2 is the build mode: one of (vanilla, esm).
# This sets up --[extern-][pre/post]-js flags in
# $(pre-post-$(1).flags.$(2)) and dependencies in
# $(pre-post-$(1).deps.$(2)).
define call-make-pre-js
pre-post-$(1).flags.$(2) ?=
$$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(2)) $$(MAKEFILE)
@@ -374,29 +421,30 @@ pre-post-$(1).flags.$(2) += \
$$(pre-post-common.flags.$(2)) \
--pre-js=$$(dir.tmp)/pre-js-$(1)-$(2).js
endef
#$(error $(call call-make-pre-js,sqlite3-wasmfs))
# /post-js and pre-js
########################################################################
########################################################################
# emcc flags for .c/.o/.wasm/.js.
emcc.flags :=
#emcc.flags += -v # _very_ loud but also informative about what it's doing
# -g3 is needed to keep -O2 and higher from creating broken JS via
# minification.
ifeq (1,$(emcc.verbose))
emcc.flags += -v
# -v is _very_ loud but also informative about what it's doing
endif
########################################################################
# emcc flags for .c/.o.
emcc.cflags :=
emcc.cflags += -std=c99 -fPIC
# -------------^^^^^^^^ we currently need c99 for WASM-specific sqlite3 APIs.
# -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c).
emcc.cflags += -I. -I$(dir.top)
########################################################################
# emcc flags specific to building the final .js/.wasm file...
# emcc flags specific to building .js/.wasm files...
emcc.jsflags := -fPIC
emcc.jsflags += --minify 0
emcc.jsflags += --no-entry
emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
emcc.jsflags += -sMODULARIZE
emcc.jsflags += -sSTRICT_JS
emcc.jsflags += -sDYNAMIC_EXECUTION=0
@@ -404,7 +452,9 @@ emcc.jsflags += -sNO_POLYFILL
emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api)
emcc.exportedRuntimeMethods := \
-sEXPORTED_RUNTIME_METHODS=FS,wasmMemory
# FS ==> stdio/POSIX I/O proxies
# FS ==> stdio/POSIX I/O proxies. Currently used explicitly only
# by the fiddle app, and it must never be exposed to client code
# via our APIs.
# wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
emcc.jsflags += $(emcc.exportedRuntimeMethods)
emcc.jsflags += -sUSE_CLOSURE_COMPILER=0
@@ -438,32 +488,44 @@ emcc.jsflags += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY))
emcc.jsflags += $(emcc.environment)
#emcc.jsflags += -sTOTAL_STACK=4194304
########################################################################
# $(sqlite3.js.init-func) is the name Emscripten assigns our exported
# module init/load function. This symbol name is hard-coded in
# $(extern-post-js.js) as well as in numerous docs.
#
# "sqlite3InitModule" is the symbol we document for client use, so
# that's the symbol name which must be exported, whether it comes from
# Emscripten or our own code in extern-post-js.js.
#
# That said... we can change $(sqlite3.js.init-func) as long as the
# name "sqlite3InitModule" is the one which gets exposed via the
# resulting JS files. That can be accomplished via
# extern-post-js.js. However... using a temporary symbol name here
# and then adding sqlite3InitModule() ourselves results in 2 global
# symbols: we cannot "delete" the Emscripten-defined
# $(sqlite3.js.init-func) because it's declared with "var".
sqlite3.js.init-func := sqlite3InitModule
# ^^^^ $(sqlite3.js.init-func) symbol name is hard-coded in
# $(extern-post-js.js) as well as in numerous docs. If changed, it
# needs to be globally modified in *.js and all related documentation.
emcc.jsflags += -sEXPORT_NAME=$(sqlite3.js.init-func)
emcc.jsflags += -sGLOBAL_BASE=4096 # HYPOTHETICALLY keep func table indexes from overlapping w/ heap addr.
#emcc.jsflags += -sSTRICT # fails due to missing __syscall_...()
#emcc.jsflags += -sALLOW_UNIMPLEMENTED_SYSCALLS
#emcc.jsflags += -sFILESYSTEM=0 # only for experimentation. sqlite3 needs the FS API
#emcc.jsflags += -sABORTING_MALLOC
#emcc.jsflags += -sABORTING_MALLOC # only for experimentation
emcc.jsflags += -sALLOW_TABLE_GROWTH
# -sALLOW_TABLE_GROWTH is required for installing new SQL UDFs
# ^^^^ -sALLOW_TABLE_GROWTH is required for installing new SQL UDFs
emcc.jsflags += -Wno-limited-postlink-optimizations
# ^^^^^ it likes to warn when we have "limited optimizations" via the -g3 flag.
#emcc.jsflags += -sSTANDALONE_WASM # causes OOM errors, not sure why
# https://lld.llvm.org/WebAssembly.html
emcc.jsflags += -sERROR_ON_UNDEFINED_SYMBOLS=0
# ^^^^ emcc likes to warn when we have "limited optimizations" via the
# -g3 flag.
# emcc.jsflags += -sSTANDALONE_WASM # causes OOM errors, not sure why.
# Re. undefined symbol handling, see: https://lld.llvm.org/WebAssembly.html
emcc.jsflags += -sERROR_ON_UNDEFINED_SYMBOLS=1
emcc.jsflags += -sLLD_REPORT_UNDEFINED
#emcc.jsflags += --allow-undefined
#emcc.jsflags += --import-undefined
#emcc.jsflags += --unresolved-symbols=import-dynamic --experimental-pic
#emcc.jsflags += --experimental-pic --unresolved-symbols=ingore-all --import-undefined
#emcc.jsflags += --unresolved-symbols=ignore-all
emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
########################################################################
# -sMEMORY64=1 fails to load, erroring with:
@@ -475,18 +537,21 @@ emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
# new Uint8Array(wasm.heap8u().buffer, ptr, n)
#
# because ptr is now a BigInt, so is invalid for passing to arguments
# which have strict must-be-a-Number requirements.
# which have strict must-be-a-Number requirements. That aspect will
# make any eventual port to 64-bit address space extremely painful, as
# such constructs are found all over the place in the source code.
########################################################################
########################################################################
# -sSINGLE_FILE:
# https://github.com/emscripten-core/emscripten/blob/main/src/settings.js#L1704
# -sSINGLE_FILE=1 would be really nice but we have to build with -g3
# https://github.com/emscripten-core/emscripten/blob/main/src/settings.js
#
# -sSINGLE_FILE=1 would be _really_ nice but we have to build with -g3
# for -O2 and higher to work (else minification breaks the code) and
# cannot wasm-strip the binary before it gets encoded into the JS
# file. The result is that the generated JS file is, because of the -g3
# debugging info, _huge_.
# file. The result is that the generated JS file is, because of the
# -g3 debugging info, _huge_.
########################################################################
sqlite3.js := $(dir.dout)/sqlite3.js
@@ -503,55 +568,69 @@ sqlite3-wasm.c := $(dir.api)/sqlite3-wasm.c
# instead of building a shared copy of sqlite3-wasm.o.
$(eval $(call call-make-pre-js,sqlite3,vanilla))
$(eval $(call call-make-pre-js,sqlite3,esm))
$(sqlite3.js):
$(sqlite3.js) $(sqlite3.mjs): $(MAKEFILE) $(sqlite3.wasm.obj) \
$(EXPORTED_FUNCTIONS.api)
$(sqlite3.js): $(pre-post-sqlite3.deps.vanilla)
$(sqlite3.mjs): $(pre-post-sqlite3.deps.esm)
# SQLITE3.xJS.RECIPE = Recipe body for $(sqlite3.js) and
# $(sqlite3.mjs). $1 = one of (vanilla, esm).
define SQLITE3.xJS.RECIPE
@echo "Building $@ ..."
$(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \
$(emcc.jsflags) \
$(pre-post-sqlite3.flags.$(1)) $(emcc.flags.sqlite3.$(1)) \
$(cflags.common) $(SQLITE_OPT) $(sqlite3-wasm.c)
if [ esm = $(1) ]; then \
sed -i -e '0,/^export default/{/^export default/d}' $@; \
fi # work around an Emscripten annoyance. See emcc.flags.esm
chmod -x $(sqlite3.wasm)
$(maybe-wasm-strip) $(sqlite3.wasm)
@ls -la $@ $(sqlite3.wasm)
endef
emcc.flags.sqlite3.vanilla :=
emcc.flags.sqlite3.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META
# Reminder: even if we use -sEXPORT_ES6=0, emcc _still_ adds:
########################################################################
# SQLITE3.xJS.RECIPE = the $(call)able recipe body for $(sqlite3.js)
# and $(sqlite3.mjs). $1 = one of (vanilla, esm).
#
# Reminder for ESM builds: even if we use -sEXPORT_ES6=0, emcc _still_
# adds:
#
# export default $(sqlite3.js.init-func);
#
# when building *.mjs, which is bad because we need to export an
# overwritten version of that function and cannot "export default"
# twice. Because of this, we have to sed $(sqlite3.mjs) to remove the
# first instance of /^export default/.
# _first_ instance (only) of /^export default/.
#
# Upstream RFE:
# https://github.com/emscripten-core/emscripten/issues/18237
########################################################################
define SQLITE3.xJS.RECIPE
@echo "Building $@ ..."
$(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \
$(emcc.jsflags) \
$(pre-post-sqlite3.flags.$(1)) $(emcc.flags.sqlite3.$(1)) \
$(cflags.common) $(SQLITE_OPT) $(sqlite3-wasm.c)
@if [ esm = $(1) ]; then \
echo "Fragile workaround for an Emscripten annoyance. See emcc.flags.sqlite3.esm."; \
sed -i -e '0,/^export default/{/^export default/d}' $@ || exit $$?; \
if ! grep -q '^export default' $@; then \
echo "Cannot find export default." 1>&2; \
exit 1; \
fi; \
fi
chmod -x $(sqlite3.wasm)
$(maybe-wasm-strip) $(sqlite3.wasm)
@ls -la $@ $(sqlite3.wasm)
endef
emcc.flags.sqlite3.vanilla :=
emcc.flags.sqlite3.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META
$(sqlite3.js):
$(call SQLITE3.xJS.RECIPE,vanilla)
$(sqlite3.mjs):
$(call SQLITE3.xJS.RECIPE,esm)
########################################################################
# We have to ensure that we do not build both $(sqlite3.js) and
# $(sqlite3.mjs) in parallel because both result in the creation of
# $(sqlite3.wasm). We have no(?) way to build just the .mjs file
# without also building the .wasm file. i.e. we're building
# $(sqlite3.wasm) twice, but that's apparently unavoidable (and
# harmless, just a waste of build time).
$(sqlite3.wasm): $(sqlite3.js)
$(sqlite3.mjs): $(sqlite3.js)
# We have to ensure that we do not build both $(sqlite3.js) and
# $(sqlite3.mjs) in parallel because both result in the build of
# $(sqlite3.wasm). We have no way to build just the .mjs file without
# also building the .wasm file. i.e. we're building $(sqlite3.wasm)
# twice, but that's unavoidable.
CLEAN_FILES += $(sqlite3.js) $(sqlite3.mjs) $(sqlite3.wasm)
all: $(sqlite3.mjs)
wasm: $(sqlite3.mjs)
# End main Emscripten-based module build
# End main $(sqlite3.js) build
########################################################################
########################################################################
# batch-runner.js...
# batch-runner.js is part of one of the test apps which reads in SQL
# dumps generated by $(speedtest1) and executes them.
dir.sql := sql
speedtest1 := ../../speedtest1
speedtest1.c := ../../test/speedtest1.c
@@ -573,29 +652,30 @@ batch: batch-runner.list
all: batch
# end batch-runner.js
########################################################################
# speedtest1.js...
# speedtest1-common.eflags = emcc flags used by multiple builds of speedtest1
# Wasmified speedtest1 is our primary benchmarking tool.
#
# speedtest1.eflags.common = emcc flags used by multiple builds of speedtest1
# speedtest1.eflags = emcc flags used by main build of speedtest1
speedtest1-common.eflags := $(emcc_opt_full)
speedtest1.eflags.common := $(emcc_opt_full)
speedtest1.eflags :=
speedtest1.eflags += -sENVIRONMENT=web
speedtest1.eflags += -sALLOW_MEMORY_GROWTH
speedtest1.eflags += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY))
speedtest1-common.eflags += -sINVOKE_RUN=0
speedtest1-common.eflags += --no-entry
#speedtest1-common.eflags += -flto
speedtest1-common.eflags += -sABORTING_MALLOC
speedtest1-common.eflags += -sSTRICT_JS
speedtest1-common.eflags += -sMODULARIZE
speedtest1-common.eflags += -Wno-limited-postlink-optimizations
speedtest1.eflags.common += -sINVOKE_RUN=0
speedtest1.eflags.common += --no-entry
#speedtest1.eflags.common += -flto
speedtest1.eflags.common += -sABORTING_MALLOC
speedtest1.eflags.common += -sSTRICT_JS
speedtest1.eflags.common += -sMODULARIZE
speedtest1.eflags.common += -Wno-limited-postlink-optimizations
EXPORTED_FUNCTIONS.speedtest1 := $(abspath $(dir.tmp)/EXPORTED_FUNCTIONS.speedtest1)
speedtest1-common.eflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.speedtest1)
speedtest1-common.eflags += $(emcc.exportedRuntimeMethods)
speedtest1-common.eflags += -sALLOW_TABLE_GROWTH
speedtest1-common.eflags += -sDYNAMIC_EXECUTION=0
speedtest1-common.eflags += --minify 0
speedtest1-common.eflags += -sEXPORT_NAME=$(sqlite3.js.init-func)
speedtest1-common.eflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
speedtest1.eflags.common += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.speedtest1)
speedtest1.eflags.common += $(emcc.exportedRuntimeMethods)
speedtest1.eflags.common += -sALLOW_TABLE_GROWTH
speedtest1.eflags.common += -sDYNAMIC_EXECUTION=0
speedtest1.eflags.common += --minify 0
speedtest1.eflags.common += -sEXPORT_NAME=$(sqlite3.js.init-func)
speedtest1.eflags.common += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
speedtest1.exit-runtime0 := -sEXIT_RUNTIME=0
speedtest1.exit-runtime1 := -sEXIT_RUNTIME=1
# Re -sEXIT_RUNTIME=1 vs 0: if it's 1 and speedtest1 crashes, we get
@@ -628,8 +708,8 @@ $(speedtest1.js): $(MAKEFILE) $(speedtest1.cses) \
$(EXPORTED_FUNCTIONS.speedtest1)
@echo "Building $@ ..."
$(emcc.bin) \
$(speedtest1.eflags) $(speedtest1-common.eflags) $(speedtest1.cflags) \
$(pre-post-speedtest1.flags.vanilla) \
$(speedtest1.eflags) $(speedtest1.eflags.common) \
$(speedtest1.cflags) $(pre-post-speedtest1.flags.vanilla) \
$(SQLITE_OPT) \
$(speedtest1.exit-runtime0) \
-o $@ $(speedtest1.cses) -lm
@@ -642,6 +722,29 @@ CLEAN_FILES += $(speedtest1.js) $(speedtest1.wasm)
# end speedtest1.js
########################################################################
########################################################################
# tester1 is the main unit and regression test application and needs
# to be able to run in 4 separate modes to cover the primary
# client-side use cases:
#
# 1) Load sqlite3 in the main UI thread of a conventional script.
# 2) Load sqlite3 in a conventional Worker thread.
# 3) Load sqlite3 as an ES6 module (ESM) in the main thread.
# 4) Load sqlite3 as an ESM worker. (Not all browsers support this.)
#
# To that end, we require two separate builds of tester1.js:
#
# tester1.js: cases 1 and 2
# tester1.mjs: cases 3 and 4
#
# To create those, we filter tester1.c-pp.js with $(bin.c-pp)...
$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.js))
$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.esm)))
$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1.html))
$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.esm)))
tester1: tester1.js tester1.mjs tester1.html tester1-esm.html
all: tester1
########################################################################
# Convenience rules to rebuild with various -Ox levels. Much
# experimentation shows -O2 to be the clear winner in terms of speed.
@@ -651,8 +754,8 @@ CLEAN_FILES += $(speedtest1.js) $(speedtest1.wasm)
.PHONY: o0 o1 o2 o3 os oz
o-xtra := -flto
# ^^^^ -flto can have a considerably performance boost at -O0 but
# doubles the build time and seems to have negligible effect on
# higher optimization levels.
# doubles the build time and seems to have negligible, if any, effect
# on higher optimization levels.
o0: clean
$(MAKE) -e "emcc_opt=-O0"
o1: clean
@@ -670,16 +773,21 @@ oz: clean
########################################################################
# Sub-makes...
# sqlite.org/fiddle application...
include fiddle.make
# Only add wasmfs if wasmfs.enable=1 or we're running (dist)clean
ifneq (,$(filter wasmfs,$(MAKECMDGOALS)))
wasmfs.enable ?= 1
else
wasmfs.enable ?= $(if $(filter %clean,$(MAKECMDGOALS)),1,0)
endif
ifeq (1,$(wasmfs.enable))
# wasmfs build disabled 2022-10-19 per /chat discussion.
# OPFS-over-wasmfs was initially a stopgap measure and a convenient
# point of comparison for the OPFS sqlite3_vfs's performance, but it
# currently doubles our deliverables and build maintenance burden for
# little, if any, benefit.
# little benefit.
#
########################################################################
# Some platforms do not support the WASMFS build. Raspberry Pi OS is one
@@ -699,15 +807,16 @@ endif
########################################################################
########################################################################
# Create deliverables:
ifneq (,$(filter dist,$(MAKECMDGOALS)))
# Create main client downloadable zip file:
ifneq (,$(filter dist snapshot,$(MAKECMDGOALS)))
include dist.make
endif
########################################################################
# Push files to public wasm-testing.sqlite.org server
wasm-testing.include = $(dir.dout) *.js *.html \
batch-runner.list $(dir.sql) $(dir.common) $(dir.fiddle) $(dir.jacc)
wasm-testing.include = *.js *.html batch-runner.list \
./tests \
$(dir.dout) $(dir.sql) $(dir.common) $(dir.fiddle) $(dir.jacc)
wasm-testing.exclude = sql/speedtest1.sql
wasm-testing.dir = /jail/sites/wasm-testing
wasm-testing.dest ?= wasm-testing:$(wasm-testing.dir)

View File

@@ -7,6 +7,7 @@ _sqlite3_bind_null
_sqlite3_bind_parameter_count
_sqlite3_bind_parameter_index
_sqlite3_bind_text
_sqlite3_busy_timeout
_sqlite3_changes
_sqlite3_changes64
_sqlite3_clear_bindings

View File

@@ -8,24 +8,25 @@
most of the associated JS code, runs outside of the
Emscripten-generated module init scope, in the current
global scope. */
//#if sqlite3-es6-module-build
//#if target=es6-module
const toExportForES6 =
//#endif
(function(){
/**
In order to hide the sqlite3InitModule()'s resulting Emscripten
module from downstream clients (and simplify our documentation by
being able to elide those details), we rewrite
sqlite3InitModule() to return the sqlite3 object.
In order to hide the sqlite3InitModule()'s resulting
Emscripten module from downstream clients (and simplify our
documentation by being able to elide those details), we hide that
function and expose a hand-written sqlite3InitModule() to return
the sqlite3 object (most of the time).
Unfortunately, we cannot modify the module-loader/exporter-based
impls which Emscripten installs at some point in the file above
this.
*/
const originalInit =
/*Maintenance reminde: DO NOT use `self.` here. It's correct
for non-ES6 Module cases but wrong for ES6 modules because those
resolve this symbol differently! */ sqlite3InitModule;
/* Maintenance reminder: DO NOT use `self.` here. It's correct
for non-ES6 Module cases but wrong for ES6 modules because those
resolve this symbol differently. */ sqlite3InitModule;
if(!originalInit){
throw new Error("Expecting self.sqlite3InitModule to be defined by the Emscripten build.");
}
@@ -58,6 +59,9 @@ const toExportForES6 =
li.pop();
initModuleState.sqlite3Dir = li.join('/') + '/';
}
if(initModuleState.sqlite3Dir){
initModuleState.sqlite3Dir = initModuleState.sqlite3Dir.replace(/[/]{2,}/g,'/');
}
self.sqlite3InitModule = (...args)=>{
//console.warn("Using replaced sqlite3InitModule()",self.location);
@@ -104,16 +108,15 @@ const toExportForES6 =
}
/* Replace the various module exports performed by the Emscripten
glue... */
if (typeof exports === 'object' && typeof module === 'object')
if (typeof exports === 'object' && typeof module === 'object'){
module.exports = sqlite3InitModule;
else if (typeof exports === 'object')
}else if (typeof exports === 'object'){
exports["sqlite3InitModule"] = sqlite3InitModule;
}
/* AMD modules get injected in a way we cannot override,
so we can't handle those here. */
//#if sqlite3-es6-module-build
return self.sqlite3InitModule;
//#endif
return self.sqlite3InitModule /* required for ESM */;
})();
//#if sqlite3-es6-module-build
//#if target=es6-module
export default toExportForES6;
//#endif

View File

@@ -29,7 +29,7 @@ sqlite3InitModuleState.debugModule('self.location =',self.location);
4) If none of the above apply, (prefix+path) is returned.
*/
Module['locateFile'] = function(path, prefix) {
//#if sqlite3-es6-module-build
//#if target=es6-module
return new URL(path, import.meta.url).href;
//#else
'use strict';

View File

@@ -92,7 +92,8 @@ const installOpfsVfs = function callee(options){
}
const urlParams = new URL(self.location.href).searchParams;
if(undefined===options.verbose){
options.verbose = urlParams.has('opfs-verbose') ? 3 : 2;
options.verbose = urlParams.has('opfs-verbose')
? (+urlParams.get('opfs-verbose') || 2) : 1;
}
if(undefined===options.sanityChecks){
options.sanityChecks = urlParams.has('opfs-sanity-check');
@@ -101,6 +102,8 @@ const installOpfsVfs = function callee(options){
options.proxyUri = callee.defaultProxyUri;
}
//console.warn("OPFS options =",options,self.location);
if('function' === typeof options.proxyUri){
options.proxyUri = options.proxyUri();
}
@@ -167,7 +170,7 @@ const installOpfsVfs = function callee(options){
return promiseReject_(err);
};
const W =
//#if sqlite3-es6-module-build
//#if target=es6-module
new Worker(new URL(options.proxyUri, import.meta.url));
//#else
new Worker(options.proxyUri);
@@ -340,6 +343,7 @@ const installOpfsVfs = function callee(options){
'SQLITE_LOCK_PENDING',
'SQLITE_LOCK_RESERVED',
'SQLITE_LOCK_SHARED',
'SQLITE_LOCKED',
'SQLITE_MISUSE',
'SQLITE_NOTFOUND',
'SQLITE_OPEN_CREATE',
@@ -1154,7 +1158,10 @@ const installOpfsVfs = function callee(options){
[
/* Truncate journal mode is faster than delete or wal for
this vfs, per speedtest1. */
"pragma journal_mode=truncate;"
"pragma journal_mode=truncate;",
/* Set a default busy-timeout handler to help OPFS dbs
deal with multi-tab/multi-worker contention. */
"pragma busy_timeout=2000;",
/*
This vfs benefits hugely from cache on moderate/large
speedtest1 --size 50 and --size 100 workloads. We currently
@@ -1162,7 +1169,7 @@ const installOpfsVfs = function callee(options){
sqlite3.wasm. If that policy changes, the cache can
be set here.
*/
//"pragma cache_size=-8388608;"
//"pragma cache_size=-16384;"
].join("")
);
}

View File

@@ -897,6 +897,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
the lines of sqlite3_prepare_v3(). The slightly problematic
part is the final argument (text destructor). */
],
["sqlite3_busy_timeout","int", "sqlite3*", "int"],
["sqlite3_close_v2", "int", "sqlite3*"],
["sqlite3_changes", "int", "sqlite3*"],
["sqlite3_clear_bindings","int", "sqlite3_stmt*"],

View File

@@ -53,7 +53,7 @@ const state = Object.create(null);
2 = warnings and errors
3 = debug, warnings, and errors
*/
state.verbose = 2;
state.verbose = 1;
const loggers = {
0:console.error.bind(console),
@@ -150,70 +150,6 @@ const getDirForFilename = async function f(absFilename, createDirs = false){
return [dh, filename];
};
/**
An error class specifically for use with getSyncHandle(), the goal
of which is to eventually be able to distinguish unambiguously
between locking-related failures and other types, noting that we
cannot currently do so because createSyncAccessHandle() does not
define its exceptions in the required level of detail.
*/
class GetSyncHandleError extends Error {
constructor(errorObject, ...msg){
super();
this.error = errorObject;
this.message = [
...msg, ': Original exception ['+errorObject.name+']:',
errorObject.message
].join(' ');
this.name = 'GetSyncHandleError';
}
};
/**
Returns the sync access handle associated with the given file
handle object (which must be a valid handle object, as created by
xOpen()), lazily opening it if needed.
In order to help alleviate cross-tab contention for a dabase,
if an exception is thrown while acquiring the handle, this routine
will wait briefly and try again, up to 3 times. If acquisition
still fails at that point it will give up and propagate the
exception.
*/
const getSyncHandle = async (fh)=>{
if(!fh.syncHandle){
const t = performance.now();
log("Acquiring sync handle for",fh.filenameAbs);
const maxTries = 4, msBase = 300;
let i = 1, ms = msBase;
for(; true; ms = msBase * ++i){
try {
//if(i<3) toss("Just testing getSyncHandle() wait-and-retry.");
//TODO? A config option which tells it to throw here
//randomly every now and then, for testing purposes.
fh.syncHandle = await fh.fileHandle.createSyncAccessHandle();
break;
}catch(e){
if(i === maxTries){
throw new GetSyncHandleError(
e, "Error getting sync handle.",maxTries,
"attempts failed.",fh.filenameAbs
);
}
warn("Error getting sync handle. Waiting",ms,
"ms and trying again.",fh.filenameAbs,e);
Atomics.wait(state.sabOPView, state.opIds.retry, 0, ms);
}
}
log("Got sync handle for",fh.filenameAbs,'in',performance.now() - t,'ms');
if(!fh.xLock){
__autoLocks.add(fh.fid);
log("Auto-locked",fh.fid,fh.filenameAbs);
}
}
return fh.syncHandle;
};
/**
If the given file-holding object has a sync handle attached to it,
that handle is remove and asynchronously closed. Though it may
@@ -253,6 +189,98 @@ const closeSyncHandleNoThrow = async (fh)=>{
}
};
/* Release all auto-locks. */
const closeAutoLocks = async ()=>{
if(__autoLocks.size){
/* Release all auto-locks. */
for(const fid of __autoLocks){
const fh = __openFiles[fid];
await closeSyncHandleNoThrow(fh);
log("Auto-unlocked",fid,fh.filenameAbs);
}
}
};
/**
An error class specifically for use with getSyncHandle(), the goal
of which is to eventually be able to distinguish unambiguously
between locking-related failures and other types, noting that we
cannot currently do so because createSyncAccessHandle() does not
define its exceptions in the required level of detail.
*/
class GetSyncHandleError extends Error {
constructor(errorObject, ...msg){
super();
this.error = errorObject;
this.message = [
...msg, ': Original exception ['+errorObject.name+']:',
errorObject.message
].join(' ');
this.name = 'GetSyncHandleError';
}
};
GetSyncHandleError.convertRc = (e,rc)=>{
if(0){
/* This approach makes the very wild assumption that such a
failure _is_ a locking error. In practice that appears to be
the most common error, by far, but we cannot unambiguously
distinguish that from other errors.
This approach is highly questionable.
*/
return (e instanceof GetSyncHandleError)
? state.sq3Codes.SQLITE_IOERR_LOCK
: rc;
}else{
return rc;
}
}
/**
Returns the sync access handle associated with the given file
handle object (which must be a valid handle object, as created by
xOpen()), lazily opening it if needed.
In order to help alleviate cross-tab contention for a dabase,
if an exception is thrown while acquiring the handle, this routine
will wait briefly and try again, up to 3 times. If acquisition
still fails at that point it will give up and propagate the
exception.
*/
const getSyncHandle = async (fh)=>{
if(!fh.syncHandle){
const t = performance.now();
log("Acquiring sync handle for",fh.filenameAbs);
const maxTries = 6, msBase = 300;
let i = 1, ms = msBase;
for(; true; ms = msBase * ++i){
try {
//if(i<3) toss("Just testing getSyncHandle() wait-and-retry.");
//TODO? A config option which tells it to throw here
//randomly every now and then, for testing purposes.
fh.syncHandle = await fh.fileHandle.createSyncAccessHandle();
break;
}catch(e){
if(i === maxTries){
throw new GetSyncHandleError(
e, "Error getting sync handle.",maxTries,
"attempts failed.",fh.filenameAbs
);
}
warn("Error getting sync handle. Waiting",ms,
"ms and trying again.",fh.filenameAbs,e);
await closeAutoLocks();
Atomics.wait(state.sabOPView, state.opIds.retry, 0, ms);
}
}
log("Got sync handle for",fh.filenameAbs,'in',performance.now() - t,'ms');
if(!fh.xLock){
__autoLocks.add(fh.fid);
log("Auto-locked",fh.fid,fh.filenameAbs);
}
}
return fh.syncHandle;
};
/**
Stores the given value at state.sabOPView[state.opIds.rc] and then
Atomics.notify()'s it.
@@ -446,12 +474,12 @@ const vfsAsyncImpls = {
wTimeStart('xFileSize');
try{
affirmLocked('xFileSize',fh);
rc = await (await getSyncHandle(fh)).getSize();
state.s11n.serialize(Number(rc));
const sz = await (await getSyncHandle(fh)).getSize();
state.s11n.serialize(Number(sz));
rc = 0;
}catch(e){
state.s11n.storeException(2,e);
rc = state.sq3Codes.SQLITE_IOERR;
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR);
}
wTimeEnd();
storeAndNotify('xFileSize', rc);
@@ -471,7 +499,7 @@ const vfsAsyncImpls = {
__autoLocks.delete(fid);
}catch(e){
state.s11n.storeException(1,e);
rc = state.sq3Codes.SQLITE_IOERR_LOCK;
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_LOCK);
fh.xLock = oldLockType;
}
wTimeEnd();
@@ -545,7 +573,7 @@ const vfsAsyncImpls = {
if(undefined===nRead) wTimeEnd();
error("xRead() failed",e,fh);
state.s11n.storeException(1,e);
rc = state.sq3Codes.SQLITE_IOERR_READ;
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_READ);
}
storeAndNotify('xRead',rc);
mTimeEnd();
@@ -579,7 +607,7 @@ const vfsAsyncImpls = {
}catch(e){
error("xTruncate():",e,fh);
state.s11n.storeException(2,e);
rc = state.sq3Codes.SQLITE_IOERR_TRUNCATE;
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_TRUNCATE);
}
wTimeEnd();
storeAndNotify('xTruncate',rc);
@@ -619,7 +647,7 @@ const vfsAsyncImpls = {
}catch(e){
error("xWrite():",e,fh);
state.s11n.storeException(1,e);
rc = state.sq3Codes.SQLITE_IOERR_WRITE;
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_WRITE);
}
wTimeEnd();
storeAndNotify('xWrite',rc);
@@ -746,22 +774,16 @@ const waitLoop = async function f(){
/**
waitTime is how long (ms) to wait for each Atomics.wait().
We need to wake up periodically to give the thread a chance
to do other things.
to do other things. If this is too high (e.g. 500ms) then
even two workers/tabs can easily run into locking errors.
*/
const waitTime = 500;
const waitTime = 150;
while(!flagAsyncShutdown){
try {
if('timed-out'===Atomics.wait(
state.sabOPView, state.opIds.whichOp, 0, waitTime
)){
if(__autoLocks.size){
/* Release all auto-locks. */
for(const fid of __autoLocks){
const fh = __openFiles[fid];
await closeSyncHandleNoThrow(fh);
log("Auto-unlocked",fid,fh.filenameAbs);
}
}
await closeAutoLocks();
continue;
}
const opId = Atomics.load(state.sabOPView, state.opIds.whichOp);
@@ -791,7 +813,7 @@ navigator.storage.getDirectory().then(function(d){
const opt = data.args;
state.littleEndian = opt.littleEndian;
state.asyncS11nExceptions = opt.asyncS11nExceptions;
state.verbose = opt.verbose ?? 2;
state.verbose = opt.verbose ?? 1;
state.fileBufferSize = opt.fileBufferSize;
state.sabS11nOffset = opt.sabS11nOffset;
state.sabS11nSize = opt.sabS11nSize;

View File

@@ -6,35 +6,38 @@
# 'make dist' rules for creating a distribution archive of the WASM/JS
# pieces, noting that we only build a dist of the built files, not the
# numerous pieces required to build them.
#
# Use 'make snapshot' to create "snapshot" releases. They use a
# distinctly different zip file and top directory name to distinguish
# them from release builds.
#######################################################################
MAKEFILE.dist := $(lastword $(MAKEFILE_LIST))
########################################################################
# Chicken/egg situation: we need $(bin.version-info) to get the version
# info for the archive name, but that binary may not yet be built, and
# won't be built until we expand the dependencies. We have to use a
# temporary name for the archive.
dist-name = sqlite-wasm-TEMP
#ifeq (0,1)
# $(info WARNING *******************************************************************)
# $(info ** Be sure to create the desired build configuration before creating the)
# $(info ** distribution archive. Use one of the following targets to do so:)
# $(info **)
# $(info ** o2: builds with -O2, resulting in the fastest builds)
# $(info ** oz: builds with -Oz, resulting in the smallest builds)
# $(info /WARNING *******************************************************************)
#endif
# Chicken/egg situation: we need $(bin.version-info) to get the
# version info for the archive name, but that binary may not yet be
# built, and won't be built until we expand the dependencies. Thus we
# have to use a temporary name for the archive until we can get
# that binary built.
ifeq (,$(filter snapshot,$(MAKECMDGOALS)))
dist-name-prefix := sqlite-wasm
else
dist-name-prefix := sqlite-wasm-snapshot-$(shell /usr/bin/date +%Y%m%d)
endif
dist-name := $(dist-name-prefix)-TEMP
########################################################################
# dist.build must be the name of a target which triggers the
# build of the files to be packed into the dist archive. The
# intention is that it be one of (o0, o1, o2, o3, os, oz), each of
# which uses like-named -Ox optimization level flags. The o2 target
# provides the best overall runtime speeds. The oz target provides
# slightly slower speeds (roughly 10%) with significantly smaller WASM
# file sizes. Note that -O2 (the o2 target) results in faster binaries
# than both -O3 and -Os (the o3 and os targets) in all tests run to
# date.
# dist.build must be the name of a target which triggers the build of
# the files to be packed into the dist archive. The intention is that
# it be one of (o0, o1, o2, o3, os, oz), each of which uses like-named
# -Ox optimization level flags. The o2 target provides the best
# overall runtime speeds. The oz target provides slightly slower
# speeds (roughly 10%) with significantly smaller WASM file
# sizes. Note that -O2 (the o2 target) results in faster binaries than
# both -O3 and -Os (the o3 and os targets) in all tests run to
# date. Our general policy is that we want the smallest binaries for
# dist zip files, so use the oz build unless there is a compelling
# reason not to.
dist.build ?= oz
dist-dir.top := $(dist-name)
@@ -42,7 +45,8 @@ dist-dir.jswasm := $(dist-dir.top)/$(notdir $(dir.dout))
dist-dir.common := $(dist-dir.top)/common
dist.top.extras := \
demo-123.html demo-123-worker.html demo-123.js \
tester1.html tester1-worker.html tester1-esm.html tester1.js \
tester1.html tester1-worker.html tester1-esm.html \
tester1.js tester1.mjs \
demo-jsstorage.html demo-jsstorage.js \
demo-worker1.html demo-worker1.js \
demo-worker1-promiser.html demo-worker1-promiser.js
@@ -51,7 +55,7 @@ dist.common.extras := \
$(wildcard $(dir.common)/*.css) \
$(dir.common)/SqliteTestUtil.js
.PHONY: dist
.PHONY: dist snapshot
########################################################################
# dist: create the end-user deliverable archive.
#
@@ -83,7 +87,7 @@ dist: \
@cp -p $(dist.common.extras) $(dist-dir.common)
@set -e; \
vnum=$$($(bin.version-info) --download-version); \
vdir=sqlite-wasm-$$vnum; \
vdir=$(dist-name-prefix)-$$vnum; \
arczip=$$vdir.zip; \
echo "Making $$arczip ..."; \
rm -fr $$arczip $$vdir; \
@@ -93,7 +97,7 @@ dist: \
ls -la $$arczip; \
set +e; \
unzip -lv $$arczip || echo "Missing unzip app? Not fatal."
snapshot: dist
# We need a separate `clean` rule to account for weirdness in
# a sub-make, where we get a copy of the $(dist-name) dir
# copied into the new $(dist-name) dir.

View File

@@ -56,9 +56,15 @@
utility code.</li>
<li><a href='tester1-worker.html'>tester1-worker</a>: same thing
but running in a Worker.</li>
<li><a href='tester1-esm.html'>tester1-esm</a>: same thing
but loaded in the main thread via an ES6 module. Note that
not all browsers permit loading modules in Worker threads.
<li><a href='tester1-esm.html'>tester1-esm</a>: same as
<code>tester1</code> but loads sqlite3 in the main thread via
an ES6 module.
</li>
<li><a href='tester1-worker.html?esm'>tester1-worker?esm</a>:
same as <code>tester1-esm</code> but loads a Worker Module which
then loads the sqlite3 API via an ES6 module. Note that
not all browsers permit loading modules in Worker
threads.
</li>
</ul>
</li>

View File

@@ -32,10 +32,6 @@
and testing is currently done against a dev-channel release
of Chrome (v107 as of 2022-09-26).
</li>
<li>Whether or not WASMFS/OPFS support is enabled on any given
page may depend on build-time options which are <em>off by
default</em>.
</li>
</ul>
</div>
<div>The tests and demos...
@@ -47,9 +43,16 @@
utility code.</li>
<li><a href='tester1-worker.html'>tester1-worker</a>: same thing
but running in a Worker.</li>
<li><a href='tester1-esm.html'>tester1-esm</a>: same thing
but loaded in the main thread via an ES6 module. Note that
not all browsers permit loading modules in Worker threads.
<li><a href='tester1-esm.html'>tester1-esm</a>: same as
<code>tester1</code> but loads sqlite3 in the main thread via
an ES6 module.
</li>
<li><a href='tester1-worker.html?esm'>tester1-worker?esm</a>:
same as <code>tester1-esm</code> but loads a Worker Module which
then loads the sqlite3 API via an ES6 module. Note that
not all browsers permit loading modules in Worker
threads.
</li>
</ul>
</li>
<li>High-level apps and demos...
@@ -101,6 +104,9 @@
synchronous sqlite3_vfs interface and the async OPFS
impl.
</li>
<li><a href='tests/opfs/concurrency/index.html'>OPFS concurrency</a>
tests using multiple workers.
</li>
</ul>
</li>
<!--li><a href='x.html'></a></li-->

View File

@@ -1,30 +0,0 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="common/emscripten.css"/>
<link rel="stylesheet" href="common/testing.css"/>
<title>sqlite3 tester ESM #1 (UI thread)</title>
<style>
body {
font-family: monospace;
}
</style>
</head>
<body>
<h1 id='color-target'>sqlite3 WASM/JS tester ESM #1 (UI thread)</h1>
<div class='input-wrapper'>
<input type='checkbox' id='cb-log-reverse'>
<label for='cb-log-reverse'>Reverse log order?</label>
</div>
<div id='test-output'></div>
<script type="module" defer>
import {default as sqlite3InitModule} from "./jswasm/sqlite3.mjs";
self.sqlite3InitModule = sqlite3InitModule;
console.log("Loaded sqlite3InitModule() via an ES6 module.");
</script>
<script src="tester1.js" defer></script>
</body>
</html>

View File

@@ -6,7 +6,7 @@
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="../common/emscripten.css"/>
<link rel="stylesheet" href="../common/testing.css"/>
<title>sqlite3 tester #1 (Worker thread)</title>
<title>sqlite3 tester #1: Worker thread</title>
<style>
body {
font-family: monospace;
@@ -14,7 +14,7 @@
</style>
</head>
<body>
<h1 id='color-target'>sqlite3 WASM/JS tester #1 (Worker thread)</h1>
<h1 id='color-target'>sqlite3 tester #1: Worker thread</h1>
<div>See <a href='tester1.html' target='tester1.html'>tester1.html</a>
for the UI-thread variant.</div>
<div class='input-wrapper'>
@@ -40,7 +40,20 @@
};
cbReverse.addEventListener('change',cbReverseIt,true);
cbReverseIt();
const w = new Worker("tester1.js?sqlite3.dir=jswasm");
const urlParams = new URL(self.location.href).searchParams;
const workerArgs = [];
if(urlParams.has('esm')){
logHtml('warning',"Attempting to run an ES6 Worker Module, "+
"which is not supported by all browsers! "+
"e.g. Firefox (as of 2022-11) cannot do this.");
workerArgs.push("tester1.mjs",{type:"module"});
document.querySelectorAll('title,#color-target').forEach((e)=>{
e.innerText = "sqlite3 tester #1: ES6 Worker Module";
});
}else{
workerArgs.push("tester1.js?sqlite3.dir=jswasm");
}
const w = new Worker(...workerArgs);
w.onmessage = function({data}){
switch(data.type){
case 'log':

View File

@@ -6,7 +6,13 @@
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="common/emscripten.css"/>
<link rel="stylesheet" href="common/testing.css"/>
<title>sqlite3 tester #1 (UI thread)</title>
<title>sqlite3 tester #1:
//#if target=es6-module
ES6 Module in UI thread
//#else
UI thread
//#endif
</title>
<style>
body {
font-family: monospace;
@@ -14,7 +20,7 @@
</style>
</head>
<body>
<h1 id='color-target'>sqlite3 WASM/JS tester #1 (UI thread)</h1>
<h1 id='color-target'></h1>
<div>See <a href='tester1-worker.html' target='tester1-worker.html'>tester1-worker.html</a>
for the Worker-thread variant.</div>
<div class='input-wrapper'>
@@ -22,7 +28,15 @@
<label for='cb-log-reverse'>Reverse log order?</label>
</div>
<div id='test-output'></div>
<script>(function(){
document.querySelector('h1').innerHTML =
document.querySelector('title').innerHTML;
})();</script>
//#if target=es6-module
<script src="tester1.mjs" type="module"></script>
//#else
<script src="jswasm/sqlite3.js"></script>
<script src="tester1.js"></script>
//#endif
</body>
</html>

View File

@@ -29,8 +29,25 @@
a db in an early test and close it in a later test. Each test gets
passed the sqlite3 namespace object as its only argument.
*/
/*
This file is intended to be processed by c-pp to inject (or not)
code specific to ES6 modules which is illegal in non-module code.
Non-ES6 module build and ES6 module for the main-thread:
./c-pp -f tester1.c-pp.js -o tester1.js
ES6 worker module build:
./c-pp -f tester1.c-pp.js -o tester1-esm.js -Dtarget=es6-module
*/
//#if target=es6-module
import {default as sqlite3InitModule} from './jswasm/sqlite3.mjs';
self.sqlite3InitModule = sqlite3InitModule;
//#else
'use strict';
(function(){
//#endif
(function(self){
/**
Set up our output channel differently depending
on whether we are running in a worker thread or
@@ -1817,7 +1834,8 @@
////////////////////////////////////////////////////////////////////////
log("Loading and initializing sqlite3 WASM module...");
if(!isUIThread()){
if(!self.sqlite3InitModule && !isUIThread()){
/* Vanilla worker, as opposed to an ES6 module worker */
/*
If sqlite3.js is in a directory other than this script, in order
to get sqlite3.js to resolve sqlite3.wasm properly, we have to
@@ -1861,4 +1879,5 @@
}
TestUtil.runTests(sqlite3);
});
})();
})(self);

View File

@@ -0,0 +1,48 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="../../../common/testing.css"/>
<title>sqlite3 OPFS Worker concurrency tester</title>
<style>
body { display: revert; }
body > * {}
#test-output {
font-family: monospace;
}
</style>
</head>
<body>
<h1></h1>
<p>
OPFS concurrency tester using multiple independent Workers.
Disclaimer: concurrency in OPFS is currently a pain point
and timing/concurrency mitigation in this environment is
highly unpredictable!
</p>
<p>
URL flags: pass a number of workers using
the <code>workers=N</code> URL flag and the worker work interval
as <code>interval=N</code> (milliseconds). Enable OPFS VFS
verbosity with <code>verbose=1-3</code> (output goes to the
dev console).
</p>
<p>Achtung: if it does not start to do anything within a couple of
seconds, check the dev console: Chrome often fails with "cannot allocate
WasmMemory" at startup. Closing and re-opening the tab usually resolves
it.
</p>
<div class='input-wrapper'>
<input type='checkbox' id='cb-log-reverse'>
<label for='cb-log-reverse'>Reverse log order?</label>
</div>
<div id='test-output'></div>
<script>(function(){
document.querySelector('h1').innerHTML =
document.querySelector('title').innerHTML;
})();</script>
<script src="test.js?sqlite3.dir=../../../jswasm"></script>
</body>
</html>

View File

@@ -0,0 +1,111 @@
(async function(self){
const logCss = (function(){
const mapToString = (v)=>{
switch(typeof v){
case 'number': case 'string': case 'boolean':
case 'undefined': case 'bigint':
return ''+v;
default: break;
}
if(null===v) return 'null';
if(v instanceof Error){
v = {
message: v.message,
stack: v.stack,
errorClass: v.name
};
}
return JSON.stringify(v,undefined,2);
};
const normalizeArgs = (args)=>args.map(mapToString);
const logTarget = document.querySelector('#test-output');
const logCss = function(cssClass,...args){
const ln = document.createElement('div');
if(cssClass){
for(const c of (Array.isArray(cssClass) ? cssClass : [cssClass])){
ln.classList.add(c);
}
}
ln.append(document.createTextNode(normalizeArgs(args).join(' ')));
logTarget.append(ln);
};
const cbReverse = document.querySelector('#cb-log-reverse');
const cbReverseKey = 'tester1:cb-log-reverse';
const cbReverseIt = ()=>{
logTarget.classList[cbReverse.checked ? 'add' : 'remove']('reverse');
localStorage.setItem(cbReverseKey, cbReverse.checked ? 1 : 0);
};
cbReverse.addEventListener('change', cbReverseIt, true);
if(localStorage.getItem(cbReverseKey)){
cbReverse.checked = !!(+localStorage.getItem(cbReverseKey));
}
cbReverseIt();
return logCss;
})();
const stdout = (...args)=>logCss('',...args);
const stderr = (...args)=>logCss('error',...args);
const wait = async (ms)=>{
return new Promise((resolve)=>setTimeout(resolve,ms));
};
const urlArgsJs = new URL(document.currentScript.src).searchParams;
const urlArgsHtml = new URL(self.location.href).searchParams;
const options = Object.create(null);
options.sqlite3Dir = urlArgsJs.get('sqlite3.dir');
options.workerCount = (
urlArgsHtml.has('workers') ? +urlArgsHtml.get('workers') : 3
) || 3;
options.opfsVerbose = (
urlArgsHtml.has('verbose') ? +urlArgsHtml.get('verbose') : 1
) || 1;
options.interval = (
urlArgsHtml.has('interval') ? +urlArgsHtml.get('interval') : 750
) || 750;
const workers = [];
workers.post = (type,...args)=>{
for(const w of workers) w.postMessage({type, payload:args});
};
workers.loadedCount = 0;
workers.onmessage = function(msg){
msg = msg.data;
const prefix = 'Worker #'+msg.worker+':';
switch(msg.type){
case 'loaded':
stdout(prefix,"loaded");
if(++workers.loadedCount === workers.length){
stdout("All workers loaded. Telling them to run...");
workers.post('run');
}
break;
case 'stdout': stdout(prefix,...msg.payload); break;
case 'stderr': stderr(prefix,...msg.payload); break;
case 'error': stderr(prefix,"ERROR:",...msg.payload); break;
case 'finished':
logCss('tests-pass',prefix,...msg.payload);
break;
case 'failed':
logCss('tests-fail',prefix,"FAILED:",...msg.payload);
break;
default: logCss('error',"Unhandled message type:",msg); break;
}
};
stdout("Launching",options.workerCount,"workers...");
workers.uri = (
'worker.js?'
+ 'sqlite3.dir='+options.sqlite3Dir
+ '&interval='+options.interval
+ '&opfs-verbose='+options.opfsVerbose
);
for(let i = 0; i < options.workerCount; ++i){
stdout("Launching worker...");
workers.push(new Worker(
workers.uri+'&workerId='+(i+1)+(i ? '' : '&unlink-db')
));
}
// Have to delay onmessage assignment until after the loop
// to avoid that early workers get an undue head start.
workers.forEach((w)=>w.onmessage = workers.onmessage);
})(self);

View File

@@ -0,0 +1,105 @@
importScripts(
(new URL(self.location.href).searchParams).get('sqlite3.dir') + '/sqlite3.js'
);
self.sqlite3InitModule().then(async function(sqlite3){
const urlArgs = new URL(self.location.href).searchParams;
const wName = urlArgs.get('workerId') || Math.round(Math.random()*10000);
const wPost = (type,...payload)=>{
postMessage({type, worker: wName, payload});
};
const stdout = (...args)=>wPost('stdout',...args);
const stderr = (...args)=>wPost('stderr',...args);
if(!sqlite3.opfs){
stderr("OPFS support not detected. Aborting.");
return;
}
const wait = async (ms)=>{
return new Promise((resolve)=>setTimeout(resolve,ms));
};
const dbName = 'concurrency-tester.db';
if(urlArgs.has('unlink-db')){
await sqlite3.opfs.unlink(dbName);
stdout("Unlinked",dbName);
}
wPost('loaded');
let db;
const interval = Object.assign(Object.create(null),{
delay: urlArgs.has('interval') ? (+urlArgs.get('interval') || 750) : 750,
handle: undefined,
count: 0
});
const finish = ()=>{
if(db){
if(!db.pointer) return;
db.close();
}
if(interval.error){
wPost('failed',"Ending work after interval #"+interval.count,
"due to error:",interval.error);
}else{
wPost('finished',"Ending work after",interval.count,"intervals.");
}
};
const run = async function(){
db = new sqlite3.opfs.OpfsDb(dbName,'c');
sqlite3.capi.sqlite3_busy_timeout(db.pointer, 5000);
db.transaction((db)=>{
db.exec([
"create table if not exists t1(w TEXT UNIQUE ON CONFLICT REPLACE,v);",
"create table if not exists t2(w TEXT UNIQUE ON CONFLICT REPLACE,v);"
]);
});
const maxIterations = 10;
stdout("Starting interval-based db updates with delay of",interval.delay,"ms.");
const doWork = async ()=>{
const tm = new Date().getTime();
++interval.count;
const prefix = "v(#"+interval.count+")";
stdout("Setting",prefix,"=",tm);
try{
db.exec({
sql:"INSERT OR REPLACE INTO t1(w,v) VALUES(?,?)",
bind: [wName, new Date().getTime()]
});
//stdout("Set",prefix);
}catch(e){
interval.error = e;
}
};
if(1){/*use setInterval()*/
interval.handle = setInterval(async ()=>{
await doWork();
if(interval.error || maxIterations === interval.count){
clearInterval(interval.handle);
finish();
}
}, interval.delay);
}else{
/*This approach provides no concurrency whatsoever: each worker
is run to completion before any others can work.*/
let i;
for(i = 0; i < maxIterations; ++i){
await doWork();
if(interval.error) break;
await wait(interval.ms);
}
finish();
}
}/*run()*/;
self.onmessage = function({data}){
switch(data.type){
case 'run': run().catch((e)=>{
if(!interval.error) interval.error = e;
finish();
});
break;
default:
stderr("Unhandled message type '"+data.type+"'.");
break;
}
};
});

View File

@@ -101,7 +101,7 @@ $(speedtest1-wasmfs.js): $(speedtest1.cses) $(sqlite3-wasmfs.js) \
$(EXPORTED_FUNCTIONS.speedtest1)
@echo "Building $@ ..."
$(emcc.bin) \
$(speedtest1-wasmfs.eflags) $(speedtest1-common.eflags) \
$(speedtest1-wasmfs.eflags) $(speedtest1.eflags.common) \
$(pre-post-speedtest1-wasmfs.flags) \
$(speedtest1.cflags) \
$(sqlite3-wasmfs.cflags) \

View File

@@ -1,5 +1,5 @@
C Remove\scheck\sfor\sWASM_WASI\smacro\swhen\sdetecting\swasi\scompilation\smode,\sas\sthat\smacro\sis\sproject-specific.\sRely\sonly\son\s__wasi__\s(exposed\sby\sclang)\sto\sdetect\swasi\scompilation\smode.
D 2022-11-20T15:30:42.968
C Merge\strunk\sinto\swasi-patches\sbranch\sto\sclean\sup\sthe\sdiff\sview.
D 2022-11-21T16:03:19.238
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -488,25 +488,25 @@ F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
F ext/wasm/GNUmakefile 1e38a4f7147d621bd2138d13938ef34157bcf47908325baa6b06cd02c5e3ef89
F ext/wasm/GNUmakefile bc1696a1189f4c571b3d878b8f3a67c1f4b52c222f52d356027a5a0c707337c7
F ext/wasm/README-dist.txt 2d670b426fc7c613b90a7d2f2b05b433088fe65181abead970980f0a4a75ea20
F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 9120c2f8f51fa85f46dcf4dcb6b12f4a807d428f6089b99cdb08d8ddfcfd88b2
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api b4d68c97d14944b48d55e06aa44f544a6f56a7fa2bcb6f9e030936a5b2a9479a
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
F ext/wasm/api/README.md 29276a845e57004e82efba61fa5866fd05f9137380a1dc26dc4c6d65264cd81c
F ext/wasm/api/extern-post-js.js 015121df2c903cf12d51507227b756ab3626036d8e9d610a2a2c15b3f54afe4d
F ext/wasm/api/extern-post-js.js 31400dd1c0ae3458a0e6510229e59318e45eac402a75dd703c2950b9b5758b46
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08902f15c34720ee4a1
F ext/wasm/api/post-js-header.js d6ab3dfef4a06960d28a7eaa338d4e2a1a5981e9b38718168bbde8fdb2a439b8
F ext/wasm/api/pre-js.js 1156a7fb9de817bb1cb39ad90b76aa93fbb9dcf950a1f2d6f547e5976872be36
F ext/wasm/api/pre-js.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f
F ext/wasm/api/sqlite3-api-cleanup.js ecdc69dbfccfe26146f04799fcfd4a6f5790d46e7e3b9b6e9b0491f92ed8ae34
F ext/wasm/api/sqlite3-api-glue.js 056f44b82c126358a0175e08a892d56fadfce177b0d7a0012502a6acf67ea6d5
F ext/wasm/api/sqlite3-api-oo1.js e9a83489bbb4838ce0aee46eaaa9350e0e25a5b926b565e4f5ae8e840e4fbaed
F ext/wasm/api/sqlite3-api-opfs.js 9f115a37dafe8067bce8812996d2deff45741c6e39f7aad7b48f5fbbd822dba5
F ext/wasm/api/sqlite3-api-prologue.js fd526fa017fa2578673ca18158354515c719e719a5d93f2f6d0e43f39170430e
F ext/wasm/api/sqlite3-api-opfs.js 38d368e33f470f9ba196f1a2b0c9ce076c930c70df233c345a246f1ad4c26d3b
F ext/wasm/api/sqlite3-api-prologue.js 08e96d26d329e8c1e08813fe0b84ee93e0e78b087efdd6eb2809ae2672902437
F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
F ext/wasm/api/sqlite3-opfs-async-proxy.js 24d1c1982a012d998907105a4ff1ff6881bf462395e90c06326817701e69f093
F ext/wasm/api/sqlite3-opfs-async-proxy.js 1ec10873f1d59d305f6f3b435c50a1b75d693d5fb739b226f3da46fcbb11261a
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c 8fc8f47680df0e9a6c0f2f03cb004148645ecc983aa216daba09cb21f7e092a2
F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b
@@ -527,14 +527,14 @@ F ext/wasm/demo-worker1-promiser.html 1de7c248c7c2cfd4a5783d2aa154bce62d74c6de98
F ext/wasm/demo-worker1-promiser.js b85a2bb1b918db4f09dfa24419241cb3edad7791389425c2505092e9b715017d
F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d
F ext/wasm/demo-worker1.js a619adffc98b75b66c633b00f747b856449a134a9a0357909287d80a182d70fa
F ext/wasm/dist.make 4b55c8a7926bbab4936adab6a08eca524085fc47bc3b08f41918df5b4665da3d
F ext/wasm/dist.make 11b98da79385701a568a4728671821fe2524c1d1ecd05ff2e24cb3e33b2c6c4f
F ext/wasm/fiddle.make 2812c44c9bafb5be9c8767963d1b9f374d77af7795fcaa06483c03e7059dea74
F ext/wasm/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
F ext/wasm/fiddle/fiddle-worker.js b4a0c8ab6c0983218543ca771c45f6075449f63a1dcf290ae5a681b2cba8800d
F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5653284071715
F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2
F ext/wasm/index-dist.html 6bfb3591e40f7c23626730df587f533e983e996d4d1fb67244fb6a88fe6cf9a6
F ext/wasm/index.html 49f58dddc29f6394b6e8a93e42768de59380c258454b68b9182e1946d13a4a4b
F ext/wasm/index-dist.html c4337617c4d6d4d0796827cec28ac81d128c6f911dcf888a290a32ad50890408
F ext/wasm/index.html 5be176de5be8ae96889798f803fef4f6a2ef31cee305a0430ca4629f6ae04c27
F ext/wasm/jaccwabyt/jaccwabyt.js 95f573de1826474c9605dda620ee622fcb1673ae74f191eb324c0853aa4dcb66
F ext/wasm/jaccwabyt/jaccwabyt.md 9aa6951b529a8b29f578ec8f0355713c39584c92cf1708f63ba0cf917cb5b68e
F ext/wasm/module-symbols.html b8eebafef8e536624bbe5f7a3da40c07a9062b843dfd3161a0bb72cbb6763dc5
@@ -549,12 +549,14 @@ F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d826
F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5
F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555e685bce3da8c3f
F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac
F ext/wasm/tester1-esm.html 8d226a21b20707dbd66d68a3990141f0392fc781a281291d3dc59f38a3555887
F ext/wasm/tester1-worker.html 51bf39e2b87f974ae3d5bc3086e2fb36d258f3698c54f6e21ba4b3b99636fa27
F ext/wasm/tester1.html 624ec41cd9f78a1f2b6d7df70aaa7a6394396b1f2455ecbd6de5775c1275b121
F ext/wasm/tester1.js bff806de454de115922d78c056f11d523ec7ed9ed3839d4e21433a9f72558b88
F ext/wasm/tester1-worker.html 5ef353348c37cf2e4fd0b23da562d3275523e036260b510734e9a3239ba8c987
F ext/wasm/tester1.c-pp.html 74aa9b31c75f12490653f814b53c3dd39f40cd3f70d6a53a716f4e8587107399 w ext/wasm/tester1.html
F ext/wasm/tester1.c-pp.js 0c129495d057c77788b59715152d51f9bf9002ebbcce759ef8b028272ce3519d w ext/wasm/tester1.js
F ext/wasm/tests/opfs/concurrency/index.html bb9b0f6da86df34c67fa506db9c45b7c4cf0045a211611cc6b8d2b53fa983481
F ext/wasm/tests/opfs/concurrency/test.js 5993c08657d547d3a26b78ff3480122aed2b7361823bc127e96e558931093aff
F ext/wasm/tests/opfs/concurrency/worker.js df065bb386ff994951f7fbdd76e12f16e58fbef0e929b2caf74553359da40afc
F ext/wasm/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd72273503ae7d5
F ext/wasm/wasmfs.make 8aa7565f9de8dd3c291ad8c3ceb1a2c67a3eb31a8e531070b25c6c6b1f0278bf
F ext/wasm/wasmfs.make 8fea9b4f3cde06141de1fc4c586ab405bd32c3f401554f4ebb18c797401a678d
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
@@ -578,9 +580,9 @@ F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
F src/backup.c a2891172438e385fdbe97c11c9745676bec54f518d4447090af97189fd8e52d7
F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d
F src/btmutex.c 6ffb0a22c19e2f9110be0964d0731d2ef1c67b5f7fabfbaeb7b9dabc4b7740ca
F src/btree.c e8fae9a95ea9561aebc41e467a9ee9ba9150ca373031e65773d62ff02d8250d2
F src/btree.c 522df0f1173495e06c5589f0b17a61f53a212017b82be53171133fcfc0e1e90a
F src/btree.h 4fcbb0b041013071dd5e9f53c538d49916c092e6ad8842185985e5270a0792de
F src/btreeInt.h 8ce1332edd89dfd2461d561ac10a0ab5601c8e06200cb5230596c3caaf54482e
F src/btreeInt.h 88ad499c92b489afedbfefc3f067c4d15023ec021afe622db240dc9d2277cfa5
F src/build.c d3e43e950e4e377c1d451a4862556792acdef1faba14a03f899d30d09731c48b
F src/callback.c 4cd7225b26a97f7de5fee5ae10464bed5a78f2adefe19534cc2095b3a8ca484a
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
@@ -711,7 +713,7 @@ F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
F src/util.c 0be191521ff6d2805995f4910f0b6231b42843678b2efdc1abecaf39929a673f
F src/vacuum.c 84ce7f01f8a7a08748e107a441db83bcec13970190ddcb0c9ff522adbc1c23fd
F src/vdbe.c 0c7cb1b934ad8611e14e7efaf2c3a95df7dd3f7964d63ea07fef42a23df86131
F src/vdbe.c c2d6d0c0c343d8ebffef996c73cbb69e337225f757fea7fe5c0e3ea14662adec
F src/vdbe.h 58675f47dcf3105bab182c3ad3726efd60ffd003e954386904ac9107d0d2b743
F src/vdbeInt.h 17b7461ffcf9ee760d1341731715a419f6b8c763089a7ece25c2e8098d702b3f
F src/vdbeapi.c 1e8713d0b653acb43cd1bdf579c40e005c4844ea90f414f065946a83db3c27fb
@@ -2057,8 +2059,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 9b8b15a779158ec7c39d936f6bfa6a35e12063a36933341ade051809993a5678
R eab0332091536d080c020fa14b102cbe
P d469ac0c448eced26a697751ce9be316e8bc3cd029fda2b50966523c7850854f 5f564bf7de7ce3ad7bedb5f06b3086ceaec55da768a60d74059fa4fba4328567
R c6e7dc02521e7ecf758d690fc58cd968
U stephan
Z 0c7f0b6e6cee222ce3be0bf4f50c95f1
Z ef5aed11fc17ce6d5e08251a18764500
# Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
d469ac0c448eced26a697751ce9be316e8bc3cd029fda2b50966523c7850854f
95de6742d3d96d2b21eec57195dc7a2236d3f61640633ae1baa36bf142a3485b

View File

@@ -1900,62 +1900,67 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
** Only the following combinations are supported. Anything different
** indicates a corrupt database files:
**
** PTF_ZERODATA
** PTF_ZERODATA | PTF_LEAF
** PTF_LEAFDATA | PTF_INTKEY
** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF
** PTF_ZERODATA (0x02, 2)
** PTF_LEAFDATA | PTF_INTKEY (0x05, 5)
** PTF_ZERODATA | PTF_LEAF (0x0a, 10)
** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF (0x0d, 13)
*/
static int decodeFlags(MemPage *pPage, int flagByte){
BtShared *pBt; /* A copy of pPage->pBt */
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 );
flagByte &= ~PTF_LEAF;
pPage->childPtrSize = 4-4*pPage->leaf;
pBt = pPage->pBt;
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
/* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an
** interior table b-tree page. */
assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
/* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a
** leaf table b-tree page. */
assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
pPage->intKey = 1;
if( pPage->leaf ){
pPage->max1bytePayload = pBt->max1bytePayload;
if( flagByte>=(PTF_ZERODATA | PTF_LEAF) ){
pPage->childPtrSize = 0;
pPage->leaf = 1;
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF) ){
pPage->intKeyLeaf = 1;
pPage->xCellSize = cellSizePtrTableLeaf;
pPage->xParseCell = btreeParseCellPtr;
pPage->intKey = 1;
pPage->maxLocal = pBt->maxLeaf;
pPage->minLocal = pBt->minLeaf;
}else if( flagByte==(PTF_ZERODATA | PTF_LEAF) ){
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
pPage->xCellSize = cellSizePtr;
pPage->xParseCell = btreeParseCellPtrIndex;
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
pPage->xCellSize = cellSizePtr;
pPage->xParseCell = btreeParseCellPtrIndex;
return SQLITE_CORRUPT_PAGE(pPage);
}
}else{
pPage->childPtrSize = 4;
pPage->leaf = 0;
if( flagByte==(PTF_ZERODATA) ){
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
pPage->xCellSize = cellSizePtr;
pPage->xParseCell = btreeParseCellPtrIndex;
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
pPage->intKeyLeaf = 0;
pPage->xCellSize = cellSizePtrNoPayload;
pPage->xParseCell = btreeParseCellPtrNoPayload;
pPage->intKey = 1;
pPage->maxLocal = pBt->maxLeaf;
pPage->minLocal = pBt->minLeaf;
}else{
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
pPage->xCellSize = cellSizePtr;
pPage->xParseCell = btreeParseCellPtrIndex;
return SQLITE_CORRUPT_PAGE(pPage);
}
pPage->maxLocal = pBt->maxLeaf;
pPage->minLocal = pBt->minLeaf;
}else if( flagByte==PTF_ZERODATA ){
/* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an
** interior index b-tree page. */
assert( (PTF_ZERODATA)==2 );
/* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a
** leaf index b-tree page. */
assert( (PTF_ZERODATA|PTF_LEAF)==10 );
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
pPage->xCellSize = cellSizePtr;
pPage->xParseCell = btreeParseCellPtrIndex;
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
/* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
** an error. */
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
pPage->xCellSize = cellSizePtr;
pPage->xParseCell = btreeParseCellPtrIndex;
return SQLITE_CORRUPT_PAGE(pPage);
}
pPage->max1bytePayload = pBt->max1bytePayload;
return SQLITE_OK;
}
@@ -6601,7 +6606,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
/* If the database supports auto-vacuum, write an entry in the pointer-map
** to indicate that the page is free.
*/
if( ISAUTOVACUUM ){
if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0, &rc);
if( rc ) goto freepage_out;
}
@@ -7041,24 +7046,20 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** in pTemp or the original pCell) and also record its index.
** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
**
** *pRC must be SQLITE_OK when this routine is called.
*/
static void insertCell(
static int insertCell(
MemPage *pPage, /* Page into which we are copying */
int i, /* New cell becomes the i-th cell of the page */
u8 *pCell, /* Content of the new cell */
int sz, /* Bytes of content in pCell */
u8 *pTemp, /* Temp storage space for pCell, if needed */
Pgno iChild, /* If non-zero, replace first 4 bytes with this value */
int *pRC /* Read and write return code from here */
Pgno iChild /* If non-zero, replace first 4 bytes with this value */
){
int idx = 0; /* Where to write new cell content in data[] */
int j; /* Loop counter */
u8 *data; /* The content of the whole page */
u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
assert( *pRC==SQLITE_OK );
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
assert( MX_CELL(pPage->pBt)<=10921 );
assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
@@ -7093,14 +7094,13 @@ static void insertCell(
}else{
int rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc!=SQLITE_OK ){
*pRC = rc;
return;
return rc;
}
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
data = pPage->aData;
assert( &data[pPage->cellOffset]==pPage->aCellIdx );
rc = allocateSpace(pPage, sz, &idx);
if( rc ){ *pRC = rc; return; }
if( rc ){ return rc; }
/* The allocateSpace() routine guarantees the following properties
** if it returns successfully */
assert( idx >= 0 );
@@ -7127,13 +7127,16 @@ static void insertCell(
assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pPage->pBt->autoVacuum ){
int rc = SQLITE_OK;
/* The cell may contain a pointer to an overflow page. If so, write
** the entry for the overflow page into the pointer map.
*/
ptrmapPutOvflPtr(pPage, pPage, pCell, pRC);
ptrmapPutOvflPtr(pPage, pPage, pCell, &rc);
if( rc ) return rc;
}
#endif
}
return SQLITE_OK;
}
/*
@@ -7234,14 +7237,16 @@ struct CellArray {
** computed.
*/
static void populateCellCache(CellArray *p, int idx, int N){
MemPage *pRef = p->pRef;
u16 *szCell = p->szCell;
assert( idx>=0 && idx+N<=p->nCell );
while( N>0 ){
assert( p->apCell[idx]!=0 );
if( p->szCell[idx]==0 ){
p->szCell[idx] = p->pRef->xCellSize(p->pRef, p->apCell[idx]);
if( szCell[idx]==0 ){
szCell[idx] = pRef->xCellSize(pRef, p->apCell[idx]);
}else{
assert( CORRUPT_DB ||
p->szCell[idx]==p->pRef->xCellSize(p->pRef, p->apCell[idx]) );
szCell[idx]==pRef->xCellSize(pRef, p->apCell[idx]) );
}
idx++;
N--;
@@ -7443,8 +7448,8 @@ static int pageFreeArray(
int nRet = 0;
int i;
int iEnd = iFirst + nCell;
u8 *pFree = 0;
int szFree = 0;
u8 *pFree = 0; /* \__ Parameters for pending call to */
int szFree = 0; /* / freeSpace() */
for(i=iFirst; i<iEnd; i++){
u8 *pCell = pCArray->apCell[i];
@@ -7465,6 +7470,9 @@ static int pageFreeArray(
return 0;
}
}else{
/* The current cell is adjacent to and before the pFree cell.
** Combine the two regions into one to reduce the number of calls
** to freeSpace(). */
pFree = pCell;
szFree += sz;
}
@@ -7672,7 +7680,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
** be marked as dirty. Returning an error code will cause a
** rollback, undoing any changes made to the parent page.
*/
if( ISAUTOVACUUM ){
if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc);
if( szCell>pNew->minLocal ){
ptrmapPutOvflPtr(pNew, pNew, pCell, &rc);
@@ -7700,8 +7708,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
/* Insert the new divider cell into pParent. */
if( rc==SQLITE_OK ){
insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
0, pPage->pgno, &rc);
rc = insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
0, pPage->pgno);
}
/* Set the right-child pointer of pParent to point to the new page. */
@@ -7810,7 +7818,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
/* If this is an auto-vacuum database, update the pointer-map entries
** for any b-tree or overflow pages that pTo now contains the pointers to.
*/
if( ISAUTOVACUUM ){
if( ISAUTOVACUUM(pBt) ){
*pRC = setChildPtrmaps(pTo);
}
}
@@ -8234,15 +8242,17 @@ static int balance_nonroot(
d = r + 1 - leafData;
(void)cachedCellSize(&b, d);
do{
int szR, szD;
assert( d<nMaxCells );
assert( r<nMaxCells );
(void)cachedCellSize(&b, r);
szR = cachedCellSize(&b, r);
szD = b.szCell[d];
if( szRight!=0
&& (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){
&& (bBulk || szRight+szD+2 > szLeft-(szR+(i==k-1?0:2)))){
break;
}
szRight += b.szCell[d] + 2;
szLeft -= b.szCell[r] + 2;
szRight += szD + 2;
szLeft -= szR + 2;
cntNew[i-1] = r;
r--;
d--;
@@ -8296,7 +8306,7 @@ static int balance_nonroot(
cntOld[i] = b.nCell;
/* Set the pointer-map entry for the new sibling page. */
if( ISAUTOVACUUM ){
if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc);
if( rc!=SQLITE_OK ){
goto balance_cleanup;
@@ -8389,7 +8399,7 @@ static int balance_nonroot(
** updated. This happens below, after the sibling pages have been
** populated, not here.
*/
if( ISAUTOVACUUM ){
if( ISAUTOVACUUM(pBt) ){
MemPage *pOld;
MemPage *pNew = pOld = apNew[0];
int cntOldNext = pNew->nCell + pNew->nOverflow;
@@ -8486,7 +8496,7 @@ static int balance_nonroot(
rc = SQLITE_CORRUPT_BKPT;
goto balance_cleanup;
}
insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc);
rc = insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno);
if( rc!=SQLITE_OK ) goto balance_cleanup;
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
}
@@ -8582,7 +8592,7 @@ static int balance_nonroot(
);
copyNodeContent(apNew[0], pParent, &rc);
freePage(apNew[0], &rc);
}else if( ISAUTOVACUUM && !leafCorrection ){
}else if( ISAUTOVACUUM(pBt) && !leafCorrection ){
/* Fix the pointer map entries associated with the right-child of each
** sibling page. All other pointer map entries have already been taken
** care of. */
@@ -8603,7 +8613,7 @@ static int balance_nonroot(
}
#if 0
if( ISAUTOVACUUM && rc==SQLITE_OK && apNew[0]->isInit ){
if( ISAUTOVACUUM(pBt) && rc==SQLITE_OK && apNew[0]->isInit ){
/* The ptrmapCheckPages() contains assert() statements that verify that
** all pointer map pages are set correctly. This is helpful while
** debugging. This is usually disabled because a corrupt database may
@@ -8665,7 +8675,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
if( rc==SQLITE_OK ){
rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0);
copyNodeContent(pRoot, pChild, &rc);
if( ISAUTOVACUUM ){
if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc);
}
}
@@ -8997,7 +9007,6 @@ int sqlite3BtreeInsert(
int idx;
MemPage *pPage;
Btree *p = pCur->pBtree;
BtShared *pBt = p->pBt;
unsigned char *oldCell;
unsigned char *newCell = 0;
@@ -9016,7 +9025,7 @@ int sqlite3BtreeInsert(
** not to clear the cursor here.
*/
if( pCur->curFlags & BTCF_Multiple ){
rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
rc = saveAllCursors(p->pBt, pCur->pgnoRoot, pCur);
if( rc ) return rc;
if( loc && pCur->iPage<0 ){
/* This can only happen if the schema is corrupt such that there is more
@@ -9040,8 +9049,8 @@ int sqlite3BtreeInsert(
assert( cursorOwnsBtShared(pCur) );
assert( (pCur->curFlags & BTCF_WriteFlag)!=0
&& pBt->inTransaction==TRANS_WRITE
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
&& p->pBt->inTransaction==TRANS_WRITE
&& (p->pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
/* Assert that the caller has been consistent. If this cursor was opened
@@ -9158,26 +9167,28 @@ int sqlite3BtreeInsert(
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit || CORRUPT_DB );
newCell = pBt->pTmpSpace;
newCell = p->pBt->pTmpSpace;
assert( newCell!=0 );
assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
if( flags & BTREE_PREFORMAT ){
rc = SQLITE_OK;
szNew = pBt->nPreformatSize;
szNew = p->pBt->nPreformatSize;
if( szNew<4 ) szNew = 4;
if( ISAUTOVACUUM && szNew>pPage->maxLocal ){
if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
CellInfo info;
pPage->xParseCell(pPage, newCell, &info);
if( info.nPayload!=info.nLocal ){
Pgno ovfl = get4byte(&newCell[szNew-4]);
ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
ptrmapPut(p->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
if( NEVER(rc) ) goto end_insert;
}
}
}else{
rc = fillInCell(pPage, newCell, pX, &szNew);
if( rc ) goto end_insert;
}
if( rc ) goto end_insert;
assert( szNew==pPage->xCellSize(pPage, newCell) );
assert( szNew <= MX_CELL_SIZE(pBt) );
assert( szNew <= MX_CELL_SIZE(p->pBt) );
idx = pCur->ix;
if( loc==0 ){
CellInfo info;
@@ -9197,7 +9208,7 @@ int sqlite3BtreeInsert(
testcase( pCur->curFlags & BTCF_ValidOvfl );
invalidateOverflowCache(pCur);
if( info.nSize==szNew && info.nLocal==info.nPayload
&& (!ISAUTOVACUUM || szNew<pPage->minLocal)
&& (!ISAUTOVACUUM(p->pBt) || szNew<pPage->minLocal)
){
/* Overwrite the old cell with the new if they are the same size.
** We could also try to do this if the old cell is smaller, then add
@@ -9227,7 +9238,7 @@ int sqlite3BtreeInsert(
}else{
assert( pPage->leaf );
}
insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
rc = insertCell(pPage, idx, newCell, szNew, 0, 0);
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
@@ -9300,7 +9311,6 @@ end_insert:
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
int rc = SQLITE_OK;
BtShared *pBt = pDest->pBt;
u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */
const u8 *aIn; /* Pointer to next input buffer */
@@ -9323,7 +9333,9 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
memcpy(aOut, aIn, nIn);
pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
return SQLITE_OK;
}else{
int rc = SQLITE_OK;
Pager *pSrcPager = pSrc->pBt->pPager;
u8 *pPgnoOut = 0;
Pgno ovflIn = 0;
@@ -9375,7 +9387,7 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
MemPage *pNew = 0;
rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
put4byte(pPgnoOut, pgnoNew);
if( ISAUTOVACUUM && pPageOut ){
if( ISAUTOVACUUM(pBt) && pPageOut ){
ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc);
}
releasePage(pPageOut);
@@ -9391,9 +9403,8 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
releasePage(pPageOut);
sqlite3PagerUnref(pPageIn);
return rc;
}
return rc;
}
/*
@@ -9548,7 +9559,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
assert( pTmp!=0 );
rc = sqlite3PagerWrite(pLeaf->pDbPage);
if( rc==SQLITE_OK ){
insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n);
}
dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
if( rc ) return rc;

View File

@@ -674,9 +674,9 @@ struct BtCursor {
** So, this macro is defined instead.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
#define ISAUTOVACUUM (pBt->autoVacuum)
#define ISAUTOVACUUM(pBt) (pBt->autoVacuum)
#else
#define ISAUTOVACUUM 0
#define ISAUTOVACUUM(pBt) 0
#endif

View File

@@ -5579,6 +5579,7 @@ case OP_Insert: {
x.nZero = 0;
}
x.pKey = 0;
assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
seekResult