]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Provide hints to the btree layer Next and Previous primitives to let them
authordrh <drh@noemail.net>
Thu, 31 Mar 2011 18:36:17 +0000 (18:36 +0000)
committerdrh <drh@noemail.net>
Thu, 31 Mar 2011 18:36:17 +0000 (18:36 +0000)
know if they can be no-ops if the underlying index is unique.

FossilOrigin-Name: a5aae1743a208e7792497dfebf3e8311140ae595

manifest
manifest.uuid
src/btree.c
src/sqliteInt.h
src/vdbe.c
src/where.c
tool/mkopts.tcl [changed mode: 0644->0755]

index 6054817eb32ba9b2903e395bde49894c5c439f7b..59380976d412b5a3135373fcaae028292a59c0c6 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,8 +1,5 @@
------BEGIN PGP SIGNED MESSAGE-----
-Hash: SHA1
-
-C Backport\sthe\s"x\sIS\sNULL"\squery\splanner\senhancement\sof\s[2353176811f]\sto\nthe\s3.7.2\sbranch.
-D 2011-03-17T01:53:00.823
+C Provide\shints\sto\sthe\sbtree\slayer\sNext\sand\sPrevious\sprimitives\sto\slet\sthem\s\nknow\sif\sthey\scan\sbe\sno-ops\sif\sthe\sunderlying\sindex\sis\sunique.
+D 2011-03-31T18:36:17.545
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -116,7 +113,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
 F src/backup.c 8ff0b7018df253c7f30d3f9702b0b16f19209d5c
 F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
 F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
-F src/btree.c 5047fb303cdf6806a42676a6f513c57e15b7d69b
+F src/btree.c c1d7d81da6a1572291560ef186090f37c0b62dd9
 F src/btree.h b4ba2fdf6b64c7c376bdfffa826af6b786b151d9
 F src/btreeInt.h 5b034ff54800046cc5870605d683ac1f9134bd99
 F src/build.c a3c83d34a7f1e56308175076f65d510ae52dd6dc
@@ -175,7 +172,7 @@ F src/select.c 7a673c43b49d5f05f76e9c5a8cafa02862cbb901
 F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
 F src/sqlite.h.in 2d72a6242df41c517e38eec8791abcf5484a36f1
 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
-F src/sqliteInt.h 39a0b4d6bd4f5daf75465a1d35c121f06cf85751
+F src/sqliteInt.h d6afefc8908e921304327144ae8c7422b44bfb0c
 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
 F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -221,7 +218,7 @@ F src/update.c 1521162d20c2994af1fdc8833e1a88dae09052c8
 F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
 F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
 F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f
-F src/vdbe.c 66c262a923915e596379b1d597178e04c5d719e4
+F src/vdbe.c 9fa023047cd97f9607726c5eb60e8855efa7c027
 F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
 F src/vdbeInt.h ffd68c4d4229227a5089bec53a1c635146177abc
 F src/vdbeapi.c d0f4407e465f261780ad725c1caece7d66a6aa35
@@ -233,7 +230,7 @@ F src/vtab.c 0e8e0cb30dffb078367e843e84e37ef99236c7e4
 F src/wal.c 5ac2119e23ee4424599d4275b66dc88d612a0543
 F src/wal.h 96669b645e27cd5a111ba59f0cae7743a207bc3c
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
-F src/where.c deee5203073e0f63d79fd104b15dbebb6083dc03
+F src/where.c 51e6657e2d585dfced4c195d6faefe4738d4f1f9
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
 F test/all.test 6745008c144bd2956d58864d21f7b304689c1cce
@@ -825,7 +822,7 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
 F tool/lemon.c fe890e2d8d2db1e3f57e2a22503dbb0f6843e517
 F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
 F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309
-F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
+F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x
 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
 F tool/mksqlite3c.tcl aff0d53f0e84cf919922c0d02e767bdf5eeafb90
 F tool/mksqlite3h.tcl eb100dce83f24b501b325b340f8b5eb8e5106b3b
@@ -850,14 +847,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 668b91dbff036c6b76a5611cc3ebe455d277ed59
-R 3deac5f89493711dcb01d153d7e3d240
+P 68daf20d019a0a84764d635a91eaa9faeeabbab4
+R 360abc8fb9d546a9c24f3a762ab15633
 U drh
-Z c3047dd905fb57f35c3045f1bdcf4daf
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.6 (GNU/Linux)
-
-iD8DBQFNgWmAoxKgR168RlERAkI3AJ46nXurlFqON8jJkpUsMsyM4a2EqwCeJzde
-XXyg86cVMugwqsg1J9KaC2s=
-=slbW
------END PGP SIGNATURE-----
+Z 7d66317f7caf97967841a7d087fe3ae8
index e04ff4770d08b6bba263a244666b6e00839824f3..56463fcf488ba4544bf513a0e78088a01bcc2228 100644 (file)
@@ -1 +1 @@
-68daf20d019a0a84764d635a91eaa9faeeabbab4
\ No newline at end of file
+a5aae1743a208e7792497dfebf3e8311140ae595
\ No newline at end of file
index 378a2183eb6a158cb2ae947885bddee4e944c379..3cbbdc5c91612331c276aab63d62d7d7eb731bb3 100644 (file)
@@ -4552,6 +4552,15 @@ int sqlite3BtreeEof(BtCursor *pCur){
 ** successful then set *pRes=0.  If the cursor
 ** was already pointing to the last entry in the database before
 ** this routine was called, then set *pRes=1.
+**
+** The calling function will set *pRes to 0 or 1.  The initial *pRes value
+** will be 1 if the cursor being stepped corresponds to an SQL index and
+** if this routine could have been skipped if that SQL index had been
+** a unique index.  Otherwise the caller will have set *pRes to zero.  
+** Zero is the common case. The btree implementation is free to use the
+** initial *pRes value as a hint to improve performance, but the current 
+** SQLite btree implementation does not. (Note that the comdb2 btree 
+** implementation does use this hint, however.)
 */
 int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
   int rc;
@@ -4559,11 +4568,12 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
   MemPage *pPage;
 
   assert( cursorHoldsMutex(pCur) );
+  assert( pRes!=0 );
+  assert( *pRes==0 || *pRes==1 );
   rc = restoreCursorPosition(pCur);
   if( rc!=SQLITE_OK ){
     return rc;
   }
-  assert( pRes!=0 );
   if( CURSOR_INVALID==pCur->eState ){
     *pRes = 1;
     return SQLITE_OK;
@@ -4621,12 +4631,23 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
 ** successful then set *pRes=0.  If the cursor
 ** was already pointing to the first entry in the database before
 ** this routine was called, then set *pRes=1.
+**
+** The calling function will set *pRes to 0 or 1.  The initial *pRes value
+** will be 1 if the cursor being stepped corresponds to an SQL index and
+** if this routine could have been skipped if that SQL index had been
+** a unique index.  Otherwise the caller will have set *pRes to zero.  
+** Zero is the common case. The btree implementation is free to use the
+** initial *pRes value as a hint to improve performance, but the current 
+** SQLite btree implementation does not. (Note that the comdb2 btree 
+** implementation does use this hint, however.)
 */
 int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
   int rc;
   MemPage *pPage;
 
   assert( cursorHoldsMutex(pCur) );
+  assert( pRes!=0 );
+  assert( *pRes==0 || *pRes==1 );
   rc = restoreCursorPosition(pCur);
   if( rc!=SQLITE_OK ){
     return rc;
@@ -6778,7 +6799,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
   ** sub-tree headed by the child page of the cell being deleted. This makes
   ** balancing the tree following the delete operation easier.  */
   if( !pPage->leaf ){
-    int notUsed;
+    int notUsed = 0;
     rc = sqlite3BtreePrevious(pCur, &notUsed);
     if( rc ) return rc;
   }
index e2880d230b1969671e9000faaa18d0e1fdad0c02..191be0016107069a53928d2106aa3348602dd89d 100644 (file)
@@ -1865,8 +1865,8 @@ struct WhereLevel {
   int addrCont;         /* Jump here to continue with the next loop cycle */
   int addrFirst;        /* First instruction of interior of the loop */
   u8 iFrom;             /* Which entry in the FROM clause */
-  u8 op, p5;            /* Opcode and P5 of the opcode that ends the loop */
-  int p1, p2;           /* Operands of the opcode used to ends the loop */
+  u8 op, p3, p5;        /* Opcode, P3, and P5 of the end-of-loop instruction */
+  int p1, p2;           /* P1 and P2 operands of the end-of-loop instruction */
   union {               /* Information that depends on plan.wsFlags */
     struct {
       int nIn;              /* Number of entries in aInLoop[] */
index 1e7fc1675289b752f9eb40ce899457bce4fe1f62..38ff7fbcafee26c7606f3737a9547aa325c17229 100644 (file)
@@ -3313,6 +3313,7 @@ case OP_SeekGt: {       /* jump, in3 */
 #endif
     if( oc>=OP_SeekGe ){  assert( oc==OP_SeekGe || oc==OP_SeekGt );
       if( res<0 || (res==0 && oc==OP_SeekGt) ){
+        res = 0;
         rc = sqlite3BtreeNext(pC->pCursor, &res);
         if( rc!=SQLITE_OK ) goto abort_due_to_error;
         pC->rowidIsValid = 0;
@@ -3322,6 +3323,7 @@ case OP_SeekGt: {       /* jump, in3 */
     }else{
       assert( oc==OP_SeekLt || oc==OP_SeekLe );
       if( res>0 || (res==0 && oc==OP_SeekLt) ){
+        res = 0;
         rc = sqlite3BtreePrevious(pC->pCursor, &res);
         if( rc!=SQLITE_OK ) goto abort_due_to_error;
         pC->rowidIsValid = 0;
@@ -4166,7 +4168,7 @@ case OP_Rewind: {        /* jump */
   break;
 }
 
-/* Opcode: Next P1 P2 * * P5
+/* Opcode: Next P1 P2 P3 * 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
@@ -4178,9 +4180,14 @@ case OP_Rewind: {        /* jump */
 ** If P5 is positive and the jump is taken, then event counter
 ** number P5-1 in the prepared statement is incremented.
 **
+** The P3 value is a hint to the btree implementation. If P3==1, that
+** means P1 is an SQL index and that this instruction could have been
+** omitted if that index had been unique.  P3 is usually 0.  P3 is 
+** always either 0 or 1.
+**
 ** See also: Prev
 */
-/* Opcode: Prev P1 P2 * * P5
+/* Opcode: Prev P1 P2 P3 * P5
 **
 ** Back up cursor P1 so that it points to the previous key/data pair in its
 ** table or index.  If there is no previous key/value pairs then fall through
@@ -4191,6 +4198,11 @@ case OP_Rewind: {        /* jump */
 **
 ** If P5 is positive and the jump is taken, then event counter
 ** number P5-1 in the prepared statement is incremented.
+**
+** The P3 value is a hint to the btree implementation. If P3==1, that
+** means P1 is an SQL index and that this instruction could have been
+** omitted if that index had been unique.  P3 is usually 0.  P3 is 
+** always either 0 or 1.
 */
 case OP_Prev:          /* jump */
 case OP_Next: {        /* jump */
@@ -4201,6 +4213,7 @@ case OP_Next: {        /* jump */
   CHECK_FOR_INTERRUPT;
   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
   assert( pOp->p5<=ArraySize(p->aCounter) );
+  assert( pOp->p3==0 || pOp->p3==1 );
   pC = p->apCsr[pOp->p1];
   if( pC==0 ){
     break;  /* See ticket #2273 */
@@ -4210,7 +4223,10 @@ case OP_Next: {        /* jump */
     pC->nullRow = 1;
     break;
   }
-  res = 1;
+  res = pOp->p3;
+  assert( res==0 || pC->isIndex==1 );
+  testcase( res==1 );
+  testcase( res==0 );
   assert( pC->deferredMoveto==0 );
   rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
                               sqlite3BtreePrevious(pCrsr, &res);
index 4f69258a2d4627184755b3c24bb96ef4bb517f35..83b9ed3595469583aa063390729feb08b22eb522 100644 (file)
@@ -253,6 +253,7 @@ struct WhereCost {
 #define WHERE_VIRTUALTABLE 0x08000000  /* Use virtual-table processing */
 #define WHERE_MULTI_OR     0x10000000  /* OR using multiple indices */
 #define WHERE_TEMP_INDEX   0x20000000  /* Uses an ephemeral index */
+#define WHERE_UNQ_WANTED   0x40000000  /* True if UNIQUE would be helpful */
 
 /*
 ** Initialize a preallocated WhereClause structure.
@@ -2878,11 +2879,11 @@ static void bestBtreeIndex(
         }
         wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE);
       }
-    }else if( pProbe->onError!=OE_None ){
+    }else{
       testcase( wsFlags & WHERE_COLUMN_IN );
       testcase( wsFlags & WHERE_COLUMN_NULL );
       if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
-        wsFlags |= WHERE_UNIQUE;
+        wsFlags |= (pProbe->onError!=OE_None) ? WHERE_UNIQUE : WHERE_UNQ_WANTED;
       }
     }
 
@@ -4016,6 +4017,8 @@ static Bitmask codeOneLoopStart(
       pLevel->op = OP_Next;
     }
     pLevel->p1 = iIdxCur;
+    assert( (WHERE_UNQ_WANTED>>30)==1 );
+    pLevel->p3 = (pLevel->plan.wsFlags>>30)&1;
   }else
 
 #ifndef SQLITE_OMIT_OR_OPTIMIZATION
@@ -4878,7 +4881,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
     pLevel = &pWInfo->a[i];
     sqlite3VdbeResolveLabel(v, pLevel->addrCont);
     if( pLevel->op!=OP_Noop ){
-      sqlite3VdbeAddOp2(v, pLevel->op, pLevel->p1, pLevel->p2);
+      sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
       sqlite3VdbeChangeP5(v, pLevel->p5);
     }
     if( pLevel->plan.wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
old mode 100644 (file)
new mode 100755 (executable)