aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2016-01-30 16:59:56 +0000
committerdrh <drh@noemail.net>2016-01-30 16:59:56 +0000
commit784c1b93fbf5f206878d9fec62dd3d418b0e678d (patch)
tree44fcac662d47f23f98d5c7620eac66335e842423 /src
parentb8d66dc4ec99cfd3d82afe5b6243a000d0d409cb (diff)
downloadsqlite-784c1b93fbf5f206878d9fec62dd3d418b0e678d.tar.gz
sqlite-784c1b93fbf5f206878d9fec62dd3d418b0e678d.zip
Merge the implementation of OP_IdxRowid and OP_Seek so that OP_Seek no longer
requires the rowid register and a separate OP_IdxRowid call. Shorter and faster prepared statements result. FossilOrigin-Name: 9bec50a1e7796a6e038db9b1cc7cc1e7e350bf74
Diffstat (limited to 'src')
-rw-r--r--src/vdbe.c103
-rw-r--r--src/wherecode.c11
2 files changed, 58 insertions, 56 deletions
diff --git a/src/vdbe.c b/src/vdbe.c
index c6ae836a2..a1e59e117 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -3857,42 +3857,6 @@ seek_not_found:
}
break;
}
-
-/* Opcode: Seek P1 P2 P3 P4 *
-** Synopsis: intkey=r[P2]
-**
-** P1 is an open table cursor and P2 is a rowid integer. Arrange
-** for P1 to move so that it points to the rowid given by P2.
-**
-** This is actually a deferred seek. Nothing actually happens until
-** the cursor is used to read a record. That way, if no reads
-** occur, no unnecessary I/O happens.
-**
-** P4 may contain an array of integers (type P4_INTARRAY) containing
-** one entry for each column in the table P1 is open on. If so, then
-** parameter P3 is a cursor open on a database index. If array entry
-** a[i] is non-zero, then reading column (a[i]-1) from cursor P3 is
-** equivalent to performing the deferred seek and then reading column i
-** from P1.
-*/
-case OP_Seek: { /* in2 */
- VdbeCursor *pC;
-
- assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- pC = p->apCsr[pOp->p1];
- assert( pC!=0 );
- assert( pC->eCurType==CURTYPE_BTREE );
- assert( pC->uc.pCursor!=0 );
- assert( pC->isTable );
- pC->nullRow = 0;
- pIn2 = &aMem[pOp->p2];
- pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
- pC->deferredMoveto = 1;
- assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
- pC->aAltMap = pOp->p4.ai;
- pC->pAltCursor = p->apCsr[pOp->p3];
- break;
-}
/* Opcode: Found P1 P2 P3 P4 *
@@ -4987,6 +4951,25 @@ case OP_IdxDelete: {
break;
}
+/* Opcode: Seek P1 * P3 P4 *
+** Synopsis: Move P3 to P1.rowid
+**
+** P1 is an open index cursor and P3 is a cursor on the corresponding
+** table. This opcode does a deferred seek of the P3 table cursor
+** to the row that corresponds to the current row of P1.
+**
+** This is a deferred seek. Nothing actually happens until
+** the cursor is used to read a record. That way, if no reads
+** occur, no unnecessary I/O happens.
+**
+** P4 may be an array of integers (type P4_INTARRAY) containing
+** one entry for each column in the P3 table. If array entry a[i]
+** is non-zero, then reading column (a[i]-1) from cursor P3 is
+** equivalent to performing the deferred seek and then reading column i
+** from P1. This information is stored in P3 and used to redirect
+** reads against P3 over to P1, thus possibly avoiding the need to
+** seek and read cursor P3.
+*/
/* Opcode: IdxRowid P1 P2 * * *
** Synopsis: r[P2]=rowid
**
@@ -4996,37 +4979,57 @@ case OP_IdxDelete: {
**
** See also: Rowid, MakeRecord.
*/
+case OP_Seek:
case OP_IdxRowid: { /* out2 */
- BtCursor *pCrsr;
- VdbeCursor *pC;
- i64 rowid;
+ VdbeCursor *pC; /* The P1 index cursor */
+ VdbeCursor *pTabCur; /* The P2 table cursor (OP_Seek only) */
+ i64 rowid; /* Rowid that P1 current points to */
- pOut = out2Prerelease(p, pOp);
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
- pCrsr = pC->uc.pCursor;
- assert( pCrsr!=0 );
- pOut->flags = MEM_Null;
+ assert( pC->uc.pCursor!=0 );
assert( pC->isTable==0 );
assert( pC->deferredMoveto==0 );
+ assert( !pC->nullRow || pOp->opcode==OP_IdxRowid );
- /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
- ** out from under the cursor. That will never happend for an IdxRowid
- ** opcode, hence the NEVER() arround the check of the return value.
- */
+ /* The IdxRowid and Seek opcodes are combined because of the commonality
+ ** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */
rc = sqlite3VdbeCursorRestore(pC);
+
+ /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
+ ** out from under the cursor. That will never happens for an IdxRowid
+ ** or Seek opcode */
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
if( !pC->nullRow ){
rowid = 0; /* Not needed. Only used to silence a warning. */
- rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid);
+ rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- pOut->u.i = rowid;
- pOut->flags = MEM_Int;
+ if( pOp->opcode==OP_Seek ){
+ assert( pOp->p3>=0 && pOp->p3<p->nCursor );
+ pTabCur = p->apCsr[pOp->p3];
+ assert( pTabCur!=0 );
+ assert( pTabCur->eCurType==CURTYPE_BTREE );
+ assert( pTabCur->uc.pCursor!=0 );
+ assert( pTabCur->isTable );
+ pTabCur->nullRow = 0;
+ pTabCur->movetoTarget = rowid;
+ pTabCur->deferredMoveto = 1;
+ assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
+ pTabCur->aAltMap = pOp->p4.ai;
+ pTabCur->pAltCursor = pC;
+ }else{
+ pOut = out2Prerelease(p, pOp);
+ pOut->u.i = rowid;
+ pOut->flags = MEM_Int;
+ }
+ }else{
+ assert( pOp->opcode==OP_IdxRowid );
+ sqlite3VdbeMemSetNull(&aMem[pOp->p2]);
}
break;
}
diff --git a/src/wherecode.c b/src/wherecode.c
index d59020315..3fbd198e3 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -768,7 +768,6 @@ static void codeDeferredSeek(
WhereInfo *pWInfo, /* Where clause context */
Index *pIdx, /* Index scan is using */
int iCur, /* Cursor for IPK b-tree */
- int iRowid, /* Register containing rowid to seek to */
int iIdxCur /* Index cursor */
){
Parse *pParse = pWInfo->pParse; /* Parse context */
@@ -777,7 +776,7 @@ static void codeDeferredSeek(
assert( iIdxCur>0 );
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
- sqlite3VdbeAddOp3(v, OP_Seek, iCur, iRowid, iIdxCur);
+ sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur);
if( (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)
&& sqlite3ParseToplevel(pParse)->writeMask==0
){
@@ -1274,14 +1273,14 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( omitTable ){
/* pIdx is a covering index. No need to access the main table. */
}else if( HasRowid(pIdx->pTable) ){
- iRowidReg = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
- sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
if( pWInfo->eOnePass!=ONEPASS_OFF ){
+ iRowidReg = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
+ sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
VdbeCoverage(v);
}else{
- codeDeferredSeek(pWInfo, pIdx, iCur, iRowidReg, iIdxCur);
+ codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur);
}
}else if( iCur!=iIdxCur ){
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);