/ 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 Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

277
278
279
280
281
282
283
















284
285
286
287
288
289
290
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
** Return TRUE if zTable is the name of the system table that stores the
** list of users and their access credentials.
*/
int sqlite3UserAuthTable(const char *zTable){
  return sqlite3_stricmp(zTable, "sqlite_user")==0;
}
#endif

















/*
** Locate the in-memory structure that describes a particular database
** table given the name of that table and (optionally) the name of the
** database containing the table.  Return NULL if not found.
**
** If zDatabase is 0, all databases are searched for the table and the
................................................................................
    return 0;
  }
#endif
  while(1){
    for(i=OMIT_TEMPDB; i<db->nDb; i++){
      int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
      if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
        int bUnload = 0;
        assert( sqlite3SchemaMutexHeld(db, j, 0) );
        if( IsReuseSchema(db) 
         && DbHasProperty(db, j, DB_SchemaLoaded)==0 
         && (db->init.busy==0 || (j!=1 && db->init.iDb==1))
        ){
          struct sqlite3InitInfo sv = db->init;
          memset(&db->init, 0, sizeof(struct sqlite3InitInfo));
          sqlite3InitOne(db, j, 0, 0);
          bUnload = (j!=1);
          db->init = sv;
        }
        p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
        if( p ) return p;
        if( bUnload ){
          sqlite3SchemaRelease(db, j);
        }
      }
    }
................................................................................
    ** can be an eponymous virtual table. */
    if( pParse->disableVtab==0 ){
      Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
      if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
        pMod = sqlite3PragmaVtabRegister(db, zName);
      }
      if( pMod ){
        if( IsReuseSchema(db)
         && DbHasProperty(db, 0, DB_SchemaLoaded)==0 
         && db->init.busy==0
        ){
          sqlite3InitOne(db, 0, 0, 0);
        }
        if( sqlite3VtabEponymousTableInit(pParse, pMod) ){
          return pMod->pEpoTab;
        }
      }
    }
#endif
    if( flags & LOCATE_NOERR ) return 0;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|

<
<
<
<
<
<
<
|
<
<







 







|
<
<
<
<
<







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
...
323
324
325
326
327
328
329
330
331







332


333
334
335
336
337
338
339
...
382
383
384
385
386
387
388
389





390
391
392
393
394
395
396
** Return TRUE if zTable is the name of the system table that stores the
** list of users and their access credentials.
*/
int sqlite3UserAuthTable(const char *zTable){
  return sqlite3_stricmp(zTable, "sqlite_user")==0;
}
#endif

static int loadReusableSchema(sqlite3 *db, int iDb){
  if( IsReuseSchema(db) 
   && DbHasProperty(db, iDb, DB_SchemaLoaded)==0 
   && (db->init.busy==0 || (iDb!=1 && db->init.iDb==1))
  ){
    char *zDummy = 0;
    struct sqlite3InitInfo sv = db->init;
    memset(&db->init, 0, sizeof(struct sqlite3InitInfo));
    sqlite3InitOne(db, iDb, &zDummy, 0);
    sqlite3_free(zDummy);
    db->init = sv;
    return (iDb!=1);
  }
  return 0;
}

/*
** Locate the in-memory structure that describes a particular database
** table given the name of that table and (optionally) the name of the
** database containing the table.  Return NULL if not found.
**
** If zDatabase is 0, all databases are searched for the table and the
................................................................................
    return 0;
  }
#endif
  while(1){
    for(i=OMIT_TEMPDB; i<db->nDb; i++){
      int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
      if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
        int bUnload;
        assert( sqlite3SchemaMutexHeld(db, j, 0) );







        bUnload = loadReusableSchema(db, j);


        p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
        if( p ) return p;
        if( bUnload ){
          sqlite3SchemaRelease(db, j);
        }
      }
    }
................................................................................
    ** can be an eponymous virtual table. */
    if( pParse->disableVtab==0 ){
      Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
      if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
        pMod = sqlite3PragmaVtabRegister(db, zName);
      }
      if( pMod ){
        loadReusableSchema(db, 0);





        if( sqlite3VtabEponymousTableInit(pParse, pMod) ){
          return pMod->pEpoTab;
        }
      }
    }
#endif
    if( flags & LOCATE_NOERR ) return 0;

Changes to src/callback.c.

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

/*







|







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

/*

Changes to src/vdbeblob.c.

144
145
146
147
148
149
150

151
152
153
154
155
156
157

158
159
160
161
162
163
164
...
329
330
331
332
333
334
335

336
337
338
339
340
341
342
  if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif
  wrFlag = !!wrFlag;                /* wrFlag = (wrFlag ? 1 : 0); */

  sqlite3_mutex_enter(db->mutex);


  bUnlock = sqlite3LockReusableSchema(db);
  pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
  do {
    memset(&sParse, 0, sizeof(Parse));
    if( !pBlob ) goto blob_open_out;
    sParse.db = db;

    sqlite3DbFree(db, zErr);
    zErr = 0;

    sqlite3BtreeEnterAll(db);
    pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
    if( pTab && IsVirtual(pTab) ){
      pTab = 0;
................................................................................
    if( db->mallocFailed ){
      goto blob_open_out;
    }
    rc = blobSeekToRow(pBlob, iRow, &zErr);
  } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );

blob_open_out:

  sqlite3UnlockReusableSchema(db, bUnlock);
  if( rc==SQLITE_OK && db->mallocFailed==0 ){
    *ppBlob = (sqlite3_blob *)pBlob;
  }else{
    if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
    sqlite3DbFree(db, pBlob);
  }







>







>







 







>







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
  if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif
  wrFlag = !!wrFlag;                /* wrFlag = (wrFlag ? 1 : 0); */

  sqlite3_mutex_enter(db->mutex);
  assert( db->pParse==0 );

  bUnlock = sqlite3LockReusableSchema(db);
  pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
  do {
    memset(&sParse, 0, sizeof(Parse));
    if( !pBlob ) goto blob_open_out;
    sParse.db = db;
    db->pParse = &sParse;
    sqlite3DbFree(db, zErr);
    zErr = 0;

    sqlite3BtreeEnterAll(db);
    pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
    if( pTab && IsVirtual(pTab) ){
      pTab = 0;
................................................................................
    if( db->mallocFailed ){
      goto blob_open_out;
    }
    rc = blobSeekToRow(pBlob, iRow, &zErr);
  } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );

blob_open_out:
  db->pParse = 0;
  sqlite3UnlockReusableSchema(db, bUnlock);
  if( rc==SQLITE_OK && db->mallocFailed==0 ){
    *ppBlob = (sqlite3_blob *)pBlob;
  }else{
    if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
    sqlite3DbFree(db, pBlob);
  }

Changes to test/reuse3.test.

63
64
65
66
67
68
69
70









71

72











  SELECT * FROM t2
} {1 4}

do_execsql_test 1.9 {
  SELECT * FROM v1
} {1 2 3 4 5 6}

finish_test






























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

>
>
>
>
>
>
>
>
>
>
>
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  SELECT * FROM t2
} {1 4}

do_execsql_test 1.9 {
  SELECT * FROM v1
} {1 2 3 4 5 6}


#-------------------------------------------------------------------------
# Test error messages when parsing the schema with a REUSE_SCHEMA 
# connection.
reset_db
do_execsql_test 2.0 {
  CREATE TABLE x1(a, b, c);
  CREATE TABLE y1(d, e, f);
  PRAGMA writable_schema = 1;
  UPDATE sqlite_master SET sql = 'CREATE TBL y1(d, e, f)' WHERE name = 'y1';
}
db close

sqlite3 db test.db -reuse-schema 1
do_catchsql_test 2.1 {
  SELECT * FROM x1;
} {1 {no such table: x1}}

do_catchsql_test 2.2 {
  SELECT * FROM x1;
} {1 {no such table: x1}}

finish_test