xref: /sqlite-3.40.0/ext/wasm/api/sqlite3-wasm.c (revision bdfd7ea0)
173079dbaSstephan /*
273079dbaSstephan ** This file requires access to sqlite3.c static state in order to
36110a5d0Sstephan ** implement certain WASM-specific features, and thus directly
46110a5d0Sstephan ** includes that file. Unlike the rest of sqlite3.c, this file
56110a5d0Sstephan ** requires compiling with -std=c99 (or equivalent, or a later C
66110a5d0Sstephan ** version) because it makes use of features not available in C89.
76110a5d0Sstephan **
86110a5d0Sstephan ** At it's simplest, to build sqlite3.wasm either place this file
96110a5d0Sstephan ** in the same directory as sqlite3.c/h before compilation or use the
106110a5d0Sstephan ** -I/path flag to tell the compiler where to find both of those
116110a5d0Sstephan ** files, then compile this file. For example:
126110a5d0Sstephan **
136110a5d0Sstephan ** emcc -o sqlite3.wasm ... -I/path/to/sqlite3-c-and-h sqlite3-wasm.c
1473079dbaSstephan */
156110a5d0Sstephan 
1653d4e01dSstephan /*
1753d4e01dSstephan ** Threading and file locking: JS is single-threaded. Each Worker
1853d4e01dSstephan ** thread is a separate instance of the JS engine so can never access
1953d4e01dSstephan ** the same db handle as another thread, thus multi-threading support
2053d4e01dSstephan ** is unnecessary in the library. Because the filesystems are virtual
2153d4e01dSstephan ** and local to a given wasm runtime instance, two Workers can never
2253d4e01dSstephan ** access the same db file at once, with the exception of OPFS. As of
2353d4e01dSstephan ** this writing (2022-09-30), OPFS exclusively locks a file when
2453d4e01dSstephan ** opening it, so two Workers can never open the same OPFS-backed file
2553d4e01dSstephan ** at once. That situation will change if and when lower-level locking
2653d4e01dSstephan ** features are added to OPFS (as is currently planned, per folks
2753d4e01dSstephan ** involved with its development).
2853d4e01dSstephan **
2953d4e01dSstephan ** Summary: except for the case of future OPFS, which supports
3053d4e01dSstephan ** locking, and any similar future filesystems, threading and file
3153d4e01dSstephan ** locking support are unnecessary in the wasm build.
3253d4e01dSstephan */
3353d4e01dSstephan #undef SQLITE_OMIT_DESERIALIZE
346110a5d0Sstephan #ifndef SQLITE_DEFAULT_UNIX_VFS
356110a5d0Sstephan # define SQLITE_DEFAULT_UNIX_VFS "unix-none"
366110a5d0Sstephan #endif
376110a5d0Sstephan #ifndef SQLITE_OMIT_DEPRECATED
386110a5d0Sstephan # define SQLITE_OMIT_DEPRECATED
396110a5d0Sstephan #endif
406110a5d0Sstephan #ifndef SQLITE_OMIT_LOAD_EXTENSION
416110a5d0Sstephan # define SQLITE_OMIT_LOAD_EXTENSION
426110a5d0Sstephan #endif
436110a5d0Sstephan #ifndef SQLITE_OMIT_SHARED_CACHE
446110a5d0Sstephan # define SQLITE_OMIT_SHARED_CACHE
456110a5d0Sstephan #endif
466110a5d0Sstephan #ifndef SQLITE_OMIT_UTF16
476110a5d0Sstephan # define SQLITE_OMIT_UTF16
486110a5d0Sstephan #endif
496110a5d0Sstephan #ifndef SQLITE_OS_KV_OPTIONAL
506110a5d0Sstephan # define SQLITE_OS_KV_OPTIONAL 1
516110a5d0Sstephan #endif
526110a5d0Sstephan #ifndef SQLITE_TEMP_STORE
536110a5d0Sstephan # define SQLITE_TEMP_STORE 3
546110a5d0Sstephan #endif
556110a5d0Sstephan #ifndef SQLITE_THREADSAFE
566110a5d0Sstephan # define SQLITE_THREADSAFE 0
576110a5d0Sstephan #endif
586110a5d0Sstephan 
593afad4d4Sstephan #include <assert.h>
606110a5d0Sstephan #include "sqlite3.c" /* yes, .c instead of .h. */
613961b263Sstephan 
6263e9ec2fSstephan #if defined(__EMSCRIPTEN__)
6363e9ec2fSstephan #  include <emscripten/console.h>
6463e9ec2fSstephan #endif
6563e9ec2fSstephan 
663961b263Sstephan /*
6773079dbaSstephan ** WASM_KEEP is identical to EMSCRIPTEN_KEEPALIVE but is not
6872ab400dSstephan ** Emscripten-specific. It explicitly marks functions for export into
6972ab400dSstephan ** the target wasm file without requiring explicit listing of those
7072ab400dSstephan ** functions in Emscripten's -sEXPORTED_FUNCTIONS=... list (or
7172ab400dSstephan ** equivalent in other build platforms). Any function with neither
7273079dbaSstephan ** this attribute nor which is listed as an explicit export will not
7373079dbaSstephan ** be exported from the wasm file (but may still be used internally
7473079dbaSstephan ** within the wasm file).
7573079dbaSstephan **
7673079dbaSstephan ** The functions in this file (sqlite3-wasm.c) which require exporting
7773079dbaSstephan ** are marked with this flag. They may also be added to any explicit
7873079dbaSstephan ** build-time export list but need not be. All of these APIs are
7973079dbaSstephan ** intended for use only within the project's own JS/WASM code, and
8073079dbaSstephan ** not by client code, so an argument can be made for reducing their
8173079dbaSstephan ** visibility by not including them in any build-time export lists.
8273079dbaSstephan **
8373079dbaSstephan ** 2022-09-11: it's not yet _proven_ that this approach works in
8473079dbaSstephan ** non-Emscripten builds. If not, such builds will need to export
8573079dbaSstephan ** those using the --export=... wasm-ld flag (or equivalent). As of
8673079dbaSstephan ** this writing we are tied to Emscripten for various reasons
8773079dbaSstephan ** and cannot test the library with other build environments.
8873079dbaSstephan */
8973079dbaSstephan #define WASM_KEEP __attribute__((used,visibility("default")))
9073079dbaSstephan // See also:
9173079dbaSstephan //__attribute__((export_name("theExportedName"), used, visibility("default")))
9273079dbaSstephan 
933afad4d4Sstephan 
943afad4d4Sstephan #if 0
953afad4d4Sstephan /*
963afad4d4Sstephan ** An EXPERIMENT in implementing a stack-based allocator analog to
973afad4d4Sstephan ** Emscripten's stackSave(), stackAlloc(), stackRestore().
983afad4d4Sstephan ** Unfortunately, this cannot work together with Emscripten because
993afad4d4Sstephan ** Emscripten defines its own native one and we'd stomp on each
1003afad4d4Sstephan ** other's memory. Other than that complication, basic tests show it
1013afad4d4Sstephan ** to work just fine.
1023afad4d4Sstephan **
1033afad4d4Sstephan ** Another option is to malloc() a chunk of our own and call that our
1043afad4d4Sstephan ** "stack".
1053afad4d4Sstephan */
1063afad4d4Sstephan WASM_KEEP void * sqlite3_wasm_stack_end(void){
1073afad4d4Sstephan   extern void __heap_base
1083afad4d4Sstephan     /* see https://stackoverflow.com/questions/10038964 */;
1093afad4d4Sstephan   return &__heap_base;
1103afad4d4Sstephan }
1113afad4d4Sstephan WASM_KEEP void * sqlite3_wasm_stack_begin(void){
1123afad4d4Sstephan   extern void __data_end;
1133afad4d4Sstephan   return &__data_end;
1143afad4d4Sstephan }
1153afad4d4Sstephan static void * sq3StackPtr = 0;
1163afad4d4Sstephan WASM_KEEP void * sqlite3_wasm_stack_ptr(void){
1173afad4d4Sstephan   if(!sq3StackPtr) sq3StackPtr = sqlite3_wasm_stack_end();
1183afad4d4Sstephan   return sq3StackPtr;
1193afad4d4Sstephan }
1203afad4d4Sstephan WASM_KEEP void sqlite3_wasm_stack_restore(void * p){
1213afad4d4Sstephan   sq3StackPtr = p;
1223afad4d4Sstephan }
1233afad4d4Sstephan WASM_KEEP void * sqlite3_wasm_stack_alloc(int n){
1243afad4d4Sstephan   if(n<=0) return 0;
1253afad4d4Sstephan   n = (n + 7) & ~7 /* align to 8-byte boundary */;
1263afad4d4Sstephan   unsigned char * const p = (unsigned char *)sqlite3_wasm_stack_ptr();
1273afad4d4Sstephan   unsigned const char * const b = (unsigned const char *)sqlite3_wasm_stack_begin();
1283afad4d4Sstephan   if(b + n >= p || b + n < b/*overflow*/) return 0;
1293afad4d4Sstephan   return sq3StackPtr = p - n;
1303afad4d4Sstephan }
1313afad4d4Sstephan #endif /* stack allocator experiment */
1323afad4d4Sstephan 
1333afad4d4Sstephan /*
1343afad4d4Sstephan ** State for the "pseudo-stack" allocator implemented in
1353afad4d4Sstephan ** sqlite3_wasm_pstack_xyz(). In order to avoid colliding with
1363afad4d4Sstephan ** Emscripten-controled stack space, it carves out a bit of stack
1373afad4d4Sstephan ** memory to use for that purpose. This memory ends up in the
1383afad4d4Sstephan ** WASM-managed memory, such that routines which manipulate the wasm
1393afad4d4Sstephan ** heap can also be used to manipulate this memory.
1403afad4d4Sstephan */
1413afad4d4Sstephan static unsigned char PStack_mem[512 * 8] = {0};
1423afad4d4Sstephan static struct {
143f446af57Sstephan   unsigned const char * const pBegin;/* Start (inclusive) of memory */
144f446af57Sstephan   unsigned const char * const pEnd;  /* One-after-the-end of memory */
145f446af57Sstephan   unsigned char * pPos;              /* Current stack pointer */
1463afad4d4Sstephan } PStack = {
1473afad4d4Sstephan   &PStack_mem[0],
1483afad4d4Sstephan   &PStack_mem[0] + sizeof(PStack_mem),
1493afad4d4Sstephan   &PStack_mem[0] + sizeof(PStack_mem)
1503afad4d4Sstephan };
1513afad4d4Sstephan /*
1523afad4d4Sstephan ** Returns the current pstack position.
1533afad4d4Sstephan */
1543afad4d4Sstephan WASM_KEEP void * sqlite3_wasm_pstack_ptr(void){
1553afad4d4Sstephan   return PStack.pPos;
1563afad4d4Sstephan }
1573afad4d4Sstephan /*
1583afad4d4Sstephan ** Sets the pstack position poitner to p. Results are undefined if the
1593afad4d4Sstephan ** given value did not come from sqlite3_wasm_pstack_ptr().
1603afad4d4Sstephan */
1613afad4d4Sstephan WASM_KEEP void sqlite3_wasm_pstack_restore(unsigned char * p){
1623afad4d4Sstephan   assert(p>=PStack.pBegin && p<=PStack.pEnd && p>=PStack.pPos);
1633afad4d4Sstephan   assert(0==(p & 0x7));
1643afad4d4Sstephan   if(p>=PStack.pBegin && p<=PStack.pEnd /*&& p>=PStack.pPos*/){
1653afad4d4Sstephan     PStack.pPos = p;
1663afad4d4Sstephan   }
1673afad4d4Sstephan }
1683afad4d4Sstephan /*
1693afad4d4Sstephan ** Allocate and zero out n bytes from the pstack. Returns a pointer to
1703afad4d4Sstephan ** the memory on success, 0 on error (including a negative n value). n
1713afad4d4Sstephan ** is always adjusted to be a multiple of 8 and returned memory is
1723afad4d4Sstephan ** always zeroed out before returning (because this keeps the client
1733afad4d4Sstephan ** JS code from having to do so, and most uses of the pstack will
1743afad4d4Sstephan ** call for doing so).
1753afad4d4Sstephan */
1763afad4d4Sstephan WASM_KEEP void * sqlite3_wasm_pstack_alloc(int n){
1773afad4d4Sstephan   if( n<=0 ) return 0;
1783afad4d4Sstephan   //if( n & 0x7 ) n += 8 - (n & 0x7) /* align to 8-byte boundary */;
1793afad4d4Sstephan   n = (n + 7) & ~7 /* align to 8-byte boundary */;
1803afad4d4Sstephan   unsigned char * const p = PStack.pPos;
1813afad4d4Sstephan   unsigned const char * const b = PStack.pBegin;
1823afad4d4Sstephan   if( b + n > p || b + n <= b/*overflow*/ ) return 0;
1833afad4d4Sstephan   memset((PStack.pPos = p - n), 0, (unsigned int)n);
1843afad4d4Sstephan   return PStack.pPos;
1853afad4d4Sstephan }
1863afad4d4Sstephan /*
1873afad4d4Sstephan ** Return the number of bytes left which can be
1883afad4d4Sstephan ** sqlite3_wasm_pstack_alloc()'d.
1893afad4d4Sstephan */
1903afad4d4Sstephan WASM_KEEP int sqlite3_wasm_pstack_remaining(void){
1913afad4d4Sstephan   assert(PStack.pPos >= PStack.pBegin);
1923afad4d4Sstephan   assert(PStack.pPos <= PStack.pEnd);
1933afad4d4Sstephan   return (int)(PStack.pPos - PStack.pBegin);
1943afad4d4Sstephan }
1953afad4d4Sstephan 
1963afad4d4Sstephan 
19773079dbaSstephan /*
1983961b263Sstephan ** This function is NOT part of the sqlite3 public API. It is strictly
1993961b263Sstephan ** for use by the sqlite project's own JS/WASM bindings.
2003961b263Sstephan **
2013961b263Sstephan ** For purposes of certain hand-crafted C/Wasm function bindings, we
2023961b263Sstephan ** need a way of reporting errors which is consistent with the rest of
203e1c34624Sstephan ** the C API, as opposed to throwing JS exceptions. To that end, this
204e1c34624Sstephan ** internal-use-only function is a thin proxy around
205e1c34624Sstephan ** sqlite3ErrorWithMessage(). The intent is that it only be used from
206e1c34624Sstephan ** Wasm bindings such as sqlite3_prepare_v2/v3(), and definitely not
207e1c34624Sstephan ** from client code.
2083961b263Sstephan **
2093961b263Sstephan ** Returns err_code.
2103961b263Sstephan */
21173079dbaSstephan WASM_KEEP
21273079dbaSstephan int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
2133961b263Sstephan   if(0!=zMsg){
2143961b263Sstephan     const int nMsg = sqlite3Strlen30(zMsg);
2153961b263Sstephan     sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg);
2163961b263Sstephan   }else{
2173961b263Sstephan     sqlite3ErrorWithMsg(db, err_code, NULL);
2183961b263Sstephan   }
2193961b263Sstephan   return err_code;
2203961b263Sstephan }
2213961b263Sstephan 
2223961b263Sstephan /*
2233961b263Sstephan ** This function is NOT part of the sqlite3 public API. It is strictly
2243961b263Sstephan ** for use by the sqlite project's own JS/WASM bindings. Unlike the
2253961b263Sstephan ** rest of the sqlite3 API, this part requires C99 for snprintf() and
2263961b263Sstephan ** variadic macros.
2273961b263Sstephan **
2283961b263Sstephan ** Returns a string containing a JSON-format "enum" of C-level
2293961b263Sstephan ** constants intended to be imported into the JS environment. The JSON
2303961b263Sstephan ** is initialized the first time this function is called and that
2313961b263Sstephan ** result is reused for all future calls.
2323961b263Sstephan **
2333961b263Sstephan ** If this function returns NULL then it means that the internal
2343961b263Sstephan ** buffer is not large enough for the generated JSON. In debug builds
2353961b263Sstephan ** that will trigger an assert().
2363961b263Sstephan */
23773079dbaSstephan WASM_KEEP
2383961b263Sstephan const char * sqlite3_wasm_enum_json(void){
2395b915007Sstephan   static char strBuf[1024 * 12] = {0} /* where the JSON goes */;
2403961b263Sstephan   int n = 0, childCount = 0, structCount = 0
2413961b263Sstephan     /* output counters for figuring out where commas go */;
2423961b263Sstephan   char * pos = &strBuf[1] /* skip first byte for now to help protect
2433961b263Sstephan                           ** against a small race condition */;
2443961b263Sstephan   char const * const zEnd = pos + sizeof(strBuf) /* one-past-the-end */;
2453961b263Sstephan   if(strBuf[0]) return strBuf;
2463961b263Sstephan   /* Leave strBuf[0] at 0 until the end to help guard against a tiny
2473961b263Sstephan   ** race condition. If this is called twice concurrently, they might
2483961b263Sstephan   ** end up both writing to strBuf, but they'll both write the same
2493961b263Sstephan   ** thing, so that's okay. If we set byte 0 up front then the 2nd
2503961b263Sstephan   ** instance might return and use the string before the 1st instance
2513961b263Sstephan   ** is done filling it. */
2523961b263Sstephan 
2533961b263Sstephan /* Core output macros... */
2543961b263Sstephan #define lenCheck assert(pos < zEnd - 128 \
2553961b263Sstephan   && "sqlite3_wasm_enum_json() buffer is too small."); \
2563961b263Sstephan   if(pos >= zEnd - 128) return 0
2573961b263Sstephan #define outf(format,...) \
2583961b263Sstephan   pos += snprintf(pos, ((size_t)(zEnd - pos)), format, __VA_ARGS__); \
2593961b263Sstephan   lenCheck
2603961b263Sstephan #define out(TXT) outf("%s",TXT)
2613961b263Sstephan #define CloseBrace(LEVEL) \
2623961b263Sstephan   assert(LEVEL<5); memset(pos, '}', LEVEL); pos+=LEVEL; lenCheck
2633961b263Sstephan 
2643961b263Sstephan /* Macros for emitting maps of integer- and string-type macros to
2653961b263Sstephan ** their values. */
2663961b263Sstephan #define DefGroup(KEY) n = 0; \
2673961b263Sstephan   outf("%s\"" #KEY "\": {",(childCount++ ? "," : ""));
2683961b263Sstephan #define DefInt(KEY)                                     \
2693961b263Sstephan   outf("%s\"%s\": %d", (n++ ? ", " : ""), #KEY, (int)KEY)
2703961b263Sstephan #define DefStr(KEY)                                     \
2713961b263Sstephan   outf("%s\"%s\": \"%s\"", (n++ ? ", " : ""), #KEY, KEY)
2723961b263Sstephan #define _DefGroup CloseBrace(1)
2733961b263Sstephan 
27453d4e01dSstephan   /* The following groups are sorted alphabetic by group name. */
27553d4e01dSstephan   DefGroup(access){
27653d4e01dSstephan     DefInt(SQLITE_ACCESS_EXISTS);
27753d4e01dSstephan     DefInt(SQLITE_ACCESS_READWRITE);
27853d4e01dSstephan     DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/;
27953d4e01dSstephan   } _DefGroup;
28053d4e01dSstephan 
28153d4e01dSstephan   DefGroup(blobFinalizers) {
28253d4e01dSstephan     /* SQLITE_STATIC/TRANSIENT need to be handled explicitly as
28353d4e01dSstephan     ** integers to avoid casting-related warnings. */
28453d4e01dSstephan     out("\"SQLITE_STATIC\":0, \"SQLITE_TRANSIENT\":-1");
28553d4e01dSstephan   } _DefGroup;
28653d4e01dSstephan 
28753d4e01dSstephan   DefGroup(dataTypes) {
28853d4e01dSstephan     DefInt(SQLITE_INTEGER);
28953d4e01dSstephan     DefInt(SQLITE_FLOAT);
29053d4e01dSstephan     DefInt(SQLITE_TEXT);
29153d4e01dSstephan     DefInt(SQLITE_BLOB);
29253d4e01dSstephan     DefInt(SQLITE_NULL);
29353d4e01dSstephan   } _DefGroup;
29453d4e01dSstephan 
29553d4e01dSstephan   DefGroup(encodings) {
29653d4e01dSstephan     /* Noting that the wasm binding only aims to support UTF-8. */
29753d4e01dSstephan     DefInt(SQLITE_UTF8);
29853d4e01dSstephan     DefInt(SQLITE_UTF16LE);
29953d4e01dSstephan     DefInt(SQLITE_UTF16BE);
30053d4e01dSstephan     DefInt(SQLITE_UTF16);
30153d4e01dSstephan     /*deprecated DefInt(SQLITE_ANY); */
30253d4e01dSstephan     DefInt(SQLITE_UTF16_ALIGNED);
30353d4e01dSstephan   } _DefGroup;
30453d4e01dSstephan 
30553d4e01dSstephan   DefGroup(fcntl) {
30653d4e01dSstephan     DefInt(SQLITE_FCNTL_LOCKSTATE);
30753d4e01dSstephan     DefInt(SQLITE_FCNTL_GET_LOCKPROXYFILE);
30853d4e01dSstephan     DefInt(SQLITE_FCNTL_SET_LOCKPROXYFILE);
30953d4e01dSstephan     DefInt(SQLITE_FCNTL_LAST_ERRNO);
31053d4e01dSstephan     DefInt(SQLITE_FCNTL_SIZE_HINT);
31153d4e01dSstephan     DefInt(SQLITE_FCNTL_CHUNK_SIZE);
31253d4e01dSstephan     DefInt(SQLITE_FCNTL_FILE_POINTER);
31353d4e01dSstephan     DefInt(SQLITE_FCNTL_SYNC_OMITTED);
31453d4e01dSstephan     DefInt(SQLITE_FCNTL_WIN32_AV_RETRY);
31553d4e01dSstephan     DefInt(SQLITE_FCNTL_PERSIST_WAL);
31653d4e01dSstephan     DefInt(SQLITE_FCNTL_OVERWRITE);
31753d4e01dSstephan     DefInt(SQLITE_FCNTL_VFSNAME);
31853d4e01dSstephan     DefInt(SQLITE_FCNTL_POWERSAFE_OVERWRITE);
31953d4e01dSstephan     DefInt(SQLITE_FCNTL_PRAGMA);
32053d4e01dSstephan     DefInt(SQLITE_FCNTL_BUSYHANDLER);
32153d4e01dSstephan     DefInt(SQLITE_FCNTL_TEMPFILENAME);
32253d4e01dSstephan     DefInt(SQLITE_FCNTL_MMAP_SIZE);
32353d4e01dSstephan     DefInt(SQLITE_FCNTL_TRACE);
32453d4e01dSstephan     DefInt(SQLITE_FCNTL_HAS_MOVED);
32553d4e01dSstephan     DefInt(SQLITE_FCNTL_SYNC);
32653d4e01dSstephan     DefInt(SQLITE_FCNTL_COMMIT_PHASETWO);
32753d4e01dSstephan     DefInt(SQLITE_FCNTL_WIN32_SET_HANDLE);
32853d4e01dSstephan     DefInt(SQLITE_FCNTL_WAL_BLOCK);
32953d4e01dSstephan     DefInt(SQLITE_FCNTL_ZIPVFS);
33053d4e01dSstephan     DefInt(SQLITE_FCNTL_RBU);
33153d4e01dSstephan     DefInt(SQLITE_FCNTL_VFS_POINTER);
33253d4e01dSstephan     DefInt(SQLITE_FCNTL_JOURNAL_POINTER);
33353d4e01dSstephan     DefInt(SQLITE_FCNTL_WIN32_GET_HANDLE);
33453d4e01dSstephan     DefInt(SQLITE_FCNTL_PDB);
33553d4e01dSstephan     DefInt(SQLITE_FCNTL_BEGIN_ATOMIC_WRITE);
33653d4e01dSstephan     DefInt(SQLITE_FCNTL_COMMIT_ATOMIC_WRITE);
33753d4e01dSstephan     DefInt(SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE);
33853d4e01dSstephan     DefInt(SQLITE_FCNTL_LOCK_TIMEOUT);
33953d4e01dSstephan     DefInt(SQLITE_FCNTL_DATA_VERSION);
34053d4e01dSstephan     DefInt(SQLITE_FCNTL_SIZE_LIMIT);
34153d4e01dSstephan     DefInt(SQLITE_FCNTL_CKPT_DONE);
34253d4e01dSstephan     DefInt(SQLITE_FCNTL_RESERVE_BYTES);
34353d4e01dSstephan     DefInt(SQLITE_FCNTL_CKPT_START);
34453d4e01dSstephan     DefInt(SQLITE_FCNTL_EXTERNAL_READER);
34553d4e01dSstephan     DefInt(SQLITE_FCNTL_CKSM_FILE);
34653d4e01dSstephan   } _DefGroup;
34753d4e01dSstephan 
34853d4e01dSstephan   DefGroup(flock) {
34953d4e01dSstephan     DefInt(SQLITE_LOCK_NONE);
35053d4e01dSstephan     DefInt(SQLITE_LOCK_SHARED);
35153d4e01dSstephan     DefInt(SQLITE_LOCK_RESERVED);
35253d4e01dSstephan     DefInt(SQLITE_LOCK_PENDING);
35353d4e01dSstephan     DefInt(SQLITE_LOCK_EXCLUSIVE);
35453d4e01dSstephan   } _DefGroup;
35553d4e01dSstephan 
35653d4e01dSstephan   DefGroup(ioCap) {
35753d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC);
35853d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC512);
35953d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC1K);
36053d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC2K);
36153d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC4K);
36253d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC8K);
36353d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC16K);
36453d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC32K);
36553d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC64K);
36653d4e01dSstephan     DefInt(SQLITE_IOCAP_SAFE_APPEND);
36753d4e01dSstephan     DefInt(SQLITE_IOCAP_SEQUENTIAL);
36853d4e01dSstephan     DefInt(SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN);
36953d4e01dSstephan     DefInt(SQLITE_IOCAP_POWERSAFE_OVERWRITE);
37053d4e01dSstephan     DefInt(SQLITE_IOCAP_IMMUTABLE);
37153d4e01dSstephan     DefInt(SQLITE_IOCAP_BATCH_ATOMIC);
37253d4e01dSstephan   } _DefGroup;
37353d4e01dSstephan 
37453d4e01dSstephan   DefGroup(openFlags) {
37553d4e01dSstephan     /* Noting that not all of these will have any effect in
37653d4e01dSstephan     ** WASM-space. */
37753d4e01dSstephan     DefInt(SQLITE_OPEN_READONLY);
37853d4e01dSstephan     DefInt(SQLITE_OPEN_READWRITE);
37953d4e01dSstephan     DefInt(SQLITE_OPEN_CREATE);
38053d4e01dSstephan     DefInt(SQLITE_OPEN_URI);
38153d4e01dSstephan     DefInt(SQLITE_OPEN_MEMORY);
38253d4e01dSstephan     DefInt(SQLITE_OPEN_NOMUTEX);
38353d4e01dSstephan     DefInt(SQLITE_OPEN_FULLMUTEX);
38453d4e01dSstephan     DefInt(SQLITE_OPEN_SHAREDCACHE);
38553d4e01dSstephan     DefInt(SQLITE_OPEN_PRIVATECACHE);
38653d4e01dSstephan     DefInt(SQLITE_OPEN_EXRESCODE);
38753d4e01dSstephan     DefInt(SQLITE_OPEN_NOFOLLOW);
38853d4e01dSstephan     /* OPEN flags for use with VFSes... */
38953d4e01dSstephan     DefInt(SQLITE_OPEN_MAIN_DB);
39053d4e01dSstephan     DefInt(SQLITE_OPEN_MAIN_JOURNAL);
39153d4e01dSstephan     DefInt(SQLITE_OPEN_TEMP_DB);
39253d4e01dSstephan     DefInt(SQLITE_OPEN_TEMP_JOURNAL);
39353d4e01dSstephan     DefInt(SQLITE_OPEN_TRANSIENT_DB);
39453d4e01dSstephan     DefInt(SQLITE_OPEN_SUBJOURNAL);
39553d4e01dSstephan     DefInt(SQLITE_OPEN_SUPER_JOURNAL);
39653d4e01dSstephan     DefInt(SQLITE_OPEN_WAL);
39753d4e01dSstephan     DefInt(SQLITE_OPEN_DELETEONCLOSE);
39853d4e01dSstephan     DefInt(SQLITE_OPEN_EXCLUSIVE);
39953d4e01dSstephan   } _DefGroup;
40053d4e01dSstephan 
40153d4e01dSstephan   DefGroup(prepareFlags) {
40253d4e01dSstephan     DefInt(SQLITE_PREPARE_PERSISTENT);
40353d4e01dSstephan     DefInt(SQLITE_PREPARE_NORMALIZE);
40453d4e01dSstephan     DefInt(SQLITE_PREPARE_NO_VTAB);
4053961b263Sstephan   } _DefGroup;
4063961b263Sstephan 
4073961b263Sstephan   DefGroup(resultCodes) {
4083961b263Sstephan     DefInt(SQLITE_OK);
4093961b263Sstephan     DefInt(SQLITE_ERROR);
4103961b263Sstephan     DefInt(SQLITE_INTERNAL);
4113961b263Sstephan     DefInt(SQLITE_PERM);
4123961b263Sstephan     DefInt(SQLITE_ABORT);
4133961b263Sstephan     DefInt(SQLITE_BUSY);
4143961b263Sstephan     DefInt(SQLITE_LOCKED);
4153961b263Sstephan     DefInt(SQLITE_NOMEM);
4163961b263Sstephan     DefInt(SQLITE_READONLY);
4173961b263Sstephan     DefInt(SQLITE_INTERRUPT);
4183961b263Sstephan     DefInt(SQLITE_IOERR);
4193961b263Sstephan     DefInt(SQLITE_CORRUPT);
4203961b263Sstephan     DefInt(SQLITE_NOTFOUND);
4213961b263Sstephan     DefInt(SQLITE_FULL);
4223961b263Sstephan     DefInt(SQLITE_CANTOPEN);
4233961b263Sstephan     DefInt(SQLITE_PROTOCOL);
4243961b263Sstephan     DefInt(SQLITE_EMPTY);
4253961b263Sstephan     DefInt(SQLITE_SCHEMA);
4263961b263Sstephan     DefInt(SQLITE_TOOBIG);
4273961b263Sstephan     DefInt(SQLITE_CONSTRAINT);
4283961b263Sstephan     DefInt(SQLITE_MISMATCH);
4293961b263Sstephan     DefInt(SQLITE_MISUSE);
4303961b263Sstephan     DefInt(SQLITE_NOLFS);
4313961b263Sstephan     DefInt(SQLITE_AUTH);
4323961b263Sstephan     DefInt(SQLITE_FORMAT);
4333961b263Sstephan     DefInt(SQLITE_RANGE);
4343961b263Sstephan     DefInt(SQLITE_NOTADB);
4353961b263Sstephan     DefInt(SQLITE_NOTICE);
4363961b263Sstephan     DefInt(SQLITE_WARNING);
4373961b263Sstephan     DefInt(SQLITE_ROW);
4383961b263Sstephan     DefInt(SQLITE_DONE);
4393961b263Sstephan     // Extended Result Codes
4403961b263Sstephan     DefInt(SQLITE_ERROR_MISSING_COLLSEQ);
4413961b263Sstephan     DefInt(SQLITE_ERROR_RETRY);
4423961b263Sstephan     DefInt(SQLITE_ERROR_SNAPSHOT);
4433961b263Sstephan     DefInt(SQLITE_IOERR_READ);
4443961b263Sstephan     DefInt(SQLITE_IOERR_SHORT_READ);
4453961b263Sstephan     DefInt(SQLITE_IOERR_WRITE);
4463961b263Sstephan     DefInt(SQLITE_IOERR_FSYNC);
4473961b263Sstephan     DefInt(SQLITE_IOERR_DIR_FSYNC);
4483961b263Sstephan     DefInt(SQLITE_IOERR_TRUNCATE);
4493961b263Sstephan     DefInt(SQLITE_IOERR_FSTAT);
4503961b263Sstephan     DefInt(SQLITE_IOERR_UNLOCK);
4513961b263Sstephan     DefInt(SQLITE_IOERR_RDLOCK);
4523961b263Sstephan     DefInt(SQLITE_IOERR_DELETE);
4533961b263Sstephan     DefInt(SQLITE_IOERR_BLOCKED);
4543961b263Sstephan     DefInt(SQLITE_IOERR_NOMEM);
4553961b263Sstephan     DefInt(SQLITE_IOERR_ACCESS);
4563961b263Sstephan     DefInt(SQLITE_IOERR_CHECKRESERVEDLOCK);
4573961b263Sstephan     DefInt(SQLITE_IOERR_LOCK);
4583961b263Sstephan     DefInt(SQLITE_IOERR_CLOSE);
4593961b263Sstephan     DefInt(SQLITE_IOERR_DIR_CLOSE);
4603961b263Sstephan     DefInt(SQLITE_IOERR_SHMOPEN);
4613961b263Sstephan     DefInt(SQLITE_IOERR_SHMSIZE);
4623961b263Sstephan     DefInt(SQLITE_IOERR_SHMLOCK);
4633961b263Sstephan     DefInt(SQLITE_IOERR_SHMMAP);
4643961b263Sstephan     DefInt(SQLITE_IOERR_SEEK);
4653961b263Sstephan     DefInt(SQLITE_IOERR_DELETE_NOENT);
4663961b263Sstephan     DefInt(SQLITE_IOERR_MMAP);
4673961b263Sstephan     DefInt(SQLITE_IOERR_GETTEMPPATH);
4683961b263Sstephan     DefInt(SQLITE_IOERR_CONVPATH);
4693961b263Sstephan     DefInt(SQLITE_IOERR_VNODE);
4703961b263Sstephan     DefInt(SQLITE_IOERR_AUTH);
4713961b263Sstephan     DefInt(SQLITE_IOERR_BEGIN_ATOMIC);
4723961b263Sstephan     DefInt(SQLITE_IOERR_COMMIT_ATOMIC);
4733961b263Sstephan     DefInt(SQLITE_IOERR_ROLLBACK_ATOMIC);
4743961b263Sstephan     DefInt(SQLITE_IOERR_DATA);
4753961b263Sstephan     DefInt(SQLITE_IOERR_CORRUPTFS);
4763961b263Sstephan     DefInt(SQLITE_LOCKED_SHAREDCACHE);
4773961b263Sstephan     DefInt(SQLITE_LOCKED_VTAB);
4783961b263Sstephan     DefInt(SQLITE_BUSY_RECOVERY);
4793961b263Sstephan     DefInt(SQLITE_BUSY_SNAPSHOT);
4803961b263Sstephan     DefInt(SQLITE_BUSY_TIMEOUT);
4813961b263Sstephan     DefInt(SQLITE_CANTOPEN_NOTEMPDIR);
4823961b263Sstephan     DefInt(SQLITE_CANTOPEN_ISDIR);
4833961b263Sstephan     DefInt(SQLITE_CANTOPEN_FULLPATH);
4843961b263Sstephan     DefInt(SQLITE_CANTOPEN_CONVPATH);
4853961b263Sstephan     //DefInt(SQLITE_CANTOPEN_DIRTYWAL)/*docs say not used*/;
4863961b263Sstephan     DefInt(SQLITE_CANTOPEN_SYMLINK);
4873961b263Sstephan     DefInt(SQLITE_CORRUPT_VTAB);
4883961b263Sstephan     DefInt(SQLITE_CORRUPT_SEQUENCE);
4893961b263Sstephan     DefInt(SQLITE_CORRUPT_INDEX);
4903961b263Sstephan     DefInt(SQLITE_READONLY_RECOVERY);
4913961b263Sstephan     DefInt(SQLITE_READONLY_CANTLOCK);
4923961b263Sstephan     DefInt(SQLITE_READONLY_ROLLBACK);
4933961b263Sstephan     DefInt(SQLITE_READONLY_DBMOVED);
4943961b263Sstephan     DefInt(SQLITE_READONLY_CANTINIT);
4953961b263Sstephan     DefInt(SQLITE_READONLY_DIRECTORY);
4963961b263Sstephan     DefInt(SQLITE_ABORT_ROLLBACK);
4973961b263Sstephan     DefInt(SQLITE_CONSTRAINT_CHECK);
4983961b263Sstephan     DefInt(SQLITE_CONSTRAINT_COMMITHOOK);
4993961b263Sstephan     DefInt(SQLITE_CONSTRAINT_FOREIGNKEY);
5003961b263Sstephan     DefInt(SQLITE_CONSTRAINT_FUNCTION);
5013961b263Sstephan     DefInt(SQLITE_CONSTRAINT_NOTNULL);
5023961b263Sstephan     DefInt(SQLITE_CONSTRAINT_PRIMARYKEY);
5033961b263Sstephan     DefInt(SQLITE_CONSTRAINT_TRIGGER);
5043961b263Sstephan     DefInt(SQLITE_CONSTRAINT_UNIQUE);
5053961b263Sstephan     DefInt(SQLITE_CONSTRAINT_VTAB);
5063961b263Sstephan     DefInt(SQLITE_CONSTRAINT_ROWID);
5073961b263Sstephan     DefInt(SQLITE_CONSTRAINT_PINNED);
5083961b263Sstephan     DefInt(SQLITE_CONSTRAINT_DATATYPE);
5093961b263Sstephan     DefInt(SQLITE_NOTICE_RECOVER_WAL);
5103961b263Sstephan     DefInt(SQLITE_NOTICE_RECOVER_ROLLBACK);
5113961b263Sstephan     DefInt(SQLITE_WARNING_AUTOINDEX);
5123961b263Sstephan     DefInt(SQLITE_AUTH_USER);
5133961b263Sstephan     DefInt(SQLITE_OK_LOAD_PERMANENTLY);
5143961b263Sstephan     //DefInt(SQLITE_OK_SYMLINK) /* internal use only */;
5153961b263Sstephan   } _DefGroup;
5163961b263Sstephan 
51753d4e01dSstephan   DefGroup(serialize){
51832781427Sstephan     DefInt(SQLITE_SERIALIZE_NOCOPY);
51953d4e01dSstephan     DefInt(SQLITE_DESERIALIZE_FREEONCLOSE);
52053d4e01dSstephan     DefInt(SQLITE_DESERIALIZE_READONLY);
52153d4e01dSstephan     DefInt(SQLITE_DESERIALIZE_RESIZEABLE);
5223961b263Sstephan   } _DefGroup;
5233961b263Sstephan 
5243961b263Sstephan   DefGroup(syncFlags) {
5253961b263Sstephan     DefInt(SQLITE_SYNC_NORMAL);
5263961b263Sstephan     DefInt(SQLITE_SYNC_FULL);
5273961b263Sstephan     DefInt(SQLITE_SYNC_DATAONLY);
5283961b263Sstephan   } _DefGroup;
5293961b263Sstephan 
53053d4e01dSstephan   DefGroup(udfFlags) {
53153d4e01dSstephan     DefInt(SQLITE_DETERMINISTIC);
53253d4e01dSstephan     DefInt(SQLITE_DIRECTONLY);
53353d4e01dSstephan     DefInt(SQLITE_INNOCUOUS);
5343961b263Sstephan   } _DefGroup;
5353961b263Sstephan 
53653d4e01dSstephan   DefGroup(version) {
53753d4e01dSstephan     DefInt(SQLITE_VERSION_NUMBER);
53853d4e01dSstephan     DefStr(SQLITE_VERSION);
53953d4e01dSstephan     DefStr(SQLITE_SOURCE_ID);
5403961b263Sstephan   } _DefGroup;
5413961b263Sstephan 
5423961b263Sstephan #undef DefGroup
5433961b263Sstephan #undef DefStr
5443961b263Sstephan #undef DefInt
5453961b263Sstephan #undef _DefGroup
5463961b263Sstephan 
5473961b263Sstephan   /*
5483961b263Sstephan   ** Emit an array of "StructBinder" struct descripions, which look
5493961b263Sstephan   ** like:
5503961b263Sstephan   **
5513961b263Sstephan   ** {
5523961b263Sstephan   **   "name": "MyStruct",
5533961b263Sstephan   **   "sizeof": 16,
5543961b263Sstephan   **   "members": {
5553961b263Sstephan   **     "member1": {"offset": 0,"sizeof": 4,"signature": "i"},
5563961b263Sstephan   **     "member2": {"offset": 4,"sizeof": 4,"signature": "p"},
5573961b263Sstephan   **     "member3": {"offset": 8,"sizeof": 8,"signature": "j"}
5583961b263Sstephan   **   }
5593961b263Sstephan   ** }
5603961b263Sstephan   **
5612315e834Sstephan   ** Detailed documentation for those bits are in the docs for the
5622315e834Sstephan   ** Jaccwabyt JS-side component.
5633961b263Sstephan   */
5643961b263Sstephan 
5653961b263Sstephan   /** Macros for emitting StructBinder description. */
5663961b263Sstephan #define StructBinder__(TYPE)                 \
5673961b263Sstephan   n = 0;                                     \
5683961b263Sstephan   outf("%s{", (structCount++ ? ", " : ""));  \
5693961b263Sstephan   out("\"name\": \"" # TYPE "\",");         \
5703961b263Sstephan   outf("\"sizeof\": %d", (int)sizeof(TYPE)); \
5713961b263Sstephan   out(",\"members\": {");
5723961b263Sstephan #define StructBinder_(T) StructBinder__(T)
5733961b263Sstephan   /** ^^^ indirection needed to expand CurrentStruct */
5743961b263Sstephan #define StructBinder StructBinder_(CurrentStruct)
5753961b263Sstephan #define _StructBinder CloseBrace(2)
5763961b263Sstephan #define M(MEMBER,SIG)                                         \
5773961b263Sstephan   outf("%s\"%s\": "                                           \
5783961b263Sstephan        "{\"offset\":%d,\"sizeof\": %d,\"signature\":\"%s\"}", \
5793961b263Sstephan        (n++ ? ", " : ""), #MEMBER,                            \
5803961b263Sstephan        (int)offsetof(CurrentStruct,MEMBER),                   \
5813961b263Sstephan        (int)sizeof(((CurrentStruct*)0)->MEMBER),              \
5823961b263Sstephan        SIG)
5833961b263Sstephan 
5843961b263Sstephan   structCount = 0;
5853961b263Sstephan   out(", \"structs\": ["); {
5863961b263Sstephan 
5873961b263Sstephan #define CurrentStruct sqlite3_vfs
5883961b263Sstephan     StructBinder {
5893961b263Sstephan       M(iVersion,"i");
5903961b263Sstephan       M(szOsFile,"i");
5913961b263Sstephan       M(mxPathname,"i");
5923961b263Sstephan       M(pNext,"p");
5933961b263Sstephan       M(zName,"s");
5943961b263Sstephan       M(pAppData,"p");
5953961b263Sstephan       M(xOpen,"i(pppip)");
5963961b263Sstephan       M(xDelete,"i(ppi)");
5973961b263Sstephan       M(xAccess,"i(ppip)");
5983961b263Sstephan       M(xFullPathname,"i(ppip)");
5993961b263Sstephan       M(xDlOpen,"p(pp)");
6003961b263Sstephan       M(xDlError,"p(pip)");
6013961b263Sstephan       M(xDlSym,"p()");
6023961b263Sstephan       M(xDlClose,"v(pp)");
6033961b263Sstephan       M(xRandomness,"i(pip)");
6043961b263Sstephan       M(xSleep,"i(pi)");
6053961b263Sstephan       M(xCurrentTime,"i(pp)");
6063961b263Sstephan       M(xGetLastError,"i(pip)");
6073961b263Sstephan       M(xCurrentTimeInt64,"i(pp)");
6083961b263Sstephan       M(xSetSystemCall,"i(ppp)");
6093961b263Sstephan       M(xGetSystemCall,"p(pp)");
6103961b263Sstephan       M(xNextSystemCall,"p(pp)");
6113961b263Sstephan     } _StructBinder;
6123961b263Sstephan #undef CurrentStruct
6133961b263Sstephan 
6143961b263Sstephan #define CurrentStruct sqlite3_io_methods
6153961b263Sstephan     StructBinder {
6163961b263Sstephan       M(iVersion,"i");
6173961b263Sstephan       M(xClose,"i(p)");
618*bdfd7ea0Sstephan       M(xRead,"i(ppij)");
619*bdfd7ea0Sstephan       M(xWrite,"i(ppij)");
620*bdfd7ea0Sstephan       M(xTruncate,"i(pj)");
6213961b263Sstephan       M(xSync,"i(pi)");
6223961b263Sstephan       M(xFileSize,"i(pp)");
6233961b263Sstephan       M(xLock,"i(pi)");
6243961b263Sstephan       M(xUnlock,"i(pi)");
6253961b263Sstephan       M(xCheckReservedLock,"i(pp)");
6263961b263Sstephan       M(xFileControl,"i(pip)");
6273961b263Sstephan       M(xSectorSize,"i(p)");
6283961b263Sstephan       M(xDeviceCharacteristics,"i(p)");
6293961b263Sstephan       M(xShmMap,"i(piiip)");
6303961b263Sstephan       M(xShmLock,"i(piii)");
6313961b263Sstephan       M(xShmBarrier,"v(p)");
6323961b263Sstephan       M(xShmUnmap,"i(pi)");
633*bdfd7ea0Sstephan       M(xFetch,"i(pjip)");
634*bdfd7ea0Sstephan       M(xUnfetch,"i(pjp)");
6353961b263Sstephan     } _StructBinder;
6363961b263Sstephan #undef CurrentStruct
6373961b263Sstephan 
6383961b263Sstephan #define CurrentStruct sqlite3_file
6393961b263Sstephan     StructBinder {
6406a643e4bSstephan       M(pMethods,"p");
6413961b263Sstephan     } _StructBinder;
6423961b263Sstephan #undef CurrentStruct
6433961b263Sstephan 
6443961b263Sstephan   } out( "]"/*structs*/);
6453961b263Sstephan 
6463961b263Sstephan   out("}"/*top-level object*/);
6473961b263Sstephan   *pos = 0;
6483961b263Sstephan   strBuf[0] = '{'/*end of the race-condition workaround*/;
6493961b263Sstephan   return strBuf;
6503961b263Sstephan #undef StructBinder
6513961b263Sstephan #undef StructBinder_
6523961b263Sstephan #undef StructBinder__
6533961b263Sstephan #undef M
6543961b263Sstephan #undef _StructBinder
6553961b263Sstephan #undef CloseBrace
6563961b263Sstephan #undef out
6573961b263Sstephan #undef outf
6583961b263Sstephan #undef lenCheck
6593961b263Sstephan }
660a579f440Sstephan 
661a579f440Sstephan /*
662a579f440Sstephan ** This function is NOT part of the sqlite3 public API. It is strictly
663a579f440Sstephan ** for use by the sqlite project's own JS/WASM bindings.
664a579f440Sstephan **
665a579f440Sstephan ** This function invokes the xDelete method of the default VFS,
666a579f440Sstephan ** passing on the given filename. If zName is NULL, no default VFS is
667a579f440Sstephan ** found, or it has no xDelete method, SQLITE_MISUSE is returned, else
668a579f440Sstephan ** the result of the xDelete() call is returned.
669a579f440Sstephan */
67073079dbaSstephan WASM_KEEP
671a579f440Sstephan int sqlite3_wasm_vfs_unlink(const char * zName){
672a579f440Sstephan   int rc = SQLITE_MISUSE /* ??? */;
673a579f440Sstephan   sqlite3_vfs * const pVfs = sqlite3_vfs_find(0);
67463e9ec2fSstephan #if defined(__EMSCRIPTEN__)
67563e9ec2fSstephan   emscripten_console_warn("sqlite3_wasm_vfs_unlink() will be removed.");
67663e9ec2fSstephan #endif
677a579f440Sstephan   if( zName && pVfs && pVfs->xDelete ){
678a579f440Sstephan     rc = pVfs->xDelete(pVfs, zName, 1);
679a579f440Sstephan   }
680a579f440Sstephan   return rc;
681a579f440Sstephan }
682a579f440Sstephan 
68332781427Sstephan /*
68432781427Sstephan ** Uses the current database's VFS xRead to stream the db file's
68532781427Sstephan ** contents out to the given callback. The callback gets a single
68632781427Sstephan ** chunk of size n (its 2nd argument) on each call and must return 0
68732781427Sstephan ** on success, non-0 on error. This function returns 0 on success,
68832781427Sstephan ** SQLITE_NOTFOUND if no db is open, or propagates any other non-0
68932781427Sstephan ** code from the callback. Note that this is not thread-friendly: it
69032781427Sstephan ** expects that it will be the only thread reading the db file and
69132781427Sstephan ** takes no measures to ensure that is the case.
69232781427Sstephan **
69332781427Sstephan ** This implementation appears to work fine, but
69432781427Sstephan ** sqlite3_wasm_db_serialize() is arguably the better way to achieve
69532781427Sstephan ** this.
69632781427Sstephan */
69732781427Sstephan WASM_KEEP
69832781427Sstephan int sqlite3_wasm_db_export_chunked( sqlite3* pDb,
69932781427Sstephan                                     int (*xCallback)(unsigned const char *zOut, int n) ){
70032781427Sstephan   sqlite3_int64 nSize = 0;
70132781427Sstephan   sqlite3_int64 nPos = 0;
70232781427Sstephan   sqlite3_file * pFile = 0;
70332781427Sstephan   unsigned char buf[1024 * 8];
70432781427Sstephan   int nBuf = (int)sizeof(buf);
70532781427Sstephan   int rc = pDb
70632781427Sstephan     ? sqlite3_file_control(pDb, "main",
70732781427Sstephan                            SQLITE_FCNTL_FILE_POINTER, &pFile)
70832781427Sstephan     : SQLITE_NOTFOUND;
70932781427Sstephan   if( rc ) return rc;
71032781427Sstephan   rc = pFile->pMethods->xFileSize(pFile, &nSize);
71132781427Sstephan   if( rc ) return rc;
71232781427Sstephan   if(nSize % nBuf){
71332781427Sstephan     /* DB size is not an even multiple of the buffer size. Reduce
71432781427Sstephan     ** buffer size so that we do not unduly inflate the db size
71532781427Sstephan     ** with zero-padding when exporting. */
71632781427Sstephan     if(0 == nSize % 4096) nBuf = 4096;
71732781427Sstephan     else if(0 == nSize % 2048) nBuf = 2048;
71832781427Sstephan     else if(0 == nSize % 1024) nBuf = 1024;
71932781427Sstephan     else nBuf = 512;
72032781427Sstephan   }
72132781427Sstephan   for( ; 0==rc && nPos<nSize; nPos += nBuf ){
72232781427Sstephan     rc = pFile->pMethods->xRead(pFile, buf, nBuf, nPos);
72332781427Sstephan     if(SQLITE_IOERR_SHORT_READ == rc){
72432781427Sstephan       rc = (nPos + nBuf) < nSize ? rc : 0/*assume EOF*/;
72532781427Sstephan     }
72632781427Sstephan     if( 0==rc ) rc = xCallback(buf, nBuf);
72732781427Sstephan   }
72832781427Sstephan   return rc;
72932781427Sstephan }
73032781427Sstephan 
73132781427Sstephan /*
73232781427Sstephan ** A proxy for sqlite3_serialize() which serializes the "main" schema
73332781427Sstephan ** of pDb, placing the serialized output in pOut and nOut. nOut may be
73432781427Sstephan ** NULL. If pDb or pOut are NULL then SQLITE_MISUSE is returned. If
73532781427Sstephan ** allocation of the serialized copy fails, SQLITE_NOMEM is returned.
73632781427Sstephan ** On success, 0 is returned and `*pOut` will contain a pointer to the
73732781427Sstephan ** memory unless mFlags includes SQLITE_SERIALIZE_NOCOPY and the
73832781427Sstephan ** database has no contiguous memory representation, in which case
73932781427Sstephan ** `*pOut` will be NULL but 0 will be returned.
74032781427Sstephan **
74132781427Sstephan ** If `*pOut` is not NULL, the caller is responsible for passing it to
74232781427Sstephan ** sqlite3_free() to free it.
74332781427Sstephan */
74432781427Sstephan WASM_KEEP
74532781427Sstephan int sqlite3_wasm_db_serialize( sqlite3* pDb, unsigned char **pOut, sqlite3_int64 * nOut,
74632781427Sstephan                                unsigned int mFlags ){
74732781427Sstephan   unsigned char * z;
74832781427Sstephan   if( !pDb || !pOut ) return SQLITE_MISUSE;
74932781427Sstephan   if(nOut) *nOut = 0;
75032781427Sstephan   z = sqlite3_serialize(pDb, "main", nOut, mFlags);
75132781427Sstephan   if( z || (SQLITE_SERIALIZE_NOCOPY & mFlags) ){
75232781427Sstephan     *pOut = z;
75332781427Sstephan     return 0;
75432781427Sstephan   }else{
75532781427Sstephan     return SQLITE_NOMEM;
75632781427Sstephan   }
75732781427Sstephan }
75832781427Sstephan 
75932781427Sstephan 
76063e9ec2fSstephan #if defined(__EMSCRIPTEN__) && defined(SQLITE_WASM_WASMFS)
7615b9973d8Sstephan #include <emscripten/wasmfs.h>
76273079dbaSstephan 
763a579f440Sstephan /*
764a579f440Sstephan ** This function is NOT part of the sqlite3 public API. It is strictly
765e3cd6760Sstephan ** for use by the sqlite project's own JS/WASM bindings, specifically
766e3cd6760Sstephan ** only when building with Emscripten's WASMFS support.
767a579f440Sstephan **
768a579f440Sstephan ** This function should only be called if the JS side detects the
769a579f440Sstephan ** existence of the Origin-Private FileSystem (OPFS) APIs in the
770a579f440Sstephan ** client. The first time it is called, this function instantiates a
771a579f440Sstephan ** WASMFS backend impl for OPFS. On success, subsequent calls are
772a579f440Sstephan ** no-ops.
773a579f440Sstephan **
774e3cd6760Sstephan ** This function may be passed a "mount point" name, which must have a
775e3cd6760Sstephan ** leading "/" and is currently restricted to a single path component,
776e3cd6760Sstephan ** e.g. "/foo" is legal but "/foo/" and "/foo/bar" are not. If it is
777e3cd6760Sstephan ** NULL or empty, it defaults to "/persistent".
778e3cd6760Sstephan **
7799a4c63b0Sstephan ** Returns 0 on success, SQLITE_NOMEM if instantiation of the backend
780e3cd6760Sstephan ** object fails, SQLITE_IOERR if mkdir() of the zMountPoint dir in
78128ef9bddSstephan ** the virtual FS fails. In builds compiled without SQLITE_WASM_WASMFS
7829a4c63b0Sstephan ** defined, SQLITE_NOTFOUND is returned without side effects.
783a579f440Sstephan */
78473079dbaSstephan WASM_KEEP
78528ef9bddSstephan int sqlite3_wasm_init_wasmfs(const char *zMountPoint){
786a579f440Sstephan   static backend_t pOpfs = 0;
7873d645484Sstephan   if( !zMountPoint || !*zMountPoint ) zMountPoint = "/opfs";
788a579f440Sstephan   if( !pOpfs ){
789a579f440Sstephan     pOpfs = wasmfs_create_opfs_backend();
790a579f440Sstephan     if( pOpfs ){
7919a4c63b0Sstephan       emscripten_console_log("Created WASMFS OPFS backend.");
792a579f440Sstephan     }
793a579f440Sstephan   }
7949a4c63b0Sstephan   /** It's not enough to instantiate the backend. We have to create a
7959a4c63b0Sstephan       mountpoint in the VFS and attach the backend to it. */
796e3cd6760Sstephan   if( pOpfs && 0!=access(zMountPoint, F_OK) ){
7979a4c63b0Sstephan     /* mkdir() simply hangs when called from fiddle app. Cause is
7989a4c63b0Sstephan        not yet determined but the hypothesis is an init-order
7999a4c63b0Sstephan        issue. */
800e3cd6760Sstephan     /* Note that this check and is not robust but it will
801e3cd6760Sstephan        hypothetically suffice for the transient wasm-based virtual
802e3cd6760Sstephan        filesystem we're currently running in. */
803e3cd6760Sstephan     const int rc = wasmfs_create_directory(zMountPoint, 0777, pOpfs);
8048fc8b5b3Sstephan     emscripten_console_logf("OPFS mkdir(%s) rc=%d", zMountPoint, rc);
8059a4c63b0Sstephan     if(rc) return SQLITE_IOERR;
8069a4c63b0Sstephan   }
807a579f440Sstephan   return pOpfs ? 0 : SQLITE_NOMEM;
808a579f440Sstephan }
8099a4c63b0Sstephan #else
81073079dbaSstephan WASM_KEEP
8113d645484Sstephan int sqlite3_wasm_init_wasmfs(const char *zUnused){
8125b9973d8Sstephan   emscripten_console_warn("WASMFS OPFS is not compiled in.");
8133d645484Sstephan   if(zUnused){/*unused*/}
8149a4c63b0Sstephan   return SQLITE_NOTFOUND;
8159a4c63b0Sstephan }
81628ef9bddSstephan #endif /* __EMSCRIPTEN__ && SQLITE_WASM_WASMFS */
817d1582296Sstephan 
81873079dbaSstephan #undef WASM_KEEP
819