/ Check-in [53220ad7]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Fix for sqlite3_table_column_metadata() on REUSE_SCHEMA databases.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | reuse-schema
Files: files | file ages | folders
SHA3-256: 53220ad7809954eb4118d9127849efa82787f43898af00c9127cd4998a12c619
User & Date: dan 2019-02-13 19:17:30
Wiki:reuse-schema
Context
2019-02-14
15:47
Add missing comments and fix other code issues in the new functions in callback.c. check-in: 441cabb6 user: dan tags: reuse-schema
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
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/main.c.

3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616

3617
3618
3619
3620
3621
3622
3623
3624
3625
3626

3627

3628

3629
3630
3631

3632
3633
3634
3635
3636
3637
3638
....
3700
3701
3702
3703
3704
3705
3706

3707
3708
3709
3710
3711
3712
3713
  const char *zColumnName,    /* Column name */
  char const **pzDataType,    /* OUTPUT: Declared data type */
  char const **pzCollSeq,     /* OUTPUT: Collation sequence name */
  int *pNotNull,              /* OUTPUT: True if NOT NULL constraint exists */
  int *pPrimaryKey,           /* OUTPUT: True if column part of PK */
  int *pAutoinc               /* OUTPUT: True if column is auto-increment */
){
  int rc;
  char *zErrMsg = 0;
  Table *pTab = 0;
  Column *pCol = 0;
  int iCol = 0;
  char const *zDataType = 0;
  char const *zCollSeq = 0;
  int notnull = 0;
  int primarykey = 0;
  int autoinc = 0;



#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif

  /* Ensure the database schema has been loaded */
  sqlite3_mutex_enter(db->mutex);

  sqlite3BtreeEnterAll(db);

  rc = sqlite3Init(db, &zErrMsg);

  if( SQLITE_OK!=rc ){
    goto error_out;
  }


  /* Locate the table in question */
  pTab = sqlite3FindTable(db, zTableName, zDbName);
  if( !pTab || pTab->pSelect ){
    pTab = 0;
    goto error_out;
  }
................................................................................
    zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName,
        zColumnName);
    rc = SQLITE_ERROR;
  }
  sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg);
  sqlite3DbFree(db, zErrMsg);
  rc = sqlite3ApiExit(db, rc);

  sqlite3_mutex_leave(db->mutex);
  return rc;
}

/*
** Sleep for a little while.  Return the amount of time slept.
*/







|









>










>

>
|
>



>







 







>







3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
....
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
  const char *zColumnName,    /* Column name */
  char const **pzDataType,    /* OUTPUT: Declared data type */
  char const **pzCollSeq,     /* OUTPUT: Collation sequence name */
  int *pNotNull,              /* OUTPUT: True if NOT NULL constraint exists */
  int *pPrimaryKey,           /* OUTPUT: True if column part of PK */
  int *pAutoinc               /* OUTPUT: True if column is auto-increment */
){
  int rc = SQLITE_OK;
  char *zErrMsg = 0;
  Table *pTab = 0;
  Column *pCol = 0;
  int iCol = 0;
  char const *zDataType = 0;
  char const *zCollSeq = 0;
  int notnull = 0;
  int primarykey = 0;
  int autoinc = 0;
  int bUnlock;


#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif

  /* Ensure the database schema has been loaded */
  sqlite3_mutex_enter(db->mutex);
  bUnlock = sqlite3LockReusableSchema(db);
  sqlite3BtreeEnterAll(db);
  if( IsReuseSchema(db)==0 ){
    rc = sqlite3Init(db, &zErrMsg);
  }
  if( SQLITE_OK!=rc ){
    goto error_out;
  }


  /* Locate the table in question */
  pTab = sqlite3FindTable(db, zTableName, zDbName);
  if( !pTab || pTab->pSelect ){
    pTab = 0;
    goto error_out;
  }
................................................................................
    zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName,
        zColumnName);
    rc = SQLITE_ERROR;
  }
  sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg);
  sqlite3DbFree(db, zErrMsg);
  rc = sqlite3ApiExit(db, rc);
  sqlite3UnlockReusableSchema(db, bUnlock);
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

/*
** Sleep for a little while.  Return the amount of time slept.
*/

Changes to src/vdbe.c.

459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
    initData.mInitFlags = 0;
    zSql = sqlite3MPrintf(db,
       "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
       db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
    if( zSql==0 ){
      rc = SQLITE_NOMEM_BKPT;
    }else{
      bRelease = sqlite3LockReusableSchema(db);
      if( IsReuseSchema(db) ){
        rc = sqlite3Init(db, &p->zErrMsg);
        if( rc ){
          sqlite3UnlockReusableSchema(db, bRelease);
          return rc;
        }
      }
      assert( db->init.busy==0 );
      db->init.busy = 1;
      initData.rc = SQLITE_OK;
      initData.nInitRow = 0;
      assert( !db->mallocFailed );
      rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
      sqlite3UnlockReusableSchema(db, bRelease);
      if( rc==SQLITE_OK ) rc = initData.rc;
      if( rc==SQLITE_OK && initData.nInitRow==0 ){
        /* The OP_ParseSchema opcode with a non-NULL P4 argument should parse
        ** at least one SQL statement. Any less than that indicates that
        ** the sqlite_master table is corrupt. */
        rc = SQLITE_CORRUPT_BKPT;
      }







<
<
<
<
<
<
<
<






<







459
460
461
462
463
464
465








466
467
468
469
470
471

472
473
474
475
476
477
478
    initData.mInitFlags = 0;
    zSql = sqlite3MPrintf(db,
       "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
       db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
    if( zSql==0 ){
      rc = SQLITE_NOMEM_BKPT;
    }else{








      assert( db->init.busy==0 );
      db->init.busy = 1;
      initData.rc = SQLITE_OK;
      initData.nInitRow = 0;
      assert( !db->mallocFailed );
      rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);

      if( rc==SQLITE_OK ) rc = initData.rc;
      if( rc==SQLITE_OK && initData.nInitRow==0 ){
        /* The OP_ParseSchema opcode with a non-NULL P4 argument should parse
        ** at least one SQL statement. Any less than that indicates that
        ** the sqlite_master table is corrupt. */
        rc = SQLITE_CORRUPT_BKPT;
      }

Changes to test/reuse2.test.

283
284
285
286
287
288
289










290
291
292
  set res
} {database_1 database_2 database_3 database_4 database_5}

do_execsql_test -db db2 5.1.2 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool ORDER BY 1;
} {nref=6 nschema=1}












finish_test








>
>
>
>
>
>
>
>
>
>



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  set res
} {database_1 database_2 database_3 database_4 database_5}

do_execsql_test -db db2 5.1.2 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool ORDER BY 1;
} {nref=6 nschema=1}

do_test 5.2.1 {
  sqlite3_table_column_metadata db2 main bbb a
} {INTEGER BINARY 0 1 0}
do_test 5.2.2 {
  sqlite3_table_column_metadata db2 main bbb b
} {{} BINARY 0 0 0}

do_execsql_test -db db2 5.2.3 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool ORDER BY 1;
} {nref=6 nschema=1}

finish_test