Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ad9533679a |
@@ -891,7 +891,6 @@ static int sessionPreupdateEqual(
|
||||
rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
|
||||
}
|
||||
assert( rc==SQLITE_OK );
|
||||
(void)rc; /* Suppress warning about unused variable */
|
||||
if( sqlite3_value_type(pVal)!=eType ) return 0;
|
||||
|
||||
/* A SessionChange object never has a NULL value in a PK column */
|
||||
|
||||
+13
-36
@@ -18,6 +18,8 @@
|
||||
# quick, q = do just a minimal build (sqlite3.js/wasm, tester1) for
|
||||
# faster development-mode turnaround.
|
||||
#
|
||||
# qo2, qoz = a combination of quick+o2/oz.
|
||||
#
|
||||
# dist = create end user deliverables. Add dist.build=oX to build
|
||||
# with a specific optimization level, where oX is one of the
|
||||
# above-listed o? or qo? target names.
|
||||
@@ -44,12 +46,11 @@
|
||||
# $(eval), or at least centralize the setup of the numerous vars
|
||||
# related to each build variant $(JS_BUILD_MODES).
|
||||
#
|
||||
default: all
|
||||
#default: quick
|
||||
SHELL := $(shell which bash 2>/dev/null)
|
||||
MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
||||
CLEAN_FILES :=
|
||||
DISTCLEAN_FILES := ./--dummy--
|
||||
default: all
|
||||
release: oz
|
||||
# JS_BUILD_MODES exists solely to reduce repetition in documentation
|
||||
# below.
|
||||
@@ -181,7 +182,7 @@ SQLITE_OPT = \
|
||||
-DSQLITE_OMIT_SHARED_CACHE \
|
||||
-DSQLITE_OMIT_WAL \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_TEMP_STORE=2 \
|
||||
-DSQLITE_TEMP_STORE=3 \
|
||||
-DSQLITE_OS_KV_OPTIONAL=1 \
|
||||
'-DSQLITE_DEFAULT_UNIX_VFS="unix-none"' \
|
||||
-DSQLITE_USE_URI=1 \
|
||||
@@ -374,7 +375,6 @@ sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.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-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
|
||||
|
||||
# SOAP.js is an external API file which is part of our distribution
|
||||
@@ -429,10 +429,6 @@ emcc.flags += -v
|
||||
# -v is _very_ loud but also informative about what it's doing
|
||||
endif
|
||||
|
||||
# ENABLE_JSPI does not yet work. This flag is only for use during
|
||||
# experimentation with it.
|
||||
ENABLE_JSPI ?= 1
|
||||
|
||||
########################################################################
|
||||
# emcc flags for .c/.o.
|
||||
emcc.cflags :=
|
||||
@@ -455,15 +451,6 @@ emcc.exportedRuntimeMethods := \
|
||||
emcc.jsflags += $(emcc.exportedRuntimeMethods)
|
||||
emcc.jsflags += -sUSE_CLOSURE_COMPILER=0
|
||||
emcc.jsflags += -sIMPORTED_MEMORY
|
||||
ifeq (1,$(ENABLE_JSPI))
|
||||
emcc.jsflags += -sASYNCIFY=2
|
||||
endif
|
||||
# ^^^ ASYNCIFY=2 is for experimental JSPI support
|
||||
# (https://v8.dev/blog/jspi), but enabling it causes the lib-level
|
||||
# init code to throw inexplicable complaints about C-level function
|
||||
# signatures not matching what we expect them to be. JSPI requires, as of
|
||||
# this writing, requires an experimental Chrome flag:
|
||||
# chrome://flags/#enable-experimental-webassembly-stack-switching
|
||||
emcc.jsflags += -sSTRICT_JS=0
|
||||
# STRICT_JS disabled due to:
|
||||
# https://github.com/emscripten-core/emscripten/issues/18610
|
||||
@@ -690,15 +677,10 @@ sqlite3-wasmfs.cfiles := $(sqlite3-wasm.cfiles)
|
||||
#
|
||||
# Upstream RFE:
|
||||
# https://github.com/emscripten-core/emscripten/issues/18237
|
||||
#
|
||||
# Maintenance reminder: Mac sed works differently than GNU sed, so
|
||||
# don't use sed for this.
|
||||
define SQLITE3.xJS.ESM-EXPORT-DEFAULT
|
||||
if [ x1 = x$(1) ]; then \
|
||||
echo "Fragile workaround for emscripten/issues/18237. See SQLITE3.xJS.RECIPE."; \
|
||||
{\
|
||||
awk '/^export default/ && !f{f=1; next} 1' $@ > $@.tmp && mv $@.tmp $@; \
|
||||
} || exit $$?; \
|
||||
sed -i -e '0,/^export default/{/^export default/d;}' $@ || exit $$?; \
|
||||
if [ x != x$(2) ]; then \
|
||||
if ! grep -q '^export default' $@; then \
|
||||
echo "Cannot find export default." 1>&2; \
|
||||
@@ -772,7 +754,7 @@ $(5): $(4) $$(MAKEFILE) $$(sqlite3-wasm.cfiles) $$(EXPORTED_FUNCTIONS.api) $$(pr
|
||||
esac; \
|
||||
ls -la $$$$dotwasm $$@
|
||||
all: $(5)
|
||||
#quick: $(5)
|
||||
quick: $(5)
|
||||
CLEAN_FILES += $(4) $(5)
|
||||
endef
|
||||
# ^^^ /SETUP_LIB_BUILD_MODE
|
||||
@@ -786,19 +768,11 @@ sqlite3-bundler-friendly.mjs := $(dir.dout)/sqlite3-bundler-friendly.mjs
|
||||
sqlite3-api-node.mjs := $(dir.dout)/sqlite3-api-node.mjs
|
||||
sqlite3-node.mjs := $(dir.dout)/sqlite3-node.mjs
|
||||
#$(info $(call SETUP_LIB_BUILD_MODE,sqlite3,vanilla,0, $(sqlite3-api.js), $(sqlite3.js)))
|
||||
ifeq (1,$(ENABLE_JSPI))
|
||||
c-pp.D.jspi := -Djspi
|
||||
else
|
||||
c-pp.D.jspi :=
|
||||
endif
|
||||
|
||||
$(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,vanilla,0,\
|
||||
$(sqlite3-api.js), $(sqlite3.js),\
|
||||
$(c-pp.D.jspi)))
|
||||
$(sqlite3-api.js), $(sqlite3.js)))
|
||||
$(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,esm,1,\
|
||||
$(sqlite3-api.mjs), $(sqlite3.mjs), \
|
||||
-Dtarget=es6-module $(c-pp.D.jspi),\
|
||||
-sEXPORT_ES6 -sUSE_ES6_IMPORT_META))
|
||||
-Dtarget=es6-module, -sEXPORT_ES6 -sUSE_ES6_IMPORT_META))
|
||||
$(eval $(call SETUP_LIB_BUILD_MODE,sqlite3,bundler-friendly,1,\
|
||||
$(sqlite3-api-bundler-friendly.mjs),$(sqlite3-bundler-friendly.mjs),\
|
||||
$(c-pp.D.sqlite3-esm) -Dtarget=es6-bundler-friendly))
|
||||
@@ -884,7 +858,7 @@ clean-batch:
|
||||
# a regular basis with different -Ox flags and rebuilding the batch
|
||||
# pieces each time is an unnecessary time sink.
|
||||
batch: batch-runner.list
|
||||
#all: batch
|
||||
all: batch
|
||||
# end batch-runner.js
|
||||
########################################################################
|
||||
# Wasmified speedtest1 is our primary benchmarking tool.
|
||||
@@ -985,7 +959,6 @@ tester1: tester1.js tester1.mjs tester1.html tester1-esm.html
|
||||
# Note that we do not include $(sqlite3-bundler-friendly.mjs) in this
|
||||
# because bundlers are client-specific.
|
||||
all quick: tester1
|
||||
quick: $(sqlite3.js)
|
||||
|
||||
########################################################################
|
||||
# Convenience rules to rebuild with various -Ox levels. Much
|
||||
@@ -1005,6 +978,8 @@ o1: clean
|
||||
$(MAKE) -e "emcc_opt=-O1 $(o-xtra)"
|
||||
o2: clean
|
||||
$(MAKE) -j2 -e "emcc_opt=-O2 $(o-xtra)"
|
||||
qo2: clean
|
||||
$(MAKE) -j2 -e "emcc_opt=-O2 $(o-xtra)" quick
|
||||
o3: clean
|
||||
$(MAKE) -e "emcc_opt=-O3 $(o-xtra)"
|
||||
os: clean
|
||||
@@ -1012,6 +987,8 @@ os: clean
|
||||
$(MAKE) -e "emcc_opt=-Os $(o-xtra)"
|
||||
oz: clean
|
||||
$(MAKE) -j2 -e "emcc_opt=-Oz $(o-xtra)"
|
||||
qoz: clean
|
||||
$(MAKE) -j2 -e "emcc_opt=-Oz $(o-xtra)" quick
|
||||
|
||||
########################################################################
|
||||
# Sub-makes...
|
||||
|
||||
+8
-9
@@ -82,7 +82,7 @@ features in the apps which use them.
|
||||
|
||||
# Testing on a remote machine that is accessed via SSH
|
||||
|
||||
*NB: The following are developer notes, last validated on 2023-07-19*
|
||||
*NB: The following are developer notes, last validated on 2022-08-18*
|
||||
|
||||
* Remote: Install git, emsdk, and althttpd
|
||||
* Use a [version of althttpd][althttpd] from
|
||||
@@ -90,17 +90,16 @@ features in the apps which use them.
|
||||
* Remote: Install the SQLite source tree. CD to ext/wasm
|
||||
* Remote: "`make`" to build WASM
|
||||
* Remote: `althttpd --enable-sab --port 8080 --popup`
|
||||
* Local: `ssh -L 8180:remote:8080 remote`
|
||||
* Local: `ssh -L 8180:localhost:8080 remote`
|
||||
* Local: Point your web-browser at http://localhost:8180/index.html
|
||||
|
||||
In order to enable [SharedArrayBuffer][], the web-browser requires
|
||||
that the two extra Cross-Origin lines be present in HTTP reply headers
|
||||
and that the request must come from "localhost" (_or_ over an SSL
|
||||
connection). Since the web-server is on a different machine from the
|
||||
web-broser, the localhost requirement means that the connection must
|
||||
be tunneled using SSH.
|
||||
In order to enable [SharedArrayBuffers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer),
|
||||
the web-browser requires that the two extra Cross-Origin lines be present
|
||||
in HTTP reply headers and that the request must come from "localhost".
|
||||
Since the web-server is on a different machine from
|
||||
the web-broser, the localhost requirement means that the connection must be tunneled
|
||||
using SSH.
|
||||
|
||||
|
||||
[emscripten]: https://emscripten.org
|
||||
[althttpd]: https://sqlite.org/althttpd
|
||||
[SharedArrayBuffer]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer
|
||||
|
||||
+11
-16
@@ -83,18 +83,15 @@ browser client:
|
||||
helpers for use by downstream code which creates `sqlite3_vfs`
|
||||
and `sqlite3_module` implementations.
|
||||
- **`sqlite3-vfs-opfs.c-pp.js`**\
|
||||
is an sqlite3 VFS implementation which supports the Origin-Private
|
||||
FileSystem (OPFS) as a storage layer to provide persistent storage
|
||||
for database files in a browser. It requires...
|
||||
is an sqlite3 VFS implementation which supports Google Chrome's
|
||||
Origin-Private FileSystem (OPFS) as a storage layer to provide
|
||||
persistent storage for database files in a browser. It requires...
|
||||
- **`sqlite3-opfs-async-proxy.js`**\
|
||||
is the asynchronous backend part of the OPFS proxy. It speaks
|
||||
directly to the (async) OPFS API and channels those results back
|
||||
to its synchronous counterpart. This file, because it must be
|
||||
started in its own Worker, is not part of the amalgamation.
|
||||
- **`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`**\
|
||||
- **`api/sqlite3-api-cleanup.js`**\
|
||||
The previous files do not immediately extend the library. Instead
|
||||
they add callback functions to be called during its
|
||||
bootstrapping. Some also temporarily create global objects in order
|
||||
@@ -111,15 +108,13 @@ browser client:
|
||||
with `c-pp`](#c-pp), noting that such preprocessing may be applied
|
||||
after all of the relevant files are concatenated. That extension is
|
||||
used primarily to keep the code maintainers cognisant of the fact that
|
||||
those files contain constructs which may not run as-is in any given
|
||||
JavaScript environment.
|
||||
those files contain constructs which will not run as-is in JavaScript.
|
||||
|
||||
The build process glues those files together, resulting in
|
||||
`sqlite3-api.js`, which is everything except for the
|
||||
`pre/post-js-*.js` files, and `sqlite3.js`, which is the
|
||||
Emscripten-generated amalgamated output and includes the
|
||||
`pre/post-js-*.js` parts, as well as the Emscripten-provided module
|
||||
loading pieces.
|
||||
`sqlite3-api.js`, which is everything except for the `post-js-*.js`
|
||||
files, and `sqlite3.js`, which is the Emscripten-generated amalgamated
|
||||
output and includes the `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
|
||||
`sqlite3.c` which `#include`'s that file and adds a couple more
|
||||
@@ -157,8 +152,8 @@ Preprocessing of Source Files
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Certain files in the build require preprocessing to filter in/out
|
||||
parts which differ between vanilla JS, ES6 Modules, and node.js
|
||||
builds. The preprocessor application itself is in
|
||||
parts which differ between vanilla JS builds and ES6 Module
|
||||
(a.k.a. esm) builds. The preprocessor application itself is in
|
||||
[`c-pp.c`](/file/ext/wasm/c-pp.c) and the complete technical details
|
||||
of such preprocessing are maintained in
|
||||
[`GNUMakefile`](/file/ext/wasm/GNUmakefile).
|
||||
|
||||
@@ -119,6 +119,5 @@ const toExportForESM =
|
||||
return globalThis.sqlite3InitModule /* required for ESM */;
|
||||
})();
|
||||
//#if target=es6-module
|
||||
sqlite3InitModule = toExportForESM;
|
||||
export default sqlite3InitModule;
|
||||
export { toExportForESM as default, toExportForESM as sqlite3InitModule }
|
||||
//#endif
|
||||
|
||||
@@ -5,12 +5,6 @@
|
||||
Emscripten's --pre-js=THIS_FILE flag (or equivalent).
|
||||
*/
|
||||
|
||||
//#if jspi
|
||||
// Only to assist in debugging problems which cause loading of the lib
|
||||
// to break.
|
||||
globalThis.$EmscriptenModule = Module;
|
||||
//#endif
|
||||
|
||||
// See notes in extern-post-js.js
|
||||
const sqlite3InitModuleState = globalThis.sqlite3InitModuleState
|
||||
|| Object.assign(Object.create(null),{
|
||||
|
||||
@@ -22,9 +22,7 @@ if('undefined' !== typeof Module){ // presumably an Emscripten build
|
||||
*/
|
||||
const SABC = Object.assign(
|
||||
Object.create(null), {
|
||||
exports: ('undefined'===typeof wasmExports)
|
||||
? Module['asm']/* emscripten <=3.1.43 */
|
||||
: wasmExports /* emscripten >=3.1.44 */,
|
||||
exports: Module['asm'],
|
||||
memory: Module.wasmMemory /* gets set if built with -sIMPORTED_MEMORY */
|
||||
},
|
||||
globalThis.sqlite3ApiConfig || {}
|
||||
|
||||
@@ -728,13 +728,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
Populate api object with sqlite3_...() by binding the "raw" wasm
|
||||
exports into type-converting proxies using wasm.xWrap().
|
||||
*/
|
||||
if(0 === wasm.exports.sqlite3_open_v2.length){
|
||||
/* This environment wraps exports in nullary functions, which means
|
||||
we must disable the arg-count validation we otherwise perform
|
||||
on the wrappers. */
|
||||
wasm.xWrap.doArgcCheck = false;
|
||||
sqlite3.config.warn("Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks.");
|
||||
}
|
||||
for(const e of wasm.bindingSignatures){
|
||||
capi[e[0]] = wasm.xWrap.apply(null, e);
|
||||
}
|
||||
|
||||
@@ -88,9 +88,9 @@
|
||||
can be replaced with (e.g.) empty functions to squelch all such
|
||||
output.
|
||||
|
||||
- `wasmfsOpfsDir`[^1]: Specifies the "mount point" of the OPFS-backed
|
||||
filesystem in WASMFS-capable builds.
|
||||
|
||||
- `wasmfsOpfsDir`[^1]: As of 2022-12-17, this feature does not
|
||||
currently work due to incompatible Emscripten-side changes made
|
||||
in the WASMFS+OPFS combination. This option is currently ignored.
|
||||
|
||||
[^1] = This property may optionally be a function, in which case
|
||||
this function calls that function to fetch the value,
|
||||
@@ -125,11 +125,11 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
log: console.log.bind(console),
|
||||
wasmfsOpfsDir: '/opfs',
|
||||
/**
|
||||
useStdAlloc is just for testing allocator discrepancies. The
|
||||
useStdAlloc is just for testing an allocator discrepancy. The
|
||||
docs guarantee that this is false in the canonical builds. For
|
||||
99% of purposes it doesn't matter which allocators we use, but
|
||||
it becomes significant with, e.g., sqlite3_deserialize() and
|
||||
certain wasm.xWrap.resultAdapter()s.
|
||||
it becomes significant with, e.g., sqlite3_deserialize()
|
||||
and certain wasm.xWrap.resultAdapter()s.
|
||||
*/
|
||||
useStdAlloc: false
|
||||
}, apiConfig || {});
|
||||
@@ -1861,9 +1861,6 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
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
|
||||
which might be required. This function returns a Promise which
|
||||
resolves to the sqlite3 namespace object. Any error in the
|
||||
@@ -1879,19 +1876,27 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
then it must be called by client-level code, which must not use
|
||||
the library until the returned promise resolves.
|
||||
|
||||
If called multiple times it will return the same promise on
|
||||
subsequent calls. The current build setup precludes that
|
||||
possibility, so it's only a hypothetical problem if/when this
|
||||
function ever needs to be invoked by clients.
|
||||
Bug: if called while a prior call is still resolving, the 2nd
|
||||
call will resolve prematurely, before the 1st call has finished
|
||||
resolving. The current build setup precludes that possibility,
|
||||
so it's only a hypothetical problem if/when this function
|
||||
ever needs to be invoked by clients.
|
||||
|
||||
In Emscripten-based builds, this function is called
|
||||
automatically and deleted from this object.
|
||||
*/
|
||||
asyncPostInit: async function ff(){
|
||||
if(ff.isReady instanceof Promise) return ff.isReady;
|
||||
let lia = sqlite3ApiBootstrap.initializersAsync;
|
||||
asyncPostInit: async function(){
|
||||
let lip = sqlite3ApiBootstrap.initializersAsync;
|
||||
delete sqlite3ApiBootstrap.initializersAsync;
|
||||
const postInit = async ()=>{
|
||||
if(!lip || !lip.length) return Promise.resolve(sqlite3);
|
||||
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){
|
||||
/* Delete references to internal-only APIs which are used by
|
||||
some initializers. Retain them when running in test mode
|
||||
@@ -1900,25 +1905,23 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
/* It's conceivable that we might want to expose
|
||||
StructBinder to client-side code, but it's only useful if
|
||||
clients build their own sqlite3.wasm which contains their
|
||||
own C struct types. */
|
||||
one C struct types. */
|
||||
delete sqlite3.StructBinder;
|
||||
}
|
||||
return sqlite3;
|
||||
};
|
||||
const catcher = (e)=>{
|
||||
config.error("an async sqlite3 initializer failed:",e);
|
||||
throw e;
|
||||
};
|
||||
if(!lia || !lia.length){
|
||||
return ff.isReady = postInit().catch(catcher);
|
||||
if(1){
|
||||
/* Run all initializers in sequence. The advantage is that it
|
||||
allows us to have post-init cleanup defined outside of this
|
||||
routine at the end of the list and have it run at a
|
||||
well-defined time. */
|
||||
let p = lip.shift();
|
||||
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
|
||||
@@ -1978,7 +1981,7 @@ globalThis.sqlite3ApiBootstrap.initializers = [];
|
||||
specifically for initializers which are asynchronous. All entries in
|
||||
this list must be either async functions, non-async functions which
|
||||
return a Promise, or a Promise. Each function in the list is called
|
||||
with the sqlite3 object as its only argument.
|
||||
with the sqlite3 ojbect as its only argument.
|
||||
|
||||
The resolved value of any Promise is ignored and rejection will kill
|
||||
the asyncPostInit() process (at an indeterminate point because all
|
||||
|
||||
@@ -35,9 +35,6 @@
|
||||
|
||||
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
|
||||
clients who use Chrome v104-ish or higher. truncate(), getSize(),
|
||||
flush(), and close() are now (as of v108) synchronous. Calling them
|
||||
|
||||
@@ -100,7 +100,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
|
||||
ACHTUNG: because we cannot generically know how to transform JS
|
||||
exceptions into result codes, the installed functions do no
|
||||
automatic catching of exceptions. It is critical, to avoid
|
||||
automatic catching of exceptions. It is critical, to avoid
|
||||
undefined behavior in the C layer, that methods mapped via
|
||||
this function do not throw. The exception, as it were, to that
|
||||
rule is...
|
||||
@@ -295,8 +295,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
|
||||
- If `struct.$zName` is falsy and the entry has a string-type
|
||||
`name` property, `struct.$zName` is set to the C-string form of
|
||||
that `name` value before registerVfs() is called. That string
|
||||
gets added to the on-dispose state of the struct.
|
||||
that `name` value before registerVfs() is called.
|
||||
|
||||
On success returns this object. Throws on error.
|
||||
*/
|
||||
@@ -609,7 +608,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
This is to facilitate creation of those methods inline in the
|
||||
passed-in object without requiring the client to explicitly get a
|
||||
reference to one of them in order to assign it to the other
|
||||
one.
|
||||
one.
|
||||
|
||||
The `catchExceptions`-installed handlers will account for
|
||||
identical references to the above functions and will install the
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
||||
//#ifnot target=node
|
||||
/*
|
||||
2022-09-18
|
||||
|
||||
@@ -24,7 +23,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
installOpfsVfs() returns a Promise which, on success, installs an
|
||||
sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs
|
||||
which accept a VFS. It is intended to be called via
|
||||
sqlite3ApiBootstrap.initializers or an equivalent mechanism.
|
||||
sqlite3ApiBootstrap.initializersAsync or an equivalent mechanism.
|
||||
|
||||
The installed VFS uses the Origin-Private FileSystem API for
|
||||
all file storage. On error it is rejected with an exception
|
||||
@@ -102,10 +101,6 @@ const installOpfsVfs = function callee(options){
|
||||
options = Object.create(null);
|
||||
}
|
||||
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){
|
||||
options.verbose = urlParams.has('opfs-verbose')
|
||||
? (+urlParams.get('opfs-verbose') || 2) : 1;
|
||||
@@ -205,9 +200,9 @@ const installOpfsVfs = function callee(options){
|
||||
opfsVfs.dispose();
|
||||
return promiseReject_(err);
|
||||
};
|
||||
const promiseResolve = ()=>{
|
||||
const promiseResolve = (value)=>{
|
||||
promiseWasRejected = false;
|
||||
return promiseResolve_(sqlite3);
|
||||
return promiseResolve_(value);
|
||||
};
|
||||
const W =
|
||||
//#if target=es6-bundler-friendly
|
||||
@@ -241,7 +236,6 @@ const installOpfsVfs = function callee(options){
|
||||
? new sqlite3_vfs(pDVfs)
|
||||
: null /* dVfs will be null when sqlite3 is built with
|
||||
SQLITE_OS_OTHER. */;
|
||||
opfsIoMethods.$iVersion = 1;
|
||||
opfsVfs.$iVersion = 2/*yes, two*/;
|
||||
opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
|
||||
opfsVfs.$mxPathname = 1024/*sure, why not?*/;
|
||||
@@ -1327,10 +1321,10 @@ const installOpfsVfs = function callee(options){
|
||||
sqlite3.opfs = opfsUtil;
|
||||
opfsUtil.rootDirectory = d;
|
||||
log("End of OPFS sqlite3_vfs setup.", opfsVfs);
|
||||
promiseResolve();
|
||||
promiseResolve(sqlite3);
|
||||
}).catch(promiseReject);
|
||||
}else{
|
||||
promiseResolve();
|
||||
promiseResolve(sqlite3);
|
||||
}
|
||||
}catch(e){
|
||||
error(e);
|
||||
@@ -1367,10 +1361,7 @@ globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
|
||||
});
|
||||
}catch(e){
|
||||
sqlite3.config.error("installOpfsVfs() exception:",e);
|
||||
return Promise.reject(e);
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}/*sqlite3ApiBootstrap.initializers.push()*/);
|
||||
//#else
|
||||
/* The OPFS VFS parts are elided from builds targeting node.js. */
|
||||
//#endif target=node
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
/**********************************************************************/
|
||||
/* SQLITE_T... */
|
||||
#ifndef SQLITE_TEMP_STORE
|
||||
# define SQLITE_TEMP_STORE 2
|
||||
# define SQLITE_TEMP_STORE 3
|
||||
#endif
|
||||
#ifndef SQLITE_THREADSAFE
|
||||
# define SQLITE_THREADSAFE 0
|
||||
|
||||
@@ -40,41 +40,8 @@ span.labeled-input {
|
||||
.tests-pass { background-color: green; color: white }
|
||||
.tests-fail { background-color: red; color: yellow }
|
||||
.faded { opacity: 0.5; }
|
||||
.group-start {
|
||||
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;
|
||||
}
|
||||
.group-start { color: blue; }
|
||||
.group-end { color: blue; }
|
||||
.input-wrapper {
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
|
||||
@@ -1391,7 +1391,7 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
target.xCall = function(fname, ...args){
|
||||
const f = target.xGet(fname);
|
||||
if(!(f instanceof Function)) toss("Exported symbol",fname,"is not a function.");
|
||||
if(target.xWrap.doArgcCheck && f.length!==args.length) __argcMismatch(fname,f.length)
|
||||
if(f.length!==args.length) __argcMismatch(fname,f.length)
|
||||
/* This is arguably over-pedantic but we want to help clients keep
|
||||
from shooting themselves in the foot when calling C APIs. */;
|
||||
return (2===arguments.length && Array.isArray(arguments[1]))
|
||||
@@ -1949,7 +1949,7 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
abstracting it into this API (and taking on the associated
|
||||
costs) may well not make good sense.
|
||||
*/
|
||||
target.xWrap = function fw(fArg, resultType, ...argTypes){
|
||||
target.xWrap = function(fArg, resultType, ...argTypes){
|
||||
if(3===arguments.length && Array.isArray(arguments[2])){
|
||||
argTypes = arguments[2];
|
||||
}
|
||||
@@ -1960,16 +1960,10 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
const fIsFunc = (fArg instanceof Function);
|
||||
const xf = fIsFunc ? fArg : target.xGet(fArg);
|
||||
if(fIsFunc) fArg = xf.name || 'unnamed function';
|
||||
if(fw.doArgcCheck && argTypes.length!==xf.length){
|
||||
__argcMismatch(fArg, xf.length);
|
||||
}
|
||||
if((null===resultType) && 0===xf.length && fw.doArgcCheck){
|
||||
if(argTypes.length!==xf.length) __argcMismatch(fArg, xf.length);
|
||||
if((null===resultType) && 0===xf.length){
|
||||
/* Func taking no args with an as-is return. We don't need a wrapper.
|
||||
We forego the argc check here, though. */
|
||||
/* We have to skip this option when !fw.doArgcCheck for the
|
||||
sake of emcc -sASYNCIFY=2, which adds a nullary wrapper
|
||||
function to all exports, leading to ALL functions getting
|
||||
this treatment. */
|
||||
return xf;
|
||||
}
|
||||
/*Verify the arg type conversions are valid...*/;
|
||||
@@ -1979,14 +1973,14 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
else __xArgAdapterCheck(t);
|
||||
}
|
||||
const cxw = cache.xWrap;
|
||||
if(0===xf.length && fw.doArgcCheck/*see notes above*/){
|
||||
if(0===xf.length){
|
||||
// No args to convert, so we can create a simpler wrapper...
|
||||
return (...args)=>(args.length
|
||||
? __argcMismatch(fArg, xf.length)
|
||||
: cxw.convertResult(resultType, xf.call(null)));
|
||||
}
|
||||
return function(...args){
|
||||
if(fw.doArgcCheck && args.length!==xf.length) __argcMismatch(fArg, xf.length);
|
||||
if(args.length!==xf.length) __argcMismatch(fArg, xf.length);
|
||||
const scope = target.scopedAllocPush();
|
||||
try{
|
||||
/*
|
||||
@@ -2014,15 +2008,6 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
}
|
||||
};
|
||||
}/*xWrap()*/;
|
||||
/**
|
||||
By default xWrap() asserts that wrapper functions have the
|
||||
same arity as the native functions being wrapped. This sanity
|
||||
check has saved many grey hairs in development and generally
|
||||
should not be disabled. However, Emscripten's -sASYNCIFY=2 flag
|
||||
adds a level of wrapper to exported functions, giving them all
|
||||
an arity of 0. This check must be suppressed for that case.
|
||||
*/
|
||||
target.xWrap.doArgcCheck = true;
|
||||
|
||||
/** Internal impl for xWrap.resultAdapter() and argAdapter(). */
|
||||
const __xAdapter = function(func, argc, typeName, adapter, modeName, xcvPart){
|
||||
|
||||
@@ -235,10 +235,10 @@
|
||||
|
||||
- get change count (total or statement-local, 32- or 64-bit)
|
||||
- get a DB's file name
|
||||
|
||||
|
||||
Misc. Stmt features:
|
||||
|
||||
- Various forms of bind()
|
||||
- Various forms of bind()
|
||||
- clearBindings()
|
||||
- reset()
|
||||
- Various forms of step()
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ dist-name := $(dist-name-prefix)-TEMP
|
||||
# date. Our general policy is that we want the smallest binaries for
|
||||
# dist zip files, so use the oz build unless there is a compelling
|
||||
# reason not to.
|
||||
dist.build ?= oz
|
||||
dist.build ?= qoz
|
||||
|
||||
dist-dir.top := $(dist-name)
|
||||
dist-dir.jswasm := $(dist-dir.top)/$(notdir $(dir.dout))
|
||||
|
||||
+1
-6
@@ -96,10 +96,6 @@
|
||||
<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=10'>speedtest1-worker?vfs=opfs</a>: speedtest1-worker with the
|
||||
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>
|
||||
</li>
|
||||
<li>The obligatory "misc." category...
|
||||
@@ -107,8 +103,7 @@
|
||||
<li><a href='module-symbols.html'>module-symbols</a> gives
|
||||
a high-level overview of the symbols exposed by the JS
|
||||
module.</li>
|
||||
<!--li><a href='batch-runner.html'>batch-runner</a>: runs batches of
|
||||
SQL exported from speedtest1.</li-->
|
||||
<li><a href='batch-runner.html'>batch-runner</a>: runs batches of SQL exported from speedtest1.</li>
|
||||
<li><a href='test-opfs-vfs.html'>test-opfs-vfs</a>
|
||||
(<a href='test-opfs-vfs.html?opfs-sanity-check&opfs-verbose'>same
|
||||
with verbose output and sanity-checking tests</a>) is an
|
||||
|
||||
@@ -171,8 +171,7 @@
|
||||
const urlParams = new URL(self.location.href).searchParams;
|
||||
const W = new Worker(
|
||||
"speedtest1-worker.js?sqlite3.dir=jswasm"+
|
||||
(urlParams.has('opfs-verbose') ? '&opfs-verbose' : '')+
|
||||
(urlParams.has('opfs-disable') ? '&opfs-disable' : '')
|
||||
(urlParams.has('opfs-verbose') ? '&opfs-verbose' : '')
|
||||
);
|
||||
const mPost = function(msgType,payload){
|
||||
W.postMessage({type: msgType, data: payload});
|
||||
@@ -268,7 +267,7 @@
|
||||
if(urlParams.has('flags')){
|
||||
preselectedFlags.push(...urlParams.get('flags').split(','));
|
||||
}
|
||||
if(!urlParams.get('vfs')){
|
||||
if('opfs'!==urlParams.get('vfs')){
|
||||
preselectedFlags.push('--memdb');
|
||||
}
|
||||
Object.keys(flags).sort().forEach(function(f){
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
if(urlParams.has('sqlite3.dir')){
|
||||
speedtestJs = urlParams.get('sqlite3.dir') + '/' + speedtestJs;
|
||||
}
|
||||
importScripts(speedtestJs);
|
||||
importScripts('common/whwasmutil.js', speedtestJs);
|
||||
/**
|
||||
If this environment contains OPFS, this function initializes it and
|
||||
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 logErr = (...args)=>logMsg('stderr',args);
|
||||
|
||||
const runSpeedtest = async function(cliFlagsArray){
|
||||
const runSpeedtest = function(cliFlagsArray){
|
||||
const scope = App.wasm.scopedAllocPush();
|
||||
const dbFile = App.pDir+"/speedtest1.sqlite3";
|
||||
try{
|
||||
@@ -56,28 +56,7 @@
|
||||
"speedtest1.wasm", ...cliFlagsArray, dbFile
|
||||
];
|
||||
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]);
|
||||
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.scopedAllocMainArgv(argv));
|
||||
}catch(e){
|
||||
@@ -92,38 +71,20 @@
|
||||
self.onmessage = function(msg){
|
||||
msg = msg.data;
|
||||
switch(msg.type){
|
||||
case 'run':
|
||||
runSpeedtest(msg.data || [])
|
||||
.catch(e=>mPost('error',e));
|
||||
break;
|
||||
case 'run': runSpeedtest(msg.data || []); break;
|
||||
default:
|
||||
logErr("Unhandled worker message type:",msg.type);
|
||||
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 = {
|
||||
print: log,
|
||||
printErr: logErr,
|
||||
setStatus: (text)=>mPost('load-status',text)
|
||||
};
|
||||
log("Initializing speedtest1 module...");
|
||||
self.sqlite3InitModule(EmscriptenModule).then(async (sqlite3)=>{
|
||||
const S = globalThis.S = App.sqlite3 = sqlite3;
|
||||
log("Loaded speedtest1 module. Setting up...");
|
||||
self.sqlite3InitModule(EmscriptenModule).then((sqlite3)=>{
|
||||
const S = sqlite3;
|
||||
App.vfsUnlink = function(pDb, fname){
|
||||
const pVfs = S.wasm.sqlite3_wasm_db_vfs(pDb, 0);
|
||||
if(pVfs) S.wasm.sqlite3_wasm_vfs_unlink(pVfs, fname||0);
|
||||
@@ -134,7 +95,5 @@
|
||||
//else log("Using transient storage.");
|
||||
mPost('ready',true);
|
||||
log("Registered VFSes:", ...S.capi.sqlite3_js_vfs_list());
|
||||
}).catch(e=>{
|
||||
logErr(e);
|
||||
});
|
||||
})();
|
||||
|
||||
+145
-255
@@ -65,14 +65,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
const haveWasmCTests = ()=>{
|
||||
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)=>{
|
||||
switch(typeof v){
|
||||
@@ -167,6 +159,8 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
/** Running total of the number of tests run via
|
||||
this API. */
|
||||
counter: 0,
|
||||
/* Separator line for log messages. */
|
||||
separator: '------------------------------------------------------------',
|
||||
/**
|
||||
If expr is a function, it is called and its result
|
||||
is returned, coerced to a bool, else expr, coerced to
|
||||
@@ -254,11 +248,13 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
return this;
|
||||
},
|
||||
run: async function(sqlite3){
|
||||
log(TestUtil.separator);
|
||||
logClass('group-start',"Group #"+this.number+':',this.name);
|
||||
const indent = ' ';
|
||||
if(this.predicate){
|
||||
const p = this.predicate(sqlite3);
|
||||
if(!p || 'string'===typeof p){
|
||||
logClass(['warning','skipping-group'],
|
||||
logClass('warning',indent,
|
||||
"SKIPPING group:", p ? p : "predicate says to" );
|
||||
return;
|
||||
}
|
||||
@@ -270,34 +266,26 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
for(const t of this.tests){
|
||||
++i;
|
||||
const n = this.number+"."+i;
|
||||
logClass('one-test-line', n+":", t.name);
|
||||
log(indent, n+":", t.name);
|
||||
if(t.predicate){
|
||||
const p = t.predicate(sqlite3);
|
||||
if(!p || 'string'===typeof p){
|
||||
logClass(['warning','skipping-test'],
|
||||
logClass('warning',indent,
|
||||
"SKIPPING:", p ? p : "predicate says to" );
|
||||
skipped.push( n+': '+t.name );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const tc = TestUtil.counter, now = performance.now();
|
||||
let rc = t.test.call(groupState, sqlite3);
|
||||
/*if(rc instanceof Promise){
|
||||
rc = rc.catch((e)=>{
|
||||
error("Test failure:",e);
|
||||
throw e;
|
||||
});
|
||||
}*/
|
||||
await rc;
|
||||
await t.test.call(groupState, sqlite3);
|
||||
const then = performance.now();
|
||||
runtime += then - now;
|
||||
logClass(['faded','one-test-summary'],
|
||||
logClass('faded',indent, indent,
|
||||
TestUtil.counter - tc, 'assertion(s) in',
|
||||
roundMs(then-now),'ms');
|
||||
}
|
||||
logClass(['green','group-end'],
|
||||
"#"+this.number+":",
|
||||
(TestUtil.counter - assertCount),
|
||||
logClass('green',
|
||||
"Group #"+this.number+":",(TestUtil.counter - assertCount),
|
||||
"assertion(s) in",roundMs(runtime),"ms");
|
||||
if(0 && skipped.length){
|
||||
logClass('warning',"SKIPPED test(s) in group",this.number+":",skipped);
|
||||
@@ -333,7 +321,8 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
await g.run(sqlite3);
|
||||
runtime += performance.now() - now;
|
||||
}
|
||||
logClass(['strong','green','full-test-summary'],
|
||||
log(TestUtil.separator);
|
||||
logClass(['strong','green'],
|
||||
"Done running tests.",TestUtil.counter,"assertions in",
|
||||
roundMs(runtime),'ms');
|
||||
pok();
|
||||
@@ -350,11 +339,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
T.g = T.addGroup;
|
||||
T.t = T.addTest;
|
||||
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...
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -728,14 +712,12 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
|
||||
//log("xWrap()...");
|
||||
{
|
||||
T.mustThrowMatching(()=>w.xWrap('sqlite3_libversion',null,'i32'),
|
||||
/requires 0 arg/).
|
||||
assert(w.xWrap.resultAdapter('i32') instanceof Function).
|
||||
assert(w.xWrap.argAdapter('i32') instanceof Function);
|
||||
let fw = w.xWrap('sqlite3_libversion','utf8');
|
||||
if(w.xWrap.doArgcCheck){
|
||||
T.mustThrowMatching(()=>w.xWrap('sqlite3_libversion',null,'i32'),
|
||||
/requires 0 arg/).
|
||||
assert(w.xWrap.resultAdapter('i32') instanceof Function).
|
||||
assert(w.xWrap.argAdapter('i32') instanceof Function);
|
||||
T.mustThrowMatching(()=>fw(1), /requires 0 arg/);
|
||||
}
|
||||
T.mustThrowMatching(()=>fw(1), /requires 0 arg/);
|
||||
let rc = fw();
|
||||
T.assert('string'===typeof rc).assert(rc.length>5);
|
||||
rc = w.xCallWrapped('sqlite3_wasm_enum_json','*');
|
||||
@@ -1306,6 +1288,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
if(1){
|
||||
const vfsList = capi.sqlite3_js_vfs_list();
|
||||
T.assert(vfsList.length>1);
|
||||
//log("vfsList =",vfsList);
|
||||
wasm.scopedAllocCall(()=>{
|
||||
const vfsArg = (v)=>wasm.xWrap.testConvertArg('sqlite3_vfs*',v);
|
||||
for(const v of vfsList){
|
||||
@@ -2632,6 +2615,128 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
}/*kvvfs sqlite3_js_vfs_create_file()*/)
|
||||
;/* 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({
|
||||
@@ -2837,7 +2942,8 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
.assert( capi.sqlite3session_enable(pSession, -1) > 0 )
|
||||
.assert(undefined === db1.selectValue('select a from t where rowid=2'));
|
||||
}else{
|
||||
warn("sqlite3session_enable() tests are currently disabled.");
|
||||
warn("sqlite3session_enable() tests disabled due to unexpected results.",
|
||||
"(Possibly a tester misunderstanding, as opposed to a bug.)");
|
||||
}
|
||||
let db1Count = db1.selectValue("select count(*) from t");
|
||||
T.assert( db1Count === (testSessionEnable ? 2 : 3) );
|
||||
@@ -2901,217 +3007,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
}
|
||||
})/*session API sanity tests*/
|
||||
;/*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();
|
||||
const fileNames = u1.getFileNames();
|
||||
T.assert(1 === fileNames.length)
|
||||
.assert(dbName === fileNames[0])
|
||||
.assert(1 === u1.getFileCount())
|
||||
.assert(true === u1.unlink(dbName))
|
||||
.assert(false === u1.unlink(dbName))
|
||||
.assert(0 === u1.getFileCount())
|
||||
.assert(0 === u1.getFileNames().length);
|
||||
|
||||
// Demonstrate that two SAH pools can coexist so long as
|
||||
// they have different names.
|
||||
const conf2 = JSON.parse(JSON.stringify(sahPoolConfig));
|
||||
conf2.name += '-test2';
|
||||
const POther = await inst(conf2);
|
||||
log("Installed second SAH instance as",conf2.name);
|
||||
T.assert(0 === POther.getFileCount())
|
||||
.assert(true === await POther.removeVfs());
|
||||
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;
|
||||
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({
|
||||
@@ -3193,15 +3088,11 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
globalThis.sqlite3InitModule({
|
||||
print: log,
|
||||
printErr: error
|
||||
}).then(async function(sqlite3){
|
||||
}).then(function(sqlite3){
|
||||
//console.log('sqlite3 =',sqlite3);
|
||||
log("Done initializing WASM/JS bits. Running tests...");
|
||||
sqlite3.config.warn("Installing sqlite3 bits as global S for local dev/test purposes.");
|
||||
globalThis.S = sqlite3;
|
||||
/*await sqlite3.installOpfsSAHPoolVfs(sahPoolConfig)
|
||||
.then((u)=>log("Loaded",u.vfsName,"VFS"))
|
||||
.catch(e=>{
|
||||
log("Cannot install OpfsSAHPool.",e);
|
||||
});*/
|
||||
capi = sqlite3.capi;
|
||||
wasm = sqlite3.wasm;
|
||||
log("sqlite3 version:",capi.sqlite3_libversion(),
|
||||
@@ -3216,7 +3107,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
}else{
|
||||
logClass('warning',"sqlite3_wasm_test_...() APIs unavailable.");
|
||||
}
|
||||
log("registered vfs list =",capi.sqlite3_js_vfs_list().join(', '));
|
||||
TestUtil.runTests(sqlite3);
|
||||
});
|
||||
})(self);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Dynamically\sdetermine\swhether\sthe\swasm.xWrap()\sargc\scheck\sworkaround\sfor\sJSPI\sis\snecessary,\sinstead\sof\sbaking\sit\sin\sto\sJSPI\sbuilds.
|
||||
D 2023-07-27T15:00:28.218
|
||||
C Enhance\sthe\sJSON\sparser\scache\ssuch\sthat\sit\sis\sable\sto\sextract\slines\sfrom\nthe\scache\sand\suse\sthem\sfor\swriting,\sthough\sthey\sthen\shave\sto\sbe\sevicted\sfrom\nthe\scache.\s\sThis\swas\san\sexperiment\sin\strying\sto\sreduce\sthe\samount\sof\sparsing\nneeded\sfor\sa\sbig\sUPDATE,\sbut\sit\sdoes\snot\sseem\sto\shelp\sany.\s\sRetained\sfor\nreference\sonly.
|
||||
D 2023-07-19T12:52:09.770
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -475,36 +475,35 @@ F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a
|
||||
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
|
||||
F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c
|
||||
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
|
||||
F ext/session/sqlite3session.c 1971b61ca45babf0d9e4bb669a65b0903135e9828af2fcd4f0c8f1b7acf36b6f
|
||||
F ext/session/sqlite3session.c e50a9218ee360db0a25298adc6614162d80ebe65d3f6a5b0a021e0902f6536a1
|
||||
F ext/session/sqlite3session.h 653e9d49c4edae231df8a4c8d69c2145195aedb32462d4b44229dbee7d2680fb
|
||||
F ext/session/test_session.c 5285482f83cd92b4c1fe12fcf88210566a18312f4f2aa110f6399dae46aeccbb
|
||||
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
||||
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
|
||||
F ext/wasm/GNUmakefile d5e296c96c2c2bf4ea77b1ea4962096aef79daa45bc610f55a9f7cb43b103748
|
||||
F ext/wasm/GNUmakefile 74e351ff45b4061cfed8df237d301819a04182ae304a99118883b064baa25fc2
|
||||
F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576
|
||||
F ext/wasm/README.md 0895244c0539ae68cf8c70d59c2de512532fd47cfba313268e2b672e6359112e
|
||||
F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api d6a5078f48a5301ed17b9a30331075d9b2506e1360c1f0dee0c7816c10acd9ab
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
|
||||
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
|
||||
F ext/wasm/api/README.md 5eb44fa02e9c693a1884a3692428647894b0380b24bca120866b7a24c8786134
|
||||
F ext/wasm/api/extern-post-js.c-pp.js e7257ea56d4077d0773d7537fcb8eade59aad0c118dab92497c27939edca41cb
|
||||
F ext/wasm/api/README.md 77a2f1f2fc60a35def7455dffc8d3f2c56385d6ac5c6cecc60fa938252ea2c54
|
||||
F ext/wasm/api/extern-post-js.c-pp.js 116749b7e55b7519129de06d3d353e19df68cfb24b12204aa4dc30c9a83023fe
|
||||
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
|
||||
F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08902f15c34720ee4a1
|
||||
F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62
|
||||
F ext/wasm/api/pre-js.c-pp.js 572c762b53101781b5e1c35dc62729e3eda616d113153f8199df843a7c1ff6da
|
||||
F ext/wasm/api/sqlite3-api-cleanup.js d235ad237df6954145404305040991c72ef8b1881715d2a650dda7b3c2576d0e
|
||||
F ext/wasm/api/sqlite3-api-glue.js 79c63d784bba2e953f0717f982595abbe461ba2475a3b733116d080545343025
|
||||
F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057afb08161d7511219
|
||||
F ext/wasm/api/sqlite3-api-cleanup.js 23ceec5ef74a0e649b19694ca985fd89e335771e21f24f50df352a626a8c81bf
|
||||
F ext/wasm/api/sqlite3-api-glue.js f1b2dcb944de5138bb5bd9a1559d2e76a4f3ec25260963d709e8237476688803
|
||||
F ext/wasm/api/sqlite3-api-oo1.js 9678dc4d9a5d39632b6ffe6ea94a023119260815bf32f265bf5f6c36c9516db8
|
||||
F ext/wasm/api/sqlite3-api-prologue.js cbd7d6ba185f3a844a8b0020e954b49bbc2ca78b305d117bec2ceca21431795a
|
||||
F ext/wasm/api/sqlite3-api-prologue.js 7d1c1ef59b9dcc42ad3a9cec9da972c42e29316a270cd126e7f660509b09027b
|
||||
F ext/wasm/api/sqlite3-api-worker1.js 9f32af64df1a031071912eea7a201557fe39b1738645c0134562bb84e88e2fec
|
||||
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
|
||||
F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25
|
||||
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 44740935f6eeab3a0c6dc9f0ca93aebb6339f8d8365f03ea6d7808c134dbfe46
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e7a690e0e78ff4d563f2eca468f91db69f001ff4b79c6d2304cbb6f62dca437d
|
||||
F ext/wasm/api/sqlite3-wasm.c 8867f1d41c112fb4a2cfe22ff224eccaf309fcdea266cee0ec554f85db72ef0f
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 961bbc3ccc1fa4e91d6519a96e8811ad7ae60173bd969fee7775dacb6eee1da2
|
||||
F ext/wasm/api/sqlite3-v-helper.js e5c202a9ecde9ef818536d3f5faf26c03a1a9f5192b1ddea8bdabf30d75ef487
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 891f3a18d9ac9b0422b32fd975319dfcd0af5a8ca392f0cce850524e51b49c87
|
||||
F ext/wasm/api/sqlite3-wasm.c 12a096d8e58a0af0589142bae5a3c27a0c7e19846755a1a37d2c206352fbedda
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f
|
||||
F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75
|
||||
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
|
||||
@@ -512,18 +511,18 @@ F ext/wasm/batch-runner.js 0dad6a02ad796f1003d3b7048947d275c4d6277f63767b8e685c2
|
||||
F ext/wasm/c-pp.c 6d80d8569d85713effe8b0818a3cf51dc779e3f0bf8dc88771b8998552ee25b4
|
||||
F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
|
||||
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
|
||||
F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f
|
||||
F ext/wasm/common/whwasmutil.js eb115cef76f568223129b659a4f0212f2e0c5fdfa6d8429c6a5382b140edd217
|
||||
F ext/wasm/common/testing.css 0ff15602a3ab2bad8aef2c3bd120c7ee3fd1c2054ad2ace7e214187ae68d926f
|
||||
F ext/wasm/common/whwasmutil.js ae263dec9d7384f4c530f324b99d00516a4d6f26424372daee65031e00eb49b3
|
||||
F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
|
||||
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
|
||||
F ext/wasm/demo-123.js 38aa8faec4d0ace1c973bc8a7a1533584463ebeecd4c420daa7d9687beeb9cb5
|
||||
F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6
|
||||
F ext/wasm/demo-jsstorage.html 409c4be4af5f207fb2877160724b91b33ea36a3cd8c204e8da1acb828ffe588e
|
||||
F ext/wasm/demo-jsstorage.js 44e3ae7ec2483b6c511384c3c290beb6f305c721186bcf5398ca4e00004a06b8
|
||||
F ext/wasm/demo-worker1-promiser.html 1de7c248c7c2cfd4a5783d2aa154bce62d74c6de98ab22f5786620b3354ed15f
|
||||
F ext/wasm/demo-worker1-promiser.js 5e5c7d7c91cd7aae9cc733afd02569ba9c6928292db413b550e8b842f4b75e87
|
||||
F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d
|
||||
F ext/wasm/demo-worker1.js 836bece8615b17b1b572584f7b15912236a5947fe8c68b98d2737d7e287447ef
|
||||
F ext/wasm/dist.make 3a851858aad72e246a5d9c5aaf6b6a144305f1bf898ac1846760ea7bab95c9a3
|
||||
F ext/wasm/dist.make 451fb1b732257849f6e898d2a862512a0401500ed369ef53bdfeddf9c77bc3b9
|
||||
F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f
|
||||
F ext/wasm/fiddle.make dbe36b90b8907ae28ecb9c0e9fd8389dbdaecf117ea4fb2ea33864bdfa498a94
|
||||
F ext/wasm/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
|
||||
@@ -531,7 +530,7 @@ F ext/wasm/fiddle/fiddle-worker.js 163d6139a93fab4bcb72064923df050d4e7c0ff0d8aa0
|
||||
F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5653284071715
|
||||
F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2
|
||||
F ext/wasm/index-dist.html 22379774f0ad4edcaaa8cf9c674c82e794cc557719a8addabed74eb8069d412e
|
||||
F ext/wasm/index.html 4e7847b909f4ae0da8c829b150b79454050e53b3658431f138636257729cd42b
|
||||
F ext/wasm/index.html b768e8659b4fe311912e54d42906449d51c0f84b7f036cca47ec1f93bf3f91de
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 1264710db3cfbcb6887d95665b7aeba60c1126eaef789ca4cf1a4a17d5bc7f54
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 37911f00db12cbcca73aa1ed72594430365f30aafae2fa9c886961de74e5e0eb
|
||||
F ext/wasm/module-symbols.html 841de62fc198988b8330e238c260e70ec93028b096e1a1234db31b187a899d10
|
||||
@@ -539,8 +538,8 @@ F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d
|
||||
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
|
||||
F ext/wasm/speedtest1-wasmfs.html 0e9d335a9b5b5fafe6e1bc8dc0f0ca7e22e6eb916682a2d7c36218bb7d67379d
|
||||
F ext/wasm/speedtest1-wasmfs.mjs ac5cadbf4ffe69e9eaac8b45e8523f030521e02bb67d654c6eb5236d9c456cbe
|
||||
F ext/wasm/speedtest1-worker.html e33e2064bda572c0c3ebaec7306c35aa758d9d27e245d67e807f8cc4a9351cc5
|
||||
F ext/wasm/speedtest1-worker.js 315d26198c46be7c85e26fda15d80ef882424276abde25ffd8b026fb02a35d8c
|
||||
F ext/wasm/speedtest1-worker.html 97c2bf5f8534091ce718de05801090d5a80c3f13575996f095ba23638e1bdca0
|
||||
F ext/wasm/speedtest1-worker.js 13b57c4a41729678a1194014afec2bd5b94435dcfc8d1039dfa9a533ac819ee1
|
||||
F ext/wasm/speedtest1.html ff048b4a623aa192e83e143e48f1ce2a899846dd42c023fdedc8772b6e3f07da
|
||||
F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x
|
||||
F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0
|
||||
@@ -549,7 +548,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
|
||||
F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
|
||||
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
|
||||
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
|
||||
F ext/wasm/tester1.c-pp.js 2b30bdf9d29f6db37b2599188296389ab097b3137be208c0b5aca1cb1b412ba1
|
||||
F ext/wasm/tester1.c-pp.js 4420eb97b6b4fc79e4e156b4b8010dd9f373365f4230dd76d823fb04ce28ffde
|
||||
F ext/wasm/tests/opfs/concurrency/index.html 0802373d57034d51835ff6041cda438c7a982deea6079efd98098d3e42fbcbc1
|
||||
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
|
||||
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
||||
@@ -588,17 +587,17 @@ F src/date.c f73f203b3877cef866c60ab402aec2bf89597219b60635cf50cbe3c5e4533e94
|
||||
F src/dbpage.c f3eea5f7ec47e09ee7da40f42b25092ecbe961fc59566b8e5f705f34335b2387
|
||||
F src/dbstat.c ec92074baa61d883de58c945162d9e666c13cd7cf3a23bc38b4d1c4d0b2c2bef
|
||||
F src/delete.c cd5f5cd06ed0b6a882ec1a8c2a0d73b3cecb28479ad19e9931c4706c5e2182be
|
||||
F src/expr.c ef4a81822da6f767696bd7f4b9983328af061158958138540142285a5b1181b7
|
||||
F src/expr.c 8d1656b65e26af3e34f78e947ac423f0d20c214ed25a67486e433bf16ca6b543
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c a7fcbf7e66d14dbb73cf49f31489ebf66d0e6006c62b95246924a3bae9f37b36
|
||||
F src/func.c cc1da67fd643a43cfe691784158ec656d8ec6d13bb17e67018b01b38b3e4f5ab
|
||||
F src/func.c 25f2e0204c011be56fc3c9a180534b68ca4866c61ec19806880136450434112d
|
||||
F src/global.c 29f56a330ed9d1b5cd9b79ac0ca36f97ac3afc730ff8bfa987b0db9e559d684d
|
||||
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
|
||||
F src/json.c 46ea5566e1363f4f353db79b0378c2bf8ffdf9d4667daee3df67b14669767bed
|
||||
F src/json.c c011e8a5c2a6ef3b310412dd16de933370655d643c0dff33c81cf96a1088e223
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 176d6b2cb18a6ad73b133db17f6fc351c4d9a2d510deebdb76c22bde9cfd1465
|
||||
F src/main.c 512b1d45bc556edf4471a845afb7ba79e64bd5b832ab222dc195c469534cd002
|
||||
@@ -706,15 +705,15 @@ F src/trigger.c ad6ab9452715fa9a8075442e15196022275b414b9141b566af8cdb7a1605f2b0
|
||||
F src/update.c 0aa36561167a7c40d01163238c297297962f31a15a8d742216b3c37cdf25f731
|
||||
F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c c2aa170f2eb429235b1dddce8952770787ffa5124dc89d405bfbe8ebad8e7ebd
|
||||
F src/util.c fea6fffdee3cdae917a66b70deec59d4f238057cfd6de623d15cf990c196940d
|
||||
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
|
||||
F src/vdbe.c 4cda877d413a18fa07346b08d6959b3d18ce982357921e7acb9649fca2534a12
|
||||
F src/vdbe.c 74282a947234513872a83b0bab1b8c644ece64b3e27b053ef17677c8ff9c81e0
|
||||
F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0
|
||||
F src/vdbeInt.h 401813862f9d75af01bdb2ab99253ad019e9d6ddcc8058e4fa61a43e9a60d1f7
|
||||
F src/vdbeapi.c dde6c4d0f87486f056b9db4d1ea185bb1d84a6839102b86e76316ba590d07cc7
|
||||
F src/vdbeInt.h 7bd49eef8f89c1a271fbf12d80a206bf56c876814c5fc6bee340f4e1907095ae
|
||||
F src/vdbeapi.c de9703f8705afc393cc2864669ce28cf9516983c8331d59aa2b978de01634365
|
||||
F src/vdbeaux.c b5e3f7e158518b4eca6f166ac43900640a3fe9735c710e12bfa119af21059339
|
||||
F src/vdbeblob.c 2516697b3ee8154eb8915f29466fb5d4f1ae39ee8b755ea909cefaf57ec5e2ce
|
||||
F src/vdbemem.c 40afb83ed848e235848ffdd3ba25adca4ba602111b8ed3b05ae3b1b12e0eacee
|
||||
F src/vdbemem.c cf4a1556dd5b18c071cf7c243373c29ce752eb516022e3ad49ba72f08b785033
|
||||
F src/vdbesort.c 0d40dca073c94e158ead752ef4225f4fee22dee84145e8c00ca2309afb489015
|
||||
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
|
||||
F src/vdbevtab.c aae4bd769410eb7e1d02c42613eec961d514459b1c3c1c63cfc84e92a137daac
|
||||
@@ -1223,7 +1222,7 @@ F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ff
|
||||
F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9e1946
|
||||
F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
|
||||
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
||||
F test/json/README.md 0992b8ccbecd8424b84c1173f9ac56bcc0ae96d49912fd2d86c04eb1f3cba7af
|
||||
F test/json/README.md 506af1f54574b524106acb50d1a341ab5ddfa6d83fe25095007892b07e663e85
|
||||
F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd28656fb261bddc8a3f
|
||||
F test/json/json-q1.txt 335a7c8ab291d354f33b7decc9559e99a2823d4142291c4be7aa339a631f3c2d
|
||||
F test/json/json-speed-check.sh 8b7babf530faa58bd59d6d362cec8e9036a68c5457ff46f3b1f1511d21af6737 x
|
||||
@@ -2044,8 +2043,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 4ce386030092b8bafe860350c66ef5516b6aea75bd1b4467ac184875109d66e7
|
||||
R c52ecea97fdf221f729bbf9a2f0e8855
|
||||
U stephan
|
||||
Z 93d381321ad94ab96168faf5e06a9b7f
|
||||
P a0d3e7571aded8d1e03908059d2d5aa5d62ec49bff099cb38f6f35df5e4b18b5
|
||||
R 1ad9eb2d7a5390b633470ac87bec02c6
|
||||
T *branch * json-write-cache
|
||||
T *sym-json-write-cache *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z 11a0a92f5fb8088da9a1185f8dea3559
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
86bb464f31b77ac7a89ee9a50c3d988a186f84fa0bbee16b15fcbbac33523fa1
|
||||
2e6fbebc41f1a24f8233b136131e6c392d7474f24946ef164fe3600afbd02357
|
||||
+2
-1
@@ -4690,7 +4690,8 @@ expr_code_doover:
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_FACTOR);
|
||||
sqlite3ExprCodeExprList(pParse, pFarg, r1, 0,
|
||||
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
|
||||
}else{
|
||||
r1 = 0;
|
||||
}
|
||||
|
||||
@@ -1227,7 +1227,6 @@ static void charFunc(
|
||||
*zOut++ = 0x80 + (u8)(c & 0x3F);
|
||||
} \
|
||||
}
|
||||
*zOut = 0;
|
||||
sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8);
|
||||
}
|
||||
|
||||
|
||||
+134
-149
@@ -135,9 +135,10 @@ struct JsonParse {
|
||||
u8 nErr; /* Number of errors seen */
|
||||
u8 oom; /* Set to true if out of memory */
|
||||
u8 hasNonstd; /* True if input uses non-standard features like JSON5 */
|
||||
u8 nRef; /* Number of references to this object */
|
||||
int nJson; /* Length of the zJson string in bytes */
|
||||
u32 iErr; /* Error location in zJson[] */
|
||||
u32 iHold; /* Replace cache line with the lowest iHold value */
|
||||
u32 iHold; /* Creation sequence number, for LRU replacement */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -218,35 +219,12 @@ static int jsonGrow(JsonString *p, u32 N){
|
||||
|
||||
/* Append N bytes from zIn onto the end of the JsonString string.
|
||||
*/
|
||||
static SQLITE_NOINLINE void jsonAppendExpand(
|
||||
JsonString *p,
|
||||
const char *zIn,
|
||||
u32 N
|
||||
){
|
||||
assert( N>0 );
|
||||
if( jsonGrow(p,N) ) return;
|
||||
static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
|
||||
if( N==0 ) return;
|
||||
if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
|
||||
memcpy(p->zBuf+p->nUsed, zIn, 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.
|
||||
*/
|
||||
@@ -261,16 +239,9 @@ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
|
||||
|
||||
/* Append a single character
|
||||
*/
|
||||
static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){
|
||||
if( jsonGrow(p,1) ) return;
|
||||
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;
|
||||
}
|
||||
if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
|
||||
p->zBuf[p->nUsed++] = c;
|
||||
}
|
||||
|
||||
/* Append a comma separator to the output buffer, if the previous
|
||||
@@ -280,8 +251,7 @@ static void jsonAppendSeparator(JsonString *p){
|
||||
char c;
|
||||
if( p->nUsed==0 ) return;
|
||||
c = p->zBuf[p->nUsed-1];
|
||||
if( c=='[' || c=='{' ) return;
|
||||
jsonAppendChar(p, ',');
|
||||
if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
|
||||
}
|
||||
|
||||
/* Append the N-byte string in zIn to the end of the JsonString string
|
||||
@@ -341,7 +311,7 @@ static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
|
||||
while( N>0 ){
|
||||
for(i=0; i<N && zIn[i]!='\\'; i++){}
|
||||
if( i>0 ){
|
||||
jsonAppendRawNZ(p, zIn, i);
|
||||
jsonAppendRaw(p, zIn, i);
|
||||
zIn += i;
|
||||
N -= i;
|
||||
if( N==0 ) break;
|
||||
@@ -352,16 +322,16 @@ static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
|
||||
jsonAppendChar(p, '\'');
|
||||
break;
|
||||
case 'v':
|
||||
jsonAppendRawNZ(p, "\\u0009", 6);
|
||||
jsonAppendRaw(p, "\\u0009", 6);
|
||||
break;
|
||||
case 'x':
|
||||
jsonAppendRawNZ(p, "\\u00", 4);
|
||||
jsonAppendRawNZ(p, &zIn[2], 2);
|
||||
jsonAppendRaw(p, "\\u00", 4);
|
||||
jsonAppendRaw(p, &zIn[2], 2);
|
||||
zIn += 2;
|
||||
N -= 2;
|
||||
break;
|
||||
case '0':
|
||||
jsonAppendRawNZ(p, "\\u0000", 6);
|
||||
jsonAppendRaw(p, "\\u0000", 6);
|
||||
break;
|
||||
case '\r':
|
||||
if( zIn[2]=='\n' ){
|
||||
@@ -379,7 +349,7 @@ static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
|
||||
N -= 2;
|
||||
break;
|
||||
default:
|
||||
jsonAppendRawNZ(p, zIn, 2);
|
||||
jsonAppendRaw(p, zIn, 2);
|
||||
break;
|
||||
}
|
||||
zIn += 2;
|
||||
@@ -409,12 +379,11 @@ static void jsonAppendNormalizedInt(JsonString *p, const char *zIn, u32 N){
|
||||
jsonPrintf(100,p,"%lld",i);
|
||||
}else{
|
||||
assert( rc==2 );
|
||||
jsonAppendRawNZ(p, "9.0e999", 7);
|
||||
jsonAppendRaw(p, "9.0e999", 7);
|
||||
}
|
||||
return;
|
||||
}
|
||||
assert( N>0 );
|
||||
jsonAppendRawNZ(p, zIn, N);
|
||||
jsonAppendRaw(p, zIn, N);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -446,7 +415,7 @@ static void jsonAppendNormalizedReal(JsonString *p, const char *zIn, u32 N){
|
||||
}
|
||||
}
|
||||
if( N>0 ){
|
||||
jsonAppendRawNZ(p, zIn, N);
|
||||
jsonAppendRaw(p, zIn, N);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +431,7 @@ static void jsonAppendValue(
|
||||
){
|
||||
switch( sqlite3_value_type(pValue) ){
|
||||
case SQLITE_NULL: {
|
||||
jsonAppendRawNZ(p, "null", 4);
|
||||
jsonAppendRaw(p, "null", 4);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
@@ -501,8 +470,7 @@ static void jsonAppendValue(
|
||||
*/
|
||||
static void jsonResult(JsonString *p){
|
||||
if( p->bErr==0 ){
|
||||
jsonAppendChar(p, 0);
|
||||
sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed-1,
|
||||
sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
|
||||
p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
|
||||
SQLITE_UTF8);
|
||||
jsonZero(p);
|
||||
@@ -538,14 +506,19 @@ static void jsonParseReset(JsonParse *pParse){
|
||||
pParse->nAlloc = 0;
|
||||
sqlite3_free(pParse->aUp);
|
||||
pParse->aUp = 0;
|
||||
pParse->nRef = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a JsonParse object that was obtained from sqlite3_malloc().
|
||||
*/
|
||||
static void jsonParseFree(JsonParse *pParse){
|
||||
jsonParseReset(pParse);
|
||||
sqlite3_free(pParse);
|
||||
if( pParse->nRef>1 ){
|
||||
pParse->nRef--;
|
||||
}else{
|
||||
jsonParseReset(pParse);
|
||||
sqlite3_free(pParse);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -571,15 +544,15 @@ static void jsonRenderNode(
|
||||
switch( pNode->eType ){
|
||||
default: {
|
||||
assert( pNode->eType==JSON_NULL );
|
||||
jsonAppendRawNZ(pOut, "null", 4);
|
||||
jsonAppendRaw(pOut, "null", 4);
|
||||
break;
|
||||
}
|
||||
case JSON_TRUE: {
|
||||
jsonAppendRawNZ(pOut, "true", 4);
|
||||
jsonAppendRaw(pOut, "true", 4);
|
||||
break;
|
||||
}
|
||||
case JSON_FALSE: {
|
||||
jsonAppendRawNZ(pOut, "false", 5);
|
||||
jsonAppendRaw(pOut, "false", 5);
|
||||
break;
|
||||
}
|
||||
case JSON_STRING: {
|
||||
@@ -595,8 +568,7 @@ static void jsonRenderNode(
|
||||
}else if( pNode->jnFlags & JNODE_JSON5 ){
|
||||
jsonAppendNormalizedString(pOut, pNode->u.zJContent, pNode->n);
|
||||
}else{
|
||||
assert( pNode->n>0 );
|
||||
jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
|
||||
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -605,8 +577,7 @@ static void jsonRenderNode(
|
||||
if( pNode->jnFlags & JNODE_JSON5 ){
|
||||
jsonAppendNormalizedReal(pOut, pNode->u.zJContent, pNode->n);
|
||||
}else{
|
||||
assert( pNode->n>0 );
|
||||
jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
|
||||
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -615,8 +586,7 @@ static void jsonRenderNode(
|
||||
if( pNode->jnFlags & JNODE_JSON5 ){
|
||||
jsonAppendNormalizedInt(pOut, pNode->u.zJContent, pNode->n);
|
||||
}else{
|
||||
assert( pNode->n>0 );
|
||||
jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
|
||||
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -918,8 +888,7 @@ static int jsonParseAddNode(
|
||||
const char *zContent /* Content */
|
||||
){
|
||||
JsonNode *p;
|
||||
assert( pParse->aNode!=0 || pParse->nNode>=pParse->nAlloc );
|
||||
if( pParse->nNode>=pParse->nAlloc ){
|
||||
if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){
|
||||
return jsonParseAddNodeExpand(pParse, eType, n, zContent);
|
||||
}
|
||||
p = &pParse->aNode[pParse->nNode];
|
||||
@@ -1272,31 +1241,15 @@ json_parse_restart:
|
||||
jnFlags = 0;
|
||||
parse_string:
|
||||
cDelim = z[i];
|
||||
for(j=i+1; 1; j++){
|
||||
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;
|
||||
j = i+1;
|
||||
for(;;){
|
||||
c = z[j];
|
||||
if( c==cDelim ){
|
||||
break;
|
||||
}else if( c=='\\' ){
|
||||
if( (c & ~0x1f)==0 ){
|
||||
/* Control characters are not allowed in strings */
|
||||
pParse->iErr = j;
|
||||
return -1;
|
||||
}
|
||||
if( c=='\\' ){
|
||||
c = z[++j];
|
||||
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|
||||
|| c=='n' || c=='r' || c=='t'
|
||||
@@ -1316,11 +1269,10 @@ json_parse_restart:
|
||||
pParse->iErr = j;
|
||||
return -1;
|
||||
}
|
||||
}else if( c<=0x1f ){
|
||||
/* Control characters are not allowed in strings */
|
||||
pParse->iErr = j;
|
||||
return -1;
|
||||
}else if( c==cDelim ){
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
jsonParseAddNode(pParse, JSON_STRING | (jnFlags<<8), j+1-i, &z[i]);
|
||||
return j+1;
|
||||
@@ -1570,6 +1522,7 @@ static int jsonParse(
|
||||
memset(pParse, 0, sizeof(*pParse));
|
||||
if( zJson==0 ) return 1;
|
||||
pParse->zJson = zJson;
|
||||
/* printf("JSON parse: %s\n", zJson); fflush(stdout); */
|
||||
i = jsonParseValue(pParse, 0);
|
||||
if( pParse->oom ) i = -1;
|
||||
if( i>0 ){
|
||||
@@ -1650,11 +1603,21 @@ static int jsonParseFindParents(JsonParse *pParse){
|
||||
** Obtain a complete parse of the JSON found in the first argument
|
||||
** of the argv array. Use the sqlite3_get_auxdata() cache for this
|
||||
** parse if it is available. If the cache is not available or if it
|
||||
** is no longer valid, parse the JSON again and return the new parse,
|
||||
** and also register the new parse so that it will be available for
|
||||
** future sqlite3_get_auxdata() calls.
|
||||
** is no longer valid, parse the JSON again and return the new parse.
|
||||
**
|
||||
** If an error occurs and pErrCtx!=0 then report the error on pErrCtx
|
||||
** If a new parse is created, it is stored in the cache unless bWrite
|
||||
** is true. If the parse is cached and pErrCtx!=0 then the caller does
|
||||
** not need to free the returned parse since the parse belongs to the
|
||||
** cache and will be freed when the cache is cleared. On the other hand,
|
||||
** the returned parse should be treated as read-only.
|
||||
**
|
||||
** If the bWrite field is true, then it is assumed that the caller will
|
||||
** make changes to the parse. In this case, the parse is not cached (or
|
||||
** it is removed from the cache). Ownership of the parse passes to the
|
||||
** caller and the caller is expected to call jsonParseFree() when it has
|
||||
** finished using the parse.
|
||||
**
|
||||
** If an error occurs and pErrCtx!=0 then an error is reported on pErrCtx
|
||||
** and return NULL.
|
||||
**
|
||||
** If an error occurs and pErrCtx==0 then return the Parse object with
|
||||
@@ -1666,7 +1629,8 @@ static int jsonParseFindParents(JsonParse *pParse){
|
||||
static JsonParse *jsonParseCached(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_value **argv,
|
||||
sqlite3_context *pErrCtx
|
||||
sqlite3_context *pErrCtx,
|
||||
int bWrite
|
||||
){
|
||||
const char *zJson = (const char*)sqlite3_value_text(argv[0]);
|
||||
int nJson = sqlite3_value_bytes(argv[0]);
|
||||
@@ -1683,12 +1647,19 @@ static JsonParse *jsonParseCached(
|
||||
iMinKey = iKey;
|
||||
break;
|
||||
}
|
||||
assert( p->nRef==1 );
|
||||
if( pMatch==0
|
||||
&& p->nJson==nJson
|
||||
&& memcmp(p->zJson,zJson,nJson)==0
|
||||
){
|
||||
p->nErr = 0;
|
||||
pMatch = p;
|
||||
if( bWrite ){
|
||||
p->nRef = 2;
|
||||
sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iKey, 0, 0);
|
||||
/* printf("JSON cache hit and purge (%d)\n", iKey); fflush(stdout); */
|
||||
}
|
||||
/* else{ printf("JSON cache hit (%d)\n", iKey); fflush(stdout); } */
|
||||
}else if( p->iHold<iMinHold ){
|
||||
iMinHold = p->iHold;
|
||||
iMinKey = iKey;
|
||||
@@ -1700,6 +1671,7 @@ static JsonParse *jsonParseCached(
|
||||
if( pMatch ){
|
||||
pMatch->nErr = 0;
|
||||
pMatch->iHold = iMaxHold+1;
|
||||
assert( pMatch->nRef==1 );
|
||||
return pMatch;
|
||||
}
|
||||
p = sqlite3_malloc64( sizeof(*p) + nJson + 1 );
|
||||
@@ -1710,9 +1682,11 @@ static JsonParse *jsonParseCached(
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->zJson = (char*)&p[1];
|
||||
memcpy((char*)p->zJson, zJson, nJson+1);
|
||||
/* printf("JSON cache miss\n"); fflush(stdout); */
|
||||
if( jsonParse(p, pErrCtx, p->zJson) ){
|
||||
if( pErrCtx==0 ){
|
||||
p->nErr = 1;
|
||||
p->nRef = 1;
|
||||
return p;
|
||||
}
|
||||
sqlite3_free(p);
|
||||
@@ -1720,9 +1694,15 @@ static JsonParse *jsonParseCached(
|
||||
}
|
||||
p->nJson = nJson;
|
||||
p->iHold = iMaxHold+1;
|
||||
sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
|
||||
(void(*)(void*))jsonParseFree);
|
||||
return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
|
||||
p->nRef = 1;
|
||||
if( !bWrite ){
|
||||
/* printf("JSON cache insert (%d)\n", iMinKey); fflush(stdout); */
|
||||
sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
|
||||
(void(*)(void*))jsonParseFree);
|
||||
p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
|
||||
}
|
||||
assert( p==0 || p->nRef==1 );
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2057,12 +2037,12 @@ static void jsonParseFunc(
|
||||
assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 );
|
||||
if( x.aNode[i].u.zJContent!=0 ){
|
||||
assert( x.aNode[i].eU==1 );
|
||||
jsonAppendChar(&s, ' ');
|
||||
jsonAppendRaw(&s, " ", 1);
|
||||
jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
|
||||
}else{
|
||||
assert( x.aNode[i].eU==0 );
|
||||
}
|
||||
jsonAppendChar(&s, '\n');
|
||||
jsonAppendRaw(&s, "\n", 1);
|
||||
}
|
||||
jsonParseReset(&x);
|
||||
jsonResult(&s);
|
||||
@@ -2149,7 +2129,7 @@ static void jsonArrayLengthFunc(
|
||||
u32 i;
|
||||
JsonNode *pNode;
|
||||
|
||||
p = jsonParseCached(ctx, argv, ctx);
|
||||
p = jsonParseCached(ctx, argv, ctx, 0);
|
||||
if( p==0 ) return;
|
||||
assert( p->nNode );
|
||||
if( argc==2 ){
|
||||
@@ -2211,7 +2191,7 @@ static void jsonExtractFunc(
|
||||
JsonString jx;
|
||||
|
||||
if( argc<2 ) return;
|
||||
p = jsonParseCached(ctx, argv, ctx);
|
||||
p = jsonParseCached(ctx, argv, ctx, 0);
|
||||
if( p==0 ) return;
|
||||
if( argc==2 ){
|
||||
/* With a single PATH argument */
|
||||
@@ -2229,11 +2209,11 @@ static void jsonExtractFunc(
|
||||
*/
|
||||
jsonInit(&jx, ctx);
|
||||
if( sqlite3Isdigit(zPath[0]) ){
|
||||
jsonAppendRawNZ(&jx, "$[", 2);
|
||||
jsonAppendRaw(&jx, "$[", 2);
|
||||
jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
|
||||
jsonAppendRawNZ(&jx, "]", 2);
|
||||
jsonAppendRaw(&jx, "]", 2);
|
||||
}else{
|
||||
jsonAppendRawNZ(&jx, "$.", 1 + (zPath[0]!='['));
|
||||
jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='['));
|
||||
jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
|
||||
jsonAppendChar(&jx, 0);
|
||||
}
|
||||
@@ -2268,7 +2248,7 @@ static void jsonExtractFunc(
|
||||
if( pNode ){
|
||||
jsonRenderNode(pNode, &jx, 0);
|
||||
}else{
|
||||
jsonAppendRawNZ(&jx, "null", 4);
|
||||
jsonAppendRaw(&jx, "null", 4);
|
||||
}
|
||||
}
|
||||
if( i==argc ){
|
||||
@@ -2367,25 +2347,27 @@ static void jsonPatchFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
JsonParse x; /* The JSON that is being patched */
|
||||
JsonParse y; /* The patch */
|
||||
JsonParse *pX; /* The JSON that is being patched */
|
||||
JsonParse *pY; /* The patch */
|
||||
JsonNode *pResult; /* The result of the merge */
|
||||
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
|
||||
if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
|
||||
jsonParseReset(&x);
|
||||
pX = jsonParseCached(ctx, argv, ctx, 1);
|
||||
if( pX==0 ) return;
|
||||
pY = jsonParseCached(ctx, argv+1, ctx, 1);
|
||||
if( pY==0 ){
|
||||
jsonParseFree(pX);
|
||||
return;
|
||||
}
|
||||
pResult = jsonMergePatch(&x, 0, y.aNode);
|
||||
assert( pResult!=0 || x.oom );
|
||||
pResult = jsonMergePatch(pX, 0, pY->aNode);
|
||||
assert( pResult!=0 || pX->oom );
|
||||
if( pResult ){
|
||||
jsonReturnJson(pResult, ctx, 0);
|
||||
}else{
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
}
|
||||
jsonParseReset(&x);
|
||||
jsonParseReset(&y);
|
||||
jsonParseFree(pX);
|
||||
jsonParseFree(pY);
|
||||
}
|
||||
|
||||
|
||||
@@ -2441,26 +2423,27 @@ static void jsonRemoveFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
JsonParse x; /* The parse */
|
||||
JsonParse *p; /* The parse */
|
||||
JsonNode *pNode;
|
||||
const char *zPath;
|
||||
u32 i;
|
||||
|
||||
if( argc<1 ) return;
|
||||
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
|
||||
assert( x.nNode );
|
||||
p = jsonParseCached(ctx, argv, ctx, 1);
|
||||
if( p==0 ) return;
|
||||
assert( p->nNode );
|
||||
for(i=1; i<(u32)argc; i++){
|
||||
zPath = (const char*)sqlite3_value_text(argv[i]);
|
||||
if( zPath==0 ) goto remove_done;
|
||||
pNode = jsonLookup(&x, zPath, 0, ctx);
|
||||
if( x.nErr ) goto remove_done;
|
||||
pNode = jsonLookup(p, zPath, 0, ctx);
|
||||
if( p->nErr ) goto remove_done;
|
||||
if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
|
||||
}
|
||||
if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
|
||||
jsonReturnJson(x.aNode, ctx, 0);
|
||||
if( (p->aNode[0].jnFlags & JNODE_REMOVE)==0 ){
|
||||
jsonReturnJson(p->aNode, ctx, 0);
|
||||
}
|
||||
remove_done:
|
||||
jsonParseReset(&x);
|
||||
jsonParseFree(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2474,7 +2457,7 @@ static void jsonReplaceFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
JsonParse x; /* The parse */
|
||||
JsonParse *p; /* The parse */
|
||||
JsonNode *pNode;
|
||||
const char *zPath;
|
||||
u32 i;
|
||||
@@ -2484,12 +2467,13 @@ static void jsonReplaceFunc(
|
||||
jsonWrongNumArgs(ctx, "replace");
|
||||
return;
|
||||
}
|
||||
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
|
||||
assert( x.nNode );
|
||||
p = jsonParseCached(ctx, argv, ctx, 1);
|
||||
if( p==0 ) return;
|
||||
assert( p->nNode );
|
||||
for(i=1; i<(u32)argc; i+=2){
|
||||
zPath = (const char*)sqlite3_value_text(argv[i]);
|
||||
pNode = jsonLookup(&x, zPath, 0, ctx);
|
||||
if( x.nErr ) goto replace_err;
|
||||
pNode = jsonLookup(p, zPath, 0, ctx);
|
||||
if( p->nErr ) goto replace_err;
|
||||
if( pNode ){
|
||||
assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 );
|
||||
testcase( pNode->eU!=0 && pNode->eU!=1 );
|
||||
@@ -2498,14 +2482,14 @@ static void jsonReplaceFunc(
|
||||
pNode->u.iReplace = i + 1;
|
||||
}
|
||||
}
|
||||
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
|
||||
assert( x.aNode[0].eU==4 );
|
||||
sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
|
||||
if( p->aNode[0].jnFlags & JNODE_REPLACE ){
|
||||
assert( p->aNode[0].eU==4 );
|
||||
sqlite3_result_value(ctx, argv[p->aNode[0].u.iReplace]);
|
||||
}else{
|
||||
jsonReturnJson(x.aNode, ctx, argv);
|
||||
jsonReturnJson(p->aNode, ctx, argv);
|
||||
}
|
||||
replace_err:
|
||||
jsonParseReset(&x);
|
||||
jsonParseFree(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -2526,7 +2510,7 @@ static void jsonSetFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
JsonParse x; /* The parse */
|
||||
JsonParse *p; /* The parse */
|
||||
JsonNode *pNode;
|
||||
const char *zPath;
|
||||
u32 i;
|
||||
@@ -2538,16 +2522,17 @@ static void jsonSetFunc(
|
||||
jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
|
||||
return;
|
||||
}
|
||||
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
|
||||
assert( x.nNode );
|
||||
p = jsonParseCached(ctx, argv, ctx, 1);
|
||||
if( p==0 ) return;
|
||||
assert( p->nNode );
|
||||
for(i=1; i<(u32)argc; i+=2){
|
||||
zPath = (const char*)sqlite3_value_text(argv[i]);
|
||||
bApnd = 0;
|
||||
pNode = jsonLookup(&x, zPath, &bApnd, ctx);
|
||||
if( x.oom ){
|
||||
pNode = jsonLookup(p, zPath, &bApnd, ctx);
|
||||
if( p->oom ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
goto jsonSetDone;
|
||||
}else if( x.nErr ){
|
||||
}else if( p->nErr ){
|
||||
goto jsonSetDone;
|
||||
}else if( pNode && (bApnd || bIsSet) ){
|
||||
testcase( pNode->eU!=0 && pNode->eU!=1 );
|
||||
@@ -2557,14 +2542,14 @@ static void jsonSetFunc(
|
||||
pNode->u.iReplace = i + 1;
|
||||
}
|
||||
}
|
||||
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
|
||||
assert( x.aNode[0].eU==4 );
|
||||
sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
|
||||
if( p->aNode[0].jnFlags & JNODE_REPLACE ){
|
||||
assert( p->aNode[0].eU==4 );
|
||||
sqlite3_result_value(ctx, argv[p->aNode[0].u.iReplace]);
|
||||
}else{
|
||||
jsonReturnJson(x.aNode, ctx, argv);
|
||||
jsonReturnJson(p->aNode, ctx, argv);
|
||||
}
|
||||
jsonSetDone:
|
||||
jsonParseReset(&x);
|
||||
jsonParseFree(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2583,7 +2568,7 @@ static void jsonTypeFunc(
|
||||
const char *zPath;
|
||||
JsonNode *pNode;
|
||||
|
||||
p = jsonParseCached(ctx, argv, ctx);
|
||||
p = jsonParseCached(ctx, argv, ctx, 0);
|
||||
if( p==0 ) return;
|
||||
if( argc==2 ){
|
||||
zPath = (const char*)sqlite3_value_text(argv[1]);
|
||||
@@ -2610,7 +2595,7 @@ static void jsonValidFunc(
|
||||
JsonParse *p; /* The parse */
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
p = jsonParseCached(ctx, argv, 0);
|
||||
p = jsonParseCached(ctx, argv, 0, 0);
|
||||
if( p==0 || p->oom ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
sqlite3_free(p);
|
||||
@@ -2656,7 +2641,7 @@ static void jsonErrorFunc(
|
||||
JsonParse *p; /* The parse */
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
p = jsonParseCached(ctx, argv, 0);
|
||||
p = jsonParseCached(ctx, argv, 0, 0);
|
||||
if( p==0 || p->oom ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
sqlite3_free(p);
|
||||
|
||||
+1
-3
@@ -846,9 +846,7 @@ int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_HEX_INTEGER */
|
||||
{
|
||||
int n = (int)(0x3fffffff&strspn(z,"+- \n\t0123456789"));
|
||||
if( z[n] ) n++;
|
||||
return sqlite3Atoi64(z, pOut, n, SQLITE_UTF8);
|
||||
return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -556,9 +556,6 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){
|
||||
sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.');
|
||||
}
|
||||
sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]);
|
||||
if( f & MEM_Term ){
|
||||
sqlite3_str_appendf(pStr, "(0-term)");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -3088,9 +3085,6 @@ op_column_restart:
|
||||
rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
|
||||
if( (t&1)!=0 && encoding==SQLITE_UTF8 ){
|
||||
pDest->flags |= MEM_Term;
|
||||
}
|
||||
pDest->flags &= ~MEM_Ephem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,7 +611,6 @@ int sqlite3VdbeMemSetZeroBlob(Mem*,int);
|
||||
int sqlite3VdbeMemIsRowSet(const Mem*);
|
||||
#endif
|
||||
int sqlite3VdbeMemSetRowSet(Mem*);
|
||||
void sqlite3VdbeMemZeroTerminateIfAble(Mem*);
|
||||
int sqlite3VdbeMemMakeWriteable(Mem*);
|
||||
int sqlite3VdbeMemStringify(Mem*, u8, u8);
|
||||
int sqlite3IntFloatCompare(i64,double);
|
||||
|
||||
@@ -514,7 +514,6 @@ void sqlite3_result_text64(
|
||||
(void)invokeValueDestructor(z, xDel, pCtx);
|
||||
}else{
|
||||
setResultStrOrError(pCtx, z, (int)n, enc, xDel);
|
||||
sqlite3VdbeMemZeroTerminateIfAble(pCtx->pOut);
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
|
||||
+1
-30
@@ -314,32 +314,6 @@ int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
|
||||
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.
|
||||
** Add the zero terminator.
|
||||
@@ -829,7 +803,6 @@ int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
int rc;
|
||||
assert( aff==SQLITE_AFF_TEXT );
|
||||
assert( MEM_Str==(MEM_Blob>>3) );
|
||||
pMem->flags |= (pMem->flags&MEM_Blob)>>3;
|
||||
@@ -837,9 +810,7 @@ int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
|
||||
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
|
||||
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
|
||||
if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1;
|
||||
rc = sqlite3VdbeChangeEncoding(pMem, encoding);
|
||||
if( rc ) return rc;
|
||||
sqlite3VdbeMemZeroTerminateIfAble(pMem);
|
||||
return sqlite3VdbeChangeEncoding(pMem, encoding);
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
|
||||
@@ -25,15 +25,3 @@ of the SQLite JSON parser.
|
||||
|
||||
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".
|
||||
|
||||
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;
|
||||
~~~~
|
||||
|
||||
Reference in New Issue
Block a user