aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/vdbe.c48
-rw-r--r--src/vdbeInt.h2
-rw-r--r--src/wherecode.c12
3 files changed, 39 insertions, 23 deletions
diff --git a/src/vdbe.c b/src/vdbe.c
index bc5addaba..a579b4ea1 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -4383,22 +4383,31 @@ seek_not_found:
break;
}
-/* Opcode: SeekHit P1 P2 * * *
-** Synopsis: seekHit=P2
+/* Opcode: SeekHit P1 P2 P3 * *
+** Synopsis: set P2<=seekHit<=P3
**
-** Set the seekHit flag on cursor P1 to the value in P2.
-** The seekHit flag is used by the IfNoHope opcode.
+** Increase or decrease the seekHit value for cursor P1, if necessary,
+** so that it is no less than P2 and no greater than P3.
**
-** P1 must be a valid b-tree cursor. P2 must be a boolean value,
-** either 0 or 1.
+** The seekHit integer represents the maximum of terms in an index for which
+** there is known to be at least one match. If the seekHit value is smaller
+** than the total number of equality terms in an index lookup, then the
+** OP_IfNoHope opcode might run to see if the IN loop can be abandoned
+** early, thus saving work. This is part of the IN-early-out optimization.
+**
+** P1 must be a valid b-tree cursor.
*/
case OP_SeekHit: {
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pOp->p2==0 || pOp->p2==1 );
- pC->seekHit = pOp->p2 & 1;
+ assert( pOp->p3>=pOp->p2 );
+ if( pC->seekHit<pOp->p2 ){
+ pC->seekHit = pOp->p2;
+ }else if( pC->seekHit>pOp->p3 ){
+ pC->seekHit = pOp->p3;
+ }
break;
}
@@ -4456,16 +4465,20 @@ case OP_IfNotOpen: { /* jump */
** Synopsis: key=r[P3@P4]
**
** Register P3 is the first of P4 registers that form an unpacked
-** record.
+** record. Cursor P1 is an index btree. P2 is a jump destination.
+** In other words, the operands to this opcode are the same as the
+** operands to OP_NotFound and OP_IdxGT.
**
-** Cursor P1 is on an index btree. If the seekHit flag is set on P1, then
-** this opcode is a no-op. But if the seekHit flag of P1 is clear, then
-** check to see if there is any entry in P1 that matches the
-** prefix identified by P3 and P4. If no entry matches the prefix,
-** jump to P2. Otherwise fall through.
+** This opcode is an optimization attempt only. If this opcode always
+** falls through, the correct answer is still obtained, but extra works
+** is performed.
**
-** This opcode behaves like OP_NotFound if the seekHit
-** flag is clear and it behaves like OP_Noop if the seekHit flag is set.
+** A value of N in the seekHit flag of cursor P1 means that there exists
+** a key P3:N that will match some record in the index. We want to know
+** if it is possible for a record P3:P4 to match some record in the
+** index. If it is not possible, we can skips some work. So if seekHit
+** is less than P4, attempt to find out if a match is possible by running
+** OP_NotFound.
**
** This opcode is used in IN clause processing for a multi-column key.
** If an IN clause is attached to an element of the key other than the
@@ -4507,7 +4520,7 @@ case OP_IfNoHope: { /* jump, in3 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- if( pC->seekHit ) break;
+ if( pC->seekHit>=pOp->p4.i ) break;
/* Fall through into OP_NotFound */
/* no break */ deliberate_fall_through
}
@@ -4589,6 +4602,7 @@ case OP_Found: { /* jump, in3 */
}else{
VdbeBranchTaken(takeJump||alreadyExists==0,2);
if( takeJump || !alreadyExists ) goto jump_to_p2;
+ if( pOp->opcode==OP_IfNoHope ) pC->seekHit = pOp->p4.i;
}
break;
}
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 901569742..7d22cb809 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -86,7 +86,7 @@ struct VdbeCursor {
Bool isEphemeral:1; /* True for an ephemeral table */
Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
- Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */
+ u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
Btree *pBtx; /* Separate file holding temporary table */
i64 seqCount; /* Sequence counter */
u32 *aAltMap; /* Mapping from table to index column numbers */
diff --git a/src/wherecode.c b/src/wherecode.c
index 145b6fa5f..591f267e8 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -570,6 +570,9 @@ static int codeEqualityTerm(
if( pLevel->u.in.nIn==0 ){
pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse);
}
+ if( iEq>0 ){
+ pLoop->wsFlags |= WHERE_IN_EARLYOUT;
+ }
i = pLevel->u.in.nIn;
pLevel->u.in.nIn += nEq;
@@ -596,7 +599,6 @@ static int codeEqualityTerm(
if( iEq>0 ){
pIn->iBase = iReg - i;
pIn->nPrefix = i;
- pLoop->wsFlags |= WHERE_IN_EARLYOUT;
}else{
pIn->nPrefix = 0;
}
@@ -606,6 +608,9 @@ static int codeEqualityTerm(
pIn++;
}
}
+ if( iEq>0 ){
+ sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq);
+ }
}else{
pLevel->u.in.nIn = 0;
}
@@ -1789,9 +1794,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** above has already left the cursor sitting on the correct row,
** so no further seeking is needed */
}else{
- if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
- sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur);
- }
if( regBignull ){
sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull);
VdbeComment((v, "NULL-scan pass ctr"));
@@ -1902,7 +1904,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
}
if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
- sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 1);
+ sqlite3VdbeAddOp3(v, OP_SeekHit, iIdxCur, nEq, nEq);
}
/* Seek the table cursor, if required */