From 76873ab240b2acf09342e2e7153a8dcef942bcf1 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 7 Jan 2006 18:48:26 +0000 Subject: [PATCH] Invalidate all VDBE cursor row caches in between calls to sqlite3_step() since the emphemeral content that those caches point to might change if the statement is READ UNCOMMITTED. (CVS 2886) FossilOrigin-Name: 0ae461313c1642a49a9f6cda608c42c7c0053ce4 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/vdbe.c | 37 ++++++++++++++++++++----------------- src/vdbeInt.h | 13 ++++++++++--- src/vdbeaux.c | 3 ++- 5 files changed, 41 insertions(+), 30 deletions(-) diff --git a/manifest b/manifest index e614b3f433..ee076b8125 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Continued\sprogress\stoward\sa\sworking\swince\sbackend.\s(CVS\s2885) -D 2006-01-07T18:14:48 +C Invalidate\sall\sVDBE\scursor\srow\scaches\sin\sbetween\scalls\sto\ssqlite3_step()\nsince\sthe\semphemeral\scontent\sthat\sthose\scaches\spoint\sto\smight\schange\sif\nthe\sstatement\sis\sREAD\sUNCOMMITTED.\s(CVS\s2886) +D 2006-01-07T18:48:26 F Makefile.in c79fbdaa264c6afcd435f2fb492551de5a8cf80d F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -84,11 +84,11 @@ F src/update.c 29ba0385c8639803cd8e6e616e99096a0bc10443 F src/utf.c b7bffac4260177ae7f83c01d025fe0f5ed70ce71 F src/util.c 8a3ef3c1b345cdadcee33ce4537c63bb0fda0ed8 F src/vacuum.c a7301804d4f849da0ce9d869219c71c6d621c34e -F src/vdbe.c b0617790673c64b78740b7c1fc9c3e247e05612a +F src/vdbe.c 87a796e2889283b681be71076fa6b6318561f2bd F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13 -F src/vdbeInt.h 9b78ba00cc006bff17e04a54ba3ded9fc7810a10 +F src/vdbeInt.h 5451cf71f229e366ac543607c0a17f36e5737ea9 F src/vdbeapi.c 7335569b1bad946ba53892384b4b1534e877b1ee -F src/vdbeaux.c a4eea656afebc6161771ddfa7a9c91186a5d7888 +F src/vdbeaux.c cb57a0b6aef5ff002b42baf366c85e389509b2d7 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5 F src/vdbemem.c deba8d6e3727643924b210a8c531a496c2b8d386 F src/where.c de22a3a84c595ca1ad206dd19818f65f950e79f8 @@ -335,7 +335,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 19f71a6d1982e986f5436bff71ef38b1bcc2e11d -R 90bcf273c8a689d05bbbb1a9b9eb146b +P 15fda14ee0c0524d3064d767f48edd689c090d95 +R 8b6ba0a7cf083b8ec0fb5215eb91310f U drh -Z fc0de77c4da0e5b5eb0148bbd35f7f04 +Z c1686b0c208bc7bdd63ff2b9442034c8 diff --git a/manifest.uuid b/manifest.uuid index c0039a101e..7f3a78821a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -15fda14ee0c0524d3064d767f48edd689c090d95 \ No newline at end of file +0ae461313c1642a49a9f6cda608c42c7c0053ce4 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index ec113e434e..fd1d942226 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.515 2006/01/07 18:10:33 drh Exp $ +** $Id: vdbe.c,v 1.516 2006/01/07 18:48:26 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -879,6 +879,9 @@ case OP_Callback: { /* no-push */ Deephemeralize(pMem); } + /* Invalidate all ephemeral cursor row caches */ + p->cacheCtr = (p->cacheCtr + 2)|1; + /* Make sure the results of the current row are \000 terminated ** and have an assigned type. The results are deephemeralized as ** as side effect. @@ -1908,7 +1911,7 @@ case OP_Column: { pCrsr = pC->pCursor; if( pC->nullRow ){ payloadSize = 0; - }else if( pC->cacheValid ){ + }else if( pC->cacheStatus==p->cacheCtr ){ payloadSize = pC->payloadSize; zRec = (char*)pC->aRow; }else if( pC->isIndex ){ @@ -1924,7 +1927,7 @@ case OP_Column: { /* The record is the sole entry of a pseudo-table */ payloadSize = pC->nData; zRec = pC->pData; - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; assert( payloadSize==0 || zRec!=0 ); nField = pC->nField; pCrsr = 0; @@ -1947,7 +1950,7 @@ case OP_Column: { /* Read and parse the table header. Store the results of the parse ** into the record header cache fields of the cursor. */ - if( pC && pC->cacheValid ){ + if( pC && pC->cacheStatus==p->cacheCtr ){ aType = pC->aType; aOffset = pC->aOffset; }else{ @@ -2042,7 +2045,7 @@ case OP_Column: { pC->payloadSize = payloadSize; pC->aType = aType; pC->aOffset = aOffset; - pC->cacheValid = 1; + pC->cacheStatus = p->cacheCtr; } } @@ -2805,7 +2808,7 @@ case OP_MoveGt: { /* no-push */ pC->rowidIsValid = 0; } pC->deferredMoveto = 0; - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; *pC->pIncrKey = 0; sqlite3_search_count++; if( oc==OP_MoveGe || oc==OP_MoveGt ){ @@ -2906,7 +2909,7 @@ case OP_Found: { /* no-push */ rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); alreadyExists = rx==SQLITE_OK && res==0; pC->deferredMoveto = 0; - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; } if( pOp->opcode==OP_Found ){ if( alreadyExists ) pc = pOp->p2 - 1; @@ -2980,7 +2983,7 @@ case OP_IsUnique: { /* no-push */ ** If there is no such entry, jump immediately to P2. */ assert( pCx->deferredMoveto==0 ); - pCx->cacheValid = 0; + pCx->cacheStatus = CACHE_STALE; rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; if( res<0 ){ @@ -3053,7 +3056,7 @@ case OP_NotExists: { /* no-push */ pC->lastRowid = pTos->i; pC->rowidIsValid = res==0; pC->nullRow = 0; - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; if( res!=0 ){ pc = pOp->p2 - 1; pC->rowidIsValid = 0; @@ -3229,7 +3232,7 @@ case OP_NewRowid: { } pC->rowidIsValid = 0; pC->deferredMoveto = 0; - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; } pTos++; pTos->i = v; @@ -3303,7 +3306,7 @@ case OP_Insert: { /* no-push */ pC->rowidIsValid = 0; pC->deferredMoveto = 0; - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p3 ){ @@ -3363,7 +3366,7 @@ case OP_Delete: { /* no-push */ if( rc ) goto abort_due_to_error; rc = sqlite3BtreeDelete(pC->pCursor); pC->nextRowidValid = 0; - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p3 ){ @@ -3541,7 +3544,7 @@ case OP_Last: { /* no-push */ rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = res; pC->deferredMoveto = 0; - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } @@ -3590,7 +3593,7 @@ case OP_Rewind: { /* no-push */ rc = sqlite3BtreeFirst(pCrsr, &res); pC->atFirst = res==0; pC->deferredMoveto = 0; - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; }else{ res = 1; } @@ -3635,7 +3638,7 @@ case OP_Next: { /* no-push */ rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : sqlite3BtreePrevious(pCrsr, &res); pC->nullRow = res; - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; } if( res==0 ){ pc = pOp->p2 - 1; @@ -3672,7 +3675,7 @@ case OP_IdxInsert: { /* no-push */ assert( pC->isTable==0 ); rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0); assert( pC->deferredMoveto==0 ); - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; } Release(pTos); pTos--; @@ -3699,7 +3702,7 @@ case OP_IdxDelete: { /* no-push */ rc = sqlite3BtreeDelete(pCrsr); } assert( pC->deferredMoveto==0 ); - pC->cacheValid = 0; + pC->cacheStatus = CACHE_STALE; } Release(pTos); pTos--; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 5871bf296d..10c5be7871 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -86,9 +86,10 @@ struct Cursor { /* Cached information about the header for the data record that the ** cursor is currently pointing to. Only valid if cacheValid is true. - ** zRow might point to (ephemeral) data for the current row, or it might - ** be NULL. */ - Bool cacheValid; /* True if the cache is valid */ + ** aRow might point to (ephemeral) data for the current row, or it might + ** be NULL. + */ + int cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ int payloadSize; /* Total number of bytes in the record */ u32 *aType; /* Type values for all entries in the record */ u32 *aOffset; /* Cached offsets to the start of each columns data */ @@ -103,6 +104,11 @@ typedef struct Cursor Cursor; */ #define NBFS 32 +/* +** A value for Cursor.cacheValid that means the cache is always invalid. +*/ +#define CACHE_STALE 0 + /* ** Internally, the vdbe manipulates nearly all SQL values as Mem ** structures. Each Mem struct may cache multiple representations (string, @@ -287,6 +293,7 @@ struct Vdbe { int nMem; /* Number of memory locations currently allocated */ Mem *aMem; /* The memory locations */ int nCallback; /* Number of callbacks invoked so far */ + int cacheCtr; /* Cursor row cache generation counter */ Fifo sFifo; /* A list of ROWIDs */ int contextStackTop; /* Index of top element in the context stack */ int contextStackDepth; /* The size of the "context" stack */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 5967533ddd..a1302dc98b 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -782,6 +782,7 @@ void sqlite3VdbeMakeReady( p->explain |= isExplain; p->magic = VDBE_MAGIC_RUN; p->nChange = 0; + p->cacheCtr = 1; p->minWriteFileFormat = 255; #ifdef VDBE_PROFILE { @@ -1453,7 +1454,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){ } sqlite3_search_count++; p->deferredMoveto = 0; - p->cacheValid = 0; + p->cacheStatus = CACHE_STALE; } return SQLITE_OK; } -- 2.47.2