/ Check-in [e002666a]
Login

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

Overview
Comment:Performance optimization in the VDBE, and a fix for a harmless compiler warning.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | reuse-schema-vdbe-opt
Files: files | file ages | folders
SHA3-256: e002666ac79c3452a772323c6ecc696104341cd842e77541553ec028f188096b
User & Date: drh 2019-02-13 13:48:48
Context
2019-02-13
14:06
Rearrange the code in the VDBE to help out the C-compiler optimizer. And fix a harmless compiler warning. check-in: 219b39e1 user: drh tags: reuse-schema
13:48
Performance optimization in the VDBE, and a fix for a harmless compiler warning. Closed-Leaf check-in: e002666a user: drh tags: reuse-schema-vdbe-opt
08:40
Fix a problem with OPEN_REUSE_SCHEMA connections reloading the temp schema. check-in: 7c2ec2d4 user: dan tags: reuse-schema
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to src/status.c.

   278    278   
   279    279         sqlite3BtreeEnterAll(db);
   280    280         db->pnBytesFreed = &nByte;
   281    281         for(i=0; i<db->nDb; i++){
   282    282           Schema *pSchema = db->aDb[i].pSchema;
   283    283           if( ALWAYS(pSchema!=0) ){
   284    284             HashElem *p;
   285         -          int nStart = nByte;
   286    285   
   287    286             nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
   288    287                 pSchema->tblHash.count 
   289    288               + pSchema->trigHash.count
   290    289               + pSchema->idxHash.count
   291    290               + pSchema->fkeyHash.count
   292    291             );

Changes to src/vdbe.c.

   407    407       return pMem->flags & (MEM_Int|MEM_Real);
   408    408     }
   409    409     if( pMem->flags & (MEM_Str|MEM_Blob) ){
   410    410       return computeNumericType(pMem);
   411    411     }
   412    412     return 0;
   413    413   }
          414  +
          415  +/*
          416  +** This is the implementation of the OP_ParseSchema opcode.  It is factored
          417  +** out of the main sqlite3VdbeExec() routine because it is not a performance-
          418  +** critical opcode and by factoring it out, it frees up registers in order
          419  +** to help the compiler optimizer do a better job with the other opcodes
          420  +** that are performance critical.
          421  +*/
          422  +static SQLITE_NOINLINE int parseSchemaOp(Vdbe *p, VdbeOp *pOp, sqlite3 *db){
          423  +  int iDb;
          424  +  const char *zMaster;
          425  +  char *zSql;
          426  +  InitData initData;
          427  +  int bRelease;
          428  +  int rc = SQLITE_OK;
          429  +
          430  +  /* Any prepared statement that invokes this opcode will hold mutexes
          431  +  ** on every btree.  This is a prerequisite for invoking 
          432  +  ** sqlite3InitCallback().
          433  +  */
          434  +#ifdef SQLITE_DEBUG
          435  +  for(iDb=0; iDb<db->nDb; iDb++){
          436  +    assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
          437  +  }
          438  +#endif
          439  +
          440  +  iDb = pOp->p1;
          441  +  assert( iDb>=0 && iDb<db->nDb );
          442  +  assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
          443  +
          444  +#ifndef SQLITE_OMIT_ALTERTABLE
          445  +  if( pOp->p4.z==0 ){
          446  +    assert( !IsReuseSchema(db) || iDb==1 );
          447  +    sqlite3SchemaClear(db->aDb[iDb].pSchema);
          448  +    db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
          449  +    rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
          450  +    db->mDbFlags |= DBFLAG_SchemaChange;
          451  +    p->expired = 0;
          452  +  }else
          453  +#endif
          454  +  {
          455  +    zMaster = MASTER_NAME;
          456  +    initData.db = db;
          457  +    initData.iDb = iDb;
          458  +    initData.pzErrMsg = &p->zErrMsg;
          459  +    initData.mInitFlags = 0;
          460  +    zSql = sqlite3MPrintf(db,
          461  +       "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
          462  +       db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
          463  +    if( zSql==0 ){
          464  +      rc = SQLITE_NOMEM_BKPT;
          465  +    }else{
          466  +      bRelease = sqlite3LockReusableSchema(db);
          467  +      if( IsReuseSchema(db) ){
          468  +        rc = sqlite3Init(db, &p->zErrMsg);
          469  +        if( rc ){
          470  +          sqlite3UnlockReusableSchema(db, bRelease);
          471  +          return rc;
          472  +        }
          473  +      }
          474  +      assert( db->init.busy==0 );
          475  +      db->init.busy = 1;
          476  +      initData.rc = SQLITE_OK;
          477  +      initData.nInitRow = 0;
          478  +      assert( !db->mallocFailed );
          479  +      rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
          480  +      sqlite3UnlockReusableSchema(db, bRelease);
          481  +      if( rc==SQLITE_OK ) rc = initData.rc;
          482  +      if( rc==SQLITE_OK && initData.nInitRow==0 ){
          483  +        /* The OP_ParseSchema opcode with a non-NULL P4 argument should parse
          484  +        ** at least one SQL statement. Any less than that indicates that
          485  +        ** the sqlite_master table is corrupt. */
          486  +        rc = SQLITE_CORRUPT_BKPT;
          487  +      }
          488  +      sqlite3DbFreeNN(db, zSql);
          489  +      db->init.busy = 0;
          490  +    }
          491  +  }
          492  +  return rc;
          493  +}
   414    494   
   415    495   #ifdef SQLITE_DEBUG
   416    496   /*
   417    497   ** Write a nice string representation of the contents of cell pMem
   418    498   ** into buffer zBuf, length nBuf.
   419    499   */
   420    500   void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
................................................................................
  5753   5833   ** that match the WHERE clause P4.  If P4 is a NULL pointer, then the
  5754   5834   ** entire schema for P1 is reparsed.
  5755   5835   **
  5756   5836   ** This opcode invokes the parser to create a new virtual machine,
  5757   5837   ** then runs the new virtual machine.  It is thus a re-entrant opcode.
  5758   5838   */
  5759   5839   case OP_ParseSchema: {
  5760         -  int iDb;
  5761         -  const char *zMaster;
  5762         -  char *zSql;
  5763         -  InitData initData;
  5764         -  int bRelease;
  5765         -
  5766         -  /* Any prepared statement that invokes this opcode will hold mutexes
  5767         -  ** on every btree.  This is a prerequisite for invoking 
  5768         -  ** sqlite3InitCallback().
  5769         -  */
  5770         -#ifdef SQLITE_DEBUG
  5771         -  for(iDb=0; iDb<db->nDb; iDb++){
  5772         -    assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
  5773         -  }
  5774         -#endif
  5775         -
  5776         -  iDb = pOp->p1;
  5777         -  assert( iDb>=0 && iDb<db->nDb );
  5778         -  assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
  5779         -
  5780         -#ifndef SQLITE_OMIT_ALTERTABLE
  5781         -  if( pOp->p4.z==0 ){
  5782         -    assert( !IsReuseSchema(db) || iDb==1 );
  5783         -    sqlite3SchemaClear(db->aDb[iDb].pSchema);
  5784         -    db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
  5785         -    rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
  5786         -    db->mDbFlags |= DBFLAG_SchemaChange;
  5787         -    p->expired = 0;
  5788         -  }else
  5789         -#endif
  5790         -  {
  5791         -    zMaster = MASTER_NAME;
  5792         -    initData.db = db;
  5793         -    initData.iDb = iDb;
  5794         -    initData.pzErrMsg = &p->zErrMsg;
  5795         -    initData.mInitFlags = 0;
  5796         -    zSql = sqlite3MPrintf(db,
  5797         -       "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
  5798         -       db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
  5799         -    if( zSql==0 ){
  5800         -      rc = SQLITE_NOMEM_BKPT;
  5801         -    }else{
  5802         -      bRelease = sqlite3LockReusableSchema(db);
  5803         -      if( IsReuseSchema(db) ){
  5804         -        rc = sqlite3Init(db, &p->zErrMsg);
  5805         -        if( rc ){
  5806         -          sqlite3UnlockReusableSchema(db, bRelease);
  5807         -          goto abort_due_to_error;
  5808         -        }
  5809         -      }
  5810         -      assert( db->init.busy==0 );
  5811         -      db->init.busy = 1;
  5812         -      initData.rc = SQLITE_OK;
  5813         -      initData.nInitRow = 0;
  5814         -      assert( !db->mallocFailed );
  5815         -      rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
  5816         -      sqlite3UnlockReusableSchema(db, bRelease);
  5817         -      if( rc==SQLITE_OK ) rc = initData.rc;
  5818         -      if( rc==SQLITE_OK && initData.nInitRow==0 ){
  5819         -        /* The OP_ParseSchema opcode with a non-NULL P4 argument should parse
  5820         -        ** at least one SQL statement. Any less than that indicates that
  5821         -        ** the sqlite_master table is corrupt. */
  5822         -        rc = SQLITE_CORRUPT_BKPT;
  5823         -      }
  5824         -      sqlite3DbFreeNN(db, zSql);
  5825         -      db->init.busy = 0;
  5826         -    }
  5827         -  }
         5840  +  rc = parseSchemaOp(p, pOp, db);
  5828   5841     if( rc ){
  5829   5842       sqlite3ResetAllSchemasOfConnection(db);
  5830   5843       if( rc==SQLITE_NOMEM ){
  5831   5844         goto no_mem;
  5832   5845       }
  5833   5846       goto abort_due_to_error;
  5834   5847     }