/ Check-in [b58ca4cb]
Login

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

Overview
Comment:Handle some boundary cases in memdb associated with OOM faults.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | memdb
Files: files | file ages | folders
SHA3-256: b58ca4cb0c921e81efad527c80b220be120263cfdb04528ae26ecf8b8f66f44a
User & Date: drh 2018-03-06 20:54:27
Context
2018-03-06
21:43
Improved documentation for sqlite3_serialize() and sqlite3_deserialize(). Change the name of the compile-time option to enable these interfaces from SQLITE_ENABLE_MEMDB to SQLITE_ENABLE_DESERIALIZE. check-in: f07e97ae user: drh tags: memdb
20:54
Handle some boundary cases in memdb associated with OOM faults. check-in: b58ca4cb user: drh tags: memdb
19:14
Simplifications to the memdb VFS. check-in: 6c3f723a user: drh tags: memdb
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/attach.c.

    93     93     if( REOPEN_AS_MEMDB(db) ){
    94     94       /* This is not a real ATTACH.  Instead, this routine is being called
    95     95       ** from sqlite3_deserialize() to close database db->init.iDb and
    96     96       ** reopen it as a MemDB */
    97     97       pVfs = sqlite3_vfs_find("memdb");
    98     98       if( pVfs==0 ) return;
    99     99       pNew = &db->aDb[db->init.iDb];
   100         -    sqlite3BtreeClose(pNew->pBt);
          100  +    if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt);
   101    101       pNew->pBt = 0;
   102    102       pNew->pSchema = 0;
   103    103       rc = sqlite3BtreeOpen(pVfs, "x", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB);
   104    104     }else{
   105    105       /* This is a real ATTACH
   106    106       **
   107    107       ** Check for the following errors:
................................................................................
   228    228     ** way we found it.
   229    229     */
   230    230     if( rc==SQLITE_OK ){
   231    231       sqlite3BtreeEnterAll(db);
   232    232       db->init.iDb = 0;
   233    233       rc = sqlite3Init(db, &zErrDyn);
   234    234       sqlite3BtreeLeaveAll(db);
          235  +    assert( zErrDyn==0 || rc!=SQLITE_OK );
   235    236     }
   236    237   #ifdef SQLITE_USER_AUTHENTICATION
   237    238     if( rc==SQLITE_OK ){
   238    239       u8 newAuth = 0;
   239    240       rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
   240    241       if( newAuth<db->auth.authLevel ){
   241    242         rc = SQLITE_AUTH_USER;
   242    243       }
   243    244     }
   244    245   #endif
   245         -  if( rc && !REOPEN_AS_MEMDB(db) ){
   246         -    int iDb = db->nDb - 1;
   247         -    assert( iDb>=2 );
   248         -    if( db->aDb[iDb].pBt ){
   249         -      sqlite3BtreeClose(db->aDb[iDb].pBt);
   250         -      db->aDb[iDb].pBt = 0;
   251         -      db->aDb[iDb].pSchema = 0;
   252         -    }
   253         -    sqlite3ResetAllSchemasOfConnection(db);
   254         -    db->nDb = iDb;
   255         -    if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
   256         -      sqlite3OomFault(db);
   257         -      sqlite3DbFree(db, zErrDyn);
   258         -      zErrDyn = sqlite3MPrintf(db, "out of memory");
   259         -    }else if( zErrDyn==0 ){
   260         -      zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile);
          246  +  if( rc ){
          247  +    if( !REOPEN_AS_MEMDB(db) ){
          248  +      int iDb = db->nDb - 1;
          249  +      assert( iDb>=2 );
          250  +      if( db->aDb[iDb].pBt ){
          251  +        sqlite3BtreeClose(db->aDb[iDb].pBt);
          252  +        db->aDb[iDb].pBt = 0;
          253  +        db->aDb[iDb].pSchema = 0;
          254  +      }
          255  +      sqlite3ResetAllSchemasOfConnection(db);
          256  +      db->nDb = iDb;
          257  +      if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
          258  +        sqlite3OomFault(db);
          259  +        sqlite3DbFree(db, zErrDyn);
          260  +        zErrDyn = sqlite3MPrintf(db, "out of memory");
          261  +      }else if( zErrDyn==0 ){
          262  +        zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile);
          263  +      }
   261    264       }
   262    265       goto attach_error;
   263    266     }
   264    267     
   265    268     return;
   266    269   
   267    270   attach_error:

Changes to src/memdb.c.

   468    468     pBt = db->aDb[iDb].pBt;
   469    469     if( pBt==0 ) return 0;
   470    470     szPage = sqlite3BtreeGetPageSize(pBt);
   471    471     zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema);
   472    472     rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM;
   473    473     sqlite3_free(zSql);
   474    474     if( rc ) return 0;
   475         -  sqlite3_step(pStmt);
   476         -  sz = sqlite3_column_int64(pStmt, 0)*szPage;
   477         -  if( piSize ) *piSize = sz;
   478         -  if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
          475  +  rc = sqlite3_step(pStmt);
          476  +  if( rc!=SQLITE_ROW ){
   479    477       pOut = 0;
   480    478     }else{
   481         -    pOut = sqlite3_malloc64( sz );
   482         -    if( pOut ){
   483         -      int nPage = sqlite3_column_int(pStmt, 0);
   484         -      Pager *pPager = sqlite3BtreePager(pBt);
   485         -      int pgno;
   486         -      for(pgno=1; pgno<=nPage; pgno++){
   487         -        DbPage *pPage = 0;
   488         -        unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1);
   489         -        rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0);
   490         -        if( rc==SQLITE_OK ){
   491         -          memcpy(pTo, sqlite3PagerGetData(pPage), szPage);
   492         -        }else{
   493         -          memset(pTo, 0, szPage);
          479  +    sz = sqlite3_column_int64(pStmt, 0)*szPage;
          480  +    if( piSize ) *piSize = sz;
          481  +    if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
          482  +      pOut = 0;
          483  +    }else{
          484  +      pOut = sqlite3_malloc64( sz );
          485  +      if( pOut ){
          486  +        int nPage = sqlite3_column_int(pStmt, 0);
          487  +        Pager *pPager = sqlite3BtreePager(pBt);
          488  +        int pgno;
          489  +        for(pgno=1; pgno<=nPage; pgno++){
          490  +          DbPage *pPage = 0;
          491  +          unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1);
          492  +          rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0);
          493  +          if( rc==SQLITE_OK ){
          494  +            memcpy(pTo, sqlite3PagerGetData(pPage), szPage);
          495  +          }else{
          496  +            memset(pTo, 0, szPage);
          497  +          }
          498  +          sqlite3PagerUnref(pPage);       
   494    499           }
   495         -        sqlite3PagerUnref(pPage);       
   496    500         }
   497    501       }
   498    502     }
   499    503     sqlite3_finalize(pStmt);
   500    504     return pOut;
   501    505   }
   502    506   
................................................................................
   532    536     rc = sqlite3_step(pStmt);
   533    537     db->init.reopenMemdb = 0;
   534    538     if( rc!=SQLITE_DONE ){
   535    539       rc = SQLITE_ERROR;
   536    540       goto end_deserialize;
   537    541     }
   538    542     p = memdbFromDbSchema(db, zSchema);
   539         -  /* The memdbFromDbSchema() call can only fail if zSchema is not
   540         -  ** a valid schema name or if the schema is not a memdb schema.  But
   541         -  ** neither of those things can be true here, so failure is not possible */
   542         -  assert( p!=0 );
   543         -  p->aData = pData;
   544         -  p->sz = szDb;
   545         -  p->szMax = szBuf;
   546         -  p->mFlags = mFlags;
   547         -  rc = SQLITE_OK;
          543  +  if( p==0 ){
          544  +    rc = SQLITE_ERROR;
          545  +  }else{
          546  +    p->aData = pData;
          547  +    p->sz = szDb;
          548  +    p->szMax = szBuf;
          549  +    p->mFlags = mFlags;
          550  +    rc = SQLITE_OK;
          551  +  }
          552  +
   548    553   end_deserialize:
   549    554     sqlite3_finalize(pStmt);
   550    555     sqlite3_mutex_leave(db->mutex);
   551    556     return rc;
   552    557   }
   553    558   
   554    559   /*