mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Rework accessPayload() function for clarity. (CVS 3912)
FossilOrigin-Name: 42d07c70ec1eb6dd9619c97d753c9d2824aeae32
This commit is contained in:
14
manifest
14
manifest
@@ -1,5 +1,5 @@
|
|||||||
C fix\sfrom\sGentoo\sfor\sallowing\sTCLLIBDIR\sto\sbe\soverridden\sin\senv\s(CVS\s3911)
|
C Rework\saccessPayload()\sfunction\sfor\sclarity.\s(CVS\s3912)
|
||||||
D 2007-05-03T20:06:11
|
D 2007-05-04T08:32:14
|
||||||
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
|
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
|
||||||
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
|
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
|
||||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||||
@@ -59,7 +59,7 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3
|
|||||||
F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651
|
F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651
|
||||||
F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c
|
F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c
|
||||||
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
|
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
|
||||||
F src/btree.c 1f75491c8d5348998ce53decc6fde671d4cfd36d
|
F src/btree.c b88c9265e323b9a55290c39f9712e44050a6162c
|
||||||
F src/btree.h 2c187d60cf76d74c2b4767294d6b5fa267037ff0
|
F src/btree.h 2c187d60cf76d74c2b4767294d6b5fa267037ff0
|
||||||
F src/build.c 02e01ec7907c7d947ab3041fda0e81eaed05db42
|
F src/build.c 02e01ec7907c7d947ab3041fda0e81eaed05db42
|
||||||
F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
|
F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
|
||||||
@@ -473,7 +473,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P 64705410bdf43b6283f7a7e59ce8c20d09cd46e4
|
P e54a49e264ecd54083587f8d3b17cce4c811fddc
|
||||||
R b876dc164a523921b9a9aaaae2c8ff74
|
R 6675084e0bd9661ee80adf52bdde8264
|
||||||
U vapier
|
U danielk1977
|
||||||
Z 4615c64c7ad9754928d4d7f62fcb1f5a
|
Z cda47f0f1385e7692b319bbdf6df8c16
|
||||||
|
@@ -1 +1 @@
|
|||||||
e54a49e264ecd54083587f8d3b17cce4c811fddc
|
42d07c70ec1eb6dd9619c97d753c9d2824aeae32
|
192
src/btree.c
192
src/btree.c
@@ -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.370 2007/05/03 13:11:32 danielk1977 Exp $
|
** $Id: btree.c,v 1.371 2007/05/04 08:32:14 danielk1977 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
|
||||||
@@ -3137,6 +3137,37 @@ static int getOverflowPage(
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copy data from a buffer to a page, or from a page to a buffer.
|
||||||
|
**
|
||||||
|
** pPayload is a pointer to data stored on database page pDbPage.
|
||||||
|
** If argument eOp is false, then nByte bytes of data are copied
|
||||||
|
** from pPayload to the buffer pointed at by pBuf. If eOp is true,
|
||||||
|
** then sqlite3PagerWrite() is called on pDbPage and nByte bytes
|
||||||
|
** of data are copied from the buffer pBuf to pPayload.
|
||||||
|
**
|
||||||
|
** SQLITE_OK is returned on success, otherwise an error code.
|
||||||
|
*/
|
||||||
|
static int copyPayload(
|
||||||
|
void *pPayload, /* Pointer to page data */
|
||||||
|
void *pBuf, /* Pointer to buffer */
|
||||||
|
int nByte, /* Number of bytes to copy */
|
||||||
|
int eOp, /* 0 -> copy from page, 1 -> copy to page */
|
||||||
|
DbPage *pDbPage /* Page containing pPayload */
|
||||||
|
){
|
||||||
|
if( eOp ){
|
||||||
|
/* Copy data from buffer to page (a write operation) */
|
||||||
|
int rc = sqlite3PagerWrite(pDbPage);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
memcpy(pPayload, pBuf, nByte);
|
||||||
|
}else{
|
||||||
|
/* Copy data from page to buffer (a read operation) */
|
||||||
|
memcpy(pBuf, pPayload, nByte);
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This function is used to read or overwrite payload information
|
** This function is used to read or overwrite payload information
|
||||||
@@ -3152,6 +3183,21 @@ static int getOverflowPage(
|
|||||||
** It just reads or writes bytes from the payload area. Data might
|
** It just reads or writes bytes from the payload area. Data might
|
||||||
** appear on the main page or be scattered out on multiple overflow
|
** appear on the main page or be scattered out on multiple overflow
|
||||||
** pages.
|
** pages.
|
||||||
|
**
|
||||||
|
** If the BtCursor.cacheOverflow flag is set, and the current
|
||||||
|
** cursor entry uses one or more overflow pages, this function
|
||||||
|
** allocates space for and lazily popluates the overflow page-list
|
||||||
|
** cache array (BtCursor.aOverflow). Subsequent calls use this
|
||||||
|
** cache to make seeking to the supplied offset more efficient.
|
||||||
|
**
|
||||||
|
** Once an overflow page-list cache has been allocated, it may be
|
||||||
|
** invalidated if some other cursor writes to the same table, or if
|
||||||
|
** the cursor is moved to a different row. Additionally, in auto-vacuum
|
||||||
|
** mode, the following events may invalidate an overflow page-list cache.
|
||||||
|
**
|
||||||
|
** * An incremental vacuum,
|
||||||
|
** * A commit in auto_vacuum="full" mode,
|
||||||
|
** * Creating a table (may require moving an overflow page).
|
||||||
*/
|
*/
|
||||||
#define getPayload(a,b,c,d,e) accessPayload(a,b,c,d,e,0)
|
#define getPayload(a,b,c,d,e) accessPayload(a,b,c,d,e,0)
|
||||||
static int accessPayload(
|
static int accessPayload(
|
||||||
@@ -3163,92 +3209,101 @@ static int accessPayload(
|
|||||||
int eOp /* zero to read. non-zero to write. */
|
int eOp /* zero to read. non-zero to write. */
|
||||||
){
|
){
|
||||||
unsigned char *aPayload;
|
unsigned char *aPayload;
|
||||||
Pgno nextPage;
|
int rc = SQLITE_OK;
|
||||||
int rc;
|
|
||||||
MemPage *pPage;
|
|
||||||
BtShared *pBt;
|
|
||||||
int ovflSize;
|
|
||||||
u32 nKey;
|
u32 nKey;
|
||||||
int iIdx = 0;
|
int iIdx = 0;
|
||||||
|
MemPage *pPage = pCur->pPage; /* Btree page of current cursor entry */
|
||||||
|
BtShared *pBt = pCur->pBtree->pBt; /* Btree this cursor belongs to */
|
||||||
|
|
||||||
assert( pCur!=0 && pCur->pPage!=0 );
|
assert( pPage );
|
||||||
assert( pCur->eState==CURSOR_VALID );
|
assert( pCur->eState==CURSOR_VALID );
|
||||||
pBt = pCur->pBtree->pBt;
|
|
||||||
pPage = pCur->pPage;
|
|
||||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||||
|
assert( offset>=0 );
|
||||||
|
|
||||||
getCellInfo(pCur);
|
getCellInfo(pCur);
|
||||||
aPayload = pCur->info.pCell + pCur->info.nHeader;
|
aPayload = pCur->info.pCell + pCur->info.nHeader;
|
||||||
if( pPage->intKey ){
|
nKey = (pPage->intKey ? 0 : pCur->info.nKey);
|
||||||
nKey = 0;
|
|
||||||
}else{
|
|
||||||
nKey = pCur->info.nKey;
|
|
||||||
}
|
|
||||||
assert( offset>=0 );
|
|
||||||
if( skipKey ){
|
if( skipKey ){
|
||||||
offset += nKey;
|
offset += nKey;
|
||||||
}
|
}
|
||||||
if( offset+amt > nKey+pCur->info.nData ){
|
if( offset+amt > nKey+pCur->info.nData ){
|
||||||
|
/* Trying to read or write past the end of the data is an error */
|
||||||
return SQLITE_ERROR;
|
return SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if data must be read/written to/from the btree page itself. */
|
||||||
if( offset<pCur->info.nLocal ){
|
if( offset<pCur->info.nLocal ){
|
||||||
int a = amt;
|
int a = amt;
|
||||||
if( a+offset>pCur->info.nLocal ){
|
if( a+offset>pCur->info.nLocal ){
|
||||||
a = pCur->info.nLocal - offset;
|
a = pCur->info.nLocal - offset;
|
||||||
}
|
}
|
||||||
if( eOp ){
|
rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
|
||||||
/* A write operation. */
|
|
||||||
rc = sqlite3PagerWrite(pPage->pDbPage);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
memcpy(&aPayload[offset], pBuf, a);
|
|
||||||
}else{
|
|
||||||
/* A read operation */
|
|
||||||
memcpy(pBuf, &aPayload[offset], a);
|
|
||||||
}
|
|
||||||
if( a==amt ){
|
|
||||||
return SQLITE_OK;
|
|
||||||
}
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
pBuf += a;
|
pBuf += a;
|
||||||
amt -= a;
|
amt -= a;
|
||||||
}else{
|
}else{
|
||||||
offset -= pCur->info.nLocal;
|
offset -= pCur->info.nLocal;
|
||||||
}
|
}
|
||||||
ovflSize = pBt->usableSize - 4;
|
|
||||||
if( amt>0 ){
|
if( rc==SQLITE_OK && amt>0 ){
|
||||||
|
const int ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
|
||||||
|
Pgno nextPage;
|
||||||
|
|
||||||
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
|
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_INCRBLOB
|
#ifndef SQLITE_OMIT_INCRBLOB
|
||||||
|
/* If the cacheOverflow flag is set and the BtCursor.aOverflow[]
|
||||||
|
** has not been allocated, allocate it now. The array is sized at
|
||||||
|
** one entry for each overflow page in the overflow chain. The
|
||||||
|
** page number of the first overflow page is stored in aOverflow[0],
|
||||||
|
** etc. A value of 0 in the aOverflow[] array means "not yet known"
|
||||||
|
** (the cache is lazily populated).
|
||||||
|
*/
|
||||||
if( pCur->cacheOverflow && !pCur->aOverflow ){
|
if( pCur->cacheOverflow && !pCur->aOverflow ){
|
||||||
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
|
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
|
||||||
pCur->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOvfl);
|
pCur->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOvfl);
|
||||||
if( nOvfl && !pCur->aOverflow ){
|
if( nOvfl && !pCur->aOverflow ){
|
||||||
return SQLITE_NOMEM;
|
rc = SQLITE_NOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the overflow page-list cache has been allocated and the
|
||||||
|
** entry for the first required overflow page is valid, skip
|
||||||
|
** directly to it.
|
||||||
|
*/
|
||||||
if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
|
if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
|
||||||
iIdx = (offset/ovflSize);
|
iIdx = (offset/ovflSize);
|
||||||
nextPage = pCur->aOverflow[iIdx];
|
nextPage = pCur->aOverflow[iIdx];
|
||||||
offset = (offset%ovflSize);
|
offset = (offset%ovflSize);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
for(iIdx++; amt>0 && nextPage; iIdx++){
|
|
||||||
|
for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_INCRBLOB
|
||||||
|
/* If required, populate the overflow page-list cache. */
|
||||||
|
if( pCur->aOverflow ){
|
||||||
|
assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
|
||||||
|
pCur->aOverflow[iIdx] = nextPage;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if( offset>=ovflSize ){
|
if( offset>=ovflSize ){
|
||||||
/* The only reason to read this page is to obtain the page
|
/* The only reason to read this page is to obtain the page
|
||||||
** number for the next page in the overflow chain. So try
|
** number for the next page in the overflow chain. The page
|
||||||
** the getOverflowPage() shortcut.
|
** data is not required. So first try to lookup the overflow
|
||||||
|
** page-list cache, if any, then fall back to the getOverflowPage()
|
||||||
|
** function.
|
||||||
*/
|
*/
|
||||||
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
offset -= ovflSize;
|
|
||||||
#ifndef SQLITE_OMIT_INCRBLOB
|
#ifndef SQLITE_OMIT_INCRBLOB
|
||||||
if( pCur->aOverflow ){
|
if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){
|
||||||
assert(nextPage);
|
nextPage = pCur->aOverflow[iIdx+1];
|
||||||
pCur->aOverflow[iIdx] = nextPage;
|
} else
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
|
||||||
|
assert(rc==SQLITE_OK || nextPage==0);
|
||||||
|
offset -= ovflSize;
|
||||||
}else{
|
}else{
|
||||||
/* Need to read this page properly. It contains some of the
|
/* Need to read this page properly. It contains some of the
|
||||||
** range of data that is being read (eOp==0) or written (eOp!=0).
|
** range of data that is being read (eOp==0) or written (eOp!=0).
|
||||||
@@ -3256,43 +3311,26 @@ static int accessPayload(
|
|||||||
DbPage *pDbPage;
|
DbPage *pDbPage;
|
||||||
int a = amt;
|
int a = amt;
|
||||||
rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
|
rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
|
||||||
if( rc!=0 ){
|
if( rc==SQLITE_OK ){
|
||||||
return rc;
|
aPayload = sqlite3PagerGetData(pDbPage);
|
||||||
}
|
nextPage = get4byte(aPayload);
|
||||||
aPayload = sqlite3PagerGetData(pDbPage);
|
if( a + offset > ovflSize ){
|
||||||
nextPage = get4byte(aPayload);
|
a = ovflSize - offset;
|
||||||
if( a + offset > ovflSize ){
|
|
||||||
a = ovflSize - offset;
|
|
||||||
}
|
|
||||||
if( eOp ){
|
|
||||||
/* A write operation. */
|
|
||||||
rc = sqlite3PagerWrite(pDbPage);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
sqlite3PagerUnref(pDbPage);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
memcpy(&aPayload[offset+4], pBuf, a);
|
rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
|
||||||
}else{
|
sqlite3PagerUnref(pDbPage);
|
||||||
/* A read operation */
|
offset = 0;
|
||||||
memcpy(pBuf, &aPayload[offset+4], a);
|
amt -= a;
|
||||||
|
pBuf += a;
|
||||||
}
|
}
|
||||||
offset = 0;
|
|
||||||
amt -= a;
|
|
||||||
pBuf += a;
|
|
||||||
sqlite3PagerUnref(pDbPage);
|
|
||||||
#ifndef SQLITE_OMIT_INCRBLOB
|
|
||||||
if( pCur->aOverflow && nextPage ){
|
|
||||||
pCur->aOverflow[iIdx] = nextPage;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( amt>0 ){
|
if( rc==SQLITE_OK && amt>0 ){
|
||||||
return SQLITE_CORRUPT_BKPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
return SQLITE_OK;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -6983,7 +7021,13 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Set a flag on this cursor to cache the locations of pages from the
|
** Set a flag on this cursor to cache the locations of pages from the
|
||||||
** overflow list for the current row.
|
** overflow list for the current row. This is used by cursors opened
|
||||||
|
** for incremental blob IO only.
|
||||||
|
**
|
||||||
|
** This function sets a flag only. The actual page location cache
|
||||||
|
** (stored in BtCursor.aOverflow[]) is allocated and used by function
|
||||||
|
** accessPayload() (the worker function for sqlite3BtreeData() and
|
||||||
|
** sqlite3BtreePutData()).
|
||||||
*/
|
*/
|
||||||
void sqlite3BtreeCacheOverflow(BtCursor *pCur){
|
void sqlite3BtreeCacheOverflow(BtCursor *pCur){
|
||||||
assert(!pCur->cacheOverflow);
|
assert(!pCur->cacheOverflow);
|
||||||
|
Reference in New Issue
Block a user