xref: /sqlite-3.40.0/ext/wasm/api/sqlite3-wasm.c (revision 8d7b4130)
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 **
8b75971e6Sstephan ** At its 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 */
154fbf90eeSstephan #define SQLITE_WASM
16d92c652aSstephan #ifdef SQLITE_WASM_ENABLE_C_TESTS
17d92c652aSstephan /*
18de6186e0Sstephan ** Code blocked off by SQLITE_WASM_TESTS is intended solely for use in
19de6186e0Sstephan ** unit/regression testing. They may be safely omitted from
20de6186e0Sstephan ** client-side builds. The main unit test script, tester1.js, will
21de6186e0Sstephan ** skip related tests if it doesn't find the corresponding functions
22de6186e0Sstephan ** in the WASM exports.
23d92c652aSstephan */
24d92c652aSstephan #  define SQLITE_WASM_TESTS 1
25d92c652aSstephan #else
26d92c652aSstephan #  define SQLITE_WASM_TESTS 0
27d92c652aSstephan #endif
284fbf90eeSstephan 
2953d4e01dSstephan /*
3053d4e01dSstephan ** Threading and file locking: JS is single-threaded. Each Worker
3153d4e01dSstephan ** thread is a separate instance of the JS engine so can never access
3253d4e01dSstephan ** the same db handle as another thread, thus multi-threading support
3353d4e01dSstephan ** is unnecessary in the library. Because the filesystems are virtual
3453d4e01dSstephan ** and local to a given wasm runtime instance, two Workers can never
3553d4e01dSstephan ** access the same db file at once, with the exception of OPFS. As of
3653d4e01dSstephan ** this writing (2022-09-30), OPFS exclusively locks a file when
3753d4e01dSstephan ** opening it, so two Workers can never open the same OPFS-backed file
3853d4e01dSstephan ** at once. That situation will change if and when lower-level locking
3953d4e01dSstephan ** features are added to OPFS (as is currently planned, per folks
4053d4e01dSstephan ** involved with its development).
4153d4e01dSstephan **
4253d4e01dSstephan ** Summary: except for the case of future OPFS, which supports
4353d4e01dSstephan ** locking, and any similar future filesystems, threading and file
4453d4e01dSstephan ** locking support are unnecessary in the wasm build.
4553d4e01dSstephan */
46d92c652aSstephan 
47d92c652aSstephan /*
48d92c652aSstephan ** Undefine any SQLITE_... config flags which we specifically do not
49d92c652aSstephan ** want undefined. Please keep these alphabetized.
50d92c652aSstephan */
5153d4e01dSstephan #undef SQLITE_OMIT_DESERIALIZE
5296b6371dSstephan #undef SQLITE_OMIT_MEMORYDB
53d92c652aSstephan 
54d92c652aSstephan /*
55d92c652aSstephan ** Define any SQLITE_... config defaults we want if they aren't
56d92c652aSstephan ** overridden by the builder. Please keep these alphabetized.
57d92c652aSstephan */
58d92c652aSstephan 
59d92c652aSstephan /**********************************************************************/
603725af73Sstephan /* SQLITE_D... */
6188838f6bSstephan #ifndef SQLITE_DEFAULT_CACHE_SIZE
6288838f6bSstephan /*
6388838f6bSstephan ** The OPFS impls benefit tremendously from an increased cache size
6488838f6bSstephan ** when working on large workloads, e.g. speedtest1 --size 50 or
6588838f6bSstephan ** higher. On smaller workloads, e.g. speedtest1 --size 25, they
6688838f6bSstephan ** clearly benefit from having 4mb of cache, but not as much as a
6788838f6bSstephan ** larger cache benefits the larger workloads. Speed differences
6888838f6bSstephan ** between 2x and nearly 3x have been measured with ample page cache.
6988838f6bSstephan */
70*c7544508Sstephan # define SQLITE_DEFAULT_CACHE_SIZE -16384
7188838f6bSstephan #endif
72d92c652aSstephan #if 0 && !defined(SQLITE_DEFAULT_PAGE_SIZE)
73d92c652aSstephan /* TODO: experiment with this. */
7488838f6bSstephan # define SQLITE_DEFAULT_PAGE_SIZE 8192 /*4096*/
7588838f6bSstephan #endif
76d92c652aSstephan #ifndef SQLITE_DEFAULT_UNIX_VFS
77d92c652aSstephan # define SQLITE_DEFAULT_UNIX_VFS "unix-none"
78d92c652aSstephan #endif
793725af73Sstephan #undef SQLITE_DQS
803725af73Sstephan #define SQLITE_DQS 0
81d92c652aSstephan 
82d92c652aSstephan /**********************************************************************/
83d92c652aSstephan /* SQLITE_ENABLE_... */
84d92c652aSstephan #ifndef SQLITE_ENABLE_BYTECODE_VTAB
85d92c652aSstephan #  define SQLITE_ENABLE_BYTECODE_VTAB 1
86d92c652aSstephan #endif
87d92c652aSstephan #ifndef SQLITE_ENABLE_DBPAGE_VTAB
88d92c652aSstephan #  define SQLITE_ENABLE_DBPAGE_VTAB 1
89d92c652aSstephan #endif
90d92c652aSstephan #ifndef SQLITE_ENABLE_DBSTAT_VTAB
91d92c652aSstephan #  define SQLITE_ENABLE_DBSTAT_VTAB 1
92d92c652aSstephan #endif
93d92c652aSstephan #ifndef SQLITE_ENABLE_EXPLAIN_COMMENTS
94d92c652aSstephan #  define SQLITE_ENABLE_EXPLAIN_COMMENTS 1
95d92c652aSstephan #endif
96d92c652aSstephan #ifndef SQLITE_ENABLE_FTS4
97d92c652aSstephan #  define SQLITE_ENABLE_FTS4 1
98d92c652aSstephan #endif
99d92c652aSstephan #ifndef SQLITE_ENABLE_OFFSET_SQL_FUNC
100d92c652aSstephan #  define SQLITE_ENABLE_OFFSET_SQL_FUNC 1
101d92c652aSstephan #endif
102d92c652aSstephan #ifndef SQLITE_ENABLE_RTREE
103d92c652aSstephan #  define SQLITE_ENABLE_RTREE 1
104d92c652aSstephan #endif
105d92c652aSstephan #ifndef SQLITE_ENABLE_STMTVTAB
106d92c652aSstephan #  define SQLITE_ENABLE_STMTVTAB 1
107d92c652aSstephan #endif
108d92c652aSstephan #ifndef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
109d92c652aSstephan #  define SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
110d92c652aSstephan #endif
111d92c652aSstephan 
112d92c652aSstephan /**********************************************************************/
113d92c652aSstephan /* SQLITE_O... */
114d92c652aSstephan #ifndef SQLITE_OMIT_DEPRECATED
115d92c652aSstephan # define SQLITE_OMIT_DEPRECATED 1
116d92c652aSstephan #endif
117d92c652aSstephan #ifndef SQLITE_OMIT_LOAD_EXTENSION
118d92c652aSstephan # define SQLITE_OMIT_LOAD_EXTENSION 1
119d92c652aSstephan #endif
120d92c652aSstephan #ifndef SQLITE_OMIT_SHARED_CACHE
121d92c652aSstephan # define SQLITE_OMIT_SHARED_CACHE 1
122d92c652aSstephan #endif
123d92c652aSstephan #ifndef SQLITE_OMIT_UTF16
124d92c652aSstephan # define SQLITE_OMIT_UTF16 1
125d92c652aSstephan #endif
126d92c652aSstephan #ifndef SQLITE_OMIT_WAL
127d92c652aSstephan # define SQLITE_OMIT_WAL 1
128d92c652aSstephan #endif
129d92c652aSstephan #ifndef SQLITE_OS_KV_OPTIONAL
130d92c652aSstephan # define SQLITE_OS_KV_OPTIONAL 1
131d92c652aSstephan #endif
132d92c652aSstephan 
133d92c652aSstephan /**********************************************************************/
134d92c652aSstephan /* SQLITE_T... */
135d92c652aSstephan #ifndef SQLITE_TEMP_STORE
136d92c652aSstephan # define SQLITE_TEMP_STORE 3
137d92c652aSstephan #endif
138d92c652aSstephan #ifndef SQLITE_THREADSAFE
139d92c652aSstephan # define SQLITE_THREADSAFE 0
140d92c652aSstephan #endif
141d92c652aSstephan 
142d92c652aSstephan /**********************************************************************/
143d92c652aSstephan /* SQLITE_USE_... */
144d92c652aSstephan #ifndef SQLITE_USE_URI
145d92c652aSstephan #  define SQLITE_USE_URI 1
14688838f6bSstephan #endif
1476110a5d0Sstephan 
1483afad4d4Sstephan #include <assert.h>
1496110a5d0Sstephan #include "sqlite3.c" /* yes, .c instead of .h. */
1503961b263Sstephan 
15163e9ec2fSstephan #if defined(__EMSCRIPTEN__)
15263e9ec2fSstephan #  include <emscripten/console.h>
15363e9ec2fSstephan #endif
15463e9ec2fSstephan 
1553961b263Sstephan /*
156d92c652aSstephan ** SQLITE_WASM_KEEP is functionally identical to EMSCRIPTEN_KEEPALIVE
157d92c652aSstephan ** but is not Emscripten-specific. It explicitly marks functions for
158d92c652aSstephan ** export into the target wasm file without requiring explicit listing
159d92c652aSstephan ** of those functions in Emscripten's -sEXPORTED_FUNCTIONS=... list
160d92c652aSstephan ** (or equivalent in other build platforms). Any function with neither
16173079dbaSstephan ** this attribute nor which is listed as an explicit export will not
16273079dbaSstephan ** be exported from the wasm file (but may still be used internally
16373079dbaSstephan ** within the wasm file).
16473079dbaSstephan **
16573079dbaSstephan ** The functions in this file (sqlite3-wasm.c) which require exporting
16673079dbaSstephan ** are marked with this flag. They may also be added to any explicit
16773079dbaSstephan ** build-time export list but need not be. All of these APIs are
16873079dbaSstephan ** intended for use only within the project's own JS/WASM code, and
16973079dbaSstephan ** not by client code, so an argument can be made for reducing their
17073079dbaSstephan ** visibility by not including them in any build-time export lists.
17173079dbaSstephan **
17273079dbaSstephan ** 2022-09-11: it's not yet _proven_ that this approach works in
17373079dbaSstephan ** non-Emscripten builds. If not, such builds will need to export
17473079dbaSstephan ** those using the --export=... wasm-ld flag (or equivalent). As of
17573079dbaSstephan ** this writing we are tied to Emscripten for various reasons
17673079dbaSstephan ** and cannot test the library with other build environments.
17773079dbaSstephan */
178b75971e6Sstephan #define SQLITE_WASM_KEEP __attribute__((used,visibility("default")))
17973079dbaSstephan // See also:
18073079dbaSstephan //__attribute__((export_name("theExportedName"), used, visibility("default")))
18173079dbaSstephan 
1823afad4d4Sstephan 
1833afad4d4Sstephan #if 0
1843afad4d4Sstephan /*
1853afad4d4Sstephan ** An EXPERIMENT in implementing a stack-based allocator analog to
1863afad4d4Sstephan ** Emscripten's stackSave(), stackAlloc(), stackRestore().
1873afad4d4Sstephan ** Unfortunately, this cannot work together with Emscripten because
1883afad4d4Sstephan ** Emscripten defines its own native one and we'd stomp on each
1893afad4d4Sstephan ** other's memory. Other than that complication, basic tests show it
1903afad4d4Sstephan ** to work just fine.
1913afad4d4Sstephan **
1923afad4d4Sstephan ** Another option is to malloc() a chunk of our own and call that our
1933afad4d4Sstephan ** "stack".
1943afad4d4Sstephan */
195b75971e6Sstephan SQLITE_WASM_KEEP void * sqlite3_wasm_stack_end(void){
1963afad4d4Sstephan   extern void __heap_base
1973afad4d4Sstephan     /* see https://stackoverflow.com/questions/10038964 */;
1983afad4d4Sstephan   return &__heap_base;
1993afad4d4Sstephan }
200b75971e6Sstephan SQLITE_WASM_KEEP void * sqlite3_wasm_stack_begin(void){
2013afad4d4Sstephan   extern void __data_end;
2023afad4d4Sstephan   return &__data_end;
2033afad4d4Sstephan }
2042b776ee2Sstephan static void * pWasmStackPtr = 0;
205b75971e6Sstephan SQLITE_WASM_KEEP void * sqlite3_wasm_stack_ptr(void){
2062b776ee2Sstephan   if(!pWasmStackPtr) pWasmStackPtr = sqlite3_wasm_stack_end();
2072b776ee2Sstephan   return pWasmStackPtr;
2083afad4d4Sstephan }
209b75971e6Sstephan SQLITE_WASM_KEEP void sqlite3_wasm_stack_restore(void * p){
2102b776ee2Sstephan   pWasmStackPtr = p;
2113afad4d4Sstephan }
212b75971e6Sstephan SQLITE_WASM_KEEP void * sqlite3_wasm_stack_alloc(int n){
2133afad4d4Sstephan   if(n<=0) return 0;
2143afad4d4Sstephan   n = (n + 7) & ~7 /* align to 8-byte boundary */;
2153afad4d4Sstephan   unsigned char * const p = (unsigned char *)sqlite3_wasm_stack_ptr();
2163afad4d4Sstephan   unsigned const char * const b = (unsigned const char *)sqlite3_wasm_stack_begin();
2173afad4d4Sstephan   if(b + n >= p || b + n < b/*overflow*/) return 0;
2182b776ee2Sstephan   return pWasmStackPtr = p - n;
2193afad4d4Sstephan }
2203afad4d4Sstephan #endif /* stack allocator experiment */
2213afad4d4Sstephan 
2223afad4d4Sstephan /*
2233afad4d4Sstephan ** State for the "pseudo-stack" allocator implemented in
2243afad4d4Sstephan ** sqlite3_wasm_pstack_xyz(). In order to avoid colliding with
2253afad4d4Sstephan ** Emscripten-controled stack space, it carves out a bit of stack
2263afad4d4Sstephan ** memory to use for that purpose. This memory ends up in the
2273afad4d4Sstephan ** WASM-managed memory, such that routines which manipulate the wasm
2283afad4d4Sstephan ** heap can also be used to manipulate this memory.
22988838f6bSstephan **
23088838f6bSstephan ** This particular allocator is intended for small allocations such as
23188838f6bSstephan ** storage for output pointers. We cannot reasonably size it large
23288838f6bSstephan ** enough for general-purpose string conversions because some of our
23388838f6bSstephan ** tests use input files (strings) of 16MB+.
2343afad4d4Sstephan */
2353afad4d4Sstephan static unsigned char PStack_mem[512 * 8] = {0};
2363afad4d4Sstephan static struct {
237f446af57Sstephan   unsigned const char * const pBegin;/* Start (inclusive) of memory */
238f446af57Sstephan   unsigned const char * const pEnd;  /* One-after-the-end of memory */
239f446af57Sstephan   unsigned char * pPos;              /* Current stack pointer */
2403afad4d4Sstephan } PStack = {
2413afad4d4Sstephan   &PStack_mem[0],
2423afad4d4Sstephan   &PStack_mem[0] + sizeof(PStack_mem),
2433afad4d4Sstephan   &PStack_mem[0] + sizeof(PStack_mem)
2443afad4d4Sstephan };
2453afad4d4Sstephan /*
2463afad4d4Sstephan ** Returns the current pstack position.
2473afad4d4Sstephan */
sqlite3_wasm_pstack_ptr(void)248b75971e6Sstephan SQLITE_WASM_KEEP void * sqlite3_wasm_pstack_ptr(void){
2493afad4d4Sstephan   return PStack.pPos;
2503afad4d4Sstephan }
2513afad4d4Sstephan /*
2523afad4d4Sstephan ** Sets the pstack position poitner to p. Results are undefined if the
2533afad4d4Sstephan ** given value did not come from sqlite3_wasm_pstack_ptr().
2543afad4d4Sstephan */
sqlite3_wasm_pstack_restore(unsigned char * p)255b75971e6Sstephan SQLITE_WASM_KEEP void sqlite3_wasm_pstack_restore(unsigned char * p){
2563afad4d4Sstephan   assert(p>=PStack.pBegin && p<=PStack.pEnd && p>=PStack.pPos);
2573afad4d4Sstephan   assert(0==(p & 0x7));
2583afad4d4Sstephan   if(p>=PStack.pBegin && p<=PStack.pEnd /*&& p>=PStack.pPos*/){
2593afad4d4Sstephan     PStack.pPos = p;
2603afad4d4Sstephan   }
2613afad4d4Sstephan }
2623afad4d4Sstephan /*
2633afad4d4Sstephan ** Allocate and zero out n bytes from the pstack. Returns a pointer to
2643afad4d4Sstephan ** the memory on success, 0 on error (including a negative n value). n
2653afad4d4Sstephan ** is always adjusted to be a multiple of 8 and returned memory is
2663afad4d4Sstephan ** always zeroed out before returning (because this keeps the client
2673afad4d4Sstephan ** JS code from having to do so, and most uses of the pstack will
2683afad4d4Sstephan ** call for doing so).
2693afad4d4Sstephan */
sqlite3_wasm_pstack_alloc(int n)270b75971e6Sstephan SQLITE_WASM_KEEP void * sqlite3_wasm_pstack_alloc(int n){
2713afad4d4Sstephan   if( n<=0 ) return 0;
2723afad4d4Sstephan   //if( n & 0x7 ) n += 8 - (n & 0x7) /* align to 8-byte boundary */;
2733afad4d4Sstephan   n = (n + 7) & ~7 /* align to 8-byte boundary */;
2742b776ee2Sstephan   if( PStack.pBegin + n > PStack.pPos /*not enough space left*/
2752b776ee2Sstephan       || PStack.pBegin + n <= PStack.pBegin /*overflow*/ ) return 0;
2762b776ee2Sstephan   memset((PStack.pPos = PStack.pPos - n), 0, (unsigned int)n);
2773afad4d4Sstephan   return PStack.pPos;
2783afad4d4Sstephan }
2793afad4d4Sstephan /*
2803afad4d4Sstephan ** Return the number of bytes left which can be
2813afad4d4Sstephan ** sqlite3_wasm_pstack_alloc()'d.
2823afad4d4Sstephan */
sqlite3_wasm_pstack_remaining(void)283b75971e6Sstephan SQLITE_WASM_KEEP int sqlite3_wasm_pstack_remaining(void){
2843afad4d4Sstephan   assert(PStack.pPos >= PStack.pBegin);
2853afad4d4Sstephan   assert(PStack.pPos <= PStack.pEnd);
2863afad4d4Sstephan   return (int)(PStack.pPos - PStack.pBegin);
2873afad4d4Sstephan }
2883afad4d4Sstephan 
2892b776ee2Sstephan /*
2902b776ee2Sstephan ** Return the total number of bytes available in the pstack, including
2912b776ee2Sstephan ** any space which is currently allocated. This value is a
2922b776ee2Sstephan ** compile-time constant.
2932b776ee2Sstephan */
sqlite3_wasm_pstack_quota(void)294b75971e6Sstephan SQLITE_WASM_KEEP int sqlite3_wasm_pstack_quota(void){
2952b776ee2Sstephan   return (int)(PStack.pEnd - PStack.pBegin);
2962b776ee2Sstephan }
2973afad4d4Sstephan 
29873079dbaSstephan /*
2993961b263Sstephan ** This function is NOT part of the sqlite3 public API. It is strictly
3003961b263Sstephan ** for use by the sqlite project's own JS/WASM bindings.
3013961b263Sstephan **
3023961b263Sstephan ** For purposes of certain hand-crafted C/Wasm function bindings, we
3033961b263Sstephan ** need a way of reporting errors which is consistent with the rest of
304e1c34624Sstephan ** the C API, as opposed to throwing JS exceptions. To that end, this
305e1c34624Sstephan ** internal-use-only function is a thin proxy around
306e1c34624Sstephan ** sqlite3ErrorWithMessage(). The intent is that it only be used from
307e1c34624Sstephan ** Wasm bindings such as sqlite3_prepare_v2/v3(), and definitely not
308e1c34624Sstephan ** from client code.
3093961b263Sstephan **
3103961b263Sstephan ** Returns err_code.
3113961b263Sstephan */
312b75971e6Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_db_error(sqlite3 * db,int err_code,const char * zMsg)31373079dbaSstephan int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
3143961b263Sstephan   if( 0!=zMsg ){
3153961b263Sstephan     const int nMsg = sqlite3Strlen30(zMsg);
3163961b263Sstephan     sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg);
3173961b263Sstephan   }else{
3183961b263Sstephan     sqlite3ErrorWithMsg(db, err_code, NULL);
3193961b263Sstephan   }
3203961b263Sstephan   return err_code;
3213961b263Sstephan }
3223961b263Sstephan 
323d92c652aSstephan #if SQLITE_WASM_TESTS
324d92c652aSstephan struct WasmTestStruct {
325d92c652aSstephan   int v4;
326d92c652aSstephan   void * ppV;
327d92c652aSstephan   const char * cstr;
328d92c652aSstephan   int64_t v8;
329d92c652aSstephan   void (*xFunc)(void*);
330d92c652aSstephan };
331d92c652aSstephan typedef struct WasmTestStruct WasmTestStruct;
332d92c652aSstephan SQLITE_WASM_KEEP
sqlite3_wasm_test_struct(WasmTestStruct * s)333d92c652aSstephan void sqlite3_wasm_test_struct(WasmTestStruct * s){
334d92c652aSstephan   if(s){
335d92c652aSstephan     s->v4 *= 2;
336d92c652aSstephan     s->v8 = s->v4 * 2;
337d92c652aSstephan     s->ppV = s;
338d92c652aSstephan     s->cstr = __FILE__;
339d92c652aSstephan     if(s->xFunc) s->xFunc(s);
340d92c652aSstephan   }
341d92c652aSstephan   return;
342d92c652aSstephan }
343d92c652aSstephan #endif /* SQLITE_WASM_TESTS */
344d92c652aSstephan 
3453961b263Sstephan /*
3463961b263Sstephan ** This function is NOT part of the sqlite3 public API. It is strictly
3473961b263Sstephan ** for use by the sqlite project's own JS/WASM bindings. Unlike the
3483961b263Sstephan ** rest of the sqlite3 API, this part requires C99 for snprintf() and
3493961b263Sstephan ** variadic macros.
3503961b263Sstephan **
3513961b263Sstephan ** Returns a string containing a JSON-format "enum" of C-level
3522b776ee2Sstephan ** constants and struct-related metadata intended to be imported into
3532b776ee2Sstephan ** the JS environment. The JSON is initialized the first time this
3542b776ee2Sstephan ** function is called and that result is reused for all future calls.
3553961b263Sstephan **
3563961b263Sstephan ** If this function returns NULL then it means that the internal
3572b776ee2Sstephan ** buffer is not large enough for the generated JSON and needs to be
3582b776ee2Sstephan ** increased. In debug builds that will trigger an assert().
3593961b263Sstephan */
360b75971e6Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_enum_json(void)3613961b263Sstephan const char * sqlite3_wasm_enum_json(void){
3622b776ee2Sstephan   static char aBuffer[1024 * 12] = {0} /* where the JSON goes */;
36388838f6bSstephan   int n = 0, nChildren = 0, nStruct = 0
3643961b263Sstephan     /* output counters for figuring out where commas go */;
3652b776ee2Sstephan   char * zPos = &aBuffer[1] /* skip first byte for now to help protect
3663961b263Sstephan                           ** against a small race condition */;
3672b776ee2Sstephan   char const * const zEnd = &aBuffer[0] + sizeof(aBuffer) /* one-past-the-end */;
3682b776ee2Sstephan   if(aBuffer[0]) return aBuffer;
3692b776ee2Sstephan   /* Leave aBuffer[0] at 0 until the end to help guard against a tiny
3703961b263Sstephan   ** race condition. If this is called twice concurrently, they might
3712b776ee2Sstephan   ** end up both writing to aBuffer, but they'll both write the same
3723961b263Sstephan   ** thing, so that's okay. If we set byte 0 up front then the 2nd
3733961b263Sstephan   ** instance might return and use the string before the 1st instance
3743961b263Sstephan   ** is done filling it. */
3753961b263Sstephan 
3763961b263Sstephan /* Core output macros... */
37788838f6bSstephan #define lenCheck assert(zPos < zEnd - 128 \
3783961b263Sstephan   && "sqlite3_wasm_enum_json() buffer is too small."); \
37988838f6bSstephan   if( zPos >= zEnd - 128 ) return 0
3803961b263Sstephan #define outf(format,...) \
38188838f6bSstephan   zPos += snprintf(zPos, ((size_t)(zEnd - zPos)), format, __VA_ARGS__); \
3823961b263Sstephan   lenCheck
3833961b263Sstephan #define out(TXT) outf("%s",TXT)
3843961b263Sstephan #define CloseBrace(LEVEL) \
38588838f6bSstephan   assert(LEVEL<5); memset(zPos, '}', LEVEL); zPos+=LEVEL; lenCheck
3863961b263Sstephan 
3873961b263Sstephan /* Macros for emitting maps of integer- and string-type macros to
3883961b263Sstephan ** their values. */
3893961b263Sstephan #define DefGroup(KEY) n = 0; \
39088838f6bSstephan   outf("%s\"" #KEY "\": {",(nChildren++ ? "," : ""));
3913961b263Sstephan #define DefInt(KEY)                                     \
3923961b263Sstephan   outf("%s\"%s\": %d", (n++ ? ", " : ""), #KEY, (int)KEY)
3933961b263Sstephan #define DefStr(KEY)                                     \
3943961b263Sstephan   outf("%s\"%s\": \"%s\"", (n++ ? ", " : ""), #KEY, KEY)
3953961b263Sstephan #define _DefGroup CloseBrace(1)
3963961b263Sstephan 
39753d4e01dSstephan   /* The following groups are sorted alphabetic by group name. */
39853d4e01dSstephan   DefGroup(access){
39953d4e01dSstephan     DefInt(SQLITE_ACCESS_EXISTS);
40053d4e01dSstephan     DefInt(SQLITE_ACCESS_READWRITE);
40153d4e01dSstephan     DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/;
40253d4e01dSstephan   } _DefGroup;
40353d4e01dSstephan 
40453d4e01dSstephan   DefGroup(blobFinalizers) {
40553d4e01dSstephan     /* SQLITE_STATIC/TRANSIENT need to be handled explicitly as
40653d4e01dSstephan     ** integers to avoid casting-related warnings. */
40753d4e01dSstephan     out("\"SQLITE_STATIC\":0, \"SQLITE_TRANSIENT\":-1");
40853d4e01dSstephan   } _DefGroup;
40953d4e01dSstephan 
41053d4e01dSstephan   DefGroup(dataTypes) {
41153d4e01dSstephan     DefInt(SQLITE_INTEGER);
41253d4e01dSstephan     DefInt(SQLITE_FLOAT);
41353d4e01dSstephan     DefInt(SQLITE_TEXT);
41453d4e01dSstephan     DefInt(SQLITE_BLOB);
41553d4e01dSstephan     DefInt(SQLITE_NULL);
41653d4e01dSstephan   } _DefGroup;
41753d4e01dSstephan 
41853d4e01dSstephan   DefGroup(encodings) {
41953d4e01dSstephan     /* Noting that the wasm binding only aims to support UTF-8. */
42053d4e01dSstephan     DefInt(SQLITE_UTF8);
42153d4e01dSstephan     DefInt(SQLITE_UTF16LE);
42253d4e01dSstephan     DefInt(SQLITE_UTF16BE);
42353d4e01dSstephan     DefInt(SQLITE_UTF16);
42453d4e01dSstephan     /*deprecated DefInt(SQLITE_ANY); */
42553d4e01dSstephan     DefInt(SQLITE_UTF16_ALIGNED);
42653d4e01dSstephan   } _DefGroup;
42753d4e01dSstephan 
42853d4e01dSstephan   DefGroup(fcntl) {
42953d4e01dSstephan     DefInt(SQLITE_FCNTL_LOCKSTATE);
43053d4e01dSstephan     DefInt(SQLITE_FCNTL_GET_LOCKPROXYFILE);
43153d4e01dSstephan     DefInt(SQLITE_FCNTL_SET_LOCKPROXYFILE);
43253d4e01dSstephan     DefInt(SQLITE_FCNTL_LAST_ERRNO);
43353d4e01dSstephan     DefInt(SQLITE_FCNTL_SIZE_HINT);
43453d4e01dSstephan     DefInt(SQLITE_FCNTL_CHUNK_SIZE);
43553d4e01dSstephan     DefInt(SQLITE_FCNTL_FILE_POINTER);
43653d4e01dSstephan     DefInt(SQLITE_FCNTL_SYNC_OMITTED);
43753d4e01dSstephan     DefInt(SQLITE_FCNTL_WIN32_AV_RETRY);
43853d4e01dSstephan     DefInt(SQLITE_FCNTL_PERSIST_WAL);
43953d4e01dSstephan     DefInt(SQLITE_FCNTL_OVERWRITE);
44053d4e01dSstephan     DefInt(SQLITE_FCNTL_VFSNAME);
44153d4e01dSstephan     DefInt(SQLITE_FCNTL_POWERSAFE_OVERWRITE);
44253d4e01dSstephan     DefInt(SQLITE_FCNTL_PRAGMA);
44353d4e01dSstephan     DefInt(SQLITE_FCNTL_BUSYHANDLER);
44453d4e01dSstephan     DefInt(SQLITE_FCNTL_TEMPFILENAME);
44553d4e01dSstephan     DefInt(SQLITE_FCNTL_MMAP_SIZE);
44653d4e01dSstephan     DefInt(SQLITE_FCNTL_TRACE);
44753d4e01dSstephan     DefInt(SQLITE_FCNTL_HAS_MOVED);
44853d4e01dSstephan     DefInt(SQLITE_FCNTL_SYNC);
44953d4e01dSstephan     DefInt(SQLITE_FCNTL_COMMIT_PHASETWO);
45053d4e01dSstephan     DefInt(SQLITE_FCNTL_WIN32_SET_HANDLE);
45153d4e01dSstephan     DefInt(SQLITE_FCNTL_WAL_BLOCK);
45253d4e01dSstephan     DefInt(SQLITE_FCNTL_ZIPVFS);
45353d4e01dSstephan     DefInt(SQLITE_FCNTL_RBU);
45453d4e01dSstephan     DefInt(SQLITE_FCNTL_VFS_POINTER);
45553d4e01dSstephan     DefInt(SQLITE_FCNTL_JOURNAL_POINTER);
45653d4e01dSstephan     DefInt(SQLITE_FCNTL_WIN32_GET_HANDLE);
45753d4e01dSstephan     DefInt(SQLITE_FCNTL_PDB);
45853d4e01dSstephan     DefInt(SQLITE_FCNTL_BEGIN_ATOMIC_WRITE);
45953d4e01dSstephan     DefInt(SQLITE_FCNTL_COMMIT_ATOMIC_WRITE);
46053d4e01dSstephan     DefInt(SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE);
46153d4e01dSstephan     DefInt(SQLITE_FCNTL_LOCK_TIMEOUT);
46253d4e01dSstephan     DefInt(SQLITE_FCNTL_DATA_VERSION);
46353d4e01dSstephan     DefInt(SQLITE_FCNTL_SIZE_LIMIT);
46453d4e01dSstephan     DefInt(SQLITE_FCNTL_CKPT_DONE);
46553d4e01dSstephan     DefInt(SQLITE_FCNTL_RESERVE_BYTES);
46653d4e01dSstephan     DefInt(SQLITE_FCNTL_CKPT_START);
46753d4e01dSstephan     DefInt(SQLITE_FCNTL_EXTERNAL_READER);
46853d4e01dSstephan     DefInt(SQLITE_FCNTL_CKSM_FILE);
46953d4e01dSstephan   } _DefGroup;
47053d4e01dSstephan 
47153d4e01dSstephan   DefGroup(flock) {
47253d4e01dSstephan     DefInt(SQLITE_LOCK_NONE);
47353d4e01dSstephan     DefInt(SQLITE_LOCK_SHARED);
47453d4e01dSstephan     DefInt(SQLITE_LOCK_RESERVED);
47553d4e01dSstephan     DefInt(SQLITE_LOCK_PENDING);
47653d4e01dSstephan     DefInt(SQLITE_LOCK_EXCLUSIVE);
47753d4e01dSstephan   } _DefGroup;
47853d4e01dSstephan 
47953d4e01dSstephan   DefGroup(ioCap) {
48053d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC);
48153d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC512);
48253d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC1K);
48353d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC2K);
48453d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC4K);
48553d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC8K);
48653d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC16K);
48753d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC32K);
48853d4e01dSstephan     DefInt(SQLITE_IOCAP_ATOMIC64K);
48953d4e01dSstephan     DefInt(SQLITE_IOCAP_SAFE_APPEND);
49053d4e01dSstephan     DefInt(SQLITE_IOCAP_SEQUENTIAL);
49153d4e01dSstephan     DefInt(SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN);
49253d4e01dSstephan     DefInt(SQLITE_IOCAP_POWERSAFE_OVERWRITE);
49353d4e01dSstephan     DefInt(SQLITE_IOCAP_IMMUTABLE);
49453d4e01dSstephan     DefInt(SQLITE_IOCAP_BATCH_ATOMIC);
49553d4e01dSstephan   } _DefGroup;
49653d4e01dSstephan 
49753d4e01dSstephan   DefGroup(openFlags) {
49853d4e01dSstephan     /* Noting that not all of these will have any effect in
49953d4e01dSstephan     ** WASM-space. */
50053d4e01dSstephan     DefInt(SQLITE_OPEN_READONLY);
50153d4e01dSstephan     DefInt(SQLITE_OPEN_READWRITE);
50253d4e01dSstephan     DefInt(SQLITE_OPEN_CREATE);
50353d4e01dSstephan     DefInt(SQLITE_OPEN_URI);
50453d4e01dSstephan     DefInt(SQLITE_OPEN_MEMORY);
50553d4e01dSstephan     DefInt(SQLITE_OPEN_NOMUTEX);
50653d4e01dSstephan     DefInt(SQLITE_OPEN_FULLMUTEX);
50753d4e01dSstephan     DefInt(SQLITE_OPEN_SHAREDCACHE);
50853d4e01dSstephan     DefInt(SQLITE_OPEN_PRIVATECACHE);
50953d4e01dSstephan     DefInt(SQLITE_OPEN_EXRESCODE);
51053d4e01dSstephan     DefInt(SQLITE_OPEN_NOFOLLOW);
51153d4e01dSstephan     /* OPEN flags for use with VFSes... */
51253d4e01dSstephan     DefInt(SQLITE_OPEN_MAIN_DB);
51353d4e01dSstephan     DefInt(SQLITE_OPEN_MAIN_JOURNAL);
51453d4e01dSstephan     DefInt(SQLITE_OPEN_TEMP_DB);
51553d4e01dSstephan     DefInt(SQLITE_OPEN_TEMP_JOURNAL);
51653d4e01dSstephan     DefInt(SQLITE_OPEN_TRANSIENT_DB);
51753d4e01dSstephan     DefInt(SQLITE_OPEN_SUBJOURNAL);
51853d4e01dSstephan     DefInt(SQLITE_OPEN_SUPER_JOURNAL);
51953d4e01dSstephan     DefInt(SQLITE_OPEN_WAL);
52053d4e01dSstephan     DefInt(SQLITE_OPEN_DELETEONCLOSE);
52153d4e01dSstephan     DefInt(SQLITE_OPEN_EXCLUSIVE);
52253d4e01dSstephan   } _DefGroup;
52353d4e01dSstephan 
52453d4e01dSstephan   DefGroup(prepareFlags) {
52553d4e01dSstephan     DefInt(SQLITE_PREPARE_PERSISTENT);
52653d4e01dSstephan     DefInt(SQLITE_PREPARE_NORMALIZE);
52753d4e01dSstephan     DefInt(SQLITE_PREPARE_NO_VTAB);
5283961b263Sstephan   } _DefGroup;
5293961b263Sstephan 
5303961b263Sstephan   DefGroup(resultCodes) {
5313961b263Sstephan     DefInt(SQLITE_OK);
5323961b263Sstephan     DefInt(SQLITE_ERROR);
5333961b263Sstephan     DefInt(SQLITE_INTERNAL);
5343961b263Sstephan     DefInt(SQLITE_PERM);
5353961b263Sstephan     DefInt(SQLITE_ABORT);
5363961b263Sstephan     DefInt(SQLITE_BUSY);
5373961b263Sstephan     DefInt(SQLITE_LOCKED);
5383961b263Sstephan     DefInt(SQLITE_NOMEM);
5393961b263Sstephan     DefInt(SQLITE_READONLY);
5403961b263Sstephan     DefInt(SQLITE_INTERRUPT);
5413961b263Sstephan     DefInt(SQLITE_IOERR);
5423961b263Sstephan     DefInt(SQLITE_CORRUPT);
5433961b263Sstephan     DefInt(SQLITE_NOTFOUND);
5443961b263Sstephan     DefInt(SQLITE_FULL);
5453961b263Sstephan     DefInt(SQLITE_CANTOPEN);
5463961b263Sstephan     DefInt(SQLITE_PROTOCOL);
5473961b263Sstephan     DefInt(SQLITE_EMPTY);
5483961b263Sstephan     DefInt(SQLITE_SCHEMA);
5493961b263Sstephan     DefInt(SQLITE_TOOBIG);
5503961b263Sstephan     DefInt(SQLITE_CONSTRAINT);
5513961b263Sstephan     DefInt(SQLITE_MISMATCH);
5523961b263Sstephan     DefInt(SQLITE_MISUSE);
5533961b263Sstephan     DefInt(SQLITE_NOLFS);
5543961b263Sstephan     DefInt(SQLITE_AUTH);
5553961b263Sstephan     DefInt(SQLITE_FORMAT);
5563961b263Sstephan     DefInt(SQLITE_RANGE);
5573961b263Sstephan     DefInt(SQLITE_NOTADB);
5583961b263Sstephan     DefInt(SQLITE_NOTICE);
5593961b263Sstephan     DefInt(SQLITE_WARNING);
5603961b263Sstephan     DefInt(SQLITE_ROW);
5613961b263Sstephan     DefInt(SQLITE_DONE);
5623961b263Sstephan     // Extended Result Codes
5633961b263Sstephan     DefInt(SQLITE_ERROR_MISSING_COLLSEQ);
5643961b263Sstephan     DefInt(SQLITE_ERROR_RETRY);
5653961b263Sstephan     DefInt(SQLITE_ERROR_SNAPSHOT);
5663961b263Sstephan     DefInt(SQLITE_IOERR_READ);
5673961b263Sstephan     DefInt(SQLITE_IOERR_SHORT_READ);
5683961b263Sstephan     DefInt(SQLITE_IOERR_WRITE);
5693961b263Sstephan     DefInt(SQLITE_IOERR_FSYNC);
5703961b263Sstephan     DefInt(SQLITE_IOERR_DIR_FSYNC);
5713961b263Sstephan     DefInt(SQLITE_IOERR_TRUNCATE);
5723961b263Sstephan     DefInt(SQLITE_IOERR_FSTAT);
5733961b263Sstephan     DefInt(SQLITE_IOERR_UNLOCK);
5743961b263Sstephan     DefInt(SQLITE_IOERR_RDLOCK);
5753961b263Sstephan     DefInt(SQLITE_IOERR_DELETE);
5763961b263Sstephan     DefInt(SQLITE_IOERR_BLOCKED);
5773961b263Sstephan     DefInt(SQLITE_IOERR_NOMEM);
5783961b263Sstephan     DefInt(SQLITE_IOERR_ACCESS);
5793961b263Sstephan     DefInt(SQLITE_IOERR_CHECKRESERVEDLOCK);
5803961b263Sstephan     DefInt(SQLITE_IOERR_LOCK);
5813961b263Sstephan     DefInt(SQLITE_IOERR_CLOSE);
5823961b263Sstephan     DefInt(SQLITE_IOERR_DIR_CLOSE);
5833961b263Sstephan     DefInt(SQLITE_IOERR_SHMOPEN);
5843961b263Sstephan     DefInt(SQLITE_IOERR_SHMSIZE);
5853961b263Sstephan     DefInt(SQLITE_IOERR_SHMLOCK);
5863961b263Sstephan     DefInt(SQLITE_IOERR_SHMMAP);
5873961b263Sstephan     DefInt(SQLITE_IOERR_SEEK);
5883961b263Sstephan     DefInt(SQLITE_IOERR_DELETE_NOENT);
5893961b263Sstephan     DefInt(SQLITE_IOERR_MMAP);
5903961b263Sstephan     DefInt(SQLITE_IOERR_GETTEMPPATH);
5913961b263Sstephan     DefInt(SQLITE_IOERR_CONVPATH);
5923961b263Sstephan     DefInt(SQLITE_IOERR_VNODE);
5933961b263Sstephan     DefInt(SQLITE_IOERR_AUTH);
5943961b263Sstephan     DefInt(SQLITE_IOERR_BEGIN_ATOMIC);
5953961b263Sstephan     DefInt(SQLITE_IOERR_COMMIT_ATOMIC);
5963961b263Sstephan     DefInt(SQLITE_IOERR_ROLLBACK_ATOMIC);
5973961b263Sstephan     DefInt(SQLITE_IOERR_DATA);
5983961b263Sstephan     DefInt(SQLITE_IOERR_CORRUPTFS);
5993961b263Sstephan     DefInt(SQLITE_LOCKED_SHAREDCACHE);
6003961b263Sstephan     DefInt(SQLITE_LOCKED_VTAB);
6013961b263Sstephan     DefInt(SQLITE_BUSY_RECOVERY);
6023961b263Sstephan     DefInt(SQLITE_BUSY_SNAPSHOT);
6033961b263Sstephan     DefInt(SQLITE_BUSY_TIMEOUT);
6043961b263Sstephan     DefInt(SQLITE_CANTOPEN_NOTEMPDIR);
6053961b263Sstephan     DefInt(SQLITE_CANTOPEN_ISDIR);
6063961b263Sstephan     DefInt(SQLITE_CANTOPEN_FULLPATH);
6073961b263Sstephan     DefInt(SQLITE_CANTOPEN_CONVPATH);
6083961b263Sstephan     //DefInt(SQLITE_CANTOPEN_DIRTYWAL)/*docs say not used*/;
6093961b263Sstephan     DefInt(SQLITE_CANTOPEN_SYMLINK);
6103961b263Sstephan     DefInt(SQLITE_CORRUPT_VTAB);
6113961b263Sstephan     DefInt(SQLITE_CORRUPT_SEQUENCE);
6123961b263Sstephan     DefInt(SQLITE_CORRUPT_INDEX);
6133961b263Sstephan     DefInt(SQLITE_READONLY_RECOVERY);
6143961b263Sstephan     DefInt(SQLITE_READONLY_CANTLOCK);
6153961b263Sstephan     DefInt(SQLITE_READONLY_ROLLBACK);
6163961b263Sstephan     DefInt(SQLITE_READONLY_DBMOVED);
6173961b263Sstephan     DefInt(SQLITE_READONLY_CANTINIT);
6183961b263Sstephan     DefInt(SQLITE_READONLY_DIRECTORY);
6193961b263Sstephan     DefInt(SQLITE_ABORT_ROLLBACK);
6203961b263Sstephan     DefInt(SQLITE_CONSTRAINT_CHECK);
6213961b263Sstephan     DefInt(SQLITE_CONSTRAINT_COMMITHOOK);
6223961b263Sstephan     DefInt(SQLITE_CONSTRAINT_FOREIGNKEY);
6233961b263Sstephan     DefInt(SQLITE_CONSTRAINT_FUNCTION);
6243961b263Sstephan     DefInt(SQLITE_CONSTRAINT_NOTNULL);
6253961b263Sstephan     DefInt(SQLITE_CONSTRAINT_PRIMARYKEY);
6263961b263Sstephan     DefInt(SQLITE_CONSTRAINT_TRIGGER);
6273961b263Sstephan     DefInt(SQLITE_CONSTRAINT_UNIQUE);
6283961b263Sstephan     DefInt(SQLITE_CONSTRAINT_VTAB);
6293961b263Sstephan     DefInt(SQLITE_CONSTRAINT_ROWID);
6303961b263Sstephan     DefInt(SQLITE_CONSTRAINT_PINNED);
6313961b263Sstephan     DefInt(SQLITE_CONSTRAINT_DATATYPE);
6323961b263Sstephan     DefInt(SQLITE_NOTICE_RECOVER_WAL);
6333961b263Sstephan     DefInt(SQLITE_NOTICE_RECOVER_ROLLBACK);
6343961b263Sstephan     DefInt(SQLITE_WARNING_AUTOINDEX);
6353961b263Sstephan     DefInt(SQLITE_AUTH_USER);
6363961b263Sstephan     DefInt(SQLITE_OK_LOAD_PERMANENTLY);
6373961b263Sstephan     //DefInt(SQLITE_OK_SYMLINK) /* internal use only */;
6383961b263Sstephan   } _DefGroup;
6393961b263Sstephan 
64053d4e01dSstephan   DefGroup(serialize){
64132781427Sstephan     DefInt(SQLITE_SERIALIZE_NOCOPY);
64253d4e01dSstephan     DefInt(SQLITE_DESERIALIZE_FREEONCLOSE);
64353d4e01dSstephan     DefInt(SQLITE_DESERIALIZE_READONLY);
64453d4e01dSstephan     DefInt(SQLITE_DESERIALIZE_RESIZEABLE);
6453961b263Sstephan   } _DefGroup;
6463961b263Sstephan 
6473961b263Sstephan   DefGroup(syncFlags) {
6483961b263Sstephan     DefInt(SQLITE_SYNC_NORMAL);
6493961b263Sstephan     DefInt(SQLITE_SYNC_FULL);
6503961b263Sstephan     DefInt(SQLITE_SYNC_DATAONLY);
6513961b263Sstephan   } _DefGroup;
6523961b263Sstephan 
6534f5bbedbSstephan   DefGroup(trace) {
6544f5bbedbSstephan     DefInt(SQLITE_TRACE_STMT);
6554f5bbedbSstephan     DefInt(SQLITE_TRACE_PROFILE);
6564f5bbedbSstephan     DefInt(SQLITE_TRACE_ROW);
6574f5bbedbSstephan     DefInt(SQLITE_TRACE_CLOSE);
6584f5bbedbSstephan   } _DefGroup;
6594f5bbedbSstephan 
66053d4e01dSstephan   DefGroup(udfFlags) {
66153d4e01dSstephan     DefInt(SQLITE_DETERMINISTIC);
66253d4e01dSstephan     DefInt(SQLITE_DIRECTONLY);
66353d4e01dSstephan     DefInt(SQLITE_INNOCUOUS);
6643961b263Sstephan   } _DefGroup;
6653961b263Sstephan 
66653d4e01dSstephan   DefGroup(version) {
66753d4e01dSstephan     DefInt(SQLITE_VERSION_NUMBER);
66853d4e01dSstephan     DefStr(SQLITE_VERSION);
66953d4e01dSstephan     DefStr(SQLITE_SOURCE_ID);
6703961b263Sstephan   } _DefGroup;
6713961b263Sstephan 
6723961b263Sstephan #undef DefGroup
6733961b263Sstephan #undef DefStr
6743961b263Sstephan #undef DefInt
6753961b263Sstephan #undef _DefGroup
6763961b263Sstephan 
6773961b263Sstephan   /*
6783961b263Sstephan   ** Emit an array of "StructBinder" struct descripions, which look
6793961b263Sstephan   ** like:
6803961b263Sstephan   **
6813961b263Sstephan   ** {
6823961b263Sstephan   **   "name": "MyStruct",
6833961b263Sstephan   **   "sizeof": 16,
6843961b263Sstephan   **   "members": {
6853961b263Sstephan   **     "member1": {"offset": 0,"sizeof": 4,"signature": "i"},
6863961b263Sstephan   **     "member2": {"offset": 4,"sizeof": 4,"signature": "p"},
6873961b263Sstephan   **     "member3": {"offset": 8,"sizeof": 8,"signature": "j"}
6883961b263Sstephan   **   }
6893961b263Sstephan   ** }
6903961b263Sstephan   **
6912315e834Sstephan   ** Detailed documentation for those bits are in the docs for the
6922315e834Sstephan   ** Jaccwabyt JS-side component.
6933961b263Sstephan   */
6943961b263Sstephan 
6953961b263Sstephan   /** Macros for emitting StructBinder description. */
6963961b263Sstephan #define StructBinder__(TYPE)                 \
6973961b263Sstephan   n = 0;                                     \
69888838f6bSstephan   outf("%s{", (nStruct++ ? ", " : ""));  \
6993961b263Sstephan   out("\"name\": \"" # TYPE "\",");         \
7003961b263Sstephan   outf("\"sizeof\": %d", (int)sizeof(TYPE)); \
7013961b263Sstephan   out(",\"members\": {");
7023961b263Sstephan #define StructBinder_(T) StructBinder__(T)
7033961b263Sstephan   /** ^^^ indirection needed to expand CurrentStruct */
7043961b263Sstephan #define StructBinder StructBinder_(CurrentStruct)
7053961b263Sstephan #define _StructBinder CloseBrace(2)
7063961b263Sstephan #define M(MEMBER,SIG)                                         \
7073961b263Sstephan   outf("%s\"%s\": "                                           \
7083961b263Sstephan        "{\"offset\":%d,\"sizeof\": %d,\"signature\":\"%s\"}", \
7093961b263Sstephan        (n++ ? ", " : ""), #MEMBER,                            \
7103961b263Sstephan        (int)offsetof(CurrentStruct,MEMBER),                   \
7113961b263Sstephan        (int)sizeof(((CurrentStruct*)0)->MEMBER),              \
7123961b263Sstephan        SIG)
7133961b263Sstephan 
71488838f6bSstephan   nStruct = 0;
7153961b263Sstephan   out(", \"structs\": ["); {
7163961b263Sstephan 
7173961b263Sstephan #define CurrentStruct sqlite3_vfs
7183961b263Sstephan     StructBinder {
7193961b263Sstephan       M(iVersion,"i");
7203961b263Sstephan       M(szOsFile,"i");
7213961b263Sstephan       M(mxPathname,"i");
7223961b263Sstephan       M(pNext,"p");
7233961b263Sstephan       M(zName,"s");
7243961b263Sstephan       M(pAppData,"p");
7253961b263Sstephan       M(xOpen,"i(pppip)");
7263961b263Sstephan       M(xDelete,"i(ppi)");
7273961b263Sstephan       M(xAccess,"i(ppip)");
7283961b263Sstephan       M(xFullPathname,"i(ppip)");
7293961b263Sstephan       M(xDlOpen,"p(pp)");
7303961b263Sstephan       M(xDlError,"p(pip)");
7313961b263Sstephan       M(xDlSym,"p()");
7323961b263Sstephan       M(xDlClose,"v(pp)");
7333961b263Sstephan       M(xRandomness,"i(pip)");
7343961b263Sstephan       M(xSleep,"i(pi)");
7353961b263Sstephan       M(xCurrentTime,"i(pp)");
7363961b263Sstephan       M(xGetLastError,"i(pip)");
7373961b263Sstephan       M(xCurrentTimeInt64,"i(pp)");
7383961b263Sstephan       M(xSetSystemCall,"i(ppp)");
7393961b263Sstephan       M(xGetSystemCall,"p(pp)");
7403961b263Sstephan       M(xNextSystemCall,"p(pp)");
7413961b263Sstephan     } _StructBinder;
7423961b263Sstephan #undef CurrentStruct
7433961b263Sstephan 
7443961b263Sstephan #define CurrentStruct sqlite3_io_methods
7453961b263Sstephan     StructBinder {
7463961b263Sstephan       M(iVersion,"i");
7473961b263Sstephan       M(xClose,"i(p)");
748bdfd7ea0Sstephan       M(xRead,"i(ppij)");
749bdfd7ea0Sstephan       M(xWrite,"i(ppij)");
750bdfd7ea0Sstephan       M(xTruncate,"i(pj)");
7513961b263Sstephan       M(xSync,"i(pi)");
7523961b263Sstephan       M(xFileSize,"i(pp)");
7533961b263Sstephan       M(xLock,"i(pi)");
7543961b263Sstephan       M(xUnlock,"i(pi)");
7553961b263Sstephan       M(xCheckReservedLock,"i(pp)");
7563961b263Sstephan       M(xFileControl,"i(pip)");
7573961b263Sstephan       M(xSectorSize,"i(p)");
7583961b263Sstephan       M(xDeviceCharacteristics,"i(p)");
7593961b263Sstephan       M(xShmMap,"i(piiip)");
7603961b263Sstephan       M(xShmLock,"i(piii)");
7613961b263Sstephan       M(xShmBarrier,"v(p)");
7623961b263Sstephan       M(xShmUnmap,"i(pi)");
763bdfd7ea0Sstephan       M(xFetch,"i(pjip)");
764bdfd7ea0Sstephan       M(xUnfetch,"i(pjp)");
7653961b263Sstephan     } _StructBinder;
7663961b263Sstephan #undef CurrentStruct
7673961b263Sstephan 
7683961b263Sstephan #define CurrentStruct sqlite3_file
7693961b263Sstephan     StructBinder {
7706a643e4bSstephan       M(pMethods,"p");
7713961b263Sstephan     } _StructBinder;
7723961b263Sstephan #undef CurrentStruct
7733961b263Sstephan 
7744fbf90eeSstephan #define CurrentStruct sqlite3_kvvfs_methods
7754fbf90eeSstephan     StructBinder {
7764fbf90eeSstephan       M(xRead,"i(sspi)");
7774fbf90eeSstephan       M(xWrite,"i(sss)");
7784fbf90eeSstephan       M(xDelete,"i(ss)");
7794fbf90eeSstephan       M(nKeySize,"i");
7804fbf90eeSstephan     } _StructBinder;
781d92c652aSstephan #undef CurrentStruct
782d92c652aSstephan 
783d92c652aSstephan #if SQLITE_WASM_TESTS
784d92c652aSstephan #define CurrentStruct WasmTestStruct
785d92c652aSstephan     StructBinder {
786d92c652aSstephan       M(v4,"i");
787d92c652aSstephan       M(cstr,"s");
788d92c652aSstephan       M(ppV,"p");
789d92c652aSstephan       M(v8,"j");
790d92c652aSstephan       M(xFunc,"v(p)");
791d92c652aSstephan     } _StructBinder;
792d92c652aSstephan #undef CurrentStruct
793d92c652aSstephan #endif
7944fbf90eeSstephan 
7953961b263Sstephan   } out( "]"/*structs*/);
7963961b263Sstephan 
7973961b263Sstephan   out("}"/*top-level object*/);
79888838f6bSstephan   *zPos = 0;
7992b776ee2Sstephan   aBuffer[0] = '{'/*end of the race-condition workaround*/;
8002b776ee2Sstephan   return aBuffer;
8013961b263Sstephan #undef StructBinder
8023961b263Sstephan #undef StructBinder_
8033961b263Sstephan #undef StructBinder__
8043961b263Sstephan #undef M
8053961b263Sstephan #undef _StructBinder
8063961b263Sstephan #undef CloseBrace
8073961b263Sstephan #undef out
8083961b263Sstephan #undef outf
8093961b263Sstephan #undef lenCheck
8103961b263Sstephan }
811a579f440Sstephan 
812a579f440Sstephan /*
813a579f440Sstephan ** This function is NOT part of the sqlite3 public API. It is strictly
814a579f440Sstephan ** for use by the sqlite project's own JS/WASM bindings.
815a579f440Sstephan **
816842c5ee8Sstephan ** This function invokes the xDelete method of the given VFS (or the
817842c5ee8Sstephan ** default VFS if pVfs is NULL), passing on the given filename. If
818842c5ee8Sstephan ** zName is NULL, no default VFS is found, or it has no xDelete
819842c5ee8Sstephan ** method, SQLITE_MISUSE is returned, else the result of the xDelete()
820842c5ee8Sstephan ** call is returned.
821a579f440Sstephan */
822b75971e6Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_vfs_unlink(sqlite3_vfs * pVfs,const char * zName)823842c5ee8Sstephan int sqlite3_wasm_vfs_unlink(sqlite3_vfs *pVfs, const char * zName){
824a579f440Sstephan   int rc = SQLITE_MISUSE /* ??? */;
825842c5ee8Sstephan   if( 0==pVfs && 0!=zName ) pVfs = sqlite3_vfs_find(0);
826a579f440Sstephan   if( zName && pVfs && pVfs->xDelete ){
827a579f440Sstephan     rc = pVfs->xDelete(pVfs, zName, 1);
828a579f440Sstephan   }
829a579f440Sstephan   return rc;
830a579f440Sstephan }
831a579f440Sstephan 
83232781427Sstephan /*
8334f5bbedbSstephan ** This function is NOT part of the sqlite3 public API. It is strictly
8344f5bbedbSstephan ** for use by the sqlite project's own JS/WASM bindings.
8354f5bbedbSstephan **
836842c5ee8Sstephan ** Returns a pointer to the given DB's VFS for the given DB name,
837842c5ee8Sstephan ** defaulting to "main" if zDbName is 0. Returns 0 if no db with the
838842c5ee8Sstephan ** given name is open.
839842c5ee8Sstephan */
840842c5ee8Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_db_vfs(sqlite3 * pDb,const char * zDbName)841842c5ee8Sstephan sqlite3_vfs * sqlite3_wasm_db_vfs(sqlite3 *pDb, const char *zDbName){
842842c5ee8Sstephan   sqlite3_vfs * pVfs = 0;
843842c5ee8Sstephan   sqlite3_file_control(pDb, zDbName ? zDbName : "main",
844842c5ee8Sstephan                        SQLITE_FCNTL_VFS_POINTER, &pVfs);
845842c5ee8Sstephan   return pVfs;
846842c5ee8Sstephan }
847842c5ee8Sstephan 
848842c5ee8Sstephan /*
849842c5ee8Sstephan ** This function is NOT part of the sqlite3 public API. It is strictly
850842c5ee8Sstephan ** for use by the sqlite project's own JS/WASM bindings.
851842c5ee8Sstephan **
8524f5bbedbSstephan ** This function resets the given db pointer's database as described at
8534f5bbedbSstephan **
8544f5bbedbSstephan ** https://www.sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigresetdatabase
8554f5bbedbSstephan **
8564f5bbedbSstephan ** Returns 0 on success, an SQLITE_xxx code on error. Returns
8574f5bbedbSstephan ** SQLITE_MISUSE if pDb is NULL.
8584f5bbedbSstephan */
859b75971e6Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_db_reset(sqlite3 * pDb)8604f5bbedbSstephan int sqlite3_wasm_db_reset(sqlite3*pDb){
8614f5bbedbSstephan   int rc = SQLITE_MISUSE;
8624f5bbedbSstephan   if( pDb ){
8634f5bbedbSstephan     rc = sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
8644f5bbedbSstephan     if( 0==rc ) rc = sqlite3_exec(pDb, "VACUUM", 0, 0, 0);
8654f5bbedbSstephan     sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
8664f5bbedbSstephan   }
8674f5bbedbSstephan   return rc;
8684f5bbedbSstephan }
8694f5bbedbSstephan 
8704f5bbedbSstephan /*
871b75971e6Sstephan ** Uses the given database's VFS xRead to stream the db file's
87232781427Sstephan ** contents out to the given callback. The callback gets a single
87332781427Sstephan ** chunk of size n (its 2nd argument) on each call and must return 0
87432781427Sstephan ** on success, non-0 on error. This function returns 0 on success,
87532781427Sstephan ** SQLITE_NOTFOUND if no db is open, or propagates any other non-0
87632781427Sstephan ** code from the callback. Note that this is not thread-friendly: it
87732781427Sstephan ** expects that it will be the only thread reading the db file and
87832781427Sstephan ** takes no measures to ensure that is the case.
87932781427Sstephan **
88032781427Sstephan ** This implementation appears to work fine, but
88132781427Sstephan ** sqlite3_wasm_db_serialize() is arguably the better way to achieve
88232781427Sstephan ** this.
88332781427Sstephan */
884b75971e6Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_db_export_chunked(sqlite3 * pDb,int (* xCallback)(unsigned const char * zOut,int n))88532781427Sstephan int sqlite3_wasm_db_export_chunked( sqlite3* pDb,
88632781427Sstephan                                     int (*xCallback)(unsigned const char *zOut, int n) ){
88732781427Sstephan   sqlite3_int64 nSize = 0;
88832781427Sstephan   sqlite3_int64 nPos = 0;
88932781427Sstephan   sqlite3_file * pFile = 0;
89032781427Sstephan   unsigned char buf[1024 * 8];
89132781427Sstephan   int nBuf = (int)sizeof(buf);
89232781427Sstephan   int rc = pDb
89332781427Sstephan     ? sqlite3_file_control(pDb, "main",
89432781427Sstephan                            SQLITE_FCNTL_FILE_POINTER, &pFile)
89532781427Sstephan     : SQLITE_NOTFOUND;
89632781427Sstephan   if( rc ) return rc;
89732781427Sstephan   rc = pFile->pMethods->xFileSize(pFile, &nSize);
89832781427Sstephan   if( rc ) return rc;
89932781427Sstephan   if(nSize % nBuf){
90032781427Sstephan     /* DB size is not an even multiple of the buffer size. Reduce
90132781427Sstephan     ** buffer size so that we do not unduly inflate the db size
90232781427Sstephan     ** with zero-padding when exporting. */
90332781427Sstephan     if(0 == nSize % 4096) nBuf = 4096;
90432781427Sstephan     else if(0 == nSize % 2048) nBuf = 2048;
90532781427Sstephan     else if(0 == nSize % 1024) nBuf = 1024;
90632781427Sstephan     else nBuf = 512;
90732781427Sstephan   }
90832781427Sstephan   for( ; 0==rc && nPos<nSize; nPos += nBuf ){
90932781427Sstephan     rc = pFile->pMethods->xRead(pFile, buf, nBuf, nPos);
91032781427Sstephan     if(SQLITE_IOERR_SHORT_READ == rc){
91132781427Sstephan       rc = (nPos + nBuf) < nSize ? rc : 0/*assume EOF*/;
91232781427Sstephan     }
91332781427Sstephan     if( 0==rc ) rc = xCallback(buf, nBuf);
91432781427Sstephan   }
91532781427Sstephan   return rc;
91632781427Sstephan }
91732781427Sstephan 
91832781427Sstephan /*
91932781427Sstephan ** A proxy for sqlite3_serialize() which serializes the "main" schema
92032781427Sstephan ** of pDb, placing the serialized output in pOut and nOut. nOut may be
92132781427Sstephan ** NULL. If pDb or pOut are NULL then SQLITE_MISUSE is returned. If
92232781427Sstephan ** allocation of the serialized copy fails, SQLITE_NOMEM is returned.
92332781427Sstephan ** On success, 0 is returned and `*pOut` will contain a pointer to the
92432781427Sstephan ** memory unless mFlags includes SQLITE_SERIALIZE_NOCOPY and the
92532781427Sstephan ** database has no contiguous memory representation, in which case
92632781427Sstephan ** `*pOut` will be NULL but 0 will be returned.
92732781427Sstephan **
92832781427Sstephan ** If `*pOut` is not NULL, the caller is responsible for passing it to
92932781427Sstephan ** sqlite3_free() to free it.
93032781427Sstephan */
931b75971e6Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_db_serialize(sqlite3 * pDb,unsigned char ** pOut,sqlite3_int64 * nOut,unsigned int mFlags)932b75971e6Sstephan int sqlite3_wasm_db_serialize( sqlite3 *pDb, unsigned char **pOut,
933b75971e6Sstephan                                sqlite3_int64 *nOut, unsigned int mFlags ){
93432781427Sstephan   unsigned char * z;
93532781427Sstephan   if( !pDb || !pOut ) return SQLITE_MISUSE;
93632781427Sstephan   if(nOut) *nOut = 0;
93732781427Sstephan   z = sqlite3_serialize(pDb, "main", nOut, mFlags);
93832781427Sstephan   if( z || (SQLITE_SERIALIZE_NOCOPY & mFlags) ){
93932781427Sstephan     *pOut = z;
94032781427Sstephan     return 0;
94132781427Sstephan   }else{
94232781427Sstephan     return SQLITE_NOMEM;
94332781427Sstephan   }
94432781427Sstephan }
94532781427Sstephan 
9464fbf90eeSstephan /*
9474fbf90eeSstephan ** This function is NOT part of the sqlite3 public API. It is strictly
9484fbf90eeSstephan ** for use by the sqlite project's own JS/WASM bindings.
9494fbf90eeSstephan **
950f45c3370Sstephan ** Creates a new file using the I/O API of the given VFS, containing
951f45c3370Sstephan ** the given number of bytes of the given data. If the file exists,
952f45c3370Sstephan ** it is truncated to the given length and populated with the given
953f45c3370Sstephan ** data.
954f45c3370Sstephan **
955f45c3370Sstephan ** This function exists so that we can implement the equivalent of
956f45c3370Sstephan ** Emscripten's FS.createDataFile() in a VFS-agnostic way. This
957f45c3370Sstephan ** functionality is intended for use in uploading database files.
958f45c3370Sstephan **
959f45c3370Sstephan ** If pVfs is NULL, sqlite3_vfs_find(0) is used.
960f45c3370Sstephan **
961f45c3370Sstephan ** If zFile is NULL, pVfs is NULL (and sqlite3_vfs_find(0) returns
962f45c3370Sstephan ** NULL), or nData is negative, SQLITE_MISUSE are returned.
963f45c3370Sstephan **
964f45c3370Sstephan ** On success, it creates a new file with the given name, populated
965f45c3370Sstephan ** with the fist nData bytes of pData. If pData is NULL, the file is
966f45c3370Sstephan ** created and/or truncated to nData bytes.
967f45c3370Sstephan **
968f45c3370Sstephan ** Whether or not directory components of zFilename are created
969f45c3370Sstephan ** automatically or not is unspecified: that detail is left to the
970f45c3370Sstephan ** VFS. The "opfs" VFS, for example, create them.
971f45c3370Sstephan **
972f45c3370Sstephan ** Not all VFSes support this functionality, e.g. the "kvvfs" does
973f45c3370Sstephan ** not.
974f45c3370Sstephan **
975f45c3370Sstephan ** If an error happens while populating or truncating the file, the
976f45c3370Sstephan ** target file will be deleted (if needed) if this function created
977f45c3370Sstephan ** it. If this function did not create it, it is not deleted but may
978f45c3370Sstephan ** be left in an undefined state.
979f45c3370Sstephan **
980f45c3370Sstephan ** Returns 0 on success. On error, it returns a code described above
981f45c3370Sstephan ** or propagates a code from one of the I/O methods.
982f45c3370Sstephan **
983f45c3370Sstephan ** Design note: nData is an integer, instead of int64, for WASM
984f45c3370Sstephan ** portability, so that the API can still work in builds where BigInt
985f45c3370Sstephan ** support is disabled or unavailable.
986f45c3370Sstephan */
987f45c3370Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_vfs_create_file(sqlite3_vfs * pVfs,const char * zFilename,const unsigned char * pData,int nData)988f45c3370Sstephan int sqlite3_wasm_vfs_create_file( sqlite3_vfs *pVfs,
989f45c3370Sstephan                                   const char *zFilename,
990f45c3370Sstephan                                   const unsigned char * pData,
991f45c3370Sstephan                                   int nData ){
992f45c3370Sstephan   int rc;
993f45c3370Sstephan   sqlite3_file *pFile = 0;
994f45c3370Sstephan   sqlite3_io_methods const *pIo;
995f45c3370Sstephan   const int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
996f45c3370Sstephan   int flagsOut = 0;
997f45c3370Sstephan   int fileExisted = 0;
998f45c3370Sstephan   int doUnlock = 0;
999f45c3370Sstephan   const unsigned char *pPos = pData;
1000f45c3370Sstephan   const int blockSize = 512
1001f45c3370Sstephan     /* Because we are using pFile->pMethods->xWrite() for writing, and
1002f45c3370Sstephan     ** it may have a buffer limit related to sqlite3's pager size, we
1003f45c3370Sstephan     ** conservatively write in 512-byte blocks (smallest page
1004f45c3370Sstephan     ** size). */;
1005f45c3370Sstephan 
1006f45c3370Sstephan   if( !pVfs ) pVfs = sqlite3_vfs_find(0);
1007f45c3370Sstephan   if( !pVfs || !zFilename || nData<0 ) return SQLITE_MISUSE;
1008f45c3370Sstephan   pVfs->xAccess(pVfs, zFilename, SQLITE_ACCESS_EXISTS, &fileExisted);
1009f45c3370Sstephan   rc = sqlite3OsOpenMalloc(pVfs, zFilename, &pFile, openFlags, &flagsOut);
1010f45c3370Sstephan   if(rc) return rc;
1011f45c3370Sstephan   pIo = pFile->pMethods;
1012f45c3370Sstephan   if( pIo->xLock ) {
1013f45c3370Sstephan     /* We need xLock() in order to accommodate the OPFS VFS, as it
1014f45c3370Sstephan     ** obtains a writeable handle via the lock operation and releases
1015f45c3370Sstephan     ** it in xUnlock(). If we don't do those here, we have to add code
1016f45c3370Sstephan     ** to the VFS to account check whether it was locked before
1017f45c3370Sstephan     ** xFileSize(), xTruncate(), and the like, and release the lock
1018f45c3370Sstephan     ** only if it was unlocked when the op was started. */
1019f45c3370Sstephan     rc = pIo->xLock(pFile, SQLITE_LOCK_EXCLUSIVE);
1020f45c3370Sstephan     doUnlock = 0==rc;
1021f45c3370Sstephan   }
1022f45c3370Sstephan   if( 0==rc) rc = pIo->xTruncate(pFile, nData);
1023f45c3370Sstephan   if( 0==rc && 0!=pData && nData>0 ){
1024f45c3370Sstephan     while( 0==rc && nData>0 ){
1025f45c3370Sstephan       const int n = nData>=blockSize ? blockSize : nData;
1026f45c3370Sstephan       rc = pIo->xWrite(pFile, pPos, n, (sqlite3_int64)(pPos - pData));
1027f45c3370Sstephan       nData -= n;
1028f45c3370Sstephan       pPos += n;
1029f45c3370Sstephan     }
1030f45c3370Sstephan     if( 0==rc && nData>0 ){
1031de6186e0Sstephan       assert( nData<blockSize );
1032f45c3370Sstephan       rc = pIo->xWrite(pFile, pPos, nData, (sqlite3_int64)(pPos - pData));
1033f45c3370Sstephan     }
1034f45c3370Sstephan   }
1035f45c3370Sstephan   if( pIo->xUnlock && doUnlock!=0 ) pIo->xUnlock(pFile, SQLITE_LOCK_NONE);
1036f45c3370Sstephan   pIo->xClose(pFile);
1037f45c3370Sstephan   if( rc!=0 && 0==fileExisted ){
1038f45c3370Sstephan     pVfs->xDelete(pVfs, zFilename, 1);
1039f45c3370Sstephan   }
1040f45c3370Sstephan   return rc;
1041f45c3370Sstephan }
1042f45c3370Sstephan 
1043f45c3370Sstephan /*
1044f45c3370Sstephan ** This function is NOT part of the sqlite3 public API. It is strictly
1045f45c3370Sstephan ** for use by the sqlite project's own JS/WASM bindings.
1046f45c3370Sstephan **
10474fbf90eeSstephan ** Allocates sqlite3KvvfsMethods.nKeySize bytes from
10484fbf90eeSstephan ** sqlite3_wasm_pstack_alloc() and returns 0 if that allocation fails,
10494fbf90eeSstephan ** else it passes that string to kvstorageMakeKey() and returns a
10504fbf90eeSstephan ** NUL-terminated pointer to that string. It is up to the caller to
10514fbf90eeSstephan ** use sqlite3_wasm_pstack_restore() to free the returned pointer.
10524fbf90eeSstephan */
1053b75971e6Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_kvvfsMakeKeyOnPstack(const char * zClass,const char * zKeyIn)10544fbf90eeSstephan char * sqlite3_wasm_kvvfsMakeKeyOnPstack(const char *zClass,
10554fbf90eeSstephan                                          const char *zKeyIn){
10564fbf90eeSstephan   assert(sqlite3KvvfsMethods.nKeySize>24);
10574fbf90eeSstephan   char *zKeyOut =
10584fbf90eeSstephan     (char *)sqlite3_wasm_pstack_alloc(sqlite3KvvfsMethods.nKeySize);
10594fbf90eeSstephan   if(zKeyOut){
10604fbf90eeSstephan     kvstorageMakeKey(zClass, zKeyIn, zKeyOut);
10614fbf90eeSstephan   }
10624fbf90eeSstephan   return zKeyOut;
10634fbf90eeSstephan }
10644fbf90eeSstephan 
10654fbf90eeSstephan /*
10664fbf90eeSstephan ** This function is NOT part of the sqlite3 public API. It is strictly
10674fbf90eeSstephan ** for use by the sqlite project's own JS/WASM bindings.
10684fbf90eeSstephan **
10694fbf90eeSstephan ** Returns the pointer to the singleton object which holds the kvvfs
10704fbf90eeSstephan ** I/O methods and associated state.
10714fbf90eeSstephan */
1072b75971e6Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_kvvfs_methods(void)10734fbf90eeSstephan sqlite3_kvvfs_methods * sqlite3_wasm_kvvfs_methods(void){
10744fbf90eeSstephan   return &sqlite3KvvfsMethods;
10754fbf90eeSstephan }
107632781427Sstephan 
1077de6186e0Sstephan #if defined(__EMSCRIPTEN__) && defined(SQLITE_ENABLE_WASMFS)
10785b9973d8Sstephan #include <emscripten/wasmfs.h>
107973079dbaSstephan 
1080a579f440Sstephan /*
1081a579f440Sstephan ** This function is NOT part of the sqlite3 public API. It is strictly
1082e3cd6760Sstephan ** for use by the sqlite project's own JS/WASM bindings, specifically
1083e3cd6760Sstephan ** only when building with Emscripten's WASMFS support.
1084a579f440Sstephan **
1085a579f440Sstephan ** This function should only be called if the JS side detects the
1086a579f440Sstephan ** existence of the Origin-Private FileSystem (OPFS) APIs in the
1087a579f440Sstephan ** client. The first time it is called, this function instantiates a
1088a579f440Sstephan ** WASMFS backend impl for OPFS. On success, subsequent calls are
1089a579f440Sstephan ** no-ops.
1090a579f440Sstephan **
1091e3cd6760Sstephan ** This function may be passed a "mount point" name, which must have a
1092e3cd6760Sstephan ** leading "/" and is currently restricted to a single path component,
1093e3cd6760Sstephan ** e.g. "/foo" is legal but "/foo/" and "/foo/bar" are not. If it is
1094b75971e6Sstephan ** NULL or empty, it defaults to "/opfs".
1095e3cd6760Sstephan **
10969a4c63b0Sstephan ** Returns 0 on success, SQLITE_NOMEM if instantiation of the backend
1097e3cd6760Sstephan ** object fails, SQLITE_IOERR if mkdir() of the zMountPoint dir in
1098de6186e0Sstephan ** the virtual FS fails. In builds compiled without SQLITE_ENABLE_WASMFS
10999a4c63b0Sstephan ** defined, SQLITE_NOTFOUND is returned without side effects.
1100a579f440Sstephan */
1101b75971e6Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_init_wasmfs(const char * zMountPoint)110228ef9bddSstephan int sqlite3_wasm_init_wasmfs(const char *zMountPoint){
1103a579f440Sstephan   static backend_t pOpfs = 0;
11043d645484Sstephan   if( !zMountPoint || !*zMountPoint ) zMountPoint = "/opfs";
1105a579f440Sstephan   if( !pOpfs ){
1106a579f440Sstephan     pOpfs = wasmfs_create_opfs_backend();
1107a579f440Sstephan   }
11089a4c63b0Sstephan   /** It's not enough to instantiate the backend. We have to create a
11099a4c63b0Sstephan       mountpoint in the VFS and attach the backend to it. */
1110e3cd6760Sstephan   if( pOpfs && 0!=access(zMountPoint, F_OK) ){
1111e3cd6760Sstephan     /* Note that this check and is not robust but it will
1112e3cd6760Sstephan        hypothetically suffice for the transient wasm-based virtual
1113e3cd6760Sstephan        filesystem we're currently running in. */
1114e3cd6760Sstephan     const int rc = wasmfs_create_directory(zMountPoint, 0777, pOpfs);
111571de8e02Sstephan     /*emscripten_console_logf("OPFS mkdir(%s) rc=%d", zMountPoint, rc);*/
11169a4c63b0Sstephan     if(rc) return SQLITE_IOERR;
11179a4c63b0Sstephan   }
1118a579f440Sstephan   return pOpfs ? 0 : SQLITE_NOMEM;
1119a579f440Sstephan }
11209a4c63b0Sstephan #else
1121b75971e6Sstephan SQLITE_WASM_KEEP
sqlite3_wasm_init_wasmfs(const char * zUnused)11223d645484Sstephan int sqlite3_wasm_init_wasmfs(const char *zUnused){
11231fc6ffccSstephan   //emscripten_console_warn("WASMFS OPFS is not compiled in.");
11243d645484Sstephan   if(zUnused){/*unused*/}
11259a4c63b0Sstephan   return SQLITE_NOTFOUND;
11269a4c63b0Sstephan }
1127de6186e0Sstephan #endif /* __EMSCRIPTEN__ && SQLITE_ENABLE_WASMFS */
1128d1582296Sstephan 
1129d92c652aSstephan #if SQLITE_WASM_TESTS
1130d92c652aSstephan 
1131d92c652aSstephan SQLITE_WASM_KEEP
sqlite3_wasm_test_intptr(int * p)1132d92c652aSstephan int sqlite3_wasm_test_intptr(int * p){
1133d92c652aSstephan   return *p = *p * 2;
1134d92c652aSstephan }
1135d92c652aSstephan 
1136d92c652aSstephan SQLITE_WASM_KEEP
sqlite3_wasm_test_int64_max(void)1137d92c652aSstephan int64_t sqlite3_wasm_test_int64_max(void){
1138d92c652aSstephan   return (int64_t)0x7fffffffffffffff;
1139d92c652aSstephan }
1140d92c652aSstephan 
1141d92c652aSstephan SQLITE_WASM_KEEP
sqlite3_wasm_test_int64_min(void)1142d92c652aSstephan int64_t sqlite3_wasm_test_int64_min(void){
1143d92c652aSstephan   return ~sqlite3_wasm_test_int64_max();
1144d92c652aSstephan }
1145d92c652aSstephan 
1146d92c652aSstephan SQLITE_WASM_KEEP
sqlite3_wasm_test_int64_times2(int64_t x)1147d92c652aSstephan int64_t sqlite3_wasm_test_int64_times2(int64_t x){
1148d92c652aSstephan   return x * 2;
1149d92c652aSstephan }
1150d92c652aSstephan 
1151d92c652aSstephan SQLITE_WASM_KEEP
sqlite3_wasm_test_int64_minmax(int64_t * min,int64_t * max)1152d92c652aSstephan void sqlite3_wasm_test_int64_minmax(int64_t * min, int64_t *max){
1153d92c652aSstephan   *max = sqlite3_wasm_test_int64_max();
1154d92c652aSstephan   *min = sqlite3_wasm_test_int64_min();
1155d92c652aSstephan   /*printf("minmax: min=%lld, max=%lld\n", *min, *max);*/
1156d92c652aSstephan }
1157d92c652aSstephan 
1158d92c652aSstephan SQLITE_WASM_KEEP
sqlite3_wasm_test_int64ptr(int64_t * p)1159d92c652aSstephan int64_t sqlite3_wasm_test_int64ptr(int64_t * p){
1160d92c652aSstephan   /*printf("sqlite3_wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
1161d92c652aSstephan   return *p = *p * 2;
1162d92c652aSstephan }
1163d92c652aSstephan 
1164d92c652aSstephan SQLITE_WASM_KEEP
sqlite3_wasm_test_stack_overflow(int recurse)1165d92c652aSstephan void sqlite3_wasm_test_stack_overflow(int recurse){
1166d92c652aSstephan   if(recurse) sqlite3_wasm_test_stack_overflow(recurse);
1167d92c652aSstephan }
1168d92c652aSstephan 
1169d92c652aSstephan /* For testing the 'string-free' whwasmutil.xWrap() conversion. */
1170d92c652aSstephan SQLITE_WASM_KEEP
sqlite3_wasm_test_str_hello(int fail)1171d92c652aSstephan char * sqlite3_wasm_test_str_hello(int fail){
1172d92c652aSstephan   char * s = fail ? 0 : (char *)malloc(6);
1173d92c652aSstephan   if(s){
1174d92c652aSstephan     memcpy(s, "hello", 5);
1175d92c652aSstephan     s[5] = 0;
1176d92c652aSstephan   }
1177d92c652aSstephan   return s;
1178d92c652aSstephan }
1179d92c652aSstephan #endif /* SQLITE_WASM_TESTS */
1180d92c652aSstephan 
1181b75971e6Sstephan #undef SQLITE_WASM_KEEP
1182