/* ** This file requires access to sqlite3.c static state in order to ** implement certain WASM-specific features, and thus directly ** includes that file. Unlike the rest of sqlite3.c, this file ** requires compiling with -std=c99 (or equivalent, or a later C ** version) because it makes use of features not available in C89. ** ** At its simplest, to build sqlite3.wasm either place this file ** in the same directory as sqlite3.c/h before compilation or use the ** -I/path flag to tell the compiler where to find both of those ** files, then compile this file. For example: ** ** emcc -o sqlite3.wasm ... -I/path/to/sqlite3-c-and-h sqlite3-wasm.c */ #define SQLITE_WASM #ifdef SQLITE_WASM_ENABLE_C_TESTS /* ** Code blocked off by SQLITE_WASM_TESTS is intended solely for use in ** unit/regression testing. They may be safely omitted from ** client-side builds. The main unit test script, tester1.js, will ** skip related tests if it doesn't find the corresponding functions ** in the WASM exports. */ # define SQLITE_WASM_TESTS 1 #else # define SQLITE_WASM_TESTS 0 #endif /* ** Threading and file locking: JS is single-threaded. Each Worker ** thread is a separate instance of the JS engine so can never access ** the same db handle as another thread, thus multi-threading support ** is unnecessary in the library. Because the filesystems are virtual ** and local to a given wasm runtime instance, two Workers can never ** access the same db file at once, with the exception of OPFS. ** ** Summary: except for the case of OPFS, which supports locking using ** its own API, threading and file locking support are unnecessary in ** the wasm build. */ /* ** Undefine any SQLITE_... config flags which we specifically do not ** want defined. Please keep these alphabetized. */ #undef SQLITE_OMIT_DESERIALIZE #undef SQLITE_OMIT_MEMORYDB /* ** Define any SQLITE_... config defaults we want if they aren't ** overridden by the builder. Please keep these alphabetized. */ /**********************************************************************/ /* SQLITE_D... */ #ifndef SQLITE_DEFAULT_CACHE_SIZE /* ** The OPFS impls benefit tremendously from an increased cache size ** when working on large workloads, e.g. speedtest1 --size 50 or ** higher. On smaller workloads, e.g. speedtest1 --size 25, they ** clearly benefit from having 4mb of cache, but not as much as a ** larger cache benefits the larger workloads. Speed differences ** between 2x and nearly 3x have been measured with ample page cache. */ # define SQLITE_DEFAULT_CACHE_SIZE -16384 #endif #if !defined(SQLITE_DEFAULT_PAGE_SIZE) /* ** OPFS performance is improved by approx. 12% with a page size of 8kb ** instead of 4kb. Performance with 16kb is equivalent to 8kb. ** ** Performance difference of kvvfs with a page size of 8kb compared to ** 4kb, as measured by speedtest1 --size 4, is indeterminate: ** measurements are all over the place either way and not ** significantly different. */ # define SQLITE_DEFAULT_PAGE_SIZE 8192 #endif #ifndef SQLITE_DEFAULT_UNIX_VFS # define SQLITE_DEFAULT_UNIX_VFS "unix-none" #endif #undef SQLITE_DQS #define SQLITE_DQS 0 /**********************************************************************/ /* SQLITE_ENABLE_... */ /* ** Unconditionally enable API_ARMOR in the WASM build. It ensures that ** public APIs behave predictable in the face of passing illegal NULLs ** or ranges which might otherwise invoke undefined behavior. */ #undef SQLITE_ENABLE_API_ARMOR #define SQLITE_ENABLE_API_ARMOR 1 #ifndef SQLITE_ENABLE_BYTECODE_VTAB # define SQLITE_ENABLE_BYTECODE_VTAB 1 #endif #ifndef SQLITE_ENABLE_DBPAGE_VTAB # define SQLITE_ENABLE_DBPAGE_VTAB 1 #endif #ifndef SQLITE_ENABLE_DBSTAT_VTAB # define SQLITE_ENABLE_DBSTAT_VTAB 1 #endif #ifndef SQLITE_ENABLE_EXPLAIN_COMMENTS # define SQLITE_ENABLE_EXPLAIN_COMMENTS 1 #endif #ifndef SQLITE_ENABLE_FTS4 # define SQLITE_ENABLE_FTS4 1 #endif #ifndef SQLITE_ENABLE_MATH_FUNCTIONS # define SQLITE_ENABLE_MATH_FUNCTIONS 1 #endif #ifndef SQLITE_ENABLE_OFFSET_SQL_FUNC # define SQLITE_ENABLE_OFFSET_SQL_FUNC 1 #endif #ifndef SQLITE_ENABLE_PREUPDATE_HOOK # define SQLITE_ENABLE_PREUPDATE_HOOK 1 /*required by session extension*/ #endif #ifndef SQLITE_ENABLE_RTREE # define SQLITE_ENABLE_RTREE 1 #endif #ifndef SQLITE_ENABLE_SESSION # define SQLITE_ENABLE_SESSION 1 #endif #ifndef SQLITE_ENABLE_STMTVTAB # define SQLITE_ENABLE_STMTVTAB 1 #endif #ifndef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION # define SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION #endif /**********************************************************************/ /* SQLITE_O... */ #ifndef SQLITE_OMIT_DEPRECATED # define SQLITE_OMIT_DEPRECATED 1 #endif #ifndef SQLITE_OMIT_LOAD_EXTENSION # define SQLITE_OMIT_LOAD_EXTENSION 1 #endif #ifndef SQLITE_OMIT_SHARED_CACHE # define SQLITE_OMIT_SHARED_CACHE 1 #endif #ifndef SQLITE_OMIT_UTF16 # define SQLITE_OMIT_UTF16 1 #endif #ifndef SQLITE_OS_KV_OPTIONAL # define SQLITE_OS_KV_OPTIONAL 1 #endif /**********************************************************************/ /* SQLITE_S... */ #ifndef SQLITE_STRICT_SUBTYPE # define SQLITE_STRICT_SUBTYPE 1 #endif /**********************************************************************/ /* SQLITE_T... */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 2 #endif #ifndef SQLITE_THREADSAFE # define SQLITE_THREADSAFE 0 #endif /**********************************************************************/ /* SQLITE_USE_... */ #ifndef SQLITE_USE_URI # define SQLITE_USE_URI 1 #endif #ifdef SQLITE_WASM_EXTRA_INIT # define SQLITE_EXTRA_INIT sqlite3_wasm_extra_init #endif #include /* ** SQLITE_WASM_EXPORT is functionally identical to EMSCRIPTEN_KEEPALIVE ** but is not Emscripten-specific. It explicitly marks functions for ** export into the target wasm file without requiring explicit listing ** of those functions in Emscripten's -sEXPORTED_FUNCTIONS=... list ** (or equivalent in other build platforms). Any function with neither ** this attribute nor which is listed as an explicit export will not ** be exported from the wasm file (but may still be used internally ** within the wasm file). ** ** The functions in this file (sqlite3-wasm.c) which require exporting ** are marked with this flag. They may also be added to any explicit ** build-time export list but need not be. All of these APIs are ** intended for use only within the project's own JS/WASM code, and ** not by client code, so an argument can be made for reducing their ** visibility by not including them in any build-time export lists. ** ** 2022-09-11: it's not yet _proven_ that this approach works in ** non-Emscripten builds. If not, such builds will need to export ** those using the --export=... wasm-ld flag (or equivalent). As of ** this writing we are tied to Emscripten for various reasons ** and cannot test the library with other build environments. */ #define SQLITE_WASM_EXPORT __attribute__((used,visibility("default"))) // See also: //__attribute__((export_name("theExportedName"), used, visibility("default"))) /* ** Which sqlite3.c we're using needs to be configurable to enable ** building against a custom copy, e.g. the SEE variant. Note that we ** #include the .c file, rather than the header, so that the WASM ** extensions have access to private API internals. ** ** The caveat here is that custom variants need to account for ** exporting any necessary symbols (e.g. sqlite3_activate_see()). We ** cannot export them from here using SQLITE_WASM_EXPORT because that ** attribute (apparently) has to be part of the function definition. */ #ifndef SQLITE_C # define SQLITE_C sqlite3.c /* yes, .c instead of .h. */ #endif #define INC__STRINGIFY_(f) #f #define INC__STRINGIFY(f) INC__STRINGIFY_(f) #include INC__STRINGIFY(SQLITE_C) #undef INC__STRINGIFY_ #undef INC__STRINGIFY #undef SQLITE_C #if defined(__EMSCRIPTEN__) # include #endif #if 0 /* ** An EXPERIMENT in implementing a stack-based allocator analog to ** Emscripten's stackSave(), stackAlloc(), stackRestore(). ** Unfortunately, this cannot work together with Emscripten because ** Emscripten defines its own native one and we'd stomp on each ** other's memory. Other than that complication, basic tests show it ** to work just fine. ** ** Another option is to malloc() a chunk of our own and call that our ** "stack". */ SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_end(void){ extern void __heap_base /* see https://stackoverflow.com/questions/10038964 */; return &__heap_base; } SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_begin(void){ extern void __data_end; return &__data_end; } static void * pWasmStackPtr = 0; SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_ptr(void){ if(!pWasmStackPtr) pWasmStackPtr = sqlite3__wasm_stack_end(); return pWasmStackPtr; } SQLITE_WASM_EXPORT void sqlite3__wasm_stack_restore(void * p){ pWasmStackPtr = p; } SQLITE_WASM_EXPORT void * sqlite3__wasm_stack_alloc(int n){ if(n<=0) return 0; n = (n + 7) & ~7 /* align to 8-byte boundary */; unsigned char * const p = (unsigned char *)sqlite3__wasm_stack_ptr(); unsigned const char * const b = (unsigned const char *)sqlite3__wasm_stack_begin(); if(b + n >= p || b + n < b/*overflow*/) return 0; return pWasmStackPtr = p - n; } #endif /* stack allocator experiment */ /* ** State for the "pseudo-stack" allocator implemented in ** sqlite3__wasm_pstack_xyz(). In order to avoid colliding with ** Emscripten-controled stack space, it carves out a bit of stack ** memory to use for that purpose. This memory ends up in the ** WASM-managed memory, such that routines which manipulate the wasm ** heap can also be used to manipulate this memory. ** ** This particular allocator is intended for small allocations such as ** storage for output pointers. We cannot reasonably size it large ** enough for general-purpose string conversions because some of our ** tests use input files (strings) of 16MB+. */ static unsigned char PStack_mem[512 * 8] = {0}; static struct { unsigned const char * const pBegin;/* Start (inclusive) of memory */ unsigned const char * const pEnd; /* One-after-the-end of memory */ unsigned char * pPos; /* Current stack pointer */ } PStack = { &PStack_mem[0], &PStack_mem[0] + sizeof(PStack_mem), &PStack_mem[0] + sizeof(PStack_mem) }; /* ** Returns the current pstack position. */ SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_ptr(void){ return PStack.pPos; } /* ** Sets the pstack position poitner to p. Results are undefined if the ** given value did not come from sqlite3__wasm_pstack_ptr(). */ SQLITE_WASM_EXPORT void sqlite3__wasm_pstack_restore(unsigned char * p){ assert(p>=PStack.pBegin && p<=PStack.pEnd && p>=PStack.pPos); assert(0==((unsigned long long)p & 0x7)); if(p>=PStack.pBegin && p<=PStack.pEnd /*&& p>=PStack.pPos*/){ PStack.pPos = p; } } /* ** Allocate and zero out n bytes from the pstack. Returns a pointer to ** the memory on success, 0 on error (including a negative n value). n ** is always adjusted to be a multiple of 8 and returned memory is ** always zeroed out before returning (because this keeps the client ** JS code from having to do so, and most uses of the pstack will ** call for doing so). */ SQLITE_WASM_EXPORT void * sqlite3__wasm_pstack_alloc(int n){ if( n<=0 ) return 0; //if( n & 0x7 ) n += 8 - (n & 0x7) /* align to 8-byte boundary */; n = (n + 7) & ~7 /* align to 8-byte boundary */; if( PStack.pBegin + n > PStack.pPos /*not enough space left*/ || PStack.pBegin + n <= PStack.pBegin /*overflow*/ ) return 0; memset((PStack.pPos = PStack.pPos - n), 0, (unsigned int)n); return PStack.pPos; } /* ** Return the number of bytes left which can be ** sqlite3__wasm_pstack_alloc()'d. */ SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_remaining(void){ assert(PStack.pPos >= PStack.pBegin); assert(PStack.pPos <= PStack.pEnd); return (int)(PStack.pPos - PStack.pBegin); } /* ** Return the total number of bytes available in the pstack, including ** any space which is currently allocated. This value is a ** compile-time constant. */ SQLITE_WASM_EXPORT int sqlite3__wasm_pstack_quota(void){ return (int)(PStack.pEnd - PStack.pBegin); } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** For purposes of certain hand-crafted C/Wasm function bindings, we ** need a way of reporting errors which is consistent with the rest of ** the C API, as opposed to throwing JS exceptions. To that end, this ** internal-use-only function is a thin proxy around ** sqlite3ErrorWithMessage(). The intent is that it only be used from ** Wasm bindings such as sqlite3_prepare_v2/v3(), and definitely not ** from client code. ** ** Returns err_code. */ SQLITE_WASM_EXPORT int sqlite3__wasm_db_error(sqlite3*db, int err_code, const char *zMsg){ if( db!=0 ){ if( 0!=zMsg ){ const int nMsg = sqlite3Strlen30(zMsg); sqlite3_mutex_enter(sqlite3_db_mutex(db)); sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg); sqlite3_mutex_leave(sqlite3_db_mutex(db)); }else{ sqlite3ErrorWithMsg(db, err_code, NULL); } } return err_code; } #if SQLITE_WASM_TESTS struct WasmTestStruct { int v4; void * ppV; const char * cstr; int64_t v8; void (*xFunc)(void*); }; typedef struct WasmTestStruct WasmTestStruct; SQLITE_WASM_EXPORT void sqlite3__wasm_test_struct(WasmTestStruct * s){ if(s){ s->v4 *= 2; s->v8 = s->v4 * 2; s->ppV = s; s->cstr = __FILE__; if(s->xFunc) s->xFunc(s); } return; } #endif /* SQLITE_WASM_TESTS */ /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. Unlike the ** rest of the sqlite3 API, this part requires C99 for snprintf() and ** variadic macros. ** ** Returns a string containing a JSON-format "enum" of C-level ** constants and struct-related metadata intended to be imported into ** the JS environment. The JSON is initialized the first time this ** function is called and that result is reused for all future calls. ** ** If this function returns NULL then it means that the internal ** buffer is not large enough for the generated JSON and needs to be ** increased. In debug builds that will trigger an assert(). */ SQLITE_WASM_EXPORT const char * sqlite3__wasm_enum_json(void){ static char aBuffer[1024 * 20] = {0} /* where the JSON goes */; int n = 0, nChildren = 0, nStruct = 0 /* output counters for figuring out where commas go */; char * zPos = &aBuffer[1] /* skip first byte for now to help protect ** against a small race condition */; char const * const zEnd = &aBuffer[0] + sizeof(aBuffer) /* one-past-the-end */; if(aBuffer[0]) return aBuffer; /* Leave aBuffer[0] at 0 until the end to help guard against a tiny ** race condition. If this is called twice concurrently, they might ** end up both writing to aBuffer, but they'll both write the same ** thing, so that's okay. If we set byte 0 up front then the 2nd ** instance might return and use the string before the 1st instance ** is done filling it. */ /* Core output macros... */ #define lenCheck assert(zPos < zEnd - 128 \ && "sqlite3__wasm_enum_json() buffer is too small."); \ if( zPos >= zEnd - 128 ) return 0 #define outf(format,...) \ zPos += snprintf(zPos, ((size_t)(zEnd - zPos)), format, __VA_ARGS__); \ lenCheck #define out(TXT) outf("%s",TXT) #define CloseBrace(LEVEL) \ assert(LEVEL<5); memset(zPos, '}', LEVEL); zPos+=LEVEL; lenCheck /* Macros for emitting maps of integer- and string-type macros to ** their values. */ #define DefGroup(KEY) n = 0; \ outf("%s\"" #KEY "\": {",(nChildren++ ? "," : "")); #define DefInt(KEY) \ outf("%s\"%s\": %d", (n++ ? ", " : ""), #KEY, (int)KEY) #define DefStr(KEY) \ outf("%s\"%s\": \"%s\"", (n++ ? ", " : ""), #KEY, KEY) #define _DefGroup CloseBrace(1) /* The following groups are sorted alphabetic by group name. */ DefGroup(access){ DefInt(SQLITE_ACCESS_EXISTS); DefInt(SQLITE_ACCESS_READWRITE); DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/; } _DefGroup; DefGroup(authorizer){ DefInt(SQLITE_DENY); DefInt(SQLITE_IGNORE); DefInt(SQLITE_CREATE_INDEX); DefInt(SQLITE_CREATE_TABLE); DefInt(SQLITE_CREATE_TEMP_INDEX); DefInt(SQLITE_CREATE_TEMP_TABLE); DefInt(SQLITE_CREATE_TEMP_TRIGGER); DefInt(SQLITE_CREATE_TEMP_VIEW); DefInt(SQLITE_CREATE_TRIGGER); DefInt(SQLITE_CREATE_VIEW); DefInt(SQLITE_DELETE); DefInt(SQLITE_DROP_INDEX); DefInt(SQLITE_DROP_TABLE); DefInt(SQLITE_DROP_TEMP_INDEX); DefInt(SQLITE_DROP_TEMP_TABLE); DefInt(SQLITE_DROP_TEMP_TRIGGER); DefInt(SQLITE_DROP_TEMP_VIEW); DefInt(SQLITE_DROP_TRIGGER); DefInt(SQLITE_DROP_VIEW); DefInt(SQLITE_INSERT); DefInt(SQLITE_PRAGMA); DefInt(SQLITE_READ); DefInt(SQLITE_SELECT); DefInt(SQLITE_TRANSACTION); DefInt(SQLITE_UPDATE); DefInt(SQLITE_ATTACH); DefInt(SQLITE_DETACH); DefInt(SQLITE_ALTER_TABLE); DefInt(SQLITE_REINDEX); DefInt(SQLITE_ANALYZE); DefInt(SQLITE_CREATE_VTABLE); DefInt(SQLITE_DROP_VTABLE); DefInt(SQLITE_FUNCTION); DefInt(SQLITE_SAVEPOINT); //DefInt(SQLITE_COPY) /* No longer used */; DefInt(SQLITE_RECURSIVE); } _DefGroup; DefGroup(blobFinalizers) { /* SQLITE_STATIC/TRANSIENT need to be handled explicitly as ** integers to avoid casting-related warnings. */ out("\"SQLITE_STATIC\":0, \"SQLITE_TRANSIENT\":-1"); outf(",\"SQLITE_WASM_DEALLOC\": %lld", (sqlite3_int64)(sqlite3_free)); } _DefGroup; DefGroup(changeset){ DefInt(SQLITE_CHANGESETSTART_INVERT); DefInt(SQLITE_CHANGESETAPPLY_NOSAVEPOINT); DefInt(SQLITE_CHANGESETAPPLY_INVERT); DefInt(SQLITE_CHANGESETAPPLY_IGNORENOOP); DefInt(SQLITE_CHANGESET_DATA); DefInt(SQLITE_CHANGESET_NOTFOUND); DefInt(SQLITE_CHANGESET_CONFLICT); DefInt(SQLITE_CHANGESET_CONSTRAINT); DefInt(SQLITE_CHANGESET_FOREIGN_KEY); DefInt(SQLITE_CHANGESET_OMIT); DefInt(SQLITE_CHANGESET_REPLACE); DefInt(SQLITE_CHANGESET_ABORT); } _DefGroup; DefGroup(config){ DefInt(SQLITE_CONFIG_SINGLETHREAD); DefInt(SQLITE_CONFIG_MULTITHREAD); DefInt(SQLITE_CONFIG_SERIALIZED); DefInt(SQLITE_CONFIG_MALLOC); DefInt(SQLITE_CONFIG_GETMALLOC); DefInt(SQLITE_CONFIG_SCRATCH); DefInt(SQLITE_CONFIG_PAGECACHE); DefInt(SQLITE_CONFIG_HEAP); DefInt(SQLITE_CONFIG_MEMSTATUS); DefInt(SQLITE_CONFIG_MUTEX); DefInt(SQLITE_CONFIG_GETMUTEX); /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ DefInt(SQLITE_CONFIG_LOOKASIDE); DefInt(SQLITE_CONFIG_PCACHE); DefInt(SQLITE_CONFIG_GETPCACHE); DefInt(SQLITE_CONFIG_LOG); DefInt(SQLITE_CONFIG_URI); DefInt(SQLITE_CONFIG_PCACHE2); DefInt(SQLITE_CONFIG_GETPCACHE2); DefInt(SQLITE_CONFIG_COVERING_INDEX_SCAN); DefInt(SQLITE_CONFIG_SQLLOG); DefInt(SQLITE_CONFIG_MMAP_SIZE); DefInt(SQLITE_CONFIG_WIN32_HEAPSIZE); DefInt(SQLITE_CONFIG_PCACHE_HDRSZ); DefInt(SQLITE_CONFIG_PMASZ); DefInt(SQLITE_CONFIG_STMTJRNL_SPILL); DefInt(SQLITE_CONFIG_SMALL_MALLOC); DefInt(SQLITE_CONFIG_SORTERREF_SIZE); DefInt(SQLITE_CONFIG_MEMDB_MAXSIZE); /* maintenance note: we specifically do not include SQLITE_CONFIG_ROWID_IN_VIEW here, on the grounds that it's only for legacy support and no apps written with this API require that. */ } _DefGroup; DefGroup(dataTypes) { DefInt(SQLITE_INTEGER); DefInt(SQLITE_FLOAT); DefInt(SQLITE_TEXT); DefInt(SQLITE_BLOB); DefInt(SQLITE_NULL); } _DefGroup; DefGroup(dbConfig){ DefInt(SQLITE_DBCONFIG_MAINDBNAME); DefInt(SQLITE_DBCONFIG_LOOKASIDE); DefInt(SQLITE_DBCONFIG_ENABLE_FKEY); DefInt(SQLITE_DBCONFIG_ENABLE_TRIGGER); DefInt(SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER); DefInt(SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION); DefInt(SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE); DefInt(SQLITE_DBCONFIG_ENABLE_QPSG); DefInt(SQLITE_DBCONFIG_TRIGGER_EQP); DefInt(SQLITE_DBCONFIG_RESET_DATABASE); DefInt(SQLITE_DBCONFIG_DEFENSIVE); DefInt(SQLITE_DBCONFIG_WRITABLE_SCHEMA); DefInt(SQLITE_DBCONFIG_LEGACY_ALTER_TABLE); DefInt(SQLITE_DBCONFIG_DQS_DML); DefInt(SQLITE_DBCONFIG_DQS_DDL); DefInt(SQLITE_DBCONFIG_ENABLE_VIEW); DefInt(SQLITE_DBCONFIG_LEGACY_FILE_FORMAT); DefInt(SQLITE_DBCONFIG_TRUSTED_SCHEMA); DefInt(SQLITE_DBCONFIG_STMT_SCANSTATUS); DefInt(SQLITE_DBCONFIG_REVERSE_SCANORDER); DefInt(SQLITE_DBCONFIG_MAX); } _DefGroup; DefGroup(dbStatus){ DefInt(SQLITE_DBSTATUS_LOOKASIDE_USED); DefInt(SQLITE_DBSTATUS_CACHE_USED); DefInt(SQLITE_DBSTATUS_SCHEMA_USED); DefInt(SQLITE_DBSTATUS_STMT_USED); DefInt(SQLITE_DBSTATUS_LOOKASIDE_HIT); DefInt(SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE); DefInt(SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL); DefInt(SQLITE_DBSTATUS_CACHE_HIT); DefInt(SQLITE_DBSTATUS_CACHE_MISS); DefInt(SQLITE_DBSTATUS_CACHE_WRITE); DefInt(SQLITE_DBSTATUS_DEFERRED_FKS); DefInt(SQLITE_DBSTATUS_CACHE_USED_SHARED); DefInt(SQLITE_DBSTATUS_CACHE_SPILL); DefInt(SQLITE_DBSTATUS_MAX); } _DefGroup; DefGroup(encodings) { /* Noting that the wasm binding only aims to support UTF-8. */ DefInt(SQLITE_UTF8); DefInt(SQLITE_UTF16LE); DefInt(SQLITE_UTF16BE); DefInt(SQLITE_UTF16); /*deprecated DefInt(SQLITE_ANY); */ DefInt(SQLITE_UTF16_ALIGNED); } _DefGroup; DefGroup(fcntl) { DefInt(SQLITE_FCNTL_LOCKSTATE); DefInt(SQLITE_FCNTL_GET_LOCKPROXYFILE); DefInt(SQLITE_FCNTL_SET_LOCKPROXYFILE); DefInt(SQLITE_FCNTL_LAST_ERRNO); DefInt(SQLITE_FCNTL_SIZE_HINT); DefInt(SQLITE_FCNTL_CHUNK_SIZE); DefInt(SQLITE_FCNTL_FILE_POINTER); DefInt(SQLITE_FCNTL_SYNC_OMITTED); DefInt(SQLITE_FCNTL_WIN32_AV_RETRY); DefInt(SQLITE_FCNTL_PERSIST_WAL); DefInt(SQLITE_FCNTL_OVERWRITE); DefInt(SQLITE_FCNTL_VFSNAME); DefInt(SQLITE_FCNTL_POWERSAFE_OVERWRITE); DefInt(SQLITE_FCNTL_PRAGMA); DefInt(SQLITE_FCNTL_BUSYHANDLER); DefInt(SQLITE_FCNTL_TEMPFILENAME); DefInt(SQLITE_FCNTL_MMAP_SIZE); DefInt(SQLITE_FCNTL_TRACE); DefInt(SQLITE_FCNTL_HAS_MOVED); DefInt(SQLITE_FCNTL_SYNC); DefInt(SQLITE_FCNTL_COMMIT_PHASETWO); DefInt(SQLITE_FCNTL_WIN32_SET_HANDLE); DefInt(SQLITE_FCNTL_WAL_BLOCK); DefInt(SQLITE_FCNTL_ZIPVFS); DefInt(SQLITE_FCNTL_RBU); DefInt(SQLITE_FCNTL_VFS_POINTER); DefInt(SQLITE_FCNTL_JOURNAL_POINTER); DefInt(SQLITE_FCNTL_WIN32_GET_HANDLE); DefInt(SQLITE_FCNTL_PDB); DefInt(SQLITE_FCNTL_BEGIN_ATOMIC_WRITE); DefInt(SQLITE_FCNTL_COMMIT_ATOMIC_WRITE); DefInt(SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE); DefInt(SQLITE_FCNTL_LOCK_TIMEOUT); DefInt(SQLITE_FCNTL_DATA_VERSION); DefInt(SQLITE_FCNTL_SIZE_LIMIT); DefInt(SQLITE_FCNTL_CKPT_DONE); DefInt(SQLITE_FCNTL_RESERVE_BYTES); DefInt(SQLITE_FCNTL_CKPT_START); DefInt(SQLITE_FCNTL_EXTERNAL_READER); DefInt(SQLITE_FCNTL_CKSM_FILE); DefInt(SQLITE_FCNTL_RESET_CACHE); } _DefGroup; DefGroup(flock) { DefInt(SQLITE_LOCK_NONE); DefInt(SQLITE_LOCK_SHARED); DefInt(SQLITE_LOCK_RESERVED); DefInt(SQLITE_LOCK_PENDING); DefInt(SQLITE_LOCK_EXCLUSIVE); } _DefGroup; DefGroup(ioCap) { DefInt(SQLITE_IOCAP_ATOMIC); DefInt(SQLITE_IOCAP_ATOMIC512); DefInt(SQLITE_IOCAP_ATOMIC1K); DefInt(SQLITE_IOCAP_ATOMIC2K); DefInt(SQLITE_IOCAP_ATOMIC4K); DefInt(SQLITE_IOCAP_ATOMIC8K); DefInt(SQLITE_IOCAP_ATOMIC16K); DefInt(SQLITE_IOCAP_ATOMIC32K); DefInt(SQLITE_IOCAP_ATOMIC64K); DefInt(SQLITE_IOCAP_SAFE_APPEND); DefInt(SQLITE_IOCAP_SEQUENTIAL); DefInt(SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN); DefInt(SQLITE_IOCAP_POWERSAFE_OVERWRITE); DefInt(SQLITE_IOCAP_IMMUTABLE); DefInt(SQLITE_IOCAP_BATCH_ATOMIC); } _DefGroup; DefGroup(limits) { DefInt(SQLITE_MAX_ALLOCATION_SIZE); DefInt(SQLITE_LIMIT_LENGTH); DefInt(SQLITE_MAX_LENGTH); DefInt(SQLITE_LIMIT_SQL_LENGTH); DefInt(SQLITE_MAX_SQL_LENGTH); DefInt(SQLITE_LIMIT_COLUMN); DefInt(SQLITE_MAX_COLUMN); DefInt(SQLITE_LIMIT_EXPR_DEPTH); DefInt(SQLITE_MAX_EXPR_DEPTH); DefInt(SQLITE_LIMIT_COMPOUND_SELECT); DefInt(SQLITE_MAX_COMPOUND_SELECT); DefInt(SQLITE_LIMIT_VDBE_OP); DefInt(SQLITE_MAX_VDBE_OP); DefInt(SQLITE_LIMIT_FUNCTION_ARG); DefInt(SQLITE_MAX_FUNCTION_ARG); DefInt(SQLITE_LIMIT_ATTACHED); DefInt(SQLITE_MAX_ATTACHED); DefInt(SQLITE_LIMIT_LIKE_PATTERN_LENGTH); DefInt(SQLITE_MAX_LIKE_PATTERN_LENGTH); DefInt(SQLITE_LIMIT_VARIABLE_NUMBER); DefInt(SQLITE_MAX_VARIABLE_NUMBER); DefInt(SQLITE_LIMIT_TRIGGER_DEPTH); DefInt(SQLITE_MAX_TRIGGER_DEPTH); DefInt(SQLITE_LIMIT_WORKER_THREADS); DefInt(SQLITE_MAX_WORKER_THREADS); } _DefGroup; DefGroup(openFlags) { /* Noting that not all of these will have any effect in ** WASM-space. */ DefInt(SQLITE_OPEN_READONLY); DefInt(SQLITE_OPEN_READWRITE); DefInt(SQLITE_OPEN_CREATE); DefInt(SQLITE_OPEN_URI); DefInt(SQLITE_OPEN_MEMORY); DefInt(SQLITE_OPEN_NOMUTEX); DefInt(SQLITE_OPEN_FULLMUTEX); DefInt(SQLITE_OPEN_SHAREDCACHE); DefInt(SQLITE_OPEN_PRIVATECACHE); DefInt(SQLITE_OPEN_EXRESCODE); DefInt(SQLITE_OPEN_NOFOLLOW); /* OPEN flags for use with VFSes... */ DefInt(SQLITE_OPEN_MAIN_DB); DefInt(SQLITE_OPEN_MAIN_JOURNAL); DefInt(SQLITE_OPEN_TEMP_DB); DefInt(SQLITE_OPEN_TEMP_JOURNAL); DefInt(SQLITE_OPEN_TRANSIENT_DB); DefInt(SQLITE_OPEN_SUBJOURNAL); DefInt(SQLITE_OPEN_SUPER_JOURNAL); DefInt(SQLITE_OPEN_WAL); DefInt(SQLITE_OPEN_DELETEONCLOSE); DefInt(SQLITE_OPEN_EXCLUSIVE); } _DefGroup; DefGroup(prepareFlags) { DefInt(SQLITE_PREPARE_PERSISTENT); DefInt(SQLITE_PREPARE_NORMALIZE); DefInt(SQLITE_PREPARE_NO_VTAB); } _DefGroup; DefGroup(resultCodes) { DefInt(SQLITE_OK); DefInt(SQLITE_ERROR); DefInt(SQLITE_INTERNAL); DefInt(SQLITE_PERM); DefInt(SQLITE_ABORT); DefInt(SQLITE_BUSY); DefInt(SQLITE_LOCKED); DefInt(SQLITE_NOMEM); DefInt(SQLITE_READONLY); DefInt(SQLITE_INTERRUPT); DefInt(SQLITE_IOERR); DefInt(SQLITE_CORRUPT); DefInt(SQLITE_NOTFOUND); DefInt(SQLITE_FULL); DefInt(SQLITE_CANTOPEN); DefInt(SQLITE_PROTOCOL); DefInt(SQLITE_EMPTY); DefInt(SQLITE_SCHEMA); DefInt(SQLITE_TOOBIG); DefInt(SQLITE_CONSTRAINT); DefInt(SQLITE_MISMATCH); DefInt(SQLITE_MISUSE); DefInt(SQLITE_NOLFS); DefInt(SQLITE_AUTH); DefInt(SQLITE_FORMAT); DefInt(SQLITE_RANGE); DefInt(SQLITE_NOTADB); DefInt(SQLITE_NOTICE); DefInt(SQLITE_WARNING); DefInt(SQLITE_ROW); DefInt(SQLITE_DONE); // Extended Result Codes DefInt(SQLITE_ERROR_MISSING_COLLSEQ); DefInt(SQLITE_ERROR_RETRY); DefInt(SQLITE_ERROR_SNAPSHOT); DefInt(SQLITE_IOERR_READ); DefInt(SQLITE_IOERR_SHORT_READ); DefInt(SQLITE_IOERR_WRITE); DefInt(SQLITE_IOERR_FSYNC); DefInt(SQLITE_IOERR_DIR_FSYNC); DefInt(SQLITE_IOERR_TRUNCATE); DefInt(SQLITE_IOERR_FSTAT); DefInt(SQLITE_IOERR_UNLOCK); DefInt(SQLITE_IOERR_RDLOCK); DefInt(SQLITE_IOERR_DELETE); DefInt(SQLITE_IOERR_BLOCKED); DefInt(SQLITE_IOERR_NOMEM); DefInt(SQLITE_IOERR_ACCESS); DefInt(SQLITE_IOERR_CHECKRESERVEDLOCK); DefInt(SQLITE_IOERR_LOCK); DefInt(SQLITE_IOERR_CLOSE); DefInt(SQLITE_IOERR_DIR_CLOSE); DefInt(SQLITE_IOERR_SHMOPEN); DefInt(SQLITE_IOERR_SHMSIZE); DefInt(SQLITE_IOERR_SHMLOCK); DefInt(SQLITE_IOERR_SHMMAP); DefInt(SQLITE_IOERR_SEEK); DefInt(SQLITE_IOERR_DELETE_NOENT); DefInt(SQLITE_IOERR_MMAP); DefInt(SQLITE_IOERR_GETTEMPPATH); DefInt(SQLITE_IOERR_CONVPATH); DefInt(SQLITE_IOERR_VNODE); DefInt(SQLITE_IOERR_AUTH); DefInt(SQLITE_IOERR_BEGIN_ATOMIC); DefInt(SQLITE_IOERR_COMMIT_ATOMIC); DefInt(SQLITE_IOERR_ROLLBACK_ATOMIC); DefInt(SQLITE_IOERR_DATA); DefInt(SQLITE_IOERR_CORRUPTFS); DefInt(SQLITE_LOCKED_SHAREDCACHE); DefInt(SQLITE_LOCKED_VTAB); DefInt(SQLITE_BUSY_RECOVERY); DefInt(SQLITE_BUSY_SNAPSHOT); DefInt(SQLITE_BUSY_TIMEOUT); DefInt(SQLITE_CANTOPEN_NOTEMPDIR); DefInt(SQLITE_CANTOPEN_ISDIR); DefInt(SQLITE_CANTOPEN_FULLPATH); DefInt(SQLITE_CANTOPEN_CONVPATH); //DefInt(SQLITE_CANTOPEN_DIRTYWAL)/*docs say not used*/; DefInt(SQLITE_CANTOPEN_SYMLINK); DefInt(SQLITE_CORRUPT_VTAB); DefInt(SQLITE_CORRUPT_SEQUENCE); DefInt(SQLITE_CORRUPT_INDEX); DefInt(SQLITE_READONLY_RECOVERY); DefInt(SQLITE_READONLY_CANTLOCK); DefInt(SQLITE_READONLY_ROLLBACK); DefInt(SQLITE_READONLY_DBMOVED); DefInt(SQLITE_READONLY_CANTINIT); DefInt(SQLITE_READONLY_DIRECTORY); DefInt(SQLITE_ABORT_ROLLBACK); DefInt(SQLITE_CONSTRAINT_CHECK); DefInt(SQLITE_CONSTRAINT_COMMITHOOK); DefInt(SQLITE_CONSTRAINT_FOREIGNKEY); DefInt(SQLITE_CONSTRAINT_FUNCTION); DefInt(SQLITE_CONSTRAINT_NOTNULL); DefInt(SQLITE_CONSTRAINT_PRIMARYKEY); DefInt(SQLITE_CONSTRAINT_TRIGGER); DefInt(SQLITE_CONSTRAINT_UNIQUE); DefInt(SQLITE_CONSTRAINT_VTAB); DefInt(SQLITE_CONSTRAINT_ROWID); DefInt(SQLITE_CONSTRAINT_PINNED); DefInt(SQLITE_CONSTRAINT_DATATYPE); DefInt(SQLITE_NOTICE_RECOVER_WAL); DefInt(SQLITE_NOTICE_RECOVER_ROLLBACK); DefInt(SQLITE_WARNING_AUTOINDEX); DefInt(SQLITE_AUTH_USER); DefInt(SQLITE_OK_LOAD_PERMANENTLY); //DefInt(SQLITE_OK_SYMLINK) /* internal use only */; } _DefGroup; DefGroup(serialize){ DefInt(SQLITE_SERIALIZE_NOCOPY); DefInt(SQLITE_DESERIALIZE_FREEONCLOSE); DefInt(SQLITE_DESERIALIZE_READONLY); DefInt(SQLITE_DESERIALIZE_RESIZEABLE); } _DefGroup; DefGroup(session){ DefInt(SQLITE_SESSION_CONFIG_STRMSIZE); DefInt(SQLITE_SESSION_OBJCONFIG_SIZE); } _DefGroup; DefGroup(sqlite3Status){ DefInt(SQLITE_STATUS_MEMORY_USED); DefInt(SQLITE_STATUS_PAGECACHE_USED); DefInt(SQLITE_STATUS_PAGECACHE_OVERFLOW); //DefInt(SQLITE_STATUS_SCRATCH_USED) /* NOT USED */; //DefInt(SQLITE_STATUS_SCRATCH_OVERFLOW) /* NOT USED */; DefInt(SQLITE_STATUS_MALLOC_SIZE); DefInt(SQLITE_STATUS_PARSER_STACK); DefInt(SQLITE_STATUS_PAGECACHE_SIZE); //DefInt(SQLITE_STATUS_SCRATCH_SIZE) /* NOT USED */; DefInt(SQLITE_STATUS_MALLOC_COUNT); } _DefGroup; DefGroup(stmtStatus){ DefInt(SQLITE_STMTSTATUS_FULLSCAN_STEP); DefInt(SQLITE_STMTSTATUS_SORT); DefInt(SQLITE_STMTSTATUS_AUTOINDEX); DefInt(SQLITE_STMTSTATUS_VM_STEP); DefInt(SQLITE_STMTSTATUS_REPREPARE); DefInt(SQLITE_STMTSTATUS_RUN); DefInt(SQLITE_STMTSTATUS_FILTER_MISS); DefInt(SQLITE_STMTSTATUS_FILTER_HIT); DefInt(SQLITE_STMTSTATUS_MEMUSED); } _DefGroup; DefGroup(syncFlags) { DefInt(SQLITE_SYNC_NORMAL); DefInt(SQLITE_SYNC_FULL); DefInt(SQLITE_SYNC_DATAONLY); } _DefGroup; DefGroup(trace) { DefInt(SQLITE_TRACE_STMT); DefInt(SQLITE_TRACE_PROFILE); DefInt(SQLITE_TRACE_ROW); DefInt(SQLITE_TRACE_CLOSE); } _DefGroup; DefGroup(txnState){ DefInt(SQLITE_TXN_NONE); DefInt(SQLITE_TXN_READ); DefInt(SQLITE_TXN_WRITE); } _DefGroup; DefGroup(udfFlags) { DefInt(SQLITE_DETERMINISTIC); DefInt(SQLITE_DIRECTONLY); DefInt(SQLITE_INNOCUOUS); DefInt(SQLITE_SUBTYPE); DefInt(SQLITE_RESULT_SUBTYPE); } _DefGroup; DefGroup(version) { DefInt(SQLITE_VERSION_NUMBER); DefStr(SQLITE_VERSION); DefStr(SQLITE_SOURCE_ID); } _DefGroup; DefGroup(vtab) { DefInt(SQLITE_INDEX_SCAN_UNIQUE); DefInt(SQLITE_INDEX_CONSTRAINT_EQ); DefInt(SQLITE_INDEX_CONSTRAINT_GT); DefInt(SQLITE_INDEX_CONSTRAINT_LE); DefInt(SQLITE_INDEX_CONSTRAINT_LT); DefInt(SQLITE_INDEX_CONSTRAINT_GE); DefInt(SQLITE_INDEX_CONSTRAINT_MATCH); DefInt(SQLITE_INDEX_CONSTRAINT_LIKE); DefInt(SQLITE_INDEX_CONSTRAINT_GLOB); DefInt(SQLITE_INDEX_CONSTRAINT_REGEXP); DefInt(SQLITE_INDEX_CONSTRAINT_NE); DefInt(SQLITE_INDEX_CONSTRAINT_ISNOT); DefInt(SQLITE_INDEX_CONSTRAINT_ISNOTNULL); DefInt(SQLITE_INDEX_CONSTRAINT_ISNULL); DefInt(SQLITE_INDEX_CONSTRAINT_IS); DefInt(SQLITE_INDEX_CONSTRAINT_LIMIT); DefInt(SQLITE_INDEX_CONSTRAINT_OFFSET); DefInt(SQLITE_INDEX_CONSTRAINT_FUNCTION); DefInt(SQLITE_VTAB_CONSTRAINT_SUPPORT); DefInt(SQLITE_VTAB_INNOCUOUS); DefInt(SQLITE_VTAB_DIRECTONLY); DefInt(SQLITE_VTAB_USES_ALL_SCHEMAS); DefInt(SQLITE_ROLLBACK); //DefInt(SQLITE_IGNORE); // Also used by sqlite3_authorizer() callback DefInt(SQLITE_FAIL); //DefInt(SQLITE_ABORT); // Also an error code DefInt(SQLITE_REPLACE); } _DefGroup; #undef DefGroup #undef DefStr #undef DefInt #undef _DefGroup /* ** Emit an array of "StructBinder" struct descripions, which look ** like: ** ** { ** "name": "MyStruct", ** "sizeof": 16, ** "members": { ** "member1": {"offset": 0,"sizeof": 4,"signature": "i"}, ** "member2": {"offset": 4,"sizeof": 4,"signature": "p"}, ** "member3": {"offset": 8,"sizeof": 8,"signature": "j"} ** } ** } ** ** Detailed documentation for those bits are in the docs for the ** Jaccwabyt JS-side component. */ /** Macros for emitting StructBinder description. */ #define StructBinder__(TYPE) \ n = 0; \ outf("%s{", (nStruct++ ? ", " : "")); \ out("\"name\": \"" # TYPE "\","); \ outf("\"sizeof\": %d", (int)sizeof(TYPE)); \ out(",\"members\": {"); #define StructBinder_(T) StructBinder__(T) /** ^^^ indirection needed to expand CurrentStruct */ #define StructBinder StructBinder_(CurrentStruct) #define _StructBinder CloseBrace(2) #define M(MEMBER,SIG) \ outf("%s\"%s\": " \ "{\"offset\":%d,\"sizeof\": %d,\"signature\":\"%s\"}", \ (n++ ? ", " : ""), #MEMBER, \ (int)offsetof(CurrentStruct,MEMBER), \ (int)sizeof(((CurrentStruct*)0)->MEMBER), \ SIG) nStruct = 0; out(", \"structs\": ["); { #define CurrentStruct sqlite3_vfs StructBinder { M(iVersion, "i"); M(szOsFile, "i"); M(mxPathname, "i"); M(pNext, "p"); M(zName, "s"); M(pAppData, "p"); M(xOpen, "i(pppip)"); M(xDelete, "i(ppi)"); M(xAccess, "i(ppip)"); M(xFullPathname, "i(ppip)"); M(xDlOpen, "p(pp)"); M(xDlError, "p(pip)"); M(xDlSym, "p()"); M(xDlClose, "v(pp)"); M(xRandomness, "i(pip)"); M(xSleep, "i(pi)"); M(xCurrentTime, "i(pp)"); M(xGetLastError, "i(pip)"); M(xCurrentTimeInt64, "i(pp)"); M(xSetSystemCall, "i(ppp)"); M(xGetSystemCall, "p(pp)"); M(xNextSystemCall, "p(pp)"); } _StructBinder; #undef CurrentStruct #define CurrentStruct sqlite3_io_methods StructBinder { M(iVersion, "i"); M(xClose, "i(p)"); M(xRead, "i(ppij)"); M(xWrite, "i(ppij)"); M(xTruncate, "i(pj)"); M(xSync, "i(pi)"); M(xFileSize, "i(pp)"); M(xLock, "i(pi)"); M(xUnlock, "i(pi)"); M(xCheckReservedLock, "i(pp)"); M(xFileControl, "i(pip)"); M(xSectorSize, "i(p)"); M(xDeviceCharacteristics, "i(p)"); M(xShmMap, "i(piiip)"); M(xShmLock, "i(piii)"); M(xShmBarrier, "v(p)"); M(xShmUnmap, "i(pi)"); M(xFetch, "i(pjip)"); M(xUnfetch, "i(pjp)"); } _StructBinder; #undef CurrentStruct #define CurrentStruct sqlite3_file StructBinder { M(pMethods, "p"); } _StructBinder; #undef CurrentStruct #define CurrentStruct sqlite3_kvvfs_methods StructBinder { M(xRead, "i(sspi)"); M(xWrite, "i(sss)"); M(xDelete, "i(ss)"); M(nKeySize, "i"); } _StructBinder; #undef CurrentStruct #define CurrentStruct sqlite3_vtab StructBinder { M(pModule, "p"); M(nRef, "i"); M(zErrMsg, "p"); } _StructBinder; #undef CurrentStruct #define CurrentStruct sqlite3_vtab_cursor StructBinder { M(pVtab, "p"); } _StructBinder; #undef CurrentStruct #define CurrentStruct sqlite3_module StructBinder { M(iVersion, "i"); M(xCreate, "i(ppippp)"); M(xConnect, "i(ppippp)"); M(xBestIndex, "i(pp)"); M(xDisconnect, "i(p)"); M(xDestroy, "i(p)"); M(xOpen, "i(pp)"); M(xClose, "i(p)"); M(xFilter, "i(pisip)"); M(xNext, "i(p)"); M(xEof, "i(p)"); M(xColumn, "i(ppi)"); M(xRowid, "i(pp)"); M(xUpdate, "i(pipp)"); M(xBegin, "i(p)"); M(xSync, "i(p)"); M(xCommit, "i(p)"); M(xRollback, "i(p)"); M(xFindFunction, "i(pispp)"); M(xRename, "i(ps)"); // ^^^ v1. v2+ follows... M(xSavepoint, "i(pi)"); M(xRelease, "i(pi)"); M(xRollbackTo, "i(pi)"); // ^^^ v2. v3+ follows... M(xShadowName, "i(s)"); } _StructBinder; #undef CurrentStruct /** ** Workaround: in order to map the various inner structs from ** sqlite3_index_info, we have to uplift those into constructs we ** can access by type name. These structs _must_ match their ** in-sqlite3_index_info counterparts byte for byte. */ typedef struct { int iColumn; unsigned char op; unsigned char usable; int iTermOffset; } sqlite3_index_constraint; typedef struct { int iColumn; unsigned char desc; } sqlite3_index_orderby; typedef struct { int argvIndex; unsigned char omit; } sqlite3_index_constraint_usage; { /* Validate that the above struct sizeof()s match ** expectations. We could improve upon this by ** checking the offsetof() for each member. */ const sqlite3_index_info siiCheck; #define IndexSzCheck(T,M) \ (sizeof(T) == sizeof(*siiCheck.M)) if(!IndexSzCheck(sqlite3_index_constraint,aConstraint) || !IndexSzCheck(sqlite3_index_orderby,aOrderBy) || !IndexSzCheck(sqlite3_index_constraint_usage,aConstraintUsage)){ assert(!"sizeof mismatch in sqlite3_index_... struct(s)"); return 0; } #undef IndexSzCheck } #define CurrentStruct sqlite3_index_constraint StructBinder { M(iColumn, "i"); M(op, "C"); M(usable, "C"); M(iTermOffset, "i"); } _StructBinder; #undef CurrentStruct #define CurrentStruct sqlite3_index_orderby StructBinder { M(iColumn, "i"); M(desc, "C"); } _StructBinder; #undef CurrentStruct #define CurrentStruct sqlite3_index_constraint_usage StructBinder { M(argvIndex, "i"); M(omit, "C"); } _StructBinder; #undef CurrentStruct #define CurrentStruct sqlite3_index_info StructBinder { M(nConstraint, "i"); M(aConstraint, "p"); M(nOrderBy, "i"); M(aOrderBy, "p"); M(aConstraintUsage, "p"); M(idxNum, "i"); M(idxStr, "p"); M(needToFreeIdxStr, "i"); M(orderByConsumed, "i"); M(estimatedCost, "d"); M(estimatedRows, "j"); M(idxFlags, "i"); M(colUsed, "j"); } _StructBinder; #undef CurrentStruct #if SQLITE_WASM_TESTS #define CurrentStruct WasmTestStruct StructBinder { M(v4, "i"); M(cstr, "s"); M(ppV, "p"); M(v8, "j"); M(xFunc, "v(p)"); } _StructBinder; #undef CurrentStruct #endif } out( "]"/*structs*/); out("}"/*top-level object*/); *zPos = 0; aBuffer[0] = '{'/*end of the race-condition workaround*/; return aBuffer; #undef StructBinder #undef StructBinder_ #undef StructBinder__ #undef M #undef _StructBinder #undef CloseBrace #undef out #undef outf #undef lenCheck } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** This function invokes the xDelete method of the given VFS (or the ** default VFS if pVfs is NULL), passing on the given filename. If ** zName is NULL, no default VFS is found, or it has no xDelete ** method, SQLITE_MISUSE is returned, else the result of the xDelete() ** call is returned. */ SQLITE_WASM_EXPORT int sqlite3__wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){ int rc = SQLITE_MISUSE /* ??? */; if( 0==pVfs && 0!=zName ) pVfs = sqlite3_vfs_find(0); if( zName && pVfs && pVfs->xDelete ){ rc = pVfs->xDelete(pVfs, zName, 1); } return rc; } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Returns a pointer to the given DB's VFS for the given DB name, ** defaulting to "main" if zDbName is 0. Returns 0 if no db with the ** given name is open. */ SQLITE_WASM_EXPORT sqlite3_vfs * sqlite3__wasm_db_vfs(sqlite3 *pDb, const char *zDbName){ sqlite3_vfs * pVfs = 0; sqlite3_file_control(pDb, zDbName ? zDbName : "main", SQLITE_FCNTL_VFS_POINTER, &pVfs); return pVfs; } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** This function resets the given db pointer's database as described at ** ** https://sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigresetdatabase ** ** But beware: virtual tables destroyed that way do not have their ** xDestroy() called, so will leak if they require that function for ** proper cleanup. ** ** Returns 0 on success, an SQLITE_xxx code on error. Returns ** SQLITE_MISUSE if pDb is NULL. */ SQLITE_WASM_EXPORT int sqlite3__wasm_db_reset(sqlite3 *pDb){ int rc = SQLITE_MISUSE; if( pDb ){ sqlite3_table_column_metadata(pDb, "main", 0, 0, 0, 0, 0, 0, 0); rc = sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); if( 0==rc ){ rc = sqlite3_exec(pDb, "VACUUM", 0, 0, 0); sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); } } return rc; } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Uses the given database's VFS xRead to stream the db file's ** contents out to the given callback. The callback gets a single ** chunk of size n (its 2nd argument) on each call and must return 0 ** on success, non-0 on error. This function returns 0 on success, ** SQLITE_NOTFOUND if no db is open, or propagates any other non-0 ** code from the callback. Note that this is not thread-friendly: it ** expects that it will be the only thread reading the db file and ** takes no measures to ensure that is the case. ** ** This implementation appears to work fine, but ** sqlite3__wasm_db_serialize() is arguably the better way to achieve ** this. */ SQLITE_WASM_EXPORT int sqlite3__wasm_db_export_chunked( sqlite3* pDb, int (*xCallback)(unsigned const char *zOut, int n) ){ sqlite3_int64 nSize = 0; sqlite3_int64 nPos = 0; sqlite3_file * pFile = 0; unsigned char buf[1024 * 8]; int nBuf = (int)sizeof(buf); int rc = pDb ? sqlite3_file_control(pDb, "main", SQLITE_FCNTL_FILE_POINTER, &pFile) : SQLITE_NOTFOUND; if( rc ) return rc; rc = pFile->pMethods->xFileSize(pFile, &nSize); if( rc ) return rc; if(nSize % nBuf){ /* DB size is not an even multiple of the buffer size. Reduce ** buffer size so that we do not unduly inflate the db size ** with zero-padding when exporting. */ if(0 == nSize % 4096) nBuf = 4096; else if(0 == nSize % 2048) nBuf = 2048; else if(0 == nSize % 1024) nBuf = 1024; else nBuf = 512; } for( ; 0==rc && nPospMethods->xRead(pFile, buf, nBuf, nPos); if( SQLITE_IOERR_SHORT_READ == rc ){ rc = (nPos + nBuf) < nSize ? rc : 0/*assume EOF*/; } if( 0==rc ) rc = xCallback(buf, nBuf); } return rc; } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** A proxy for sqlite3_serialize() which serializes the schema zSchema ** of pDb, placing the serialized output in pOut and nOut. nOut may be ** NULL. If zSchema is NULL then "main" is assumed. If pDb or pOut are ** NULL then SQLITE_MISUSE is returned. If allocation of the ** serialized copy fails, SQLITE_NOMEM is returned. On success, 0 is ** returned and `*pOut` will contain a pointer to the memory unless ** mFlags includes SQLITE_SERIALIZE_NOCOPY and the database has no ** contiguous memory representation, in which case `*pOut` will be ** NULL but 0 will be returned. ** ** If `*pOut` is not NULL, the caller is responsible for passing it to ** sqlite3_free() to free it. */ SQLITE_WASM_EXPORT int sqlite3__wasm_db_serialize( sqlite3 *pDb, const char *zSchema, unsigned char **pOut, sqlite3_int64 *nOut, unsigned int mFlags ){ unsigned char * z; if( !pDb || !pOut ) return SQLITE_MISUSE; if( nOut ) *nOut = 0; z = sqlite3_serialize(pDb, zSchema ? zSchema : "main", nOut, mFlags); if( z || (SQLITE_SERIALIZE_NOCOPY & mFlags) ){ *pOut = z; return 0; }else{ return SQLITE_NOMEM; } } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** ACHTUNG: it was discovered on 2023-08-11 that, with SQLITE_DEBUG, ** this function's out-of-scope use of the sqlite3_vfs/file/io_methods ** APIs leads to triggering of assertions in the core library. Its use ** is now deprecated and VFS-specific APIs for importing files need to ** be found to replace it. sqlite3__wasm_posix_create_file() is ** suitable for the "unix" family of VFSes. ** ** Creates a new file using the I/O API of the given VFS, containing ** the given number of bytes of the given data. If the file exists, it ** is truncated to the given length and populated with the given ** data. ** ** This function exists so that we can implement the equivalent of ** Emscripten's FS.createDataFile() in a VFS-agnostic way. This ** functionality is intended for use in uploading database files. ** ** Not all VFSes support this functionality, e.g. the "kvvfs" does ** not. ** ** If pVfs is NULL, sqlite3_vfs_find(0) is used. ** ** If zFile is NULL, pVfs is NULL (and sqlite3_vfs_find(0) returns ** NULL), or nData is negative, SQLITE_MISUSE are returned. ** ** On success, it creates a new file with the given name, populated ** with the fist nData bytes of pData. If pData is NULL, the file is ** created and/or truncated to nData bytes. ** ** Whether or not directory components of zFilename are created ** automatically or not is unspecified: that detail is left to the ** VFS. The "opfs" VFS, for example, creates them. ** ** If an error happens while populating or truncating the file, the ** target file will be deleted (if needed) if this function created ** it. If this function did not create it, it is not deleted but may ** be left in an undefined state. ** ** Returns 0 on success. On error, it returns a code described above ** or propagates a code from one of the I/O methods. ** ** Design note: nData is an integer, instead of int64, for WASM ** portability, so that the API can still work in builds where BigInt ** support is disabled or unavailable. */ SQLITE_WASM_EXPORT int sqlite3__wasm_vfs_create_file( sqlite3_vfs *pVfs, const char *zFilename, const unsigned char * pData, int nData ){ int rc; sqlite3_file *pFile = 0; sqlite3_io_methods const *pIo; const int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE #if 0 && defined(SQLITE_DEBUG) | SQLITE_OPEN_MAIN_JOURNAL /* ^^^^ This is for testing a horrible workaround to avoid triggering a specific assert() in os_unix.c:unixOpen(). Please do not enable this in real builds. */ #endif ; int flagsOut = 0; int fileExisted = 0; int doUnlock = 0; const unsigned char *pPos = pData; const int blockSize = 512 /* Because we are using pFile->pMethods->xWrite() for writing, and ** it may have a buffer limit related to sqlite3's pager size, we ** conservatively write in 512-byte blocks (smallest page ** size). */; //fprintf(stderr, "pVfs=%p, zFilename=%s, nData=%d\n", pVfs, zFilename, nData); if( !pVfs ) pVfs = sqlite3_vfs_find(0); if( !pVfs || !zFilename || nData<0 ) return SQLITE_MISUSE; pVfs->xAccess(pVfs, zFilename, SQLITE_ACCESS_EXISTS, &fileExisted); rc = sqlite3OsOpenMalloc(pVfs, zFilename, &pFile, openFlags, &flagsOut); #if 0 # define RC fprintf(stderr,"create_file(%s,%s) @%d rc=%d\n", \ pVfs->zName, zFilename, __LINE__, rc); #else # define RC #endif RC; if(rc) return rc; pIo = pFile->pMethods; if( pIo->xLock ) { /* We need xLock() in order to accommodate the OPFS VFS, as it ** obtains a writeable handle via the lock operation and releases ** it in xUnlock(). If we don't do those here, we have to add code ** to the VFS to account check whether it was locked before ** xFileSize(), xTruncate(), and the like, and release the lock ** only if it was unlocked when the op was started. */ rc = pIo->xLock(pFile, SQLITE_LOCK_EXCLUSIVE); RC; doUnlock = 0==rc; } if( 0==rc ){ rc = pIo->xTruncate(pFile, nData); RC; } if( 0==rc && 0!=pData && nData>0 ){ while( 0==rc && nData>0 ){ const int n = nData>=blockSize ? blockSize : nData; rc = pIo->xWrite(pFile, pPos, n, (sqlite3_int64)(pPos - pData)); RC; nData -= n; pPos += n; } if( 0==rc && nData>0 ){ assert( nDataxWrite(pFile, pPos, nData, (sqlite3_int64)(pPos - pData)); RC; } } if( pIo->xUnlock && doUnlock!=0 ){ pIo->xUnlock(pFile, SQLITE_LOCK_NONE); } pIo->xClose(pFile); if( rc!=0 && 0==fileExisted ){ pVfs->xDelete(pVfs, zFilename, 1); } RC; #undef RC return rc; } /** ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Creates or overwrites a file using the POSIX file API, ** i.e. Emscripten's virtual filesystem. Creates or truncates ** zFilename, appends pData bytes to it, and returns 0 on success or ** SQLITE_IOERR on error. */ SQLITE_WASM_EXPORT int sqlite3__wasm_posix_create_file( const char *zFilename, const unsigned char * pData, int nData ){ int rc; FILE * pFile = 0; int fileExisted = 0; size_t nWrote = 1; if( !zFilename || nData<0 || (pData==0 && nData>0) ) return SQLITE_MISUSE; pFile = fopen(zFilename, "w"); if( 0==pFile ) return SQLITE_IOERR; if( nData>0 ){ nWrote = fwrite(pData, (size_t)nData, 1, pFile); } fclose(pFile); return 1==nWrote ? 0 : SQLITE_IOERR; } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Allocates sqlite3KvvfsMethods.nKeySize bytes from ** sqlite3__wasm_pstack_alloc() and returns 0 if that allocation fails, ** else it passes that string to kvstorageMakeKey() and returns a ** NUL-terminated pointer to that string. It is up to the caller to ** use sqlite3__wasm_pstack_restore() to free the returned pointer. */ SQLITE_WASM_EXPORT char * sqlite3__wasm_kvvfsMakeKeyOnPstack(const char *zClass, const char *zKeyIn){ assert(sqlite3KvvfsMethods.nKeySize>24); char *zKeyOut = (char *)sqlite3__wasm_pstack_alloc(sqlite3KvvfsMethods.nKeySize); if(zKeyOut){ kvstorageMakeKey(zClass, zKeyIn, zKeyOut); } return zKeyOut; } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Returns the pointer to the singleton object which holds the kvvfs ** I/O methods and associated state. */ SQLITE_WASM_EXPORT sqlite3_kvvfs_methods * sqlite3__wasm_kvvfs_methods(void){ return &sqlite3KvvfsMethods; } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** This is a proxy for the variadic sqlite3_vtab_config() which passes ** its argument on, or not, to sqlite3_vtab_config(), depending on the ** value of its 2nd argument. Returns the result of ** sqlite3_vtab_config(), or SQLITE_MISUSE if the 2nd arg is not a ** valid value. */ SQLITE_WASM_EXPORT int sqlite3__wasm_vtab_config(sqlite3 *pDb, int op, int arg){ switch(op){ case SQLITE_VTAB_DIRECTONLY: case SQLITE_VTAB_INNOCUOUS: return sqlite3_vtab_config(pDb, op); case SQLITE_VTAB_CONSTRAINT_SUPPORT: return sqlite3_vtab_config(pDb, op, arg); default: return SQLITE_MISUSE; } } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Wrapper for the variants of sqlite3_db_config() which take ** (int,int*) variadic args. */ SQLITE_WASM_EXPORT int sqlite3__wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){ switch(op){ case SQLITE_DBCONFIG_ENABLE_FKEY: case SQLITE_DBCONFIG_ENABLE_TRIGGER: case SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: case SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: case SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: case SQLITE_DBCONFIG_ENABLE_QPSG: case SQLITE_DBCONFIG_TRIGGER_EQP: case SQLITE_DBCONFIG_RESET_DATABASE: case SQLITE_DBCONFIG_DEFENSIVE: case SQLITE_DBCONFIG_WRITABLE_SCHEMA: case SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: case SQLITE_DBCONFIG_DQS_DML: case SQLITE_DBCONFIG_DQS_DDL: case SQLITE_DBCONFIG_ENABLE_VIEW: case SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: case SQLITE_DBCONFIG_TRUSTED_SCHEMA: case SQLITE_DBCONFIG_STMT_SCANSTATUS: case SQLITE_DBCONFIG_REVERSE_SCANORDER: return sqlite3_db_config(pDb, op, arg1, pArg2); default: return SQLITE_MISUSE; } } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Wrapper for the variants of sqlite3_db_config() which take ** (void*,int,int) variadic args. */ SQLITE_WASM_EXPORT int sqlite3__wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int arg3){ switch(op){ case SQLITE_DBCONFIG_LOOKASIDE: return sqlite3_db_config(pDb, op, pArg1, arg2, arg3); default: return SQLITE_MISUSE; } } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Wrapper for the variants of sqlite3_db_config() which take ** (const char *) variadic args. */ SQLITE_WASM_EXPORT int sqlite3__wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){ switch(op){ case SQLITE_DBCONFIG_MAINDBNAME: return sqlite3_db_config(pDb, op, zArg); default: return SQLITE_MISUSE; } } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Binding for combinations of sqlite3_config() arguments which take ** a single integer argument. */ SQLITE_WASM_EXPORT int sqlite3__wasm_config_i(int op, int arg){ return sqlite3_config(op, arg); } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Binding for combinations of sqlite3_config() arguments which take ** two int arguments. */ SQLITE_WASM_EXPORT int sqlite3__wasm_config_ii(int op, int arg1, int arg2){ return sqlite3_config(op, arg1, arg2); } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Binding for combinations of sqlite3_config() arguments which take ** a single i64 argument. */ SQLITE_WASM_EXPORT int sqlite3__wasm_config_j(int op, sqlite3_int64 arg){ return sqlite3_config(op, arg); } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** If z is not NULL, returns the result of passing z to ** sqlite3_mprintf()'s %Q modifier (if addQuotes is true) or %q (if ** addQuotes is 0). Returns NULL if z is NULL or on OOM. */ SQLITE_WASM_EXPORT char * sqlite3__wasm_qfmt_token(char *z, int addQuotes){ char * rc = 0; if( z ){ rc = addQuotes ? sqlite3_mprintf("%Q", z) : sqlite3_mprintf("%q", z); } return rc; } #if defined(__EMSCRIPTEN__) && defined(SQLITE_ENABLE_WASMFS) #include /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings, specifically ** only when building with Emscripten's WASMFS support. ** ** This function should only be called if the JS side detects the ** existence of the Origin-Private FileSystem (OPFS) APIs in the ** client. The first time it is called, this function instantiates a ** WASMFS backend impl for OPFS. On success, subsequent calls are ** no-ops. ** ** This function may be passed a "mount point" name, which must have a ** leading "/" and is currently restricted to a single path component, ** e.g. "/foo" is legal but "/foo/" and "/foo/bar" are not. If it is ** NULL or empty, it defaults to "/opfs". ** ** Returns 0 on success, SQLITE_NOMEM if instantiation of the backend ** object fails, SQLITE_IOERR if mkdir() of the zMountPoint dir in ** the virtual FS fails. In builds compiled without SQLITE_ENABLE_WASMFS ** defined, SQLITE_NOTFOUND is returned without side effects. */ SQLITE_WASM_EXPORT int sqlite3__wasm_init_wasmfs(const char *zMountPoint){ static backend_t pOpfs = 0; if( !zMountPoint || !*zMountPoint ) zMountPoint = "/opfs"; if( !pOpfs ){ pOpfs = wasmfs_create_opfs_backend(); } /** It's not enough to instantiate the backend. We have to create a mountpoint in the VFS and attach the backend to it. */ if( pOpfs && 0!=access(zMountPoint, F_OK) ){ /* Note that this check and is not robust but it will hypothetically suffice for the transient wasm-based virtual filesystem we're currently running in. */ const int rc = wasmfs_create_directory(zMountPoint, 0777, pOpfs); /*emscripten_console_logf("OPFS mkdir(%s) rc=%d", zMountPoint, rc);*/ if(rc) return SQLITE_IOERR; } return pOpfs ? 0 : SQLITE_NOMEM; } #else SQLITE_WASM_EXPORT int sqlite3__wasm_init_wasmfs(const char *zUnused){ //emscripten_console_warn("WASMFS OPFS is not compiled in."); if(zUnused){/*unused*/} return SQLITE_NOTFOUND; } #endif /* __EMSCRIPTEN__ && SQLITE_ENABLE_WASMFS */ #if SQLITE_WASM_TESTS SQLITE_WASM_EXPORT int sqlite3__wasm_test_intptr(int * p){ return *p = *p * 2; } SQLITE_WASM_EXPORT void * sqlite3__wasm_test_voidptr(void * p){ return p; } SQLITE_WASM_EXPORT int64_t sqlite3__wasm_test_int64_max(void){ return (int64_t)0x7fffffffffffffff; } SQLITE_WASM_EXPORT int64_t sqlite3__wasm_test_int64_min(void){ return ~sqlite3__wasm_test_int64_max(); } SQLITE_WASM_EXPORT int64_t sqlite3__wasm_test_int64_times2(int64_t x){ return x * 2; } SQLITE_WASM_EXPORT void sqlite3__wasm_test_int64_minmax(int64_t * min, int64_t *max){ *max = sqlite3__wasm_test_int64_max(); *min = sqlite3__wasm_test_int64_min(); /*printf("minmax: min=%lld, max=%lld\n", *min, *max);*/ } SQLITE_WASM_EXPORT int64_t sqlite3__wasm_test_int64ptr(int64_t * p){ /*printf("sqlite3__wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/ return *p = *p * 2; } SQLITE_WASM_EXPORT void sqlite3__wasm_test_stack_overflow(int recurse){ if(recurse) sqlite3__wasm_test_stack_overflow(recurse); } /* For testing the 'string:dealloc' whwasmutil.xWrap() conversion. */ SQLITE_WASM_EXPORT char * sqlite3__wasm_test_str_hello(int fail){ char * s = fail ? 0 : (char *)sqlite3_malloc(6); if(s){ memcpy(s, "hello", 5); s[5] = 0; } return s; } /* ** For testing using SQLTester scripts. ** ** Return non-zero if string z matches glob pattern zGlob and zero if the ** pattern does not match. ** ** To repeat: ** ** zero == no match ** non-zero == match ** ** Globbing rules: ** ** '*' Matches any sequence of zero or more characters. ** ** '?' Matches exactly one character. ** ** [...] Matches one character from the enclosed list of ** characters. ** ** [^...] Matches one character not in the enclosed list. ** ** '#' Matches any sequence of one or more digits with an ** optional + or - sign in front, or a hexadecimal ** literal of the form 0x... */ static int sqlite3__wasm_SQLTester_strnotglob(const char *zGlob, const char *z){ int c, c2; int invert; int seen; typedef int (*recurse_f)(const char *,const char *); static const recurse_f recurse = sqlite3__wasm_SQLTester_strnotglob; while( (c = (*(zGlob++)))!=0 ){ if( c=='*' ){ while( (c=(*(zGlob++))) == '*' || c=='?' ){ if( c=='?' && (*(z++))==0 ) return 0; } if( c==0 ){ return 1; }else if( c=='[' ){ while( *z && recurse(zGlob-1,z)==0 ){ z++; } return (*z)!=0; } while( (c2 = (*(z++)))!=0 ){ while( c2!=c ){ c2 = *(z++); if( c2==0 ) return 0; } if( recurse(zGlob,z) ) return 1; } return 0; }else if( c=='?' ){ if( (*(z++))==0 ) return 0; }else if( c=='[' ){ int prior_c = 0; seen = 0; invert = 0; c = *(z++); if( c==0 ) return 0; c2 = *(zGlob++); if( c2=='^' ){ invert = 1; c2 = *(zGlob++); } if( c2==']' ){ if( c==']' ) seen = 1; c2 = *(zGlob++); } while( c2 && c2!=']' ){ if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){ c2 = *(zGlob++); if( c>=prior_c && c<=c2 ) seen = 1; prior_c = 0; }else{ if( c==c2 ){ seen = 1; } prior_c = c2; } c2 = *(zGlob++); } if( c2==0 || (seen ^ invert)==0 ) return 0; }else if( c=='#' ){ if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ z += 3; while( sqlite3Isxdigit(z[0]) ){ z++; } }else{ if( (z[0]=='-' || z[0]=='+') && sqlite3Isdigit(z[1]) ) z++; if( !sqlite3Isdigit(z[0]) ) return 0; z++; while( sqlite3Isdigit(z[0]) ){ z++; } } }else{ if( c!=(*(z++)) ) return 0; } } return *z==0; } SQLITE_WASM_EXPORT int sqlite3__wasm_SQLTester_strglob(const char *zGlob, const char *z){ return !sqlite3__wasm_SQLTester_strnotglob(zGlob, z); } #endif /* SQLITE_WASM_TESTS */ #undef SQLITE_WASM_EXPORT