mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Add delete-before-open=1 URI flag to the 'opfs' VFS to tell it to xDelete the db file before opening it, primarily to enable users to work around a corrupt db without having to reach into OPFS-specific APIs to remove the db file.
FossilOrigin-Name: e83f9788636f7f9bcca7d2a09620c13ab4eb83436d5b2946a827e48addf0267d
This commit is contained in:
@ -562,6 +562,17 @@ const installAsyncProxy = function(self){
|
||||
wTimeEnd();
|
||||
return;
|
||||
}
|
||||
if( state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN & opfsFlags ){
|
||||
//log("async proxy opfsFlags =",opfsFlags);
|
||||
try{
|
||||
await hDir.removeEntry(filenamePart);
|
||||
//log("Unlinked",filename,hDir,filenamePart);
|
||||
}
|
||||
catch(e){
|
||||
/* ignoring */
|
||||
//warn("Ignoring failed Unlink of",filename,":",e);
|
||||
}
|
||||
}
|
||||
const hFile = await hDir.getFileHandle(filenamePart, {create});
|
||||
wTimeEnd();
|
||||
const fh = Object.assign(Object.create(null),{
|
||||
|
@ -423,10 +423,18 @@ const installOpfsVfs = function callee(options){
|
||||
});
|
||||
state.opfsFlags = Object.assign(Object.create(null),{
|
||||
/**
|
||||
Flag for use with xOpen(). "opfs-unlock-asap=1" enables
|
||||
this. See defaultUnlockAsap, below.
|
||||
Flag for use with xOpen(). URI flag "opfs-unlock-asap=1"
|
||||
enables this. See defaultUnlockAsap, below.
|
||||
*/
|
||||
OPFS_UNLOCK_ASAP: 0x01,
|
||||
/**
|
||||
Flag for use with xOpen(). URI flag "delete-before-open=1"
|
||||
tells the VFS to delete the db file before attempting to open
|
||||
it. This can be used, e.g., to replace a db which has been
|
||||
corrupted (without forcing us to expose a delete/unlink()
|
||||
function in the public API).
|
||||
*/
|
||||
OPFS_UNLINK_BEFORE_OPEN: 0x02,
|
||||
/**
|
||||
If true, any async routine which implicitly acquires a sync
|
||||
access handle (i.e. an OPFS lock) will release that locks at
|
||||
@ -875,13 +883,17 @@ const installOpfsVfs = function callee(options){
|
||||
let opfsFlags = 0;
|
||||
if(0===zName){
|
||||
zName = randomFilename();
|
||||
}else if('number'===typeof zName){
|
||||
}else if(wasm.isPtr(zName)){
|
||||
if(capi.sqlite3_uri_boolean(zName, "opfs-unlock-asap", 0)){
|
||||
/* -----------------------^^^^^ MUST pass the untranslated
|
||||
C-string here. */
|
||||
opfsFlags |= state.opfsFlags.OPFS_UNLOCK_ASAP;
|
||||
}
|
||||
if(capi.sqlite3_uri_boolean(zName, "delete-before-open", 0)){
|
||||
opfsFlags |= state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN;
|
||||
}
|
||||
zName = wasm.cstrToJs(zName);
|
||||
//warn("xOpen zName =",zName, "opfsFlags =",opfsFlags);
|
||||
}
|
||||
const fh = Object.create(null);
|
||||
fh.fid = pFile;
|
||||
|
@ -2888,18 +2888,17 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
.t({
|
||||
name: 'OPFS db sanity checks',
|
||||
test: async function(sqlite3){
|
||||
T.assert(capi.sqlite3_vfs_find('opfs'));
|
||||
const opfs = sqlite3.opfs;
|
||||
const filename = this.opfsDbFile = '/dir/sqlite3-tester1.db';
|
||||
const pVfs = this.opfsVfs = capi.sqlite3_vfs_find('opfs');
|
||||
T.assert(pVfs);
|
||||
const unlink = this.opfsUnlink =
|
||||
(fn=filename)=>{sqlite3.util.sqlite3__wasm_vfs_unlink(pVfs,fn)};
|
||||
unlink();
|
||||
let db = new sqlite3.oo1.OpfsDb(filename);
|
||||
const fileUri = 'file://'+filename+'?delete-before-open=1';
|
||||
const initSql = [
|
||||
'create table p(a);',
|
||||
'insert into p(a) values(1),(2),(3)'
|
||||
];
|
||||
let db = new sqlite3.oo1.OpfsDb(fileUri);
|
||||
try {
|
||||
db.exec([
|
||||
'create table p(a);',
|
||||
'insert into p(a) values(1),(2),(3)'
|
||||
]);
|
||||
db.exec(initSql);
|
||||
T.assert(3 === db.selectValue('select count(*) from p'));
|
||||
db.close();
|
||||
db = new sqlite3.oo1.OpfsDb(filename);
|
||||
@ -2911,7 +2910,14 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
&& 0===this.opfsDbExport.byteLength % 512);
|
||||
}finally{
|
||||
db.close();
|
||||
unlink();
|
||||
}
|
||||
T.assert(await opfs.entryExists(filename));
|
||||
try {
|
||||
db = new sqlite3.oo1.OpfsDb(fileUri);
|
||||
db.exec(initSql) /* will throw if delete-before-open did not work */;
|
||||
T.assert(3 === db.selectValue('select count(*) from p'));
|
||||
}finally{
|
||||
if(db) db.close();
|
||||
}
|
||||
}
|
||||
}/*OPFS db sanity checks*/)
|
||||
@ -2919,15 +2925,17 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
name: 'OPFS import',
|
||||
test: async function(sqlite3){
|
||||
let db;
|
||||
const filename = this.opfsDbFile;
|
||||
try {
|
||||
const exp = this.opfsDbExport;
|
||||
const filename = this.opfsDbFile;
|
||||
delete this.opfsDbExport;
|
||||
this.opfsImportSize = await sqlite3.oo1.OpfsDb.importDb(filename, exp);
|
||||
db = new sqlite3.oo1.OpfsDb(this.opfsDbFile);
|
||||
T.assert(6 === db.selectValue('select count(*) from p')).
|
||||
assert( this.opfsImportSize == exp.byteLength );
|
||||
db.close();
|
||||
const unlink = this.opfsUnlink =
|
||||
(fn=filename)=>sqlite3.util.sqlite3__wasm_vfs_unlink("opfs",fn);
|
||||
this.opfsUnlink(filename);
|
||||
T.assert(!(await sqlite3.opfs.entryExists(filename)));
|
||||
// Try again with a function as an input source:
|
||||
@ -2954,11 +2962,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
name: '(Internal-use) OPFS utility APIs',
|
||||
test: async function(sqlite3){
|
||||
const filename = this.opfsDbFile;
|
||||
const pVfs = this.opfsVfs;
|
||||
const unlink = this.opfsUnlink;
|
||||
T.assert(filename && pVfs && !!unlink);
|
||||
T.assert(filename && !!unlink);
|
||||
delete this.opfsDbFile;
|
||||
delete this.opfsVfs;
|
||||
delete this.opfsUnlink;
|
||||
/**************************************************************
|
||||
ATTENTION CLIENT-SIDE USERS: sqlite3.opfs is NOT intended
|
||||
|
Reference in New Issue
Block a user