mirror of https://github.com/sqlite/sqlite
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:
parent
b8d66dc4ec
commit
784c1b93fb
15
manifest
15
manifest
|
@ -1,5 +1,5 @@
|
|||
C Only\shonor\sthe\sregister\ssubtype\svalue\sif\sthe\sMEM_Subtype\sflag\sis\sset.\nRevised\sand\simproved\sfix\sfor\sticket\s[f45ac567eaa9f9].
|
||||
D 2016-01-30T15:52:39.136
|
||||
C Merge\sthe\simplementation\sof\sOP_IdxRowid\sand\sOP_Seek\sso\sthat\sOP_Seek\sno\slonger\nrequires\sthe\srowid\sregister\sand\sa\sseparate\sOP_IdxRowid\scall.\s\sShorter\sand\nfaster\sprepared\sstatements\sresult.
|
||||
D 2016-01-30T16:59:56.592
|
||||
F Makefile.in 027c1603f255390c43a426671055a31c0a65fdb4
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 72b7858f02017611c3ac1ddc965251017fed0845
|
||||
|
@ -412,7 +412,7 @@ F src/update.c 17332f9fe818cbc0444c36a811800af8498af4c3
|
|||
F src/utf.c 10cc2519e82e3369344d0969ad4b1a333dc86d18
|
||||
F src/util.c 72d40df0a52d3f30b462a15f0e094fcbade6dc82
|
||||
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
|
||||
F src/vdbe.c 49e0a224526f4307ab80e9d3a63697b28cf0cb21
|
||||
F src/vdbe.c 73f0f61eb5556e430487671a557d032ecac52240
|
||||
F src/vdbe.h 7a733ea8aac1b77305a67698e784fa3484ee3337
|
||||
F src/vdbeInt.h 4b69d5451bcadd473e745af53ef1e8abfdce0a79
|
||||
F src/vdbeapi.c 9d640d5efd9a140a6bda8da53b220aa258167993
|
||||
|
@ -428,7 +428,7 @@ F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
|
|||
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
|
||||
F src/where.c af9bf5dcec1a0e52726c550924aa91d837166251
|
||||
F src/whereInt.h 78b6b4de94db84aecbdc07fe3e38f648eb391e9a
|
||||
F src/wherecode.c ef0d7019029624625416cdf32cc86604c970416f
|
||||
F src/wherecode.c 7ea737b14e7a35d7f55cbad589a29aa49dfe3f7a
|
||||
F src/whereexpr.c 197a448b52073aee43eca3a2233fc113369eb2d4
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
|
@ -1422,8 +1422,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
|
|||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 96b780209cc95c3f3769bb880591380d94bfe38d 2e9fb1295cd31fc29c97444c3dec82fef68e939f
|
||||
R bd3d63263e82ae4209cc8f920c59f1ec
|
||||
T +closed 2e9fb1295cd31fc29c97444c3dec82fef68e939f
|
||||
P 1f4c667f37d63fc3ef2e8f2581ecd3a66c054426
|
||||
R c807c9436e91d8aabdffdea0ecd68c4e
|
||||
U drh
|
||||
Z 5703eae66c478a55119b68d54c8bb9ef
|
||||
Z a3f05d9c2a4721d817f24f533822e83f
|
||||
|
|
|
@ -1 +1 @@
|
|||
1f4c667f37d63fc3ef2e8f2581ecd3a66c054426
|
||||
9bec50a1e7796a6e038db9b1cc7cc1e7e350bf74
|
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue