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:
20
manifest
20
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
|
||||
|
@@ -1 +1 @@
|
||||
cf75cac9b6bd43e60c6e25042b194ec5c60e5671
|
||||
8d9eab178f285415775060369f372a88c7091f9f
|
79
src/btree.c
79
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->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);
|
||||
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->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);
|
||||
}
|
||||
getCellInfo(pCur);
|
||||
*pSize = pCur->info.nData;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -1555,16 +1542,7 @@ static int getPayload(
|
||||
pageIntegrity(pPage);
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
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->idx<pPage->nCell );
|
||||
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;
|
||||
|
127
src/vdbe.c
127
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,33 +1951,44 @@ 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( !pC->cacheValid ){
|
||||
pC->payloadSize = payloadSize;
|
||||
if( zRec ){
|
||||
zData = zRec;
|
||||
}else{
|
||||
/* We can assume that 9 bytes (maximum length of a varint) fits
|
||||
** on the main page in all cases.
|
||||
*/
|
||||
int n = 9;
|
||||
if( payloadSize<9 ) n = payloadSize;
|
||||
if( pC->keyAsData ){
|
||||
zData = (char *)sqlite3BtreeKeyFetch(pCrsr, 9>payloadSize?payloadSize:9);
|
||||
zData = (char *)sqlite3BtreeKeyFetch(pCrsr, n);
|
||||
}else{
|
||||
zData = (char *)sqlite3BtreeDataFetch(pCrsr, 9>payloadSize?payloadSize:9);
|
||||
zData = (char *)sqlite3BtreeDataFetch(pCrsr, n);
|
||||
}
|
||||
assert( zData );
|
||||
}
|
||||
offset = sqlite3GetVarint(zData, &nFields);
|
||||
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;
|
||||
|
||||
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
|
||||
** 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 nFields varints by
|
||||
** 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
|
||||
@@ -1986,7 +1997,7 @@ case OP_Column: {
|
||||
** itself. In all cases the length required to store this is three
|
||||
** bytes or less.
|
||||
*/
|
||||
int max_space = sqlite3VarintLen((((u64)payloadSize)<<1)+13)*nFields;
|
||||
int max_space = sqlite3VarintLen((((u64)payloadSize)<<1)+13)*nField;
|
||||
max_space += offset;
|
||||
if( max_space>payloadSize ){
|
||||
max_space = payloadSize;
|
||||
@@ -2001,10 +2012,9 @@ case OP_Column: {
|
||||
/* This code will run very infrequently (e.g. tables with several
|
||||
** hundred columns).
|
||||
*/
|
||||
zData = (char *)sqliteMallocRaw(offset+max_space);
|
||||
zData = (char *)sqliteMallocRaw(max_space);
|
||||
if( !zData ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto abort_due_to_error;
|
||||
goto no_mem;
|
||||
}
|
||||
if( pC->keyAsData ){
|
||||
rc = sqlite3BtreeKey(pCrsr, 0, max_space, zData);
|
||||
@@ -2019,32 +2029,28 @@ case OP_Column: {
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
/* 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( freeZdata ){
|
||||
sqliteFree(zData);
|
||||
freeZdata = 0;
|
||||
for(nn=0; nn<nField; nn++){
|
||||
offset += sqlite3GetVarint(&zData[offset], &pC->aType[nn]);
|
||||
}
|
||||
rc = SQLITE_NOMEM;
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
for(nn=0; nn<nFields; nn++){
|
||||
offset += sqlite3GetVarint(&zData[offset], &aTypes[nn]);
|
||||
}
|
||||
|
||||
if( freeZdata ){
|
||||
freeZdata = 0;
|
||||
sqliteFree(zData);
|
||||
}
|
||||
pC->nHeader = 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; nn<p2; nn++){
|
||||
offset += sqlite3VdbeSerialTypeLen(aTypes[nn]);
|
||||
offset += sqlite3VdbeSerialTypeLen(pC->aType[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 && i<p->nCursor );
|
||||
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 && i<p->nCursor );
|
||||
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 && i<p->nCursor );
|
||||
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--;
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user