From: drh <> Date: Fri, 25 Feb 2022 15:44:13 +0000 (+0000) Subject: This branch proposes to consolidate various state fields of VdbeCursor X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=44e932564466e3ac361a9caacc01e2ac7b008435;p=thirdparty%2Fsqlite.git This branch proposes to consolidate various state fields of VdbeCursor (specifically, nullRow, deferredMoveto, and cacheStatus) into a single eCurState field. This first check-in adds the new eCurState field while retaining and continuing to use the legacy state fields. FossilOrigin-Name: 7953716c12ca1deb50ee2c91d9b62a029e38f7cb61af418eeca438283c45f825 --- diff --git a/manifest b/manifest index e6c22fe855..f510c37f92 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 @@ -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 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 @@ -1944,8 +1944,11 @@ 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 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. diff --git a/manifest.uuid b/manifest.uuid index 0e6e71b15e..168c33756a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -54f49f65ac943263a1622b1efe519c8a61f30f23694fd4fec89ad2bf0e17b473 \ No newline at end of file +7953716c12ca1deb50ee2c91d9b62a029e38f7cb61af418eeca438283c45f825 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 19e9156030..9d0a227e81 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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; inCursor; 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->p1nCursor ); - 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; } @@ -2700,18 +2712,22 @@ case OP_Column: { /* 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); @@ -2722,6 +2738,7 @@ case OP_Column: { goto too_big; } } + pC->eCurState = pC->eCurType; pC->cacheStatus = p->cacheCtr; pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]); pC->nHdrParsed = 0; @@ -4023,6 +4040,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 +4084,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 +4209,7 @@ case OP_OpenEphemeral: { } if( rc ) goto abort_due_to_error; pCx->nullRow = 1; + pCx->eCurState = CURSTATE_NULLROW; break; } @@ -4260,6 +4280,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 +4445,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 +4979,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 +5084,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 +5250,7 @@ case OP_NewRowid: { /* out2 */ } pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; + pC->eCurState = CURSTATE_UNINIT; } pOut->u.i = v; break; @@ -5338,6 +5363,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 +5524,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 +5608,10 @@ case OP_SorterData: { assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); assert( pOp->p1>=0 && pOp->p1nCursor ); 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 +5656,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 +5705,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 +5727,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; @@ -5718,6 +5752,7 @@ case OP_NullRow: { 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); @@ -5777,6 +5812,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 +5916,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->p2nOp ); VdbeBranchTaken(res!=0,2); if( res ) goto jump_to_p2; @@ -5978,6 +6015,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 +6028,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 +6086,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 +6161,7 @@ case OP_IdxDelete: { } assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; + pC->eCurState = CURSTATE_UNINIT; pC->seekResult = 0; break; } @@ -6193,6 +6234,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 +6263,7 @@ case OP_FinishSeek: { assert( pOp->p1>=0 && pOp->p1nCursor ); 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 +7861,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 +7896,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 +7949,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 ); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index f02b37c6a2..6e6398b2b1 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -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() */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index bcfe63130f..2856fe014a 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3495,6 +3495,7 @@ int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){ #endif p->deferredMoveto = 0; p->cacheStatus = CACHE_STALE; + p->eCurState = p->nullRow ? CURSTATE_NULLROW : 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; } @@ -3547,6 +3552,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){ if( p->deferredMoveto ){ 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;