From: drh Date: Thu, 31 Mar 2011 18:36:17 +0000 (+0000) Subject: Provide hints to the btree layer Next and Previous primitives to let them X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5bc564f0d3fe04abdeff6250493f883e89b928a0;p=thirdparty%2Fsqlite.git Provide hints to the btree layer Next and Previous primitives to let them know if they can be no-ops if the underlying index is unique. FossilOrigin-Name: a5aae1743a208e7792497dfebf3e8311140ae595 --- diff --git a/manifest b/manifest index 6054817eb3..59380976d4 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index e04ff4770d..56463fcf48 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -68daf20d019a0a84764d635a91eaa9faeeabbab4 \ No newline at end of file +a5aae1743a208e7792497dfebf3e8311140ae595 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 378a2183eb..3cbbdc5c91 100644 --- a/src/btree.c +++ b/src/btree.c @@ -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, ¬Used); if( rc ) return rc; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e2880d230b..191be00161 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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[] */ diff --git a/src/vdbe.c b/src/vdbe.c index 1e7fc16752..38ff7fbcaf 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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->p1nCursor ); 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); diff --git a/src/where.c b/src/where.c index 4f69258a2d..83b9ed3595 100644 --- a/src/where.c +++ b/src/where.c @@ -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 ){ diff --git a/tool/mkopts.tcl b/tool/mkopts.tcl old mode 100644 new mode 100755