aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api/sqlite3-wasm.c
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-08-10 11:26:08 +0000
committerstephan <stephan@noemail.net>2022-08-10 11:26:08 +0000
commit3961b2636329819f16b1f32739274f3a1d3273de (patch)
treeb363bc8081c45b6e16ffe1d9a55862dd0bda4036 /ext/wasm/api/sqlite3-wasm.c
parent8c3b7501af8fa321a1cdf3194d91603d0cbc6394 (diff)
downloadsqlite-3961b2636329819f16b1f32739274f3a1d3273de.tar.gz
sqlite-3961b2636329819f16b1f32739274f3a1d3273de.zip
wasm refactoring part 2 of (apparently) 2: moved ext/fiddle/... into ext/wasm and restructured the core API-related parts of the JS/WASM considerably.
FossilOrigin-Name: 27f9da4eaaff39d1d58e9ffef7ddccf1e41b3726914f754b920e3e1fb572cba6
Diffstat (limited to 'ext/wasm/api/sqlite3-wasm.c')
-rw-r--r--ext/wasm/api/sqlite3-wasm.c413
1 files changed, 413 insertions, 0 deletions
diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c
new file mode 100644
index 000000000..c27dad56f
--- /dev/null
+++ b/ext/wasm/api/sqlite3-wasm.c
@@ -0,0 +1,413 @@
+#include "sqlite3.c"
+
+/*
+** 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. 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.
+*/
+int sqlite3_wasm_db_error(sqlite3*db, int err_code,
+ const char *zMsg){
+ if(0!=zMsg){
+ const int nMsg = sqlite3Strlen30(zMsg);
+ sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg);
+ }else{
+ sqlite3ErrorWithMsg(db, err_code, NULL);
+ }
+ return err_code;
+}
+
+/*
+** 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 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. In debug builds
+** that will trigger an assert().
+*/
+const char * sqlite3_wasm_enum_json(void){
+ static char strBuf[1024 * 8] = {0} /* where the JSON goes */;
+ int n = 0, childCount = 0, structCount = 0
+ /* output counters for figuring out where commas go */;
+ char * pos = &strBuf[1] /* skip first byte for now to help protect
+ ** against a small race condition */;
+ char const * const zEnd = pos + sizeof(strBuf) /* one-past-the-end */;
+ if(strBuf[0]) return strBuf;
+ /* Leave strBuf[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 strBuf, 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(pos < zEnd - 128 \
+ && "sqlite3_wasm_enum_json() buffer is too small."); \
+ if(pos >= zEnd - 128) return 0
+#define outf(format,...) \
+ pos += snprintf(pos, ((size_t)(zEnd - pos)), format, __VA_ARGS__); \
+ lenCheck
+#define out(TXT) outf("%s",TXT)
+#define CloseBrace(LEVEL) \
+ assert(LEVEL<5); memset(pos, '}', LEVEL); pos+=LEVEL; lenCheck
+
+/* Macros for emitting maps of integer- and string-type macros to
+** their values. */
+#define DefGroup(KEY) n = 0; \
+ outf("%s\"" #KEY "\": {",(childCount++ ? "," : ""));
+#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)
+
+ DefGroup(version) {
+ DefInt(SQLITE_VERSION_NUMBER);
+ DefStr(SQLITE_VERSION);
+ DefStr(SQLITE_SOURCE_ID);
+ } _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(dataTypes) {
+ DefInt(SQLITE_INTEGER);
+ DefInt(SQLITE_FLOAT);
+ DefInt(SQLITE_TEXT);
+ DefInt(SQLITE_BLOB);
+ DefInt(SQLITE_NULL);
+ } _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(blobFinalizers) {
+ /* SQLITE_STATIC/TRANSIENT need to be handled explicitly as
+ ** integers to avoid casting-related warnings. */
+ out("\"SQLITE_STATIC\":0, "
+ "\"SQLITE_TRANSIENT\":-1");
+ } _DefGroup;
+
+ DefGroup(udfFlags) {
+ DefInt(SQLITE_DETERMINISTIC);
+ DefInt(SQLITE_DIRECTONLY);
+ DefInt(SQLITE_INNOCUOUS);
+ } _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(syncFlags) {
+ DefInt(SQLITE_SYNC_NORMAL);
+ DefInt(SQLITE_SYNC_FULL);
+ DefInt(SQLITE_SYNC_DATAONLY);
+ } _DefGroup;
+
+ DefGroup(prepareFlags) {
+ DefInt(SQLITE_PREPARE_PERSISTENT);
+ DefInt(SQLITE_PREPARE_NORMALIZE);
+ DefInt(SQLITE_PREPARE_NO_VTAB);
+ } _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(access){
+ DefInt(SQLITE_ACCESS_EXISTS);
+ DefInt(SQLITE_ACCESS_READWRITE);
+ DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/;
+ } _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 an external
+ ** file (StackBinder.md, as of this writing).
+ */
+
+ /** Macros for emitting StructBinder description. */
+#define StructBinder__(TYPE) \
+ n = 0; \
+ outf("%s{", (structCount++ ? ", " : "")); \
+ 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)
+
+ structCount = 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
+
+ } out( "]"/*structs*/);
+
+ out("}"/*top-level object*/);
+ *pos = 0;
+ strBuf[0] = '{'/*end of the race-condition workaround*/;
+ return strBuf;
+#undef StructBinder
+#undef StructBinder_
+#undef StructBinder__
+#undef M
+#undef _StructBinder
+#undef CloseBrace
+#undef out
+#undef outf
+#undef lenCheck
+}