]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Experimental changes to improve the performance of OP_Next.
authordan <dan@noemail.net>
Sat, 27 Aug 2011 18:48:57 +0000 (18:48 +0000)
committerdan <dan@noemail.net>
Sat, 27 Aug 2011 18:48:57 +0000 (18:48 +0000)
FossilOrigin-Name: 1a249845251199c00817893add300a1a654b4df9

manifest
manifest.uuid
src/btree.c
src/vdbe.c
src/vdbe.h
src/vdbeaux.c

index 530096adf2c16ba1417194eaed010f7587edb402..21e42fba5a823ab231e1f6e035aa7e11bf1202da 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sseveral\sharmless\scompiler\swarnings\sand\sa\sdocumentation\sbug.
-D 2011-08-26T20:55:50.529
+C Experimental\schanges\sto\simprove\sthe\sperformance\sof\sOP_Next.
+D 2011-08-27T18:48:57.573
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 8c930e7b493d59099ea1304bd0f2aed152eb3315
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -124,7 +124,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
 F src/backup.c 28a4fe55327ff708bfaf9d4326d02686f7a553c3
 F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
-F src/btree.c ed13fdefdbe671d5777773dcfb3a162ddb4623ae
+F src/btree.c bd89d604a532063da8ed1a095f1805db49896325
 F src/btree.h 9ddf04226eac592d4cc3709c5a8b33b2351ff5f7
 F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
 F src/build.c 2d5de52df616a3bf5a659cbca85211c46e2ba9bd
@@ -238,11 +238,11 @@ F src/update.c 74a6cfb34e9732c1e2a86278b229913b4b51eeec
 F src/utf.c c53eb7404b3eb5c1cbb5655c6a7a0e0ce6bd50f0
 F src/util.c 06302ffd2b80408d4f6c7af71f7090e0cf8d8ff7
 F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e
-F src/vdbe.c 4a7191c0f8e918b74e8c84cbdd77746d6b7e3bcf
-F src/vdbe.h 2bf6ec77d8b9980fc19da6e0b0a36d0dbf884ce4
+F src/vdbe.c d63854aef07d036987f768dae7ca5c852881ce28
+F src/vdbe.h c1eeedacab6bcf1e7c2cf8203ba9763a616f9a86
 F src/vdbeInt.h f9250326f264ca5f100acc19e9c07096bb889096
 F src/vdbeapi.c 11dc47987abacb76ad016dcf5abc0dc422482a98
-F src/vdbeaux.c 11b0df8822ecf61e543562247207df75e2ebb617
+F src/vdbeaux.c dd5d10ae523bbc6ed55ac73daa28a9ea1f2fa42a
 F src/vdbeblob.c f024f0bf420f36b070143c32b15cc7287341ffd3
 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
 F src/vdbesort.c 8a61a6d731cbe612217edf9eece6197f37c9489e
@@ -961,7 +961,10 @@ F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5
 F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings.sh b7fdb2cc525f5ef4fa43c80e771636dd3690f9d2
-P 1dada5158215d1816edb69ff2610f9d2259ce19d
-R 16e082a02686bfb3de55c1b850240992
-U drh
-Z 9f47e5dd82da8bb114d554ebcb62232c
+P 5454d0fe227b7c1f0e7715b6c08f97019628fc4c
+R 06eac31c16dc3f7f5b4649f86c063bf4
+T *branch * experimental
+T *sym-experimental *
+T -sym-trunk *
+U dan
+Z 50e65d7380a3dc463f2c091e8241574b
index 07a8c25fcae606cb7ce1ba78adf5230e127039e3..ae93ed9c60973e3b6c981465a8688730ba911a30 100644 (file)
@@ -1 +1 @@
-5454d0fe227b7c1f0e7715b6c08f97019628fc4c
\ No newline at end of file
+1a249845251199c00817893add300a1a654b4df9
\ No newline at end of file
index 0c5fa38e4a4fcf8ea733a2aef5e28134c07bc420..d77fce4c8e10162330347c35ca5be48f19c0aae2 100644 (file)
@@ -3479,7 +3479,8 @@ static int btreeCursor(
     return SQLITE_READONLY;
   }
   if( iTable==1 && btreePagecount(pBt)==0 ){
-    return SQLITE_EMPTY;
+    assert( wrFlag==0 );
+    iTable = 0;
   }
 
   /* Now that no other errors can occur, finish filling in the BtCursor
@@ -4233,6 +4234,9 @@ static int moveToRoot(BtCursor *pCur){
       releasePage(pCur->apPage[i]);
     }
     pCur->iPage = 0;
+  }else if( pCur->pgnoRoot==0 ){
+    pCur->eState = CURSOR_INVALID;
+    return SQLITE_OK;
   }else{
     rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]);
     if( rc!=SQLITE_OK ){
@@ -4342,7 +4346,7 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
   rc = moveToRoot(pCur);
   if( rc==SQLITE_OK ){
     if( pCur->eState==CURSOR_INVALID ){
-      assert( pCur->apPage[pCur->iPage]->nCell==0 );
+      assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
       *pRes = 1;
     }else{
       assert( pCur->apPage[pCur->iPage]->nCell>0 );
@@ -4381,7 +4385,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
   rc = moveToRoot(pCur);
   if( rc==SQLITE_OK ){
     if( CURSOR_INVALID==pCur->eState ){
-      assert( pCur->apPage[pCur->iPage]->nCell==0 );
+      assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
       *pRes = 1;
     }else{
       assert( pCur->eState==CURSOR_VALID );
@@ -4454,12 +4458,12 @@ int sqlite3BtreeMovetoUnpacked(
   if( rc ){
     return rc;
   }
-  assert( pCur->apPage[pCur->iPage] );
-  assert( pCur->apPage[pCur->iPage]->isInit );
-  assert( pCur->apPage[pCur->iPage]->nCell>0 || pCur->eState==CURSOR_INVALID );
+  assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] );
+  assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit );
+  assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 );
   if( pCur->eState==CURSOR_INVALID ){
     *pRes = -1;
-    assert( pCur->apPage[pCur->iPage]->nCell==0 );
+    assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
     return SQLITE_OK;
   }
   assert( pCur->apPage[0]->intKey || pIdxKey );
@@ -7376,6 +7380,11 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
 int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
   i64 nEntry = 0;                      /* Value to return in *pnEntry */
   int rc;                              /* Return code */
+
+  if( pCur->pgnoRoot==0 ){
+    *pnEntry = 0;
+    return SQLITE_OK;
+  }
   rc = moveToRoot(pCur);
 
   /* Unless an error occurs, the following loop runs one iteration for each
index 849130650711c026554343a6e62814e64a6a6630..133dc54b925893710a6b323e46b907241e8e6944 100644 (file)
@@ -2550,7 +2550,7 @@ case OP_Count: {         /* out2-prerelease */
   BtCursor *pCrsr;
 
   pCrsr = p->apCsr[pOp->p1]->pCursor;
-  if( pCrsr ){
+  if( ALWAYS(pCrsr) ){
     rc = sqlite3BtreeCount(pCrsr, &nEntry);
   }else{
     nEntry = 0;
@@ -3112,15 +3112,9 @@ case OP_OpenWrite: {
   rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
   pCur->pKeyInfo = pKeyInfo;
 
-  /* Since it performs no memory allocation or IO, the only values that
-  ** sqlite3BtreeCursor() may return are SQLITE_EMPTY and SQLITE_OK. 
-  ** SQLITE_EMPTY is only returned when attempting to open the table
-  ** rooted at page 1 of a zero-byte database.  */
-  assert( rc==SQLITE_EMPTY || rc==SQLITE_OK );
-  if( rc==SQLITE_EMPTY ){
-    pCur->pCursor = 0;
-    rc = SQLITE_OK;
-  }
+  /* Since it performs no memory allocation or IO, the only value that
+  ** sqlite3BtreeCursor() may return is SQLITE_OK. */
+  assert( rc==SQLITE_OK );
 
   /* Set the VdbeCursor.isTable and isIndex variables. Previous versions of
   ** SQLite used to check if the root-page flags were sane at this point
@@ -3333,7 +3327,7 @@ case OP_SeekGt: {       /* jump, in3 */
   assert( OP_SeekGe == OP_SeekLt+2 );
   assert( OP_SeekGt == OP_SeekLt+3 );
   assert( pC->isOrdered );
-  if( pC->pCursor!=0 ){
+  if( ALWAYS(pC->pCursor!=0) ){
     oc = pOp->opcode;
     pC->nullRow = 0;
     if( pC->isTable ){
@@ -3691,7 +3685,7 @@ case OP_NotExists: {        /* jump, in3 */
   assert( pC->isTable );
   assert( pC->pseudoTableReg==0 );
   pCrsr = pC->pCursor;
-  if( pCrsr!=0 ){
+  if( ALWAYS(pCrsr!=0) ){
     res = 0;
     iKey = pIn3->u.i;
     rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
@@ -4218,6 +4212,7 @@ case OP_NullRow: {
   assert( pC!=0 );
   pC->nullRow = 1;
   pC->rowidIsValid = 0;
+  assert( pC->pCursor || pC->pVtabCursor );
   if( pC->pCursor ){
     sqlite3BtreeClearCursor(pC->pCursor);
   }
@@ -4241,7 +4236,7 @@ case OP_Last: {        /* jump */
   pC = p->apCsr[pOp->p1];
   assert( pC!=0 );
   pCrsr = pC->pCursor;
-  if( pCrsr==0 ){
+  if( NEVER(pCrsr==0) ){
     res = 1;
   }else{
     rc = sqlite3BtreeLast(pCrsr, &res);
@@ -4296,7 +4291,9 @@ case OP_Rewind: {        /* jump */
   res = 1;
   if( isSorter(pC) ){
     rc = sqlite3VdbeSorterRewind(db, pC, &res);
-  }else if( (pCrsr = pC->pCursor)!=0 ){
+  }else{
+    pCrsr = pC->pCursor;
+    assert( pCrsr );
     rc = sqlite3BtreeFirst(pCrsr, &res);
     pC->atFirst = res==0 ?1:0;
     pC->deferredMoveto = 0;
@@ -4311,7 +4308,7 @@ case OP_Rewind: {        /* jump */
   break;
 }
 
-/* Opcode: Next P1 P2 * * P5
+/* Opcode: Next P1 P2 * P4 P5
 **
 ** Advance cursor P1 so that it points to the next key/data pair in its
 ** table or index.  If there are no more key/value pairs then fall through
@@ -4320,6 +4317,9 @@ case OP_Rewind: {        /* jump */
 **
 ** The P1 cursor must be for a real table, not a pseudo-table.
 **
+** P4 is always of type P4_ADVANCE. The function pointer points to
+** sqlite3BtreeNext().
+**
 ** If P5 is positive and the jump is taken, then event counter
 ** number P5-1 in the prepared statement is incremented.
 **
@@ -4334,13 +4334,15 @@ case OP_Rewind: {        /* jump */
 **
 ** The P1 cursor must be for a real table, not a pseudo-table.
 **
+** P4 is always of type P4_ADVANCE. The function pointer points to
+** sqlite3BtreePrevious().
+**
 ** If P5 is positive and the jump is taken, then event counter
 ** number P5-1 in the prepared statement is incremented.
 */
 case OP_Prev:          /* jump */
 case OP_Next: {        /* jump */
   VdbeCursor *pC;
-  BtCursor *pCrsr;
   int res;
 
   CHECK_FOR_INTERRUPT;
@@ -4354,15 +4356,12 @@ case OP_Next: {        /* jump */
     assert( pOp->opcode==OP_Next );
     rc = sqlite3VdbeSorterNext(db, pC, &res);
   }else{
-    pCrsr = pC->pCursor;
-    if( pCrsr==0 ){
-      pC->nullRow = 1;
-      break;
-    }
     res = 1;
     assert( pC->deferredMoveto==0 );
-    rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
-                                sqlite3BtreePrevious(pCrsr, &res);
+    assert( pC->pCursor );
+    assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
+    assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
+    rc = pOp->p4.xAdvance(pC->pCursor, &res);
   }
   pC->nullRow = (u8)res;
   pC->cacheStatus = CACHE_STALE;
index fe758d2dbdd06cde562d35c3b9ba68ede5b87d52..9728548517f2d8160766e776db9adf59a59f93f3 100644 (file)
@@ -61,6 +61,7 @@ struct VdbeOp {
     KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */
     int *ai;               /* Used when p4type is P4_INTARRAY */
     SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */
+    int (*xAdvance)(BtCursor *, int *);
   } p4;
 #ifdef SQLITE_DEBUG
   char *zComment;          /* Comment to improve readability */
@@ -116,6 +117,7 @@ typedef struct VdbeOpList VdbeOpList;
 #define P4_INT32    (-14) /* P4 is a 32-bit signed integer */
 #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
 #define P4_SUBPROGRAM  (-18) /* P4 is a pointer to a SubProgram structure */
+#define P4_ADVANCE  (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
 
 /* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure
 ** is made.  That copy is freed when the Vdbe is finalized.  But if the
index ffbb95ecac0c59697060570b748fc5329b16063d..a1e6a276f38ad7b035768a1e22100f5bee8332a8 100644 (file)
@@ -433,6 +433,12 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
       n = pOp[-1].p1;
       if( n>nMaxArgs ) nMaxArgs = n;
 #endif
+    }else if( opcode==OP_Next ){
+      pOp->p4.xAdvance = sqlite3BtreeNext;
+      pOp->p4type = P4_ADVANCE;
+    }else if( opcode==OP_Prev ){
+      pOp->p4.xAdvance = sqlite3BtreePrevious;
+      pOp->p4type = P4_ADVANCE;
     }
 
     if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){