sqlite3.c shell.c
gzip < $@ > $@.gz
gzip < $(fiddle_dir)/fiddle-module.wasm > $(fiddle_dir)/fiddle-module.wasm.gz
-$(sqlite3_wasm_js): Makefile sqlite3.c \
+$(sqlite3_wasm_js): Makefile sqlite3.c $(fiddle_dir)/wasm_util.c \
$(fiddle_dir)/sqlite3-api.js \
$(fiddle_dir)/EXPORTED_RUNTIME_METHODS \
$(fiddle_dir)/EXPORTED_FUNCTIONS.sqlite3-api
emcc -o $@ $(emcc_flags) \
- -sEXPORT_NAME=initSqlite3Module \
+ -sEXPORT_NAME=sqlite3InitModule \
-sEXPORTED_FUNCTIONS=@$(fiddle_dir_abs)/EXPORTED_FUNCTIONS.sqlite3-api \
--post-js=$(fiddle_dir)/sqlite3-api.js \
--no-entry \
- sqlite3.c
+ sqlite3.c $(fiddle_dir)/wasm_util.c
gzip < $@ > $@.gz
gzip < $(sqlite3_wasm) > $(sqlite3_wasm).gz
gzip < $(fiddle_dir)/sqlite3-api.js > $(fiddle_dir)/sqlite3-api.js.gz
_sqlite3_value_double
_sqlite3_value_text
_sqlite3_value_type
+_sqlite3_wasm_enum_json
_free
/**
This is a module object for use with the emscripten-installed
- initSqlite3Module() factory function.
+ sqlite3InitModule() factory function.
*/
self.sqlite3TestModule = {
postRun: [
This file is intended to be appended to the emcc-generated
sqlite3.js via emcc:
- emcc ... -sMODULARIZE -sEXPORT_NAME=initSqlite3Module --post-js=THIS_FILE
+ emcc ... -sMODULARIZE -sEXPORT_NAME=sqlite3InitModule --post-js=THIS_FILE
It is loaded by importing the emcc-generated sqlite3.js, then:
- initSqlite3Module({module object}).then(
+ sqlite3InitModule({module object}).then(
function(theModule){
theModule.sqlite3 == an object containing this file's
deliverables:
It is up to the caller to provide a module object compatible with
emcc, but it can be a plain empty object. The object passed to
- initSqlite3Module() will get populated by the emscripten-generated
+ sqlite3InitModule() will get populated by the emscripten-generated
bits and, in part, by the code from this file. Specifically, this file
installs the `theModule.sqlite3` part shown above.
follows is strongly influenced by the sql.js implementation.
*/
const api = {
- /* It is important that the following integer values match
- those from the C code. Ideally we could fetch them from the
- C API, e.g., in the form of a JSON object, but getting that
- JSON string constructed within our current confines is
- currently not worth the effort.
-
- Reminder to self: we could probably do so by adding the
- proverbial level of indirection, calling in to C to get it,
- and having that C func call an
- emscripten-installed/JS-implemented library function which
- builds the result object:
-
- const obj = {};
- sqlite3__get_enum(function(key,val){
- obj[key] = val;
- });
-
- but whether or not we can pass a function that way, via a
- (void*) is as yet unknown.
- */
- /* Minimum subset of sqlite result codes we'll need. */
- SQLITE_OK: 0,
- SQLITE_ROW: 100,
- SQLITE_DONE: 101,
- /* sqlite data types */
- SQLITE_INTEGER: 1,
- SQLITE_FLOAT: 2,
- SQLITE_TEXT: 3,
- SQLITE_BLOB: 4,
- SQLITE_NULL: 5,
- /* create_function() flags */
- SQLITE_DETERMINISTIC: 0x000000800,
- SQLITE_DIRECTONLY: 0x000080000,
- SQLITE_INNOCUOUS: 0x000200000,
- /* sqlite encodings, used for creating UDFs, noting that we
- will only support UTF8. */
- SQLITE_UTF8: 1,
- /* Values for the final argument of sqlite3_result_blob(),
- noting that these are interpreted in WASM as pointer
- values. */
- SQLITE_TRANSIENT: -1,
- SQLITE_STATIC: 0,
-
/**
Holds state which are specific to the WASM-related
infrastructure and glue code. It is not expected that client
"number", "number"]),
};
- const uint8ToString = (str)=>new TextDecoder('utf-8').decode(str);
+ /* Import C-level constants... */
+ //console.log("wasmEnum=",SQM.ccall('sqlite3_wasm_enum_json', 'string', []));
+ const wasmEnum = JSON.parse(SQM.ccall('sqlite3_wasm_enum_json', 'string', []));
+ ['resultCodes','dataTypes','udfFlags',
+ 'encodings','blobFinalizers'].forEach(function(t){
+ Object.keys(wasmEnum[t]).forEach(function(k){
+ api[k] = wasmEnum[t][k];
+ });
+ });
+
+ const utf8Decoder = new TextDecoder('utf-8');
+ const typedArrayToString = (str)=>utf8Decoder.decode(str);
//const stringToUint8 = (sql)=>new TextEncoder('utf-8').encode(sql);
/**
parameters) requires using api.wasm.getValue().
*/
api.sqlite3_prepare_v2 = function(pDb, sql, sqlLen, ppStmt, pzTail){
- if(sql instanceof Uint8Array) sql = uint8ToString(sql);
+ if(isSupportedTypedArray(sql)) sql = typedArrayToString(sql);
switch(typeof sql){
case 'string': return prepareMethods.basic(pDb, sql, -1, ppStmt, null);
case 'number': return prepareMethods.full(pDb, sql, -1, ppStmt, pzTail);
case 1:
if('string'===typeof args[0]){
out.sql = args[0];
- }else if(args[0] instanceof Uint8Array){
+ }else if(isSupportedTypedArray(args[0])){
out.sql = args[0];
}else if(args[0] && 'object'===typeof args[0]){
out.opt = args[0];
break;
default: toss("Invalid argument count for exec().");
};
- if(out.sql instanceof Uint8Array){
- out.sql = uint8ToString(out.sql);
+ if(isSupportedTypedArray(out.sql)){
+ out.sql = typedArrayToString(out.sql);
}else if(Array.isArray(out.sql)){
out.sql = out.sql.join('');
}else if('string'!==typeof out.sql){
(opt.callback && opt.rowMode)
? opt.rowMode : false);
try{
- const sql = (arg.sql instanceof Uint8Array)
- ? uint8ToString(arg.sql)
+ const sql = isSupportedTypedArray(arg.sql)
+ ? typedArrayToString(arg.sql)
: arg.sql;
let pSql = api.wasm.allocateUTF8OnStack(sql)
const ppStmt = api.wasm.stackAlloc(8) /* output (sqlite3_stmt**) arg */;
If passed no arguments then it returns an object mapping
all known compilation options to their compile-time values,
- or boolean true if they are defined with no value.
+ or boolean true if they are defined with no value. This
+ result, which is relatively expensive to compute, is cached
+ and returned for future no-argument calls.
In all other cases it returns true if the given option was
active when when compiling the sqlite3 module, else false.
*/
compileOptionUsed: function f(optName){
if(!arguments.length){
- if(!f._opt){
+ if(f._result) return f._result;
+ else if(!f._opt){
f._rx = /^([^=]+)=(.+)/;
f._rxInt = /^-?\d+$/;
f._opt = function(opt, rv){
f._opt(k,ov);
rc[ov[0]] = ov[1];
}
- return rc;
- }
- else if(Array.isArray(optName)){
+ return f._result = rc;
+ }else if(Array.isArray(optName)){
const rc = {};
optName.forEach((v)=>{
rc[v] = api.sqlite3_compileoption_used(v);
});
return rc;
- }
- else if('object' === typeof optName){
+ }else if('object' === typeof optName){
Object.keys(optName).forEach((k)=> {
optName[k] = api.sqlite3_compileoption_used(k);
});
loading sqlite3.js via a Worker. Loading sqlite3.js from the main
window thread elides the Worker-specific API. Instantiating a worker
with new Worker("sqlite.js") will not (cannot) call
- initSqlite3Module() to initialize the module due to a
+ sqlite3InitModule() to initialize the module due to a
timing/order-of-operations conflict (and that symbol is not exported
in a way that a Worker loading it that way can see it). Thus JS
code wanting to load the sqlite3 Worker-specific API needs to pass
*/
"use strict";
importScripts('sqlite3.js');
-initSqlite3Module().then(function(){
+sqlite3InitModule().then(function(){
setTimeout(()=>self.postMessage({type:'sqlite3-api',data:'ready'}), 0);
});
api.sqlite3_sourceid());
log("Build options:",oo.compileOptionUsed());
log("api.wasm.HEAP8 size =",api.wasm.HEAP8.length);
+ log("wasmEnum",JSON.parse(Module.ccall('sqlite3_wasm_enum_json', 'string', [])));
+ [ /* Spot-check a handful of constants to make sure they got installed... */
+ 'SQLITE_SCHEMA','SQLITE_NULL','SQLITE_UTF8',
+ 'SQLITE_STATIC', 'SQLITE_DIRECTONLY'
+ ].forEach(function(k){
+ T.assert('number' === typeof api[k]);
+ });
const db = new oo.DB();
try {
log("DB:",db.filename);
db.close();
}
log("Total Test count:",T.counter);
- log("api.wasm.HEAP8 size =",api.wasm.HEAP8.length);
};
- initSqlite3Module(self.sqlite3TestModule).then(function(theModule){
- /** Use a timeout so that we are (hopefully) out from
- under the module init stack when our setup gets
- run. Just on principle, not because we _need_ to
- be. */
+ sqlite3InitModule(self.sqlite3TestModule).then(function(theModule){
+ /** Use a timeout so that we are (hopefully) out from under
+ the module init stack when our setup gets run. Just on
+ principle, not because we _need_ to be. */
//console.debug("theModule =",theModule);
setTimeout(()=>runTests(theModule), 0);
});
--- /dev/null
+#include "sqlite3.h"
+#include <stdlib.h> /*atexit()*/
+/*
+** 2022-06-25
+**
+** The author disclaims copyright to this source code. In place of a
+** legal notice, here is a blessing:
+**
+** * May you do good and not evil.
+** * May you find forgiveness for yourself and forgive others.
+** * May you share freely, never taking more than you give.
+**
+***********************************************************************
+**
+** Utility functions for use with the emscripten/WASM bits. These
+** functions ARE NOT part of the sqlite3 public API. They are strictly
+** for internal use by the JS/WASM bindings.
+*/
+
+/** Result value of sqlite3_wasm_enum_json(). */
+static char * zWasmEnum = 0;
+/* atexit() handler to clean up any WASM-related state. */
+static void sqlite3_wasm_cleanup(void){
+ free(zWasmEnum);
+}
+
+/*
+** Returns a string containing a JSON-format "enum" of C-level
+** constants intended to be imported into the JS environment. The JSON
+** is initialized the first time this function is called and that
+** result is reused for all future calls and cleaned up via atexit().
+** (If we didn't cache the result, it would be leaked by the JS glue
+** code on each call during the WASM-to-JS conversion.)
+**
+** This function is NOT part of the sqlite3 public API. It is strictly
+** for use by the JS/WASM bindings.
+*/
+const char * sqlite3_wasm_enum_json(void){
+ sqlite3_str * s;
+ if(zWasmEnum) return zWasmEnum;
+ s = sqlite3_str_new(0);
+ sqlite3_str_appendall(s, "{");
+
+#define SD_(X,S,FINAL) \
+ sqlite3_str_appendf(s, "\"%s\": %d%s", S, (int)X, (FINAL ? "}" : ", "))
+#define SD(X) SD_(X,#X,0)
+#define SDFinal(X) SD_(X,#X,1)
+
+ sqlite3_str_appendall(s,"\"resultCodes\": {");
+ SD(SQLITE_OK);
+ SD(SQLITE_ERROR);
+ SD(SQLITE_INTERNAL);
+ SD(SQLITE_PERM);
+ SD(SQLITE_ABORT);
+ SD(SQLITE_BUSY);
+ SD(SQLITE_LOCKED);
+ SD(SQLITE_NOMEM);
+ SD(SQLITE_READONLY);
+ SD(SQLITE_INTERRUPT);
+ SD(SQLITE_IOERR);
+ SD(SQLITE_CORRUPT);
+ SD(SQLITE_NOTFOUND);
+ SD(SQLITE_FULL);
+ SD(SQLITE_CANTOPEN);
+ SD(SQLITE_PROTOCOL);
+ SD(SQLITE_EMPTY);
+ SD(SQLITE_SCHEMA);
+ SD(SQLITE_TOOBIG);
+ SD(SQLITE_CONSTRAINT);
+ SD(SQLITE_MISMATCH);
+ SD(SQLITE_MISUSE);
+ SD(SQLITE_NOLFS);
+ SD(SQLITE_AUTH);
+ SD(SQLITE_FORMAT);
+ SD(SQLITE_RANGE);
+ SD(SQLITE_NOTADB);
+ SD(SQLITE_NOTICE);
+ SD(SQLITE_WARNING);
+ SD(SQLITE_ROW);
+ SDFinal(SQLITE_DONE);
+
+ sqlite3_str_appendall(s,",\"dataTypes\": {");
+ SD(SQLITE_INTEGER);
+ SD(SQLITE_FLOAT);
+ SD(SQLITE_TEXT);
+ SD(SQLITE_BLOB);
+ SDFinal(SQLITE_NULL);
+
+ sqlite3_str_appendf(s,",\"encodings\": {");
+ SDFinal(SQLITE_UTF8);
+
+ sqlite3_str_appendall(s,",\"blobFinalizers\": {");
+ SD(SQLITE_STATIC);
+ SDFinal(SQLITE_TRANSIENT);
+
+ sqlite3_str_appendall(s,",\"udfFlags\": {");
+ SD(SQLITE_DETERMINISTIC);
+ SD(SQLITE_DIRECTONLY);
+ SDFinal(SQLITE_INNOCUOUS);
+
+#undef SD_
+#undef SD
+#undef SDFinal
+ sqlite3_str_appendall(s, "}");
+ zWasmEnum = sqlite3_str_finish(s);
+ atexit(sqlite3_wasm_cleanup);
+ return zWasmEnum;
+}
-C wasm:\seliminated\sthe\sneed\sfor\sStmt\sobjects\sto\skeep\sahold\sof\smemory\sallocated\sfor\sbound\sstrings\sand\sblobs.\sAdded\salternate\sstring/blob\sbind\simpls\swhich\sare\shypothetically\smore\sefficient\sbut\snot\syet\sproven\sto\sbe\sso.
-D 2022-06-25T07:42:24.832
+C wasm:\sadded\sutility\sC\scode\sto\sgenerate\sa\sJSON-format\s"enum"\sof\sthe\snumerous\sSQLITE_xyz\sconstants\sso\sthat\swe\sdo\snot\srisk\sthose\sgetting\sout\sof\ssync\sin\sthe\sJS\scode.\sRenamed\sinitSqlite3Module\sto\ssqlite3InitModule.\sCleanups\sin\sthe\sTypedArray\shandling.
+D 2022-06-25T10:30:24.409
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
-F Makefile.in bccb0ed3f05fc41aee15da77c844c48b5da419cbb9af35b8a147536c9ad1c822
+F Makefile.in b3ccd1a79e6364d49c465b38cec5eccdc74dfdc06501be62ef8eb01dc1f93f43
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
F Makefile.msc de7cb3e095ce2fdc33513ccd76ebdaeda1483d0ddab0410fe65cbdeadd4c0ee1
F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e
F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 7fb73f7150ab79d83bb45a67d257553c905c78cd3d693101699243f36c5ae6c3
-F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3-api 540b9dec63a3a62a256e2f030827848a92e9b9d9b6fa5c0188295a4a1c5382cd
+F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3-api 2ef8a8d58815a96de196d085b8aaf126400b8d13a5b7f724f86dfe9f61d0600d
F ext/fiddle/EXPORTED_RUNTIME_METHODS a004bd5eeeda6d3b28d16779b7f1a80305bfe009dfc7f0721b042967f0d39d02
F ext/fiddle/Makefile e25d34a0e1324f771d64c09c592601b97219282011587e6ce410fa8acdedb913
-F ext/fiddle/SqliteTestUtil.js 559731c3e8e0de330ec7d292e6c1846566408caee6637acc8a119ac338a8781c
+F ext/fiddle/SqliteTestUtil.js 2e87d424b12674476bdf8139934dcacc3ff8a7a5f5ff4392ba5e5a8d8cee9fbd
F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
F ext/fiddle/fiddle-worker.js 88bc2193a6cb6a3f04d8911bed50a4401fe6f277de7a71ba833865ab64a1b4ae
F ext/fiddle/fiddle.html 550c5aafce40bd218de9bf26192749f69f9b10bc379423ecd2e162bcef885c08
F ext/fiddle/fiddle.js 812f9954cc7c4b191884ad171f36fcf2d0112d0a7ecfdf6087896833a0c079a8
F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf
-F ext/fiddle/sqlite3-api.js 664a454d82694c6cfab36b8ad9e36620cfc44fa37e05642ba87109c37409f51f
-F ext/fiddle/sqlite3-worker.js a9c2b614beca187dbdd8c053ec2770cc61ec1ac9c0ec6398ceb49a79f705a421
+F ext/fiddle/sqlite3-api.js 03ac065f4bc68eefd3b09cf3957a58891cbfcebe2a5ffe1c8a10f16a58dfc70b
+F ext/fiddle/sqlite3-worker.js 50b7a9ce14c8fae0af965e35605fe12cafb79c1e01e99216d8110d8b02fbf4b5
F ext/fiddle/testing.css 750572dded671d2cf142bbcb27af5542522ac08db128245d0b9fe410aa1d7f2a
F ext/fiddle/testing1.html ea1f3be727f78e420007f823912c1a03b337ecbb8e79449abc2244ad4fe15d9a
-F ext/fiddle/testing1.js 5c04721d205b3d909ec6896682743051cb5e5202e9151a058e90600a42f48f48
+F ext/fiddle/testing1.js f9615ff58b9de6879e4836618b34322085510ec44c6754e725a92a097c908a6f
F ext/fiddle/testing2.html 9063b2430ade2fe9da4e711addd1b51a2741cf0c7ebf6926472a5e5dd63c0bc4
F ext/fiddle/testing2.js 7b45b4e7fddbd51dbaf89b6722c02758051b34bac5a98c11b569a7e7572f88ee
+F ext/fiddle/wasm_util.c b63e00c2f264ab4a9c45c9f9727627cbc4d8aa2f93c5dd09e8105d63ff7e0872
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 140618b212e3aa9ff2df20f22af846a1c4c5ffaeefd84330446f61362b39a8f1
-R ecfc68999ba200e5f9d0ce8c6a78fe70
+P da1d3151a440567f34a2f6c0b2bfc2e9fab81c256cc361c9ce7b46f2c23a2aa8
+R ff53072845ce3be319c8a5687950f355
U stephan
-Z ec8563cad502dab169a1c4538eaf6ec1
+Z 0ce9f393ac2f284b021257ae10338830
# Remove this line to create a well-formed Fossil manifest.
-da1d3151a440567f34a2f6c0b2bfc2e9fab81c256cc361c9ce7b46f2c23a2aa8
\ No newline at end of file
+778062e3b415dca5104eee398950741b6dbb9d4bdf7c998eef18371a42669946
\ No newline at end of file