/ Check-in [b102148e]
Login

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

Overview
Comment:Avoid crashing after parsing a corrupt schema with a REUSE_SCHEMA connection.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | reuse-schema
Files: files | file ages | folders
SHA3-256:b102148e71c0102eedbf28d9bc8ea8d9bd742eac45ee7f1b08ece60bcdab5036
User & Date: dan 2019-02-13 18:29:49
Wiki:reuse-schema
Context
2019-02-13
19:17
Fix for sqlite3_table_column_metadata() on REUSE_SCHEMA databases. check-in: 53220ad7 user: dan tags: reuse-schema
18:29
Avoid crashing after parsing a corrupt schema with a REUSE_SCHEMA connection. check-in: b102148e user: dan tags: reuse-schema
15:51
Fix a problem with the incrblob API and reusable schemas. check-in: 34f0f96f user: dan tags: reuse-schema
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/build.c.

   277    277   ** Return TRUE if zTable is the name of the system table that stores the
   278    278   ** list of users and their access credentials.
   279    279   */
   280    280   int sqlite3UserAuthTable(const char *zTable){
   281    281     return sqlite3_stricmp(zTable, "sqlite_user")==0;
   282    282   }
   283    283   #endif
          284  +
          285  +static int loadReusableSchema(sqlite3 *db, int iDb){
          286  +  if( IsReuseSchema(db) 
          287  +   && DbHasProperty(db, iDb, DB_SchemaLoaded)==0 
          288  +   && (db->init.busy==0 || (iDb!=1 && db->init.iDb==1))
          289  +  ){
          290  +    char *zDummy = 0;
          291  +    struct sqlite3InitInfo sv = db->init;
          292  +    memset(&db->init, 0, sizeof(struct sqlite3InitInfo));
          293  +    sqlite3InitOne(db, iDb, &zDummy, 0);
          294  +    sqlite3_free(zDummy);
          295  +    db->init = sv;
          296  +    return (iDb!=1);
          297  +  }
          298  +  return 0;
          299  +}
   284    300   
   285    301   /*
   286    302   ** Locate the in-memory structure that describes a particular database
   287    303   ** table given the name of that table and (optionally) the name of the
   288    304   ** database containing the table.  Return NULL if not found.
   289    305   **
   290    306   ** If zDatabase is 0, all databases are searched for the table and the
................................................................................
   307    323       return 0;
   308    324     }
   309    325   #endif
   310    326     while(1){
   311    327       for(i=OMIT_TEMPDB; i<db->nDb; i++){
   312    328         int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
   313    329         if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
   314         -        int bUnload = 0;
          330  +        int bUnload;
   315    331           assert( sqlite3SchemaMutexHeld(db, j, 0) );
   316         -        if( IsReuseSchema(db) 
   317         -         && DbHasProperty(db, j, DB_SchemaLoaded)==0 
   318         -         && (db->init.busy==0 || (j!=1 && db->init.iDb==1))
   319         -        ){
   320         -          struct sqlite3InitInfo sv = db->init;
   321         -          memset(&db->init, 0, sizeof(struct sqlite3InitInfo));
   322         -          sqlite3InitOne(db, j, 0, 0);
   323         -          bUnload = (j!=1);
   324         -          db->init = sv;
   325         -        }
          332  +        bUnload = loadReusableSchema(db, j);
   326    333           p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
   327    334           if( p ) return p;
   328    335           if( bUnload ){
   329    336             sqlite3SchemaRelease(db, j);
   330    337           }
   331    338         }
   332    339       }
................................................................................
   375    382       ** can be an eponymous virtual table. */
   376    383       if( pParse->disableVtab==0 ){
   377    384         Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
   378    385         if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
   379    386           pMod = sqlite3PragmaVtabRegister(db, zName);
   380    387         }
   381    388         if( pMod ){
   382         -        if( IsReuseSchema(db)
   383         -         && DbHasProperty(db, 0, DB_SchemaLoaded)==0 
   384         -         && db->init.busy==0
   385         -        ){
   386         -          sqlite3InitOne(db, 0, 0, 0);
   387         -        }
          389  +        loadReusableSchema(db, 0);
   388    390           if( sqlite3VtabEponymousTableInit(pParse, pMod) ){
   389    391             return pMod->pEpoTab;
   390    392           }
   391    393         }
   392    394       }
   393    395   #endif
   394    396       if( flags & LOCATE_NOERR ) return 0;

Changes to src/callback.c.

   524    524   ** database iDb. 
   525    525   **
   526    526   ** If an OOM error occurs while disconnecting from a schema-pool, 
   527    527   ** the db->mallocFailed flag is set.
   528    528   */
   529    529   void sqlite3SchemaClearOrDisconnect(sqlite3 *db, int iDb){
   530    530     Db *pDb = &db->aDb[iDb];
   531         -  if( IsReuseSchema(db) && iDb!=1 ){
          531  +  if( IsReuseSchema(db) && iDb!=1 && pDb->pSPool ){
   532    532       sqlite3SchemaDisconnect(db, iDb, 1);
   533    533     }else{
   534    534       sqlite3SchemaClear(pDb->pSchema);
   535    535     }
   536    536   }
   537    537   
   538    538   /*

Changes to src/vdbeblob.c.

   144    144     if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
   145    145       return SQLITE_MISUSE_BKPT;
   146    146     }
   147    147   #endif
   148    148     wrFlag = !!wrFlag;                /* wrFlag = (wrFlag ? 1 : 0); */
   149    149   
   150    150     sqlite3_mutex_enter(db->mutex);
          151  +  assert( db->pParse==0 );
   151    152   
   152    153     bUnlock = sqlite3LockReusableSchema(db);
   153    154     pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
   154    155     do {
   155    156       memset(&sParse, 0, sizeof(Parse));
   156    157       if( !pBlob ) goto blob_open_out;
   157    158       sParse.db = db;
          159  +    db->pParse = &sParse;
   158    160       sqlite3DbFree(db, zErr);
   159    161       zErr = 0;
   160    162   
   161    163       sqlite3BtreeEnterAll(db);
   162    164       pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
   163    165       if( pTab && IsVirtual(pTab) ){
   164    166         pTab = 0;
................................................................................
   329    331       if( db->mallocFailed ){
   330    332         goto blob_open_out;
   331    333       }
   332    334       rc = blobSeekToRow(pBlob, iRow, &zErr);
   333    335     } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );
   334    336   
   335    337   blob_open_out:
          338  +  db->pParse = 0;
   336    339     sqlite3UnlockReusableSchema(db, bUnlock);
   337    340     if( rc==SQLITE_OK && db->mallocFailed==0 ){
   338    341       *ppBlob = (sqlite3_blob *)pBlob;
   339    342     }else{
   340    343       if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
   341    344       sqlite3DbFree(db, pBlob);
   342    345     }

Changes to test/reuse3.test.

    63     63     SELECT * FROM t2
    64     64   } {1 4}
    65     65   
    66     66   do_execsql_test 1.9 {
    67     67     SELECT * FROM v1
    68     68   } {1 2 3 4 5 6}
    69     69   
    70         -finish_test
           70  +#-------------------------------------------------------------------------
           71  +# Test error messages when parsing the schema with a REUSE_SCHEMA 
           72  +# connection.
           73  +reset_db
           74  +do_execsql_test 2.0 {
           75  +  CREATE TABLE x1(a, b, c);
           76  +  CREATE TABLE y1(d, e, f);
           77  +  PRAGMA writable_schema = 1;
           78  +  UPDATE sqlite_master SET sql = 'CREATE TBL y1(d, e, f)' WHERE name = 'y1';
           79  +}
           80  +db close
           81  +
           82  +sqlite3 db test.db -reuse-schema 1
           83  +do_catchsql_test 2.1 {
           84  +  SELECT * FROM x1;
           85  +} {1 {no such table: x1}}
           86  +
           87  +do_catchsql_test 2.2 {
           88  +  SELECT * FROM x1;
           89  +} {1 {no such table: x1}}
    71     90   
           91  +finish_test
    72     92