SQLite

Check-in [0a326240]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Ensure that the OPFS VFS's xOpen() writes back the read-only flag to the output flags. Resolves the problem reported in forum post cf37d5ff1182c31081.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 0a32624015f16fd881a4ecbb56b7833391028d327a95f4c899eee864ed7fe00d
User & Date: stephan 2024-10-17 12:14:34
Context
2024-10-17
22:20
Merge current trunk into the autosetup branch. (check-in: 352da23b user: stephan tags: autosetup)
13:00
Attempt to get the TEA builder in the amalgamation-autoconf tarball working using hints from Jan Nijtmans. (check-in: ad9d7bde user: drh tags: trunk)
12:17
Fix the OPFS VFS's xOpen() to honor the read-only flag. Fix the OPFS SAHPool VFS to enable re-installation of the VFS after calling OpfsSAHPoolUtil.removeVfs(). (check-in: 63ee3584 user: stephan tags: branch-3.46)
12:14
Ensure that the OPFS VFS's xOpen() writes back the read-only flag to the output flags. Resolves the problem reported in forum post cf37d5ff1182c31081. (check-in: 0a326240 user: stephan tags: trunk)
11:12
When calling OpfsSAHPoolUtil.removeVfs(), ensure that the cached result the VFS init is also removed so that the VFS may later be registered again with the same name. Set up test code for the regression reported in forum post cf37d5ff11 (which uncovered the removeVfs() shortcoming) but that test is currently only known to fail with the "opfs" VFS and is not currently set up to fail. (check-in: b7f7a5de user: stephan tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/wasm/api/sqlite3-opfs-async-proxy.js.

502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
        const fh = Object.assign(Object.create(null),{
          fid: fid,
          filenameAbs: filename,
          filenamePart: filenamePart,
          dirHandle: hDir,
          fileHandle: hFile,
          sabView: state.sabFileBufView,
          readOnly: create
            ? false : (state.sq3Codes.SQLITE_OPEN_READONLY & flags),
          deleteOnClose: !!(state.sq3Codes.SQLITE_OPEN_DELETEONCLOSE & flags)
        });
        fh.releaseImplicitLocks =
          (opfsFlags & state.opfsFlags.OPFS_UNLOCK_ASAP)
          || state.opfsFlags.defaultUnlockAsap;
        __openFiles[fid] = fh;
        storeAndNotify(opName, 0);







<
|







502
503
504
505
506
507
508

509
510
511
512
513
514
515
516
        const fh = Object.assign(Object.create(null),{
          fid: fid,
          filenameAbs: filename,
          filenamePart: filenamePart,
          dirHandle: hDir,
          fileHandle: hFile,
          sabView: state.sabFileBufView,

          readOnly: !create && !!(state.sq3Codes.SQLITE_OPEN_READONLY & flags),
          deleteOnClose: !!(state.sq3Codes.SQLITE_OPEN_DELETEONCLOSE & flags)
        });
        fh.releaseImplicitLocks =
          (opfsFlags & state.opfsFlags.OPFS_UNLOCK_ASAP)
          || state.opfsFlags.defaultUnlockAsap;
        __openFiles[fid] = fh;
        storeAndNotify(opName, 0);

Changes to ext/wasm/api/sqlite3-vfs-opfs.c-pp.js.

918
919
920
921
922
923
924


925
926
927
928
929
930
931
          //warn("xOpen zName =",zName, "opfsFlags =",opfsFlags);
        }
        const fh = Object.create(null);
        fh.fid = pFile;
        fh.filename = zName;
        fh.sab = new SharedArrayBuffer(state.fileBufferSize);
        fh.flags = flags;


        const rc = opRun('xOpen', pFile, zName, flags, opfsFlags);
        if(!rc){
          /* Recall that sqlite3_vfs::xClose() will be called, even on
             error, unless pFile->pMethods is NULL. */
          if(fh.readOnly){
            wasm.poke(pOutFlags, capi.SQLITE_OPEN_READONLY, 'i32');
          }







>
>







918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
          //warn("xOpen zName =",zName, "opfsFlags =",opfsFlags);
        }
        const fh = Object.create(null);
        fh.fid = pFile;
        fh.filename = zName;
        fh.sab = new SharedArrayBuffer(state.fileBufferSize);
        fh.flags = flags;
        fh.readOnly = !(sqlite3.SQLITE_OPEN_CREATE & flags)
          && !!(flags & capi.SQLITE_OPEN_READONLY);
        const rc = opRun('xOpen', pFile, zName, flags, opfsFlags);
        if(!rc){
          /* Recall that sqlite3_vfs::xClose() will be called, even on
             error, unless pFile->pMethods is NULL. */
          if(fh.readOnly){
            wasm.poke(pOutFlags, capi.SQLITE_OPEN_READONLY, 'i32');
          }

Changes to ext/wasm/tester1.c-pp.js.

3356
3357
3358
3359
3360
3361
3362
3363
3364
3365



3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381

3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392













3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
      }
    })
    .t({
      name: 'r/o connection recovery from write op error',
      predicate: ()=>hasOpfs() || "Requires OPFS to reproduce",
      //predicate: ()=>false,
      test: async function(sqlite3){
        /* https://sqlite.org/forum/forumpost/cf37d5ff11 */
        const poolConfig = JSON.parse(JSON.stringify(sahPoolConfig));
        poolConfig.name = 'opfs-sahpool-cf37d5ff11';



        const vfsName = 0 ? poolConfig.name : (1 ? undefined : 'opfs');
        let poolUtil;
        const uri = 'file:///foo.db';
        //log('poolConfig =',poolConfig);
        if( poolConfig.name === vfsName ){
          await sqlite3.installOpfsSAHPoolVfs(poolConfig).then(p=>poolUtil=p);
          T.assert(!!sqlite3.capi.sqlite3_vfs_find(poolConfig.name), "Expecting to find just-registered VFS");
        }
        let db = new sqlite3.oo1.DB(uri + (vfsName ? '?vfs='+vfsName : ''));
        db.exec([
          "drop table if exists t;",
          "create table t(a);",
          "insert into t(a) values('abc'),('def'),('ghi');"
        ]);
        db.close();
        db = new sqlite3.oo1.DB(uri+'?mode=ro'+(vfsName ? '&vfs='+vfsName : ''));

        let err;
        try {
          db.exec('insert into t(a) values(1)');
        }catch(e){
          err = e;
        }
        //log("err =",err);
        T.assert(err && (err.message.indexOf('SQLITE_IOERR_WRITE')===0/*opfs*/
                         || err.message.indexOf('readonly')>0)/*Emscripten FS*/);
        try{
          db.exec('select a from t');













        }finally{
          db.close();
        }
        if( poolUtil ) await poolUtil.removeVfs();
      }
    })
  ;/*end of Bug Reports group*/;

  ////////////////////////////////////////////////////////////////////////
  log("Loading and initializing sqlite3 WASM module...");
  if(0){







|
|
|
>
>
>
|
<
|
<
<
<
<
<
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
<
|
<
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>

|

<







3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369

3370





3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385

3386

3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404

3405
3406
3407
3408
3409
3410
3411
      }
    })
    .t({
      name: 'r/o connection recovery from write op error',
      predicate: ()=>hasOpfs() || "Requires OPFS to reproduce",
      //predicate: ()=>false,
      test: async function(sqlite3){
        /* https://sqlite.org/forum/forumpost/cf37d5ff1182c31081

           The "opfs" VFS (but not SAHPool) was formerly misbehaving
           after a write attempt was made on a db opened with
           mode=ro. This test ensures that that behavior is fixed and
           compares that behavior with other VFSes. */
        const tryOne = function(vfsName,descr){

          const uri = 'file:///foo.db';





          let db = new sqlite3.oo1.DB(uri + (vfsName ? '?vfs='+vfsName : ''));
          db.exec([
            "drop table if exists t;",
            "create table t(a);",
            "insert into t(a) values('abc'),('def'),('ghi');"
          ]);
          db.close();
          db = new sqlite3.oo1.DB(uri+'?mode=ro'+
                                  (vfsName ? '&vfs='+vfsName : ''));
          let err;
          try {
            db.exec('insert into t(a) values(1)');
          }catch(e){
            err = e;
          }

          T.assert(err && (err.message.indexOf('SQLITE_READONLY')===0));

          try{
            db.exec('select a from t');
          }finally{
            db.close();
          }
        };
        const poolConfig = JSON.parse(JSON.stringify(sahPoolConfig));
        poolConfig.name = 'opfs-sahpool-cf37d5ff11';
        let poolUtil;
        await sqlite3.installOpfsSAHPoolVfs(poolConfig).then(p=>poolUtil=p);
        T.assert(!!sqlite3.capi.sqlite3_vfs_find(poolConfig.name), "Expecting to find just-registered VFS");
        try{
          tryOne(false, "Emscripten filesystem");
          tryOne(poolConfig.name);
          tryOne('opfs');
        }finally{
          await poolUtil.removeVfs();
        }

      }
    })
  ;/*end of Bug Reports group*/;

  ////////////////////////////////////////////////////////////////////////
  log("Loading and initializing sqlite3 WASM module...");
  if(0){