aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2015-11-05 20:25:09 +0000
committerdrh <drh@noemail.net>2015-11-05 20:25:09 +0000
commit70528d7868e67752833c6bac7b34f4d5d652d130 (patch)
tree372b20b32551bbbe108cd161a8e2d93bcd8beea5 /src
parentd82211db56f53b2ddf0e62904f3c691d24bd2afb (diff)
downloadsqlite-70528d7868e67752833c6bac7b34f4d5d652d130.tar.gz
sqlite-70528d7868e67752833c6bac7b34f4d5d652d130.zip
The top of an index equality loop normally starts with OP_SeekGE and OP_IdxGT.
This check-in adds a flag to OP_SeekGE such that it fails immediately if the key is not equal, then jumps over the OP_IdxGT, saving a call to the key comparison functions. Consider this check-in a proof-of-concept. It needs improvement before going on trunk. Some tests fail, but only because they new use fewer key comparisons than expected (which is a good thing!). FossilOrigin-Name: 32e31b9bc8664afcd326a1ff3892d86dc5202474
Diffstat (limited to 'src')
-rw-r--r--src/sqliteInt.h7
-rw-r--r--src/vdbe.c7
-rw-r--r--src/vdbeaux.c3
-rw-r--r--src/wherecode.c9
4 files changed, 23 insertions, 3 deletions
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 96f43070c..b86de1b2b 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1830,12 +1830,13 @@ struct KeyInfo {
*/
struct UnpackedRecord {
KeyInfo *pKeyInfo; /* Collation and sort-order information */
+ Mem *aMem; /* Values */
u16 nField; /* Number of entries in apMem[] */
i8 default_rc; /* Comparison result if keys are equal */
u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
- Mem *aMem; /* Values */
- int r1; /* Value to return if (lhs > rhs) */
- int r2; /* Value to return if (rhs < lhs) */
+ i8 r1; /* Value to return if (lhs > rhs) */
+ i8 r2; /* Value to return if (rhs < lhs) */
+ u8 eqSeen; /* True if an equality comparison has been seen */
};
diff --git a/src/vdbe.c b/src/vdbe.c
index c5508a2b2..6a4729a69 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -3691,11 +3691,13 @@ case OP_SeekGT: { /* jump, in3 */
#ifdef SQLITE_DEBUG
if( sqlite3BtreeCursorHasHint(pC->pCursor, BTREE_SEEK_EQ) ){
assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
+#if 0
assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
assert( pOp[1].p1==pOp[0].p1 );
assert( pOp[1].p2==pOp[0].p2 );
assert( pOp[1].p3==pOp[0].p3 );
assert( pOp[1].p4.i==pOp[0].p4.i );
+#endif
}
#endif
@@ -3772,10 +3774,14 @@ case OP_SeekGT: { /* jump, in3 */
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
#endif
ExpandBlob(r.aMem);
+ r.eqSeen = 0;
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
+ if( (pOp->p5 & OPFLAG_SEEKEQ)!=0 && r.eqSeen==0 ){
+ goto take_the_jump;
+ }
}
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
@@ -3803,6 +3809,7 @@ case OP_SeekGT: { /* jump, in3 */
res = sqlite3BtreeEof(pC->pCursor);
}
}
+take_the_jump:
assert( pOp->p2>0 );
VdbeBranchTaken(res!=0,2);
if( res ){
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index f605ea3ec..8e53ef7de 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -3969,6 +3969,7 @@ int sqlite3VdbeRecordCompareWithSkip(
|| vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc)
|| pKeyInfo->db->mallocFailed
);
+ pPKey2->eqSeen = 1;
return pPKey2->default_rc;
}
int sqlite3VdbeRecordCompare(
@@ -4068,6 +4069,7 @@ static int vdbeRecordCompareInt(
/* The first fields of the two keys are equal and there are no trailing
** fields. Return pPKey2->default_rc in this case. */
res = pPKey2->default_rc;
+ pPKey2->eqSeen = 1;
}
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) );
@@ -4114,6 +4116,7 @@ static int vdbeRecordCompareString(
res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
}else{
res = pPKey2->default_rc;
+ pPKey2->eqSeen = 1;
}
}else if( res>0 ){
res = pPKey2->r2;
diff --git a/src/wherecode.c b/src/wherecode.c
index 87db0e0a2..644c1aa0a 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -1026,6 +1026,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */
int startEq; /* True if range start uses ==, >= or <= */
int endEq; /* True if range end uses ==, >= or <= */
+ int eqOnly; /* True if uses only == */
int start_constraints; /* Start of range is constrained */
int nConstraint; /* Number of constraint terms */
Index *pIdx; /* The index we will be using */
@@ -1095,6 +1096,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
}
}
assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
+ eqOnly = nEq>0 && (pLoop->wsFlags & WHERE_COLUMN_RANGE)==0
+ && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0;
/* If we are doing a reverse order scan on an ascending index, or
** a forward order scan on a descending index, interchange the
@@ -1167,6 +1170,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT );
+ if( eqOnly ) sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ);
/* Load the value for the inequality constraint at the end of the
** range (if any).
@@ -1202,6 +1206,11 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* Check if the index cursor is past the end of the range. */
if( nConstraint ){
+ if( eqOnly ){
+ int bx = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, bx+2);
+ pLevel->p2 = bx+1;
+ }
op = aEndOp[bRev*2 + endEq];
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );