aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-12-25 20:25:44 +0000
committerstephan <stephan@noemail.net>2022-12-25 20:25:44 +0000
commit3caf13f1cbf3e502eb898959b3de3e42966e202e (patch)
treebec129ee03bbaf478f92fa373ca4292b0501ccc5 /ext/wasm/api
parent7a5544b958e04f8cf99e27353aa3982b28728a5e (diff)
parent9d61db1944238d35ee00cefe0b4bfb7ac291e36b (diff)
downloadsqlite-3caf13f1cbf3e502eb898959b3de3e42966e202e.tar.gz
sqlite-3caf13f1cbf3e502eb898959b3de3e42966e202e.zip
Merge wasm-session-api branch into trunk, adding the session API to the JS/WASM components.
FossilOrigin-Name: dfb8b651fa4faef2d3307a05512cdc479398484c3a59715827179c363861a777
Diffstat (limited to 'ext/wasm/api')
-rw-r--r--ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api48
-rw-r--r--ext/wasm/api/sqlite3-api-glue.js195
-rw-r--r--ext/wasm/api/sqlite3-api-oo1.js4
-rw-r--r--ext/wasm/api/sqlite3-api-prologue.js17
-rw-r--r--ext/wasm/api/sqlite3-wasm.c31
5 files changed, 280 insertions, 15 deletions
diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api
index 47a7e4a06..a6559cbb3 100644
--- a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api
+++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api
@@ -1,3 +1,6 @@
+_malloc
+_free
+_realloc
_sqlite3_aggregate_context
_sqlite3_bind_blob
_sqlite3_bind_double
@@ -144,6 +147,45 @@ _sqlite3_vtab_in_next
_sqlite3_vtab_nochange
_sqlite3_vtab_on_conflict
_sqlite3_vtab_rhs_value
-_malloc
-_free
-_realloc
+_sqlite3changegroup_add
+_sqlite3changegroup_add_strm
+_sqlite3changegroup_delete
+_sqlite3changegroup_new
+_sqlite3changegroup_output
+_sqlite3changegroup_output_strm
+_sqlite3changeset_apply
+_sqlite3changeset_apply_strm
+_sqlite3changeset_apply_v2
+_sqlite3changeset_apply_v2_strm
+_sqlite3changeset_concat
+_sqlite3changeset_concat_strm
+_sqlite3changeset_conflict
+_sqlite3changeset_finalize
+_sqlite3changeset_fk_conflicts
+_sqlite3changeset_invert
+_sqlite3changeset_invert_strm
+_sqlite3changeset_new
+_sqlite3changeset_next
+_sqlite3changeset_old
+_sqlite3changeset_op
+_sqlite3changeset_pk
+_sqlite3changeset_start
+_sqlite3changeset_start_strm
+_sqlite3changeset_start_v2
+_sqlite3changeset_start_v2_strm
+_sqlite3session_attach
+_sqlite3session_changeset
+_sqlite3session_changeset_size
+_sqlite3session_changeset_strm
+_sqlite3session_config
+_sqlite3session_create
+_sqlite3session_delete
+_sqlite3session_diff
+_sqlite3session_enable
+_sqlite3session_indirect
+_sqlite3session_isempty
+_sqlite3session_memory_used
+_sqlite3session_object_config
+_sqlite3session_patchset
+_sqlite3session_patchset_strm
+_sqlite3session_table_filter
diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js
index dcdc17942..8a0d8147f 100644
--- a/ext/wasm/api/sqlite3-api-glue.js
+++ b/ext/wasm/api/sqlite3-api-glue.js
@@ -337,6 +337,184 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"]
];
+ // Add session/changeset APIs...
+ if(wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add){
+ /* ACHTUNG: 2022-12-23: the session/changeset API bindings are
+ COMPLETELY UNTESTED. */
+ /**
+ FuncPtrAdapter options for session-related callbacks with the
+ native signature "i(ps)". This proxy converts the 2nd argument
+ from a C string to a JS string before passing the arguments on
+ to the client-provided JS callback.
+ */
+ const __ipsProxy = {
+ signature: 'i(ps)',
+ callProxy:(callback)=>{
+ return (p,s)=>{
+ try{return callback(p, wasm.cstrToJs(s)) | 0}
+ catch(e){return e.resultCode || capi.SQLITE_ERROR}
+ }
+ }
+ };
+
+ wasm.bindingSignatures.int64.push(...[
+ ['sqlite3changegroup_add', 'int', ['sqlite3_changegroup*', 'int', 'void*']],
+ ['sqlite3changegroup_add_strm', 'int', [
+ 'sqlite3_changegroup*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changegroup_delete', undefined, ['sqlite3_changegroup*']],
+ ['sqlite3changegroup_new', 'int', ['**']],
+ ['sqlite3changegroup_output', 'int', ['sqlite3_changegroup*', 'int*', '**']],
+ ['sqlite3changegroup_output_strm', 'int', [
+ 'sqlite3_changegroup*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_apply', 'int', [
+ 'sqlite3*', 'int', 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xFilter', bindScope: 'transient', ...__ipsProxy
+ }),
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_apply_strm', 'int', [
+ 'sqlite3*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xFilter', bindScope: 'transient', ...__ipsProxy
+ }),
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_apply_v2', 'int', [
+ 'sqlite3*', 'int', 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xFilter', bindScope: 'transient', ...__ipsProxy
+ }),
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
+ }),
+ 'void*', '**', 'int*', 'int'
+
+ ]],
+ ['sqlite3changeset_apply_v2_strm', 'int', [
+ 'sqlite3*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xFilter', bindScope: 'transient', ...__ipsProxy
+ }),
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
+ }),
+ 'void*', '**', 'int*', 'int'
+ ]],
+ ['sqlite3changeset_concat', 'int', ['int','void*', 'int', 'void*', 'int*', '**']],
+ ['sqlite3changeset_concat_strm', 'int', [
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInputA', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInputB', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_conflict', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
+ ['sqlite3changeset_finalize', 'int', ['sqlite3_changeset_iter*']],
+ ['sqlite3changeset_fk_conflicts', 'int', ['sqlite3_changeset_iter*', 'int*']],
+ ['sqlite3changeset_invert', 'int', ['int', 'void*', 'int*', '**']],
+ ['sqlite3changeset_invert_strm', 'int', [
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_new', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
+ ['sqlite3changeset_next', 'int', ['sqlite3_changeset_iter*']],
+ ['sqlite3changeset_old', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
+ ['sqlite3changeset_op', 'int', [
+ 'sqlite3_changeset_iter*', '**', 'int*', 'int*','int*'
+ ]],
+ ['sqlite3changeset_pk', 'int', ['sqlite3_changeset_iter*', '**', 'int*']],
+ ['sqlite3changeset_start', 'int', ['**', 'int', '*']],
+ ['sqlite3changeset_start_strm', 'int', [
+ '**',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3changeset_start_v2', 'int', ['**', 'int', '*', 'int']],
+ ['sqlite3changeset_start_v2_strm', 'int', [
+ '**',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*', 'int'
+ ]],
+ ['sqlite3session_attach', 'int', ['sqlite3_session*', 'string']],
+ ['sqlite3session_changeset', 'int', ['sqlite3_session*', 'int*', '**']],
+ ['sqlite3session_changeset_size', 'i64', ['sqlite3_session*']],
+ ['sqlite3session_changeset_strm', 'int', [
+ 'sqlite3_session*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xOutput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3session_config', 'int', ['int', 'void*']],
+ ['sqlite3session_create', 'int', ['sqlite3*', 'string', '**']],
+ ['sqlite3session_delete', undefined, ['sqlite3_session*']],
+ ['sqlite3session_diff', 'int', ['sqlite3_session*', 'string', 'string', '**']],
+ ['sqlite3session_enable', 'int', ['sqlite3_session*', 'int']],
+ ['sqlite3session_indirect', 'int', ['sqlite3_session*', 'int']],
+ ['sqlite3session_isempty', 'int', ['sqlite3_session*']],
+ ['sqlite3session_memory_used', 'i64', ['sqlite3_session*']],
+ ['sqlite3session_object_config', 'int', ['sqlite3_session*', 'int', 'void*']],
+ ['sqlite3session_patchset', 'int', ['sqlite3_session*', '*', '**']],
+ ['sqlite3session_patchset_strm', 'int', [
+ 'sqlite3_session*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xOutput', signature: 'i(ppp)', bindScope: 'transient'
+ }),
+ 'void*'
+ ]],
+ ['sqlite3session_table_filter', undefined, [
+ 'sqlite3_session*',
+ new wasm.xWrap.FuncPtrAdapter({
+ name: 'xFilter', ...__ipsProxy,
+ contextKey: (argv,argIndex)=>argv[0/* (sqlite3_session*) */]
+ }),
+ '*'
+ ]]
+ ]);
+ }/*session/changeset APIs*/
+
/**
Functions which are intended solely for API-internal use by the
WASM components, not client code. These get installed into
@@ -406,10 +584,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if(1){// wasm.xWrap() bindings...
/**
Add some descriptive xWrap() aliases for '*' intended to (A)
- initially improve readability/correctness of capi.signatures
- and (B) provide automatic conversion from higher-level
- representations, e.g. capi.sqlite3_vfs to `sqlite3_vfs*` via
- capi.sqlite3_vfs.pointer.
+ initially improve readability/correctness of
+ wasm.bindingSignatures and (B) provide automatic conversion
+ from higher-level representations, e.g. capi.sqlite3_vfs to
+ `sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
*/
const aPtr = wasm.xWrap.argAdapter('*');
const nilType = function(){};
@@ -417,6 +595,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
('sqlite3_context*', aPtr)
('sqlite3_value*', aPtr)
('void*', aPtr)
+ ('sqlite3_changegroup*', aPtr)
+ ('sqlite3_changeset_iter*', aPtr)
+ //('sqlite3_rebaser*', aPtr)
+ ('sqlite3_session*', aPtr)
('sqlite3_stmt*', (v)=>
aPtr((v instanceof (sqlite3?.oo1?.Stmt || nilType))
? v.pointer : v))
@@ -1001,7 +1183,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
wasm.ctype = JSON.parse(wasm.cstrToJs(cJson));
// Groups of SQLITE_xyz macros...
const defineGroups = ['access', 'authorizer',
- 'blobFinalizers', 'config', 'dataTypes',
+ 'blobFinalizers', 'changeset',
+ 'config', 'dataTypes',
'dbConfig', 'dbStatus',
'encodings', 'fcntl', 'flock', 'ioCap',
'limits', 'openFlags',
@@ -1011,7 +1194,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
'trace', 'txnState', 'udfFlags',
'version' ];
if(wasm.bigIntEnabled){
- defineGroups.push('serialize', 'vtab');
+ defineGroups.push('serialize', 'session', 'vtab');
}
for(const t of defineGroups){
for(const e of Object.entries(wasm.ctype[t])){
diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.js
index 16f5f00b1..1823773de 100644
--- a/ext/wasm/api/sqlite3-api-oo1.js
+++ b/ext/wasm/api/sqlite3-api-oo1.js
@@ -72,7 +72,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
wasm.installFunction('i(ippp)', function(t,c,p,x){
if(capi.SQLITE_TRACE_STMT===t){
// x == SQL, p == sqlite3_stmt*
- console.log("SQL TRACE #"+(++this.counter),
+ console.log("SQL TRACE #"+(++this.counter)+' via sqlite3@'+c+':',
wasm.cstrToJs(x));
}
}.bind({counter: 0}));
@@ -161,7 +161,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
capi.sqlite3_extended_result_codes(pDb, 1);
if(flagsStr.indexOf('t')>=0){
capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
- __dbTraceToConsole, 0);
+ __dbTraceToConsole, pDb);
}
}catch( e ){
if( pDb ) capi.sqlite3_close_v2(pDb);
diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js
index 307ab43f5..9bac70448 100644
--- a/ext/wasm/api/sqlite3-api-prologue.js
+++ b/ext/wasm/api/sqlite3-api-prologue.js
@@ -1020,12 +1020,20 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
to the memory. On error, returns throws a WasmAllocError. The
memory must eventually be released using restore().
+ If n is a string, it must be a WASM "IR" value in the set
+ accepted by wasm.irSizeof(), which is mapped to the size of
+ that data type. If passed a string not in that set, it throws a
+ WasmAllocError.
+
This method always adjusts the given value to be a multiple
of 8 bytes because failing to do so can lead to incorrect
results when reading and writing 64-bit values from/to the WASM
heap. Similarly, the returned address is always 8-byte aligned.
*/
- alloc: (n)=>{
+ alloc: function(n){
+ if('string'===typeof n && !(n = wasm.irSizeof(n))){
+ WasmAllocError.toss("Invalid value for pstack.alloc(",arguments[0],")");
+ }
return wasm.exports.sqlite3_wasm_pstack_alloc(n)
|| WasmAllocError.toss("Could not allocate",n,
"bytes from the pstack.");
@@ -1035,6 +1043,8 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
returns the addresses as an array of n element, each holding
the address of one chunk.
+ sz may optionally be an IR string accepted by wasm.irSizeof().
+
Throws a WasmAllocError if allocation fails.
Example:
@@ -1043,7 +1053,10 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
const [p1, p2, p3] = wasm.pstack.allocChunks(3,4);
```
*/
- allocChunks: (n,sz)=>{
+ allocChunks: function(n,sz){
+ if('string'===typeof sz && !(sz = wasm.irSizeof(sz))){
+ WasmAllocError.toss("Invalid size value for allocChunks(",arguments[1],")");
+ }
const mem = wasm.pstack.alloc(n * sz);
const rc = [];
let i = 0, offset = 0;
diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c
index 5c9b53318..b39e252b1 100644
--- a/ext/wasm/api/sqlite3-wasm.c
+++ b/ext/wasm/api/sqlite3-wasm.c
@@ -99,15 +99,21 @@
#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_MATH_FUNCTIONS
-# define SQLITE_ENABLE_MATH_FUNCTIONS 1
+#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
@@ -460,6 +466,22 @@ const char * sqlite3_wasm_enum_json(void){
out("\"SQLITE_STATIC\":0, \"SQLITE_TRANSIENT\":-1");
} _DefGroup;
+ DefGroup(changeset){
+ DefInt(SQLITE_CHANGESETSTART_INVERT);
+ DefInt(SQLITE_CHANGESETAPPLY_NOSAVEPOINT);
+ DefInt(SQLITE_CHANGESETAPPLY_INVERT);
+
+ 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);
@@ -796,6 +818,11 @@ const char * sqlite3_wasm_enum_json(void){
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);