-C Improved\scomment\son\sthe\scodeDeferredSeek()\sroutine.\sNo\scode\schanges.
-D 2022-02-25T13:29:56.636
+C This\sbranch\sproposes\sto\sconsolidate\svarious\sstate\sfields\sof\sVdbeCursor\n(specifically,\snullRow,\sdeferredMoveto,\sand\scacheStatus)\sinto\sa\ssingle\neCurState\sfield.\s\sThis\sfirst\scheck-in\sadds\sthe\snew\seCurState\sfield\swhile\nretaining\sand\scontinuing\sto\suse\sthe\slegacy\sstate\sfields.
+D 2022-02-25T15:44:13.844
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23
F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3
-F src/vdbe.c 5ff8a23c52b38a25f5b8ae398c0a787aff6fdf49e60e675915614022862a4a0a
+F src/vdbe.c 588de992e0efc2cc167748888b90fc0910e93b3030a16b5685f0acd7cb5f1cb3
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 b938eb6ba843f370fe6f97069a3ed3693e1d6cbb01f3cbe718d4a877a25d3e38
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
F src/vdbemem.c 7737f0b1c480a32b057849c804d2f21d5389649bb8be80f77ad75df700adc9a1
F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 393460132994d6ca133e52af57374e43a2795a9e7fc7781bd9dea752a2b52c6a
-R 9d513bd798b81de21bb7dd572470a8e8
+P 54f49f65ac943263a1622b1efe519c8a61f30f23694fd4fec89ad2bf0e17b473
+R 2ff4c217735fef3148c991fc4ac1775c
+T *branch * simplify-cursor-state
+T *sym-simplify-cursor-state *
+T -sym-trunk *
U drh
-Z bd0ff582d66826c917840ae517528eb1
+Z 177b4f0e5553a1f45304df314a704a95
# Remove this line to create a well-formed Fossil manifest.
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
** 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;
}
/* For the special case of as pseudo-cursor, the seekResult field
** identifies the register that holds the record */
assert( pC->seekResult>0 );
+ assert( pC->eCurState==CURSTATE_PSEUDO_UNINIT
+ || pC->eCurState==CURSTATE_NULLROW );
pReg = &aMem[pC->seekResult];
assert( pReg->flags & MEM_Blob );
assert( memIsValid(pReg) );
pC->payloadSize = pC->szRow = pReg->n;
pC->aRow = (u8*)pReg->z;
}else{
+ assert( pC->eCurState==CURSTATE_NULLROW );
sqlite3VdbeMemSetNull(pDest);
goto op_column_out;
}
}else{
pCrsr = pC->uc.pCursor;
assert( pC->eCurType==CURTYPE_BTREE );
+ assert( pC->eCurState==CURSTATE_UNINIT );
assert( pCrsr );
assert( sqlite3BtreeCursorIsValid(pCrsr) );
pC->payloadSize = sqlite3BtreePayloadSize(pCrsr);
goto too_big;
}
}
+ pC->eCurState = pC->eCurType;
pC->cacheStatus = p->cacheCtr;
pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
pC->nHdrParsed = 0;
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
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;
}
if( rc ) goto abort_due_to_error;
pCx->nullRow = 1;
+ pCx->eCurState = CURSTATE_NULLROW;
break;
}
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
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 */
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;
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;
}
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
+ pC->eCurState = CURSTATE_UNINIT;
}
pOut->u.i = v;
break;
);
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
+ pC->eCurState = CURSTATE_UNINIT;
/* Invoke the update-hook if required. */
if( rc ) goto abort_due_to_error;
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;
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;
}
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;
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 ){
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;
assert( pC!=0 );
pC->nullRow = 1;
pC->cacheStatus = CACHE_STALE;
+ pC->eCurState = CURSTATE_NULLROW;
if( pC->eCurType==CURTYPE_BTREE ){
assert( pC->uc.pCursor!=0 );
sqlite3BtreeClearCursor(pC->uc.pCursor);
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);
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;
next_tail:
pC->cacheStatus = CACHE_STALE;
+ pC->eCurState = CURSTATE_UNINIT;
VdbeBranchTaken(rc==SQLITE_OK,2);
if( rc==SQLITE_OK ){
pC->nullRow = 0;
if( rc!=SQLITE_DONE ) goto abort_due_to_error;
rc = SQLITE_OK;
pC->nullRow = 1;
+ pC->eCurState = CURSTATE_NULLROW;
goto check_for_interrupt;
}
);
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
+ pC->eCurState = CURSTATE_UNINIT;
if( rc) goto abort_due_to_error;
break;
}
}
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
+ pC->eCurState = CURSTATE_UNINIT;
pC->seekResult = 0;
break;
}
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;
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;
}
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;
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 );
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 );
/* 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:
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() */