aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/fiddle/fiddle-worker.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/wasm/fiddle/fiddle-worker.js')
-rw-r--r--ext/wasm/fiddle/fiddle-worker.js89
1 files changed, 81 insertions, 8 deletions
diff --git a/ext/wasm/fiddle/fiddle-worker.js b/ext/wasm/fiddle/fiddle-worker.js
index 827d2cfa9..5da09257d 100644
--- a/ext/wasm/fiddle/fiddle-worker.js
+++ b/ext/wasm/fiddle/fiddle-worker.js
@@ -99,7 +99,9 @@
};
const stdout = (...args)=>wMsg('stdout', args);
const stderr = (...args)=>wMsg('stderr', args);
-
+ const toss = (...args)=>{
+ throw new Error(args.join(' '));
+ };
const fixmeOPFS = "(FIXME: won't work with vanilla OPFS.)";
self.onerror = function(/*message, source, lineno, colno, error*/) {
@@ -136,7 +138,7 @@
const S = fiddleModule.sqlite3;
/* We need to call sqlite3_shutdown() in order to avoid numerous
legitimate warnings from the shell about it being initialized
- after sqlite3_initialize() has been called. This mean ,
+ after sqlite3_initialize() has been called. This means,
however, that any initialization done by the JS code may need
to be re-done (e.g. re-registration of dynamically-loaded
VFSes). */
@@ -156,7 +158,7 @@
if(S.opfs){
stdout("\nOPFS is available. To open a persistent db, use:\n\n",
" .open file:name?vfs=opfs\n\nbut note that some",
- "features (e.g. export) do not yet work with OPFS.");
+ "features (e.g. upload) do not yet work with OPFS.");
S.opfs.reregisterVfs();
}
stdout('\nEnter ".help" for usage hints.');
@@ -207,6 +209,69 @@
f._();
}
};
+
+ /**
+ Exports the shell's current db file in such a way that it can
+ export DBs hosted in the Emscripten-supplied FS or in native OPFS
+ (and, hypothetically, kvvfs). Throws on error. On success returns
+ a Blob containing the whole db contents.
+
+ Bug: xFileSize() is returning garbage for the default VFS but
+ works in OPFS. Thus for exporting that impl we'll use the
+ fiddleModule.FS API for the time being.
+ */
+ const exportDbFileToBlob = function(){
+ const S = fiddleModule.sqlite3, capi = S.capi, wasm = capi.wasm;
+ const pDb = wasm.xCall("fiddle_db_handle");
+ if(!pDb) toss("No db is opened.");
+ const scope = wasm.scopedAllocPush();
+ try{
+ const ppFile = wasm.scopedAlloc(12/*sizeof(i32 + i64)*/);
+ const pFileSize = ppFile + 4;
+ wasm.setMemValue(ppFile, 0, 'i32');
+ let rc = capi.sqlite3_file_control(
+ pDb, "main", capi.SQLITE_FCNTL_FILE_POINTER, ppFile
+ );
+ if(rc) toss("Cannot get sqlite3_file handle.");
+ const jFile = new capi.sqlite3_file(wasm.getPtrValue(ppFile));
+ const jIom = new capi.sqlite3_io_methods(jFile.$pMethods);
+ console.warn("jIom =",jIom);
+ const xFileSize = wasm.functionEntry(jIom.$xFileSize);
+ const xRead = wasm.functionEntry(jIom.$xRead);
+ wasm.setMemValue(pFileSize, 0n, 'i64');
+ //stderr("nFileSize =",wasm.getMemValue(pFileSize,'i64'),"pFileSize =",pFileSize);
+ rc = xFileSize( jFile.pointer, pFileSize );
+ if(rc) toss("Cannot get db file size.");
+ //stderr("nFileSize =",wasm.getMemValue(pFileSize,'i64'),"pFileSize =",pFileSize);
+ const nFileSize = Number( wasm.getMemValue(pFileSize,'i64') );
+ if(nFileSize <= 0n || nFileSize>=Number.MAX_SAFE_INTEGER){
+ toss("Unexpected DB size:",nFileSize);
+ }
+ //stderr("nFileSize =",nFileSize,"pFileSize =",pFileSize);
+ const nIobuf = 1024 * 4;
+ const iobuf = wasm.scopedAlloc(nIobuf);
+ let nPos = 0;
+ const blobList = [];
+ const heap = wasm.heap8u();
+ for( ; nPos < nFileSize; nPos += nIobuf ){
+ rc = xRead(jFile.pointer, iobuf, nIobuf, BigInt(nPos));
+ if(rc){
+ if(capi.SQLITE_IOERR_SHORT_READ === rc){
+ //stderr('rc =',rc,'nPos =',nPos,'nIobuf =',nIobuf,'nFileSize =',nFileSize);
+ rc = ((nPos + nIobuf) < nFileSize) ? rc : 0/*assume EOF*/;
+ }
+ if(rc) toss("xRead() SQLITE_xxx error #"+rc,capi.sqlite3_wasm_rc_str(rc));
+ }
+ blobList.push(heap.slice(iobuf, iobuf+nIobuf));
+ }
+ return new Blob(blobList);
+ }catch(e){
+ console.error('exportDbFileToBlob()',e);
+ stderr("exportDbFileToBlob():",e.message);
+ }finally{
+ wasm.scopedAllocPop(scope);
+ }
+ }/*exportDbFileToBlob()*/;
self.onmessage = function f(ev){
ev = ev.data;
@@ -233,14 +298,22 @@
*/
case 'db-export': {
const fn = Sqlite3Shell.dbFilename();
- stdout("Exporting",fn+".",fixmeOPFS);
+ stdout("Exporting",fn+".");
const fn2 = fn ? fn.split(/[/\\]/).pop() : null;
try{
if(!fn2) throw new Error("DB appears to be closed.");
- const buffer = fiddleModule.FS.readFile(
- fn, {encoding:"binary"}
- ).buffer;
- wMsg('db-export',{filename: fn2, buffer}, [buffer]);
+ if(fiddleModule.sqlite3.capi.wasm.xCall(
+ 'fiddle_db_is_opfs'
+ )){
+ exportDbFileToBlob().arrayBuffer().then((buffer)=>{
+ wMsg('db-export',{filename: fn2, buffer}, [buffer]);
+ });
+ }else{
+ const buffer = fiddleModule.FS.readFile(
+ fn, {encoding:"binary"}
+ ).buffer;
+ wMsg('db-export',{filename: fn2, buffer}, [buffer]);
+ }
}catch(e){
/* Post a failure message so that UI elements disabled
during the export can be re-enabled. */