Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Strip progress handlers and window functions from the wasm bare-bones (formerly 'minimal') JS bits, noting that we can't yet use OMIT_WINDOWFUNC (for the C parts) without a custom amalgamation. Currently at 604kb. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | wasm-build-rework |
Files: | files | file ages | folders |
SHA3-256: |
ec02e9237e1ef81c4196fa630822cb10 |
User & Date: | stephan 2024-07-25 16:21:19.087 |
Context
2024-07-25
| ||
16:28 | Fix a non-bare-bones-mode test case broken by the previous checkin. (check-in: 3be729493b user: stephan tags: wasm-build-rework) | |
16:21 | Strip progress handlers and window functions from the wasm bare-bones (formerly 'minimal') JS bits, noting that we can't yet use OMIT_WINDOWFUNC (for the C parts) without a custom amalgamation. Currently at 604kb. (check-in: ec02e9237e user: stephan tags: wasm-build-rework) | |
14:00 | More work on the minimal-mode wasm build (now 603kb uncompressed). Remove the hard-coded feature-enable flags from sqlite3-wasm.c and rely on the build to provide them. Some wasm build cleanup, but attempts to completely overhaul it have been thwarted by my inability to make script-generated makefile code more legible/maintainable than the current eval spaghetti. (check-in: b029c40679 user: stephan tags: wasm-build-rework) | |
Changes
Changes to ext/wasm/GNUmakefile.
︙ | ︙ | |||
153 154 155 156 157 158 159 | $(sqlite3.c): $(sqlite3.h) ######################################################################## # .gen.make is generated by a shell script and holds certain parts # of the makefile, some of which are relatively expensive to calculate # on each run (that is, they can take a human-visible amount of time). # | | | > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > | > | | > > > | | | > > > | < > > > > > > > > > > | | > | > | > > > > | | | | > | | < > | | | | | > | < < < | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | $(sqlite3.c): $(sqlite3.h) ######################################################################## # .gen.make is generated by a shell script and holds certain parts # of the makefile, some of which are relatively expensive to calculate # on each run (that is, they can take a human-visible amount of time). # # Sidebar: three attempts have been made to move much of the # $(eval)-generated makefile code into make-make.sh but the result is # even less legible/maintainable than make-side $(eval). ifeq (0,$(MAKING_CLEAN)) .gen.make: $(MAKEFILE) $(sqlite3.c) rm -f $@ $(SHELL) make-make.sh $(sqlite3.c) > $@ chmod -w $@ -include .gen.make endif ifeq (,$(filter release snapshot,$(MAKECMDGOALS))) $(info Development build. Use 'release' or 'snapshot' target for a smaller release build.) endif ######################################################################## # minimal=1 disables all "extraneous" stuff from sqlite3-wasm.c, the # goal being to create a WASM file with only the core APIs. ifeq (1,$(minimal)) wasm-bare-bones := 1 else wasm-bare-bones := 0 endif undefine minimal # Common options for building sqlite3-wasm.c and speedtest1.c. # Explicit ENABLEs... SQLITE_OPT.common := \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_TEMP_STORE=2 \ -DSQLITE_ENABLE_MATH_FUNCTIONS \ -DSQLITE_OS_KV_OPTIONAL=1 \ '-DSQLITE_DEFAULT_UNIX_VFS="unix-none"' \ -DSQLITE_USE_URI=1 \ -DSQLITE_C=$(sqlite3.c) \ -DSQLITE_OMIT_DEPRECATED \ -DSQLITE_OMIT_UTF16 \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_OMIT_SHARED_CACHE # ^^^ These particular OMITs are hard-coded in sqlite3-wasm.c and # removing them from this list will serve only to break the speedtest1 # builds. # Currently always needed but TODO is paring tester1.c-pp.js down # to be able to run without this: SQLITE_OPT.common += -DSQLITE_WASM_ENABLE_C_TESTS SQLITE_OPT.full-featured := \ -DSQLITE_ENABLE_BYTECODE_VTAB \ -DSQLITE_ENABLE_DBPAGE_VTAB \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_FTS5 \ -DSQLITE_ENABLE_MATH_FUNCTIONS \ -DSQLITE_ENABLE_OFFSET_SQL_FUNC \ -DSQLITE_ENABLE_PREUPDATE_HOOK \ -DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_SESSION \ -DSQLITE_ENABLE_STMTVTAB \ -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION ifeq (0,$(wasm-bare-bones)) # The so-called canonical build is full-featured: SQLITE_OPT := \ $(SQLITE_OPT.common) \ $(SQLITE_OPT.full-featured) else # The so-called bare-bones build is exactly that: SQLITE_OPT := \ $(SQLITE_OPT.common) \ -DSQLITE_WASM_BARE_BONES # SQLITE_WASM_BARE_BONES tells sqlite3-wasm.c to explicitly omit # a bunch of stuff, in the interest of keeping the wasm file size # down. As of this writing it equates to: # # -USQLITE_ENABLE_DBPAGE_VTAB # -USQLITE_ENABLE_DBSTAT_VTAB # -USQLITE_ENABLE_EXPLAIN_COMMENTS # -USQLITE_ENABLE_FTS5 # -USQLITE_ENABLE_OFFSET_SQL_FUNC # -USQLITE_ENABLE_PREUPDATE_HOOK # -USQLITE_ENABLE_RTREE # -USQLITE_ENABLE_SESSION # -USQLITE_ENABLE_STMTVTAB # -DSQLITE_OMIT_AUTHORIZATION # -DSQLITE_OMIT_GET_TABLE # -DSQLITE_OMIT_INCRBLOB # -DSQLITE_OMIT_INTROSPECTION_PRAGMAS # -DSQLITE_OMIT_JSON # -DSQLITE_OMIT_PROGRESS_CALLBACK # -DSQLITE_OMIT_WAL # # There are others we want here but which require explicit OMIT when # creating their amalgamation, and that step is TODO: # # -DSQLITE_OMIT_EXPLAIN # -DSQLITE_OMIT_TRIGGER # -DSQLITE_OMIT_VIRTUALTABLE # -DSQLITE_OMIT_WINDOWFUNC endif #SQLITE_OPT += -DSQLITE_DEBUG # Enabling SQLITE_DEBUG will break sqlite3_wasm_vfs_create_file() # (and thus sqlite3_js_vfs_create_file()). Those functions are # deprecated and alternatives are in place, but this crash behavior # can be used to find errant uses of sqlite3_js_vfs_create_file() # in client code. ######################################################################## # The following flags are hard-coded into sqlite3-wasm.c and cannot be # modified via the build process: # # SQLITE_ENABLE_API_ARMOR # SQLITE_OMIT_LOAD_EXTENSION # SQLITE_OMIT_DEPRECATED # SQLITE_OMIT_UTF16 # SQLITE_OMIT_SHARED_CACHE ######################################################################## ######################################################################## # Adding custom C code via sqlite3_wasm_extra_init.c: # # If the canonical build process finds the file # sqlite3_wasm_extra_init.c in the main wasm build directory, it # arranges to include that file in the build of sqlite3.wasm and |
︙ | ︙ | |||
381 382 383 384 385 386 387 | # EXPORTED_FUNCTIONS.* = files for use with Emscripten's # -sEXPORTED_FUNCTION flag. EXPORTED_FUNCTIONS.api.core := $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core EXPORTED_FUNCTIONS.api.in := $(EXPORTED_FUNCTIONS.api.core) ifeq (1,$(SQLITE_C_IS_SEE)) EXPORTED_FUNCTIONS.api.in += $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-see endif | | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | # EXPORTED_FUNCTIONS.* = files for use with Emscripten's # -sEXPORTED_FUNCTION flag. EXPORTED_FUNCTIONS.api.core := $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core EXPORTED_FUNCTIONS.api.in := $(EXPORTED_FUNCTIONS.api.core) ifeq (1,$(SQLITE_C_IS_SEE)) EXPORTED_FUNCTIONS.api.in += $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-see endif ifeq (0,$(wasm-bare-bones)) EXPORTED_FUNCTIONS.api.in += $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-extras else $(info ========================================) $(info This is a minimal-mode build. It is missing many features.) $(info ========================================) endif EXPORTED_FUNCTIONS.api := $(dir.tmp)/EXPORTED_FUNCTIONS.api |
︙ | ︙ | |||
421 422 423 424 425 426 427 | sqlite3-api.jses += $(sqlite3-api-build-version.js) # sqlite3-api-oo1 = the oo1 API: sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.c-pp.js # sqlite3-api-worker = the Worker1 API: sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.c-pp.js # sqlite3-vfs-helper = helper APIs for VFSes: sqlite3-api.jses += $(dir.api)/sqlite3-vfs-helper.c-pp.js | | | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | sqlite3-api.jses += $(sqlite3-api-build-version.js) # sqlite3-api-oo1 = the oo1 API: sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.c-pp.js # sqlite3-api-worker = the Worker1 API: sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.c-pp.js # sqlite3-vfs-helper = helper APIs for VFSes: sqlite3-api.jses += $(dir.api)/sqlite3-vfs-helper.c-pp.js ifeq (0,$(wasm-bare-bones)) # sqlite3-vtab-helper = helper APIs for VTABLEs: sqlite3-api.jses += $(dir.api)/sqlite3-vtab-helper.c-pp.js endif # sqlite3-vfs-opfs = the first OPFS VFS: sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js # sqlite3-vfs-opfs-sahpool = the second OPFS VFS: sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js |
︙ | ︙ | |||
1049 1050 1051 1052 1053 1054 1055 | $(EXPORTED_FUNCTIONS.speedtest1) @echo "Building $@ ..." $(emcc.bin) \ $(emcc.speedtest1) \ $(emcc.speedtest1.common) \ $(emcc.flags.speedtest1-vanilla) $(pre-post-speedtest1-vanilla.flags) \ $(SQLITE_OPT) \ | | | 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 | $(EXPORTED_FUNCTIONS.speedtest1) @echo "Building $@ ..." $(emcc.bin) \ $(emcc.speedtest1) \ $(emcc.speedtest1.common) \ $(emcc.flags.speedtest1-vanilla) $(pre-post-speedtest1-vanilla.flags) \ $(SQLITE_OPT) \ -USQLITE_WASM_BARE_BONES \ -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c) \ $(speedtest1.exit-runtime0) \ -o $@ $(speedtest1.cfiles) -lm $(maybe-wasm-strip) $(speedtest1.wasm) chmod -x $(speedtest1.wasm) ls -la $@ $(speedtest1.wasm) |
︙ | ︙ |
Changes to ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-core.
︙ | ︙ | |||
37 38 39 40 41 42 43 | _sqlite3_compileoption_used _sqlite3_complete _sqlite3_context_db_handle _sqlite3_create_collation _sqlite3_create_collation_v2 _sqlite3_create_function _sqlite3_create_function_v2 | < | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | _sqlite3_compileoption_used _sqlite3_complete _sqlite3_context_db_handle _sqlite3_create_collation _sqlite3_create_collation_v2 _sqlite3_create_function _sqlite3_create_function_v2 _sqlite3_data_count _sqlite3_db_filename _sqlite3_db_handle _sqlite3_db_name _sqlite3_db_readonly _sqlite3_db_status _sqlite3_deserialize |
︙ | ︙ | |||
76 77 78 79 80 81 82 | _sqlite3_malloc64 _sqlite3_msize _sqlite3_open _sqlite3_open_v2 _sqlite3_overload_function _sqlite3_prepare_v2 _sqlite3_prepare_v3 | < | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | _sqlite3_malloc64 _sqlite3_msize _sqlite3_open _sqlite3_open_v2 _sqlite3_overload_function _sqlite3_prepare_v2 _sqlite3_prepare_v3 _sqlite3_randomness _sqlite3_realloc _sqlite3_realloc64 _sqlite3_reset _sqlite3_reset_auto_extension _sqlite3_result_blob _sqlite3_result_double |
︙ | ︙ |
Changes to ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras.
1 2 3 4 5 6 7 | _sqlite3_set_authorizer _sqlite3_preupdate_blobwrite _sqlite3_preupdate_count _sqlite3_preupdate_depth _sqlite3_preupdate_hook _sqlite3_preupdate_new _sqlite3_preupdate_old | > > | 1 2 3 4 5 6 7 8 9 | _sqlite3_create_window_function _sqlite3_progress_handler _sqlite3_set_authorizer _sqlite3_preupdate_blobwrite _sqlite3_preupdate_count _sqlite3_preupdate_depth _sqlite3_preupdate_hook _sqlite3_preupdate_new _sqlite3_preupdate_old |
︙ | ︙ |
Changes to ext/wasm/api/sqlite3-api-glue.c-pp.js.
︙ | ︙ | |||
132 133 134 135 136 137 138 | }), '*' ]], ["sqlite3_compileoption_get", "string", "int"], ["sqlite3_compileoption_used", "int", "string"], ["sqlite3_complete", "int", "string:flexible"], ["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"], | | > > < < < < < < < < < < | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | }), '*' ]], ["sqlite3_compileoption_get", "string", "int"], ["sqlite3_compileoption_used", "int", "string"], ["sqlite3_complete", "int", "string:flexible"], ["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"], /* sqlite3_create_collation() and sqlite3_create_collation_v2() use hand-written bindings to simplify passing of the callback function. */ /* sqlite3_create_function(), sqlite3_create_function_v2(), and sqlite3_create_window_function() use hand-written bindings to simplify handling of their function-type arguments. */ ["sqlite3_data_count", "int", "sqlite3_stmt*"], ["sqlite3_db_filename", "string", "sqlite3*", "string"], ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"], ["sqlite3_db_name", "string", "sqlite3*", "int"], ["sqlite3_db_readonly", "int", "sqlite3*", "string"], ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"], ["sqlite3_errcode", "int", "sqlite3*"], |
︙ | ︙ | |||
207 208 209 210 211 212 213 | ["sqlite3_open", "int", "string", "*"], ["sqlite3_open_v2", "int", "string", "*", "int", "string"], /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled separately due to us requiring two different sets of semantics for those, depending on how their SQL argument is provided. */ /* sqlite3_randomness() uses a hand-written wrapper to extend the range of supported argument types. */ | < < < < < < < < | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | ["sqlite3_open", "int", "string", "*"], ["sqlite3_open_v2", "int", "string", "*", "int", "string"], /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled separately due to us requiring two different sets of semantics for those, depending on how their SQL argument is provided. */ /* sqlite3_randomness() uses a hand-written wrapper to extend the range of supported argument types. */ ["sqlite3_realloc", "*","*","int"], ["sqlite3_reset", "int", "sqlite3_stmt*"], /* sqlite3_reset_auto_extension() has a hand-written binding. */ ["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"], ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"], ["sqlite3_result_error", undefined, "sqlite3_context*", "string", "int"], ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"], |
︙ | ︙ | |||
298 299 300 301 302 303 304 305 306 307 308 309 310 311 | ["sqlite3_value_subtype", "int", "sqlite3_value*"], ["sqlite3_value_text", "string", "sqlite3_value*"], ["sqlite3_value_type", "int", "sqlite3_value*"], ["sqlite3_vfs_find", "*", "string"], ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"] ]/*wasm.bindingSignatures*/; if( !!wasm.exports.sqlite3_stmt_explain ){ wasm.bindingSignatures.push( ["sqlite3_stmt_explain", "int", "sqlite3_stmt*", "int"], ["sqlite3_stmt_isexplain", "int", "sqlite3_stmt*"] ); } | > > > > > > > > > > > > > | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | ["sqlite3_value_subtype", "int", "sqlite3_value*"], ["sqlite3_value_text", "string", "sqlite3_value*"], ["sqlite3_value_type", "int", "sqlite3_value*"], ["sqlite3_vfs_find", "*", "string"], ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"] ]/*wasm.bindingSignatures*/; if( !!wasm.exports.sqlite3_progress_handler ){ wasm.bindingSignatures.push( ["sqlite3_progress_handler", undefined, [ "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({ name: 'xProgressHandler', signature: 'i(p)', bindScope: 'context', contextKey: (argv,argIndex)=>argv[0/* sqlite3* */] }), "*" ]] ); } if( !!wasm.exports.sqlite3_stmt_explain ){ wasm.bindingSignatures.push( ["sqlite3_stmt_explain", "int", "sqlite3_stmt*", "int"], ["sqlite3_stmt_isexplain", "int", "sqlite3_stmt*"] ); } |
︙ | ︙ | |||
946 947 948 949 950 951 952 | return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_MISUSE, f+"() requires "+n+" argument"+ (1===n?"":'s')+"."); }; /** Code duplication reducer for functions which take an encoding argument and require SQLITE_UTF8. Sets the db error code to | > | | 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 | return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_MISUSE, f+"() requires "+n+" argument"+ (1===n?"":'s')+"."); }; /** Code duplication reducer for functions which take an encoding argument and require SQLITE_UTF8. Sets the db error code to SQLITE_FORMAT, installs a descriptive error message, and returns SQLITE_FORMAT. */ const __errEncoding = (pDb)=>{ return util.sqlite3__wasm_db_error( pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding." ); }; /** |
︙ | ︙ | |||
996 997 998 999 1000 1001 1002 | __dbCleanupMap.addFunction = function(pDb, name, arity){ const m = __dbCleanupMap(pDb, 1); if(!m.udf) m.udf = new Map; this._addUDF(pDb, name, arity, m.udf); }; | > | | | | | > | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 | __dbCleanupMap.addFunction = function(pDb, name, arity){ const m = __dbCleanupMap(pDb, 1); if(!m.udf) m.udf = new Map; this._addUDF(pDb, name, arity, m.udf); }; if( wasm.exports.sqlite3_create_window_function ){ __dbCleanupMap.addWindowFunc = function(pDb, name, arity){ const m = __dbCleanupMap(pDb, 1); if(!m.wudf) m.wudf = new Map; this._addUDF(pDb, name, arity, m.wudf); }; } /** Intended to be called _only_ from sqlite3_close_v2(), passed its non-0 db argument. This function frees up certain automatically-installed WASM function bindings which were installed on behalf of the given db, |
︙ | ︙ | |||
1269 1270 1271 1272 1273 1274 1275 | new wasm.xWrap.FuncPtrAdapter({name: 'xFunc', ...__cfProxy.xFunc}), new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}), new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}), new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy}) ] ); | | > > | | | | | | | | | < > > | 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 | new wasm.xWrap.FuncPtrAdapter({name: 'xFunc', ...__cfProxy.xFunc}), new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}), new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}), new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy}) ] ); const __sqlite3CreateWindowFunction = wasm.exports.sqlite3_create_window_function ? wasm.xWrap( "sqlite3_create_window_function", "int", [ "sqlite3*", "string"/*funcName*/, "int"/*nArg*/, "int"/*eTextRep*/, "*"/*pApp*/, new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}), new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}), new wasm.xWrap.FuncPtrAdapter({name: 'xValue', ...__cfProxy.xFinalAndValue}), new wasm.xWrap.FuncPtrAdapter({name: 'xInverse', ...__cfProxy.xInverseAndStep}), new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy}) ] ) : undefined; /* Documented in the api object's initializer. */ capi.sqlite3_create_function_v2 = function f( pDb, funcName, nArg, eTextRep, pApp, xFunc, //void (*xFunc)(sqlite3_context*,int,sqlite3_value**) xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**) xFinal, //void (*xFinal)(sqlite3_context*) |
︙ | ︙ | |||
1324 1325 1326 1327 1328 1329 1330 | return (f.length===arguments.length) ? capi.sqlite3_create_function_v2(pDb, funcName, nArg, eTextRep, pApp, xFunc, xStep, xFinal, 0) : __dbArgcMismatch(pDb,"sqlite3_create_function",f.length); }; /* Documented in the api object's initializer. */ | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > | > > | > > | > > | 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 | return (f.length===arguments.length) ? capi.sqlite3_create_function_v2(pDb, funcName, nArg, eTextRep, pApp, xFunc, xStep, xFinal, 0) : __dbArgcMismatch(pDb,"sqlite3_create_function",f.length); }; /* Documented in the api object's initializer. */ if( __sqlite3CreateWindowFunction ){ capi.sqlite3_create_window_function = function f( pDb, funcName, nArg, eTextRep, pApp, xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**) xFinal, //void (*xFinal)(sqlite3_context*) xValue, //void (*xValue)(sqlite3_context*) xInverse,//void (*xInverse)(sqlite3_context*,int,sqlite3_value**) xDestroy //void (*xDestroy)(void*) ){ if( f.length!==arguments.length ){ return __dbArgcMismatch(pDb,"sqlite3_create_window_function",f.length); }else if( 0 === (eTextRep & 0xf) ){ eTextRep |= capi.SQLITE_UTF8; }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){ return __errEncoding(pDb); } try{ const rc = __sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep, pApp, xStep, xFinal, xValue, xInverse, xDestroy); if(0===rc && (xStep instanceof Function || xFinal instanceof Function || xValue instanceof Function || xInverse instanceof Function || xDestroy instanceof Function)){ __dbCleanupMap.addWindowFunc(pDb, funcName, nArg); } return rc; }catch(e){ console.error("sqlite3_create_window_function() setup threw:",e); return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e); } }; }else{ delete capi.sqlite3_create_window_function; } /** A _deprecated_ alias for capi.sqlite3_result_js() which predates the addition of that function in the public API. */ capi.sqlite3_create_function_v2.udfSetResult = capi.sqlite3_create_function.udfSetResult = capi.sqlite3_result_js; if(capi.sqlite3_create_window_function){ capi.sqlite3_create_window_function.udfSetResult = capi.sqlite3_result_js; } /** A _deprecated_ alias for capi.sqlite3_values_to_js() which predates the addition of that function in the public API. */ capi.sqlite3_create_function_v2.udfConvertArgs = capi.sqlite3_create_function.udfConvertArgs = capi.sqlite3_values_to_js; if(capi.sqlite3_create_window_function){ capi.sqlite3_create_window_function.udfConvertArgs = capi.sqlite3_values_to_js; } /** A _deprecated_ alias for capi.sqlite3_result_error_js() which predates the addition of that function in the public API. */ capi.sqlite3_create_function_v2.udfSetError = capi.sqlite3_create_function.udfSetError = capi.sqlite3_result_error_js; if(capi.sqlite3_create_window_function){ capi.sqlite3_create_window_function.udfSetError = capi.sqlite3_result_error_js; } }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/; {/* Special-case handling of sqlite3_prepare_v2() and sqlite3_prepare_v3() */ /** |
︙ | ︙ |
Changes to ext/wasm/api/sqlite3-wasm.c.
︙ | ︙ | |||
91 92 93 94 95 96 97 | ** or ranges which might otherwise invoke undefined behavior. */ #undef SQLITE_ENABLE_API_ARMOR #define SQLITE_ENABLE_API_ARMOR 1 /**********************************************************************/ /* SQLITE_O... */ | | | < | | < | | < | | < | | < | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | ** or ranges which might otherwise invoke undefined behavior. */ #undef SQLITE_ENABLE_API_ARMOR #define SQLITE_ENABLE_API_ARMOR 1 /**********************************************************************/ /* SQLITE_O... */ #undef SQLITE_OMIT_DEPRECATED #define SQLITE_OMIT_DEPRECATED 1 #undef SQLITE_OMIT_LOAD_EXTENSION #define SQLITE_OMIT_LOAD_EXTENSION 1 #undef SQLITE_OMIT_SHARED_CACHE #define SQLITE_OMIT_SHARED_CACHE 1 #undef SQLITE_OMIT_UTF16 #define SQLITE_OMIT_UTF16 1 #undef SQLITE_OS_KV_OPTIONAL #define SQLITE_OS_KV_OPTIONAL 1 /**********************************************************************/ /* SQLITE_S... */ #ifndef SQLITE_STRICT_SUBTYPE # define SQLITE_STRICT_SUBTYPE 1 #endif |
︙ | ︙ | |||
133 134 135 136 137 138 139 | #endif #ifdef SQLITE_WASM_EXTRA_INIT # define SQLITE_EXTRA_INIT sqlite3_wasm_extra_init #endif /* | | | | | | | | | | | | | | | | | | < > | | > | < < | | | > | > > > > > > > | > > | | | | > > > > | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | #endif #ifdef SQLITE_WASM_EXTRA_INIT # define SQLITE_EXTRA_INIT sqlite3_wasm_extra_init #endif /* ** If SQLITE_WASM_BARE_BONES is defined, undefine most of the ENABLE ** macros. */ #ifdef SQLITE_WASM_BARE_BONES # undef SQLITE_ENABLE_DBPAGE_VTAB # undef SQLITE_ENABLE_DBSTAT_VTAB # undef SQLITE_ENABLE_EXPLAIN_COMMENTS # undef SQLITE_ENABLE_FTS5 # undef SQLITE_ENABLE_OFFSET_SQL_FUNC # undef SQLITE_ENABLE_PREUPDATE_HOOK # undef SQLITE_ENABLE_RTREE # undef SQLITE_ENABLE_SESSION # undef SQLITE_ENABLE_STMTVTAB # undef SQLITE_OMIT_AUTHORIZATION # define SQLITE_OMIT_AUTHORIZATION # undef SQLITE_OMIT_GET_TABLE # define SQLITE_OMIT_GET_TABLE # undef SQLITE_OMIT_INCRBLOB # define SQLITE_OMIT_INCRBLOB # undef SQLITE_OMIT_INTROSPECTION_PRAGMAS # define SQLITE_OMIT_INTROSPECTION_PRAGMAS # undef SQLITE_OMIT_JSON # define SQLITE_OMIT_JSON # undef SQLITE_OMIT_PROGRESS_CALLBACK # define SQLITE_OMIT_PROGRESS_CALLBACK # undef SQLITE_OMIT_WAL # define SQLITE_OMIT_WAL /* The following OMITs do not work with the standard amalgamation, so require a custom build: fossil clean -x ./configure OPTS='...' make -e sqlite3 where ... has a -D... for each of the following OMIT flags: # undef SQLITE_OMIT_EXPLAIN # define SQLITE_OMIT_EXPLAIN # undef SQLITE_OMIT_TRIGGER # define SQLITE_OMIT_TRIGGER # undef SQLITE_OMIT_VIRTUALTABLE # define SQLITE_OMIT_VIRTUALTABLE # undef SQLITE_OMIT_WINDOWFUNC # define SQLITE_OMIT_WINDOWFUNC As of this writing (2024-07-25), such a build fails in various ways for as-yet-unknown reasons. */ #endif #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_WASM_BARE_BONES) # define SQLITE_WASM_HAS_VTAB 1 #else # define SQLITE_WASM_HAS_VTAB 0 #endif #include <assert.h> |
︙ | ︙ | |||
230 231 232 233 234 235 236 | #define INC__STRINGIFY_(f) #f #define INC__STRINGIFY(f) INC__STRINGIFY_(f) #include INC__STRINGIFY(SQLITE_C) #undef INC__STRINGIFY_ #undef INC__STRINGIFY #undef SQLITE_C | < < < < | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | #define INC__STRINGIFY_(f) #f #define INC__STRINGIFY(f) INC__STRINGIFY_(f) #include INC__STRINGIFY(SQLITE_C) #undef INC__STRINGIFY_ #undef INC__STRINGIFY #undef SQLITE_C #if 0 /* ** An EXPERIMENT in implementing a stack-based allocator analog to ** Emscripten's stackSave(), stackAlloc(), stackRestore(). ** Unfortunately, this cannot work together with Emscripten because ** Emscripten defines its own native one and we'd stomp on each ** other's memory. Other than that complication, basic tests show it |
︙ | ︙ | |||
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 | ? sqlite3_mprintf("%Q", z) : sqlite3_mprintf("%q", z); } return rc; } #if defined(__EMSCRIPTEN__) && defined(SQLITE_ENABLE_WASMFS) #include <emscripten/wasmfs.h> /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings, specifically ** only when building with Emscripten's WASMFS support. ** | > | 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 | ? sqlite3_mprintf("%Q", z) : sqlite3_mprintf("%q", z); } return rc; } #if defined(__EMSCRIPTEN__) && defined(SQLITE_ENABLE_WASMFS) #include <emscripten/console.h> #include <emscripten/wasmfs.h> /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings, specifically ** only when building with Emscripten's WASMFS support. ** |
︙ | ︙ | |||
1937 1938 1939 1940 1941 1942 1943 | return !sqlite3__wasm_SQLTester_strnotglob(zGlob, z); } #endif /* SQLITE_WASM_ENABLE_C_TESTS */ #undef SQLITE_WASM_EXPORT #undef SQLITE_WASM_HAS_VTAB | | | 1942 1943 1944 1945 1946 1947 1948 1949 1950 | return !sqlite3__wasm_SQLTester_strnotglob(zGlob, z); } #endif /* SQLITE_WASM_ENABLE_C_TESTS */ #undef SQLITE_WASM_EXPORT #undef SQLITE_WASM_HAS_VTAB #undef SQLITE_WASM_BARE_BONES #undef SQLITE_WASM_ENABLE_C_TESTS |
Changes to ext/wasm/fiddle.make.
︙ | ︙ | |||
37 38 39 40 41 42 43 | -sDYNAMIC_EXECUTION=0 \ -sWASM_BIGINT=$(emcc.WASM_BIGINT) \ -sEXPORT_NAME=$(sqlite3.js.init-func) \ -Wno-limited-postlink-optimizations \ $(emcc.exportedRuntimeMethods) \ -sEXPORTED_FUNCTIONS=@$(abspath $(EXPORTED_FUNCTIONS.fiddle)) \ -sEXPORTED_RUNTIME_METHODS=FS,wasmMemory \ | > | > | < | > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | -sDYNAMIC_EXECUTION=0 \ -sWASM_BIGINT=$(emcc.WASM_BIGINT) \ -sEXPORT_NAME=$(sqlite3.js.init-func) \ -Wno-limited-postlink-optimizations \ $(emcc.exportedRuntimeMethods) \ -sEXPORTED_FUNCTIONS=@$(abspath $(EXPORTED_FUNCTIONS.fiddle)) \ -sEXPORTED_RUNTIME_METHODS=FS,wasmMemory \ $(SQLITE_OPT.full-featured) \ $(SQLITE_OPT.common) \ $(SHELL_OPT) \ -USQLITE_WASM_BARE_BONES \ -DSQLITE_SHELL_FIDDLE # Flags specifically for debug builds of fiddle. Performance suffers # greatly in debug builds. fiddle.emcc-flags.debug := $(fiddle.emcc-flags) \ -DSQLITE_DEBUG \ -DSQLITE_ENABLE_SELECTTRACE \ -DSQLITE_ENABLE_WHERETRACE fiddle.EXPORTED_FUNCTIONS.in := \ EXPORTED_FUNCTIONS.fiddle.in \ $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core \ $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-extras $(EXPORTED_FUNCTIONS.fiddle): $(fiddle.EXPORTED_FUNCTIONS.in) $(MAKEFILE.fiddle) sort -u $(fiddle.EXPORTED_FUNCTIONS.in) > $@ fiddle.cses := $(dir.top)/shell.c $(sqlite3-wasm.c) $(eval $(call call-make-pre-post,fiddle-module,vanilla)) |
︙ | ︙ |
Changes to ext/wasm/tester1.c-pp.js.
︙ | ︙ | |||
844 845 846 847 848 849 850 | }); } } }/*xWrap()*/ }/*WhWasmUtil*/) //////////////////////////////////////////////////////////////////// | > | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | }); } } }/*xWrap()*/ }/*WhWasmUtil*/) //////////////////////////////////////////////////////////////////// .t({ name: 'sqlite3.StructBinder (jaccwabyt🐇)', predicate: (sqlite3)=>!!sqlite3.wasm.exports.sqlite3__wasm_test_struct || "Built without SQLITE_WASM_ENABLE_C_TESTS", test: function(sqlite3){ const S = sqlite3, W = S.wasm; const MyStructDef = { sizeof: 16, members: { p4: {offset: 0, sizeof: 4, signature: "i"}, pP: {offset: 4, sizeof: 4, signature: "P"}, ro: {offset: 8, sizeof: 4, signature: "i", readOnly: true}, cstr: {offset: 12, sizeof: 4, signature: "s"} } }; if(W.bigIntEnabled){ const m = MyStructDef; m.members.p8 = {offset: m.sizeof, sizeof: 8, signature: "j"}; m.sizeof += m.members.p8.sizeof; } const StructType = S.StructBinder.StructType; const K = S.StructBinder('my_struct',MyStructDef); T.mustThrowMatching(()=>K(), /via 'new'/). mustThrowMatching(()=>new K('hi'), /^Invalid pointer/); const k1 = new K(), k2 = new K(); try { T.assert(k1.constructor === K). assert(K.isA(k1)). assert(k1 instanceof K). assert(K.prototype.lookupMember('p4').key === '$p4'). assert(K.prototype.lookupMember('$p4').name === 'p4'). mustThrowMatching(()=>K.prototype.lookupMember('nope'), /not a mapped/). assert(undefined === K.prototype.lookupMember('nope',false)). assert(k1 instanceof StructType). assert(StructType.isA(k1)). mustThrowMatching(()=>k1.$ro = 1, /read-only/); Object.keys(MyStructDef.members).forEach(function(key){ key = K.memberKey(key); T.assert(0 == k1[key], "Expecting allocation to zero the memory "+ "for "+key+" but got: "+k1[key]+ " from "+k1.memoryDump()); }); T.assert('number' === typeof k1.pointer). mustThrowMatching(()=>k1.pointer = 1, /pointer/); k1.$p4 = 1; k1.$pP = 2; T.assert(1 === k1.$p4).assert(2 === k1.$pP); if(MyStructDef.members.$p8){ k1.$p8 = 1/*must not throw despite not being a BigInt*/; k1.$p8 = BigInt(Number.MAX_SAFE_INTEGER * 2); T.assert(BigInt(2 * Number.MAX_SAFE_INTEGER) === k1.$p8); } T.assert(!k1.ondispose); k1.setMemberCString('cstr', "A C-string."); T.assert(Array.isArray(k1.ondispose)). assert(k1.ondispose[0] === k1.$cstr). assert('number' === typeof k1.$cstr). assert('A C-string.' === k1.memberToJsString('cstr')); k1.$pP = k2; T.assert(k1.$pP === k2.pointer); k1.$pP = null/*null is special-cased to 0.*/; T.assert(0===k1.$pP); let ptr = k1.pointer; k1.dispose(); T.assert(undefined === k1.pointer). mustThrowMatching(()=>{k1.$pP=1}, /disposed instance/); }finally{ k1.dispose(); k2.dispose(); } if(!W.bigIntEnabled){ log("Skipping WasmTestStruct tests: BigInt not enabled."); return; } const WTStructDesc = W.ctype.structs.filter((e)=>'WasmTestStruct'===e.name)[0]; const autoResolvePtr = true /* EXPERIMENTAL */; if(autoResolvePtr){ WTStructDesc.members.ppV.signature = 'P'; } const WTStruct = S.StructBinder(WTStructDesc); //log(WTStruct.structName, WTStruct.structInfo); const wts = new WTStruct(); //log("WTStruct.prototype keys:",Object.keys(WTStruct.prototype)); try{ T.assert(wts.constructor === WTStruct). assert(WTStruct.memberKeys().indexOf('$ppV')>=0). assert(wts.memberKeys().indexOf('$v8')>=0). assert(!K.isA(wts)). assert(WTStruct.isA(wts)). assert(wts instanceof WTStruct). assert(wts instanceof StructType). assert(StructType.isA(wts)). assert(wts.pointer>0).assert(0===wts.$v4).assert(0n===wts.$v8). assert(0===wts.$ppV).assert(0===wts.$xFunc); const testFunc = W.xGet('sqlite3__wasm_test_struct'/*name gets mangled in -O3 builds!*/); let counter = 0; //log("wts.pointer =",wts.pointer); const wtsFunc = function(arg){ /*log("This from a JS function called from C, "+ "which itself was called from JS. arg =",arg);*/ ++counter; if(3===counter){ tossQuietly("Testing exception propagation."); } } wts.$v4 = 10; wts.$v8 = 20; wts.$xFunc = W.installFunction(wtsFunc, wts.memberSignature('xFunc')) T.assert(0===counter).assert(10 === wts.$v4).assert(20n === wts.$v8) .assert(0 === wts.$ppV).assert('number' === typeof wts.$xFunc) .assert(0 === wts.$cstr) .assert(wts.memberIsString('$cstr')) .assert(!wts.memberIsString('$v4')) .assert(null === wts.memberToJsString('$cstr')) .assert(W.functionEntry(wts.$xFunc) instanceof Function); /* It might seem silly to assert that the values match what we just set, but recall that all of those property reads and writes are, via property interceptors, actually marshaling their data to/from a raw memory buffer, so merely reading them back is actually part of testing the struct-wrapping API. */ testFunc(wts.pointer); //log("wts.pointer, wts.$ppV",wts.pointer, wts.$ppV); T.assert(1===counter).assert(20 === wts.$v4).assert(40n === wts.$v8) .assert(wts.$ppV === wts.pointer) .assert('string' === typeof wts.memberToJsString('cstr')) .assert(wts.memberToJsString('cstr') === wts.memberToJsString('$cstr')) .mustThrowMatching(()=>wts.memberToJsString('xFunc'), /Invalid member type signature for C-string/) ; testFunc(wts.pointer); T.assert(2===counter).assert(40 === wts.$v4).assert(80n === wts.$v8) .assert(wts.$ppV === wts.pointer); /** The 3rd call to wtsFunc throw from JS, which is called from C, which is called from JS. Let's ensure that that exception propagates back here... */ T.mustThrowMatching(()=>testFunc(wts.pointer),/^Testing/); W.uninstallFunction(wts.$xFunc); wts.$xFunc = 0; wts.$ppV = 0; T.assert(!wts.$ppV); //WTStruct.debugFlags(0x03); wts.$ppV = wts; T.assert(wts.pointer === wts.$ppV) wts.setMemberCString('cstr', "A C-string."); T.assert(Array.isArray(wts.ondispose)). assert(wts.ondispose[0] === wts.$cstr). assert('A C-string.' === wts.memberToJsString('cstr')); const ptr = wts.pointer; wts.dispose(); T.assert(ptr).assert(undefined === wts.pointer); }finally{ wts.dispose(); } if(1){ // ondispose of other struct instances const s1 = new WTStruct, s2 = new WTStruct, s3 = new WTStruct; T.assert(s1.lookupMember instanceof Function) .assert(s1.addOnDispose instanceof Function); s1.addOnDispose(s2,"testing variadic args"); T.assert(2===s1.ondispose.length); s2.addOnDispose(s3); s1.dispose(); T.assert(!s2.pointer,"Expecting s2 to be ondispose'd by s1."); T.assert(!s3.pointer,"Expecting s3 to be ondispose'd by s2."); } } }/*StructBinder*/) //////////////////////////////////////////////////////////////////// .t('sqlite3.wasm.pstack', function(sqlite3){ const P = wasm.pstack; const isAllocErr = (e)=>e instanceof sqlite3.WasmAllocError; |
︙ | ︙ | |||
1122 1123 1124 1125 1126 1127 1128 | T.assert(t0 === capi.sqlite3_randomness(t0), "0-length array is a special case"); }) ;/*end sqlite3_randomness() checks*/ //////////////////////////////////////////////////////////////////////// T.g('sqlite3.oo1') | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > | | | | > > | 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 | T.assert(t0 === capi.sqlite3_randomness(t0), "0-length array is a special case"); }) ;/*end sqlite3_randomness() checks*/ //////////////////////////////////////////////////////////////////////// T.g('sqlite3.oo1') .t({ name:'Create db', //predicate: (sqlite3)=> test: function(sqlite3){ const dbFile = '/tester1.db'; sqlite3.util.sqlite3__wasm_vfs_unlink(0, dbFile); const db = this.db = new sqlite3.oo1.DB(dbFile, 0 ? 'ct' : 'c'); db.onclose = { disposeAfter: [], disposeBefore: [ (db)=>{ //console.debug("db.onclose.before dropping modules"); //sqlite3.capi.sqlite3_drop_modules(db.pointer, 0); } ], before: function(db){ while(this.disposeBefore.length){ const v = this.disposeBefore.shift(); console.debug("db.onclose.before cleaning up:",v); if(wasm.isPtr(v)) wasm.dealloc(v); else if(v instanceof sqlite3.StructBinder.StructType){ v.dispose(); }else if(v instanceof Function){ try{ v(db) } catch(e){ console.warn("beforeDispose() callback threw:",e); } } } }, after: function(){ while(this.disposeAfter.length){ const v = this.disposeAfter.shift(); console.debug("db.onclose.after cleaning up:",v); if(wasm.isPtr(v)) wasm.dealloc(v); else if(v instanceof sqlite3.StructBinder.StructType){ v.dispose(); }else if(v instanceof Function){ try{v()} catch(e){/*ignored*/} } } } }; T.assert(wasm.isPtr(db.pointer)) .mustThrowMatching(()=>db.pointer=1, /read-only/) .assert(0===sqlite3.capi.sqlite3_extended_result_codes(db.pointer,1)) .assert('main'===db.dbName(0)) .assert('string' === typeof db.dbVfsName()) .assert(db.pointer === wasm.xWrap.testConvertArg('sqlite3*',db)); // Custom db error message handling via sqlite3_prepare_v2/v3() let rc = capi.sqlite3_prepare_v3(db.pointer, {/*invalid*/}, -1, 0, null, null); T.assert(capi.SQLITE_MISUSE === rc) .assert(0 === capi.sqlite3_errmsg(db.pointer).indexOf("Invalid SQL")) .assert(dbFile === db.dbFilename()) .assert(!db.dbFilename('nope')); //Sanity check DB.checkRc()... let ex; try{db.checkRc(rc)} catch(e){ex = e} T.assert(ex instanceof sqlite3.SQLite3Error) .assert(capi.SQLITE_MISUSE===ex.resultCode) .assert(0===ex.message.indexOf("SQLITE_MISUSE: sqlite3 result code")) .assert(ex.message.indexOf("Invalid SQL")>0); T.assert(db === db.checkRc(0)) .assert(db === sqlite3.oo1.DB.checkRc(db,0)) .assert(null === sqlite3.oo1.DB.checkRc(null,0)); this.progressHandlerCount = 0; if( wasm.compileOptionUsed('OMIT_PROGRESS_CALLBACK') ){ T.assert( !capi.sqlite3_progress_handler ); }else{ T.assert( capi.sqlite3_progress_handler ); capi.sqlite3_progress_handler(db, 5, (p)=>{ ++this.progressHandlerCount; return 0; }, 0); } } }) //////////////////////////////////////////////////////////////////// .t('sqlite3_db_config() and sqlite3_db_status()', function(sqlite3){ let rc = capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, 0, 0); T.assert(0===rc); rc = capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_MAX+1, 0); T.assert(capi.SQLITE_MISUSE === rc); |
︙ | ︙ | |||
1232 1233 1234 1235 1236 1237 1238 | //////////////////////////////////////////////////////////////////// .t('DB.Stmt', function(sqlite3){ let st = this.db.prepare( new TextEncoder('utf-8').encode("select 3 as a") ); //debug("statement =",st); | | | 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 | //////////////////////////////////////////////////////////////////// .t('DB.Stmt', function(sqlite3){ let st = this.db.prepare( new TextEncoder('utf-8').encode("select 3 as a") ); //debug("statement =",st); T.assert( !this.progressHandlerCount ); let rc; try { T.assert(wasm.isPtr(st.pointer)) .mustThrowMatching(()=>st.pointer=1, /read-only/) .assert(1===this.db.openStatementCount()) .assert( capi.sqlite3_stmt_status( |
︙ | ︙ | |||
1274 1275 1276 1277 1278 1279 1280 | .assert(false===st.step()) .assert(!st._mayGet) .assert( capi.sqlite3_stmt_status( st, capi.SQLITE_STMTSTATUS_RUN, 0 ) > 0); | | > | 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 | .assert(false===st.step()) .assert(!st._mayGet) .assert( capi.sqlite3_stmt_status( st, capi.SQLITE_STMTSTATUS_RUN, 0 ) > 0); T.assert(this.progressHandlerCount>0 || wasm.compileOptionUsed('OMIT_PROGRESS_CALLBACK'), "Expecting progress callback."). assert(0===capi.sqlite3_strglob("*.txt", "foo.txt")). assert(0!==capi.sqlite3_strglob("*.txt", "foo.xtx")). assert(0===capi.sqlite3_strlike("%.txt", "foo.txt", 0)). assert(0!==capi.sqlite3_strlike("%.txt", "foo.xtx", 0)); }finally{ rc = st.finalize(); |
︙ | ︙ | |||
1359 1360 1361 1362 1363 1364 1365 | bind: [5,6] }); //debug("Exec'd SQL:", list); T.assert(rc === db) .assert(2 === list.length) .assert('string'===typeof list[1]) .assert(3===db.changes()) | | > | 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 | bind: [5,6] }); //debug("Exec'd SQL:", list); T.assert(rc === db) .assert(2 === list.length) .assert('string'===typeof list[1]) .assert(3===db.changes()) .assert(this.progressHandlerCount > 0 || wasm.compileOptionUsed('OMIT_PROGRESS_CALLBACK'), "Expecting progress callback.") if(wasm.bigIntEnabled){ T.assert(3n===db.changes(false,true)); } rc = db.exec({ sql: "INSERT INTO t(a,b) values('blob',X'6869') RETURNING 13", rowMode: 0 |
︙ | ︙ | |||
1900 1901 1902 1903 1904 1905 1906 | T.assert(9007199254740994n===v); } }/*aggregate UDFs*/) //////////////////////////////////////////////////////////////////// .t({ name: 'Window UDFs', | | > > | 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 | T.assert(9007199254740994n===v); } }/*aggregate UDFs*/) //////////////////////////////////////////////////////////////////// .t({ name: 'Window UDFs', predicate: (sqlite3)=>!!sqlite3.wasm.exports.sqlite3_create_window_function /*!sqlite3.wasm.compileOptionUsed('OMIT_WINDOWFUNC')*/ || "Missing window functions", test: function(){ /* Example window function, table, and results taken from: https://sqlite.org/windowfunctions.html#udfwinfunc */ const db = this.db; const sjac = (cx,n=4)=>capi.sqlite3_js_aggregate_context(cx,n); const xValueFinal = (pCtx)=>{ const ac = sjac(pCtx, 0); |
︙ | ︙ | |||
3128 3129 3130 3131 3132 3133 3134 | over the other journaling modes. */, 'create table t(a);', 'insert into t(a) values(1),(2),(3)' ]); T.assert(2 === u1.getFileCount() /* one is the journal file */) .assert(3 === db.selectValue('select count(*) from t')) | > | > > | 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 | over the other journaling modes. */, 'create table t(a);', 'insert into t(a) values(1),(2),(3)' ]); T.assert(2 === u1.getFileCount() /* one is the journal file */) .assert(3 === db.selectValue('select count(*) from t')) .assert( 'wal'===db.selectValue('pragma journal_mode') || wasm.compileOptionUsed('OMIT_WAL') ); 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) |
︙ | ︙ |