From: drh Date: Sat, 30 Jan 2016 16:59:56 +0000 (+0000) Subject: Merge the implementation of OP_IdxRowid and OP_Seek so that OP_Seek no longer X-Git-Tag: version-3.11.0~76 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=784c1b93fbf5f206878d9fec62dd3d418b0e678d;p=thirdparty%2Fsqlite.git 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 --- diff --git a/manifest b/manifest index df7711094d..d850d9282e 100644 --- a/manifest +++ b/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 diff --git a/manifest.uuid b/manifest.uuid index f4551f775a..01040f34b0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1f4c667f37d63fc3ef2e8f2581ecd3a66c054426 \ No newline at end of file +9bec50a1e7796a6e038db9b1cc7cc1e7e350bf74 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index c6ae836a28..a1e59e1170 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->p1nCursor ); - 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->p1nCursor ); 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->p3nCursor ); + 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 d590203155..3fbd198e31 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);