/ Check-in [968fec44]
Login

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

Overview
Comment:Combine the various boolean fields of the BtCursor object into a single bit-vector. This allows setting or clearing more than one boolean at a time and makes the overflow-pgno-cache branch faster than trunk on speedtest1.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | overflow-pgno-cache
Files: files | file ages | folders
SHA1:968fec44d7fde3adbd3e9603e4282351f0d4bda1
User & Date: drh 2014-03-11 23:40:44
Context
2014-03-11
23:44
Remove a stray C99-style comment. check-in: f500e87d user: drh tags: overflow-pgno-cache
23:40
Combine the various boolean fields of the BtCursor object into a single bit-vector. This allows setting or clearing more than one boolean at a time and makes the overflow-pgno-cache branch faster than trunk on speedtest1. check-in: 968fec44 user: drh tags: overflow-pgno-cache
20:33
Enable the b-tree cursor object's overflow page-number cache, which is normally enabled only for incr-blob cursors, for all cursors. check-in: da591985 user: dan tags: overflow-pgno-cache
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

   446    446   }
   447    447   #endif
   448    448   
   449    449   /*
   450    450   ** Invalidate the overflow cache of the cursor passed as the first argument.
   451    451   ** on the shared btree structure pBt.
   452    452   */
   453         -#define invalidateOverflowCache(pCur) (pCur->bOvflValid = 0)
          453  +#define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl)
   454    454   
   455    455   /*
   456    456   ** Invalidate the overflow page-list cache for all cursors opened
   457    457   ** on the shared btree structure pBt.
   458    458   */
   459    459   static void invalidateAllOverflowCache(BtShared *pBt){
   460    460     BtCursor *p;
................................................................................
   483    483     i64 iRow,               /* The rowid that might be changing */
   484    484     int isClearTable        /* True if all rows are being deleted */
   485    485   ){
   486    486     BtCursor *p;
   487    487     BtShared *pBt = pBtree->pBt;
   488    488     assert( sqlite3BtreeHoldsMutex(pBtree) );
   489    489     for(p=pBt->pCursor; p; p=p->pNext){
   490         -    if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){
          490  +    if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){
   491    491         p->eState = CURSOR_INVALID;
   492    492       }
   493    493     }
   494    494   }
   495    495   
   496    496   #else
   497    497     /* Stub function when INCRBLOB is omitted */
................................................................................
  2539   2539   ** is capable of reading or writing to the databse.  Cursors that
  2540   2540   ** have been tripped into the CURSOR_FAULT state are not counted.
  2541   2541   */
  2542   2542   static int countValidCursors(BtShared *pBt, int wrOnly){
  2543   2543     BtCursor *pCur;
  2544   2544     int r = 0;
  2545   2545     for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
  2546         -    if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++; 
         2546  +    if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0)
         2547  +     && pCur->eState!=CURSOR_FAULT ) r++; 
  2547   2548     }
  2548   2549     return r;
  2549   2550   }
  2550   2551   #endif
  2551   2552   
  2552   2553   /*
  2553   2554   ** If there are no outstanding cursors and we are not in the middle
................................................................................
  3614   3615     /* Now that no other errors can occur, finish filling in the BtCursor
  3615   3616     ** variables and link the cursor into the BtShared list.  */
  3616   3617     pCur->pgnoRoot = (Pgno)iTable;
  3617   3618     pCur->iPage = -1;
  3618   3619     pCur->pKeyInfo = pKeyInfo;
  3619   3620     pCur->pBtree = p;
  3620   3621     pCur->pBt = pBt;
  3621         -  pCur->wrFlag = (u8)wrFlag;
         3622  +  pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0;
  3622   3623     pCur->pNext = pBt->pCursor;
  3623   3624     if( pCur->pNext ){
  3624   3625       pCur->pNext->pPrev = pCur;
  3625   3626     }
  3626   3627     pBt->pCursor = pCur;
  3627   3628     pCur->eState = CURSOR_INVALID;
  3628   3629     return SQLITE_OK;
................................................................................
  3723   3724   #endif
  3724   3725   #ifdef _MSC_VER
  3725   3726     /* Use a real function in MSVC to work around bugs in that compiler. */
  3726   3727     static void getCellInfo(BtCursor *pCur){
  3727   3728       if( pCur->info.nSize==0 ){
  3728   3729         int iPage = pCur->iPage;
  3729   3730         btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
  3730         -      pCur->validNKey = 1;
         3731  +      pCur->curFlags |= BTCF_ValidNKey;
  3731   3732       }else{
  3732   3733         assertCellInfo(pCur);
  3733   3734       }
  3734   3735     }
  3735   3736   #else /* if not _MSC_VER */
  3736   3737     /* Use a macro in all other compilers so that the function is inlined */
  3737   3738   #define getCellInfo(pCur)                                                      \
  3738   3739     if( pCur->info.nSize==0 ){                                                   \
  3739   3740       int iPage = pCur->iPage;                                                   \
  3740         -    btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
  3741         -    pCur->validNKey = 1;                                                       \
         3741  +    btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);        \
         3742  +    pCur->curFlags |= BTCF_ValidNKey;                                          \
  3742   3743     }else{                                                                       \
  3743   3744       assertCellInfo(pCur);                                                      \
  3744   3745     }
  3745   3746   #endif /* _MSC_VER */
  3746   3747   
  3747   3748   #ifndef NDEBUG  /* The next routine used only within assert() statements */
  3748   3749   /*
................................................................................
  3983   3984   
  3984   3985     if( rc==SQLITE_OK && amt>0 ){
  3985   3986       const u32 ovflSize = pBt->usableSize - 4;  /* Bytes content per ovfl page */
  3986   3987       Pgno nextPage;
  3987   3988   
  3988   3989       nextPage = get4byte(&aPayload[pCur->info.nLocal]);
  3989   3990   
  3990         -    /* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[]
         3991  +    /* If the BTCF_Incrblob flag is set and the BtCursor.aOverflow[]
  3991   3992       ** has not been allocated, allocate it now. The array is sized at
  3992   3993       ** one entry for each overflow page in the overflow chain. The
  3993   3994       ** page number of the first overflow page is stored in aOverflow[0],
  3994   3995       ** etc. A value of 0 in the aOverflow[] array means "not yet known"
  3995   3996       ** (the cache is lazily populated).
  3996   3997       */
  3997         -    if( eOp!=2 && !pCur->bOvflValid ){
         3998  +    if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
  3998   3999         int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
  3999   4000         if( nOvfl>pCur->nOvflAlloc ){
  4000   4001           Pgno *aNew = (Pgno*)sqlite3DbRealloc(
  4001   4002               pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
  4002   4003           );
  4003   4004           if( aNew==0 ){
  4004   4005             rc = SQLITE_NOMEM;
................................................................................
  4005   4006           }else{
  4006   4007             pCur->nOvflAlloc = nOvfl*2;
  4007   4008             pCur->aOverflow = aNew;
  4008   4009           }
  4009   4010         }
  4010   4011         if( rc==SQLITE_OK ){
  4011   4012           memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
  4012         -        pCur->bOvflValid = 1;
         4013  +        pCur->curFlags |= BTCF_ValidOvfl;
  4013   4014         }
  4014   4015       }
  4015   4016   
  4016   4017       /* If the overflow page-list cache has been allocated and the
  4017   4018       ** entry for the first required overflow page is valid, skip
  4018   4019       ** directly to it.
  4019   4020       */
  4020         -    if( pCur->bOvflValid && pCur->aOverflow[offset/ovflSize] ){
         4021  +    if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){
  4021   4022         iIdx = (offset/ovflSize);
  4022   4023         nextPage = pCur->aOverflow[iIdx];
  4023   4024         offset = (offset%ovflSize);
  4024   4025       }
  4025   4026   
  4026   4027       for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
  4027   4028   
  4028   4029         /* If required, populate the overflow page-list cache. */
  4029         -      if( pCur->bOvflValid ){
         4030  +      if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
  4030   4031           assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
  4031   4032           pCur->aOverflow[iIdx] = nextPage;
  4032   4033         }
  4033   4034   
  4034   4035         if( offset>=ovflSize ){
  4035   4036           /* The only reason to read this page is to obtain the page
  4036   4037           ** number for the next page in the overflow chain. The page
  4037   4038           ** data is not required. So first try to lookup the overflow
  4038   4039           ** page-list cache, if any, then fall back to the getOverflowPage()
  4039   4040           ** function.
  4040   4041           */
  4041         -        if( pCur->bOvflValid && pCur->aOverflow[iIdx+1] ){
         4042  +        if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[iIdx+1] ){
  4042   4043             nextPage = pCur->aOverflow[iIdx+1];
  4043   4044           } else 
  4044   4045             rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
  4045   4046           offset -= ovflSize;
  4046   4047         }else{
  4047   4048           /* Need to read this page properly. It contains some of the
  4048   4049           ** range of data that is being read (eOp==0) or written (eOp!=0).
................................................................................
  4235   4236     assert( pCur->eState==CURSOR_VALID );
  4236   4237     assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
  4237   4238     assert( pCur->iPage>=0 );
  4238   4239     if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
  4239   4240       return SQLITE_CORRUPT_BKPT;
  4240   4241     }
  4241   4242     rc = getAndInitPage(pBt, newPgno, &pNewPage,
  4242         -               pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
         4243  +               (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
  4243   4244     if( rc ) return rc;
  4244   4245     pCur->apPage[i+1] = pNewPage;
  4245   4246     pCur->aiIdx[i+1] = 0;
  4246   4247     pCur->iPage++;
  4247   4248   
  4248   4249     pCur->info.nSize = 0;
  4249         -  pCur->validNKey = 0;
         4250  +  pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
  4250   4251     if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
  4251   4252       return SQLITE_CORRUPT_BKPT;
  4252   4253     }
  4253   4254     return SQLITE_OK;
  4254   4255   }
  4255   4256   
  4256   4257   #if 0
................................................................................
  4300   4301     );
  4301   4302   #endif
  4302   4303     testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
  4303   4304   
  4304   4305     releasePage(pCur->apPage[pCur->iPage]);
  4305   4306     pCur->iPage--;
  4306   4307     pCur->info.nSize = 0;
  4307         -  pCur->validNKey = 0;
         4308  +  pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
  4308   4309   }
  4309   4310   
  4310   4311   /*
  4311   4312   ** Move the cursor to point to the root page of its b-tree structure.
  4312   4313   **
  4313   4314   ** If the table has a virtual root page, then the cursor is moved to point
  4314   4315   ** to the virtual root page instead of the actual root page. A table has a
................................................................................
  4332   4333     MemPage *pRoot;
  4333   4334     int rc = SQLITE_OK;
  4334   4335   
  4335   4336     assert( cursorHoldsMutex(pCur) );
  4336   4337     assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
  4337   4338     assert( CURSOR_VALID   < CURSOR_REQUIRESEEK );
  4338   4339     assert( CURSOR_FAULT   > CURSOR_REQUIRESEEK );
  4339         -  invalidateOverflowCache(pCur);
         4340  +//  invalidateOverflowCache(pCur);
  4340   4341     if( pCur->eState>=CURSOR_REQUIRESEEK ){
  4341   4342       if( pCur->eState==CURSOR_FAULT ){
  4342   4343         assert( pCur->skipNext!=SQLITE_OK );
  4343   4344         return pCur->skipNext;
  4344   4345       }
  4345   4346       sqlite3BtreeClearCursor(pCur);
  4346   4347     }
................................................................................
  4348   4349     if( pCur->iPage>=0 ){
  4349   4350       while( pCur->iPage ) releasePage(pCur->apPage[pCur->iPage--]);
  4350   4351     }else if( pCur->pgnoRoot==0 ){
  4351   4352       pCur->eState = CURSOR_INVALID;
  4352   4353       return SQLITE_OK;
  4353   4354     }else{
  4354   4355       rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
  4355         -                        pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
         4356  +                 (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
  4356   4357       if( rc!=SQLITE_OK ){
  4357   4358         pCur->eState = CURSOR_INVALID;
  4358   4359         return rc;
  4359   4360       }
  4360   4361       pCur->iPage = 0;
  4361   4362     }
  4362   4363     pRoot = pCur->apPage[0];
................................................................................
  4375   4376     assert( pRoot->intKey==1 || pRoot->intKey==0 );
  4376   4377     if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
  4377   4378       return SQLITE_CORRUPT_BKPT;
  4378   4379     }
  4379   4380   
  4380   4381     pCur->aiIdx[0] = 0;
  4381   4382     pCur->info.nSize = 0;
  4382         -  pCur->atLast = 0;
  4383         -  pCur->validNKey = 0;
         4383  +  pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
  4384   4384   
  4385   4385     if( pRoot->nCell>0 ){
  4386   4386       pCur->eState = CURSOR_VALID;
  4387   4387     }else if( !pRoot->leaf ){
  4388   4388       Pgno subpage;
  4389   4389       if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT;
  4390   4390       subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]);
................................................................................
  4439   4439       pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
  4440   4440       pCur->aiIdx[pCur->iPage] = pPage->nCell;
  4441   4441       rc = moveToChild(pCur, pgno);
  4442   4442     }
  4443   4443     if( rc==SQLITE_OK ){
  4444   4444       pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
  4445   4445       pCur->info.nSize = 0;
  4446         -    pCur->validNKey = 0;
         4446  +    pCur->curFlags &= ~BTCF_ValidNKey;
  4447   4447     }
  4448   4448     return rc;
  4449   4449   }
  4450   4450   
  4451   4451   /* Move the cursor to the first entry in the table.  Return SQLITE_OK
  4452   4452   ** on success.  Set *pRes to 0 if the cursor actually points to something
  4453   4453   ** or set *pRes to 1 if the table is empty.
................................................................................
  4478   4478   int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
  4479   4479     int rc;
  4480   4480    
  4481   4481     assert( cursorHoldsMutex(pCur) );
  4482   4482     assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
  4483   4483   
  4484   4484     /* If the cursor already points to the last entry, this is a no-op. */
  4485         -  if( CURSOR_VALID==pCur->eState && pCur->atLast ){
         4485  +  if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
  4486   4486   #ifdef SQLITE_DEBUG
  4487   4487       /* This block serves to assert() that the cursor really does point 
  4488   4488       ** to the last entry in the b-tree. */
  4489   4489       int ii;
  4490   4490       for(ii=0; ii<pCur->iPage; ii++){
  4491   4491         assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
  4492   4492       }
................................................................................
  4501   4501       if( CURSOR_INVALID==pCur->eState ){
  4502   4502         assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
  4503   4503         *pRes = 1;
  4504   4504       }else{
  4505   4505         assert( pCur->eState==CURSOR_VALID );
  4506   4506         *pRes = 0;
  4507   4507         rc = moveToRightmost(pCur);
  4508         -      pCur->atLast = rc==SQLITE_OK ?1:0;
         4508  +      if( rc==SQLITE_OK ){
         4509  +        pCur->curFlags |= BTCF_AtLast;
         4510  +      }else{
         4511  +        pCur->curFlags &= ~BTCF_AtLast;
         4512  +      }
         4513  +   
  4509   4514       }
  4510   4515     }
  4511   4516     return rc;
  4512   4517   }
  4513   4518   
  4514   4519   /* Move the cursor so that it points to an entry near the key 
  4515   4520   ** specified by pIdxKey or intKey.   Return a success code.
................................................................................
  4552   4557     assert( cursorHoldsMutex(pCur) );
  4553   4558     assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
  4554   4559     assert( pRes );
  4555   4560     assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
  4556   4561   
  4557   4562     /* If the cursor is already positioned at the point we are trying
  4558   4563     ** to move to, then just return without doing any work */
  4559         -  if( pCur->eState==CURSOR_VALID && pCur->validNKey 
         4564  +  if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
  4560   4565      && pCur->apPage[0]->intKey 
  4561   4566     ){
  4562   4567       if( pCur->info.nKey==intKey ){
  4563   4568         *pRes = 0;
  4564   4569         return SQLITE_OK;
  4565   4570       }
  4566         -    if( pCur->atLast && pCur->info.nKey<intKey ){
         4571  +    if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
  4567   4572         *pRes = -1;
  4568   4573         return SQLITE_OK;
  4569   4574       }
  4570   4575     }
  4571   4576   
  4572   4577     if( pIdxKey ){
  4573   4578       xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
................................................................................
  4625   4630             lwr = idx+1;
  4626   4631             if( lwr>upr ){ c = -1; break; }
  4627   4632           }else if( nCellKey>intKey ){
  4628   4633             upr = idx-1;
  4629   4634             if( lwr>upr ){ c = +1; break; }
  4630   4635           }else{
  4631   4636             assert( nCellKey==intKey );
  4632         -          pCur->validNKey = 1;
         4637  +          pCur->curFlags |= BTCF_ValidNKey;
  4633   4638             pCur->info.nKey = nCellKey;
  4634   4639             pCur->aiIdx[pCur->iPage] = (u16)idx;
  4635   4640             if( !pPage->leaf ){
  4636   4641               lwr = idx;
  4637   4642               goto moveto_next_layer;
  4638   4643             }else{
  4639   4644               *pRes = 0;
................................................................................
  4727   4732       }
  4728   4733       pCur->aiIdx[pCur->iPage] = (u16)lwr;
  4729   4734       rc = moveToChild(pCur, chldPg);
  4730   4735       if( rc ) break;
  4731   4736     }
  4732   4737   moveto_finish:
  4733   4738     pCur->info.nSize = 0;
  4734         -  pCur->validNKey = 0;
         4739  +  pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
  4735   4740     return rc;
  4736   4741   }
  4737   4742   
  4738   4743   
  4739   4744   /*
  4740   4745   ** Return TRUE if the cursor is not pointing at an entry of the table.
  4741   4746   **
................................................................................
  4771   4776     int idx;
  4772   4777     MemPage *pPage;
  4773   4778   
  4774   4779     assert( cursorHoldsMutex(pCur) );
  4775   4780     assert( pRes!=0 );
  4776   4781     assert( *pRes==0 || *pRes==1 );
  4777   4782     assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
  4778         -  invalidateOverflowCache(pCur);
  4779   4783     if( pCur->eState!=CURSOR_VALID ){
         4784  +    invalidateOverflowCache(pCur);
  4780   4785       rc = restoreCursorPosition(pCur);
  4781   4786       if( rc!=SQLITE_OK ){
  4782   4787         *pRes = 0;
  4783   4788         return rc;
  4784   4789       }
  4785   4790       if( CURSOR_INVALID==pCur->eState ){
  4786   4791         *pRes = 1;
................................................................................
  4806   4811     ** to be invalid here. This can only occur if a second cursor modifies
  4807   4812     ** the page while cursor pCur is holding a reference to it. Which can
  4808   4813     ** only happen if the database is corrupt in such a way as to link the
  4809   4814     ** page into more than one b-tree structure. */
  4810   4815     testcase( idx>pPage->nCell );
  4811   4816   
  4812   4817     pCur->info.nSize = 0;
  4813         -  pCur->validNKey = 0;
         4818  +  pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
  4814   4819     if( idx>=pPage->nCell ){
  4815   4820       if( !pPage->leaf ){
  4816   4821         rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
  4817   4822         if( rc ){
  4818   4823           *pRes = 0;
  4819   4824           return rc;
  4820   4825         }
................................................................................
  4867   4872     int rc;
  4868   4873     MemPage *pPage;
  4869   4874   
  4870   4875     assert( cursorHoldsMutex(pCur) );
  4871   4876     assert( pRes!=0 );
  4872   4877     assert( *pRes==0 || *pRes==1 );
  4873   4878     assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
  4874         -  invalidateOverflowCache(pCur);
  4875         -  pCur->atLast = 0;
         4879  +  pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl);
  4876   4880     if( pCur->eState!=CURSOR_VALID ){
  4877   4881       if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
  4878   4882         rc = btreeRestoreCursorPosition(pCur);
  4879   4883         if( rc!=SQLITE_OK ){
  4880   4884           *pRes = 0;
  4881   4885           return rc;
  4882   4886         }
................................................................................
  4913   4917           pCur->eState = CURSOR_INVALID;
  4914   4918           *pRes = 1;
  4915   4919           return SQLITE_OK;
  4916   4920         }
  4917   4921         moveToParent(pCur);
  4918   4922       }
  4919   4923       pCur->info.nSize = 0;
  4920         -    pCur->validNKey = 0;
         4924  +    pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
  4921   4925   
  4922   4926       pCur->aiIdx[pCur->iPage]--;
  4923   4927       pPage = pCur->apPage[pCur->iPage];
  4924   4928       if( pPage->intKey && !pPage->leaf ){
  4925   4929         rc = sqlite3BtreePrevious(pCur, pRes);
  4926   4930       }else{
  4927   4931         rc = SQLITE_OK;
................................................................................
  6938   6942   
  6939   6943     if( pCur->eState==CURSOR_FAULT ){
  6940   6944       assert( pCur->skipNext!=SQLITE_OK );
  6941   6945       return pCur->skipNext;
  6942   6946     }
  6943   6947   
  6944   6948     assert( cursorHoldsMutex(pCur) );
  6945         -  assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE
         6949  +  assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE
  6946   6950                 && (pBt->btsFlags & BTS_READ_ONLY)==0 );
  6947   6951     assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
  6948   6952   
  6949   6953     /* Assert that the caller has been consistent. If this cursor was opened
  6950   6954     ** expecting an index b-tree, then the caller should be inserting blob
  6951   6955     ** keys with no associated data. If the cursor was opened expecting an
  6952   6956     ** intkey table, the caller should be inserting integer keys with a
................................................................................
  6971   6975       /* If this is an insert into a table b-tree, invalidate any incrblob 
  6972   6976       ** cursors open on the row being replaced */
  6973   6977       invalidateIncrblobCursors(p, nKey, 0);
  6974   6978   
  6975   6979       /* If the cursor is currently on the last row and we are appending a
  6976   6980       ** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
  6977   6981       ** call */
  6978         -    if( pCur->validNKey && nKey>0 && pCur->info.nKey==nKey-1 ){
         6982  +    if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){
  6979   6983         loc = -1;
  6980   6984       }
  6981   6985     }
  6982   6986   
  6983   6987     if( !loc ){
  6984   6988       rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc);
  6985   6989       if( rc ) return rc;
................................................................................
  7024   7028       assert( pPage->leaf );
  7025   7029     }
  7026   7030     insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
  7027   7031     assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
  7028   7032   
  7029   7033     /* If no error has occurred and pPage has an overflow cell, call balance() 
  7030   7034     ** to redistribute the cells within the tree. Since balance() may move
  7031         -  ** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey
         7035  +  ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
  7032   7036     ** variables.
  7033   7037     **
  7034   7038     ** Previous versions of SQLite called moveToRoot() to move the cursor
  7035   7039     ** back to the root page as balance() used to invalidate the contents
  7036   7040     ** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that,
  7037   7041     ** set the cursor state to "invalid". This makes common insert operations
  7038   7042     ** slightly faster.
................................................................................
  7044   7048     ** the b-tree if possible. If the cursor is left pointing to the last
  7045   7049     ** entry in the table, and the next row inserted has an integer key
  7046   7050     ** larger than the largest existing key, it is possible to insert the
  7047   7051     ** row without seeking the cursor. This can be a big performance boost.
  7048   7052     */
  7049   7053     pCur->info.nSize = 0;
  7050   7054     if( rc==SQLITE_OK && pPage->nOverflow ){
  7051         -    pCur->validNKey = 0;
         7055  +    pCur->curFlags &= ~(BTCF_ValidNKey);
  7052   7056       rc = balance(pCur);
  7053   7057   
  7054   7058       /* Must make sure nOverflow is reset to zero even if the balance()
  7055   7059       ** fails. Internal data structure corruption will result otherwise. 
  7056   7060       ** Also, set the cursor state to invalid. This stops saveCursorPosition()
  7057   7061       ** from trying to save the current position of the cursor.  */
  7058   7062       pCur->apPage[pCur->iPage]->nOverflow = 0;
................................................................................
  7076   7080     unsigned char *pCell;                /* Pointer to cell to delete */
  7077   7081     int iCellIdx;                        /* Index of cell to delete */
  7078   7082     int iCellDepth;                      /* Depth of node containing pCell */ 
  7079   7083   
  7080   7084     assert( cursorHoldsMutex(pCur) );
  7081   7085     assert( pBt->inTransaction==TRANS_WRITE );
  7082   7086     assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
  7083         -  assert( pCur->wrFlag );
         7087  +  assert( pCur->curFlags & BTCF_WriteFlag );
  7084   7088     assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
  7085   7089     assert( !hasReadConflicts(p, pCur->pgnoRoot) );
  7086   7090   
  7087   7091     if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell) 
  7088   7092      || NEVER(pCur->eState!=CURSOR_VALID)
  7089   7093     ){
  7090   7094       return SQLITE_ERROR;  /* Something has gone awry. */
................................................................................
  8380   8384   ** parameters that attempt to write past the end of the existing data,
  8381   8385   ** no modifications are made and SQLITE_CORRUPT is returned.
  8382   8386   */
  8383   8387   int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
  8384   8388     int rc;
  8385   8389     assert( cursorHoldsMutex(pCsr) );
  8386   8390     assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
  8387         -  assert( pCsr->isIncrblobHandle );
         8391  +  assert( pCsr->curFlags & BTCF_Incrblob );
  8388   8392   
  8389   8393     rc = restoreCursorPosition(pCsr);
  8390   8394     if( rc!=SQLITE_OK ){
  8391   8395       return rc;
  8392   8396     }
  8393   8397     assert( pCsr->eState!=CURSOR_REQUIRESEEK );
  8394   8398     if( pCsr->eState!=CURSOR_VALID ){
................................................................................
  8409   8413     /* Check some assumptions: 
  8410   8414     **   (a) the cursor is open for writing,
  8411   8415     **   (b) there is a read/write transaction open,
  8412   8416     **   (c) the connection holds a write-lock on the table (if required),
  8413   8417     **   (d) there are no conflicting read-locks, and
  8414   8418     **   (e) the cursor points at a valid row of an intKey table.
  8415   8419     */
  8416         -  if( !pCsr->wrFlag ){
         8420  +  if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){
  8417   8421       return SQLITE_READONLY;
  8418   8422     }
  8419   8423     assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
  8420   8424                 && pCsr->pBt->inTransaction==TRANS_WRITE );
  8421   8425     assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
  8422   8426     assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) );
  8423   8427     assert( pCsr->apPage[pCsr->iPage]->intKey );
................................................................................
  8425   8429     return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
  8426   8430   }
  8427   8431   
  8428   8432   /* 
  8429   8433   ** Mark this cursor as an incremental blob cursor.
  8430   8434   */
  8431   8435   void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
  8432         -  pCur->isIncrblobHandle = 1;
         8436  +  pCur->curFlags |= BTCF_Incrblob;
  8433   8437   }
  8434   8438   #endif
  8435   8439   
  8436   8440   /*
  8437   8441   ** Set both the "read version" (single byte at byte offset 18) and 
  8438   8442   ** "write version" (single byte at byte offset 19) fields in the database
  8439   8443   ** header to iVersion.

Changes to src/btreeInt.h.

   492    492   ** found at self->pBt->mutex. 
   493    493   */
   494    494   struct BtCursor {
   495    495     Btree *pBtree;            /* The Btree to which this cursor belongs */
   496    496     BtShared *pBt;            /* The BtShared this cursor points to */
   497    497     BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
   498    498     struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
   499         -#ifndef SQLITE_OMIT_INCRBLOB
   500         -  int nOvflAlloc;           /* Allocated size of aOverflow[] array */
   501         -  u8 bOvflValid;            /* True if size and contents of aOverflow[] valid */
   502    499     Pgno *aOverflow;          /* Cache of overflow page locations */
   503         -#endif
          500  +  CellInfo info;            /* A parse of the cell we are pointing at */
          501  +  i64 nKey;                 /* Size of pKey, or last integer key */
          502  +  void *pKey;               /* Saved key that was cursor last known position */
   504    503     Pgno pgnoRoot;            /* The root page of this tree */
   505         -  CellInfo info;            /* A parse of the cell we are pointing at */
   506         -  i64 nKey;        /* Size of pKey, or last integer key */
   507         -  void *pKey;      /* Saved key that was cursor's last known position */
          504  +  int nOvflAlloc;           /* Allocated size of aOverflow[] array */
   508    505     int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
   509         -  u8 wrFlag;                /* True if writable */
   510         -  u8 atLast;                /* Cursor pointing to the last entry */
   511         -  u8 validNKey;             /* True if info.nKey is valid */
          506  +  u8 curFlags;              /* zero or more BTCF_* flags defined below */
   512    507     u8 eState;                /* One of the CURSOR_XXX constants (see below) */
   513         -#ifndef SQLITE_OMIT_INCRBLOB
   514         -  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
   515         -#endif
   516    508     u8 hints;                             /* As configured by CursorSetHints() */
   517    509     i16 iPage;                            /* Index of current page in apPage */
   518    510     u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
   519    511     MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
   520    512   };
   521    513   
          514  +/*
          515  +** Legal values for BtCursor.curFlags
          516  +*/
          517  +#define BTCF_ValidNKey    0x01   /* True if info.nKey is valid */
          518  +#define BTCF_ValidOvfl    0x02   /* True if aOverflow is valid */
          519  +#define BTCF_AtLast       0x04   /* Cursor is pointing ot the last entry */
          520  +#define BTCF_WriteFlag    0x08   /* True if a write cursor */
          521  +#define BTCF_Incrblob     0x10   /* True if an incremental I/O handle */
          522  +
   522    523   /*
   523    524   ** Potential values for BtCursor.eState.
   524    525   **
   525    526   ** CURSOR_INVALID:
   526    527   **   Cursor does not point to a valid entry. This can happen (for example) 
   527    528   **   because the table is empty or because BtreeCursorFirst() has not been
   528    529   **   called.

Changes to src/test_btree.c.

    47     47   */
    48     48   void sqlite3BtreeCursorList(Btree *p){
    49     49   #ifdef SQLITE_DEBUG
    50     50     BtCursor *pCur;
    51     51     BtShared *pBt = p->pBt;
    52     52     for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
    53     53       MemPage *pPage = pCur->apPage[pCur->iPage];
    54         -    char *zMode = pCur->wrFlag ? "rw" : "ro";
           54  +    char *zMode = (pCur->curFlags & BTCF_WriteFlag) ? "rw" : "ro";
    55     55       sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n",
    56     56          pCur, pCur->pgnoRoot, zMode,
    57     57          pPage ? pPage->pgno : 0, pCur->aiIdx[pCur->iPage],
    58     58          (pCur->eState==CURSOR_VALID) ? "" : " eof"
    59     59       );
    60     60     }
    61     61   #endif
    62     62   }