aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/btree.c163
-rw-r--r--src/btree.h3
-rw-r--r--src/vdbeblob.c3
3 files changed, 128 insertions, 41 deletions
diff --git a/src/btree.c b/src/btree.c
index 484b52879..c572c1b68 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.365 2007/05/02 13:16:30 danielk1977 Exp $
+** $Id: btree.c,v 1.366 2007/05/02 16:48:37 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -394,6 +394,10 @@ struct BtCursor {
void *pKey; /* Saved key that was cursor's last known position */
i64 nKey; /* Size of pKey, or last integer key */
int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
+#ifndef SQLITE_OMIT_INCRBLOB
+ u8 cacheOverflow; /* True to use aOverflow */
+ Pgno *aOverflow; /* Cache of overflow page locations */
+#endif
};
/*
@@ -691,6 +695,12 @@ static int saveCursorPosition(BtCursor *pCur){
pCur->eState = CURSOR_REQUIRESEEK;
}
+#ifndef SQLITE_OMIT_INCRBLOB
+ /* Delete the cache of overflow page numbers. */
+ sqliteFree(pCur->aOverflow);
+ pCur->aOverflow = 0;
+#endif
+
return rc;
}
@@ -2413,13 +2423,20 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin){
*/
int sqlite3BtreeIncrVacuum(Btree *p){
BtShared *pBt = p->pBt;
+ BtCursor *pCur;
assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE );
if( !pBt->autoVacuum ){
return SQLITE_DONE;
}
-
- return incrVacuumStep(p->pBt, 0);
+#ifndef SQLITE_OMIT_INCRBLOB
+ for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
+ /* Delete the cache of overflow page numbers. */
+ sqliteFree(pCur->aOverflow);
+ pCur->aOverflow = 0;
+ }
+#endif
+ return incrVacuumStep(pBt, 0);
}
/*
@@ -2438,6 +2455,15 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){
int nRef = sqlite3PagerRefcount(pPager);
#endif
+#ifndef SQLITE_OMIT_INCRBLOB
+ BtCursor *pCur;
+ for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
+ /* Delete the cache of overflow page numbers. */
+ sqliteFree(pCur->aOverflow);
+ pCur->aOverflow = 0;
+ }
+#endif
+
assert(pBt->autoVacuum);
if( !pBt->incrVacuum ){
Pgno nFin = 0;
@@ -2933,6 +2959,9 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
}
releasePage(pCur->pPage);
unlockBtreeIfUnused(pBt);
+#ifndef SQLITE_OMIT_INCRBLOB
+ sqliteFree(pCur->aOverflow);
+#endif
sqliteFree(pCur);
return SQLITE_OK;
}
@@ -3132,6 +3161,7 @@ static int getPayload(
BtShared *pBt;
int ovflSize;
u32 nKey;
+ int iIdx = 0;
assert( pCur!=0 && pCur->pPage!=0 );
assert( pCur->eState==CURSOR_VALID );
@@ -3170,7 +3200,21 @@ static int getPayload(
ovflSize = pBt->usableSize - 4;
if( amt>0 ){
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
- while( amt>0 && nextPage ){
+#ifndef SQLITE_OMIT_INCRBLOB
+ if( pCur->cacheOverflow && !pCur->aOverflow ){
+ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
+ pCur->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOvfl);
+ if( nOvfl && !pCur->aOverflow ){
+ return SQLITE_NOMEM;
+ }
+ }
+ if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
+ iIdx = (offset/ovflSize);
+ nextPage = pCur->aOverflow[iIdx];
+ offset = (offset%ovflSize);
+ }
+#endif
+ for(iIdx++; amt>0 && nextPage; iIdx++){
if( offset>=ovflSize ){
/* The only reason to read this page is to obtain the page
** number for the next page in the overflow chain. So try
@@ -3181,6 +3225,12 @@ static int getPayload(
return rc;
}
offset -= ovflSize;
+#ifndef SQLITE_OMIT_INCRBLOB
+ if( pCur->aOverflow ){
+ assert(nextPage);
+ pCur->aOverflow[iIdx] = nextPage;
+ }
+#endif
}else{
/* Need to read this page properly, to obtain data to copy into
** the caller's buffer.
@@ -3201,6 +3251,11 @@ static int getPayload(
amt -= a;
pBuf += a;
sqlite3PagerUnref(pDbPage);
+#ifndef SQLITE_OMIT_INCRBLOB
+ if( pCur->aOverflow && nextPage ){
+ pCur->aOverflow[iIdx] = nextPage;
+ }
+#endif
}
}
}
@@ -6874,6 +6929,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){
u8 *zRem = (u8 *)z; /* Pointer to data not yet written */
u32 iOffset = offset; /* Offset from traversal point to start of write */
+ Pgno iIdx = 0; /* Index of overflow page in pCsr->aOverflow */
Pgno iOvfl; /* Page number for next overflow page */
int ovflSize; /* Bytes of data per overflow page. */
@@ -6908,6 +6964,16 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){
if( pInfo->nData<(offset+amt) ){
return SQLITE_ERROR;
}
+ ovflSize = pBt->usableSize - 4;
+
+ assert(pCsr->cacheOverflow);
+ if( !pCsr->aOverflow ){
+ int nOverflow = (pInfo->nPayload - pInfo->nLocal + ovflSize - 1)/ovflSize;
+ pCsr->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOverflow);
+ if( nOverflow && !pCsr->aOverflow ){
+ return SQLITE_NOMEM;
+ }
+ }
if( pInfo->nLocal>iOffset ){
/* In this case data must be written to the b-tree page. */
@@ -6926,50 +6992,69 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){
}
iOffset = ((iOffset<pInfo->nLocal)?0:(iOffset-pInfo->nLocal));
- ovflSize = pBt->usableSize - 4;
assert(pInfo->iOverflow>0 || iRem==0);
- iOvfl = get4byte(&pInfo->pCell[pInfo->iOverflow]);
- while( iRem>0 ){
- if( iOffset>ovflSize ){
- /* The only reason to read this page is to obtain the page
- ** number for the next page in the overflow chain. So try
- ** the getOverflowPage() shortcut. */
- rc = getOverflowPage(pBt, iOvfl, 0, &iOvfl);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- iOffset -= ovflSize;
+ if( iRem>0 ){
+ if( pCsr->aOverflow[iOffset/ovflSize] ){
+ iIdx = iOffset/ovflSize;
+ iOvfl = pCsr->aOverflow[iIdx];
+ iOffset = iOffset%ovflSize;
}else{
- int iWrite = ovflSize - iOffset;
- DbPage *pOvfl; /* The overflow page. */
- u8 *aData; /* Page data */
-
- rc = sqlite3PagerGet(pBt->pPager, iOvfl, &pOvfl);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- rc = sqlite3PagerWrite(pOvfl);
- if( rc!=SQLITE_OK ){
+ iOvfl = get4byte(&pInfo->pCell[pInfo->iOverflow]);
+ }
+ for(iIdx++; iRem>0; iIdx++){
+ if( iOffset>ovflSize ){
+ /* The only reason to read this page is to obtain the page
+ ** number for the next page in the overflow chain. So try
+ ** the getOverflowPage() shortcut. */
+ rc = getOverflowPage(pBt, iOvfl, 0, &iOvfl);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ iOffset -= ovflSize;
+ pCsr->aOverflow[iIdx] = iOvfl;
+ }else{
+ int iWrite = ovflSize - iOffset;
+ DbPage *pOvfl; /* The overflow page. */
+ u8 *aData; /* Page data */
+
+ rc = sqlite3PagerGet(pBt->pPager, iOvfl, &pOvfl);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ rc = sqlite3PagerWrite(pOvfl);
+ if( rc!=SQLITE_OK ){
+ sqlite3PagerUnref(pOvfl);
+ return rc;
+ }
+
+ aData = sqlite3PagerGetData(pOvfl);
+ iOvfl = get4byte(aData);
+ pCsr->aOverflow[iIdx] = iOvfl;
+ if( iWrite>iRem ){
+ iWrite = iRem;
+ }
+ memcpy(&aData[iOffset+4], zRem, iWrite);
sqlite3PagerUnref(pOvfl);
- return rc;
- }
-
- aData = sqlite3PagerGetData(pOvfl);
- iOvfl = get4byte(aData);
- if( iWrite>iRem ){
- iWrite = iRem;
+
+ zRem += iWrite;
+ iRem -= iWrite;
+ iOffset = ((iOffset<ovflSize)?0:(iOffset-ovflSize));
}
- memcpy(&aData[iOffset+4], zRem, iWrite);
- sqlite3PagerUnref(pOvfl);
-
- zRem += iWrite;
- iRem -= iWrite;
- iOffset = ((iOffset<ovflSize)?0:(iOffset-ovflSize));
}
}
return SQLITE_OK;
}
+
+/*
+** Set a flag on this cursor to cache the locations of pages from the
+** overflow list for the current row.
+*/
+void sqlite3BtreeCacheOverflow(BtCursor *pCur){
+ assert(!pCur->cacheOverflow);
+ assert(!pCur->aOverflow);
+ pCur->cacheOverflow = 1;
+}
#endif
/*
diff --git a/src/btree.h b/src/btree.h
index b3cd58564..69e72e3e7 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
-** @(#) $Id: btree.h,v 1.77 2007/05/02 01:34:31 drh Exp $
+** @(#) $Id: btree.h,v 1.78 2007/05/02 16:48:37 danielk1977 Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
@@ -143,6 +143,7 @@ char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*);
int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, const void*);
+void sqlite3BtreeCacheOverflow(BtCursor *);
#ifdef SQLITE_TEST
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index ddc81b669..711802b9f 100644
--- a/src/vdbeblob.c
+++ b/src/vdbeblob.c
@@ -10,7 +10,7 @@
**
*************************************************************************
**
-** $Id: vdbeblob.c,v 1.1 2007/05/01 17:49:49 danielk1977 Exp $
+** $Id: vdbeblob.c,v 1.2 2007/05/02 16:48:37 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -173,6 +173,7 @@ int sqlite3_blob_open(
}
pBlob->flags = flags;
pBlob->pCsr = v->apCsr[0]->pCursor;
+ sqlite3BtreeCacheOverflow(pBlob->pCsr);
pBlob->pStmt = (sqlite3_stmt *)v;
pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
pBlob->nByte = sqlite3VdbeSerialTypeLen(type);