]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Cache record headers in the OP_Column opcode. (CVS 1382)
authordrh <drh@noemail.net>
Fri, 14 May 2004 21:12:22 +0000 (21:12 +0000)
committerdrh <drh@noemail.net>
Fri, 14 May 2004 21:12:22 +0000 (21:12 +0000)
FossilOrigin-Name: 8d9eab178f285415775060369f372a88c7091f9f

manifest
manifest.uuid
src/btree.c
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
test/limit.test

index 037c3a5dddc0be330339be10baaf5cb939f14b4e..2eeac7aa21d95c88b504a5e7a44b94ea0138c34a 100644 (file)
--- 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
index a1785d8dd18202ee00221463946cdbbf9857066a..bfb52e9896bdfbf6d136401a0ca5c9e68ec44adb 100644 (file)
@@ -1 +1 @@
-cf75cac9b6bd43e60c6e25042b194ec5c60e5671
\ No newline at end of file
+8d9eab178f285415775060369f372a88c7091f9f
\ No newline at end of file
index 099d4a09e277fdaa029814fcf769a3dd6496f71f..1f81934a2119c603638761c1c35ba6b480fe0ebc 100644 (file)
@@ -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;
index f83e025655d02d40e594bbf1f29161c40d287175..a024cd9ff37281159bcf675105720879a6272cc7 100644 (file)
@@ -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:
-    **
-    **     (<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;
+      /* 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, n);
+      }else{
+        zData = (char *)sqlite3BtreeDataFetch(pCrsr, n);
+      }
+      assert( zData );
     }
-
-    if( pC->keyAsData ){
-      zData = (char *)sqlite3BtreeKeyFetch(pCrsr, max_space);
-    }else{
-      zData = (char *)sqlite3BtreeDataFetch(pCrsr, max_space);
+    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;
+      }
     }
-    if( !zData ){
-      /* This code will run very infrequently (e.g. tables with several
-      ** hundred columns).
+    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 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:
+      **
+      **     (<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. 
       */
-      zData = (char *)sqliteMallocRaw(offset+max_space);
-      if( !zData ){
-        rc = SQLITE_NOMEM;
-        goto abort_due_to_error;
+      int max_space = sqlite3VarintLen((((u64)payloadSize)<<1)+13)*nField;
+      max_space += offset;
+      if( max_space>payloadSize ){
+        max_space = payloadSize;
       }
+
       if( pC->keyAsData ){
-        rc = sqlite3BtreeKey(pCrsr, 0, max_space, zData);
+        zData = (char *)sqlite3BtreeKeyFetch(pCrsr, max_space);
       }else{
-        rc = sqlite3BtreeData(pCrsr, 0, max_space, zData);
+        zData = (char *)sqlite3BtreeDataFetch(pCrsr, max_space);
       }
-      if( rc!=SQLITE_OK ){
-        sqliteFree(zData);
-        goto abort_due_to_error;
+      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;
       }
-      freeZdata = 1;
     }
-  }
 
-  /* 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 ){
+    /* 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 ){
-      sqliteFree(zData);
       freeZdata = 0;
+      sqliteFree(zData);
     }
-    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--;
index ab8964634069d4c41abc55a0677b773a0b6ceb62..3bd25c0f18fb4f19f859d1ad59a28919ebcba542 100644 (file)
@@ -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;
 
index 11a7ba7e67379833d8b95beb44839fa5ed807901..297d97f3b9749d477ec933e104717388e23346af 100644 (file)
@@ -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;
 }
index 9f964017b7cadb31b4e56876ad4dc37cf3a7c3e8..157bd759f862b5b579eacb69596c4e723978fbb1 100644 (file)
@@ -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;