diff options
author | stephan <stephan@noemail.net> | 2022-05-22 00:27:19 +0000 |
---|---|---|
committer | stephan <stephan@noemail.net> | 2022-05-22 00:27:19 +0000 |
commit | 166542cc98f78ac2e25adb8e84cffcb6eee30fc0 (patch) | |
tree | 0410e697efe668fb38af437f0c5ee43b0a9e18a1 /ext/fiddle/sqlite3-api.js | |
parent | 4ec29fc1158afb199a0b631339e4cda72b252522 (diff) | |
download | sqlite-166542cc98f78ac2e25adb8e84cffcb6eee30fc0.tar.gz sqlite-166542cc98f78ac2e25adb8e84cffcb6eee30fc0.zip |
Build refactoring for the fiddle/wasm bits. Set up wasm binding of a chunk of the core C API and added some infastructure for creating test pages for it.
FossilOrigin-Name: dea098b64eb95c395b346ebcae687afe42b7d21df48833527808c02226300a66
Diffstat (limited to 'ext/fiddle/sqlite3-api.js')
-rw-r--r-- | ext/fiddle/sqlite3-api.js | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js new file mode 100644 index 000000000..65e6b00f6 --- /dev/null +++ b/ext/fiddle/sqlite3-api.js @@ -0,0 +1,165 @@ +/* + 2022-05-22 + + The author disclaims copyright to this source code. In place of a + legal notice, here is a blessing: + + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give. + + *********************************************************************** + + This file is intended to be loaded after loading + sqlite3-module.wasm. It sets one of any number of potential + bindings using that API, this one as closely matching the C-native + API as is feasible. + + Note that this file is not named sqlite3.js because that file gets + generated by emscripten as the JS-glue counterpart of sqlite3.wasm. + + The API gets installed as self.sqlite3, where self is expected to be + either the global window or Worker object. + + Because using this API properly requires some degree of WASM-related + magic, it is not recommended that this API be used as-is in + client-level code, but instead is intended to be used as a basis for + APIs more appropriate for high-level client code. + + This file installs namespace.sqlite3, where namespace is `self`, + meaning either the global window or worker, depending on where this + is loaded from. +*/ +(function(namespace){ + /* For reference: sql.js does essentially everything we want and + it solves much of the wasm-related voodoo, but we'll need a + different structure because we want the db connection to run in + a worker thread and feed data back into the main + thread. Regardless of those differences, it makes a great point + of reference: + + https://github.com/sql-js/sql.js + + Some of the specific design goals here: + + - Bind a low-level sqlite3 API which is close to the native one + in terms of usage. + + - Create a higher-level one, more akin to sql.js and + node.js-style implementations. This one would speak directly + to the low-level API. This API could be used by clients who + import the low-level API directly into their main thread + (which we don't want to recommend but also don't want to + outright forbid). + + - Create a second higher-level one which speaks to the + low-level API via worker messages. This one would be intended + for use in the main thread, talking to the low-level UI via + worker messages. Because workers have only a single message + channel, some acrobatics will be needed here to feed async + work results back into client-side callbacks (as those + callbacks cannot simply be passed to the worker). Exactly + what those acrobatics should look like is not yet entirely + clear and much experimentation is pending. + */ + + /** + Set up the main sqlite3 binding API here, mimicking the C API as + closely as we can. + + Attribution: though not a direct copy/paste, much of what + follows is strongly influenced by the sql.js implementation. + */ + const api = { + /* It is important that the following integer values match + those from the C code. Ideally we could fetch them from the + C API, e.g., in the form of a JSON object, but getting that + JSON string constructed within our current confised is + currently not worth the effort. */ + /* Minimum subset of sqlite result codes we'll need. */ + SQLITE_OK: 0, + SQLITE_ROW: 100, + SQLITE_DONE: 101, + /* sqlite data types */ + SQLITE_INTEGER: 1, + SQLITE_FLOAT: 2, + SQLITE_TEXT: 3, + SQLITE_BLOB: 4, + /* sqlite encodings, used for creating UDFs, noting that we + will only support UTF8. */ + SQLITE_UTF8: 1 + }; + const cwrap = Module.cwrap; + [/* C-side functions to bind. Each entry is an array with 3 or 4 + elements: + + ["c-side name", + "result type" (cwrap() syntax), + [arg types in cwrap() syntax] + ] + + If it has 4 elements, the first one is an alternate name to + use for the JS-side binding. That's required when overloading + a binding for two different uses. + */ + ["sqlite3_open", "number", ["string", "number"]], + ["sqlite3_close_v2", "number", ["number"]], + ["sqlite3_exec", "number", + ["number", "string", "number", "number", "number"]], + ["sqlite3_changes", "number", ["number"]], + ["sqlite3_prepare_v2", "number", ["number", "string", "number", "number", "number"]], + ["sqlite3_prepare_v2_sqlptr", + /* Impl which requires that the 2nd argument be a pointer to + the SQL, instead of a string. This is used for cases where + we require a non-NULL value for the final argument. We may + or may not need this, depending on how our higher-level + API shapes up, but this code's spiritual guide (sql.js) + uses it we we'll include it. */ + "sqlite3_prepare_v2", + "number", ["number", "number", "number", "number", "number"]], + ["sqlite3_bind_text","number",["number", "number", "number", "number", "number"]], + ["sqlite3_bind_blob","number",["number", "number", "number", "number", "number"]], + ["sqlite3_bind_double","number",["number", "number", "number"]], + ["sqlite3_bind_int","number",["number", "number", "number"]], + ["sqlite3_bind_parameter_index","number",["number", "string"]], + ["sqlite3_step", "number", ["number"]], + ["sqlite3_errmsg", "string", ["number"]], + ["sqlite3_column_count","number",["number"]], + ["sqlite3_data_count", "number", ["number"]], + ["sqlite3_column_count", "number", ["number"]], + ["sqlite3_column_double","number",["number", "number"]], + ["sqlite3_column_text","string",["number", "number"]], + ["sqlite3_column_blob","number", ["number", "number"]], + ["sqlite3_column_bytes","number",["number", "number"]], + ["sqlite3_column_type","number",["number", "number"]], + ["sqlite3_column_name","string",["number", "number"]], + ["sqlite3_reset", "number", ["number"]], + ["sqlite3_clear_bindings","number",["number"]], + ["sqlite3_finalize", "number", ["number"]], + ["sqlite3_create_function_v2", "number", + ["number", "string", "number", "number", + "number", "number", "number", "number", + "number"]], + ["sqlite3_value_type", "number", ["number"]], + ["sqlite3_value_bytes","number",["number"]], + ["sqlite3_value_text", "string", ["number"]], + ["sqlite3_value_blob", "number", ["number"]], + ["sqlite3_value_double","number",["number"]], + ["sqlite3_result_double",null,["number", "number"]], + ["sqlite3_result_null",null,["number"]], + ["sqlite3_result_text",null,["number", "string", "number", "number"]], + ["sqlite3_result_blob",null,["number", "number", "number", "number"]], + ["sqlite3_result_int",null,["number", "number"]], + ["sqlite3_result_error",null,["number", "string", "number"]], + ["sqlite3_libversion", "string", []], + ["sqlite3_sourceid", "string", []] + //["sqlite3_sql", "string", ["number"]], + //["sqlite3_normalized_sql", "string", ["number"]] + ].forEach(function(e){ + const a = Array.prototype.slice.call(e); + const k = (4==a.length) ? a.shift() : a[0]; + api[k] = cwrap.apply(this, a); + }); + //console.debug("libversion =",api.sqlite3_libversion()); + namespace.sqlite3 = api; +})(self/*worker or window*/); |