Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b18a90d8d | |||
| 544d3b7805 | |||
| 44e9325644 |
@@ -1,5 +1,5 @@
|
||||
C Improved\scomment\son\sthe\scodeDeferredSeek()\sroutine.\sNo\scode\schanges.
|
||||
D 2022-02-25T13:29:56.636
|
||||
C Attempt\sto\stransform\sOP_Column\sto\smake\suse\sof\seCurState\sinstead\sof\sthe\sother\nmiscellaneous\sflags.
|
||||
D 2022-02-25T18:15:09.709
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -624,11 +624,11 @@ F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23
|
||||
F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3
|
||||
F src/vdbe.c 5ff8a23c52b38a25f5b8ae398c0a787aff6fdf49e60e675915614022862a4a0a
|
||||
F src/vdbe.c 7778e0f54e7ffe99edf44133e346915cb1ababb696186e6f566ff0053d39f28d
|
||||
F src/vdbe.h a1d0e3b934e835e73edd146f2e7c4eadb711b5c9875c18159a57483fd78e550e
|
||||
F src/vdbeInt.h b45599a2b59f1ce042512ab6786b0b82a8cf3002f6b0fa60b4834e2cd3ac61d8
|
||||
F src/vdbeInt.h 68756566247e190f22ea8f175a81f9d1b91b6258bcdd69832ea2eb3c78ecfb11
|
||||
F src/vdbeapi.c 8863ffb5a7bac42fe9a68aaa3526ee29fc18fb02a9b27188b756de41e33856e9
|
||||
F src/vdbeaux.c 3aa7ec0f53156760e9b42557122c61f90efddba5d9d173d076b3b8826b1b23bb
|
||||
F src/vdbeaux.c 2c3e77262e0f5604d1b560b0559e9be7a793a7448ddf4baf90cedce7fedf683d
|
||||
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
|
||||
F src/vdbemem.c 7737f0b1c480a32b057849c804d2f21d5389649bb8be80f77ad75df700adc9a1
|
||||
F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
|
||||
@@ -1944,8 +1944,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 393460132994d6ca133e52af57374e43a2795a9e7fc7781bd9dea752a2b52c6a
|
||||
R 9d513bd798b81de21bb7dd572470a8e8
|
||||
P 1c026bcb3c9e1ae0f38ad8a3e6e3bda1a0cdff9dcc77a08b1820f2fdde2ee200
|
||||
R 6589fae24aaa3fb0ff9b2ab0fa20c61e
|
||||
U drh
|
||||
Z bd0ff582d66826c917840ae517528eb1
|
||||
Z bb01b1e110beac42908286888d97e4bc
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
54f49f65ac943263a1622b1efe519c8a61f30f23694fd4fec89ad2bf0e17b473
|
||||
09a47f32a44bfe8630157f09518e6467fac281bc70cf229c88efccac2028ea70
|
||||
+139
-68
@@ -1536,12 +1536,18 @@ case OP_FkCheck: {
|
||||
case OP_ResultRow: {
|
||||
Mem *pMem;
|
||||
int i;
|
||||
VdbeCursor *pC;
|
||||
|
||||
assert( p->nResColumn==pOp->p2 );
|
||||
assert( pOp->p1>0 || CORRUPT_DB );
|
||||
assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
|
||||
|
||||
/* Invalidate all ephemeral cursor row caches */
|
||||
p->cacheCtr = (p->cacheCtr + 2)|1;
|
||||
for(i=0; i<p->nCursor; i++){
|
||||
pC = p->apCsr[i];
|
||||
if( pC && pC->eCurState<2 ) pC->eCurState |= 2;
|
||||
}
|
||||
|
||||
/* Make sure the results of the current row are \000 terminated
|
||||
** and have an assigned type. The results are de-ephemeralized as
|
||||
@@ -2597,11 +2603,17 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
||||
** changes.
|
||||
*/
|
||||
case OP_IfNullRow: { /* jump */
|
||||
VdbeCursor *pC;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( p->apCsr[pOp->p1]!=0 );
|
||||
if( p->apCsr[pOp->p1]->nullRow ){
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
if( pC->nullRow ){
|
||||
assert( pC->eCurState==CURSTATE_NULLROW );
|
||||
sqlite3VdbeMemSetNull(aMem + pOp->p3);
|
||||
goto jump_to_p2;
|
||||
}else{
|
||||
assert( pC->eCurState!=CURSTATE_NULLROW );
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2676,42 +2688,59 @@ case OP_Column: {
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
p2 = (u32)pOp->p2;
|
||||
|
||||
/* If the cursor cache is stale (meaning it is not currently point at
|
||||
** the correct row) then bring it up-to-date by doing the necessary
|
||||
** B-Tree seek. */
|
||||
rc = sqlite3VdbeCursorMoveto(&pC, &p2);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
|
||||
op_column_restart:
|
||||
assert( pC!=0 );
|
||||
assert( p2<(u32)pC->nField );
|
||||
aOffset = pC->aOffset;
|
||||
assert( aOffset==pC->aType+pC->nField );
|
||||
assert( aOffset==pC->aType+pC->nField );
|
||||
assert( pC->eCurType!=CURTYPE_VTAB );
|
||||
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
|
||||
assert( pC->eCurType!=CURTYPE_SORTER );
|
||||
|
||||
if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/
|
||||
if( pC->nullRow ){
|
||||
if( pC->eCurType==CURTYPE_PSEUDO ){
|
||||
/* For the special case of as pseudo-cursor, the seekResult field
|
||||
** identifies the register that holds the record */
|
||||
assert( pC->seekResult>0 );
|
||||
pReg = &aMem[pC->seekResult];
|
||||
assert( pReg->flags & MEM_Blob );
|
||||
assert( memIsValid(pReg) );
|
||||
pC->payloadSize = pC->szRow = pReg->n;
|
||||
pC->aRow = (u8*)pReg->z;
|
||||
}else{
|
||||
sqlite3VdbeMemSetNull(pDest);
|
||||
goto op_column_out;
|
||||
switch( pC->eCurState ){
|
||||
case CURSTATE_READY: {
|
||||
rc = sqlite3VdbeCursorRestore(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
break;
|
||||
}
|
||||
case CURSTATE_PSEUDO: {
|
||||
break;
|
||||
}
|
||||
case CURSTATE_DEFERRED: {
|
||||
u32 iMap;
|
||||
assert( !pC->isEphemeral );
|
||||
if( pC->ub.aAltMap && (iMap = pC->ub.aAltMap[1+p2])>0 ){
|
||||
pC = pC->pAltCursor;
|
||||
p2 = iMap - 1;
|
||||
goto op_column_restart;
|
||||
}
|
||||
}else{
|
||||
rc = sqlite3VdbeFinishMoveto(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
goto op_column_btree_init;
|
||||
}
|
||||
case CURSTATE_PSEUDO_UNINIT: {
|
||||
assert( pC->eCurType==CURTYPE_PSEUDO );
|
||||
/* For the special case of as pseudo-cursor, the seekResult field
|
||||
** identifies the register that holds the record */
|
||||
assert( pC->seekResult>0 );
|
||||
pReg = &aMem[pC->seekResult];
|
||||
assert( pReg->flags & MEM_Blob );
|
||||
assert( memIsValid(pReg) );
|
||||
pC->payloadSize = pC->szRow = pReg->n;
|
||||
pC->aRow = (u8*)pReg->z;
|
||||
goto op_column_init_cache;
|
||||
}
|
||||
case CURSTATE_UNINIT: {
|
||||
rc = sqlite3VdbeCursorRestore(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
op_column_btree_init:
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->eCurState==CURSTATE_UNINIT );
|
||||
assert( pCrsr );
|
||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||
pC->payloadSize = sqlite3BtreePayloadSize(pCrsr);
|
||||
@@ -2721,50 +2750,57 @@ case OP_Column: {
|
||||
if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
goto too_big;
|
||||
}
|
||||
}
|
||||
pC->cacheStatus = p->cacheCtr;
|
||||
pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
|
||||
pC->nHdrParsed = 0;
|
||||
op_column_init_cache:
|
||||
pC->eCurState = pC->eCurType;
|
||||
pC->cacheStatus = p->cacheCtr;
|
||||
pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
|
||||
pC->nHdrParsed = 0;
|
||||
|
||||
if( pC->szRow<aOffset[0] ){ /*OPTIMIZATION-IF-FALSE*/
|
||||
/* pC->aRow does not have to hold the entire row, but it does at least
|
||||
** need to cover the header of the record. If pC->aRow does not contain
|
||||
** the complete header, then set it to zero, forcing the header to be
|
||||
** dynamically allocated. */
|
||||
pC->aRow = 0;
|
||||
pC->szRow = 0;
|
||||
|
||||
if( pC->szRow<aOffset[0] ){ /*OPTIMIZATION-IF-FALSE*/
|
||||
/* pC->aRow does not have to hold the entire row, but it does at least
|
||||
** need to cover the header of the record. If pC->aRow does not contain
|
||||
** the complete header, then set it to zero, forcing the header to be
|
||||
** dynamically allocated. */
|
||||
pC->aRow = 0;
|
||||
pC->szRow = 0;
|
||||
|
||||
/* Make sure a corrupt database has not given us an oversize header.
|
||||
** Do this now to avoid an oversize memory allocation.
|
||||
**
|
||||
** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte
|
||||
** types use so much data space that there can only be 4096 and 32 of
|
||||
** them, respectively. So the maximum header length results from a
|
||||
** 3-byte type for each of the maximum of 32768 columns plus three
|
||||
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
|
||||
*/
|
||||
if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){
|
||||
goto op_column_corrupt;
|
||||
/* Make sure a corrupt database has not given us an oversize header.
|
||||
** Do this now to avoid an oversize memory allocation.
|
||||
**
|
||||
** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte
|
||||
** types use so much data space that there can only be 4096 and 32 of
|
||||
** them, respectively. So the maximum header length results from a
|
||||
** 3-byte type for each of the maximum of 32768 columns plus three
|
||||
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
|
||||
*/
|
||||
if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){
|
||||
goto op_column_corrupt;
|
||||
}
|
||||
}else{
|
||||
/* This is an optimization. By skipping over the first few tests
|
||||
** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a
|
||||
** measurable performance gain.
|
||||
**
|
||||
** This branch is taken even if aOffset[0]==0. Such a record is never
|
||||
** generated by SQLite, and could be considered corruption, but we
|
||||
** accept it for historical reasons. When aOffset[0]==0, the code this
|
||||
** branch jumps to reads past the end of the record, but never more
|
||||
** than a few bytes. Even if the record occurs at the end of the page
|
||||
** content area, the "page header" comes after the page content and so
|
||||
** this overread is harmless. Similar overreads can occur for a corrupt
|
||||
** database file.
|
||||
*/
|
||||
zData = pC->aRow;
|
||||
assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */
|
||||
testcase( aOffset[0]==0 );
|
||||
goto op_column_read_header;
|
||||
}
|
||||
}else{
|
||||
/* This is an optimization. By skipping over the first few tests
|
||||
** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a
|
||||
** measurable performance gain.
|
||||
**
|
||||
** This branch is taken even if aOffset[0]==0. Such a record is never
|
||||
** generated by SQLite, and could be considered corruption, but we
|
||||
** accept it for historical reasons. When aOffset[0]==0, the code this
|
||||
** branch jumps to reads past the end of the record, but never more
|
||||
** than a few bytes. Even if the record occurs at the end of the page
|
||||
** content area, the "page header" comes after the page content and so
|
||||
** this overread is harmless. Similar overreads can occur for a corrupt
|
||||
** database file.
|
||||
*/
|
||||
zData = pC->aRow;
|
||||
assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */
|
||||
testcase( aOffset[0]==0 );
|
||||
goto op_column_read_header;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert( pC->eCurState==CURSTATE_NULLROW );
|
||||
sqlite3VdbeMemSetNull(pDest);
|
||||
goto op_column_out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4023,6 +4059,7 @@ case OP_OpenWrite:
|
||||
if( pCur==0 ) goto no_mem;
|
||||
pCur->iDb = iDb;
|
||||
pCur->nullRow = 1;
|
||||
pCur->eCurState = CURSTATE_NULLROW;
|
||||
pCur->isOrdered = 1;
|
||||
pCur->pgnoRoot = p2;
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -4066,6 +4103,7 @@ case OP_OpenDup: {
|
||||
pCx = allocateCursor(p, pOp->p1, pOrig->nField, CURTYPE_BTREE);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
pCx->eCurState = CURSTATE_NULLROW;
|
||||
pCx->isEphemeral = 1;
|
||||
pCx->pKeyInfo = pOrig->pKeyInfo;
|
||||
pCx->isTable = pOrig->isTable;
|
||||
@@ -4190,6 +4228,7 @@ case OP_OpenEphemeral: {
|
||||
}
|
||||
if( rc ) goto abort_due_to_error;
|
||||
pCx->nullRow = 1;
|
||||
pCx->eCurState = CURSTATE_NULLROW;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4260,6 +4299,7 @@ case OP_OpenPseudo: {
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p3, CURTYPE_PSEUDO);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
pCx->eCurState = CURSTATE_NULLROW;
|
||||
pCx->seekResult = pOp->p2;
|
||||
pCx->isTable = 1;
|
||||
/* Give this pseudo-cursor a fake BtCursor pointer so that pCx
|
||||
@@ -4424,6 +4464,7 @@ case OP_SeekGT: { /* jump, in3, group */
|
||||
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = CURSTATE_UNINIT;
|
||||
if( pC->isTable ){
|
||||
u16 flags3, newType;
|
||||
/* The OPFLAG_SEEKEQ/BTREE_SEEK_EQ flag is only set on index cursors */
|
||||
@@ -4957,6 +4998,7 @@ case OP_Found: { /* jump, in3 */
|
||||
pC->nullRow = 1-alreadyExists;
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = alreadyExists ? CURSTATE_UNINIT : CURSTATE_NULLROW;
|
||||
if( pOp->opcode==OP_Found ){
|
||||
VdbeBranchTaken(alreadyExists!=0,2);
|
||||
if( alreadyExists ) goto jump_to_p2;
|
||||
@@ -5061,6 +5103,7 @@ notExistsWithKey:
|
||||
pC->movetoTarget = iKey; /* Used by OP_Delete */
|
||||
pC->nullRow = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = CURSTATE_UNINIT;
|
||||
pC->deferredMoveto = 0;
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
pC->seekResult = res;
|
||||
@@ -5226,6 +5269,7 @@ case OP_NewRowid: { /* out2 */
|
||||
}
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = CURSTATE_UNINIT;
|
||||
}
|
||||
pOut->u.i = v;
|
||||
break;
|
||||
@@ -5338,6 +5382,7 @@ case OP_Insert: {
|
||||
);
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = CURSTATE_UNINIT;
|
||||
|
||||
/* Invoke the update-hook if required. */
|
||||
if( rc ) goto abort_due_to_error;
|
||||
@@ -5498,6 +5543,7 @@ case OP_Delete: {
|
||||
|
||||
rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = CURSTATE_UNINIT;
|
||||
pC->seekResult = 0;
|
||||
if( rc ) goto abort_due_to_error;
|
||||
|
||||
@@ -5581,7 +5627,10 @@ case OP_SorterData: {
|
||||
assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
if( rc ) goto abort_due_to_error;
|
||||
p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE;
|
||||
pC = p->apCsr[pOp->p3];
|
||||
assert( pC!=0 );
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = pC->eCurType + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5626,6 +5675,7 @@ case OP_RowData: {
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( isSorter(pC)==0 );
|
||||
assert( pC->nullRow==0 );
|
||||
assert( pC->eCurState!=CURSTATE_NULLROW );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
|
||||
@@ -5674,10 +5724,12 @@ case OP_Rowid: { /* out2 */
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
|
||||
assert( (pC->eCurState==CURSTATE_NULLROW)==(pC->nullRow!=0) );
|
||||
if( pC->nullRow ){
|
||||
pOut->flags = MEM_Null;
|
||||
break;
|
||||
}else if( pC->deferredMoveto ){
|
||||
assert( pC->eCurState==CURSTATE_DEFERRED );
|
||||
v = pC->movetoTarget;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
}else if( pC->eCurType==CURTYPE_VTAB ){
|
||||
@@ -5694,6 +5746,7 @@ case OP_Rowid: { /* out2 */
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
rc = sqlite3VdbeCursorRestore(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
assert( (pC->eCurState==CURSTATE_NULLROW)==(pC->nullRow!=0) );
|
||||
if( pC->nullRow ){
|
||||
pOut->flags = MEM_Null;
|
||||
break;
|
||||
@@ -5721,6 +5774,11 @@ case OP_NullRow: {
|
||||
if( pC->eCurType==CURTYPE_BTREE ){
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
sqlite3BtreeClearCursor(pC->uc.pCursor);
|
||||
pC->eCurState = CURSTATE_NULLROW;
|
||||
}else if( pC->eCurType==CURTYPE_PSEUDO ){
|
||||
pC->eCurState = CURSTATE_PSEUDO_UNINIT;
|
||||
}else{
|
||||
pC->eCurState = CURSTATE_NULLROW;
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pC->seekOp==0 ) pC->seekOp = OP_NullRow;
|
||||
@@ -5777,6 +5835,7 @@ case OP_Last: { /* jump */
|
||||
pC->nullRow = (u8)res;
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = res ? CURSTATE_NULLROW : CURSTATE_UNINIT;
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( pOp->p2>0 ){
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
@@ -5880,8 +5939,9 @@ case OP_Rewind: { /* jump */
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
}
|
||||
if( rc ) goto abort_due_to_error;
|
||||
pC->nullRow = (u8)res;
|
||||
pC->eCurState = res ? CURSTATE_NULLROW : CURSTATE_UNINIT;
|
||||
if( rc ) goto abort_due_to_error;
|
||||
assert( pOp->p2>0 && pOp->p2<p->nOp );
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ) goto jump_to_p2;
|
||||
@@ -5978,6 +6038,7 @@ case OP_Next: /* jump */
|
||||
|
||||
next_tail:
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = CURSTATE_UNINIT;
|
||||
VdbeBranchTaken(rc==SQLITE_OK,2);
|
||||
if( rc==SQLITE_OK ){
|
||||
pC->nullRow = 0;
|
||||
@@ -5990,6 +6051,7 @@ next_tail:
|
||||
if( rc!=SQLITE_DONE ) goto abort_due_to_error;
|
||||
rc = SQLITE_OK;
|
||||
pC->nullRow = 1;
|
||||
pC->eCurState = CURSTATE_NULLROW;
|
||||
goto check_for_interrupt;
|
||||
}
|
||||
|
||||
@@ -6047,6 +6109,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
);
|
||||
assert( pC->deferredMoveto==0 );
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = CURSTATE_UNINIT;
|
||||
if( rc) goto abort_due_to_error;
|
||||
break;
|
||||
}
|
||||
@@ -6121,6 +6184,7 @@ case OP_IdxDelete: {
|
||||
}
|
||||
assert( pC->deferredMoveto==0 );
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->eCurState = CURSTATE_UNINIT;
|
||||
pC->seekResult = 0;
|
||||
break;
|
||||
}
|
||||
@@ -6193,6 +6257,7 @@ case OP_IdxRowid: { /* out2 */
|
||||
pTabCur->nullRow = 0;
|
||||
pTabCur->movetoTarget = rowid;
|
||||
pTabCur->deferredMoveto = 1;
|
||||
pTabCur->eCurState = CURSTATE_DEFERRED;
|
||||
assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
|
||||
assert( !pTabCur->isEphemeral );
|
||||
pTabCur->ub.aAltMap = pOp->p4.ai;
|
||||
@@ -6221,6 +6286,7 @@ case OP_FinishSeek: {
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
if( pC->deferredMoveto ){
|
||||
assert( pC->eCurState==CURSTATE_DEFERRED );
|
||||
rc = sqlite3VdbeFinishMoveto(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
}
|
||||
@@ -7818,6 +7884,7 @@ case OP_VFilter: { /* jump */
|
||||
if( rc ) goto abort_due_to_error;
|
||||
res = pModule->xEof(pVCur);
|
||||
pCur->nullRow = 0;
|
||||
pCur->eCurState = CURSTATE_READY;
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ) goto jump_to_p2;
|
||||
break;
|
||||
@@ -7852,9 +7919,11 @@ case OP_VColumn: {
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
if( pCur->nullRow ){
|
||||
assert( pCur->eCurState==CURSTATE_NULLROW );
|
||||
sqlite3VdbeMemSetNull(pDest);
|
||||
break;
|
||||
}
|
||||
assert( pCur->eCurState!=CURSTATE_NULLROW );
|
||||
pVtab = pCur->uc.pVCur->pVtab;
|
||||
pModule = pVtab->pModule;
|
||||
assert( pModule->xColumn );
|
||||
@@ -7903,8 +7972,10 @@ case OP_VNext: { /* jump */
|
||||
assert( pCur!=0 );
|
||||
assert( pCur->eCurType==CURTYPE_VTAB );
|
||||
if( pCur->nullRow ){
|
||||
assert( pCur->eCurState==CURSTATE_NULLROW );
|
||||
break;
|
||||
}
|
||||
assert( pCur->eCurState!=CURSTATE_NULLROW );
|
||||
pVtab = pCur->uc.pVCur->pVtab;
|
||||
pModule = pVtab->pModule;
|
||||
assert( pModule->xNext );
|
||||
|
||||
+31
-3
@@ -58,9 +58,36 @@ typedef struct AuxData AuxData;
|
||||
|
||||
/* Types of VDBE cursors */
|
||||
#define CURTYPE_BTREE 0
|
||||
#define CURTYPE_SORTER 1
|
||||
#define CURTYPE_VTAB 2
|
||||
#define CURTYPE_PSEUDO 3
|
||||
#define CURTYPE_PSEUDO 1
|
||||
#define CURTYPE_SORTER 2
|
||||
#define CURTYPE_VTAB 3
|
||||
|
||||
/* Allowed values for VdbeCursor.eCurState, representing the "cursor state".
|
||||
**
|
||||
** The cursor state captures most of the information that the OP_Column
|
||||
** opcode needs to know about the status of the cursor. This state info
|
||||
** used to be captured by three different fields of the VdbeCursor:
|
||||
**
|
||||
** u8 nullRow; // True if pointing to a row with no data
|
||||
** u8 deferredMoveto; // A call to sqlite3BtreeMoveto() is needed
|
||||
** u32 cacheStatus; // Cache is valid if this matches Vdbe.cacheCtr
|
||||
**
|
||||
** Moving the state information into a single variable simplifies the logic
|
||||
** and requires fewer CPU cycles to process.
|
||||
**
|
||||
** Constraints on values:
|
||||
**
|
||||
** CURSTATE_READY == CURTYPE_BTREE
|
||||
** CURSTATE_PSEUDO == CURTYPE_PSEUDO
|
||||
** CURSTATE_UNINIT == CURSTATE_READY + 2
|
||||
** CURSTATE_PSEUDO_UNINIT == CURSTATE_PSEUDO + 2
|
||||
*/
|
||||
#define CURSTATE_READY 0 /* Cursor ready for use */
|
||||
#define CURSTATE_PSEUDO 1 /* Pseudo-cursor ready for use */
|
||||
#define CURSTATE_UNINIT 2 /* Without column cache */
|
||||
#define CURSTATE_PSEUDO_UNINIT 3 /* Pseudo without column cache */
|
||||
#define CURSTATE_DEFERRED 4 /* Btree with deferred seek */
|
||||
#define CURSTATE_NULLROW 5 /* Return NULL for all columns */
|
||||
|
||||
/*
|
||||
** A VdbeCursor is an superclass (a wrapper) for various cursor objects:
|
||||
@@ -79,6 +106,7 @@ struct VdbeCursor {
|
||||
u8 nullRow; /* True if pointing to a row with no data */
|
||||
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||
u8 isTable; /* True for rowid tables. False for indexes */
|
||||
u8 eCurState; /* Current state of the cursor */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 seekOp; /* Most recent seek operation on this cursor */
|
||||
u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */
|
||||
|
||||
+8
-2
@@ -3495,6 +3495,7 @@ int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){
|
||||
#endif
|
||||
p->deferredMoveto = 0;
|
||||
p->cacheStatus = CACHE_STALE;
|
||||
if( !p->nullRow ) p->eCurState = CURSTATE_UNINIT;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -3512,7 +3513,11 @@ static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
|
||||
assert( sqlite3BtreeCursorHasMoved(p->uc.pCursor) );
|
||||
rc = sqlite3BtreeCursorRestore(p->uc.pCursor, &isDifferentRow);
|
||||
p->cacheStatus = CACHE_STALE;
|
||||
if( isDifferentRow ) p->nullRow = 1;
|
||||
p->eCurState = CURSTATE_UNINIT;
|
||||
if( isDifferentRow ){
|
||||
p->nullRow = 1;
|
||||
p->eCurState = CURSTATE_NULLROW;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3544,9 +3549,10 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){
|
||||
VdbeCursor *p = *pp;
|
||||
assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
|
||||
if( p->deferredMoveto ){
|
||||
if( p->deferredMoveto && !p->nullRow ){
|
||||
u32 iMap;
|
||||
assert( !p->isEphemeral );
|
||||
assert( p->eCurState==CURSTATE_DEFERRED );
|
||||
if( p->ub.aAltMap && (iMap = p->ub.aAltMap[1+*piCol])>0 && !p->nullRow ){
|
||||
*pp = p->pAltCursor;
|
||||
*piCol = iMap - 1;
|
||||
|
||||
Reference in New Issue
Block a user