mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
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
This commit is contained in:
103
src/vdbe.c
103
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 );
|
||||
|
||||
/* 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 happend for an IdxRowid
|
||||
** opcode, hence the NEVER() arround the check of the return value.
|
||||
*/
|
||||
rc = sqlite3VdbeCursorRestore(pC);
|
||||
** 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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user