1 /* 2 ** This file requires access to sqlite3.c static state in order to 3 ** implement certain WASM-specific features. Unlike the rest of 4 ** sqlite3.c, this file requires compiling with -std=c99 (or 5 ** equivalent, or a later C version) because it makes use of features 6 ** not available in C89. 7 */ 8 #include "sqlite3.c" 9 10 /* 11 ** WASM_KEEP is identical to EMSCRIPTEN_KEEPALIVE but is not 12 ** Emscripten-specific. It explicitly includes marked functions for 13 ** export into the target wasm file without requiring explicit listing 14 ** of those functions in Emscripten's -sEXPORTED_FUNCTIONS=... list 15 ** (or equivalent in other build platforms). Any function with neither 16 ** this attribute nor which is listed as an explicit export will not 17 ** be exported from the wasm file (but may still be used internally 18 ** within the wasm file). 19 ** 20 ** The functions in this file (sqlite3-wasm.c) which require exporting 21 ** are marked with this flag. They may also be added to any explicit 22 ** build-time export list but need not be. All of these APIs are 23 ** intended for use only within the project's own JS/WASM code, and 24 ** not by client code, so an argument can be made for reducing their 25 ** visibility by not including them in any build-time export lists. 26 ** 27 ** 2022-09-11: it's not yet _proven_ that this approach works in 28 ** non-Emscripten builds. If not, such builds will need to export 29 ** those using the --export=... wasm-ld flag (or equivalent). As of 30 ** this writing we are tied to Emscripten for various reasons 31 ** and cannot test the library with other build environments. 32 */ 33 #define WASM_KEEP __attribute__((used,visibility("default"))) 34 // See also: 35 //__attribute__((export_name("theExportedName"), used, visibility("default"))) 36 37 /* 38 ** This function is NOT part of the sqlite3 public API. It is strictly 39 ** for use by the sqlite project's own JS/WASM bindings. 40 ** 41 ** For purposes of certain hand-crafted C/Wasm function bindings, we 42 ** need a way of reporting errors which is consistent with the rest of 43 ** the C API, as opposed to throwing JS exceptions. To that end, this 44 ** internal-use-only function is a thin proxy around 45 ** sqlite3ErrorWithMessage(). The intent is that it only be used from 46 ** Wasm bindings such as sqlite3_prepare_v2/v3(), and definitely not 47 ** from client code. 48 ** 49 ** Returns err_code. 50 */ 51 WASM_KEEP 52 int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){ 53 if(0!=zMsg){ 54 const int nMsg = sqlite3Strlen30(zMsg); 55 sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg); 56 }else{ 57 sqlite3ErrorWithMsg(db, err_code, NULL); 58 } 59 return err_code; 60 } 61 62 /* 63 ** This function is NOT part of the sqlite3 public API. It is strictly 64 ** for use by the sqlite project's own JS/WASM bindings. Unlike the 65 ** rest of the sqlite3 API, this part requires C99 for snprintf() and 66 ** variadic macros. 67 ** 68 ** Returns a string containing a JSON-format "enum" of C-level 69 ** constants intended to be imported into the JS environment. The JSON 70 ** is initialized the first time this function is called and that 71 ** result is reused for all future calls. 72 ** 73 ** If this function returns NULL then it means that the internal 74 ** buffer is not large enough for the generated JSON. In debug builds 75 ** that will trigger an assert(). 76 */ 77 WASM_KEEP 78 const char * sqlite3_wasm_enum_json(void){ 79 static char strBuf[1024 * 8] = {0} /* where the JSON goes */; 80 int n = 0, childCount = 0, structCount = 0 81 /* output counters for figuring out where commas go */; 82 char * pos = &strBuf[1] /* skip first byte for now to help protect 83 ** against a small race condition */; 84 char const * const zEnd = pos + sizeof(strBuf) /* one-past-the-end */; 85 if(strBuf[0]) return strBuf; 86 /* Leave strBuf[0] at 0 until the end to help guard against a tiny 87 ** race condition. If this is called twice concurrently, they might 88 ** end up both writing to strBuf, but they'll both write the same 89 ** thing, so that's okay. If we set byte 0 up front then the 2nd 90 ** instance might return and use the string before the 1st instance 91 ** is done filling it. */ 92 93 /* Core output macros... */ 94 #define lenCheck assert(pos < zEnd - 128 \ 95 && "sqlite3_wasm_enum_json() buffer is too small."); \ 96 if(pos >= zEnd - 128) return 0 97 #define outf(format,...) \ 98 pos += snprintf(pos, ((size_t)(zEnd - pos)), format, __VA_ARGS__); \ 99 lenCheck 100 #define out(TXT) outf("%s",TXT) 101 #define CloseBrace(LEVEL) \ 102 assert(LEVEL<5); memset(pos, '}', LEVEL); pos+=LEVEL; lenCheck 103 104 /* Macros for emitting maps of integer- and string-type macros to 105 ** their values. */ 106 #define DefGroup(KEY) n = 0; \ 107 outf("%s\"" #KEY "\": {",(childCount++ ? "," : "")); 108 #define DefInt(KEY) \ 109 outf("%s\"%s\": %d", (n++ ? ", " : ""), #KEY, (int)KEY) 110 #define DefStr(KEY) \ 111 outf("%s\"%s\": \"%s\"", (n++ ? ", " : ""), #KEY, KEY) 112 #define _DefGroup CloseBrace(1) 113 114 DefGroup(version) { 115 DefInt(SQLITE_VERSION_NUMBER); 116 DefStr(SQLITE_VERSION); 117 DefStr(SQLITE_SOURCE_ID); 118 } _DefGroup; 119 120 DefGroup(resultCodes) { 121 DefInt(SQLITE_OK); 122 DefInt(SQLITE_ERROR); 123 DefInt(SQLITE_INTERNAL); 124 DefInt(SQLITE_PERM); 125 DefInt(SQLITE_ABORT); 126 DefInt(SQLITE_BUSY); 127 DefInt(SQLITE_LOCKED); 128 DefInt(SQLITE_NOMEM); 129 DefInt(SQLITE_READONLY); 130 DefInt(SQLITE_INTERRUPT); 131 DefInt(SQLITE_IOERR); 132 DefInt(SQLITE_CORRUPT); 133 DefInt(SQLITE_NOTFOUND); 134 DefInt(SQLITE_FULL); 135 DefInt(SQLITE_CANTOPEN); 136 DefInt(SQLITE_PROTOCOL); 137 DefInt(SQLITE_EMPTY); 138 DefInt(SQLITE_SCHEMA); 139 DefInt(SQLITE_TOOBIG); 140 DefInt(SQLITE_CONSTRAINT); 141 DefInt(SQLITE_MISMATCH); 142 DefInt(SQLITE_MISUSE); 143 DefInt(SQLITE_NOLFS); 144 DefInt(SQLITE_AUTH); 145 DefInt(SQLITE_FORMAT); 146 DefInt(SQLITE_RANGE); 147 DefInt(SQLITE_NOTADB); 148 DefInt(SQLITE_NOTICE); 149 DefInt(SQLITE_WARNING); 150 DefInt(SQLITE_ROW); 151 DefInt(SQLITE_DONE); 152 153 // Extended Result Codes 154 DefInt(SQLITE_ERROR_MISSING_COLLSEQ); 155 DefInt(SQLITE_ERROR_RETRY); 156 DefInt(SQLITE_ERROR_SNAPSHOT); 157 DefInt(SQLITE_IOERR_READ); 158 DefInt(SQLITE_IOERR_SHORT_READ); 159 DefInt(SQLITE_IOERR_WRITE); 160 DefInt(SQLITE_IOERR_FSYNC); 161 DefInt(SQLITE_IOERR_DIR_FSYNC); 162 DefInt(SQLITE_IOERR_TRUNCATE); 163 DefInt(SQLITE_IOERR_FSTAT); 164 DefInt(SQLITE_IOERR_UNLOCK); 165 DefInt(SQLITE_IOERR_RDLOCK); 166 DefInt(SQLITE_IOERR_DELETE); 167 DefInt(SQLITE_IOERR_BLOCKED); 168 DefInt(SQLITE_IOERR_NOMEM); 169 DefInt(SQLITE_IOERR_ACCESS); 170 DefInt(SQLITE_IOERR_CHECKRESERVEDLOCK); 171 DefInt(SQLITE_IOERR_LOCK); 172 DefInt(SQLITE_IOERR_CLOSE); 173 DefInt(SQLITE_IOERR_DIR_CLOSE); 174 DefInt(SQLITE_IOERR_SHMOPEN); 175 DefInt(SQLITE_IOERR_SHMSIZE); 176 DefInt(SQLITE_IOERR_SHMLOCK); 177 DefInt(SQLITE_IOERR_SHMMAP); 178 DefInt(SQLITE_IOERR_SEEK); 179 DefInt(SQLITE_IOERR_DELETE_NOENT); 180 DefInt(SQLITE_IOERR_MMAP); 181 DefInt(SQLITE_IOERR_GETTEMPPATH); 182 DefInt(SQLITE_IOERR_CONVPATH); 183 DefInt(SQLITE_IOERR_VNODE); 184 DefInt(SQLITE_IOERR_AUTH); 185 DefInt(SQLITE_IOERR_BEGIN_ATOMIC); 186 DefInt(SQLITE_IOERR_COMMIT_ATOMIC); 187 DefInt(SQLITE_IOERR_ROLLBACK_ATOMIC); 188 DefInt(SQLITE_IOERR_DATA); 189 DefInt(SQLITE_IOERR_CORRUPTFS); 190 DefInt(SQLITE_LOCKED_SHAREDCACHE); 191 DefInt(SQLITE_LOCKED_VTAB); 192 DefInt(SQLITE_BUSY_RECOVERY); 193 DefInt(SQLITE_BUSY_SNAPSHOT); 194 DefInt(SQLITE_BUSY_TIMEOUT); 195 DefInt(SQLITE_CANTOPEN_NOTEMPDIR); 196 DefInt(SQLITE_CANTOPEN_ISDIR); 197 DefInt(SQLITE_CANTOPEN_FULLPATH); 198 DefInt(SQLITE_CANTOPEN_CONVPATH); 199 //DefInt(SQLITE_CANTOPEN_DIRTYWAL)/*docs say not used*/; 200 DefInt(SQLITE_CANTOPEN_SYMLINK); 201 DefInt(SQLITE_CORRUPT_VTAB); 202 DefInt(SQLITE_CORRUPT_SEQUENCE); 203 DefInt(SQLITE_CORRUPT_INDEX); 204 DefInt(SQLITE_READONLY_RECOVERY); 205 DefInt(SQLITE_READONLY_CANTLOCK); 206 DefInt(SQLITE_READONLY_ROLLBACK); 207 DefInt(SQLITE_READONLY_DBMOVED); 208 DefInt(SQLITE_READONLY_CANTINIT); 209 DefInt(SQLITE_READONLY_DIRECTORY); 210 DefInt(SQLITE_ABORT_ROLLBACK); 211 DefInt(SQLITE_CONSTRAINT_CHECK); 212 DefInt(SQLITE_CONSTRAINT_COMMITHOOK); 213 DefInt(SQLITE_CONSTRAINT_FOREIGNKEY); 214 DefInt(SQLITE_CONSTRAINT_FUNCTION); 215 DefInt(SQLITE_CONSTRAINT_NOTNULL); 216 DefInt(SQLITE_CONSTRAINT_PRIMARYKEY); 217 DefInt(SQLITE_CONSTRAINT_TRIGGER); 218 DefInt(SQLITE_CONSTRAINT_UNIQUE); 219 DefInt(SQLITE_CONSTRAINT_VTAB); 220 DefInt(SQLITE_CONSTRAINT_ROWID); 221 DefInt(SQLITE_CONSTRAINT_PINNED); 222 DefInt(SQLITE_CONSTRAINT_DATATYPE); 223 DefInt(SQLITE_NOTICE_RECOVER_WAL); 224 DefInt(SQLITE_NOTICE_RECOVER_ROLLBACK); 225 DefInt(SQLITE_WARNING_AUTOINDEX); 226 DefInt(SQLITE_AUTH_USER); 227 DefInt(SQLITE_OK_LOAD_PERMANENTLY); 228 //DefInt(SQLITE_OK_SYMLINK) /* internal use only */; 229 } _DefGroup; 230 231 DefGroup(dataTypes) { 232 DefInt(SQLITE_INTEGER); 233 DefInt(SQLITE_FLOAT); 234 DefInt(SQLITE_TEXT); 235 DefInt(SQLITE_BLOB); 236 DefInt(SQLITE_NULL); 237 } _DefGroup; 238 239 DefGroup(encodings) { 240 /* Noting that the wasm binding only aims to support UTF-8. */ 241 DefInt(SQLITE_UTF8); 242 DefInt(SQLITE_UTF16LE); 243 DefInt(SQLITE_UTF16BE); 244 DefInt(SQLITE_UTF16); 245 /*deprecated DefInt(SQLITE_ANY); */ 246 DefInt(SQLITE_UTF16_ALIGNED); 247 } _DefGroup; 248 249 DefGroup(blobFinalizers) { 250 /* SQLITE_STATIC/TRANSIENT need to be handled explicitly as 251 ** integers to avoid casting-related warnings. */ 252 out("\"SQLITE_STATIC\":0, \"SQLITE_TRANSIENT\":-1"); 253 } _DefGroup; 254 255 DefGroup(udfFlags) { 256 DefInt(SQLITE_DETERMINISTIC); 257 DefInt(SQLITE_DIRECTONLY); 258 DefInt(SQLITE_INNOCUOUS); 259 } _DefGroup; 260 261 DefGroup(openFlags) { 262 /* Noting that not all of these will have any effect in WASM-space. */ 263 DefInt(SQLITE_OPEN_READONLY); 264 DefInt(SQLITE_OPEN_READWRITE); 265 DefInt(SQLITE_OPEN_CREATE); 266 DefInt(SQLITE_OPEN_URI); 267 DefInt(SQLITE_OPEN_MEMORY); 268 DefInt(SQLITE_OPEN_NOMUTEX); 269 DefInt(SQLITE_OPEN_FULLMUTEX); 270 DefInt(SQLITE_OPEN_SHAREDCACHE); 271 DefInt(SQLITE_OPEN_PRIVATECACHE); 272 DefInt(SQLITE_OPEN_EXRESCODE); 273 DefInt(SQLITE_OPEN_NOFOLLOW); 274 /* OPEN flags for use with VFSes... */ 275 DefInt(SQLITE_OPEN_MAIN_DB); 276 DefInt(SQLITE_OPEN_MAIN_JOURNAL); 277 DefInt(SQLITE_OPEN_TEMP_DB); 278 DefInt(SQLITE_OPEN_TEMP_JOURNAL); 279 DefInt(SQLITE_OPEN_TRANSIENT_DB); 280 DefInt(SQLITE_OPEN_SUBJOURNAL); 281 DefInt(SQLITE_OPEN_SUPER_JOURNAL); 282 DefInt(SQLITE_OPEN_WAL); 283 DefInt(SQLITE_OPEN_DELETEONCLOSE); 284 DefInt(SQLITE_OPEN_EXCLUSIVE); 285 } _DefGroup; 286 287 DefGroup(syncFlags) { 288 DefInt(SQLITE_SYNC_NORMAL); 289 DefInt(SQLITE_SYNC_FULL); 290 DefInt(SQLITE_SYNC_DATAONLY); 291 } _DefGroup; 292 293 DefGroup(prepareFlags) { 294 DefInt(SQLITE_PREPARE_PERSISTENT); 295 DefInt(SQLITE_PREPARE_NORMALIZE); 296 DefInt(SQLITE_PREPARE_NO_VTAB); 297 } _DefGroup; 298 299 DefGroup(flock) { 300 DefInt(SQLITE_LOCK_NONE); 301 DefInt(SQLITE_LOCK_SHARED); 302 DefInt(SQLITE_LOCK_RESERVED); 303 DefInt(SQLITE_LOCK_PENDING); 304 DefInt(SQLITE_LOCK_EXCLUSIVE); 305 } _DefGroup; 306 307 DefGroup(ioCap) { 308 DefInt(SQLITE_IOCAP_ATOMIC); 309 DefInt(SQLITE_IOCAP_ATOMIC512); 310 DefInt(SQLITE_IOCAP_ATOMIC1K); 311 DefInt(SQLITE_IOCAP_ATOMIC2K); 312 DefInt(SQLITE_IOCAP_ATOMIC4K); 313 DefInt(SQLITE_IOCAP_ATOMIC8K); 314 DefInt(SQLITE_IOCAP_ATOMIC16K); 315 DefInt(SQLITE_IOCAP_ATOMIC32K); 316 DefInt(SQLITE_IOCAP_ATOMIC64K); 317 DefInt(SQLITE_IOCAP_SAFE_APPEND); 318 DefInt(SQLITE_IOCAP_SEQUENTIAL); 319 DefInt(SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN); 320 DefInt(SQLITE_IOCAP_POWERSAFE_OVERWRITE); 321 DefInt(SQLITE_IOCAP_IMMUTABLE); 322 DefInt(SQLITE_IOCAP_BATCH_ATOMIC); 323 } _DefGroup; 324 325 DefGroup(access){ 326 DefInt(SQLITE_ACCESS_EXISTS); 327 DefInt(SQLITE_ACCESS_READWRITE); 328 DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/; 329 } _DefGroup; 330 331 #undef DefGroup 332 #undef DefStr 333 #undef DefInt 334 #undef _DefGroup 335 336 /* 337 ** Emit an array of "StructBinder" struct descripions, which look 338 ** like: 339 ** 340 ** { 341 ** "name": "MyStruct", 342 ** "sizeof": 16, 343 ** "members": { 344 ** "member1": {"offset": 0,"sizeof": 4,"signature": "i"}, 345 ** "member2": {"offset": 4,"sizeof": 4,"signature": "p"}, 346 ** "member3": {"offset": 8,"sizeof": 8,"signature": "j"} 347 ** } 348 ** } 349 ** 350 ** Detailed documentation for those bits are in the docs for the 351 ** Jaccwabyt JS-side component. 352 */ 353 354 /** Macros for emitting StructBinder description. */ 355 #define StructBinder__(TYPE) \ 356 n = 0; \ 357 outf("%s{", (structCount++ ? ", " : "")); \ 358 out("\"name\": \"" # TYPE "\","); \ 359 outf("\"sizeof\": %d", (int)sizeof(TYPE)); \ 360 out(",\"members\": {"); 361 #define StructBinder_(T) StructBinder__(T) 362 /** ^^^ indirection needed to expand CurrentStruct */ 363 #define StructBinder StructBinder_(CurrentStruct) 364 #define _StructBinder CloseBrace(2) 365 #define M(MEMBER,SIG) \ 366 outf("%s\"%s\": " \ 367 "{\"offset\":%d,\"sizeof\": %d,\"signature\":\"%s\"}", \ 368 (n++ ? ", " : ""), #MEMBER, \ 369 (int)offsetof(CurrentStruct,MEMBER), \ 370 (int)sizeof(((CurrentStruct*)0)->MEMBER), \ 371 SIG) 372 373 structCount = 0; 374 out(", \"structs\": ["); { 375 376 #define CurrentStruct sqlite3_vfs 377 StructBinder { 378 M(iVersion,"i"); 379 M(szOsFile,"i"); 380 M(mxPathname,"i"); 381 M(pNext,"p"); 382 M(zName,"s"); 383 M(pAppData,"p"); 384 M(xOpen,"i(pppip)"); 385 M(xDelete,"i(ppi)"); 386 M(xAccess,"i(ppip)"); 387 M(xFullPathname,"i(ppip)"); 388 M(xDlOpen,"p(pp)"); 389 M(xDlError,"p(pip)"); 390 M(xDlSym,"p()"); 391 M(xDlClose,"v(pp)"); 392 M(xRandomness,"i(pip)"); 393 M(xSleep,"i(pi)"); 394 M(xCurrentTime,"i(pp)"); 395 M(xGetLastError,"i(pip)"); 396 M(xCurrentTimeInt64,"i(pp)"); 397 M(xSetSystemCall,"i(ppp)"); 398 M(xGetSystemCall,"p(pp)"); 399 M(xNextSystemCall,"p(pp)"); 400 } _StructBinder; 401 #undef CurrentStruct 402 403 #define CurrentStruct sqlite3_io_methods 404 StructBinder { 405 M(iVersion,"i"); 406 M(xClose,"i(p)"); 407 M(xRead,"i(ppij)"); 408 M(xWrite,"i(ppij)"); 409 M(xTruncate,"i(pj)"); 410 M(xSync,"i(pi)"); 411 M(xFileSize,"i(pp)"); 412 M(xLock,"i(pi)"); 413 M(xUnlock,"i(pi)"); 414 M(xCheckReservedLock,"i(pp)"); 415 M(xFileControl,"i(pip)"); 416 M(xSectorSize,"i(p)"); 417 M(xDeviceCharacteristics,"i(p)"); 418 M(xShmMap,"i(piiip)"); 419 M(xShmLock,"i(piii)"); 420 M(xShmBarrier,"v(p)"); 421 M(xShmUnmap,"i(pi)"); 422 M(xFetch,"i(pjip)"); 423 M(xUnfetch,"i(pjp)"); 424 } _StructBinder; 425 #undef CurrentStruct 426 427 #define CurrentStruct sqlite3_file 428 StructBinder { 429 M(pMethods,"P"); 430 } _StructBinder; 431 #undef CurrentStruct 432 433 } out( "]"/*structs*/); 434 435 out("}"/*top-level object*/); 436 *pos = 0; 437 strBuf[0] = '{'/*end of the race-condition workaround*/; 438 return strBuf; 439 #undef StructBinder 440 #undef StructBinder_ 441 #undef StructBinder__ 442 #undef M 443 #undef _StructBinder 444 #undef CloseBrace 445 #undef out 446 #undef outf 447 #undef lenCheck 448 } 449 450 /* 451 ** This function is NOT part of the sqlite3 public API. It is strictly 452 ** for use by the sqlite project's own JS/WASM bindings. 453 ** 454 ** This function invokes the xDelete method of the default VFS, 455 ** passing on the given filename. If zName is NULL, no default VFS is 456 ** found, or it has no xDelete method, SQLITE_MISUSE is returned, else 457 ** the result of the xDelete() call is returned. 458 */ 459 WASM_KEEP 460 int sqlite3_wasm_vfs_unlink(const char * zName){ 461 int rc = SQLITE_MISUSE /* ??? */; 462 sqlite3_vfs * const pVfs = sqlite3_vfs_find(0); 463 if( zName && pVfs && pVfs->xDelete ){ 464 rc = pVfs->xDelete(pVfs, zName, 1); 465 } 466 return rc; 467 } 468 469 #if defined(__EMSCRIPTEN__) && defined(SQLITE_WASM_OPFS) 470 #include <emscripten/wasmfs.h> 471 #include <emscripten/console.h> 472 473 /* 474 ** This function is NOT part of the sqlite3 public API. It is strictly 475 ** for use by the sqlite project's own JS/WASM bindings, specifically 476 ** only when building with Emscripten's WASMFS support. 477 ** 478 ** This function should only be called if the JS side detects the 479 ** existence of the Origin-Private FileSystem (OPFS) APIs in the 480 ** client. The first time it is called, this function instantiates a 481 ** WASMFS backend impl for OPFS. On success, subsequent calls are 482 ** no-ops. 483 ** 484 ** This function may be passed a "mount point" name, which must have a 485 ** leading "/" and is currently restricted to a single path component, 486 ** e.g. "/foo" is legal but "/foo/" and "/foo/bar" are not. If it is 487 ** NULL or empty, it defaults to "/persistent". 488 ** 489 ** Returns 0 on success, SQLITE_NOMEM if instantiation of the backend 490 ** object fails, SQLITE_IOERR if mkdir() of the zMountPoint dir in 491 ** the virtual FS fails. In builds compiled without SQLITE_WASM_OPFS 492 ** defined, SQLITE_NOTFOUND is returned without side effects. 493 */ 494 WASM_KEEP 495 int sqlite3_wasm_init_opfs(const char *zMountPoint){ 496 static backend_t pOpfs = 0; 497 if( !zMountPoint || !*zMountPoint ) zMountPoint = "/persistent"; 498 if( !pOpfs ){ 499 pOpfs = wasmfs_create_opfs_backend(); 500 if( pOpfs ){ 501 emscripten_console_log("Created WASMFS OPFS backend."); 502 } 503 } 504 /** It's not enough to instantiate the backend. We have to create a 505 mountpoint in the VFS and attach the backend to it. */ 506 if( pOpfs && 0!=access(zMountPoint, F_OK) ){ 507 /* mkdir() simply hangs when called from fiddle app. Cause is 508 not yet determined but the hypothesis is an init-order 509 issue. */ 510 /* Note that this check and is not robust but it will 511 hypothetically suffice for the transient wasm-based virtual 512 filesystem we're currently running in. */ 513 const int rc = wasmfs_create_directory(zMountPoint, 0777, pOpfs); 514 emscripten_console_logf("OPFS mkdir(%s) rc=%d", zMountPoint, rc); 515 if(rc) return SQLITE_IOERR; 516 } 517 return pOpfs ? 0 : SQLITE_NOMEM; 518 } 519 #else 520 WASM_KEEP 521 int sqlite3_wasm_init_opfs(void){ 522 return SQLITE_NOTFOUND; 523 } 524 #endif /* __EMSCRIPTEN__ && SQLITE_WASM_OPFS */ 525 526 527 #undef WASM_KEEP 528