1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Update the latest trunk enhancements into the wal-shm-exceptions branch.

FossilOrigin-Name: 3187ee3f69fc28a259ba0e951ac10a65c07ef2c3866acbefaf9544333a930cc6
This commit is contained in:
drh
2023-07-24 12:59:53 +00:00
41 changed files with 2316 additions and 886 deletions

View File

@@ -4655,9 +4655,13 @@ static void fts5SecureDeleteOverflow(
int i1 = pLeaf->szLeaf; int i1 = pLeaf->szLeaf;
int i2 = 0; int i2 = 0;
i1 += fts5GetVarint32(&aPg[i1], iFirst);
if( iFirst<iNext ){
p->rc = FTS5_CORRUPT;
break;
}
aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2); aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2);
if( aIdx==0 ) break; if( aIdx==0 ) break;
i1 += fts5GetVarint32(&aPg[i1], iFirst);
i2 = sqlite3Fts5PutVarint(aIdx, iFirst-nShift); i2 = sqlite3Fts5PutVarint(aIdx, iFirst-nShift);
if( i1<pLeaf->nn ){ if( i1<pLeaf->nn ){
memcpy(&aIdx[i2], &aPg[i1], pLeaf->nn-i1); memcpy(&aIdx[i2], &aPg[i1], pLeaf->nn-i1);

View File

@@ -18,8 +18,6 @@
# quick, q = do just a minimal build (sqlite3.js/wasm, tester1) for # quick, q = do just a minimal build (sqlite3.js/wasm, tester1) for
# faster development-mode turnaround. # faster development-mode turnaround.
# #
# qo2, qoz = a combination of quick+o2/oz.
#
# dist = create end user deliverables. Add dist.build=oX to build # dist = create end user deliverables. Add dist.build=oX to build
# with a specific optimization level, where oX is one of the # with a specific optimization level, where oX is one of the
# above-listed o? or qo? target names. # above-listed o? or qo? target names.
@@ -46,11 +44,12 @@
# $(eval), or at least centralize the setup of the numerous vars # $(eval), or at least centralize the setup of the numerous vars
# related to each build variant $(JS_BUILD_MODES). # related to each build variant $(JS_BUILD_MODES).
# #
default: all
#default: quick
SHELL := $(shell which bash 2>/dev/null) SHELL := $(shell which bash 2>/dev/null)
MAKEFILE := $(lastword $(MAKEFILE_LIST)) MAKEFILE := $(lastword $(MAKEFILE_LIST))
CLEAN_FILES := CLEAN_FILES :=
DISTCLEAN_FILES := ./--dummy-- DISTCLEAN_FILES := ./--dummy--
default: all
release: oz release: oz
# JS_BUILD_MODES exists solely to reduce repetition in documentation # JS_BUILD_MODES exists solely to reduce repetition in documentation
# below. # below.
@@ -68,13 +67,6 @@ ifeq (,$(emcc.version))
else else
$(info using emcc version [$(emcc.version)]) $(info using emcc version [$(emcc.version)])
endif endif
emcc.version := $(shell "$(emcc.bin)" --version | sed -n 1p \
| sed -e 's/^.* \([3-9][^ ]*\) .*$$/\1/;')
ifeq (,$(emcc.version))
$(warning Cannot determine emcc version. This might unduly impact build flags.)
else
$(info using emcc version [$(emcc.version)])
endif
wasm-strip ?= $(shell which wasm-strip 2>/dev/null) wasm-strip ?= $(shell which wasm-strip 2>/dev/null)
ifeq (,$(filter clean,$(MAKECMDGOALS))) ifeq (,$(filter clean,$(MAKECMDGOALS)))
@@ -159,6 +151,9 @@ endif
# bundle. # bundle.
# #
# A custom sqlite3.c must not have any spaces in its name. # A custom sqlite3.c must not have any spaces in its name.
# $(sqlite3.canonical.c) must point to the sqlite3.c in
# the sqlite3 canonical source tree, as that source file
# is required for certain utility and test code.
sqlite3.canonical.c := $(dir.top)/sqlite3.c sqlite3.canonical.c := $(dir.top)/sqlite3.c
sqlite3.c ?= $(firstword $(wildcard $(dir.top)/sqlite3-see.c) $(sqlite3.canonical.c)) sqlite3.c ?= $(firstword $(wildcard $(dir.top)/sqlite3-see.c) $(sqlite3.canonical.c))
sqlite3.h := $(dir.top)/sqlite3.h sqlite3.h := $(dir.top)/sqlite3.h
@@ -186,7 +181,7 @@ SQLITE_OPT = \
-DSQLITE_OMIT_SHARED_CACHE \ -DSQLITE_OMIT_SHARED_CACHE \
-DSQLITE_OMIT_WAL \ -DSQLITE_OMIT_WAL \
-DSQLITE_THREADSAFE=0 \ -DSQLITE_THREADSAFE=0 \
-DSQLITE_TEMP_STORE=3 \ -DSQLITE_TEMP_STORE=2 \
-DSQLITE_OS_KV_OPTIONAL=1 \ -DSQLITE_OS_KV_OPTIONAL=1 \
'-DSQLITE_DEFAULT_UNIX_VFS="unix-none"' \ '-DSQLITE_DEFAULT_UNIX_VFS="unix-none"' \
-DSQLITE_USE_URI=1 \ -DSQLITE_USE_URI=1 \
@@ -379,20 +374,17 @@ sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.js
sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.js sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.js
sqlite3-api.jses += $(dir.api)/sqlite3-v-helper.js sqlite3-api.jses += $(dir.api)/sqlite3-v-helper.js
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js
sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
# "External" API files which are part of our distribution # SOAP.js is an external API file which is part of our distribution
# but not part of the sqlite3-api.js amalgamation. # but not part of the sqlite3-api.js amalgamation.
SOAP.js := $(dir.api)/sqlite3-opfs-async-proxy.js SOAP.js := $(dir.api)/sqlite3-opfs-async-proxy.js
# COPY_XAPI = a $(call)able function to copy $1 to $(dir.dout), where SOAP.js.bld := $(dir.dout)/$(notdir $(SOAP.js))
# $1 must be one of the "external" JS API files. sqlite3-api.ext.jses += $(SOAP.js.bld)
define COPY_XAPI $(SOAP.js.bld): $(SOAP.js)
sqlite3-api.ext.jses += $$(dir.dout)/$$(notdir $(1)) cp $< $@
$$(dir.dout)/$$(notdir $(1)): $(1) $$(MAKEFILE)
cp $$< $$@
endef
$(foreach X,$(SOAP.js),\
$(eval $(call COPY_XAPI,$(X))))
all quick: $(sqlite3-api.ext.jses) all quick: $(sqlite3-api.ext.jses)
q: quick q: quick
@@ -615,26 +607,40 @@ $(post-js.js.in): $(post-jses.js) $(MAKEFILE)
######################################################################## ########################################################################
# call-make-pre-post is a $(call)able which creates rules for # call-make-pre-post is a $(call)able which creates rules for
# pre-js-$(1).js. $1 = the base name of the JS file on whose behalf # pre-js-$(1)-$(2).js. $1 = the base name of the JS file on whose
# this pre-js is for (one of: sqlite3, sqlite3-wasmfs). $2 is the # behalf this pre-js is for (one of: sqlite3, sqlite3-wasmfs). $2 is
# build mode: one of $(JS_BUILD_MODES). This # the build mode: one of $(JS_BUILD_MODES). This sets up
# sets up --[extern-][pre/post]-js flags in # --[extern-][pre/post]-js flags in $(pre-post-$(1)-$(2).flags) and
# $(pre-post-$(1).flags.$(2)) and dependencies in # dependencies in $(pre-post-$(1)-$(2).deps). The resulting files get
# $(pre-post-$(1).deps.$(2)). # filtered using $(C-PP.FILTER). Any flags necessary for such
# filtering need to be set in $(c-pp.D.$(1)-$(2)) before $(call)ing
# this.
define call-make-pre-post define call-make-pre-post
pre-post-$(1).flags.$(2) ?= pre-post-$(1)-$(2).flags ?=
$$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(2)) $$(MAKEFILE) pre-js.js.$(1)-$(2) := $$(dir.tmp)/pre-js.$(1)-$(2).intermediary.js
cp $$(pre-js.js.$(2)) $$@ $$(eval $$(call C-PP.FILTER,$$(pre-js.js.in),$$(pre-js.js.$(1)-$(2)),$$(c-pp.D.$(1)-$(2))))
post-js.js.$(1)-$(2) := $$(dir.tmp)/post-js.$(1)-$(2).js
$$(eval $$(call C-PP.FILTER,$$(post-js.js.in),$$(post-js.js.$(1)-$(2)),$$(c-pp.D.$(1)-$(2))))
extern-post-js.js.$(1)-$(2) := $$(dir.tmp)/extern-post-js.$(1)-$(2).js
$$(eval $$(call C-PP.FILTER,$$(extern-post-js.js.in),$$(extern-post-js.js.$(1)-$(2)),$$(c-pp.D.$(1)-$(2))))
pre-post-common.flags.$(1)-$(2) := \
$$(pre-post-common.flags) \
--post-js=$$(post-js.js.$(1)-$(2)) \
--extern-post-js=$$(extern-post-js.js.$(1)-$(2))
pre-post-jses.$(1)-$(2).deps := $$(pre-post-jses.deps.common) \
$$(post-js.js.$(1)-$(2)) $$(extern-post-js.js.$(1)-$(2))
$$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(1)-$(2)) $$(MAKEFILE)
cp $$(pre-js.js.$(1)-$(2)) $$@
@if [ sqlite3-wasmfs = $(1) ]; then \ @if [ sqlite3-wasmfs = $(1) ]; then \
echo "delete Module[xNameOfInstantiateWasm] /*for WASMFS build*/;"; \ echo "delete Module[xNameOfInstantiateWasm] /*for WASMFS build*/;"; \
elif [ sqlite3 != $(1) ]; then \ elif [ sqlite3 != $(1) ]; then \
echo "Module[xNameOfInstantiateWasm].uri = '$(1).wasm';"; \ echo "Module[xNameOfInstantiateWasm].uri = '$(1).wasm';"; \
fi >> $$@ fi >> $$@
pre-post-$(1).deps.$(2) := \ pre-post-$(1)-$(2).deps := \
$$(pre-post-jses.deps.$(2)) \ $$(pre-post-jses.$(1)-$(2).deps) \
$$(dir.tmp)/pre-js-$(1)-$(2).js $$(dir.tmp)/pre-js-$(1)-$(2).js
pre-post-$(1).flags.$(2) += \ pre-post-$(1)-$(2).flags += \
$$(pre-post-common.flags.$(2)) \ $$(pre-post-common.flags.$(1)-$(2)) \
--pre-js=$$(dir.tmp)/pre-js-$(1)-$(2).js --pre-js=$$(dir.tmp)/pre-js-$(1)-$(2).js
endef endef
# /post-js and pre-js # /post-js and pre-js
@@ -645,7 +651,8 @@ endef
# https://github.com/emscripten-core/emscripten/issues/14383 # https://github.com/emscripten-core/emscripten/issues/14383
sqlite3.wasm := $(dir.dout)/sqlite3.wasm sqlite3.wasm := $(dir.dout)/sqlite3.wasm
sqlite3-wasm.c := $(dir.api)/sqlite3-wasm.c sqlite3-wasm.c := $(dir.api)/sqlite3-wasm.c
sqlite3-wasm.cses := $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c) sqlite3-wasm.cfiles := $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c)
sqlite3-wasmfs.cfiles := $(sqlite3-wasm.cfiles)
# sqlite3-wasm.o vs sqlite3-wasm.c: building against the latter # sqlite3-wasm.o vs sqlite3-wasm.c: building against the latter
# (predictably) results in a slightly faster binary. We're close # (predictably) results in a slightly faster binary. We're close
# enough to the target speed requirements that the 500ms makes a # enough to the target speed requirements that the 500ms makes a
@@ -655,7 +662,8 @@ sqlite3-wasm.cses := $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c)
# SQLITE3.xJS.EXPORT-DEFAULT is part of SQLITE3-WASMFS.xJS.RECIPE and # SQLITE3.xJS.EXPORT-DEFAULT is part of SQLITE3-WASMFS.xJS.RECIPE and
# SETUP_LIB_BUILD_MODE, factored into a separate piece to avoid code # SETUP_LIB_BUILD_MODE, factored into a separate piece to avoid code
# duplication. $1 is 1 if the build mode needs this workaround (esm, # duplication. $1 is 1 if the build mode needs this workaround (esm,
# bundler-friendly) and 0 if not (vanilla). # bundler-friendly, node) and 0 if not (vanilla). $2 must be empty for
# all builds except sqlite3-wasmfs.mjs, in which case it must be 1.
# #
# Reminder for ESM builds: even if we use -sEXPORT_ES6=0, emcc _still_ # Reminder for ESM builds: even if we use -sEXPORT_ES6=0, emcc _still_
# adds: # adds:
@@ -671,11 +679,13 @@ sqlite3-wasm.cses := $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c)
# https://github.com/emscripten-core/emscripten/issues/18237 # https://github.com/emscripten-core/emscripten/issues/18237
define SQLITE3.xJS.ESM-EXPORT-DEFAULT define SQLITE3.xJS.ESM-EXPORT-DEFAULT
if [ x1 = x$(1) ]; then \ if [ x1 = x$(1) ]; then \
echo "Fragile workaround for an Emscripten annoyance. See SQLITE3.xJS.RECIPE."; \ echo "Fragile workaround for emscripten/issues/18237. See SQLITE3.xJS.RECIPE."; \
sed -i -e '0,/^export default/{/^export default/d;}' $@ || exit $$?; \ sed -i -e '0,/^export default/{/^export default/d;}' $@ || exit $$?; \
if ! grep -q '^export default' $@; then \ if [ x != x$(2) ]; then \
echo "Cannot find export default." 1>&2; \ if ! grep -q '^export default' $@; then \
exit 1; \ echo "Cannot find export default." 1>&2; \
exit 1; \
fi; \
fi; \ fi; \
fi fi
endef endef
@@ -695,53 +705,57 @@ pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)
# SETUP_LIB_BUILD_MODE is a $(call)'able which sets up numerous pieces # SETUP_LIB_BUILD_MODE is a $(call)'able which sets up numerous pieces
# for one of the build modes. # for one of the build modes.
# #
# $1 = build mode name: one of $(JS_BUILD_MODES) # $1 = one of: sqlite3, sqlite3-wasmfs
# $2 = 1 for ESM build mode, else 0 # $2 = build mode name: one of $(JS_BUILD_MODES)
# $3 = resulting sqlite-api JS/MJS file # $3 = 1 for ESM build mode, else 0
# $4 = resulting JS/MJS file # $4 = resulting sqlite-api JS/MJS file
# $5 = -D... flags for $(bin.c-pp) # $5 = resulting JS/MJS file
# $6 = emcc -sXYZ flags (CURRENTLY UNUSED - was factored out) # $6 = -D... flags for $(bin.c-pp)
# $7 = emcc -sXYZ flags (CURRENTLY UNUSED - was factored out)
# #
# emcc.environment.$(1) must be set to a value for the -sENVIRONMENT flag. # Maintenance reminder: be careful not to introduce spaces around args
# ($1, $2), otherwise string concatenation will malfunction.
#
# emcc.environment.$(2) must be set to a value for the -sENVIRONMENT flag.
#
# $(cflags.$(1)) and $(cflags.$(1).$(2)) may be defined to append
# CFLAGS to a given build mode.
#
# $(emcc.flags.$(1)) and $(emcc.flags.$(1).$(2)) may be defined to
# append emcc-specific flags to a given build mode.
define SETUP_LIB_BUILD_MODE define SETUP_LIB_BUILD_MODE
$(info Setting up build [$(1)]: $(4)) $(info Setting up build [$(1)-$(2)]: $(5))
c-pp.D.$(1) := $(5) c-pp.D.$(1)-$(2) := $(6)
pre-js.js.$(1) := $$(dir.tmp)/pre-js.$(1).js $$(eval $$(call call-make-pre-post,$(1),$(2)))
$$(eval $$(call C-PP.FILTER,$$(pre-js.js.in),$$(pre-js.js.$(1)),$$(c-pp.D.$(1)))) emcc.flags.$(1).$(2) ?=
post-js.js.$(1) := $$(dir.tmp)/post-js.$(1).js emcc.flags.$(1).$(2) += $(7)
$$(eval $$(call C-PP.FILTER,$$(post-js.js.in),$$(post-js.js.$(1)),$$(c-pp.D.$(1)))) $$(eval $$(call C-PP.FILTER, $$(sqlite3-api.js.in), $(4), $(6)))
extern-post-js.js.$(1) := $$(dir.tmp)/extern-post-js.$(1).js $(5): $(4) $$(MAKEFILE) $$(sqlite3-wasm.cfiles) $$(EXPORTED_FUNCTIONS.api) $$(pre-post-$(1)-$(2).deps)
$$(eval $$(call C-PP.FILTER,$$(extern-post-js.js.in),$$(extern-post-js.js.$(1)),$$(c-pp.D.$(1))))
pre-post-common.flags.$(1) := \
$$(pre-post-common.flags) \
--post-js=$$(post-js.js.$(1)) \
--extern-post-js=$$(extern-post-js.js.$(1))
pre-post-jses.deps.$(1) := $$(pre-post-jses.deps.common) \
$$(post-js.js.$(1)) $$(extern-post-js.js.$(1))
$$(eval $$(call call-make-pre-post,sqlite3,$(1)))
emcc.flags.sqlite3.$(1) := $(6)
$$(eval $$(call C-PP.FILTER, $$(sqlite3-api.js.in), $(3), $(5)))
$(4): $(3) $$(MAKEFILE) $$(sqlite3-wasm.cses) $$(EXPORTED_FUNCTIONS.api) $$(pre-post-sqlite3.deps.$(1))
@echo "Building $$@ ..." @echo "Building $$@ ..."
$$(emcc.bin) -o $$@ $$(emcc_opt_full) $$(emcc.flags) \ $$(emcc.bin) -o $$@ $$(emcc_opt_full) $$(emcc.flags) \
$$(emcc.jsflags) \ $$(emcc.jsflags) \
-sENVIRONMENT=$$(emcc.environment.$(1)) \ -sENVIRONMENT=$$(emcc.environment.$(2)) \
$$(pre-post-sqlite3.flags.$(1)) $$(emcc.flags.sqlite3.$(1)) \ $$(pre-post-$(1)-$(2).flags) \
$$(cflags.common) $$(SQLITE_OPT) $$(cflags.wasm_extra_init) $$(sqlite3-wasm.cses) $$(emcc.flags.$(1)) $$(emcc.flags.$(1).$(2)) \
@$$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,$(2)) $$(cflags.common) $$(SQLITE_OPT) \
@case $(1) in \ $$(cflags.$(1)) $$(cflags.$(1).$(2)) \
$$(cflags.wasm_extra_init) $$(sqlite3-wasm.cfiles)
@$$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,$(3))
@dotwasm=$$(basename $$@).wasm; \
chmod -x $$$$dotwasm; \
$(maybe-wasm-strip) $$$$dotwasm; \
case $(2) in \
bundler-friendly|node) \ bundler-friendly|node) \
echo "Patching $(3) for sqlite3.wasm..."; \ echo "Patching $$@ for $(1).wasm..."; \
rm -f $$(dir.dout)/sqlite3-$(1).wasm; \ rm -f $$$$dotwasm; \
sed -i -e 's/sqlite3-$(1).wasm/sqlite3.wasm/g' $$@ || exit $$$$?; \ dotwasm=; \
sed -i -e 's/$(1)-$(2).wasm/$(1).wasm/g' $$@ || exit $$$$?; \
;; \ ;; \
esac esac; \
chmod -x $$(sqlite3.wasm) ls -la $$$$dotwasm $$@
$$(maybe-wasm-strip) $$(sqlite3.wasm) all: $(5)
@ls -la $@ $$(sqlite3.wasm) #quick: $(5)
all: $(4) CLEAN_FILES += $(4) $(5)
quick: $(4)
CLEAN_FILES += $(3) $(4)
endef endef
# ^^^ /SETUP_LIB_BUILD_MODE # ^^^ /SETUP_LIB_BUILD_MODE
######################################################################## ########################################################################
@@ -753,21 +767,24 @@ sqlite3-api-bundler-friendly.mjs := $(dir.dout)/sqlite3-api-bundler-friendly.mjs
sqlite3-bundler-friendly.mjs := $(dir.dout)/sqlite3-bundler-friendly.mjs sqlite3-bundler-friendly.mjs := $(dir.dout)/sqlite3-bundler-friendly.mjs
sqlite3-api-node.mjs := $(dir.dout)/sqlite3-api-node.mjs sqlite3-api-node.mjs := $(dir.dout)/sqlite3-api-node.mjs
sqlite3-node.mjs := $(dir.dout)/sqlite3-node.mjs sqlite3-node.mjs := $(dir.dout)/sqlite3-node.mjs
# Maintenance reminder: careful not to introduce spaces around args $1, $2 #$(info $(call SETUP_LIB_BUILD_MODE,sqlite3,vanilla,0, $(sqlite3-api.js), $(sqlite3.js)))
#$(info $(call SETUP_LIB_BUILD_MODE,vanilla,0, $(sqlite3-api.js), $(sqlite3.js))) $(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,vanilla,0,\
$(eval $(call SETUP_LIB_BUILD_MODE,vanilla,0, $(sqlite3-api.js), $(sqlite3.js))) $(sqlite3-api.js), $(sqlite3.js)))
$(eval $(call SETUP_LIB_BUILD_MODE,esm,1, $(sqlite3-api.mjs), $(sqlite3.mjs), \ $(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,esm,1,\
$(sqlite3-api.mjs), $(sqlite3.mjs), \
-Dtarget=es6-module, -sEXPORT_ES6 -sUSE_ES6_IMPORT_META)) -Dtarget=es6-module, -sEXPORT_ES6 -sUSE_ES6_IMPORT_META))
$(eval $(call SETUP_LIB_BUILD_MODE,bundler-friendly,1,\ $(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,bundler-friendly,1,\
$(sqlite3-api-bundler-friendly.mjs),$(sqlite3-bundler-friendly.mjs),\ $(sqlite3-api-bundler-friendly.mjs),$(sqlite3-bundler-friendly.mjs),\
$(c-pp.D.esm) -Dtarget=es6-bundler-friendly)) $(c-pp.D.sqlite3-esm) -Dtarget=es6-bundler-friendly))
$(eval $(call SETUP_LIB_BUILD_MODE,node,1,\ $(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,node,1,\
$(sqlite3-api-node.mjs),$(sqlite3-node.mjs),\ $(sqlite3-api-node.mjs),$(sqlite3-node.mjs),\
$(c-pp.D.bundler-friendly) -Dtarget=node)) $(c-pp.D.sqlite3-bundler-friendly) -Dtarget=node))
# The various -D... values used by *.c-pp.js include: # The various -D... values used by *.c-pp.js include:
# #
# -Dtarget=es6-module: for all ESM module builds # -Dtarget=es6-module: for all ESM module builds
# #
# -Dtarget=node: for node.js builds
#
# -Dtarget=es6-module -Dtarget=es6-bundler-friendly: intended for # -Dtarget=es6-module -Dtarget=es6-bundler-friendly: intended for
# "bundler-friendly" ESM module build. These have some restrictions # "bundler-friendly" ESM module build. These have some restrictions
# on how URL() objects are constructed in some contexts: URLs which # on how URL() objects are constructed in some contexts: URLs which
@@ -849,7 +866,7 @@ all: batch
# emcc.speedtest1.common = emcc flags used by multiple builds of speedtest1 # emcc.speedtest1.common = emcc flags used by multiple builds of speedtest1
# emcc.speedtest1 = emcc flags used by main build of speedtest1 # emcc.speedtest1 = emcc flags used by main build of speedtest1
emcc.speedtest1.common := $(emcc_opt_full) emcc.speedtest1.common := $(emcc_opt_full)
emcc.speedtest1 := emcc.speedtest1 := -I. -I$(dir $(sqlite3.canonical.c))
emcc.speedtest1 += -sENVIRONMENT=web emcc.speedtest1 += -sENVIRONMENT=web
emcc.speedtest1 += -sALLOW_MEMORY_GROWTH emcc.speedtest1 += -sALLOW_MEMORY_GROWTH
emcc.speedtest1 += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY)) emcc.speedtest1 += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY))
@@ -892,22 +909,24 @@ $(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api.main)
@{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api.main); } > $@ @{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api.main); } > $@
speedtest1.js := $(dir.dout)/speedtest1.js speedtest1.js := $(dir.dout)/speedtest1.js
speedtest1.wasm := $(dir.dout)/speedtest1.wasm speedtest1.wasm := $(dir.dout)/speedtest1.wasm
cflags.speedtest1 := $(cflags.common) -DSQLITE_SPEEDTEST1_WASM emcc.flags.speedtest1-vanilla := $(cflags.common) -DSQLITE_SPEEDTEST1_WASM
speedtest1.cses := $(speedtest1.c) $(sqlite3-wasm.c)
speedtest1.cfiles := $(speedtest1.c) $(sqlite3-wasm.c)
$(eval $(call call-make-pre-post,speedtest1,vanilla)) $(eval $(call call-make-pre-post,speedtest1,vanilla))
$(speedtest1.js): $(MAKEFILE) $(speedtest1.cses) \ $(speedtest1.js): $(MAKEFILE) $(speedtest1.cfiles) \
$(pre-post-speedtest1.deps.vanilla) \ $(pre-post-speedtest1-vanilla.deps) \
$(EXPORTED_FUNCTIONS.speedtest1) $(EXPORTED_FUNCTIONS.speedtest1)
@echo "Building $@ ..." @echo "Building $@ ..."
$(emcc.bin) \ $(emcc.bin) \
$(emcc.speedtest1) -I$(dir $(sqlite3.canonical.c)) \ $(emcc.speedtest1) \
$(emcc.speedtest1.common) \ $(emcc.speedtest1.common) \
$(cflags.speedtest1) $(pre-post-speedtest1.flags.vanilla) \ $(emcc.flags.speedtest1-vanilla) $(pre-post-speedtest1-vanilla.flags) \
$(SQLITE_OPT) \ $(SQLITE_OPT) \
-USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c) \ -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c) \
$(speedtest1.exit-runtime0) \ $(speedtest1.exit-runtime0) \
-o $@ $(speedtest1.cses) -lm -o $@ $(speedtest1.cfiles) -lm
$(maybe-wasm-strip) $(speedtest1.wasm) $(maybe-wasm-strip) $(speedtest1.wasm)
chmod -x $(speedtest1.wasm)
ls -la $@ $(speedtest1.wasm) ls -la $@ $(speedtest1.wasm)
speedtest1: $(speedtest1.js) speedtest1: $(speedtest1.js)
@@ -933,13 +952,14 @@ CLEAN_FILES += $(speedtest1.js) $(speedtest1.wasm)
# #
# To create those, we filter tester1.c-pp.js with $(bin.c-pp)... # 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.js))
$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.esm))) $(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.sqlite3-esm)))
$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1.html)) $(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))) $(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.sqlite3-esm)))
tester1: tester1.js tester1.mjs tester1.html tester1-esm.html tester1: tester1.js tester1.mjs tester1.html tester1-esm.html
# Note that we do not include $(sqlite3-bundler-friendly.mjs) in this # Note that we do not include $(sqlite3-bundler-friendly.mjs) in this
# because bundlers are client-specific. # because bundlers are client-specific.
all quick: tester1 all quick: tester1
quick: $(sqlite3.js)
######################################################################## ########################################################################
# Convenience rules to rebuild with various -Ox levels. Much # Convenience rules to rebuild with various -Ox levels. Much
@@ -959,8 +979,6 @@ o1: clean
$(MAKE) -e "emcc_opt=-O1 $(o-xtra)" $(MAKE) -e "emcc_opt=-O1 $(o-xtra)"
o2: clean o2: clean
$(MAKE) -j2 -e "emcc_opt=-O2 $(o-xtra)" $(MAKE) -j2 -e "emcc_opt=-O2 $(o-xtra)"
qo2: clean
$(MAKE) -j2 -e "emcc_opt=-O2 $(o-xtra)" quick
o3: clean o3: clean
$(MAKE) -e "emcc_opt=-O3 $(o-xtra)" $(MAKE) -e "emcc_opt=-O3 $(o-xtra)"
os: clean os: clean
@@ -968,8 +986,6 @@ os: clean
$(MAKE) -e "emcc_opt=-Os $(o-xtra)" $(MAKE) -e "emcc_opt=-Os $(o-xtra)"
oz: clean oz: clean
$(MAKE) -j2 -e "emcc_opt=-Oz $(o-xtra)" $(MAKE) -j2 -e "emcc_opt=-Oz $(o-xtra)"
qoz: clean
$(MAKE) -j2 -e "emcc_opt=-Oz $(o-xtra)" quick
######################################################################## ########################################################################
# Sub-makes... # Sub-makes...
@@ -981,6 +997,8 @@ include fiddle.make
ifneq (,$(filter wasmfs,$(MAKECMDGOALS))) ifneq (,$(filter wasmfs,$(MAKECMDGOALS)))
wasmfs.enable ?= 1 wasmfs.enable ?= 1
else else
# Unconditionally enable wasmfs for [dist]clean so that the wasmfs
# sub-make can clean up.
wasmfs.enable ?= $(if $(filter %clean,$(MAKECMDGOALS)),1,0) wasmfs.enable ?= $(if $(filter %clean,$(MAKECMDGOALS)),1,0)
endif endif
ifeq (1,$(wasmfs.enable)) ifeq (1,$(wasmfs.enable))

View File

@@ -82,7 +82,7 @@ features in the apps which use them.
# Testing on a remote machine that is accessed via SSH # Testing on a remote machine that is accessed via SSH
*NB: The following are developer notes, last validated on 2022-08-18* *NB: The following are developer notes, last validated on 2023-07-19*
* Remote: Install git, emsdk, and althttpd * Remote: Install git, emsdk, and althttpd
* Use a [version of althttpd][althttpd] from * Use a [version of althttpd][althttpd] from
@@ -90,16 +90,17 @@ features in the apps which use them.
* Remote: Install the SQLite source tree. CD to ext/wasm * Remote: Install the SQLite source tree. CD to ext/wasm
* Remote: "`make`" to build WASM * Remote: "`make`" to build WASM
* Remote: `althttpd --enable-sab --port 8080 --popup` * Remote: `althttpd --enable-sab --port 8080 --popup`
* Local: `ssh -L 8180:localhost:8080 remote` * Local: `ssh -L 8180:remote:8080 remote`
* Local: Point your web-browser at http://localhost:8180/index.html * Local: Point your web-browser at http://localhost:8180/index.html
In order to enable [SharedArrayBuffers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer), In order to enable [SharedArrayBuffer][], the web-browser requires
the web-browser requires that the two extra Cross-Origin lines be present that the two extra Cross-Origin lines be present in HTTP reply headers
in HTTP reply headers and that the request must come from "localhost". and that the request must come from "localhost" (_or_ over an SSL
Since the web-server is on a different machine from connection). Since the web-server is on a different machine from the
the web-broser, the localhost requirement means that the connection must be tunneled web-broser, the localhost requirement means that the connection must
using SSH. be tunneled using SSH.
[emscripten]: https://emscripten.org [emscripten]: https://emscripten.org
[althttpd]: https://sqlite.org/althttpd [althttpd]: https://sqlite.org/althttpd
[SharedArrayBuffer]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer

View File

@@ -83,15 +83,18 @@ browser client:
helpers for use by downstream code which creates `sqlite3_vfs` helpers for use by downstream code which creates `sqlite3_vfs`
and `sqlite3_module` implementations. and `sqlite3_module` implementations.
- **`sqlite3-vfs-opfs.c-pp.js`**\ - **`sqlite3-vfs-opfs.c-pp.js`**\
is an sqlite3 VFS implementation which supports Google Chrome's is an sqlite3 VFS implementation which supports the Origin-Private
Origin-Private FileSystem (OPFS) as a storage layer to provide FileSystem (OPFS) as a storage layer to provide persistent storage
persistent storage for database files in a browser. It requires... for database files in a browser. It requires...
- **`sqlite3-opfs-async-proxy.js`**\ - **`sqlite3-opfs-async-proxy.js`**\
is the asynchronous backend part of the OPFS proxy. It speaks is the asynchronous backend part of the OPFS proxy. It speaks
directly to the (async) OPFS API and channels those results back directly to the (async) OPFS API and channels those results back
to its synchronous counterpart. This file, because it must be to its synchronous counterpart. This file, because it must be
started in its own Worker, is not part of the amalgamation. started in its own Worker, is not part of the amalgamation.
- **`api/sqlite3-api-cleanup.js`**\ - **`sqlite3-vfs-opfs-sahpool.c-pp.js`**\
is another sqlite3 VFS supporting the OPFS, but uses a completely
different approach that the above-listed one.
- **`sqlite3-api-cleanup.js`**\
The previous files do not immediately extend the library. Instead The previous files do not immediately extend the library. Instead
they add callback functions to be called during its they add callback functions to be called during its
bootstrapping. Some also temporarily create global objects in order bootstrapping. Some also temporarily create global objects in order
@@ -108,13 +111,15 @@ browser client:
with `c-pp`](#c-pp), noting that such preprocessing may be applied with `c-pp`](#c-pp), noting that such preprocessing may be applied
after all of the relevant files are concatenated. That extension is after all of the relevant files are concatenated. That extension is
used primarily to keep the code maintainers cognisant of the fact that used primarily to keep the code maintainers cognisant of the fact that
those files contain constructs which will not run as-is in JavaScript. those files contain constructs which may not run as-is in any given
JavaScript environment.
The build process glues those files together, resulting in The build process glues those files together, resulting in
`sqlite3-api.js`, which is everything except for the `post-js-*.js` `sqlite3-api.js`, which is everything except for the
files, and `sqlite3.js`, which is the Emscripten-generated amalgamated `pre/post-js-*.js` files, and `sqlite3.js`, which is the
output and includes the `post-js-*.js` parts, as well as the Emscripten-generated amalgamated output and includes the
Emscripten-provided module loading pieces. `pre/post-js-*.js` parts, as well as the Emscripten-provided module
loading pieces.
The non-JS outlier file is `sqlite3-wasm.c`: it is a proxy for The non-JS outlier file is `sqlite3-wasm.c`: it is a proxy for
`sqlite3.c` which `#include`'s that file and adds a couple more `sqlite3.c` which `#include`'s that file and adds a couple more
@@ -152,8 +157,8 @@ Preprocessing of Source Files
------------------------------------------------------------------------ ------------------------------------------------------------------------
Certain files in the build require preprocessing to filter in/out Certain files in the build require preprocessing to filter in/out
parts which differ between vanilla JS builds and ES6 Module parts which differ between vanilla JS, ES6 Modules, and node.js
(a.k.a. esm) builds. The preprocessor application itself is in builds. The preprocessor application itself is in
[`c-pp.c`](/file/ext/wasm/c-pp.c) and the complete technical details [`c-pp.c`](/file/ext/wasm/c-pp.c) and the complete technical details
of such preprocessing are maintained in of such preprocessing are maintained in
[`GNUMakefile`](/file/ext/wasm/GNUmakefile). [`GNUMakefile`](/file/ext/wasm/GNUmakefile).

View File

@@ -23,10 +23,7 @@ const toExportForESM =
impls which Emscripten installs at some point in the file above impls which Emscripten installs at some point in the file above
this. this.
*/ */
const originalInit = const originalInit = 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){ if(!originalInit){
throw new Error("Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build."); throw new Error("Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build.");
} }
@@ -66,18 +63,16 @@ const toExportForESM =
//console.warn("Using replaced sqlite3InitModule()",globalThis.location); //console.warn("Using replaced sqlite3InitModule()",globalThis.location);
return originalInit(...args).then((EmscriptenModule)=>{ return originalInit(...args).then((EmscriptenModule)=>{
if('undefined'!==typeof WorkerGlobalScope && if('undefined'!==typeof WorkerGlobalScope &&
(EmscriptenModule['ENVIRONMENT_IS_PTHREAD'] EmscriptenModule['ENVIRONMENT_IS_PTHREAD']){
|| EmscriptenModule['_pthread_self']
|| 'function'===typeof threadAlert
|| globalThis?.location?.pathname?.endsWith?.('.worker.js')
)){
/** Workaround for wasmfs-generated worker, which calls this /** Workaround for wasmfs-generated worker, which calls this
routine from each individual thread and requires that its routine from each individual thread and requires that its
argument be returned. All of the criteria above are fragile, argument be returned. The conditional criteria above are
based solely on inspection of the offending code, not public fragile, based solely on inspection of the offending code,
Emscripten details. */ not public Emscripten details. */
//console.warn("sqlite3InitModule() returning E-module.",EmscriptenModule);
return EmscriptenModule; return EmscriptenModule;
} }
//console.warn("sqlite3InitModule() returning sqlite3 object.");
const s = EmscriptenModule.sqlite3; const s = EmscriptenModule.sqlite3;
s.scriptInfo = initModuleState; s.scriptInfo = initModuleState;
//console.warn("sqlite3.scriptInfo =",s.scriptInfo); //console.warn("sqlite3.scriptInfo =",s.scriptInfo);
@@ -124,5 +119,5 @@ const toExportForESM =
return globalThis.sqlite3InitModule /* required for ESM */; return globalThis.sqlite3InitModule /* required for ESM */;
})(); })();
//#if target=es6-module //#if target=es6-module
export default toExportForESM; export { toExportForESM as default, toExportForESM as sqlite3InitModule }
//#endif //#endif

View File

@@ -23,7 +23,7 @@ if('undefined' !== typeof Module){ // presumably an Emscripten build
const SABC = Object.assign( const SABC = Object.assign(
Object.create(null), { Object.create(null), {
exports: Module['asm'], exports: Module['asm'],
memory: Module.wasmMemory /* gets set if built with -sIMPORT_MEMORY */ memory: Module.wasmMemory /* gets set if built with -sIMPORTED_MEMORY */
}, },
globalThis.sqlite3ApiConfig || {} globalThis.sqlite3ApiConfig || {}
); );

View File

@@ -53,7 +53,7 @@
- `memory`[^1]: optional WebAssembly.Memory object, defaulting to - `memory`[^1]: optional WebAssembly.Memory object, defaulting to
`exports.memory`. In Emscripten environments this should be set `exports.memory`. In Emscripten environments this should be set
to `Module.wasmMemory` if the build uses `-sIMPORT_MEMORY`, or be to `Module.wasmMemory` if the build uses `-sIMPORTED_MEMORY`, or be
left undefined/falsy to default to `exports.memory` when using left undefined/falsy to default to `exports.memory` when using
WASM-exported memory. WASM-exported memory.
@@ -88,12 +88,12 @@
can be replaced with (e.g.) empty functions to squelch all such can be replaced with (e.g.) empty functions to squelch all such
output. output.
- `wasmfsOpfsDir`[^1]: As of 2022-12-17, this feature does not - `wasmfsOpfsDir`[^1]: Specifies the "mount point" of the OPFS-backed
currently work due to incompatible Emscripten-side changes made filesystem in WASMFS-capable builds.
in the WASMFS+OPFS combination. This option is currently ignored.
[^1] = This property may optionally be a function, in which case this
function re-assigns calls that function to fetch the value, [^1] = This property may optionally be a function, in which case
this function calls that function to fetch the value,
enabling delayed evaluation. enabling delayed evaluation.
The returned object is the top-level sqlite3 namespace object. The returned object is the top-level sqlite3 namespace object.
@@ -125,11 +125,11 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
log: console.log.bind(console), log: console.log.bind(console),
wasmfsOpfsDir: '/opfs', wasmfsOpfsDir: '/opfs',
/** /**
useStdAlloc is just for testing an allocator discrepancy. The useStdAlloc is just for testing allocator discrepancies. The
docs guarantee that this is false in the canonical builds. For docs guarantee that this is false in the canonical builds. For
99% of purposes it doesn't matter which allocators we use, but 99% of purposes it doesn't matter which allocators we use, but
it becomes significant with, e.g., sqlite3_deserialize() it becomes significant with, e.g., sqlite3_deserialize() and
and certain wasm.xWrap.resultAdapter()s. certain wasm.xWrap.resultAdapter()s.
*/ */
useStdAlloc: false useStdAlloc: false
}, apiConfig || {}); }, apiConfig || {});
@@ -149,11 +149,6 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
config[k] = config[k](); config[k] = config[k]();
} }
}); });
config.wasmOpfsDir =
/* 2022-12-17: WASMFS+OPFS can no longer be activated from the
main thread (aborts via a failed assert() if it's attempted),
which eliminates any(?) benefit to supporting it. */ false;
/** /**
The main sqlite3 binding API gets installed into this object, The main sqlite3 binding API gets installed into this object,
mimicking the C API as closely as we can. The numerous members mimicking the C API as closely as we can. The numerous members
@@ -809,7 +804,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|| toss3("Missing API config.exports (WASM module exports)."), || toss3("Missing API config.exports (WASM module exports)."),
/** /**
When Emscripten compiles with `-sIMPORT_MEMORY`, it When Emscripten compiles with `-sIMPORTED_MEMORY`, it
initalizes the heap and imports it into wasm, as opposed to initalizes the heap and imports it into wasm, as opposed to
the other way around. In this case, the memory is not the other way around. In this case, the memory is not
available via this.exports.memory. available via this.exports.memory.
@@ -1177,31 +1172,31 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
/** State for sqlite3_wasmfs_opfs_dir(). */ /** State for sqlite3_wasmfs_opfs_dir(). */
let __wasmfsOpfsDir = undefined; let __wasmfsOpfsDir = undefined;
/** /**
2022-12-17: incompatible WASMFS changes have made WASMFS+OPFS
unavailable from the main thread, which eliminates the most
significant benefit of supporting WASMFS. This function is now a
no-op which always returns a falsy value. Before that change,
this function behaved as documented below (and how it will again
if we can find a compelling reason to support it).
If the wasm environment has a WASMFS/OPFS-backed persistent If the wasm environment has a WASMFS/OPFS-backed persistent
storage directory, its path is returned by this function. If it storage directory, its path is returned by this function. If it
does not then it returns "" (noting that "" is a falsy value). does not then it returns "" (noting that "" is a falsy value).
The first time this is called, this function inspects the current The first time this is called, this function inspects the current
environment to determine whether persistence support is available environment to determine whether persistence support is available
and, if it is, enables it (if needed). and, if it is, enables it (if needed). After the first call it
always returns the cached result.
This function currently only recognizes the WASMFS/OPFS storage If the returned string is not empty, any files stored under the
combination and its path refers to storage rooted in the given path (recursively) are housed in OPFS storage. If the
Emscripten-managed virtual filesystem. returned string is empty, this particular persistent storage
option is not available on the client.
Though the mount point name returned by this function is intended
to remain stable, clients should not hard-coded it anywhere. Always call this function to get the path.
Note that this function is a no-op in must builds of this
library, as the WASMFS capability requires a custom
build.
*/ */
capi.sqlite3_wasmfs_opfs_dir = function(){ capi.sqlite3_wasmfs_opfs_dir = function(){
if(undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir; if(undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir;
// If we have no OPFS, there is no persistent dir // If we have no OPFS, there is no persistent dir
const pdir = config.wasmfsOpfsDir; const pdir = config.wasmfsOpfsDir;
console.error("sqlite3_wasmfs_opfs_dir() can no longer work due "+
"to incompatible WASMFS changes. It will be removed.");
if(!pdir if(!pdir
|| !globalThis.FileSystemHandle || !globalThis.FileSystemHandle
|| !globalThis.FileSystemDirectoryHandle || !globalThis.FileSystemDirectoryHandle
@@ -1223,8 +1218,6 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
}; };
/** /**
Experimental and subject to change or removal.
Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a
non-empty string and the given name starts with (that string + non-empty string and the given name starts with (that string +
'/'), else returns false. '/'), else returns false.
@@ -1234,13 +1227,6 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
return (p && name) ? name.startsWith(p+'/') : false; return (p && name) ? name.startsWith(p+'/') : false;
}; };
// This bit is highly arguable and is incompatible with the fiddle shell.
if(false && 0===wasm.exports.sqlite3_vfs_find(0)){
/* Assume that sqlite3_initialize() has not yet been called.
This will be the case in an SQLITE_OS_KV build. */
wasm.exports.sqlite3_initialize();
}
/** /**
Given an `sqlite3*`, an sqlite3_vfs name, and an optional db name Given an `sqlite3*`, an sqlite3_vfs name, and an optional db name
(defaulting to "main"), returns a truthy value (see below) if (defaulting to "main"), returns a truthy value (see below) if
@@ -1875,6 +1861,9 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
client: undefined, client: undefined,
/** /**
This function is not part of the public interface, but a
piece of internal bootstrapping infrastructure.
Performs any optional asynchronous library-level initialization Performs any optional asynchronous library-level initialization
which might be required. This function returns a Promise which which might be required. This function returns a Promise which
resolves to the sqlite3 namespace object. Any error in the resolves to the sqlite3 namespace object. Any error in the
@@ -1890,27 +1879,19 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
then it must be called by client-level code, which must not use then it must be called by client-level code, which must not use
the library until the returned promise resolves. the library until the returned promise resolves.
Bug: if called while a prior call is still resolving, the 2nd If called multiple times it will return the same promise on
call will resolve prematurely, before the 1st call has finished subsequent calls. The current build setup precludes that
resolving. The current build setup precludes that possibility, possibility, so it's only a hypothetical problem if/when this
so it's only a hypothetical problem if/when this function function ever needs to be invoked by clients.
ever needs to be invoked by clients.
In Emscripten-based builds, this function is called In Emscripten-based builds, this function is called
automatically and deleted from this object. automatically and deleted from this object.
*/ */
asyncPostInit: async function(){ asyncPostInit: async function ff(){
let lip = sqlite3ApiBootstrap.initializersAsync; if(ff.isReady instanceof Promise) return ff.isReady;
let lia = sqlite3ApiBootstrap.initializersAsync;
delete sqlite3ApiBootstrap.initializersAsync; delete sqlite3ApiBootstrap.initializersAsync;
if(!lip || !lip.length) return Promise.resolve(sqlite3); const postInit = async ()=>{
lip = lip.map((f)=>{
const p = (f instanceof Promise) ? f : f(sqlite3);
return p.catch((e)=>{
console.error("an async sqlite3 initializer failed:",e);
throw e;
});
});
const postInit = ()=>{
if(!sqlite3.__isUnderTest){ if(!sqlite3.__isUnderTest){
/* Delete references to internal-only APIs which are used by /* Delete references to internal-only APIs which are used by
some initializers. Retain them when running in test mode some initializers. Retain them when running in test mode
@@ -1919,23 +1900,25 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
/* It's conceivable that we might want to expose /* It's conceivable that we might want to expose
StructBinder to client-side code, but it's only useful if StructBinder to client-side code, but it's only useful if
clients build their own sqlite3.wasm which contains their clients build their own sqlite3.wasm which contains their
one C struct types. */ own C struct types. */
delete sqlite3.StructBinder; delete sqlite3.StructBinder;
} }
return sqlite3; return sqlite3;
}; };
if(1){ const catcher = (e)=>{
/* Run all initializers in sequence. The advantage is that it config.error("an async sqlite3 initializer failed:",e);
allows us to have post-init cleanup defined outside of this throw e;
routine at the end of the list and have it run at a };
well-defined time. */ if(!lia || !lia.length){
let p = lip.shift(); return ff.isReady = postInit().catch(catcher);
while(lip.length) p = p.then(lip.shift());
return p.then(postInit);
}else{
/* Run them in an arbitrary order. */
return Promise.all(lip).then(postInit);
} }
lia = lia.map((f)=>{
return (f instanceof Function) ? async x=>f(sqlite3) : f;
});
lia.push(postInit);
let p = Promise.resolve(sqlite3);
while(lia.length) p = p.then(lia.shift());
return ff.isReady = p.catch(catcher);
}, },
/** /**
scriptInfo ideally gets injected into this object by the scriptInfo ideally gets injected into this object by the
@@ -1995,7 +1978,7 @@ globalThis.sqlite3ApiBootstrap.initializers = [];
specifically for initializers which are asynchronous. All entries in specifically for initializers which are asynchronous. All entries in
this list must be either async functions, non-async functions which this list must be either async functions, non-async functions which
return a Promise, or a Promise. Each function in the list is called return a Promise, or a Promise. Each function in the list is called
with the sqlite3 ojbect as its only argument. with the sqlite3 object as its only argument.
The resolved value of any Promise is ignored and rejection will kill The resolved value of any Promise is ignored and rejection will kill
the asyncPostInit() process (at an indeterminate point because all the asyncPostInit() process (at an indeterminate point because all

View File

@@ -35,6 +35,9 @@
https://developer.chrome.com/blog/sync-methods-for-accesshandles/ https://developer.chrome.com/blog/sync-methods-for-accesshandles/
Firefox v111 and Safari 16.4, both released in March 2023, also
include this.
We cannot change to the sync forms at this point without breaking We cannot change to the sync forms at this point without breaking
clients who use Chrome v104-ish or higher. truncate(), getSize(), clients who use Chrome v104-ish or higher. truncate(), getSize(),
flush(), and close() are now (as of v108) synchronous. Calling them flush(), and close() are now (as of v108) synchronous. Calling them

View File

@@ -295,7 +295,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- If `struct.$zName` is falsy and the entry has a string-type - If `struct.$zName` is falsy and the entry has a string-type
`name` property, `struct.$zName` is set to the C-string form of `name` property, `struct.$zName` is set to the C-string form of
that `name` value before registerVfs() is called. that `name` value before registerVfs() is called. That string
gets added to the on-dispose state of the struct.
On success returns this object. Throws on error. On success returns this object. Throws on error.
*/ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
//#ifnot target=node
/* /*
2022-09-18 2022-09-18
@@ -23,7 +24,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
installOpfsVfs() returns a Promise which, on success, installs an installOpfsVfs() returns a Promise which, on success, installs an
sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs
which accept a VFS. It is intended to be called via which accept a VFS. It is intended to be called via
sqlite3ApiBootstrap.initializersAsync or an equivalent mechanism. sqlite3ApiBootstrap.initializers or an equivalent mechanism.
The installed VFS uses the Origin-Private FileSystem API for The installed VFS uses the Origin-Private FileSystem API for
all file storage. On error it is rejected with an exception all file storage. On error it is rejected with an exception
@@ -101,6 +102,10 @@ const installOpfsVfs = function callee(options){
options = Object.create(null); options = Object.create(null);
} }
const urlParams = new URL(globalThis.location.href).searchParams; const urlParams = new URL(globalThis.location.href).searchParams;
if(urlParams.has('opfs-disable')){
//sqlite3.config.warn('Explicitly not installing "opfs" VFS due to opfs-disable flag.');
return Promise.resolve(sqlite3);
}
if(undefined===options.verbose){ if(undefined===options.verbose){
options.verbose = urlParams.has('opfs-verbose') options.verbose = urlParams.has('opfs-verbose')
? (+urlParams.get('opfs-verbose') || 2) : 1; ? (+urlParams.get('opfs-verbose') || 2) : 1;
@@ -118,11 +123,11 @@ const installOpfsVfs = function callee(options){
options.proxyUri = options.proxyUri(); options.proxyUri = options.proxyUri();
} }
const thePromise = new Promise(function(promiseResolve_, promiseReject_){ const thePromise = new Promise(function(promiseResolve_, promiseReject_){
const loggers = { const loggers = [
0:sqlite3.config.error, sqlite3.config.error,
1:sqlite3.config.warn, sqlite3.config.warn,
2:sqlite3.config.log sqlite3.config.log
}; ];
const logImpl = (level,...args)=>{ const logImpl = (level,...args)=>{
if(options.verbose>level) loggers[level]("OPFS syncer:",...args); if(options.verbose>level) loggers[level]("OPFS syncer:",...args);
}; };
@@ -191,17 +196,18 @@ const installOpfsVfs = function callee(options){
s.count = s.time = 0; s.count = s.time = 0;
} }
}/*metrics*/; }/*metrics*/;
const opfsVfs = new sqlite3_vfs();
const opfsIoMethods = new sqlite3_io_methods(); const opfsIoMethods = new sqlite3_io_methods();
const opfsVfs = new sqlite3_vfs()
.addOnDispose( ()=>opfsIoMethods.dispose());
let promiseWasRejected = undefined; let promiseWasRejected = undefined;
const promiseReject = (err)=>{ const promiseReject = (err)=>{
promiseWasRejected = true; promiseWasRejected = true;
opfsVfs.dispose(); opfsVfs.dispose();
return promiseReject_(err); return promiseReject_(err);
}; };
const promiseResolve = (value)=>{ const promiseResolve = ()=>{
promiseWasRejected = false; promiseWasRejected = false;
return promiseResolve_(value); return promiseResolve_(sqlite3);
}; };
const W = const W =
//#if target=es6-bundler-friendly //#if target=es6-bundler-friendly
@@ -235,17 +241,17 @@ const installOpfsVfs = function callee(options){
? new sqlite3_vfs(pDVfs) ? new sqlite3_vfs(pDVfs)
: null /* dVfs will be null when sqlite3 is built with : null /* dVfs will be null when sqlite3 is built with
SQLITE_OS_OTHER. */; SQLITE_OS_OTHER. */;
opfsIoMethods.$iVersion = 1;
opfsVfs.$iVersion = 2/*yes, two*/; opfsVfs.$iVersion = 2/*yes, two*/;
opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
opfsVfs.$mxPathname = 1024/*sure, why not?*/; opfsVfs.$mxPathname = 1024/*sure, why not?*/;
opfsVfs.$zName = wasm.allocCString("opfs"); opfsVfs.$zName = wasm.allocCString("opfs");
// All C-side memory of opfsVfs is zeroed out, but just to be explicit: // All C-side memory of opfsVfs is zeroed out, but just to be explicit:
opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null; opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null;
opfsVfs.ondispose = [ opfsVfs.addOnDispose(
'$zName', opfsVfs.$zName, '$zName', opfsVfs.$zName,
'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null), 'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null)
'cleanup opfsIoMethods', ()=>opfsIoMethods.dispose() );
];
/** /**
Pedantic sidebar about opfsVfs.ondispose: the entries in that array Pedantic sidebar about opfsVfs.ondispose: the entries in that array
are items to clean up when opfsVfs.dispose() is called, but in this are items to clean up when opfsVfs.dispose() is called, but in this
@@ -298,6 +304,7 @@ const installOpfsVfs = function callee(options){
lock contention to free up. lock contention to free up.
*/ */
state.asyncIdleWaitTime = 150; state.asyncIdleWaitTime = 150;
/** /**
Whether the async counterpart should log exceptions to Whether the async counterpart should log exceptions to
the serialization channel. That produces a great deal of the serialization channel. That produces a great deal of
@@ -832,22 +839,19 @@ const installOpfsVfs = function callee(options){
/* If it turns out that we need to adjust for timezone, see: /* If it turns out that we need to adjust for timezone, see:
https://stackoverflow.com/a/11760121/1458521 */ https://stackoverflow.com/a/11760121/1458521 */
wasm.poke(pOut, 2440587.5 + (new Date().getTime()/86400000), wasm.poke(pOut, 2440587.5 + (new Date().getTime()/86400000),
'double'); 'double');
return 0; return 0;
}, },
xCurrentTimeInt64: function(pVfs,pOut){ xCurrentTimeInt64: function(pVfs,pOut){
// TODO: confirm that this calculation is correct
wasm.poke(pOut, (2440587.5 * 86400000) + new Date().getTime(), wasm.poke(pOut, (2440587.5 * 86400000) + new Date().getTime(),
'i64'); 'i64');
return 0; return 0;
}, },
xDelete: function(pVfs, zName, doSyncDir){ xDelete: function(pVfs, zName, doSyncDir){
mTimeStart('xDelete'); mTimeStart('xDelete');
opRun('xDelete', wasm.cstrToJs(zName), doSyncDir, false); const rc = opRun('xDelete', wasm.cstrToJs(zName), doSyncDir, false);
/* We're ignoring errors because we cannot yet differentiate
between harmless and non-harmless failures. */
mTimeEnd(); mTimeEnd();
return 0; return rc;
}, },
xFullPathname: function(pVfs,zName,nOut,pOut){ xFullPathname: function(pVfs,zName,nOut,pOut){
/* Until/unless we have some notion of "current dir" /* Until/unless we have some notion of "current dir"
@@ -1089,7 +1093,7 @@ const installOpfsVfs = function callee(options){
propagate any exception on error, rather than returning false. propagate any exception on error, rather than returning false.
*/ */
opfsUtil.unlink = async function(fsEntryName, recursive = false, opfsUtil.unlink = async function(fsEntryName, recursive = false,
throwOnError = false){ throwOnError = false){
try { try {
const [hDir, filenamePart] = const [hDir, filenamePart] =
await opfsUtil.getDirForFilename(fsEntryName, false); await opfsUtil.getDirForFilename(fsEntryName, false);
@@ -1186,19 +1190,23 @@ const installOpfsVfs = function callee(options){
contention. */ contention. */
sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000); sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000);
sqlite3.capi.sqlite3_exec(oo1Db, [ sqlite3.capi.sqlite3_exec(oo1Db, [
/* Truncate journal mode is faster than delete for /* As of July 2023, the PERSIST journal mode on OPFS is
this vfs, per speedtest1. That gap seems to have closed with somewhat slower than DELETE or TRUNCATE (it was faster
Chrome version 108 or 109, but "persist" is very roughly 5-6% before Chrome version 108 or 109). TRUNCATE and DELETE
faster than truncate in initial tests. have very similar performance on OPFS.
For later analysis: Roy Hashimoto notes that TRUNCATE Roy Hashimoto notes that TRUNCATE and PERSIST modes may
and PERSIST modes may decrease OPFS concurrency because decrease OPFS concurrency because multiple connections
multiple connections can open the journal file in those can open the journal file in those modes:
modes:
https://github.com/rhashimoto/wa-sqlite/issues/68 https://github.com/rhashimoto/wa-sqlite/issues/68
Given that, and the fact that testing has not revealed
any appreciable difference between performance of
TRUNCATE and DELETE modes on OPFS, we currently (as of
2023-07-13) default to DELETE mode.
*/ */
"pragma journal_mode=persist;", "pragma journal_mode=DELETE;",
/* /*
This vfs benefits hugely from cache on moderate/large This vfs benefits hugely from cache on moderate/large
speedtest1 --size 50 and --size 100 workloads. We speedtest1 --size 50 and --size 100 workloads. We
@@ -1319,10 +1327,10 @@ const installOpfsVfs = function callee(options){
sqlite3.opfs = opfsUtil; sqlite3.opfs = opfsUtil;
opfsUtil.rootDirectory = d; opfsUtil.rootDirectory = d;
log("End of OPFS sqlite3_vfs setup.", opfsVfs); log("End of OPFS sqlite3_vfs setup.", opfsVfs);
promiseResolve(sqlite3); promiseResolve();
}).catch(promiseReject); }).catch(promiseReject);
}else{ }else{
promiseResolve(sqlite3); promiseResolve();
} }
}catch(e){ }catch(e){
error(e); error(e);
@@ -1359,7 +1367,10 @@ globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
}); });
}catch(e){ }catch(e){
sqlite3.config.error("installOpfsVfs() exception:",e); sqlite3.config.error("installOpfsVfs() exception:",e);
throw e; return Promise.reject(e);
} }
}); });
}/*sqlite3ApiBootstrap.initializers.push()*/); }/*sqlite3ApiBootstrap.initializers.push()*/);
//#else
/* The OPFS VFS parts are elided from builds targeting node.js. */
//#endif target=node

View File

@@ -1,69 +0,0 @@
/**
Dummy function stubs to get sqlite3.c compiling with
wasi-sdk. This requires, in addition:
-D_WASI_EMULATED_MMAN -D_WASI_EMULATED_GETPID
-lwasi-emulated-getpid
*/
typedef unsigned mode_t;
int fchmod(int fd, mode_t mode);
int fchmod(int fd, mode_t mode){
return (fd && mode) ? 0 : 0;
}
typedef unsigned uid_t;
typedef uid_t gid_t;
int fchown(int fd, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group){
return (fd && owner && group) ? 0 : 0;
}
uid_t geteuid(void);
uid_t geteuid(void){return 0;}
#if !defined(F_WRLCK)
enum {
F_WRLCK,
F_RDLCK,
F_GETLK,
F_SETLK,
F_UNLCK
};
#endif
#undef HAVE_PREAD
#include <wasi/api.h>
#define WASM__KEEP __attribute__((used))
#if 0
/**
wasi-sdk cannot build sqlite3's default VFS without at least the following
functions. They are apparently syscalls which clients have to implement or
otherwise obtain.
https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md
*/
environ_get
environ_sizes_get
clock_time_get
fd_close
fd_fdstat_get
fd_fdstat_set_flags
fd_filestat_get
fd_filestat_set_size
fd_pread
fd_prestat_get
fd_prestat_dir_name
fd_read
fd_seek
fd_sync
fd_write
path_create_directory
path_filestat_get
path_filestat_set_times
path_open
path_readlink
path_remove_directory
path_unlink_file
poll_oneoff
proc_exit
#endif

View File

@@ -151,7 +151,7 @@
/**********************************************************************/ /**********************************************************************/
/* SQLITE_T... */ /* SQLITE_T... */
#ifndef SQLITE_TEMP_STORE #ifndef SQLITE_TEMP_STORE
# define SQLITE_TEMP_STORE 3 # define SQLITE_TEMP_STORE 2
#endif #endif
#ifndef SQLITE_THREADSAFE #ifndef SQLITE_THREADSAFE
# define SQLITE_THREADSAFE 0 # define SQLITE_THREADSAFE 0

View File

@@ -40,8 +40,41 @@ span.labeled-input {
.tests-pass { background-color: green; color: white } .tests-pass { background-color: green; color: white }
.tests-fail { background-color: red; color: yellow } .tests-fail { background-color: red; color: yellow }
.faded { opacity: 0.5; } .faded { opacity: 0.5; }
.group-start { color: blue; } .group-start {
.group-end { color: blue; } color: blue;
background-color: skyblue;
font-weight: bold;
border-top: 1px dotted blue;
padding: 0.5em;
margin-top: 0.5em;
}
.group-end {
padding: 0.5em;
margin-bottom: 0.25em;
/*border-bottom: 1px dotted blue;*/
}
.group-end.green {
background: lightgreen;
border-bottom: 1px dotted green;
}
.one-test-line, .skipping-group {
margin-left: 3em;
}
.skipping-test, .skipping-group {
padding: 0.25em 0.5em;
background-color: #ffff73;
}
.skipping-test {
margin-left: 6em;
}
.one-test-summary {
margin-left: 6em;
}
.full-test-summary {
padding-bottom: 0.5em;
padding-top: 0.5em;
border-top: 1px solid black;
}
.input-wrapper { .input-wrapper {
white-space: nowrap; white-space: nowrap;
display: flex; display: flex;

View File

@@ -1656,25 +1656,11 @@ globalThis.WhWasmUtilInstaller = function(target){
? opt.callProxy : undefined; ? opt.callProxy : undefined;
} }
/** If true, the constructor emits a warning. The intent is that /**
this be set to true after bootstrapping of the higher-level Note that static class members are defined outside of the class
client library is complete, to warn downstream clients that to work around an emcc toolchain build problem: one of the
they shouldn't be relying on this implemenation detail which tools in emsdk v3.1.42 does not support the static keyword.
does not have a stable interface. */ */
static warnOnUse = false;
/** If true, convertArg() will FuncPtrAdapter.debugOut() when it
(un)installs a function binding to/from WASM. Note that
deinstallation of bindScope=transient bindings happens
via scopedAllocPop() so will not be output. */
static debugFuncInstall = false;
/** Function used for debug output. */
static debugOut = console.debug.bind(console);
static bindScopes = [
'transient', 'context', 'singleton', 'permanent'
];
/* Dummy impl. Overwritten per-instance as needed. */ /* Dummy impl. Overwritten per-instance as needed. */
contextKey(argv,argIndex){ contextKey(argv,argIndex){
@@ -1761,6 +1747,26 @@ globalThis.WhWasmUtilInstaller = function(target){
}/*convertArg()*/ }/*convertArg()*/
}/*FuncPtrAdapter*/; }/*FuncPtrAdapter*/;
/** If true, the constructor emits a warning. The intent is that
this be set to true after bootstrapping of the higher-level
client library is complete, to warn downstream clients that
they shouldn't be relying on this implemenation detail which
does not have a stable interface. */
xArg.FuncPtrAdapter.warnOnUse = false;
/** If true, convertArg() will FuncPtrAdapter.debugOut() when it
(un)installs a function binding to/from WASM. Note that
deinstallation of bindScope=transient bindings happens
via scopedAllocPop() so will not be output. */
xArg.FuncPtrAdapter.debugFuncInstall = false;
/** Function used for debug output. */
xArg.FuncPtrAdapter.debugOut = console.debug.bind(console);
xArg.FuncPtrAdapter.bindScopes = [
'transient', 'context', 'singleton', 'permanent'
];
const __xArgAdapterCheck = const __xArgAdapterCheck =
(t)=>xArg.get(t) || toss("Argument adapter not found:",t); (t)=>xArg.get(t) || toss("Argument adapter not found:",t);

View File

@@ -38,7 +38,7 @@ dist-name := $(dist-name-prefix)-TEMP
# date. Our general policy is that we want the smallest binaries for # 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 # dist zip files, so use the oz build unless there is a compelling
# reason not to. # reason not to.
dist.build ?= qoz dist.build ?= oz
dist-dir.top := $(dist-name) dist-dir.top := $(dist-name)
dist-dir.jswasm := $(dist-dir.top)/$(notdir $(dir.dout)) dist-dir.jswasm := $(dist-dir.top)/$(notdir $(dir.dout))

View File

@@ -93,9 +93,13 @@
<ul> <ul>
<li><a href='speedtest1.html'>speedtest1</a>: a main-thread WASM build of speedtest1.</li> <li><a href='speedtest1.html'>speedtest1</a>: a main-thread WASM build of speedtest1.</li>
<li><a href='speedtest1.html?vfs=kvvfs'>speedtest1?vfs=kvvfs</a>: speedtest1 with the kvvfs.</li> <li><a href='speedtest1.html?vfs=kvvfs'>speedtest1?vfs=kvvfs</a>: speedtest1 with the kvvfs.</li>
<li><a href='speedtest1-worker.html?size=25'>speedtest1-worker</a>: an interactive Worker-thread variant of speedtest1.</li> <li><a href='speedtest1-worker.html?size=15'>speedtest1-worker</a>: an interactive Worker-thread variant of speedtest1.</li>
<li><a href='speedtest1-worker.html?vfs=opfs&size=25'>speedtest1-worker?vfs=opfs</a>: speedtest1-worker with the <li><a href='speedtest1-worker.html?vfs=opfs&size=10'>speedtest1-worker?vfs=opfs</a>: speedtest1-worker with the
OPFS VFS preselected and configured for a moderate workload.</li> OPFS VFS preselected and configured for a moderate workload.</li>
<li><a href='speedtest1-worker.html?vfs=opfs-sahpool&size=10'>speedtest1-worker?vfs=opfs-sahpool</a>:
speedtest1-worker with the OPFS-SAHPOOL VFS preselected
and configured for a moderate workload.
</li>
</ul> </ul>
</li> </li>
<li>The obligatory "misc." category... <li>The obligatory "misc." category...
@@ -117,18 +121,19 @@
</li> </li>
</ul> </ul>
</li> </li>
<!--li>WASMFS-specific tests which currently do not work due to incompatible changes <li><strong>WASMFS</strong>-specific tests which require that
made to the WASMFS+OPFS combination. the WASMFS build is available on this server (it is not by
default) and that this server emits the COOP/COEP headers.
<ul> <ul>
<li><a href='speedtest1-wasmfs.html?flags=--size,25'>speedtest1-wasmfs</a>: <li><a href='scratchpad-wasmfs.html'>scratchpad-wasmfs</a>:
experimenting with WASMFS/OPFS-based persistence.
</li>
<li><a href='speedtest1-wasmfs.html?flags=--size,15'>speedtest1-wasmfs</a>:
a variant of speedtest1 built solely for the wasmfs/opfs a variant of speedtest1 built solely for the wasmfs/opfs
feature.</li> feature.
<li><a href='scratchpad-wasmfs-main.html'>scratchpad-wasmfs-main</a>: </li>
experimenting with WASMFS/OPFS-based persistence. Maintenance
reminder: we cannot currently (2022-09-15) load WASMFS in a
worker due to an Emscripten wasm loader limitation.</li>
</ul> </ul>
</li--> </li>
<!--li><a href='x.html'></a></li--> <!--li><a href='x.html'></a></li-->
</ul> </ul>
</div> </div>

View File

@@ -1,70 +0,0 @@
/*
2022-05-22
The author disclaims copyright to this source code. In place of a
legal notice, here is a blessing:
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
***********************************************************************
A basic test script for sqlite3-api.js. This file must be run in
main JS thread and sqlite3.js must have been loaded before it.
*/
'use strict';
(function(){
const toss = function(...args){throw new Error(args.join(' '))};
const log = console.log.bind(console),
warn = console.warn.bind(console),
error = console.error.bind(console);
const stdout = log;
const stderr = error;
const test1 = function(db){
db.exec("create table if not exists t(a);")
.transaction(function(db){
db.prepare("insert into t(a) values(?)")
.bind(new Date().getTime())
.stepFinalize();
stdout("Number of values in table t:",
db.selectValue("select count(*) from t"));
});
};
const runTests = function(sqlite3){
const capi = sqlite3.capi,
oo = sqlite3.oo1,
wasm = sqlite3.wasm;
stdout("Loaded sqlite3:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
const persistentDir = capi.sqlite3_wasmfs_opfs_dir();
if(persistentDir){
stdout("Persistent storage dir:",persistentDir);
}else{
stderr("No persistent storage available.");
}
const startTime = performance.now();
let db;
try {
db = new oo.DB(persistentDir+'/foo.db');
stdout("DB filename:",db.filename);
const banner1 = '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>',
banner2 = '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<';
[
test1
].forEach((f)=>{
const n = performance.now();
stdout(banner1,"Running",f.name+"()...");
f(db, sqlite3);
stdout(banner2,f.name+"() took ",(performance.now() - n),"ms");
});
}finally{
if(db) db.close();
}
stdout("Total test time:",(performance.now() - startTime),"ms");
};
sqlite3InitModule(self.sqlite3TestModule).then(runTests);
})();

View File

@@ -10,20 +10,6 @@
</head> </head>
<body> <body>
<header id='titlebar'><span>sqlite3 WASMFS/OPFS Main-thread Scratchpad</span></header> <header id='titlebar'><span>sqlite3 WASMFS/OPFS Main-thread Scratchpad</span></header>
<!-- emscripten bits -->
<figure id="module-spinner">
<div class="spinner"></div>
<div class='center'><strong>Initializing app...</strong></div>
<div class='center'>
On a slow internet connection this may take a moment. If this
message displays for "a long time", intialization may have
failed and the JavaScript console may contain clues as to why.
</div>
</figure>
<div class="emscripten" id="module-status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="module-progress" hidden='1'></progress>
</div><!-- /emscripten bits -->
<p>Scratchpad/test app for the WASMF/OPFS integration in the <p>Scratchpad/test app for the WASMF/OPFS integration in the
main window thread. This page requires that the sqlite3 API have main window thread. This page requires that the sqlite3 API have
been built with WASMFS support. If OPFS support is available then been built with WASMFS support. If OPFS support is available then
@@ -33,8 +19,12 @@
<p>All stuff on this page happens in the dev console.</p> <p>All stuff on this page happens in the dev console.</p>
<hr> <hr>
<div id='test-output'></div> <div id='test-output'></div>
<script src="sqlite3-wasmfs.js"></script> <script>
<script src="common/SqliteTestUtil.js"></script> (function(){
<script src="scratchpad-wasmfs-main.js"></script> const W = new Worker('scratchpad-wasmfs.mjs',{
type: 'module'
});
})();
</script>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,70 @@
/*
2022-05-22
The author disclaims copyright to this source code. In place of a
legal notice, here is a blessing:
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
***********************************************************************
A basic test script for sqlite3-api.js. This file must be run in
main JS thread and sqlite3.js must have been loaded before it.
*/
import sqlite3InitModule from './jswasm/sqlite3-wasmfs.mjs';
//console.log('sqlite3InitModule =',sqlite3InitModule);
const toss = function(...args){throw new Error(args.join(' '))};
const log = console.log.bind(console),
warn = console.warn.bind(console),
error = console.error.bind(console);
const stdout = log;
const stderr = error;
const test1 = function(db){
db.exec("create table if not exists t(a);")
.transaction(function(db){
db.prepare("insert into t(a) values(?)")
.bind(new Date().getTime())
.stepFinalize();
stdout("Number of values in table t:",
db.selectValue("select count(*) from t"));
});
};
const runTests = function(sqlite3){
const capi = sqlite3.capi,
oo = sqlite3.oo1,
wasm = sqlite3.wasm;
stdout("Loaded module:",sqlite3);
stdout("Loaded sqlite3:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
const persistentDir = capi.sqlite3_wasmfs_opfs_dir();
if(persistentDir){
stdout("Persistent storage dir:",persistentDir);
}else{
stderr("No persistent storage available.");
}
const startTime = performance.now();
let db;
try {
db = new oo.DB(persistentDir+'/foo.db');
stdout("DB filename:",db.filename);
const banner1 = '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>',
banner2 = '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<';
[
test1
].forEach((f)=>{
const n = performance.now();
stdout(banner1,"Running",f.name+"()...");
f(db, sqlite3);
stdout(banner2,f.name+"() took ",(performance.now() - n),"ms");
});
}finally{
if(db) db.close();
}
stdout("Total test time:",(performance.now() - startTime),"ms");
};
sqlite3InitModule().then(runTests);

View File

@@ -10,141 +10,46 @@
</head> </head>
<body> <body>
<header id='titlebar'><span>speedtest1-wasmfs.wasm</span></header> <header id='titlebar'><span>speedtest1-wasmfs.wasm</span></header>
<div>See also: <a href='speedtest1-worker.html'>A Worker-thread variant of this page.</a></div> <div>See also: <a href='speedtest1-worker.html'>speedtest1-worker</a></div>
<!-- emscripten bits -->
<figure id="module-spinner">
<div class="spinner"></div>
<div class='center'><strong>Initializing app...</strong></div>
<div class='center'>
On a slow internet connection this may take a moment. If this
message displays for "a long time", intialization may have
failed and the JavaScript console may contain clues as to why.
</div>
</figure>
<div class="emscripten" id="module-status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="module-progress" hidden='1'></progress>
</div><!-- /emscripten bits -->
<div class='warning'>This page starts running the main exe when it loads, which will
block the UI until it finishes! Adding UI controls to manually configure and start it
are TODO.</div>
</div>
<div class='warning'>Achtung: running it with the dev tools open may <div class='warning'>Achtung: running it with the dev tools open may
<em>drastically</em> slow it down. For faster results, keep the dev <em>drastically</em> slow it down. For faster results, keep the dev
tools closed when running it! tools closed when running it!
</div> </div>
<div>Output is delayed/buffered because we cannot update the UI while the
speedtest is running. Output will appear below when ready...
<div id='test-output'></div> <div id='test-output'></div>
<script src="common/SqliteTestUtil.js"></script> <script>
<script src="speedtest1-wasmfs.js"></script> (function(){
<script>(function(){ const eOut = document.querySelector('#test-output');
/** const log2 = function(cssClass,...args){
If this environment contains OPFS, this function initializes it and const ln = document.createElement('div');
returns the name of the dir on which OPFS is mounted, else it returns if(cssClass) ln.classList.add(cssClass);
an empty string. ln.append(document.createTextNode(args.join(' ')));
*/ eOut.append(ln);
const wasmfsDir = function f(wasmUtil,dirName="/opfs"){ //this.e.output.lastElementChild.scrollIntoViewIfNeeded();
if(undefined !== f._) return f._; };
if( !self.FileSystemHandle /* can't update DOM while speedtest is running unless we run
|| !self.FileSystemDirectoryHandle speedtest in a worker thread. */;
|| !self.FileSystemFileHandle){ const log = (...args)=>{
return f._ = ""; console.log(...args);
} log2('',...args);
try{ };
if(0===wasmUtil.xCallWrapped( const logErr = function(...args){
'sqlite3_wasm_init_wasmfs', 'i32', ['string'], dirName console.error(...args);
)){ log2('error',...args);
return f._ = dirName; };
}else{ const W = new Worker(
return f._ = ""; 'speedtest1-wasmfs.mjs'+globalThis.location.search,{
} type: 'module'
}catch(e){ });
// sqlite3_wasm_init_wasmfs() is not available log("Starting up...");
return f._ = ""; W.onmessage = function({data}){
} switch(data.type){
}; case 'log': log(...data.args); break;
wasmfsDir._ = undefined; case 'logErr': logErr(...data.args); break;
default:
const eOut = document.querySelector('#test-output'); break;
const log2 = function(cssClass,...args){ }
const ln = document.createElement('div'); };
if(cssClass) ln.classList.add(cssClass); })();
ln.append(document.createTextNode(args.join(' '))); </script>
eOut.append(ln);
//this.e.output.lastElementChild.scrollIntoViewIfNeeded();
};
const logList = [];
const dumpLogList = function(){
logList.forEach((v)=>log2('',v));
logList.length = 0;
};
/* can't update DOM while speedtest is running unless we run
speedtest in a worker thread. */;
const log = (...args)=>{
console.log(...args);
logList.push(args.join(' '));
};
const logErr = function(...args){
console.error(...args);
logList.push('ERROR: '+args.join(' '));
};
const runTests = function(sqlite3){
console.log("Module inited.");
const wasm = sqlite3.wasm;
const __unlink = wasm.xWrap("sqlite3_wasm_vfs_unlink", "int", ["*","string"]);
const unlink = (fn)=>__unlink(0,fn);
const pDir = wasmfsDir(wasm);
if(pDir) log2('',"Persistent storage:",pDir);
else{
log2('error',"Expecting persistent storage in this build.");
return;
}
const scope = wasm.scopedAllocPush();
const dbFile = pDir+"/speedtest1.db";
const urlParams = new URL(self.location.href).searchParams;
const argv = ["speedtest1"];
if(urlParams.has('flags')){
argv.push(...(urlParams.get('flags').split(',')));
let i = argv.indexOf('--vfs');
if(i>=0) argv.splice(i,2);
}else{
argv.push(
"--singlethread",
"--nomutex",
"--nosync",
"--nomemstat"
);
//"--memdb", // note that memdb trumps the filename arg
}
if(argv.indexOf('--memdb')>=0){
log2('error',"WARNING: --memdb flag trumps db filename.");
}
argv.push("--big-transactions"/*important for tests 410 and 510!*/,
dbFile);
console.log("argv =",argv);
// These log messages are not emitted to the UI until after main() returns. Fixing that
// requires moving the main() call and related cleanup into a timeout handler.
if(pDir) unlink(dbFile);
log2('',"Starting native app:\n ",argv.join(' '));
log2('',"This will take a while and the browser might warn about the runaway JS.",
"Give it time...");
logList.length = 0;
setTimeout(function(){
wasm.xCall('wasm_main', argv.length,
wasm.scopedAllocMainArgv(argv));
wasm.scopedAllocPop(scope);
if(pDir) unlink(dbFile);
logList.unshift("Done running native main(). Output:");
dumpLogList();
}, 25);
}/*runTests()*/;
self.sqlite3TestModule.print = log;
self.sqlite3TestModule.printErr = logErr;
sqlite3InitModule(self.sqlite3TestModule).then(runTests);
})();</script>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,90 @@
import sqlite3InitModule from './jswasm/speedtest1-wasmfs.mjs';
const wMsg = (type,...args)=>{
postMessage({type, args});
};
wMsg('log',"speedtest1-wasmfs starting...");
/**
If this environment contains OPFS, this function initializes it and
returns the name of the dir on which OPFS is mounted, else it returns
an empty string.
*/
const wasmfsDir = function f(wasmUtil,dirName="/opfs"){
if(undefined !== f._) return f._;
if( !self.FileSystemHandle
|| !self.FileSystemDirectoryHandle
|| !self.FileSystemFileHandle){
return f._ = "";
}
try{
if(0===wasmUtil.xCallWrapped(
'sqlite3_wasm_init_wasmfs', 'i32', ['string'], dirName
)){
return f._ = dirName;
}else{
return f._ = "";
}
}catch(e){
// sqlite3_wasm_init_wasmfs() is not available
return f._ = "";
}
};
wasmfsDir._ = undefined;
const log = (...args)=>wMsg('log',...args);
const logErr = (...args)=>wMsg('logErr',...args);
const runTests = function(sqlite3){
console.log("Module inited.",sqlite3);
const wasm = sqlite3.wasm;
const __unlink = wasm.xWrap("sqlite3_wasm_vfs_unlink", "int", ["*","string"]);
const unlink = (fn)=>__unlink(0,fn);
const pDir = wasmfsDir(wasm);
if(pDir) log("Persistent storage:",pDir);
else{
logErr("Expecting persistent storage in this build.");
return;
}
const scope = wasm.scopedAllocPush();
const dbFile = pDir+"/speedtest1.db";
const urlParams = new URL(self.location.href).searchParams;
const argv = ["speedtest1"];
if(urlParams.has('flags')){
argv.push(...(urlParams.get('flags').split(',')));
let i = argv.indexOf('--vfs');
if(i>=0) argv.splice(i,2);
}else{
argv.push(
"--singlethread",
"--nomutex",
//"--nosync",
"--nomemstat",
"--size", "10"
);
}
if(argv.indexOf('--memdb')>=0){
logErr("WARNING: --memdb flag trumps db filename.");
}
argv.push("--big-transactions"/*important for tests 410 and 510!*/,
dbFile);
//log("argv =",argv);
// These log messages are not emitted to the UI until after main() returns. Fixing that
// requires moving the main() call and related cleanup into a timeout handler.
if(pDir) unlink(dbFile);
log("Starting native app:\n ",argv.join(' '));
log("This will take a while and the browser might warn about the runaway JS.",
"Give it time...");
setTimeout(function(){
if(pDir) unlink(dbFile);
wasm.xCall('wasm_main', argv.length,
wasm.scopedAllocMainArgv(argv));
wasm.scopedAllocPop(scope);
if(pDir) unlink(dbFile);
log("Done running native main()");
}, 25);
}/*runTests()*/;
sqlite3InitModule({
print: log,
printErr: logErr
}).then(runTests);

View File

@@ -171,7 +171,8 @@
const urlParams = new URL(self.location.href).searchParams; const urlParams = new URL(self.location.href).searchParams;
const W = new Worker( const W = new Worker(
"speedtest1-worker.js?sqlite3.dir=jswasm"+ "speedtest1-worker.js?sqlite3.dir=jswasm"+
(urlParams.has('opfs-verbose') ? '&opfs-verbose' : '') (urlParams.has('opfs-verbose') ? '&opfs-verbose' : '')+
(urlParams.has('opfs-disable') ? '&opfs-disable' : '')
); );
const mPost = function(msgType,payload){ const mPost = function(msgType,payload){
W.postMessage({type: msgType, data: payload}); W.postMessage({type: msgType, data: payload});
@@ -259,7 +260,7 @@
flags["--utf16be"] = "Set text encoding to UTF-16BE"; flags["--utf16be"] = "Set text encoding to UTF-16BE";
flags["--utf16le"] = "Set text encoding to UTF-16LE"; flags["--utf16le"] = "Set text encoding to UTF-16LE";
flags["--verify"] = "Run additional verification steps."; flags["--verify"] = "Run additional verification steps.";
flags["--without"] = "rowid Use WITHOUT ROWID where appropriate"; flags["--without-rowid"] = "Use WITHOUT ROWID where appropriate";
const preselectedFlags = [ const preselectedFlags = [
'--big-transactions', '--big-transactions',
'--singlethread' '--singlethread'
@@ -267,7 +268,7 @@
if(urlParams.has('flags')){ if(urlParams.has('flags')){
preselectedFlags.push(...urlParams.get('flags').split(',')); preselectedFlags.push(...urlParams.get('flags').split(','));
} }
if('opfs'!==urlParams.get('vfs')){ if(!urlParams.get('vfs')){
preselectedFlags.push('--memdb'); preselectedFlags.push('--memdb');
} }
Object.keys(flags).sort().forEach(function(f){ Object.keys(flags).sort().forEach(function(f){

View File

@@ -5,7 +5,7 @@
if(urlParams.has('sqlite3.dir')){ if(urlParams.has('sqlite3.dir')){
speedtestJs = urlParams.get('sqlite3.dir') + '/' + speedtestJs; speedtestJs = urlParams.get('sqlite3.dir') + '/' + speedtestJs;
} }
importScripts('common/whwasmutil.js', speedtestJs); importScripts(speedtestJs);
/** /**
If this environment contains OPFS, this function initializes it and If this environment contains OPFS, this function initializes it and
returns the name of the dir on which OPFS is mounted, else it returns returns the name of the dir on which OPFS is mounted, else it returns
@@ -48,7 +48,7 @@
const log = (...args)=>logMsg('stdout',args); const log = (...args)=>logMsg('stdout',args);
const logErr = (...args)=>logMsg('stderr',args); const logErr = (...args)=>logMsg('stderr',args);
const runSpeedtest = function(cliFlagsArray){ const runSpeedtest = async function(cliFlagsArray){
const scope = App.wasm.scopedAllocPush(); const scope = App.wasm.scopedAllocPush();
const dbFile = App.pDir+"/speedtest1.sqlite3"; const dbFile = App.pDir+"/speedtest1.sqlite3";
try{ try{
@@ -56,7 +56,28 @@
"speedtest1.wasm", ...cliFlagsArray, dbFile "speedtest1.wasm", ...cliFlagsArray, dbFile
]; ];
App.logBuffer.length = 0; App.logBuffer.length = 0;
const ndxSahPool = argv.indexOf('opfs-sahpool');
const realSahName = 'opfs-sahpool-speedtest1';
if(ndxSahPool>0){
argv[ndxSahPool] = realSahName;
log("Updated argv for opfs-sahpool: --vfs",realSahName);
}
mPost('run-start', [...argv]); mPost('run-start', [...argv]);
if(App.sqlite3.installOpfsSAHPoolVfs
&& !App.sqlite3.$SAHPoolUtil
&& ndxSahPool>0){
log("Installing opfs-sahpool as",realSahName,"...");
await App.sqlite3.installOpfsSAHPoolVfs({
name: realSahName,
initialCapacity: 3,
clearOnInit: true,
verbosity: 2
}).then(PoolUtil=>{
log("opfs-sahpool successfully installed as",realSahName);
App.sqlite3.$SAHPoolUtil = PoolUtil;
//console.log("sqlite3.oo1.OpfsSAHPoolDb =", App.sqlite3.oo1.OpfsSAHPoolDb);
});
}
App.wasm.xCall('wasm_main', argv.length, App.wasm.xCall('wasm_main', argv.length,
App.wasm.scopedAllocMainArgv(argv)); App.wasm.scopedAllocMainArgv(argv));
}catch(e){ }catch(e){
@@ -71,20 +92,38 @@
self.onmessage = function(msg){ self.onmessage = function(msg){
msg = msg.data; msg = msg.data;
switch(msg.type){ switch(msg.type){
case 'run': runSpeedtest(msg.data || []); break; case 'run':
runSpeedtest(msg.data || [])
.catch(e=>mPost('error',e));
break;
default: default:
logErr("Unhandled worker message type:",msg.type); logErr("Unhandled worker message type:",msg.type);
break; break;
} }
}; };
const sahpSanityChecks = function(sqlite3){
log("Attempting OpfsSAHPoolDb sanity checks...");
const db = new sqlite3.oo1.OpfsSAHPoolDb('opfs-sahpoool.db');
const fn = db.filename;
db.exec([
'create table t(a);',
'insert into t(a) values(1),(2),(3);'
]);
db.close();
sqlite3.wasm.sqlite3_wasm_vfs_unlink(sqlite3_vfs_find("opfs-sahpool"), fn);
log("SAH sanity checks done.");
};
const EmscriptenModule = { const EmscriptenModule = {
print: log, print: log,
printErr: logErr, printErr: logErr,
setStatus: (text)=>mPost('load-status',text) setStatus: (text)=>mPost('load-status',text)
}; };
self.sqlite3InitModule(EmscriptenModule).then((sqlite3)=>{ log("Initializing speedtest1 module...");
const S = sqlite3; self.sqlite3InitModule(EmscriptenModule).then(async (sqlite3)=>{
const S = globalThis.S = App.sqlite3 = sqlite3;
log("Loaded speedtest1 module. Setting up...");
App.vfsUnlink = function(pDb, fname){ App.vfsUnlink = function(pDb, fname){
const pVfs = S.wasm.sqlite3_wasm_db_vfs(pDb, 0); const pVfs = S.wasm.sqlite3_wasm_db_vfs(pDb, 0);
if(pVfs) S.wasm.sqlite3_wasm_vfs_unlink(pVfs, fname||0); if(pVfs) S.wasm.sqlite3_wasm_vfs_unlink(pVfs, fname||0);
@@ -95,5 +134,7 @@
//else log("Using transient storage."); //else log("Using transient storage.");
mPost('ready',true); mPost('ready',true);
log("Registered VFSes:", ...S.capi.sqlite3_js_vfs_list()); log("Registered VFSes:", ...S.capi.sqlite3_js_vfs_list());
}).catch(e=>{
logErr(e);
}); });
})(); })();

View File

@@ -45,7 +45,7 @@
*/ */
//#if target=es6-module //#if target=es6-module
import {default as sqlite3InitModule} from './jswasm/sqlite3.mjs'; import {default as sqlite3InitModule} from './jswasm/sqlite3.mjs';
self.sqlite3InitModule = sqlite3InitModule; globalThis.sqlite3InitModule = sqlite3InitModule;
//#else //#else
'use strict'; 'use strict';
//#endif //#endif
@@ -57,7 +57,7 @@ self.sqlite3InitModule = sqlite3InitModule;
*/ */
let logClass; let logClass;
/* Predicate for tests/groups. */ /* Predicate for tests/groups. */
const isUIThread = ()=>(self.window===self && self.document); const isUIThread = ()=>(globalThis.window===self && globalThis.document);
/* Predicate for tests/groups. */ /* Predicate for tests/groups. */
const isWorker = ()=>!isUIThread(); const isWorker = ()=>!isUIThread();
/* Predicate for tests/groups. */ /* Predicate for tests/groups. */
@@ -65,6 +65,14 @@ self.sqlite3InitModule = sqlite3InitModule;
const haveWasmCTests = ()=>{ const haveWasmCTests = ()=>{
return !!wasm.exports.sqlite3_wasm_test_intptr; return !!wasm.exports.sqlite3_wasm_test_intptr;
}; };
const hasOpfs = ()=>{
return globalThis.FileSystemHandle
&& globalThis.FileSystemDirectoryHandle
&& globalThis.FileSystemFileHandle
&& globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle
&& navigator?.storage?.getDirectory;
};
{ {
const mapToString = (v)=>{ const mapToString = (v)=>{
switch(typeof v){ switch(typeof v){
@@ -159,8 +167,6 @@ self.sqlite3InitModule = sqlite3InitModule;
/** Running total of the number of tests run via /** Running total of the number of tests run via
this API. */ this API. */
counter: 0, counter: 0,
/* Separator line for log messages. */
separator: '------------------------------------------------------------',
/** /**
If expr is a function, it is called and its result If expr is a function, it is called and its result
is returned, coerced to a bool, else expr, coerced to is returned, coerced to a bool, else expr, coerced to
@@ -248,13 +254,11 @@ self.sqlite3InitModule = sqlite3InitModule;
return this; return this;
}, },
run: async function(sqlite3){ run: async function(sqlite3){
log(TestUtil.separator);
logClass('group-start',"Group #"+this.number+':',this.name); logClass('group-start',"Group #"+this.number+':',this.name);
const indent = ' ';
if(this.predicate){ if(this.predicate){
const p = this.predicate(sqlite3); const p = this.predicate(sqlite3);
if(!p || 'string'===typeof p){ if(!p || 'string'===typeof p){
logClass('warning',indent, logClass(['warning','skipping-group'],
"SKIPPING group:", p ? p : "predicate says to" ); "SKIPPING group:", p ? p : "predicate says to" );
return; return;
} }
@@ -266,26 +270,34 @@ self.sqlite3InitModule = sqlite3InitModule;
for(const t of this.tests){ for(const t of this.tests){
++i; ++i;
const n = this.number+"."+i; const n = this.number+"."+i;
log(indent, n+":", t.name); logClass('one-test-line', n+":", t.name);
if(t.predicate){ if(t.predicate){
const p = t.predicate(sqlite3); const p = t.predicate(sqlite3);
if(!p || 'string'===typeof p){ if(!p || 'string'===typeof p){
logClass('warning',indent, logClass(['warning','skipping-test'],
"SKIPPING:", p ? p : "predicate says to" ); "SKIPPING:", p ? p : "predicate says to" );
skipped.push( n+': '+t.name ); skipped.push( n+': '+t.name );
continue; continue;
} }
} }
const tc = TestUtil.counter, now = performance.now(); const tc = TestUtil.counter, now = performance.now();
await t.test.call(groupState, sqlite3); let rc = t.test.call(groupState, sqlite3);
/*if(rc instanceof Promise){
rc = rc.catch((e)=>{
error("Test failure:",e);
throw e;
});
}*/
await rc;
const then = performance.now(); const then = performance.now();
runtime += then - now; runtime += then - now;
logClass('faded',indent, indent, logClass(['faded','one-test-summary'],
TestUtil.counter - tc, 'assertion(s) in', TestUtil.counter - tc, 'assertion(s) in',
roundMs(then-now),'ms'); roundMs(then-now),'ms');
} }
logClass('green', logClass(['green','group-end'],
"Group #"+this.number+":",(TestUtil.counter - assertCount), "#"+this.number+":",
(TestUtil.counter - assertCount),
"assertion(s) in",roundMs(runtime),"ms"); "assertion(s) in",roundMs(runtime),"ms");
if(0 && skipped.length){ if(0 && skipped.length){
logClass('warning',"SKIPPED test(s) in group",this.number+":",skipped); logClass('warning',"SKIPPED test(s) in group",this.number+":",skipped);
@@ -321,8 +333,7 @@ self.sqlite3InitModule = sqlite3InitModule;
await g.run(sqlite3); await g.run(sqlite3);
runtime += performance.now() - now; runtime += performance.now() - now;
} }
log(TestUtil.separator); logClass(['strong','green','full-test-summary'],
logClass(['strong','green'],
"Done running tests.",TestUtil.counter,"assertions in", "Done running tests.",TestUtil.counter,"assertions in",
roundMs(runtime),'ms'); roundMs(runtime),'ms');
pok(); pok();
@@ -339,6 +350,11 @@ self.sqlite3InitModule = sqlite3InitModule;
T.g = T.addGroup; T.g = T.addGroup;
T.t = T.addTest; T.t = T.addTest;
let capi, wasm/*assigned after module init*/; let capi, wasm/*assigned after module init*/;
const sahPoolConfig = {
name: 'opfs-sahpool-tester1',
clearOnInit: true,
initialCapacity: 3
};
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// End of infrastructure setup. Now define the tests... // End of infrastructure setup. Now define the tests...
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@@ -1288,7 +1304,6 @@ self.sqlite3InitModule = sqlite3InitModule;
if(1){ if(1){
const vfsList = capi.sqlite3_js_vfs_list(); const vfsList = capi.sqlite3_js_vfs_list();
T.assert(vfsList.length>1); T.assert(vfsList.length>1);
//log("vfsList =",vfsList);
wasm.scopedAllocCall(()=>{ wasm.scopedAllocCall(()=>{
const vfsArg = (v)=>wasm.xWrap.testConvertArg('sqlite3_vfs*',v); const vfsArg = (v)=>wasm.xWrap.testConvertArg('sqlite3_vfs*',v);
for(const v of vfsList){ for(const v of vfsList){
@@ -2615,128 +2630,6 @@ self.sqlite3InitModule = sqlite3InitModule;
}/*kvvfs sqlite3_js_vfs_create_file()*/) }/*kvvfs sqlite3_js_vfs_create_file()*/)
;/* end kvvfs tests */ ;/* end kvvfs tests */
////////////////////////////////////////////////////////////////////////
T.g('OPFS: Origin-Private File System',
(sqlite3)=>(sqlite3.opfs
? true : "requires Worker thread in a compatible browser"))
.t({
name: 'OPFS db sanity checks',
test: async function(sqlite3){
const filename = this.opfsDbFile = 'sqlite3-tester1.db';
const pVfs = this.opfsVfs = capi.sqlite3_vfs_find('opfs');
T.assert(pVfs);
const unlink = this.opfsUnlink =
(fn=filename)=>{wasm.sqlite3_wasm_vfs_unlink(pVfs,fn)};
unlink();
let db = new sqlite3.oo1.OpfsDb(filename);
try {
db.exec([
'create table p(a);',
'insert into p(a) values(1),(2),(3)'
]);
T.assert(3 === db.selectValue('select count(*) from p'));
db.close();
db = new sqlite3.oo1.OpfsDb(filename);
db.exec('insert into p(a) values(4),(5),(6)');
T.assert(6 === db.selectValue('select count(*) from p'));
this.opfsDbExport = capi.sqlite3_js_db_export(db);
T.assert(this.opfsDbExport instanceof Uint8Array)
.assert(this.opfsDbExport.byteLength>0
&& 0===this.opfsDbExport.byteLength % 512);
}finally{
db.close();
unlink();
}
}
}/*OPFS db sanity checks*/)
.t({
name: 'OPFS export/import',
test: async function(sqlite3){
let db;
try {
const exp = this.opfsDbExport;
delete this.opfsDbExport;
capi.sqlite3_js_vfs_create_file("opfs", this.opfsDbFile, exp);
const db = new sqlite3.oo1.OpfsDb(this.opfsDbFile);
T.assert(6 === db.selectValue('select count(*) from p'));
}finally{
if(db) db.close();
}
}
}/*OPFS export/import*/)
.t({
name: 'OPFS utility APIs and sqlite3_js_vfs_create_file()',
test: async function(sqlite3){
const filename = this.opfsDbFile;
const pVfs = this.opfsVfs;
const unlink = this.opfsUnlink;
T.assert(filename && pVfs && !!unlink);
delete this.opfsDbFile;
delete this.opfsVfs;
delete this.opfsUnlink;
unlink();
// Sanity-test sqlite3_js_vfs_create_file()...
/**************************************************************
ATTENTION CLIENT-SIDE USERS: sqlite3.opfs is NOT intended
for client-side use. It is only for this project's own
internal use. Its APIs are subject to change or removal at
any time.
***************************************************************/
const opfs = sqlite3.opfs;
const fSize = 1379;
let sh;
try{
T.assert(!(await opfs.entryExists(filename)));
capi.sqlite3_js_vfs_create_file(
pVfs, filename, null, fSize
);
T.assert(await opfs.entryExists(filename));
let fh = await opfs.rootDirectory.getFileHandle(filename);
sh = await fh.createSyncAccessHandle();
T.assert(fSize === await sh.getSize());
await sh.close();
sh = undefined;
unlink();
T.assert(!(await opfs.entryExists(filename)));
const ba = new Uint8Array([1,2,3,4,5]);
capi.sqlite3_js_vfs_create_file(
"opfs", filename, ba
);
T.assert(await opfs.entryExists(filename));
fh = await opfs.rootDirectory.getFileHandle(filename);
sh = await fh.createSyncAccessHandle();
T.assert(ba.byteLength === await sh.getSize());
await sh.close();
sh = undefined;
unlink();
T.mustThrowMatching(()=>{
capi.sqlite3_js_vfs_create_file(
"no-such-vfs", filename, ba
);
}, "SQLITE_NOTFOUND: Unknown sqlite3_vfs name: no-such-vfs");
}finally{
if(sh) await sh.close();
unlink();
}
// Some sanity checks of the opfs utility functions...
const testDir = '/sqlite3-opfs-'+opfs.randomFilename(12);
const aDir = testDir+'/test/dir';
T.assert(await opfs.mkdir(aDir), "mkdir failed")
.assert(await opfs.mkdir(aDir), "mkdir must pass if the dir exists")
.assert(!(await opfs.unlink(testDir+'/test')), "delete 1 should have failed (dir not empty)")
.assert((await opfs.unlink(testDir+'/test/dir')), "delete 2 failed")
.assert(!(await opfs.unlink(testDir+'/test/dir')),
"delete 2b should have failed (dir already deleted)")
.assert((await opfs.unlink(testDir, true)), "delete 3 failed")
.assert(!(await opfs.entryExists(testDir)),
"entryExists(",testDir,") should have failed");
}
}/*OPFS util sanity checks*/)
;/* end OPFS tests */
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
T.g('Hook APIs') T.g('Hook APIs')
.t({ .t({
@@ -2942,8 +2835,7 @@ self.sqlite3InitModule = sqlite3InitModule;
.assert( capi.sqlite3session_enable(pSession, -1) > 0 ) .assert( capi.sqlite3session_enable(pSession, -1) > 0 )
.assert(undefined === db1.selectValue('select a from t where rowid=2')); .assert(undefined === db1.selectValue('select a from t where rowid=2'));
}else{ }else{
warn("sqlite3session_enable() tests disabled due to unexpected results.", warn("sqlite3session_enable() tests are currently disabled.");
"(Possibly a tester misunderstanding, as opposed to a bug.)");
} }
let db1Count = db1.selectValue("select count(*) from t"); let db1Count = db1.selectValue("select count(*) from t");
T.assert( db1Count === (testSessionEnable ? 2 : 3) ); T.assert( db1Count === (testSessionEnable ? 2 : 3) );
@@ -3007,6 +2899,205 @@ self.sqlite3InitModule = sqlite3InitModule;
} }
})/*session API sanity tests*/ })/*session API sanity tests*/
;/*end of session API group*/; ;/*end of session API group*/;
////////////////////////////////////////////////////////////////////////
T.g('OPFS: Origin-Private File System',
(sqlite3)=>(sqlite3.capi.sqlite3_vfs_find("opfs")
|| 'requires "opfs" VFS'))
.t({
name: 'OPFS db sanity checks',
test: async function(sqlite3){
const filename = this.opfsDbFile = 'sqlite3-tester1.db';
const pVfs = this.opfsVfs = capi.sqlite3_vfs_find('opfs');
T.assert(pVfs);
const unlink = this.opfsUnlink =
(fn=filename)=>{wasm.sqlite3_wasm_vfs_unlink(pVfs,fn)};
unlink();
let db = new sqlite3.oo1.OpfsDb(filename);
try {
db.exec([
'create table p(a);',
'insert into p(a) values(1),(2),(3)'
]);
T.assert(3 === db.selectValue('select count(*) from p'));
db.close();
db = new sqlite3.oo1.OpfsDb(filename);
db.exec('insert into p(a) values(4),(5),(6)');
T.assert(6 === db.selectValue('select count(*) from p'));
this.opfsDbExport = capi.sqlite3_js_db_export(db);
T.assert(this.opfsDbExport instanceof Uint8Array)
.assert(this.opfsDbExport.byteLength>0
&& 0===this.opfsDbExport.byteLength % 512);
}finally{
db.close();
unlink();
}
}
}/*OPFS db sanity checks*/)
.t({
name: 'OPFS export/import',
test: async function(sqlite3){
let db;
try {
const exp = this.opfsDbExport;
delete this.opfsDbExport;
capi.sqlite3_js_vfs_create_file("opfs", this.opfsDbFile, exp);
const db = new sqlite3.oo1.OpfsDb(this.opfsDbFile);
T.assert(6 === db.selectValue('select count(*) from p'));
}finally{
if(db) db.close();
}
}
}/*OPFS export/import*/)
.t({
name: 'OPFS utility APIs and sqlite3_js_vfs_create_file()',
test: async function(sqlite3){
const filename = this.opfsDbFile;
const pVfs = this.opfsVfs;
const unlink = this.opfsUnlink;
T.assert(filename && pVfs && !!unlink);
delete this.opfsDbFile;
delete this.opfsVfs;
delete this.opfsUnlink;
unlink();
// Sanity-test sqlite3_js_vfs_create_file()...
/**************************************************************
ATTENTION CLIENT-SIDE USERS: sqlite3.opfs is NOT intended
for client-side use. It is only for this project's own
internal use. Its APIs are subject to change or removal at
any time.
***************************************************************/
const opfs = sqlite3.opfs;
const fSize = 1379;
let sh;
try{
T.assert(!(await opfs.entryExists(filename)));
capi.sqlite3_js_vfs_create_file(
pVfs, filename, null, fSize
);
T.assert(await opfs.entryExists(filename));
let fh = await opfs.rootDirectory.getFileHandle(filename);
sh = await fh.createSyncAccessHandle();
T.assert(fSize === await sh.getSize());
await sh.close();
sh = undefined;
unlink();
T.assert(!(await opfs.entryExists(filename)));
const ba = new Uint8Array([1,2,3,4,5]);
capi.sqlite3_js_vfs_create_file(
"opfs", filename, ba
);
T.assert(await opfs.entryExists(filename));
fh = await opfs.rootDirectory.getFileHandle(filename);
sh = await fh.createSyncAccessHandle();
T.assert(ba.byteLength === await sh.getSize());
await sh.close();
sh = undefined;
unlink();
T.mustThrowMatching(()=>{
capi.sqlite3_js_vfs_create_file(
"no-such-vfs", filename, ba
);
}, "SQLITE_NOTFOUND: Unknown sqlite3_vfs name: no-such-vfs");
}finally{
if(sh) await sh.close();
unlink();
}
// Some sanity checks of the opfs utility functions...
const testDir = '/sqlite3-opfs-'+opfs.randomFilename(12);
const aDir = testDir+'/test/dir';
T.assert(await opfs.mkdir(aDir), "mkdir failed")
.assert(await opfs.mkdir(aDir), "mkdir must pass if the dir exists")
.assert(!(await opfs.unlink(testDir+'/test')), "delete 1 should have failed (dir not empty)")
.assert((await opfs.unlink(testDir+'/test/dir')), "delete 2 failed")
.assert(!(await opfs.unlink(testDir+'/test/dir')),
"delete 2b should have failed (dir already deleted)")
.assert((await opfs.unlink(testDir, true)), "delete 3 failed")
.assert(!(await opfs.entryExists(testDir)),
"entryExists(",testDir,") should have failed");
}
}/*OPFS util sanity checks*/)
;/* end OPFS tests */
////////////////////////////////////////////////////////////////////////
T.g('OPFS SyncAccessHandle Pool VFS',
(sqlite3)=>(hasOpfs() || "requires OPFS APIs"))
.t({
name: 'SAH sanity checks',
test: async function(sqlite3){
T.assert(!sqlite3.capi.sqlite3_vfs_find(sahPoolConfig.name))
.assert(sqlite3.capi.sqlite3_js_vfs_list().indexOf(sahPoolConfig.name) < 0)
const inst = sqlite3.installOpfsSAHPoolVfs,
catcher = (e)=>{
error("Cannot load SAH pool VFS.",
"This might not be a problem,",
"depending on the environment.");
return false;
};
let u1, u2;
// Ensure that two immediately-consecutive installations
// resolve to the same Promise instead of triggering
// a locking error.
const P1 = inst(sahPoolConfig).then(u=>u1 = u).catch(catcher),
P2 = inst(sahPoolConfig).then(u=>u2 = u).catch(catcher);
await Promise.all([P1, P2]);
if(!(await P1)) return;
T.assert(u1 === u2)
.assert(sahPoolConfig.name === u1.vfsName)
.assert(sqlite3.capi.sqlite3_vfs_find(sahPoolConfig.name))
.assert(u1.getCapacity() >= sahPoolConfig.initialCapacity
/* If a test fails before we get to nuke the VFS, we
can have more than the initial capacity on the next
run. */)
.assert(u1.getCapacity() + 2 === (await u2.addCapacity(2)))
.assert(2 === (await u2.reduceCapacity(2)))
.assert(sqlite3.capi.sqlite3_js_vfs_list().indexOf(sahPoolConfig.name) >= 0);
T.assert(0 === u1.getFileCount());
const dbName = '/foo.db';
let db = new u1.OpfsSAHPoolDb(dbName);
T.assert(db instanceof sqlite3.oo1.DB)
.assert(1 === u1.getFileCount());
db.exec([
'create table t(a);',
'insert into t(a) values(1),(2),(3)'
]);
T.assert(1 === u1.getFileCount());
T.assert(3 === db.selectValue('select count(*) from t'));
db.close();
T.assert(1 === u1.getFileCount());
db = new u2.OpfsSAHPoolDb(dbName);
T.assert(1 === u1.getFileCount());
db.close();
T.assert(1 === u1.getFileCount())
.assert(true === u1.unlink(dbName))
.assert(false === u1.unlink(dbName))
.assert(0 === u1.getFileCount());
if(0){
/* Enable this block to inspect vfs's contents via the dev
console or OPFS Explorer browser extension. The
following bits will remove them. */
return;
}
T.assert(true === await u2.removeVfs())
.assert(false === await u1.removeVfs())
.assert(!sqlite3.capi.sqlite3_vfs_find(sahPoolConfig.name));
let cErr, u3;
const conf2 = JSON.parse(JSON.stringify(sahPoolConfig));
conf2.$testThrowInInit = new Error("Testing throwing during init.");
conf2.name = sahPoolConfig.name+'-err';
const P3 = await inst(conf2).then(u=>u3 = u).catch((e)=>cErr=e);
T.assert(P3 === conf2.$testThrowInInit)
.assert(cErr === P3)
.assert(undefined === u3)
.assert(!sqlite3.capi.sqlite3_vfs_find(conf2.name));
}
}/*OPFS SAH Pool sanity checks*/)
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
T.g('Bug Reports') T.g('Bug Reports')
.t({ .t({
@@ -3050,14 +3141,15 @@ self.sqlite3InitModule = sqlite3InitModule;
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
log("Loading and initializing sqlite3 WASM module..."); log("Loading and initializing sqlite3 WASM module...");
if(0){ if(0){
self.sqlite3ApiConfig = { globalThis.sqlite3ApiConfig = {
debug: ()=>{}, debug: ()=>{},
log: ()=>{}, log: ()=>{},
warn: ()=>{}, warn: ()=>{},
error: ()=>{} error: ()=>{}
} }
} }
if(!self.sqlite3InitModule && !isUIThread()){ //#ifnot target=es6-module
if(!globalThis.sqlite3InitModule && !isUIThread()){
/* Vanilla worker, as opposed to an ES6 module worker */ /* Vanilla worker, as opposed to an ES6 module worker */
/* /*
If sqlite3.js is in a directory other than this script, in order If sqlite3.js is in a directory other than this script, in order
@@ -3070,27 +3162,32 @@ self.sqlite3InitModule = sqlite3InitModule;
that's not needed. that's not needed.
URL arguments passed as part of the filename via importScripts() URL arguments passed as part of the filename via importScripts()
are simply lost, and such scripts see the self.location of are simply lost, and such scripts see the globalThis.location of
_this_ script. _this_ script.
*/ */
let sqlite3Js = 'sqlite3.js'; let sqlite3Js = 'sqlite3.js';
const urlParams = new URL(self.location.href).searchParams; const urlParams = new URL(globalThis.location.href).searchParams;
if(urlParams.has('sqlite3.dir')){ if(urlParams.has('sqlite3.dir')){
sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js; sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
} }
importScripts(sqlite3Js); importScripts(sqlite3Js);
} }
self.sqlite3InitModule.__isUnderTest = //#endif
globalThis.sqlite3InitModule.__isUnderTest =
true /* disables certain API-internal cleanup so that we can true /* disables certain API-internal cleanup so that we can
test internal APIs from here */; test internal APIs from here */;
self.sqlite3InitModule({ globalThis.sqlite3InitModule({
print: log, print: log,
printErr: error printErr: error
}).then(function(sqlite3){ }).then(async function(sqlite3){
//console.log('sqlite3 =',sqlite3);
log("Done initializing WASM/JS bits. Running tests..."); log("Done initializing WASM/JS bits. Running tests...");
sqlite3.config.warn("Installing sqlite3 bits as global S for local dev/test purposes."); sqlite3.config.warn("Installing sqlite3 bits as global S for local dev/test purposes.");
self.S = sqlite3; globalThis.S = sqlite3;
/*await sqlite3.installOpfsSAHPoolVfs(sahPoolConfig)
.then((u)=>log("Loaded",u.vfsName,"VFS"))
.catch(e=>{
log("Cannot install OpfsSAHPool.",e);
});*/
capi = sqlite3.capi; capi = sqlite3.capi;
wasm = sqlite3.wasm; wasm = sqlite3.wasm;
log("sqlite3 version:",capi.sqlite3_libversion(), log("sqlite3 version:",capi.sqlite3_libversion(),
@@ -3105,6 +3202,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}else{ }else{
logClass('warning',"sqlite3_wasm_test_...() APIs unavailable."); logClass('warning',"sqlite3_wasm_test_...() APIs unavailable.");
} }
log("registered vfs list =",capi.sqlite3_js_vfs_list().join(', '));
TestUtil.runTests(sqlite3); TestUtil.runTests(sqlite3);
}); });
})(self); })(self);

View File

@@ -6,14 +6,10 @@
# GNUMakefile. # GNUMakefile.
######################################################################## ########################################################################
MAKEFILE.wasmfs := $(lastword $(MAKEFILE_LIST)) MAKEFILE.wasmfs := $(lastword $(MAKEFILE_LIST))
$(warning The WASMFS build is currently incomplete.)
# Maintenance reminder: these particular files cannot be built into a #dir.wasmfs := $(dir.wasm)
# subdirectory because loading of the auxiliary dir.wasmfs := $(dir.dout)
# sqlite3-wasmfs.worker.js file it creates fails if sqlite3-wasmfs.js
# is loaded from any directory other than the one in which the
# containing HTML lives. Similarly, they cannot be loaded from a
# Worker to an Emscripten quirk regarding loading nested Workers.
dir.wasmfs := $(dir.wasm)
sqlite3-wasmfs.js := $(dir.wasmfs)/sqlite3-wasmfs.js sqlite3-wasmfs.js := $(dir.wasmfs)/sqlite3-wasmfs.js
sqlite3-wasmfs.mjs := $(dir.wasmfs)/sqlite3-wasmfs.mjs sqlite3-wasmfs.mjs := $(dir.wasmfs)/sqlite3-wasmfs.mjs
sqlite3-wasmfs.wasm := $(dir.wasmfs)/sqlite3-wasmfs.wasm sqlite3-wasmfs.wasm := $(dir.wasmfs)/sqlite3-wasmfs.wasm
@@ -28,105 +24,92 @@ CLEAN_FILES += $(sqlite3-wasmfs.js) $(sqlite3-wasmfs.wasm) \
cflags.sqlite3-wasmfs := cflags.sqlite3-wasmfs :=
cflags.sqlite3-wasmfs += -std=c99 -fPIC cflags.sqlite3-wasmfs += -std=c99 -fPIC
cflags.sqlite3-wasmfs += -pthread cflags.sqlite3-wasmfs += -pthread
cflags.sqlite3-wasmfs += $(cflags.speedtest1) cflags.sqlite3-wasmfs += -DSQLITE_ENABLE_WASMFS
cflags.sqlite3-wasmfs += $(SQLITE_OPT) -DSQLITE_ENABLE_WASMFS
######################################################################## ########################################################################
# emcc flags specific to building the final .js/.wasm file... # emcc flags specific to building the final .js/.wasm file...
emcc.flags.sqlite3-wasmfs := -fPIC emcc.flags.sqlite3-wasmfs :=
emcc.flags.sqlite3-wasmfs += --no-entry emcc.flags.sqlite3-wasmfs += \
emcc.flags.sqlite3-wasmfs += --minify 0 -sEXPORTED_RUNTIME_METHODS=wasmMemory,allocateUTF8OnStack,stringToUTF8OnStack
emcc.flags.sqlite3-wasmfs += -sMODULARIZE
emcc.flags.sqlite3-wasmfs += -sEXPORT_NAME=$(sqlite3.js.init-func)
emcc.flags.sqlite3-wasmfs += -sSTRICT_JS
emcc.flags.sqlite3-wasmfs += -sDYNAMIC_EXECUTION=0
emcc.flags.sqlite3-wasmfs += -sNO_POLYFILL
emcc.flags.sqlite3-wasmfs += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
emcc.flags.sqlite3-wasmfs += -sEXPORTED_FUNCTIONS=@$(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api)
emcc.flags.sqlite3-wasmfs += -sEXPORTED_RUNTIME_METHODS=FS,wasmMemory,allocateUTF8OnStack
# wasmMemory ==> for -sIMPORTED_MEMORY # wasmMemory ==> for -sIMPORTED_MEMORY
# allocateUTF8OnStack ==> wasmfs internals # *OnStack ==> wasmfs internals (leaky abstraction)
emcc.flags.sqlite3-wasmfs += -sUSE_CLOSURE_COMPILER=0 emcc.flags.sqlite3-wasmfs += -sUSE_CLOSURE_COMPILER=0
emcc.flags.sqlite3-wasmfs += -Wno-limited-postlink-optimizations emcc.flags.sqlite3-wasmfs += -Wno-limited-postlink-optimizations
# ^^^^^ it likes to warn when we have "limited optimizations" via the -g3 flag. # ^^^^^ it likes to warn when we have "limited optimizations" via the -g3 flag.
emcc.flags.sqlite3-wasmfs += -sALLOW_TABLE_GROWTH
emcc.flags.sqlite3-wasmfs += -sSTACK_SIZE=512KB
emcc.flags.sqlite3-wasmfs += -sGLOBAL_BASE=4096 # HYPOTHETICALLY keep func table indexes from overlapping w/ heap addr.
emcc.flags.sqlite3-wasmfs += -sMEMORY64=0 emcc.flags.sqlite3-wasmfs += -sMEMORY64=0
emcc.flags.sqlite3-wasmfs += -sIMPORTED_MEMORY
emcc.flags.sqlite3-wasmfs += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.128) emcc.flags.sqlite3-wasmfs += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.128)
# ^^^^ 64MB is not enough for WASMFS/OPFS test runs using batch-runner.js # ^^^^ 64MB is not enough for WASMFS/OPFS test runs using batch-runner.js
sqlite3-wasmfs.fsflags := -pthread -sWASMFS \ sqlite3-wasmfs.fsflags := -pthread -sWASMFS \
-sPTHREAD_POOL_SIZE=2 -sENVIRONMENT=web,worker \ -sPTHREAD_POOL_SIZE=1 \
-sERROR_ON_UNDEFINED_SYMBOLS=0 -sLLD_REPORT_UNDEFINED -sERROR_ON_UNDEFINED_SYMBOLS=0 -sLLD_REPORT_UNDEFINED
# ^^^^^ why undefined symbols are necessary for the wasmfs build is anyone's guess. # ^^^^^ why undefined symbols are necessary for the wasmfs build is anyone's guess.
emcc.flags.sqlite3-wasmfs += $(sqlite3-wasmfs.fsflags) emcc.flags.sqlite3-wasmfs += $(sqlite3-wasmfs.fsflags)
#emcc.flags.sqlite3-wasmfs += -sALLOW_MEMORY_GROWTH emcc.flags.sqlite3-wasmfs += -sALLOW_MEMORY_GROWTH=0
#^^^ using ALLOW_MEMORY_GROWTH produces a warning from emcc: #^^^ using ALLOW_MEMORY_GROWTH produces a warning from emcc:
# USE_PTHREADS + ALLOW_MEMORY_GROWTH may run non-wasm code slowly, # USE_PTHREADS + ALLOW_MEMORY_GROWTH may run non-wasm code slowly,
# see https://github.com/WebAssembly/design/issues/1271 [-Wpthreads-mem-growth] # see https://github.com/WebAssembly/design/issues/1271 [-Wpthreads-mem-growth]
# And, indeed, it runs slowly if memory is permitted to grow. # And, indeed, it runs slowly if memory is permitted to grow.
emcc.flags.sqlite3-wasmfs.vanilla := #emcc.flags.sqlite3-wasmfs.vanilla :=
emcc.flags.sqlite3-wasmfs.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META #emcc.flags.sqlite3-wasmfs.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META
$(eval $(call call-make-pre-js,sqlite3-wasmfs,vanilla)) sqlite3-api.mjs.wasmfs := $(dir.tmp)/sqlite3-api-wasmfs.mjs
$(eval $(call call-make-pre-js,sqlite3-wasmfs,esm)) $(eval $(call SETUP_LIB_BUILD_MODE,sqlite3-wasmfs,esm,1,\
Xemcc.flags.sqlite3-wasmfs.vanilla += \ $(sqlite3-api.mjs.wasmfs), $(sqlite3-wasmfs.mjs),\
$(pre-post-common.flags.vanilla) \ $(c-pp.D.sqlite3-bundler-friendly) -Dwasmfs,\
$(pre-post-sqlite3-wasmfs.flags.vanilla) -sEXPORT_ES6 -sUSE_ES6_IMPORT_META\
Xemcc.flags.sqlite3-wasmfs.esm += \ ))
$(pre-post-common.flags.esm) \ $(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs): $(MAKEFILE.wasmfs)
$(pre-post-sqlite3-wasmfs.flags.esm) ########################################################################
$(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs): $(sqlite3-wasm.c) \ # Build quirk: we cannot build BOTH .js and .mjs with our current
$(EXPORTED_FUNCTIONS.api) $(MAKEFILE) $(MAKEFILE.wasmfs) # build infrastructure because the supplemental *.worker.js files get
$(sqlite3-wasmfs.js): $(pre-post-sqlite3-wasmfs.deps.vanilla) # generated with the name of the main module file
$(sqlite3-wasmfs.mjs): $(pre-post-sqlite3-wasmfs.deps.esm) # ($(sqlite3-wasmfs.{js,mjs})) hard-coded in them. Thus the last one
# SQLITE3-WASMFS.xJS.RECIPE is the wasmfs-specific counterpart # to get built gets the *.worker.js files mapped to it. In order to
# of SQLITE3.xJS.RECIPE from the main makefile. # build both modes they would need to have distinct base names or
define SQLITE3-WASMFS.xJS.RECIPE # output directories. "The problem" with giving them distinct base
@echo "Building $@ ..." # names is that it means that the corresponding .wasm file is also
$(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \ # built/saved multiple times.
$(cflags.sqlite3-wasmfs) \ #
$(emcc.flags.sqlite3-wasmfs) $(emcc.flags.sqlite3-wasmfs.$(1)) \ wasmfs.build.ext := mjs
$(pre-post-sqlite3-wasmfs.flags.$(1)) \ $(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs): $(SOAP.js.bld)
$(sqlite3-wasm.c) ifeq (js,$(wasmfs.build.ext))
@$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,$(1)) $(sqlite3-wasmfs.wasm): $(sqlite3-wasmfs.js)
chmod -x $(sqlite3-wasmfs.wasm) wasmfs: $(sqlite3-wasmfs.js)
$(maybe-wasm-strip) $(sqlite3-wasmfs.wasm) else
@ls -la $(sqlite3-wasmfs.wasm) sqlite3-wasmfs*js $(sqlite3-wasmfs.wasm): $(sqlite3-wasmfs.mjs)
endef wasmfs: $(sqlite3-wasmfs.mjs)
$(sqlite3-wasmfs.js): endif
$(call SQLITE3-WASMFS.xJS.RECIPE,vanilla)
$(sqlite3-wasmfs.mjs): $(sqlite3-wasmfs.js)
$(call SQLITE3-WASMFS.xJS.RECIPE,esm)
$(sqlite3-wasmfs.wasm): $(sqlite3-wasmfs.js)
wasmfs: $(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs)
#all: wasmfs #all: wasmfs
######################################################################## ########################################################################
# speedtest1 for wasmfs. # speedtest1 for wasmfs.
speedtest1-wasmfs.js := $(dir.wasmfs)/speedtest1-wasmfs.js speedtest1-wasmfs.mjs := $(dir.wasmfs)/speedtest1-wasmfs.mjs
speedtest1-wasmfs.wasm := $(subst .js,.wasm,$(speedtest1-wasmfs.js)) speedtest1-wasmfs.wasm := $(subst .mjs,.wasm,$(speedtest1-wasmfs.mjs))
emcc.flags.speedtest1-wasmfs := $(sqlite3-wasmfs.fsflags) emcc.flags.speedtest1-wasmfs := $(sqlite3-wasmfs.fsflags)
emcc.flags.speedtest1-wasmfs += $(SQLITE_OPT) -DSQLITE_ENABLE_WASMFS emcc.flags.speedtest1-wasmfs += $(SQLITE_OPT)
emcc.flags.speedtest1-wasmfs += -sALLOW_MEMORY_GROWTH=0 emcc.flags.speedtest1-wasmfs += -sALLOW_MEMORY_GROWTH=0
emcc.flags.speedtest1-wasmfs += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.128) emcc.flags.speedtest1-wasmfs += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.128)
#$(eval $(call call-make-pre-js,speedtest1-wasmfs,vanilla)) #$(eval $(call call-make-pre-js,speedtest1-wasmfs,ems))
$(speedtest1-wasmfs.js): $(speedtest1.cses) $(sqlite3-wasmfs.js) \ $(speedtest1-wasmfs.mjs): $(speedtest1.cfiles) $(sqlite3-wasmfs.js) \
$(MAKEFILE) $(MAKEFILE.wasmfs) \ $(MAKEFILE) $(MAKEFILE.wasmfs) \
$(pre-post-sqlite3-wasmfs.deps) \ $(pre-post-sqlite3-wasmfs-esm.deps) \
$(EXPORTED_FUNCTIONS.speedtest1) $(EXPORTED_FUNCTIONS.speedtest1)
@echo "Building $@ ..." @echo "Building $@ ..."
$(emcc.bin) \ $(emcc.bin) \
$(emcc.speedtest1.common) $(emcc.flags.speedtest1-wasmfs) \ $(pre-post-sqlite3-wasmfs-esm.flags) \
$(pre-post-sqlite3-wasmfs.flags.vanilla) \ $(cflags.common) \
$(cflags.sqlite3-wasmfs) \ $(cflags.sqlite3-wasmfs) \
-o $@ $(speedtest1.cses) -lm $(emcc.speedtest1.common) \
$(emcc.flags.speedtest1-vanilla) \
$(emcc.flags.sqlite3-wasmfs) \
$(emcc.flags.speedtest1-wasmfs) \
-o $@ $(speedtest1.cfiles) -lm
@$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,1)
$(maybe-wasm-strip) $(speedtest1-wasmfs.wasm) $(maybe-wasm-strip) $(speedtest1-wasmfs.wasm)
chmod -x $(speedtest1-wasmfs.wasm)
ls -la $@ $(speedtest1-wasmfs.wasm) ls -la $@ $(speedtest1-wasmfs.wasm)
#speedtest1: $(speedtest1-wasmfs.js) wasmfs: $(speedtest1-wasmfs.mjs)
wasmfs: $(speedtest1-wasmfs.js) CLEAN_FILES += $(speedtest1-wasmfs.mjs) $(speedtest1-wasmfs.wasm) \
CLEAN_FILES += $(speedtest1-wasmfs.js) $(speedtest1-wasmfs.wasm) \ $(subst .js,.worker.js,$(speedtest1-wasmfs.mjs))
$(subst .js,.worker.js,$(speedtest1-wasmfs.js))
# end speedtest1.js # end speedtest1.js
######################################################################## ########################################################################

View File

@@ -1,5 +1,5 @@
C Get\sfault\sinjection\sfor\stesting\sworking\scorrectly.\s\sOther\scode\sclean-up. C Update\sthe\slatest\strunk\senhancements\sinto\sthe\swal-shm-exceptions\sbranch.
D 2023-07-11T15:52:52.116 D 2023-07-24T12:59:53.689
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -92,7 +92,7 @@ F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b7292
F ext/fts5/fts5_config.c 051056a9052f5d3a4d1c695f996fd364f920e341f136c60ab2c04aa7e267113f F ext/fts5/fts5_config.c 051056a9052f5d3a4d1c695f996fd364f920e341f136c60ab2c04aa7e267113f
F ext/fts5/fts5_expr.c 58fb8ceddfb1cefcd54510f9f2f33c220ef9d1b3fa77462111f5ae2a825ab7b1 F ext/fts5/fts5_expr.c 58fb8ceddfb1cefcd54510f9f2f33c220ef9d1b3fa77462111f5ae2a825ab7b1
F ext/fts5/fts5_hash.c d4fb70940359f2120ccd1de7ffe64cc3efe65de9e8995b822cd536ff64c96982 F ext/fts5/fts5_hash.c d4fb70940359f2120ccd1de7ffe64cc3efe65de9e8995b822cd536ff64c96982
F ext/fts5/fts5_index.c fe98ebd8835760b9c787d20f6b50d648a761afd8e3b55780e718ee34c694743b F ext/fts5/fts5_index.c 430d3edfc5b51d02f0671e2b8268c12bf485f7dc80db2b61c996e74814bc46b0
F ext/fts5/fts5_main.c b4dba04a36aaf9b8e8cef0100b6dbb422cc74753eacc11d6401cac7a87c0f38d F ext/fts5/fts5_main.c b4dba04a36aaf9b8e8cef0100b6dbb422cc74753eacc11d6401cac7a87c0f38d
F ext/fts5/fts5_storage.c 76c6085239eb44424004c022e9da17a5ecd5aaec859fba90ad47d3b08f4c8082 F ext/fts5/fts5_storage.c 76c6085239eb44424004c022e9da17a5ecd5aaec859fba90ad47d3b08f4c8082
F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae
@@ -482,29 +482,29 @@ F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
F ext/wasm/GNUmakefile 38700d5074af690f004e4e5f3533164ab49693b9d0832929c4ecf97a0bc09494 F ext/wasm/GNUmakefile 4e8260d05c52d9924b853efbdfe052bd483cfe42f055567c1bbf29d274794b22
F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576 F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576
F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9 F ext/wasm/README.md 0895244c0539ae68cf8c70d59c2de512532fd47cfba313268e2b672e6359112e
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api d6a5078f48a5301ed17b9a30331075d9b2506e1360c1f0dee0c7816c10acd9ab F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api d6a5078f48a5301ed17b9a30331075d9b2506e1360c1f0dee0c7816c10acd9ab
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
F ext/wasm/api/README.md 77a2f1f2fc60a35def7455dffc8d3f2c56385d6ac5c6cecc60fa938252ea2c54 F ext/wasm/api/README.md 5eb44fa02e9c693a1884a3692428647894b0380b24bca120866b7a24c8786134
F ext/wasm/api/extern-post-js.c-pp.js 393ab78b807da94096eae1a68bfddb999a2299936a185d910162fe87a57a9a3a F ext/wasm/api/extern-post-js.c-pp.js 116749b7e55b7519129de06d3d353e19df68cfb24b12204aa4dc30c9a83023fe
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08902f15c34720ee4a1 F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08902f15c34720ee4a1
F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62
F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057afb08161d7511219 F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057afb08161d7511219
F ext/wasm/api/sqlite3-api-cleanup.js cc21e3486da748463e02bbe51e2464c6ac136587cdfd5aa00cd0b5385f6ca808 F ext/wasm/api/sqlite3-api-cleanup.js 23ceec5ef74a0e649b19694ca985fd89e335771e21f24f50df352a626a8c81bf
F ext/wasm/api/sqlite3-api-glue.js f1b2dcb944de5138bb5bd9a1559d2e76a4f3ec25260963d709e8237476688803 F ext/wasm/api/sqlite3-api-glue.js f1b2dcb944de5138bb5bd9a1559d2e76a4f3ec25260963d709e8237476688803
F ext/wasm/api/sqlite3-api-oo1.js 9678dc4d9a5d39632b6ffe6ea94a023119260815bf32f265bf5f6c36c9516db8 F ext/wasm/api/sqlite3-api-oo1.js 9678dc4d9a5d39632b6ffe6ea94a023119260815bf32f265bf5f6c36c9516db8
F ext/wasm/api/sqlite3-api-prologue.js 17f4ec398ba34c5c666fea8e8c4eb82064a35b302f2f2eb355283cd8d3f68ed5 F ext/wasm/api/sqlite3-api-prologue.js cbd7d6ba185f3a844a8b0020e954b49bbc2ca78b305d117bec2ceca21431795a
F ext/wasm/api/sqlite3-api-worker1.js 9f32af64df1a031071912eea7a201557fe39b1738645c0134562bb84e88e2fec F ext/wasm/api/sqlite3-api-worker1.js 9f32af64df1a031071912eea7a201557fe39b1738645c0134562bb84e88e2fec
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 961bbc3ccc1fa4e91d6519a96e8811ad7ae60173bd969fee7775dacb6eee1da2 F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
F ext/wasm/api/sqlite3-v-helper.js e5c202a9ecde9ef818536d3f5faf26c03a1a9f5192b1ddea8bdabf30d75ef487 F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 05f2563ddebfdc7a0f0ac0eb7cb381bb72043299aae1600ba9367c12f52b3fcc F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 7931b50b63246a3d6b46a4c703c28820aa10c5b1ae7c0718e1f58dae2cf6db85
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e7a690e0e78ff4d563f2eca468f91db69f001ff4b79c6d2304cbb6f62dca437d
F ext/wasm/api/sqlite3-wasm.c 12a096d8e58a0af0589142bae5a3c27a0c7e19846755a1a37d2c206352fbedda F ext/wasm/api/sqlite3-wasm.c 8867f1d41c112fb4a2cfe22ff224eccaf309fcdea266cee0ec554f85db72ef0f
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f
F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75 F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8 F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
@@ -512,8 +512,8 @@ F ext/wasm/batch-runner.js 0dad6a02ad796f1003d3b7048947d275c4d6277f63767b8e685c2
F ext/wasm/c-pp.c 6d80d8569d85713effe8b0818a3cf51dc779e3f0bf8dc88771b8998552ee25b4 F ext/wasm/c-pp.c 6d80d8569d85713effe8b0818a3cf51dc779e3f0bf8dc88771b8998552ee25b4
F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51 F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15 F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
F ext/wasm/common/testing.css 0ff15602a3ab2bad8aef2c3bd120c7ee3fd1c2054ad2ace7e214187ae68d926f F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f
F ext/wasm/common/whwasmutil.js 03407d7b61b817fd135c82401987e56688a45ee4d6b9c0eced160c0000d6e4c2 F ext/wasm/common/whwasmutil.js ae263dec9d7384f4c530f324b99d00516a4d6f26424372daee65031e00eb49b3
F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6 F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6
@@ -523,7 +523,7 @@ F ext/wasm/demo-worker1-promiser.html 1de7c248c7c2cfd4a5783d2aa154bce62d74c6de98
F ext/wasm/demo-worker1-promiser.js 5e5c7d7c91cd7aae9cc733afd02569ba9c6928292db413b550e8b842f4b75e87 F ext/wasm/demo-worker1-promiser.js 5e5c7d7c91cd7aae9cc733afd02569ba9c6928292db413b550e8b842f4b75e87
F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d
F ext/wasm/demo-worker1.js 836bece8615b17b1b572584f7b15912236a5947fe8c68b98d2737d7e287447ef F ext/wasm/demo-worker1.js 836bece8615b17b1b572584f7b15912236a5947fe8c68b98d2737d7e287447ef
F ext/wasm/dist.make 451fb1b732257849f6e898d2a862512a0401500ed369ef53bdfeddf9c77bc3b9 F ext/wasm/dist.make 3a851858aad72e246a5d9c5aaf6b6a144305f1bf898ac1846760ea7bab95c9a3
F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f
F ext/wasm/fiddle.make dbe36b90b8907ae28ecb9c0e9fd8389dbdaecf117ea4fb2ea33864bdfa498a94 F ext/wasm/fiddle.make dbe36b90b8907ae28ecb9c0e9fd8389dbdaecf117ea4fb2ea33864bdfa498a94
F ext/wasm/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/wasm/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
@@ -531,15 +531,16 @@ F ext/wasm/fiddle/fiddle-worker.js 163d6139a93fab4bcb72064923df050d4e7c0ff0d8aa0
F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5653284071715 F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5653284071715
F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2 F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2
F ext/wasm/index-dist.html 22379774f0ad4edcaaa8cf9c674c82e794cc557719a8addabed74eb8069d412e F ext/wasm/index-dist.html 22379774f0ad4edcaaa8cf9c674c82e794cc557719a8addabed74eb8069d412e
F ext/wasm/index.html dd900891844caebd9cadbddd704f66bd841d7c12fd69ce5af490e2c10fb49f45 F ext/wasm/index.html b4e55de741be9fb7656445ea55085f703a784aebde620e1c4852fa21c1ac1c5b
F ext/wasm/jaccwabyt/jaccwabyt.js 1264710db3cfbcb6887d95665b7aeba60c1126eaef789ca4cf1a4a17d5bc7f54 F ext/wasm/jaccwabyt/jaccwabyt.js 1264710db3cfbcb6887d95665b7aeba60c1126eaef789ca4cf1a4a17d5bc7f54
F ext/wasm/jaccwabyt/jaccwabyt.md 37911f00db12cbcca73aa1ed72594430365f30aafae2fa9c886961de74e5e0eb F ext/wasm/jaccwabyt/jaccwabyt.md 37911f00db12cbcca73aa1ed72594430365f30aafae2fa9c886961de74e5e0eb
F ext/wasm/module-symbols.html 841de62fc198988b8330e238c260e70ec93028b096e1a1234db31b187a899d10 F ext/wasm/module-symbols.html 841de62fc198988b8330e238c260e70ec93028b096e1a1234db31b187a899d10
F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06 F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96 w ext/wasm/scratchpad-wasmfs-main.html
F ext/wasm/scratchpad-wasmfs-main.js 4c140457f4d6da9d646a49addd91edb6e9ad1643c6c48e3258b5bce24725dc18 F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63 w ext/wasm/scratchpad-wasmfs-main.js
F ext/wasm/speedtest1-wasmfs.html 7a301f4f5b6ad4f5d37fd6e7ca03a2f5d5547fd289da60a39075a93d7646d354 F ext/wasm/speedtest1-wasmfs.html 0e9d335a9b5b5fafe6e1bc8dc0f0ca7e22e6eb916682a2d7c36218bb7d67379d
F ext/wasm/speedtest1-worker.html 82869822e641c1bef3ec0cd2d7d2b6a42d0b4f68a7b160fb2e1dd0b523940a9b F ext/wasm/speedtest1-wasmfs.mjs ac5cadbf4ffe69e9eaac8b45e8523f030521e02bb67d654c6eb5236d9c456cbe
F ext/wasm/speedtest1-worker.js 13b57c4a41729678a1194014afec2bd5b94435dcfc8d1039dfa9a533ac819ee1 F ext/wasm/speedtest1-worker.html e33e2064bda572c0c3ebaec7306c35aa758d9d27e245d67e807f8cc4a9351cc5
F ext/wasm/speedtest1-worker.js 315d26198c46be7c85e26fda15d80ef882424276abde25ffd8b026fb02a35d8c
F ext/wasm/speedtest1.html ff048b4a623aa192e83e143e48f1ce2a899846dd42c023fdedc8772b6e3f07da F ext/wasm/speedtest1.html ff048b4a623aa192e83e143e48f1ce2a899846dd42c023fdedc8772b6e3f07da
F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x
F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0 F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0
@@ -548,12 +549,12 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2 F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
F ext/wasm/tester1.c-pp.js 1a05497ae2b2fcca008d43b37072f9b841e1c970c06c01eb0faf675db567bfc8 F ext/wasm/tester1.c-pp.js f835c9f703b562142f23a3607fa4a34cb6aece5fb5d674ea5bd7d37b0e47e104
F ext/wasm/tests/opfs/concurrency/index.html 0802373d57034d51835ff6041cda438c7a982deea6079efd98098d3e42fbcbc1 F ext/wasm/tests/opfs/concurrency/index.html 0802373d57034d51835ff6041cda438c7a982deea6079efd98098d3e42fbcbc1
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
F ext/wasm/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd72273503ae7d5 F ext/wasm/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd72273503ae7d5
F ext/wasm/wasmfs.make cf9a68162d92ca2bcb0b9528b244cb36d5cc2d84ccc9c2d398461927d6e75aea F ext/wasm/wasmfs.make 8a4955882aaa0783b3f60a9484a1f0f3d8b6f775c0fcd17c082f31966f1bc16a
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0 F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
@@ -576,7 +577,7 @@ F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523 F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645 F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645
F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522 F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
F src/btree.c c9400cc1509116a29120dc06feb00ca7e26b5a4a6dba80758b1ba109d8fce5a4 F src/btree.c 2281facb0531d53fb42c03d1f32bc1b5903564d782ec5ff4ffc63171d960e2aa
F src/btree.h aa354b9bad4120af71e214666b35132712b8f2ec11869cb2315c52c81fad45cc F src/btree.h aa354b9bad4120af71e214666b35132712b8f2ec11869cb2315c52c81fad45cc
F src/btreeInt.h 3b4eff7155c0cea6971dc51f62e3529934a15a6640ec607dd42a767e379cb3a9 F src/btreeInt.h 3b4eff7155c0cea6971dc51f62e3529934a15a6640ec607dd42a767e379cb3a9
F src/build.c a8ae3b32d9aa9bbd2c0e97d7c0dd80def9fbca408425de1608f57ee6f47f45f4 F src/build.c a8ae3b32d9aa9bbd2c0e97d7c0dd80def9fbca408425de1608f57ee6f47f45f4
@@ -587,17 +588,17 @@ F src/date.c f73f203b3877cef866c60ab402aec2bf89597219b60635cf50cbe3c5e4533e94
F src/dbpage.c f3eea5f7ec47e09ee7da40f42b25092ecbe961fc59566b8e5f705f34335b2387 F src/dbpage.c f3eea5f7ec47e09ee7da40f42b25092ecbe961fc59566b8e5f705f34335b2387
F src/dbstat.c ec92074baa61d883de58c945162d9e666c13cd7cf3a23bc38b4d1c4d0b2c2bef F src/dbstat.c ec92074baa61d883de58c945162d9e666c13cd7cf3a23bc38b4d1c4d0b2c2bef
F src/delete.c cd5f5cd06ed0b6a882ec1a8c2a0d73b3cecb28479ad19e9931c4706c5e2182be F src/delete.c cd5f5cd06ed0b6a882ec1a8c2a0d73b3cecb28479ad19e9931c4706c5e2182be
F src/expr.c 8d1656b65e26af3e34f78e947ac423f0d20c214ed25a67486e433bf16ca6b543 F src/expr.c ef4a81822da6f767696bd7f4b9983328af061158958138540142285a5b1181b7
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c a7fcbf7e66d14dbb73cf49f31489ebf66d0e6006c62b95246924a3bae9f37b36 F src/fkey.c a7fcbf7e66d14dbb73cf49f31489ebf66d0e6006c62b95246924a3bae9f37b36
F src/func.c cffa6edb4aa4865d8e237022399ba9c2b22fd11e5581efba7c5b524b525952ca F src/func.c cc1da67fd643a43cfe691784158ec656d8ec6d13bb17e67018b01b38b3e4f5ab
F src/global.c 29f56a330ed9d1b5cd9b79ac0ca36f97ac3afc730ff8bfa987b0db9e559d684d F src/global.c 29f56a330ed9d1b5cd9b79ac0ca36f97ac3afc730ff8bfa987b0db9e559d684d
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220 F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c 14c474fb1249a46eb44e878e2361f36abfe686b134039b0d1883d93d61505b4a F src/json.c 46ea5566e1363f4f353db79b0378c2bf8ffdf9d4667daee3df67b14669767bed
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 176d6b2cb18a6ad73b133db17f6fc351c4d9a2d510deebdb76c22bde9cfd1465 F src/loadext.c 176d6b2cb18a6ad73b133db17f6fc351c4d9a2d510deebdb76c22bde9cfd1465
F src/main.c 512b1d45bc556edf4471a845afb7ba79e64bd5b832ab222dc195c469534cd002 F src/main.c 512b1d45bc556edf4471a845afb7ba79e64bd5b832ab222dc195c469534cd002
@@ -642,7 +643,7 @@ F src/shell.c.in d320d8a13636de06d777cc1eab981caca304e175464e98183cf4ea68d93db81
F src/sqlite.h.in 6a0ffe5886af2528baff6087efb34a4915d2ff394d15df32e6e2de8524b756d2 F src/sqlite.h.in 6a0ffe5886af2528baff6087efb34a4915d2ff394d15df32e6e2de8524b756d2
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4 F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
F src/sqliteInt.h 002a6c3e24752d123468c5d948a80e2cd4acf01badce268f9dd98b581cd7bb96 F src/sqliteInt.h dcb1a885e8b6cb78df618944b89d44361a99d0fe33e1bba2c150a855f7dc5599
F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6 F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -705,24 +706,24 @@ F src/trigger.c ad6ab9452715fa9a8075442e15196022275b414b9141b566af8cdb7a1605f2b0
F src/update.c 0aa36561167a7c40d01163238c297297962f31a15a8d742216b3c37cdf25f731 F src/update.c 0aa36561167a7c40d01163238c297297962f31a15a8d742216b3c37cdf25f731
F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145 F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
F src/util.c 161e49e88b080c2370a4990aa55f51f9edcaf8c41c3cb06cd4c37ffde1c85e6d F src/util.c 987e31e45aa9a7f206b8b86b0d09dd440263b869b627931a8dace5f39638e698
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104 F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
F src/vdbe.c 74282a947234513872a83b0bab1b8c644ece64b3e27b053ef17677c8ff9c81e0 F src/vdbe.c 4cda877d413a18fa07346b08d6959b3d18ce982357921e7acb9649fca2534a12
F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0 F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0
F src/vdbeInt.h 7bd49eef8f89c1a271fbf12d80a206bf56c876814c5fc6bee340f4e1907095ae F src/vdbeInt.h 401813862f9d75af01bdb2ab99253ad019e9d6ddcc8058e4fa61a43e9a60d1f7
F src/vdbeapi.c de9703f8705afc393cc2864669ce28cf9516983c8331d59aa2b978de01634365 F src/vdbeapi.c dde6c4d0f87486f056b9db4d1ea185bb1d84a6839102b86e76316ba590d07cc7
F src/vdbeaux.c d56f179577cee110d1d60129a07d37035e85b0d39a272d7587f3dbb99b40b94a F src/vdbeaux.c d56f179577cee110d1d60129a07d37035e85b0d39a272d7587f3dbb99b40b94a
F src/vdbeblob.c 2516697b3ee8154eb8915f29466fb5d4f1ae39ee8b755ea909cefaf57ec5e2ce F src/vdbeblob.c 2516697b3ee8154eb8915f29466fb5d4f1ae39ee8b755ea909cefaf57ec5e2ce
F src/vdbemem.c cf4a1556dd5b18c071cf7c243373c29ce752eb516022e3ad49ba72f08b785033 F src/vdbemem.c 40afb83ed848e235848ffdd3ba25adca4ba602111b8ed3b05ae3b1b12e0eacee
F src/vdbesort.c 0d40dca073c94e158ead752ef4225f4fee22dee84145e8c00ca2309afb489015 F src/vdbesort.c 0d40dca073c94e158ead752ef4225f4fee22dee84145e8c00ca2309afb489015
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823 F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
F src/vdbevtab.c aae4bd769410eb7e1d02c42613eec961d514459b1c3c1c63cfc84e92a137daac F src/vdbevtab.c aae4bd769410eb7e1d02c42613eec961d514459b1c3c1c63cfc84e92a137daac
F src/vtab.c 1ecf8c3745d29275688d583e12822fa984d421e0286b5ef50c137bc3bf6d7a64 F src/vtab.c 1ecf8c3745d29275688d583e12822fa984d421e0286b5ef50c137bc3bf6d7a64
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c e4bfb243cc1f6f89c7fba5dd8872ae38a8c1dcc760c276dbb164edb7290072a6 F src/wal.c 17a7ec957bd66e46a7d6403a8d55ce92518fb382ec598a5f50e2326de0206a80
F src/wal.h 04a9e53121d5076f2a173b0f2facb39d33047093fee71bd3bbe6b1f6f1f5fd4b F src/wal.h 04a9e53121d5076f2a173b0f2facb39d33047093fee71bd3bbe6b1f6f1f5fd4b
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
F src/where.c 2dc708cf8b6a691fb79f16bbc46567497ee6f991043318d421e294b2da114d93 F src/where.c 477fcc5e561ef169e6002499602af6b805156c2aae6b2f5c2c93ef8c1cd64768
F src/whereInt.h c7d19902863beadec1d04e66aca39c0bcd60b74f05f0eaa7422c7005dfc5d51a F src/whereInt.h c7d19902863beadec1d04e66aca39c0bcd60b74f05f0eaa7422c7005dfc5d51a
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1 F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00 F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00
@@ -1222,7 +1223,7 @@ F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ff
F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9e1946 F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9e1946
F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json/README.md 506af1f54574b524106acb50d1a341ab5ddfa6d83fe25095007892b07e663e85 F test/json/README.md 0992b8ccbecd8424b84c1173f9ac56bcc0ae96d49912fd2d86c04eb1f3cba7af
F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd28656fb261bddc8a3f F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd28656fb261bddc8a3f
F test/json/json-q1.txt 335a7c8ab291d354f33b7decc9559e99a2823d4142291c4be7aa339a631f3c2d F test/json/json-q1.txt 335a7c8ab291d354f33b7decc9559e99a2823d4142291c4be7aa339a631f3c2d
F test/json/json-speed-check.sh 8b7babf530faa58bd59d6d362cec8e9036a68c5457ff46f3b1f1511d21af6737 x F test/json/json-speed-check.sh 8b7babf530faa58bd59d6d362cec8e9036a68c5457ff46f3b1f1511d21af6737 x
@@ -2044,8 +2045,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 4c950872c870a5968fa4cb8840cf60569a66c0e508811ee79992825ec9c02da3 P ff492277ed00c1f637a5b4ccd6d8193ea22f6781f90073861588a2b7d5c045b7 c1b080e39397c983c13a5e79303223827de7b4946c18a79396851ec1814782f3
R 966aa4944515db815a2a3b1d2b09adbd R 2d227170a4d38cef4891eb7e41ae2e61
U drh U drh
Z 4e4c72cb034026cb3cf7caeaeea5ca69 Z bee2c2751faa3281b3853d97c12aa683
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
ff492277ed00c1f637a5b4ccd6d8193ea22f6781f90073861588a2b7d5c045b7 3187ee3f69fc28a259ba0e951ac10a65c07ef2c3866acbefaf9544333a930cc6

View File

@@ -1534,7 +1534,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){
pPage->xParseCell(pPage, pCell, &info); pPage->xParseCell(pPage, pCell, &info);
if( info.nLocal<info.nPayload ){ if( info.nLocal<info.nPayload ){
Pgno ovfl; Pgno ovfl;
if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){ if( SQLITE_OVERFLOW(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
testcase( pSrc!=pPage ); testcase( pSrc!=pPage );
*pRC = SQLITE_CORRUPT_BKPT; *pRC = SQLITE_CORRUPT_BKPT;
return; return;
@@ -8695,7 +8695,7 @@ static int balance_nonroot(
assert( iOvflSpace <= (int)pBt->pageSize ); assert( iOvflSpace <= (int)pBt->pageSize );
for(k=0; ALWAYS(k<NB*2) && b.ixNx[k]<=j; k++){} for(k=0; ALWAYS(k<NB*2) && b.ixNx[k]<=j; k++){}
pSrcEnd = b.apEnd[k]; pSrcEnd = b.apEnd[k];
if( SQLITE_WITHIN(pSrcEnd, pCell, pCell+sz) ){ if( SQLITE_OVERFLOW(pSrcEnd, pCell, pCell+sz) ){
rc = SQLITE_CORRUPT_BKPT; rc = SQLITE_CORRUPT_BKPT;
goto balance_cleanup; goto balance_cleanup;
} }

View File

@@ -4690,8 +4690,7 @@ expr_code_doover:
} }
} }
sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_FACTOR);
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
}else{ }else{
r1 = 0; r1 = 0;
} }

View File

@@ -1227,6 +1227,7 @@ static void charFunc(
*zOut++ = 0x80 + (u8)(c & 0x3F); *zOut++ = 0x80 + (u8)(c & 0x3F);
} \ } \
} }
*zOut = 0;
sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8); sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8);
} }
@@ -1764,11 +1765,10 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
p->ovrfl = 1; p->ovrfl = 1;
kahanBabuskaNeumaierInit(p, p->iSum); kahanBabuskaNeumaierInit(p, p->iSum);
p->approx = 1; p->approx = 1;
kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0])); kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0]));
} }
} }
}else{ }else{
p->approx = 1;
if( type==SQLITE_INTEGER ){ if( type==SQLITE_INTEGER ){
kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0])); kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0]));
}else{ }else{

View File

@@ -218,12 +218,35 @@ static int jsonGrow(JsonString *p, u32 N){
/* Append N bytes from zIn onto the end of the JsonString string. /* Append N bytes from zIn onto the end of the JsonString string.
*/ */
static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ static SQLITE_NOINLINE void jsonAppendExpand(
if( N==0 ) return; JsonString *p,
if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; const char *zIn,
u32 N
){
assert( N>0 );
if( jsonGrow(p,N) ) return;
memcpy(p->zBuf+p->nUsed, zIn, N); memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N; p->nUsed += N;
} }
static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
if( N==0 ) return;
if( N+p->nUsed >= p->nAlloc ){
jsonAppendExpand(p,zIn,N);
}else{
memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N;
}
}
static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){
assert( N>0 );
if( N+p->nUsed >= p->nAlloc ){
jsonAppendExpand(p,zIn,N);
}else{
memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N;
}
}
/* Append formatted text (not to exceed N bytes) to the JsonString. /* Append formatted text (not to exceed N bytes) to the JsonString.
*/ */
@@ -238,10 +261,17 @@ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
/* Append a single character /* Append a single character
*/ */
static void jsonAppendChar(JsonString *p, char c){ static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){
if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return; if( jsonGrow(p,1) ) return;
p->zBuf[p->nUsed++] = c; p->zBuf[p->nUsed++] = c;
} }
static void jsonAppendChar(JsonString *p, char c){
if( p->nUsed>=p->nAlloc ){
jsonAppendCharExpand(p,c);
}else{
p->zBuf[p->nUsed++] = c;
}
}
/* Append a comma separator to the output buffer, if the previous /* Append a comma separator to the output buffer, if the previous
** character is not '[' or '{'. ** character is not '[' or '{'.
@@ -250,7 +280,8 @@ static void jsonAppendSeparator(JsonString *p){
char c; char c;
if( p->nUsed==0 ) return; if( p->nUsed==0 ) return;
c = p->zBuf[p->nUsed-1]; c = p->zBuf[p->nUsed-1];
if( c!='[' && c!='{' ) jsonAppendChar(p, ','); if( c=='[' || c=='{' ) return;
jsonAppendChar(p, ',');
} }
/* Append the N-byte string in zIn to the end of the JsonString string /* Append the N-byte string in zIn to the end of the JsonString string
@@ -310,7 +341,7 @@ static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
while( N>0 ){ while( N>0 ){
for(i=0; i<N && zIn[i]!='\\'; i++){} for(i=0; i<N && zIn[i]!='\\'; i++){}
if( i>0 ){ if( i>0 ){
jsonAppendRaw(p, zIn, i); jsonAppendRawNZ(p, zIn, i);
zIn += i; zIn += i;
N -= i; N -= i;
if( N==0 ) break; if( N==0 ) break;
@@ -321,16 +352,16 @@ static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
jsonAppendChar(p, '\''); jsonAppendChar(p, '\'');
break; break;
case 'v': case 'v':
jsonAppendRaw(p, "\\u0009", 6); jsonAppendRawNZ(p, "\\u0009", 6);
break; break;
case 'x': case 'x':
jsonAppendRaw(p, "\\u00", 4); jsonAppendRawNZ(p, "\\u00", 4);
jsonAppendRaw(p, &zIn[2], 2); jsonAppendRawNZ(p, &zIn[2], 2);
zIn += 2; zIn += 2;
N -= 2; N -= 2;
break; break;
case '0': case '0':
jsonAppendRaw(p, "\\u0000", 6); jsonAppendRawNZ(p, "\\u0000", 6);
break; break;
case '\r': case '\r':
if( zIn[2]=='\n' ){ if( zIn[2]=='\n' ){
@@ -348,7 +379,7 @@ static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
N -= 2; N -= 2;
break; break;
default: default:
jsonAppendRaw(p, zIn, 2); jsonAppendRawNZ(p, zIn, 2);
break; break;
} }
zIn += 2; zIn += 2;
@@ -378,11 +409,12 @@ static void jsonAppendNormalizedInt(JsonString *p, const char *zIn, u32 N){
jsonPrintf(100,p,"%lld",i); jsonPrintf(100,p,"%lld",i);
}else{ }else{
assert( rc==2 ); assert( rc==2 );
jsonAppendRaw(p, "9.0e999", 7); jsonAppendRawNZ(p, "9.0e999", 7);
} }
return; return;
} }
jsonAppendRaw(p, zIn, N); assert( N>0 );
jsonAppendRawNZ(p, zIn, N);
} }
/* /*
@@ -414,7 +446,7 @@ static void jsonAppendNormalizedReal(JsonString *p, const char *zIn, u32 N){
} }
} }
if( N>0 ){ if( N>0 ){
jsonAppendRaw(p, zIn, N); jsonAppendRawNZ(p, zIn, N);
} }
} }
@@ -430,7 +462,7 @@ static void jsonAppendValue(
){ ){
switch( sqlite3_value_type(pValue) ){ switch( sqlite3_value_type(pValue) ){
case SQLITE_NULL: { case SQLITE_NULL: {
jsonAppendRaw(p, "null", 4); jsonAppendRawNZ(p, "null", 4);
break; break;
} }
case SQLITE_FLOAT: { case SQLITE_FLOAT: {
@@ -469,7 +501,8 @@ static void jsonAppendValue(
*/ */
static void jsonResult(JsonString *p){ static void jsonResult(JsonString *p){
if( p->bErr==0 ){ if( p->bErr==0 ){
sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, jsonAppendChar(p, 0);
sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed-1,
p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
SQLITE_UTF8); SQLITE_UTF8);
jsonZero(p); jsonZero(p);
@@ -538,15 +571,15 @@ static void jsonRenderNode(
switch( pNode->eType ){ switch( pNode->eType ){
default: { default: {
assert( pNode->eType==JSON_NULL ); assert( pNode->eType==JSON_NULL );
jsonAppendRaw(pOut, "null", 4); jsonAppendRawNZ(pOut, "null", 4);
break; break;
} }
case JSON_TRUE: { case JSON_TRUE: {
jsonAppendRaw(pOut, "true", 4); jsonAppendRawNZ(pOut, "true", 4);
break; break;
} }
case JSON_FALSE: { case JSON_FALSE: {
jsonAppendRaw(pOut, "false", 5); jsonAppendRawNZ(pOut, "false", 5);
break; break;
} }
case JSON_STRING: { case JSON_STRING: {
@@ -562,7 +595,8 @@ static void jsonRenderNode(
}else if( pNode->jnFlags & JNODE_JSON5 ){ }else if( pNode->jnFlags & JNODE_JSON5 ){
jsonAppendNormalizedString(pOut, pNode->u.zJContent, pNode->n); jsonAppendNormalizedString(pOut, pNode->u.zJContent, pNode->n);
}else{ }else{
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); assert( pNode->n>0 );
jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
} }
break; break;
} }
@@ -571,7 +605,8 @@ static void jsonRenderNode(
if( pNode->jnFlags & JNODE_JSON5 ){ if( pNode->jnFlags & JNODE_JSON5 ){
jsonAppendNormalizedReal(pOut, pNode->u.zJContent, pNode->n); jsonAppendNormalizedReal(pOut, pNode->u.zJContent, pNode->n);
}else{ }else{
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); assert( pNode->n>0 );
jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
} }
break; break;
} }
@@ -580,7 +615,8 @@ static void jsonRenderNode(
if( pNode->jnFlags & JNODE_JSON5 ){ if( pNode->jnFlags & JNODE_JSON5 ){
jsonAppendNormalizedInt(pOut, pNode->u.zJContent, pNode->n); jsonAppendNormalizedInt(pOut, pNode->u.zJContent, pNode->n);
}else{ }else{
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); assert( pNode->n>0 );
jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
} }
break; break;
} }
@@ -882,7 +918,8 @@ static int jsonParseAddNode(
const char *zContent /* Content */ const char *zContent /* Content */
){ ){
JsonNode *p; JsonNode *p;
if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){ assert( pParse->aNode!=0 || pParse->nNode>=pParse->nAlloc );
if( pParse->nNode>=pParse->nAlloc ){
return jsonParseAddNodeExpand(pParse, eType, n, zContent); return jsonParseAddNodeExpand(pParse, eType, n, zContent);
} }
p = &pParse->aNode[pParse->nNode]; p = &pParse->aNode[pParse->nNode];
@@ -1235,15 +1272,31 @@ json_parse_restart:
jnFlags = 0; jnFlags = 0;
parse_string: parse_string:
cDelim = z[i]; cDelim = z[i];
j = i+1; for(j=i+1; 1; j++){
for(;;){ static const char aOk[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
if( aOk[(unsigned char)z[j]] ) continue;
c = z[j]; c = z[j];
if( (c & ~0x1f)==0 ){ if( c==cDelim ){
/* Control characters are not allowed in strings */ break;
pParse->iErr = j; }else if( c=='\\' ){
return -1;
}
if( c=='\\' ){
c = z[++j]; c = z[++j];
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|| c=='n' || c=='r' || c=='t' || c=='n' || c=='r' || c=='t'
@@ -1263,10 +1316,11 @@ json_parse_restart:
pParse->iErr = j; pParse->iErr = j;
return -1; return -1;
} }
}else if( c==cDelim ){ }else if( c<=0x1f ){
break; /* Control characters are not allowed in strings */
pParse->iErr = j;
return -1;
} }
j++;
} }
jsonParseAddNode(pParse, JSON_STRING | (jnFlags<<8), j+1-i, &z[i]); jsonParseAddNode(pParse, JSON_STRING | (jnFlags<<8), j+1-i, &z[i]);
return j+1; return j+1;
@@ -2003,12 +2057,12 @@ static void jsonParseFunc(
assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 ); assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 );
if( x.aNode[i].u.zJContent!=0 ){ if( x.aNode[i].u.zJContent!=0 ){
assert( x.aNode[i].eU==1 ); assert( x.aNode[i].eU==1 );
jsonAppendRaw(&s, " ", 1); jsonAppendChar(&s, ' ');
jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n); jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
}else{ }else{
assert( x.aNode[i].eU==0 ); assert( x.aNode[i].eU==0 );
} }
jsonAppendRaw(&s, "\n", 1); jsonAppendChar(&s, '\n');
} }
jsonParseReset(&x); jsonParseReset(&x);
jsonResult(&s); jsonResult(&s);
@@ -2175,11 +2229,11 @@ static void jsonExtractFunc(
*/ */
jsonInit(&jx, ctx); jsonInit(&jx, ctx);
if( sqlite3Isdigit(zPath[0]) ){ if( sqlite3Isdigit(zPath[0]) ){
jsonAppendRaw(&jx, "$[", 2); jsonAppendRawNZ(&jx, "$[", 2);
jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
jsonAppendRaw(&jx, "]", 2); jsonAppendRawNZ(&jx, "]", 2);
}else{ }else{
jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='[')); jsonAppendRawNZ(&jx, "$.", 1 + (zPath[0]!='['));
jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
jsonAppendChar(&jx, 0); jsonAppendChar(&jx, 0);
} }
@@ -2214,7 +2268,7 @@ static void jsonExtractFunc(
if( pNode ){ if( pNode ){
jsonRenderNode(pNode, &jx, 0); jsonRenderNode(pNode, &jx, 0);
}else{ }else{
jsonAppendRaw(&jx, "null", 4); jsonAppendRawNZ(&jx, "null", 4);
} }
} }
if( i==argc ){ if( i==argc ){

View File

@@ -889,8 +889,31 @@ typedef INT16_TYPE LogEst;
** the end of buffer S. This macro returns true if P points to something ** the end of buffer S. This macro returns true if P points to something
** contained within the buffer S. ** contained within the buffer S.
*/ */
#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E))) #define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
/*
** P is one byte past the end of a large buffer. Return true if a span of bytes
** between S..E crosses the end of that buffer. In other words, return true
** if the sub-buffer S..E-1 overflows the buffer show last byte is P-1.
**
** S is the start of the span. E is one byte past the end of end of span.
**
** P
** |-----------------| FALSE
** |-------|
** S E
**
** P
** |-----------------|
** |-------| TRUE
** S E
**
** P
** |-----------------|
** |-------| FALSE
** S E
*/
#define SQLITE_OVERFLOW(P,S,E) (((uptr)(S)<(uptr)(P))&&((uptr)(E)>(uptr)(P)))
/* /*
** Macros to determine whether the machine is big or little endian, ** Macros to determine whether the machine is big or little endian,

View File

@@ -863,7 +863,9 @@ int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
}else }else
#endif /* SQLITE_OMIT_HEX_INTEGER */ #endif /* SQLITE_OMIT_HEX_INTEGER */
{ {
return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8); int n = (int)(0x3fffffff&strspn(z,"+- \n\t0123456789"));
if( z[n] ) n++;
return sqlite3Atoi64(z, pOut, n, SQLITE_UTF8);
} }
} }

View File

@@ -556,6 +556,9 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){
sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.'); sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.');
} }
sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]); sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]);
if( f & MEM_Term ){
sqlite3_str_appendf(pStr, "(0-term)");
}
} }
} }
#endif #endif
@@ -3085,6 +3088,9 @@ op_column_restart:
rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest); rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
if( rc!=SQLITE_OK ) goto abort_due_to_error; if( rc!=SQLITE_OK ) goto abort_due_to_error;
sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
if( (t&1)!=0 && encoding==SQLITE_UTF8 ){
pDest->flags |= MEM_Term;
}
pDest->flags &= ~MEM_Ephem; pDest->flags &= ~MEM_Ephem;
} }
} }

View File

@@ -611,6 +611,7 @@ int sqlite3VdbeMemSetZeroBlob(Mem*,int);
int sqlite3VdbeMemIsRowSet(const Mem*); int sqlite3VdbeMemIsRowSet(const Mem*);
#endif #endif
int sqlite3VdbeMemSetRowSet(Mem*); int sqlite3VdbeMemSetRowSet(Mem*);
void sqlite3VdbeMemZeroTerminateIfAble(Mem*);
int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*);
int sqlite3VdbeMemStringify(Mem*, u8, u8); int sqlite3VdbeMemStringify(Mem*, u8, u8);
int sqlite3IntFloatCompare(i64,double); int sqlite3IntFloatCompare(i64,double);

View File

@@ -514,6 +514,7 @@ void sqlite3_result_text64(
(void)invokeValueDestructor(z, xDel, pCtx); (void)invokeValueDestructor(z, xDel, pCtx);
}else{ }else{
setResultStrOrError(pCtx, z, (int)n, enc, xDel); setResultStrOrError(pCtx, z, (int)n, enc, xDel);
sqlite3VdbeMemZeroTerminateIfAble(pCtx->pOut);
} }
} }
#ifndef SQLITE_OMIT_UTF16 #ifndef SQLITE_OMIT_UTF16

View File

@@ -314,6 +314,32 @@ int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
return SQLITE_OK; return SQLITE_OK;
} }
/*
** If pMem is already a string, detect if it is a zero-terminated
** string, or make it into one if possible, and mark it as such.
**
** This is an optimization. Correct operation continues even if
** this routine is a no-op.
*/
void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){
if( (pMem->flags & (MEM_Str|MEM_Term))!=MEM_Str ) return;
if( pMem->enc!=SQLITE_UTF8 ) return;
if( NEVER(pMem->z==0) ) return;
if( pMem->flags & MEM_Dyn ){
if( pMem->xDel==sqlite3_free
&& sqlite3_msize(pMem->z) >= (u64)(pMem->n+1)
){
pMem->z[pMem->n] = 0;
pMem->flags |= MEM_Term;
return;
}
}else if( pMem->szMalloc>0 && pMem->szMalloc >= pMem->n+1 ){
pMem->z[pMem->n] = 0;
pMem->flags |= MEM_Term;
return;
}
}
/* /*
** It is already known that pMem contains an unterminated string. ** It is already known that pMem contains an unterminated string.
** Add the zero terminator. ** Add the zero terminator.
@@ -803,6 +829,7 @@ int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
break; break;
} }
default: { default: {
int rc;
assert( aff==SQLITE_AFF_TEXT ); assert( aff==SQLITE_AFF_TEXT );
assert( MEM_Str==(MEM_Blob>>3) ); assert( MEM_Str==(MEM_Blob>>3) );
pMem->flags |= (pMem->flags&MEM_Blob)>>3; pMem->flags |= (pMem->flags&MEM_Blob)>>3;
@@ -810,7 +837,9 @@ int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero); pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1; if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1;
return sqlite3VdbeChangeEncoding(pMem, encoding); rc = sqlite3VdbeChangeEncoding(pMem, encoding);
if( rc ) return rc;
sqlite3VdbeMemZeroTerminateIfAble(pMem);
} }
} }
return SQLITE_OK; return SQLITE_OK;

View File

@@ -1945,7 +1945,6 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
p->nSegment = nSegment; p->nSegment = nSegment;
aTmp = (ht_slot*)&(((u8*)p)[nByte]); aTmp = (ht_slot*)&(((u8*)p)[nByte]);
SEH_FREE_ON_ERROR(0, p); SEH_FREE_ON_ERROR(0, p);
for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && i<nSegment; i++){ for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && i<nSegment; i++){
WalHashLoc sLoc; WalHashLoc sLoc;
@@ -1973,7 +1972,6 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
p->aSegment[i].aPgno = (u32 *)sLoc.aPgno; p->aSegment[i].aPgno = (u32 *)sLoc.aPgno;
} }
} }
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
SEH_FREE_ON_ERROR(p, 0); SEH_FREE_ON_ERROR(p, 0);
walIteratorFree(p); walIteratorFree(p);

View File

@@ -5122,9 +5122,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* TUNING: A full-scan of a VIEW or subquery in the outer loop /* TUNING: A full-scan of a VIEW or subquery in the outer loop
** is not so bad. */ ** is not so bad. */
if( iLoop==0 && (pWLoop->wsFlags & WHERE_VIEWSCAN)!=0 ){ if( iLoop==0 && (pWLoop->wsFlags & WHERE_VIEWSCAN)!=0 && nLoop>1 ){
rCost += -10; rCost += -10;
nOut += -30; nOut += -30;
WHERETRACE(0x80,("VIEWSCAN cost reduction for %c\n",pWLoop->cId));
} }
/* Check to see if pWLoop should be added to the set of /* Check to see if pWLoop should be added to the set of

View File

@@ -25,3 +25,15 @@ of the SQLite JSON parser.
2. Run "`sh json-speed-check-1.sh x1`". The profile output will appear 2. Run "`sh json-speed-check-1.sh x1`". The profile output will appear
in jout-x1.txt. Substitute any label you want in place of "x1". in jout-x1.txt. Substitute any label you want in place of "x1".
3. Run the script shown below in the CLI.
Divide 2500 by the real elapse time from this test
to get an estimate for number of MB/s that the JSON parser is
able to process.
> ~~~~
.open json100mb.db
.timer on
WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<25)
SELECT sum(json_valid(x)) FROM c, data1;
~~~~