/ Check-in [240d5714]
Login

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

Overview
Comment:Change the internal btree routine moveToRoot() to return SQLITE_EMPTY if the table is empty or if it has pgnoRoot==0. This simplifies the callers, making them smaller and faster. The SQLITE_EMPTY result code is intercepted and changed into SQLITE_OK before surfacing in an API.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 240d57143d943eaddd5f7c2d473f47a1d29417e61d28142f70f3d960bb9b30df
User & Date: drh 2017-08-14 18:13:52
Context
2017-08-14
23:53
Minor size and performance optimization to sqlite3BtreeCloseCursor(). check-in: 16969338 user: drh tags: trunk
18:13
Change the internal btree routine moveToRoot() to return SQLITE_EMPTY if the table is empty or if it has pgnoRoot==0. This simplifies the callers, making them smaller and faster. The SQLITE_EMPTY result code is intercepted and changed into SQLITE_OK before surfacing in an API. check-in: 240d5714 user: drh tags: trunk
17:03
Fix harmless indentation error. check-in: 25e92baa user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

  4910   4910   **
  4911   4911   ** If the table has a virtual root page, then the cursor is moved to point
  4912   4912   ** to the virtual root page instead of the actual root page. A table has a
  4913   4913   ** virtual root page when the actual root page contains no cells and a 
  4914   4914   ** single child page. This can only happen with the table rooted at page 1.
  4915   4915   **
  4916   4916   ** If the b-tree structure is empty, the cursor state is set to 
  4917         -** CURSOR_INVALID. Otherwise, the cursor is set to point to the first
  4918         -** cell located on the root (or virtual root) page and the cursor state
  4919         -** is set to CURSOR_VALID.
         4917  +** CURSOR_INVALID and this routine returns SQLITE_EMPTY. Otherwise,
         4918  +** the cursor is set to point to the first cell located on the root
         4919  +** (or virtual root) page and the cursor state is set to CURSOR_VALID.
  4920   4920   **
  4921   4921   ** If this function returns successfully, it may be assumed that the
  4922   4922   ** page-header flags indicate that the [virtual] root-page is the expected 
  4923   4923   ** kind of b-tree page (i.e. if when opening the cursor the caller did not
  4924   4924   ** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D,
  4925   4925   ** indicating a table b-tree, or if the caller did specify a KeyInfo 
  4926   4926   ** structure the flags byte is set to 0x02 or 0x0A, indicating an index
................................................................................
  4931   4931     int rc = SQLITE_OK;
  4932   4932   
  4933   4933     assert( cursorOwnsBtShared(pCur) );
  4934   4934     assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
  4935   4935     assert( CURSOR_VALID   < CURSOR_REQUIRESEEK );
  4936   4936     assert( CURSOR_FAULT   > CURSOR_REQUIRESEEK );
  4937   4937     assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 );
         4938  +  assert( pCur->pgnoRoot>0 || pCur->iPage<0 );
  4938   4939   
  4939   4940     if( pCur->iPage>=0 ){
  4940   4941       if( pCur->iPage ){
  4941   4942         do{
  4942   4943           assert( pCur->apPage[pCur->iPage]!=0 );
  4943   4944           releasePageNotNull(pCur->apPage[pCur->iPage--]);
  4944   4945         }while( pCur->iPage);
  4945   4946         goto skip_init;
  4946   4947       }
  4947   4948     }else if( pCur->pgnoRoot==0 ){
  4948   4949       pCur->eState = CURSOR_INVALID;
  4949         -    return SQLITE_OK;
         4950  +    return SQLITE_EMPTY;
  4950   4951     }else{
  4951   4952       assert( pCur->iPage==(-1) );
  4952   4953       if( pCur->eState>=CURSOR_REQUIRESEEK ){
  4953   4954         if( pCur->eState==CURSOR_FAULT ){
  4954   4955           assert( pCur->skipNext!=SQLITE_OK );
  4955   4956           return pCur->skipNext;
  4956   4957         }
................................................................................
  4995   4996       Pgno subpage;
  4996   4997       if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT;
  4997   4998       subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]);
  4998   4999       pCur->eState = CURSOR_VALID;
  4999   5000       rc = moveToChild(pCur, subpage);
  5000   5001     }else{
  5001   5002       pCur->eState = CURSOR_INVALID;
         5003  +    rc = SQLITE_EMPTY;
  5002   5004     }
  5003   5005     return rc;
  5004   5006   }
  5005   5007   
  5006   5008   /*
  5007   5009   ** Move the cursor down to the left-most leaf entry beneath the
  5008   5010   ** entry to which it is currently pointing.
................................................................................
  5061   5063   int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
  5062   5064     int rc;
  5063   5065   
  5064   5066     assert( cursorOwnsBtShared(pCur) );
  5065   5067     assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
  5066   5068     rc = moveToRoot(pCur);
  5067   5069     if( rc==SQLITE_OK ){
  5068         -    if( pCur->eState==CURSOR_INVALID ){
  5069         -      assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
  5070         -      *pRes = 1;
  5071         -    }else{
  5072         -      assert( pCur->apPage[pCur->iPage]->nCell>0 );
  5073         -      *pRes = 0;
  5074         -      rc = moveToLeftmost(pCur);
  5075         -    }
         5070  +    assert( pCur->apPage[pCur->iPage]->nCell>0 );
         5071  +    *pRes = 0;
         5072  +    rc = moveToLeftmost(pCur);
         5073  +  }else if( rc==SQLITE_EMPTY ){
         5074  +    assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
         5075  +    *pRes = 1;
         5076  +    rc = SQLITE_OK;
  5076   5077     }
  5077   5078     return rc;
  5078   5079   }
  5079   5080   
  5080   5081   /* Move the cursor to the last entry in the table.  Return SQLITE_OK
  5081   5082   ** on success.  Set *pRes to 0 if the cursor actually points to something
  5082   5083   ** or set *pRes to 1 if the table is empty.
................................................................................
  5100   5101       assert( pCur->apPage[pCur->iPage]->leaf );
  5101   5102   #endif
  5102   5103       return SQLITE_OK;
  5103   5104     }
  5104   5105   
  5105   5106     rc = moveToRoot(pCur);
  5106   5107     if( rc==SQLITE_OK ){
  5107         -    if( CURSOR_INVALID==pCur->eState ){
  5108         -      assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
  5109         -      *pRes = 1;
         5108  +    assert( pCur->eState==CURSOR_VALID );
         5109  +    *pRes = 0;
         5110  +    rc = moveToRightmost(pCur);
         5111  +    if( rc==SQLITE_OK ){
         5112  +      pCur->curFlags |= BTCF_AtLast;
  5110   5113       }else{
  5111         -      assert( pCur->eState==CURSOR_VALID );
  5112         -      *pRes = 0;
  5113         -      rc = moveToRightmost(pCur);
  5114         -      if( rc==SQLITE_OK ){
  5115         -        pCur->curFlags |= BTCF_AtLast;
  5116         -      }else{
  5117         -        pCur->curFlags &= ~BTCF_AtLast;
  5118         -      }
  5119         -   
         5114  +      pCur->curFlags &= ~BTCF_AtLast;
  5120   5115       }
         5116  +  }else if( rc==SQLITE_EMPTY ){
         5117  +    assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
         5118  +    *pRes = 1;
         5119  +    rc = SQLITE_OK;
  5121   5120     }
  5122   5121     return rc;
  5123   5122   }
  5124   5123   
  5125   5124   /* Move the cursor so that it points to an entry near the key 
  5126   5125   ** specified by pIdxKey or intKey.   Return a success code.
  5127   5126   **
................................................................................
  5212   5211       );
  5213   5212     }else{
  5214   5213       xRecordCompare = 0; /* All keys are integers */
  5215   5214     }
  5216   5215   
  5217   5216     rc = moveToRoot(pCur);
  5218   5217     if( rc ){
         5218  +    if( rc==SQLITE_EMPTY ){
         5219  +      assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
         5220  +      *pRes = -1;
         5221  +      return SQLITE_OK;
         5222  +    }
  5219   5223       return rc;
  5220   5224     }
  5221         -  assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] );
  5222         -  assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit );
  5223         -  assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 );
  5224         -  if( pCur->eState==CURSOR_INVALID ){
  5225         -    *pRes = -1;
  5226         -    assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
  5227         -    return SQLITE_OK;
  5228         -  }
         5225  +  assert( pCur->apPage[pCur->iPage] );
         5226  +  assert( pCur->apPage[pCur->iPage]->isInit );
         5227  +  assert( pCur->eState==CURSOR_VALID );
         5228  +  assert( pCur->apPage[pCur->iPage]->nCell > 0 );
  5229   5229     assert( pCur->apPage[0]->intKey==pCur->curIntKey );
  5230   5230     assert( pCur->curIntKey || pIdxKey );
  5231   5231     for(;;){
  5232   5232       int lwr, upr, idx, c;
  5233   5233       Pgno chldPg;
  5234   5234       MemPage *pPage = pCur->apPage[pCur->iPage];
  5235   5235       u8 *pCell;                          /* Pointer to current cell in pPage */
................................................................................
  8435   8435         }
  8436   8436       }else{
  8437   8437         rc = moveToRoot(pCur);
  8438   8438         if( bPreserve ){
  8439   8439           btreeReleaseAllCursorPages(pCur);
  8440   8440           pCur->eState = CURSOR_REQUIRESEEK;
  8441   8441         }
         8442  +      if( rc==SQLITE_EMPTY ) rc = SQLITE_OK;
  8442   8443       }
  8443   8444     }
  8444   8445     return rc;
  8445   8446   }
  8446   8447   
  8447   8448   /*
  8448   8449   ** Create a new BTree table.  Write into *piTable the page
................................................................................
  8899   8900   ** Otherwise, if an error is encountered (i.e. an IO error or database
  8900   8901   ** corruption) an SQLite error code is returned.
  8901   8902   */
  8902   8903   int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
  8903   8904     i64 nEntry = 0;                      /* Value to return in *pnEntry */
  8904   8905     int rc;                              /* Return code */
  8905   8906   
  8906         -  if( pCur->pgnoRoot==0 ){
         8907  +  rc = moveToRoot(pCur);
         8908  +  if( rc==SQLITE_EMPTY ){
  8907   8909       *pnEntry = 0;
  8908   8910       return SQLITE_OK;
  8909   8911     }
  8910         -  rc = moveToRoot(pCur);
  8911   8912   
  8912   8913     /* Unless an error occurs, the following loop runs one iteration for each
  8913   8914     ** page in the B-Tree structure (not including overflow pages). 
  8914   8915     */
  8915   8916     while( rc==SQLITE_OK ){
  8916   8917       int iIdx;                          /* Index of child node in parent */
  8917   8918       MemPage *pPage;                    /* Current page of the b-tree */

Changes to src/sqlite.h.in.

   428    428   #define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite3_interrupt()*/
   429    429   #define SQLITE_IOERR       10   /* Some kind of disk I/O error occurred */
   430    430   #define SQLITE_CORRUPT     11   /* The database disk image is malformed */
   431    431   #define SQLITE_NOTFOUND    12   /* Unknown opcode in sqlite3_file_control() */
   432    432   #define SQLITE_FULL        13   /* Insertion failed because database is full */
   433    433   #define SQLITE_CANTOPEN    14   /* Unable to open the database file */
   434    434   #define SQLITE_PROTOCOL    15   /* Database lock protocol error */
   435         -#define SQLITE_EMPTY       16   /* Not used */
          435  +#define SQLITE_EMPTY       16   /* Internal use only */
   436    436   #define SQLITE_SCHEMA      17   /* The database schema changed */
   437    437   #define SQLITE_TOOBIG      18   /* String or BLOB exceeds size limit */
   438    438   #define SQLITE_CONSTRAINT  19   /* Abort due to constraint violation */
   439    439   #define SQLITE_MISMATCH    20   /* Data type mismatch */
   440    440   #define SQLITE_MISUSE      21   /* Library used incorrectly */
   441    441   #define SQLITE_NOLFS       22   /* Uses OS features not supported on host */
   442    442   #define SQLITE_AUTH        23   /* Authorization denied */