aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c18
-rw-r--r--src/fkey.c2
-rw-r--r--src/pragma.c2
-rw-r--r--src/select.c4
-rw-r--r--src/vdbe.c61
-rw-r--r--src/vdbe.h1
-rw-r--r--src/vdbeaux.c16
-rw-r--r--src/where.c14
8 files changed, 73 insertions, 45 deletions
diff --git a/src/expr.c b/src/expr.c
index 8ff43381b..a50348f2d 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1546,7 +1546,7 @@ int sqlite3CodeSubselect(
affinity = sqlite3ExprAffinity(pLeft);
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
- ** expression it is handled the same way. A virtual table is
+ ** expression it is handled the same way. An ephemeral table is
** filled with single-field index keys representing the results
** from the SELECT or the <exprlist>.
**
@@ -1754,12 +1754,7 @@ static void sqlite3ExprCodeIN(
}else{
/* In this case, the RHS is an index b-tree.
*/
- int r2; /* Register holding LHS value as a Record */
-
- /* Create a record that can be used for membership testing.
- */
- r2 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1);
+ sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1);
/* If the set membership test fails, then the result of the
** "x IN (...)" expression must be either 0 or NULL. If the set
@@ -1775,21 +1770,20 @@ static void sqlite3ExprCodeIN(
** Also run this branch if NULL is equivalent to FALSE
** for this particular IN operator.
*/
- sqlite3VdbeAddOp3(v, OP_NotFound, pExpr->iTable, destIfFalse, r2);
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1);
}else{
/* In this branch, the RHS of the IN might contain a NULL and
** the presence of a NULL on the RHS makes a difference in the
** outcome.
*/
- static const char nullRecord[] = { 0x02, 0x00 };
int j1, j2, j3;
/* First check to see if the LHS is contained in the RHS. If so,
** then the presence of NULLs in the RHS does not matter, so jump
** over all of the code that follows.
*/
- j1 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r2);
+ j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
/* Here we begin generating code that runs if the LHS is not
** contained within the RHS. Generate additional code that
@@ -1798,8 +1792,7 @@ static void sqlite3ExprCodeIN(
** jump to destIfFalse.
*/
j2 = sqlite3VdbeAddOp1(v, OP_NotNull, rRhsHasNull);
- sqlite3VdbeAddOp4(v, OP_Blob, 2, r2, 0, nullRecord, P4_STATIC);
- j3 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r2);
+ j3 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1);
sqlite3VdbeAddOp2(v, OP_Integer, -1, rRhsHasNull);
sqlite3VdbeJumpHere(v, j3);
sqlite3VdbeAddOp2(v, OP_AddImm, rRhsHasNull, 1);
@@ -1816,7 +1809,6 @@ static void sqlite3ExprCodeIN(
*/
sqlite3VdbeJumpHere(v, j1);
}
- sqlite3ReleaseTempReg(pParse, r2);
}
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ExprCachePop(pParse, 1);
diff --git a/src/fkey.c b/src/fkey.c
index df0a5b466..e6f4bfc05 100644
--- a/src/fkey.c
+++ b/src/fkey.c
@@ -399,7 +399,7 @@ static void fkLookupParent(
sqlite3VdbeAddOp3(v, OP_MakeRecord, regTemp, nCol, regRec);
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0);
- sqlite3VdbeAddOp3(v, OP_Found, iCur, iOk, regRec);
+ sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0);
sqlite3ReleaseTempReg(pParse, regRec);
sqlite3ReleaseTempRange(pParse, regTemp, nCol);
diff --git a/src/pragma.c b/src/pragma.c
index fb6d37219..69dea4edb 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -1142,7 +1142,7 @@ void sqlite3Pragma(
{ OP_Halt, 0, 0, 0},
};
sqlite3GenerateIndexKey(pParse, pIdx, 1, 3, 1);
- jmp2 = sqlite3VdbeAddOp3(v, OP_Found, j+2, 0, 3);
+ jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, j+2, 0, 3, 0);
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC);
sqlite3VdbeChangeP4(v, addr+3, " missing from index ", P4_STATIC);
diff --git a/src/select.c b/src/select.c
index be504603a..80a04f40e 100644
--- a/src/select.c
+++ b/src/select.c
@@ -440,7 +440,7 @@ static void codeDistinct(
v = pParse->pVdbe;
r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
- sqlite3VdbeAddOp3(v, OP_Found, iTab, addrRepeat, r1);
+ sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, r1, 0);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
sqlite3ReleaseTempReg(pParse, r1);
}
@@ -1670,7 +1670,7 @@ static int multiSelect(
sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak);
r1 = sqlite3GetTempReg(pParse);
iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1);
- sqlite3VdbeAddOp3(v, OP_NotFound, tab2, iCont, r1);
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0);
sqlite3ReleaseTempReg(pParse, r1);
selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
0, -1, &dest, iCont, iBreak);
diff --git a/src/vdbe.c b/src/vdbe.c
index 758e07973..a13a7e62a 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -3354,19 +3354,27 @@ case OP_Seek: { /* in2 */
}
-/* Opcode: Found P1 P2 P3 * *
+/* Opcode: Found P1 P2 P3 P4 *
**
-** Register P3 holds a blob constructed by MakeRecord. P1 is an index.
-** If P3 is a prefix of any entry in P1 then a jump is made to P2 and
+** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
+** P4>0 then register P3 is the first of P4 registers that form an unpacked
+** record.
+**
+** Cursor P1 is on an index btree. If the record identified by P3 and P4
+** is a prefix of any entry in P1 then a jump is made to P2 and
** P1 is left pointing at the matching entry.
*/
-/* Opcode: NotFound P1 P2 P3 * *
+/* Opcode: NotFound P1 P2 P3 P4 *
**
-** Register P3 holds a blob constructed by MakeRecord. P1 is
-** an index. If P3 is not the prefix of any entry in P1 then a jump
-** is made to P2. If P1 does contain an entry whose prefix matches
-** P3 then control falls through to the next instruction and P1 is
-** left pointing at the matching entry.
+** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
+** P4>0 then register P3 is the first of P4 registers that form an unpacked
+** record.
+**
+** Cursor P1 is on an index btree. If the record identified by P3 and P4
+** is not the prefix of any entry in P1 then a jump is made to P2. If P1
+** does contain an entry whose prefix matches the P3/P4 record then control
+** falls through to the next instruction and P1 is left pointing at the
+** matching entry.
**
** See also: Found, NotExists, IsUnique
*/
@@ -3376,6 +3384,7 @@ case OP_Found: { /* jump, in3 */
VdbeCursor *pC;
int res;
UnpackedRecord *pIdxKey;
+ UnpackedRecord r;
char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
#ifdef SQLITE_TEST
@@ -3384,21 +3393,32 @@ case OP_Found: { /* jump, in3 */
alreadyExists = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ assert( pOp->p4type==P4_INT32 );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
if( ALWAYS(pC->pCursor!=0) ){
assert( pC->isTable==0 );
- assert( pIn3->flags & MEM_Blob );
- ExpandBlob(pIn3);
- pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z,
- aTempRec, sizeof(aTempRec));
- if( pIdxKey==0 ){
- goto no_mem;
+ if( pOp->p4.i>0 ){
+ r.pKeyInfo = pC->pKeyInfo;
+ r.nField = pOp->p4.i;
+ r.aMem = pIn3;
+ r.flags = UNPACKED_PREFIX_MATCH;
+ pIdxKey = &r;
+ }else{
+ assert( pIn3->flags & MEM_Blob );
+ ExpandBlob(pIn3);
+ pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z,
+ aTempRec, sizeof(aTempRec));
+ if( pIdxKey==0 ){
+ goto no_mem;
+ }
+ pIdxKey->flags |= UNPACKED_PREFIX_MATCH;
}
- pIdxKey->flags |= UNPACKED_PREFIX_MATCH;
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
- sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
+ if( pOp->p4.i==0 ){
+ sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
+ }
if( rc!=SQLITE_OK ){
break;
}
@@ -3416,9 +3436,10 @@ case OP_Found: { /* jump, in3 */
/* Opcode: IsUnique P1 P2 P3 P4 *
**
-** Cursor P1 is open on an index. So it has no data and its key consists
-** of a record generated by OP_MakeRecord where the last field is the
-** rowid of the entry that the index refers to.
+** Cursor P1 is open on an index b-tree - that is to say, a btree which
+** no data and where the key are records generated by OP_MakeRecord with
+** the list field being the integer ROWID of the entry that the index
+** entry refers to.
**
** The P3 register contains an integer record number. Call this record
** number R. Register P4 is the first in a set of N contiguous registers
diff --git a/src/vdbe.h b/src/vdbe.h
index 7caf90442..fbe62d772 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -170,6 +170,7 @@ int sqlite3VdbeAddOp1(Vdbe*,int,int);
int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
+int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index a3905da17..16499ce12 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -196,6 +196,22 @@ int sqlite3VdbeAddOp4(
}
/*
+** Add an opcode that includes the p4 value as an integer.
+*/
+int sqlite3VdbeAddOp4Int(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ int p4 /* The P4 operand as an integer */
+){
+ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+ sqlite3VdbeChangeP4(p, addr, SQLITE_INT_TO_PTR(p4), P4_INT32);
+ return addr;
+}
+
+/*
** Create a new symbolic label for an instruction that has yet to be
** coded. The symbolic label is really just a negative number. The
** label can be used as the P2 value of an operation. Later, when
diff --git a/src/where.c b/src/where.c
index 135ff8002..90df4c495 100644
--- a/src/where.c
+++ b/src/where.c
@@ -3119,8 +3119,7 @@ static Bitmask codeOneLoopStart(
testcase( op==OP_SeekGe );
testcase( op==OP_SeekLe );
testcase( op==OP_SeekLt );
- sqlite3VdbeAddOp4(v, op, iIdxCur, addrNxt, regBase,
- SQLITE_INT_TO_PTR(nConstraint), P4_INT32);
+ sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
/* Load the value for the inequality constraint at the end of the
** range (if any).
@@ -3153,8 +3152,7 @@ static Bitmask codeOneLoopStart(
testcase( op==OP_IdxGE );
testcase( op==OP_IdxLT );
if( op!=OP_Noop ){
- sqlite3VdbeAddOp4(v, op, iIdxCur, addrNxt, regBase,
- SQLITE_INT_TO_PTR(nConstraint), P4_INT32);
+ sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
sqlite3VdbeChangeP5(v, endEq!=bRev ?1:0);
}
@@ -3283,9 +3281,8 @@ static Bitmask codeOneLoopStart(
int r;
r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur,
regRowid, 0);
- sqlite3VdbeAddOp4(v, OP_RowSetTest, regRowset,
- sqlite3VdbeCurrentAddr(v)+2,
- r, SQLITE_INT_TO_PTR(iSet), P4_INT32);
+ sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset,
+ sqlite3VdbeCurrentAddr(v)+2, r, iSet);
}
sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody);
@@ -3816,7 +3813,8 @@ WhereInfo *sqlite3WhereBegin(
Bitmask b = pTabItem->colUsed;
int n = 0;
for(; b; b=b>>1, n++){}
- sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1, SQLITE_INT_TO_PTR(n), P4_INT32);
+ sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1,
+ SQLITE_INT_TO_PTR(n), P4_INT32);
assert( n<=pTab->nCol );
}
}else{