1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Cache record headers in the OP_Column opcode. (CVS 1382)

FossilOrigin-Name: 8d9eab178f285415775060369f372a88c7091f9f
This commit is contained in:
drh
2004-05-14 21:12:22 +00:00
parent fa1a98a24e
commit 9188b38919
7 changed files with 169 additions and 172 deletions

View File

@@ -1,5 +1,5 @@
C More\sspeed\simprovements.\s(CVS\s1381) C Cache\srecord\sheaders\sin\sthe\sOP_Column\sopcode.\s(CVS\s1382)
D 2004-05-14T19:08:18 D 2004-05-14T21:12:23
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -23,7 +23,7 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5 F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
F src/btree.c c263f1f26b28e0ac929b9807bccf50877335c1b8 F src/btree.c 731695f701be37c20146b0aaaf415135f01b6deb
F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050 F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050
F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5 F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
F src/build.c e93f443a20eab57ffb77ff6244b1e09a1f7d9390 F src/build.c e93f443a20eab57ffb77ff6244b1e09a1f7d9390
@@ -63,10 +63,10 @@ F src/update.c 0441f8b64d616ef244583449e66c984e536c6c9b
F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f
F src/util.c f9511ffba78e6cf71a28774c2820d7750b5bacdf F src/util.c f9511ffba78e6cf71a28774c2820d7750b5bacdf
F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476 F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476
F src/vdbe.c fff79c08b3063d8d6f7b600fc6896c255c72238c F src/vdbe.c 90018d7938d36daec5caf3fb4c3833bcd803b061
F src/vdbe.h 94457ca73bae972dc61bca33a4dccc2e6e14e2f8 F src/vdbe.h 94457ca73bae972dc61bca33a4dccc2e6e14e2f8
F src/vdbeInt.h 03f4c3642482570a697a42a9bbb12908c6535bbe F src/vdbeInt.h 6740a3b80d437e9a6b3710aead703690fc0d1ddc
F src/vdbeaux.c 6cf897c49c1fde153d8b9e4c168714207f07cce3 F src/vdbeaux.c 38f924db0aa31c13d556bd65ad129d6f5d8c0a27
F src/where.c 6957bbd333cc7ffa7b3878adbe67a095319daa54 F src/where.c 6957bbd333cc7ffa7b3878adbe67a095319daa54
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83
@@ -102,7 +102,7 @@ F test/join.test 9ef6aabaac9de51d5fc41e68d1f4355da05a84cd
F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8 F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8
F test/lastinsert.test 31382f88b9b0270333ac9e4a17f2c2f4732da718 F test/lastinsert.test 31382f88b9b0270333ac9e4a17f2c2f4732da718
F test/laststmtchanges.test cabd11bdfbaf73a4486c50b58297d9c2038ccc18 F test/laststmtchanges.test cabd11bdfbaf73a4486c50b58297d9c2038ccc18
F test/limit.test e28ce938ddacefdff860d082be45e1e5e2801441 F test/limit.test 94c5dca1e81b7503ce90262ec5a2dc6c4e38d313
F test/lock.test 226ef831dad60ad4d200dc83e25479ba952aac7e F test/lock.test 226ef831dad60ad4d200dc83e25479ba952aac7e
F test/main.test 6a851b5992c4881a725a3d9647e629199df8de9d F test/main.test 6a851b5992c4881a725a3d9647e629199df8de9d
F test/malloc.test 2cfcffb7c858640e01e6520ee1cd54ca57d98e80 F test/malloc.test 2cfcffb7c858640e01e6520ee1cd54ca57d98e80
@@ -191,7 +191,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P d4e0933dc72b66157164610e0b03f339bc535fb9 P cf75cac9b6bd43e60c6e25042b194ec5c60e5671
R 9330d9bd11be003784ef684f1b9c1f25 R 1c44996f87c60027ab5d6785ca9e8bee
U drh U drh
Z 185a62bf4f1e1cc9ef6d8083626f74a6 Z d44c78218fc520c849f4d72442c0d411

View File

@@ -1 +1 @@
cf75cac9b6bd43e60c6e25042b194ec5c60e5671 8d9eab178f285415775060369f372a88c7091f9f

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** 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. ** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to ** 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 ** 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 ** 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. ** itself, not the number of bytes in the key.
*/ */
int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
MemPage *pPage;
unsigned char *cell;
if( !pCur->isValid ){ if( !pCur->isValid ){
*pSize = 0; *pSize = 0;
}else{ }else{
pPage = pCur->pPage; getCellInfo(pCur);
pageIntegrity(pPage); *pSize = pCur->info.nKey;
assert( pPage!=0 );
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
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);
} }
return SQLITE_OK; return SQLITE_OK;
} }
@@ -1499,28 +1502,12 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
** the database is empty) then *pSize is set to 0. ** the database is empty) then *pSize is set to 0.
*/ */
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
MemPage *pPage;
unsigned char *cell;
if( !pCur->isValid ){ if( !pCur->isValid ){
/* Not pointing at a valid entry - set *pSize to 0. */ /* Not pointing at a valid entry - set *pSize to 0. */
*pSize = 0; *pSize = 0;
}else{ }else{
pPage = pCur->pPage; getCellInfo(pCur);
assert( pPage!=0 ); *pSize = pCur->info.nData;
assert( pPage->isInit );
pageIntegrity(pPage);
if( !pPage->hasData ){
*pSize = 0;
}else{
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
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);
}
} }
return SQLITE_OK; return SQLITE_OK;
} }
@@ -1555,16 +1542,7 @@ static int getPayload(
pageIntegrity(pPage); pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
aPayload = pPage->aCell[pCur->idx]; aPayload = pPage->aCell[pCur->idx];
if( !pCur->infoValid ){ getCellInfo(pCur);
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
}
aPayload += pCur->info.nHeader; aPayload += pCur->info.nHeader;
if( pPage->intKey ){ if( pPage->intKey ){
nKey = 0; nKey = 0;
@@ -1703,16 +1681,7 @@ static const unsigned char *fetchPayload(
pageIntegrity(pPage); pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
aPayload = pPage->aCell[pCur->idx]; aPayload = pPage->aCell[pCur->idx];
if( !pCur->infoValid ){ getCellInfo(pCur);
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
}
aPayload += pCur->info.nHeader; aPayload += pCur->info.nHeader;
if( pPage->intKey ){ if( pPage->intKey ){
nKey = 0; nKey = 0;

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** 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 "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -1875,10 +1875,7 @@ case OP_NotNull: {
break; break;
} }
/* Opcode: Column3 P1 P2 * /* Opcode: Column P1 P2 *
**
** This opcode (not yet in use) is a replacement for the current OP_Column3
** that supports the SQLite3 manifest typing feature.
** **
** Interpret the data that cursor P1 points to as a structure built using ** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional ** the MakeRecord instruction. (See the MakeRecord opcode for additional
@@ -1905,8 +1902,7 @@ case OP_Column: {
char *zData; char *zData;
int freeZdata = 0; /* zData requires sqliteFree() */ int freeZdata = 0; /* zData requires sqliteFree() */
u64 nFields; /* number of fields in the record */ u64 nField; /* number of fields in the record */
u64 *aTypes; /* An array of serial types (size nFields) */
int len; /* The length of the serialized data for the column */ int len; /* The length of the serialized data for the column */
int offset; int offset;
@@ -1924,12 +1920,15 @@ case OP_Column: {
assert( pTos[i].flags & MEM_Str ); assert( pTos[i].flags & MEM_Str );
zRec = pTos[i].z; zRec = pTos[i].z;
payloadSize = pTos[i].n; payloadSize = pTos[i].n;
pC->cacheValid = 0;
}else if( (pC = &p->aCsr[i])->pCursor!=0 ){ }else if( (pC = &p->aCsr[i])->pCursor!=0 ){
sqlite3VdbeCursorMoveto(pC); sqlite3VdbeCursorMoveto(pC);
zRec = 0; zRec = 0;
pCrsr = pC->pCursor; pCrsr = pC->pCursor;
if( pC->nullRow ){ if( pC->nullRow ){
payloadSize = 0; payloadSize = 0;
}else if( pC->cacheValid ){
payloadSize = pC->payloadSize;
}else if( pC->keyAsData ){ }else if( pC->keyAsData ){
i64 payloadSize64; i64 payloadSize64;
sqlite3BtreeKeySize(pCrsr, &payloadSize64); sqlite3BtreeKeySize(pCrsr, &payloadSize64);
@@ -1940,6 +1939,7 @@ case OP_Column: {
}else if( pC->pseudoTable ){ }else if( pC->pseudoTable ){
payloadSize = pC->nData; payloadSize = pC->nData;
zRec = pC->pData; zRec = pC->pData;
pC->cacheValid = 0;
assert( payloadSize==0 || zRec!=0 ); assert( payloadSize==0 || zRec!=0 );
}else{ }else{
payloadSize = 0; payloadSize = 0;
@@ -1951,100 +1951,106 @@ case OP_Column: {
break; break;
} }
/* Read the number of fields for the record. /* Read and parse the table header. Store the results of the parse
** FIX ME: The Cursor object should cache this data and the array of ** into the record header cache fields of the cursor.
** field types for subsequent OP_Column instructions.
*/ */
if( zRec ){ if( !pC->cacheValid ){
zData = zRec; pC->payloadSize = payloadSize;
}else{ if( zRec ){
/* We can assume that 9 bytes (maximum length of a varint) fits zData = zRec;
** on the main page in all cases.
*/
if( pC->keyAsData ){
zData = (char *)sqlite3BtreeKeyFetch(pCrsr, 9>payloadSize?payloadSize:9);
}else{ }else{
zData = (char *)sqlite3BtreeDataFetch(pCrsr, 9>payloadSize?payloadSize:9); /* We can assume that 9 bytes (maximum length of a varint) fits
} ** on the main page in all cases.
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:
**
** (<record length> * 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).
*/ */
zData = (char *)sqliteMallocRaw(offset+max_space); int n = 9;
if( !zData ){ if( payloadSize<9 ) n = payloadSize;
rc = SQLITE_NOMEM;
goto abort_due_to_error;
}
if( pC->keyAsData ){ if( pC->keyAsData ){
rc = sqlite3BtreeKey(pCrsr, 0, max_space, zData); zData = (char *)sqlite3BtreeKeyFetch(pCrsr, n);
}else{ }else{
rc = sqlite3BtreeData(pCrsr, 0, max_space, zData); zData = (char *)sqlite3BtreeDataFetch(pCrsr, n);
} }
if( rc!=SQLITE_OK ){ assert( zData );
sqliteFree(zData);
goto abort_due_to_error;
}
freeZdata = 1;
} }
} 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 if( !zRec ){
** the serial types for the record. At the end of this block variable /* If the record is stored in a table, see if enough of it is on
** offset is set to the offset to the start of Data0 in the record. ** the main page to use sqlite3BtreeDataFetch() to get the data
*/ ** containing the nField serial types (varints). This will almost
aTypes = (u64 *)sqliteMallocRaw(sizeof(u64)*nFields); ** always work, but if it doesn't sqliteMalloc() space and use
if( !aTypes ){ ** sqlite3BtreeData().
**
** Estimate the maximum space required by the nField varints by
** assuming the maximum space for each is the length required to store:
**
** (<record length> * 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; nn<nField; nn++){
offset += sqlite3GetVarint(&zData[offset], &pC->aType[nn]);
}
if( freeZdata ){ if( freeZdata ){
sqliteFree(zData);
freeZdata = 0; freeZdata = 0;
sqliteFree(zData);
} }
rc = SQLITE_NOMEM; pC->nHeader = offset;
goto abort_due_to_error; pC->cacheValid = 1;
}
for(nn=0; nn<nFields; nn++){
offset += sqlite3GetVarint(&zData[offset], &aTypes[nn]);
}
if( freeZdata ){
freeZdata = 0;
sqliteFree(zData);
} }
/* 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; nn<p2; nn++){ for(nn=0; nn<p2; nn++){
offset += sqlite3VdbeSerialTypeLen(aTypes[nn]); offset += sqlite3VdbeSerialTypeLen(pC->aType[nn]);
} }
len = sqlite3VdbeSerialTypeLen(aTypes[p2]); len = sqlite3VdbeSerialTypeLen(pC->aType[p2]);
if( !zRec ){ if( !zRec ){
/* If the record is stored in a table, see if enough of it /* If the record is stored in a table, see if enough of it
@@ -2057,12 +2063,10 @@ case OP_Column: {
}else{ }else{
zData = (char *)sqlite3BtreeDataFetch(pCrsr, offset+len); zData = (char *)sqlite3BtreeDataFetch(pCrsr, offset+len);
} }
if( !zData && len>0 ){ if( !zData ){
zData = (char *)sqliteMallocRaw(len); zData = (char *)sqliteMallocRaw(len);
if( !zData ){ if( !zData ){
sqliteFree(aTypes); goto no_mem;
rc = SQLITE_NOMEM;
goto abort_due_to_error;
} }
if( pC->keyAsData ){ if( pC->keyAsData ){
rc = sqlite3BtreeKey(pCrsr, offset, len, zData); rc = sqlite3BtreeKey(pCrsr, offset, len, zData);
@@ -2070,7 +2074,6 @@ case OP_Column: {
rc = sqlite3BtreeData(pCrsr, offset, len, zData); rc = sqlite3BtreeData(pCrsr, offset, len, zData);
} }
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqliteFree( aTypes );
sqliteFree( zData ); sqliteFree( zData );
goto abort_due_to_error; goto abort_due_to_error;
} }
@@ -2080,9 +2083,8 @@ case OP_Column: {
} }
/* Deserialize the value directly into the top of the stack */ /* 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 ){ if( freeZdata ){
sqliteFree(zData); sqliteFree(zData);
} }
@@ -2822,6 +2824,7 @@ case OP_MoveTo: {
pC->recnoIsValid = 0; pC->recnoIsValid = 0;
} }
pC->deferredMoveto = 0; pC->deferredMoveto = 0;
pC->cacheValid = 0;
pC->incrKey = 0; pC->incrKey = 0;
sqlite3_search_count++; sqlite3_search_count++;
oc = pOp->opcode; oc = pOp->opcode;
@@ -2899,6 +2902,7 @@ case OP_Found: {
rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
alreadyExists = rx==SQLITE_OK && res==0; alreadyExists = rx==SQLITE_OK && res==0;
pC->deferredMoveto = 0; pC->deferredMoveto = 0;
pC->cacheValid = 0;
} }
if( pOp->opcode==OP_Found ){ if( pOp->opcode==OP_Found ){
if( alreadyExists ) pc = pOp->p2 - 1; 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. /* 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. ** 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); rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error; if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( res<0 ){ if( res<0 ){
@@ -3025,22 +3030,24 @@ case OP_IsUnique: {
*/ */
case OP_NotExists: { case OP_NotExists: {
int i = pOp->p1; int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
assert( i>=0 && i<p->nCursor ); assert( i>=0 && i<p->nCursor );
if( (pCrsr = p->aCsr[i].pCursor)!=0 ){ if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){
int res, rx; int res, rx;
u64 iKey; u64 iKey;
assert( pTos->flags & MEM_Int ); assert( pTos->flags & MEM_Int );
assert( p->aCsr[i].intKey ); assert( p->aCsr[i].intKey );
iKey = intToKey(pTos->i); iKey = intToKey(pTos->i);
rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res); rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res);
p->aCsr[i].lastRecno = pTos->i; pC->lastRecno = pTos->i;
p->aCsr[i].recnoIsValid = res==0; pC->recnoIsValid = res==0;
p->aCsr[i].nullRow = 0; pC->nullRow = 0;
pC->cacheValid = 0;
if( rx!=SQLITE_OK || res!=0 ){ if( rx!=SQLITE_OK || res!=0 ){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
p->aCsr[i].recnoIsValid = 0; pC->recnoIsValid = 0;
} }
} }
Release(pTos); Release(pTos);
@@ -3148,6 +3155,7 @@ case OP_NewRecno: {
} }
pC->recnoIsValid = 0; pC->recnoIsValid = 0;
pC->deferredMoveto = 0; pC->deferredMoveto = 0;
pC->cacheValid = 0;
} }
pTos++; pTos++;
pTos->i = v; pTos->i = v;
@@ -3249,6 +3257,7 @@ case OP_PutStrKey: {
} }
pC->recnoIsValid = 0; pC->recnoIsValid = 0;
pC->deferredMoveto = 0; pC->deferredMoveto = 0;
pC->cacheValid = 0;
} }
popStack(&pTos, 2); popStack(&pTos, 2);
break; break;
@@ -3278,6 +3287,7 @@ case OP_Delete: {
sqlite3VdbeCursorMoveto(pC); sqlite3VdbeCursorMoveto(pC);
rc = sqlite3BtreeDelete(pC->pCursor); rc = sqlite3BtreeDelete(pC->pCursor);
pC->nextRowidValid = 0; pC->nextRowidValid = 0;
pC->cacheValid = 0;
} }
if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++; if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++;
if( pOp->p2 & OPFLAG_CSCHANGE ) db->csChange++; if( pOp->p2 & OPFLAG_CSCHANGE ) db->csChange++;
@@ -3490,6 +3500,7 @@ case OP_Last: {
rc = sqlite3BtreeLast(pCrsr, &res); rc = sqlite3BtreeLast(pCrsr, &res);
pC->nullRow = res; pC->nullRow = res;
pC->deferredMoveto = 0; pC->deferredMoveto = 0;
pC->cacheValid = 0;
if( res && pOp->p2>0 ){ if( res && pOp->p2>0 ){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
} }
@@ -3519,6 +3530,7 @@ case OP_Rewind: {
rc = sqlite3BtreeFirst(pCrsr, &res); rc = sqlite3BtreeFirst(pCrsr, &res);
pC->atFirst = res==0; pC->atFirst = res==0;
pC->deferredMoveto = 0; pC->deferredMoveto = 0;
pC->cacheValid = 0;
}else{ }else{
res = 1; res = 1;
} }
@@ -3562,6 +3574,7 @@ case OP_Next: {
rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
sqlite3BtreePrevious(pCrsr, &res); sqlite3BtreePrevious(pCrsr, &res);
pC->nullRow = res; pC->nullRow = res;
pC->cacheValid = 0;
} }
if( res==0 ){ if( res==0 ){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
@@ -3587,11 +3600,12 @@ case OP_Next: {
*/ */
case OP_IdxPut: { case OP_IdxPut: {
int i = pOp->p1; int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
assert( i>=0 && i<p->nCursor ); assert( i>=0 && i<p->nCursor );
assert( pTos->flags & MEM_Str ); assert( pTos->flags & MEM_Str );
if( (pCrsr = p->aCsr[i].pCursor)!=0 ){ if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){
int nKey = pTos->n; int nKey = pTos->n;
const char *zKey = pTos->z; const char *zKey = pTos->z;
if( pOp->p2 ){ if( pOp->p2 ){
@@ -3609,7 +3623,7 @@ case OP_IdxPut: {
int c; int c;
sqlite3BtreeKeySize(pCrsr, &n); sqlite3BtreeKeySize(pCrsr, &n);
if( n==nKey && if( n==nKey &&
sqlite3VdbeIdxKeyCompare(&p->aCsr[i], len, zKey, 0, &c)==SQLITE_OK sqlite3VdbeIdxKeyCompare(pC, len, zKey, 0, &c)==SQLITE_OK
&& c==0 && c==0
){ ){
rc = SQLITE_CONSTRAINT; 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); rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0);
assert( p->aCsr[i].deferredMoveto==0 ); assert( pC->deferredMoveto==0 );
pC->cacheValid = 0;
} }
Release(pTos); Release(pTos);
pTos--; pTos--;
@@ -3642,17 +3657,19 @@ case OP_IdxPut: {
*/ */
case OP_IdxDelete: { case OP_IdxDelete: {
int i = pOp->p1; int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
assert( pTos->flags & MEM_Str ); assert( pTos->flags & MEM_Str );
assert( i>=0 && i<p->nCursor ); assert( i>=0 && i<p->nCursor );
if( (pCrsr = p->aCsr[i].pCursor)!=0 ){ if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){
int rx, res; int rx, res;
rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res); rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
if( rx==SQLITE_OK && res==0 ){ if( rx==SQLITE_OK && res==0 ){
rc = sqlite3BtreeDelete(pCrsr); rc = sqlite3BtreeDelete(pCrsr);
} }
assert( p->aCsr[i].deferredMoveto==0 ); assert( pC->deferredMoveto==0 );
pC->cacheValid = 0;
} }
Release(pTos); Release(pTos);
pTos--; pTos--;

View File

@@ -78,6 +78,14 @@ struct Cursor {
int nData; /* Number of bytes in pData */ int nData; /* Number of bytes in pData */
char *pData; /* Data for a NEW or OLD pseudo-table */ char *pData; /* Data for a NEW or OLD pseudo-table */
i64 iKey; /* Key for the NEW or OLD pseudo-table row */ 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; typedef struct Cursor Cursor;

View File

@@ -735,6 +735,7 @@ void sqlite3VdbeCleanupCursor(Cursor *pCx){
sqlite3BtreeClose(pCx->pBt); sqlite3BtreeClose(pCx->pBt);
} }
sqliteFree(pCx->pData); sqliteFree(pCx->pData);
sqliteFree(pCx->aType);
memset(pCx, 0, sizeof(Cursor)); memset(pCx, 0, sizeof(Cursor));
} }
@@ -1062,6 +1063,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
} }
sqlite3_search_count++; sqlite3_search_count++;
p->deferredMoveto = 0; p->deferredMoveto = 0;
p->cacheValid = 0;
} }
return SQLITE_OK; return SQLITE_OK;
} }

View File

@@ -12,7 +12,7 @@
# focus of this file is testing the LIMIT ... OFFSET ... clause # focus of this file is testing the LIMIT ... OFFSET ... clause
# of SELECT statements. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -90,6 +90,7 @@ do_test limit-3.1 {
} }
} {50 51 52 53 54} } {50 51 52 53 54}
btree_breakpoint
do_test limit-4.1 { do_test limit-4.1 {
execsql { execsql {
BEGIN; BEGIN;