]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
This branch proposes to consolidate various state fields of VdbeCursor
authordrh <>
Fri, 25 Feb 2022 15:44:13 +0000 (15:44 +0000)
committerdrh <>
Fri, 25 Feb 2022 15:44:13 +0000 (15:44 +0000)
(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

manifest
manifest.uuid
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c

index e6c22fe8554fc8c9c5396932f92f39e41d63bb48..f510c37f92fc6e78658d8d8755016288a532fcae 100644 (file)
--- 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.
index 0e6e71b15efdadeffe4cfd558b6f48bee79f0b10..168c33756aa56b81359282fa6fc9c5eaf9c4125b 100644 (file)
@@ -1 +1 @@
-54f49f65ac943263a1622b1efe519c8a61f30f23694fd4fec89ad2bf0e17b473
\ No newline at end of file
+7953716c12ca1deb50ee2c91d9b62a029e38f7cb61af418eeca438283c45f825
\ No newline at end of file
index 19e91560305ae426b15f8ca1c8fbab0929f366c8..9d0a227e81a0ba9522bcb914290a94b877d8cc05 100644 (file)
@@ -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;
 }
@@ -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->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 +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->p2<p->nOp );
   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->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 +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 );
index f02b37c6a2995d723354ccf6efaf050fc3131fbc..6e6398b2b1c5c75abe617a5ac7884db50b1f9392 100644 (file)
@@ -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() */
index bcfe63130f78d1f468886110ec4118725929c783..2856fe014ac9b0e6d028ac690d15c28387d89216 100644 (file)
@@ -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;