diff --git a/manifest b/manifest index 037c3a5ddd..2eeac7aa21 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\sspeed\simprovements.\s(CVS\s1381) -D 2004-05-14T19:08:18 +C Cache\srecord\sheaders\sin\sthe\sOP_Column\sopcode.\s(CVS\s1382) +D 2004-05-14T21:12:23 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -23,7 +23,7 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79 -F src/btree.c c263f1f26b28e0ac929b9807bccf50877335c1b8 +F src/btree.c 731695f701be37c20146b0aaaf415135f01b6deb F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050 F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5 F src/build.c e93f443a20eab57ffb77ff6244b1e09a1f7d9390 @@ -63,10 +63,10 @@ F src/update.c 0441f8b64d616ef244583449e66c984e536c6c9b F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f F src/util.c f9511ffba78e6cf71a28774c2820d7750b5bacdf F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476 -F src/vdbe.c fff79c08b3063d8d6f7b600fc6896c255c72238c +F src/vdbe.c 90018d7938d36daec5caf3fb4c3833bcd803b061 F src/vdbe.h 94457ca73bae972dc61bca33a4dccc2e6e14e2f8 -F src/vdbeInt.h 03f4c3642482570a697a42a9bbb12908c6535bbe -F src/vdbeaux.c 6cf897c49c1fde153d8b9e4c168714207f07cce3 +F src/vdbeInt.h 6740a3b80d437e9a6b3710aead703690fc0d1ddc +F src/vdbeaux.c 38f924db0aa31c13d556bd65ad129d6f5d8c0a27 F src/where.c 6957bbd333cc7ffa7b3878adbe67a095319daa54 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83 @@ -102,7 +102,7 @@ F test/join.test 9ef6aabaac9de51d5fc41e68d1f4355da05a84cd F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8 F test/lastinsert.test 31382f88b9b0270333ac9e4a17f2c2f4732da718 F test/laststmtchanges.test cabd11bdfbaf73a4486c50b58297d9c2038ccc18 -F test/limit.test e28ce938ddacefdff860d082be45e1e5e2801441 +F test/limit.test 94c5dca1e81b7503ce90262ec5a2dc6c4e38d313 F test/lock.test 226ef831dad60ad4d200dc83e25479ba952aac7e F test/main.test 6a851b5992c4881a725a3d9647e629199df8de9d F test/malloc.test 2cfcffb7c858640e01e6520ee1cd54ca57d98e80 @@ -191,7 +191,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P d4e0933dc72b66157164610e0b03f339bc535fb9 -R 9330d9bd11be003784ef684f1b9c1f25 +P cf75cac9b6bd43e60c6e25042b194ec5c60e5671 +R 1c44996f87c60027ab5d6785ca9e8bee U drh -Z 185a62bf4f1e1cc9ef6d8083626f74a6 +Z d44c78218fc520c849f4d72442c0d411 diff --git a/manifest.uuid b/manifest.uuid index a1785d8dd1..bfb52e9896 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cf75cac9b6bd43e60c6e25042b194ec5c60e5671 \ No newline at end of file +8d9eab178f285415775060369f372a88c7091f9f \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 099d4a09e2..1f81934a21 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.138 2004/05/14 19:08:18 drh Exp $ +** $Id: btree.c,v 1.139 2004/05/14 21:12:23 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -1459,6 +1459,23 @@ static void releaseTempCursor(BtCursor *pCur){ } } +/* +** Make sure the BtCursor.info field of the given cursor is valid. +*/ +static void getCellInfo(BtCursor *pCur){ + MemPage *pPage = pCur->pPage; + if( !pCur->infoValid ){ + parseCell(pPage, pPage->aCell[pCur->idx], &pCur->info); + pCur->infoValid = 1; + }else{ +#ifndef NDEBUG + CellInfo info; + parseCell(pPage, pPage->aCell[pCur->idx], &info); + assert( memcmp(&info, &pCur->info, sizeof(info))==0 ); +#endif + } +} + /* ** Set *pSize to the size of the buffer needed to hold the value of ** the key for the current entry. If the cursor is not pointing @@ -1468,25 +1485,11 @@ static void releaseTempCursor(BtCursor *pCur){ ** itself, not the number of bytes in the key. */ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ - MemPage *pPage; - unsigned char *cell; - if( !pCur->isValid ){ *pSize = 0; }else{ - pPage = pCur->pPage; - pageIntegrity(pPage); - assert( pPage!=0 ); - assert( pCur->idx>=0 && pCur->idxnCell ); - cell = pPage->aCell[pCur->idx]; - cell += 2; /* Skip the offset to the next cell */ - if( !pPage->leaf ){ - cell += 4; /* Skip the child pointer */ - } - if( pPage->hasData ){ - while( (0x80&*(cell++))!=0 ){} /* Skip the data size number */ - } - getVarint(cell, pSize); + getCellInfo(pCur); + *pSize = pCur->info.nKey; } return SQLITE_OK; } @@ -1499,28 +1502,12 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ ** the database is empty) then *pSize is set to 0. */ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ - MemPage *pPage; - unsigned char *cell; - if( !pCur->isValid ){ /* Not pointing at a valid entry - set *pSize to 0. */ *pSize = 0; }else{ - pPage = pCur->pPage; - assert( pPage!=0 ); - assert( pPage->isInit ); - pageIntegrity(pPage); - if( !pPage->hasData ){ - *pSize = 0; - }else{ - assert( pCur->idx>=0 && pCur->idxnCell ); - cell = pPage->aCell[pCur->idx]; - cell += 2; /* Skip the offset to the next cell */ - if( !pPage->leaf ){ - cell += 4; /* Skip the child pointer */ - } - getVarint32(cell, pSize); - } + getCellInfo(pCur); + *pSize = pCur->info.nData; } return SQLITE_OK; } @@ -1555,16 +1542,7 @@ static int getPayload( pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idxnCell ); aPayload = pPage->aCell[pCur->idx]; - if( !pCur->infoValid ){ - parseCell(pPage, aPayload, &pCur->info); - pCur->infoValid = 1; - }else{ -#ifndef NDEBUG - CellInfo info; - parseCell(pPage, aPayload, &info); - assert( memcmp(&info, &pCur->info, sizeof(info))==0 ); -#endif - } + getCellInfo(pCur); aPayload += pCur->info.nHeader; if( pPage->intKey ){ nKey = 0; @@ -1703,16 +1681,7 @@ static const unsigned char *fetchPayload( pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idxnCell ); aPayload = pPage->aCell[pCur->idx]; - if( !pCur->infoValid ){ - parseCell(pPage, aPayload, &pCur->info); - pCur->infoValid = 1; - }else{ -#ifndef NDEBUG - CellInfo info; - parseCell(pPage, aPayload, &info); - assert( memcmp(&info, &pCur->info, sizeof(info))==0 ); -#endif - } + getCellInfo(pCur); aPayload += pCur->info.nHeader; if( pPage->intKey ){ nKey = 0; diff --git a/src/vdbe.c b/src/vdbe.c index f83e025655..a024cd9ff3 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.291 2004/05/14 15:27:29 drh Exp $ +** $Id: vdbe.c,v 1.292 2004/05/14 21:12:23 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -1875,10 +1875,7 @@ case OP_NotNull: { break; } -/* Opcode: Column3 P1 P2 * -** -** This opcode (not yet in use) is a replacement for the current OP_Column3 -** that supports the SQLite3 manifest typing feature. +/* Opcode: Column P1 P2 * ** ** Interpret the data that cursor P1 points to as a structure built using ** the MakeRecord instruction. (See the MakeRecord opcode for additional @@ -1905,8 +1902,7 @@ case OP_Column: { char *zData; int freeZdata = 0; /* zData requires sqliteFree() */ - u64 nFields; /* number of fields in the record */ - u64 *aTypes; /* An array of serial types (size nFields) */ + u64 nField; /* number of fields in the record */ int len; /* The length of the serialized data for the column */ int offset; @@ -1924,12 +1920,15 @@ case OP_Column: { assert( pTos[i].flags & MEM_Str ); zRec = pTos[i].z; payloadSize = pTos[i].n; + pC->cacheValid = 0; }else if( (pC = &p->aCsr[i])->pCursor!=0 ){ sqlite3VdbeCursorMoveto(pC); zRec = 0; pCrsr = pC->pCursor; if( pC->nullRow ){ payloadSize = 0; + }else if( pC->cacheValid ){ + payloadSize = pC->payloadSize; }else if( pC->keyAsData ){ i64 payloadSize64; sqlite3BtreeKeySize(pCrsr, &payloadSize64); @@ -1940,6 +1939,7 @@ case OP_Column: { }else if( pC->pseudoTable ){ payloadSize = pC->nData; zRec = pC->pData; + pC->cacheValid = 0; assert( payloadSize==0 || zRec!=0 ); }else{ payloadSize = 0; @@ -1951,100 +1951,106 @@ case OP_Column: { break; } - /* Read the number of fields for the record. - ** FIX ME: The Cursor object should cache this data and the array of - ** field types for subsequent OP_Column instructions. + /* Read and parse the table header. Store the results of the parse + ** into the record header cache fields of the cursor. */ - if( zRec ){ - zData = zRec; - }else{ - /* We can assume that 9 bytes (maximum length of a varint) fits - ** on the main page in all cases. - */ - if( pC->keyAsData ){ - zData = (char *)sqlite3BtreeKeyFetch(pCrsr, 9>payloadSize?payloadSize:9); + if( !pC->cacheValid ){ + pC->payloadSize = payloadSize; + if( zRec ){ + zData = zRec; }else{ - zData = (char *)sqlite3BtreeDataFetch(pCrsr, 9>payloadSize?payloadSize:9); - } - assert( zData ); - } - offset = sqlite3GetVarint(zData, &nFields); - - if( !zRec ){ - /* If the record is stored in a table, see if enough of it is on - ** the main page to use sqlite3BtreeDataFetch() to get the data - ** containing the nFields serial types (varints). This will almost - ** always work, but if it doesn't sqliteMalloc() space and use - ** sqlite3BtreeData(). - ** - ** Estimate the maximum space required by the nFields varints by - ** assuming the maximum space for each is the length required to store: - ** - ** ( * 2) + 13 - ** - ** This is the serial-type for a text object as long as the record - ** itself. In all cases the length required to store this is three - ** bytes or less. - */ - int max_space = sqlite3VarintLen((((u64)payloadSize)<<1)+13)*nFields; - max_space += offset; - if( max_space>payloadSize ){ - max_space = payloadSize; - } - - if( pC->keyAsData ){ - zData = (char *)sqlite3BtreeKeyFetch(pCrsr, max_space); - }else{ - zData = (char *)sqlite3BtreeDataFetch(pCrsr, max_space); - } - if( !zData ){ - /* This code will run very infrequently (e.g. tables with several - ** hundred columns). + /* We can assume that 9 bytes (maximum length of a varint) fits + ** on the main page in all cases. */ - zData = (char *)sqliteMallocRaw(offset+max_space); - if( !zData ){ - rc = SQLITE_NOMEM; - goto abort_due_to_error; - } + int n = 9; + if( payloadSize<9 ) n = payloadSize; if( pC->keyAsData ){ - rc = sqlite3BtreeKey(pCrsr, 0, max_space, zData); + zData = (char *)sqlite3BtreeKeyFetch(pCrsr, n); }else{ - rc = sqlite3BtreeData(pCrsr, 0, max_space, zData); + zData = (char *)sqlite3BtreeDataFetch(pCrsr, n); } - if( rc!=SQLITE_OK ){ - sqliteFree(zData); - goto abort_due_to_error; - } - freeZdata = 1; + assert( zData ); } - } + offset = sqlite3GetVarint(zData, &nField); + if( nField>pC->nField ){ + sqliteFree(pC->aType); + pC->aType = sqliteMallocRaw( nField*sizeof(pC->aType[0]) ); + if( pC->aType==0 ){ + goto no_mem; + } + } + pC->nField = nField; - /* Dynamically allocate space for the aTypes array. and read all - ** the serial types for the record. At the end of this block variable - ** offset is set to the offset to the start of Data0 in the record. - */ - aTypes = (u64 *)sqliteMallocRaw(sizeof(u64)*nFields); - if( !aTypes ){ + if( !zRec ){ + /* If the record is stored in a table, see if enough of it is on + ** the main page to use sqlite3BtreeDataFetch() to get the data + ** containing the nField serial types (varints). This will almost + ** always work, but if it doesn't sqliteMalloc() space and use + ** sqlite3BtreeData(). + ** + ** Estimate the maximum space required by the nField varints by + ** assuming the maximum space for each is the length required to store: + ** + ** ( * 2) + 13 + ** + ** This is the serial-type for a text object as long as the record + ** itself. In all cases the length required to store this is three + ** bytes or less. + */ + int max_space = sqlite3VarintLen((((u64)payloadSize)<<1)+13)*nField; + max_space += offset; + if( max_space>payloadSize ){ + max_space = payloadSize; + } + + if( pC->keyAsData ){ + zData = (char *)sqlite3BtreeKeyFetch(pCrsr, max_space); + }else{ + zData = (char *)sqlite3BtreeDataFetch(pCrsr, max_space); + } + if( !zData ){ + /* This code will run very infrequently (e.g. tables with several + ** hundred columns). + */ + zData = (char *)sqliteMallocRaw(max_space); + if( !zData ){ + goto no_mem; + } + if( pC->keyAsData ){ + rc = sqlite3BtreeKey(pCrsr, 0, max_space, zData); + }else{ + rc = sqlite3BtreeData(pCrsr, 0, max_space, zData); + } + if( rc!=SQLITE_OK ){ + sqliteFree(zData); + goto abort_due_to_error; + } + freeZdata = 1; + } + } + + /* Read all the serial types for the record. At the end of this block + ** variable offset is set to the offset to the start of Data0 in the record. + */ + for(nn=0; nnaType[nn]); + } if( freeZdata ){ - sqliteFree(zData); freeZdata = 0; + sqliteFree(zData); } - rc = SQLITE_NOMEM; - goto abort_due_to_error; - } - for(nn=0; nnnHeader = offset; + pC->cacheValid = 1; } + /* Compute the offset from the beginning of the record to the beginning + ** of the data. And get the length of the data. + */ + offset = pC->nHeader; for(nn=0; nnaType[nn]); } - len = sqlite3VdbeSerialTypeLen(aTypes[p2]); + len = sqlite3VdbeSerialTypeLen(pC->aType[p2]); if( !zRec ){ /* If the record is stored in a table, see if enough of it @@ -2057,12 +2063,10 @@ case OP_Column: { }else{ zData = (char *)sqlite3BtreeDataFetch(pCrsr, offset+len); } - if( !zData && len>0 ){ + if( !zData ){ zData = (char *)sqliteMallocRaw(len); if( !zData ){ - sqliteFree(aTypes); - rc = SQLITE_NOMEM; - goto abort_due_to_error; + goto no_mem; } if( pC->keyAsData ){ rc = sqlite3BtreeKey(pCrsr, offset, len, zData); @@ -2070,7 +2074,6 @@ case OP_Column: { rc = sqlite3BtreeData(pCrsr, offset, len, zData); } if( rc!=SQLITE_OK ){ - sqliteFree( aTypes ); sqliteFree( zData ); goto abort_due_to_error; } @@ -2080,9 +2083,8 @@ case OP_Column: { } /* Deserialize the value directly into the top of the stack */ - sqlite3VdbeSerialGet(&zData[offset], aTypes[p2], pTos); + sqlite3VdbeSerialGet(&zData[offset], pC->aType[p2], pTos); - sqliteFree(aTypes); if( freeZdata ){ sqliteFree(zData); } @@ -2822,6 +2824,7 @@ case OP_MoveTo: { pC->recnoIsValid = 0; } pC->deferredMoveto = 0; + pC->cacheValid = 0; pC->incrKey = 0; sqlite3_search_count++; oc = pOp->opcode; @@ -2899,6 +2902,7 @@ case OP_Found: { rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); alreadyExists = rx==SQLITE_OK && res==0; pC->deferredMoveto = 0; + pC->cacheValid = 0; } if( pOp->opcode==OP_Found ){ if( alreadyExists ) pc = pOp->p2 - 1; @@ -2968,7 +2972,8 @@ case OP_IsUnique: { /* Search for an entry in P1 where all but the last four bytes match K. ** If there is no such entry, jump immediately to P2. */ - assert( p->aCsr[i].deferredMoveto==0 ); + assert( pCx->deferredMoveto==0 ); + pCx->cacheValid = 0; rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; if( res<0 ){ @@ -3025,22 +3030,24 @@ case OP_IsUnique: { */ case OP_NotExists: { int i = pOp->p1; + Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && inCursor ); - if( (pCrsr = p->aCsr[i].pCursor)!=0 ){ + if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){ int res, rx; u64 iKey; assert( pTos->flags & MEM_Int ); assert( p->aCsr[i].intKey ); iKey = intToKey(pTos->i); rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res); - p->aCsr[i].lastRecno = pTos->i; - p->aCsr[i].recnoIsValid = res==0; - p->aCsr[i].nullRow = 0; + pC->lastRecno = pTos->i; + pC->recnoIsValid = res==0; + pC->nullRow = 0; + pC->cacheValid = 0; if( rx!=SQLITE_OK || res!=0 ){ pc = pOp->p2 - 1; - p->aCsr[i].recnoIsValid = 0; + pC->recnoIsValid = 0; } } Release(pTos); @@ -3148,6 +3155,7 @@ case OP_NewRecno: { } pC->recnoIsValid = 0; pC->deferredMoveto = 0; + pC->cacheValid = 0; } pTos++; pTos->i = v; @@ -3249,6 +3257,7 @@ case OP_PutStrKey: { } pC->recnoIsValid = 0; pC->deferredMoveto = 0; + pC->cacheValid = 0; } popStack(&pTos, 2); break; @@ -3278,6 +3287,7 @@ case OP_Delete: { sqlite3VdbeCursorMoveto(pC); rc = sqlite3BtreeDelete(pC->pCursor); pC->nextRowidValid = 0; + pC->cacheValid = 0; } if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++; if( pOp->p2 & OPFLAG_CSCHANGE ) db->csChange++; @@ -3490,6 +3500,7 @@ case OP_Last: { rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = res; pC->deferredMoveto = 0; + pC->cacheValid = 0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } @@ -3519,6 +3530,7 @@ case OP_Rewind: { rc = sqlite3BtreeFirst(pCrsr, &res); pC->atFirst = res==0; pC->deferredMoveto = 0; + pC->cacheValid = 0; }else{ res = 1; } @@ -3562,6 +3574,7 @@ case OP_Next: { rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : sqlite3BtreePrevious(pCrsr, &res); pC->nullRow = res; + pC->cacheValid = 0; } if( res==0 ){ pc = pOp->p2 - 1; @@ -3587,11 +3600,12 @@ case OP_Next: { */ case OP_IdxPut: { int i = pOp->p1; + Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && inCursor ); assert( pTos->flags & MEM_Str ); - if( (pCrsr = p->aCsr[i].pCursor)!=0 ){ + if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){ int nKey = pTos->n; const char *zKey = pTos->z; if( pOp->p2 ){ @@ -3609,7 +3623,7 @@ case OP_IdxPut: { int c; sqlite3BtreeKeySize(pCrsr, &n); if( n==nKey && - sqlite3VdbeIdxKeyCompare(&p->aCsr[i], len, zKey, 0, &c)==SQLITE_OK + sqlite3VdbeIdxKeyCompare(pC, len, zKey, 0, &c)==SQLITE_OK && c==0 ){ rc = SQLITE_CONSTRAINT; @@ -3626,9 +3640,10 @@ case OP_IdxPut: { } } } - assert( p->aCsr[i].intKey==0 ); + assert( pC->intKey==0 ); rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0); - assert( p->aCsr[i].deferredMoveto==0 ); + assert( pC->deferredMoveto==0 ); + pC->cacheValid = 0; } Release(pTos); pTos--; @@ -3642,17 +3657,19 @@ case OP_IdxPut: { */ case OP_IdxDelete: { int i = pOp->p1; + Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( pTos->flags & MEM_Str ); assert( i>=0 && inCursor ); - if( (pCrsr = p->aCsr[i].pCursor)!=0 ){ + if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){ int rx, res; rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res); if( rx==SQLITE_OK && res==0 ){ rc = sqlite3BtreeDelete(pCrsr); } - assert( p->aCsr[i].deferredMoveto==0 ); + assert( pC->deferredMoveto==0 ); + pC->cacheValid = 0; } Release(pTos); pTos--; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index ab89646340..3bd25c0f18 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -78,6 +78,14 @@ struct Cursor { int nData; /* Number of bytes in pData */ char *pData; /* Data for a NEW or OLD pseudo-table */ i64 iKey; /* Key for the NEW or OLD pseudo-table row */ + + /* Cached information about the header for the data record that the + ** cursor is currently pointing to */ + Bool cacheValid; /* True if the cache is valid */ + int nField; /* Number of fields in the header */ + int nHeader; /* Number of bytes in the entire header */ + int payloadSize; /* Total number of bytes in the record */ + u64 *aType; /* Type values for all entries in the record */ }; typedef struct Cursor Cursor; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 11a7ba7e67..297d97f3b9 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -735,6 +735,7 @@ void sqlite3VdbeCleanupCursor(Cursor *pCx){ sqlite3BtreeClose(pCx->pBt); } sqliteFree(pCx->pData); + sqliteFree(pCx->aType); memset(pCx, 0, sizeof(Cursor)); } @@ -1062,6 +1063,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){ } sqlite3_search_count++; p->deferredMoveto = 0; + p->cacheValid = 0; } return SQLITE_OK; } diff --git a/test/limit.test b/test/limit.test index 9f964017b7..157bd759f8 100644 --- a/test/limit.test +++ b/test/limit.test @@ -12,7 +12,7 @@ # focus of this file is testing the LIMIT ... OFFSET ... clause # of SELECT statements. # -# $Id: limit.test,v 1.11 2004/03/08 13:26:18 drh Exp $ +# $Id: limit.test,v 1.12 2004/05/14 21:12:24 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -90,6 +90,7 @@ do_test limit-3.1 { } } {50 51 52 53 54} +btree_breakpoint do_test limit-4.1 { execsql { BEGIN;