mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
More btree.c bug fixes. (CVS 1327)
FossilOrigin-Name: e9f84ff3fe45a014ab60fabbfd91d19e6d353477
This commit is contained in:
20
manifest
20
manifest
@ -1,5 +1,5 @@
|
|||||||
C Get\sthe\scode\sback\sto\sthe\spoint\swhere\sit\swill\scompile\sthe\sbtree.c\stests.\nMove\sthe\sdefault\skey\scomparison\sroutine\sfrom\sbtree.c\sinto\svdbeaux.c.\nCommented\sout\scode\sin\svdbe.c\sthat\swill\sneed\sto\sbe\sfixed.\s(CVS\s1326)
|
C More\sbtree.c\sbug\sfixes.\s(CVS\s1327)
|
||||||
D 2004-05-08T10:56:11
|
D 2004-05-08T20:07:40
|
||||||
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,8 +23,8 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f
|
|||||||
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
||||||
F src/attach.c fa9a58234406d84eeb900517d0c0adc4b2da051a
|
F src/attach.c fa9a58234406d84eeb900517d0c0adc4b2da051a
|
||||||
F src/auth.c a2a46e3ed7799134cf3d2dd5ae6650115f26b653
|
F src/auth.c a2a46e3ed7799134cf3d2dd5ae6650115f26b653
|
||||||
F src/btree.c 27600f910e247c905389ecf3f246f27e9649cbea
|
F src/btree.c 26f7caa992e7828db3c045c19a67161150e8ebc4
|
||||||
F src/btree.h 07a16dbb8c29291d0768b956649350d8f8c3dac3
|
F src/btree.h e111dde03373721afbe87e374adf57656c45f0c5
|
||||||
F src/btree_rb.c 47e5b5ec90846af392b5668b34648198ba459561
|
F src/btree_rb.c 47e5b5ec90846af392b5668b34648198ba459561
|
||||||
F src/build.c 21b6645c966970dac51bcccfa8650403a3f56210
|
F src/build.c 21b6645c966970dac51bcccfa8650403a3f56210
|
||||||
F src/copy.c 3c33157f6b4919d6851602b78008c67d466cdadd
|
F src/copy.c 3c33157f6b4919d6851602b78008c67d466cdadd
|
||||||
@ -40,7 +40,7 @@ F src/main.c b6e249c71c3f815d7551ddf1b914f4bb45a4bd67
|
|||||||
F src/md5.c 01d2f55b06316d242749759b6a37186439ef7fe3
|
F src/md5.c 01d2f55b06316d242749759b6a37186439ef7fe3
|
||||||
F src/os.c 4092dcc87e66f49ed660fae1519569a0cee34da0
|
F src/os.c 4092dcc87e66f49ed660fae1519569a0cee34da0
|
||||||
F src/os.h fbb2f6595fc34fa351830d88fe1c6b85118f0383
|
F src/os.h fbb2f6595fc34fa351830d88fe1c6b85118f0383
|
||||||
F src/pager.c 97a675f1653ec2dc2907ebc247b1bae5a4d6ed9a
|
F src/pager.c 350f5cd153b248c67058cafc75c3f1b7d28c2b0b
|
||||||
F src/pager.h 0c95b18f2785b58bfbb2b6f6a221f23caf378687
|
F src/pager.h 0c95b18f2785b58bfbb2b6f6a221f23caf378687
|
||||||
F src/parse.y d0258aa3cc8b0c5742b07b699d10fa98f3caea7d
|
F src/parse.y d0258aa3cc8b0c5742b07b699d10fa98f3caea7d
|
||||||
F src/pragma.c d9f8332a1a87bc4058113ee9686e0c14286d69fd
|
F src/pragma.c d9f8332a1a87bc4058113ee9686e0c14286d69fd
|
||||||
@ -54,7 +54,7 @@ F src/table.c 882b0ae9524c67758157540dd6467c9a5de52335
|
|||||||
F src/tclsqlite.c 21147148e7b57a0bb7409cff5878c60470df9acc
|
F src/tclsqlite.c 21147148e7b57a0bb7409cff5878c60470df9acc
|
||||||
F src/test1.c 67a72fa1f5f6d41c838fa97f324f8dbfb4051413
|
F src/test1.c 67a72fa1f5f6d41c838fa97f324f8dbfb4051413
|
||||||
F src/test2.c 8dab493c7eccd2c7bb93a8e31f7db60f14e61b7b
|
F src/test2.c 8dab493c7eccd2c7bb93a8e31f7db60f14e61b7b
|
||||||
F src/test3.c c5a25235b6b2ada516550eb17b57f8dd002f6b41
|
F src/test3.c e9bb798e010ac44221b9d23ed94f9eb76d7a32a8
|
||||||
F src/test4.c 92d2a10380a65d61e5527a556f604bfde16411e8
|
F src/test4.c 92d2a10380a65d61e5527a556f604bfde16411e8
|
||||||
F src/test5.c eb39aac8fed61bd930b92613cd705c145244074a
|
F src/test5.c eb39aac8fed61bd930b92613cd705c145244074a
|
||||||
F src/tokenize.c 256a3cf0ff938cd79774d7f95173d74281912df9
|
F src/tokenize.c 256a3cf0ff938cd79774d7f95173d74281912df9
|
||||||
@ -75,7 +75,7 @@ F test/auth.test 5c4d95cdaf539c0c236e20ce1f71a93e7dde9185
|
|||||||
F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
|
F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
|
||||||
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
||||||
F test/bind.test 56a57043b42c4664ca705f6050e56717a8a6699a
|
F test/bind.test 56a57043b42c4664ca705f6050e56717a8a6699a
|
||||||
F test/btree.test d9d00f8ac8bfa4945861f92c5b14fbe884d874c4
|
F test/btree.test c26328987d486893282dd25c0cbbeba2cd9b8f95
|
||||||
F test/btree2.test e3b81ec33dc2f89b3e6087436dfe605b870c9080
|
F test/btree2.test e3b81ec33dc2f89b3e6087436dfe605b870c9080
|
||||||
F test/btree3.test e597fb59be2ac0ea69c62aaa2064e998e528b665
|
F test/btree3.test e597fb59be2ac0ea69c62aaa2064e998e528b665
|
||||||
F test/btree3rb.test 127efcf5cdfcc352054e7db12622b01cdd8b36ac
|
F test/btree3rb.test 127efcf5cdfcc352054e7db12622b01cdd8b36ac
|
||||||
@ -190,7 +190,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 1a09a1ada199b76926c64bd79ad39d6d50a75011
|
P 2bca92240b16a51f78661c3ba4d779d231780f8d
|
||||||
R 020d676c42c3c99a03395fc2bd1d45bd
|
R 49eb87c67ff9b6cc18c64077117ae3ba
|
||||||
U drh
|
U drh
|
||||||
Z e3b04ec339a83a6885a62a5e117d1378
|
Z 62f7ad80381b47a4b8e3828b4a596f0a
|
||||||
|
@ -1 +1 @@
|
|||||||
2bca92240b16a51f78661c3ba4d779d231780f8d
|
e9f84ff3fe45a014ab60fabbfd91d19e6d353477
|
122
src/btree.c
122
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.115 2004/05/08 10:56:11 drh Exp $
|
** $Id: btree.c,v 1.116 2004/05/08 20:07:40 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
|
||||||
@ -211,8 +211,6 @@ static const char zMagicHeader[] = "SQLite format 3";
|
|||||||
*/
|
*/
|
||||||
struct MemPage {
|
struct MemPage {
|
||||||
u32 notUsed;
|
u32 notUsed;
|
||||||
struct Btree *pBt; /* Pointer back to BTree structure */
|
|
||||||
unsigned char *aData; /* Pointer back to the start of the page */
|
|
||||||
u8 isInit; /* True if previously initialized */
|
u8 isInit; /* True if previously initialized */
|
||||||
u8 idxShift; /* True if Cell indices have changed */
|
u8 idxShift; /* True if Cell indices have changed */
|
||||||
u8 isOverfull; /* Some aCell[] do not fit on page */
|
u8 isOverfull; /* Some aCell[] do not fit on page */
|
||||||
@ -220,13 +218,16 @@ struct MemPage {
|
|||||||
u8 leaf; /* True if leaf flag is set */
|
u8 leaf; /* True if leaf flag is set */
|
||||||
u8 zeroData; /* True if zero data flag is set */
|
u8 zeroData; /* True if zero data flag is set */
|
||||||
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
|
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
|
||||||
Pgno pgno; /* Page number for this page */
|
|
||||||
MemPage *pParent; /* The parent of this page. NULL for root */
|
|
||||||
int idxParent; /* Index in pParent->aCell[] of this node */
|
int idxParent; /* Index in pParent->aCell[] of this node */
|
||||||
int nFree; /* Number of free bytes on the page */
|
int nFree; /* Number of free bytes on the page */
|
||||||
int nCell; /* Number of entries on this page */
|
int nCell; /* Number of entries on this page */
|
||||||
int nCellAlloc; /* Number of slots allocated in aCell[] */
|
int nCellAlloc; /* Number of slots allocated in aCell[] */
|
||||||
unsigned char **aCell; /* Pointer to start of each cell */
|
unsigned char **aCell; /* Pointer to start of each cell */
|
||||||
|
struct Btree *pBt; /* Pointer back to BTree structure */
|
||||||
|
|
||||||
|
unsigned char *aData; /* Pointer back to the start of the page */
|
||||||
|
Pgno pgno; /* Page number for this page */
|
||||||
|
MemPage *pParent; /* The parent of this page. NULL for root */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -598,13 +599,12 @@ static int initPage(
|
|||||||
assert( pParent==0 || pParent->pBt==pPage->pBt );
|
assert( pParent==0 || pParent->pBt==pPage->pBt );
|
||||||
assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
|
assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
|
||||||
assert( pPage->aData == &((unsigned char*)pPage)[-pPage->pBt->pageSize] );
|
assert( pPage->aData == &((unsigned char*)pPage)[-pPage->pBt->pageSize] );
|
||||||
assert( pPage->isInit==0 || pPage->pParent==pParent );
|
assert( pPage->pParent==0 || pPage->pParent==pParent );
|
||||||
if( pPage->isInit ) return SQLITE_OK;
|
if( pPage->pParent==0 && pParent!=0 ){
|
||||||
assert( pPage->pParent==0 );
|
pPage->pParent = pParent;
|
||||||
pPage->pParent = pParent;
|
|
||||||
if( pParent ){
|
|
||||||
sqlite3pager_ref(pParent->aData);
|
sqlite3pager_ref(pParent->aData);
|
||||||
}
|
}
|
||||||
|
if( pPage->isInit ) return SQLITE_OK;
|
||||||
pPage->nCell = pPage->nCellAlloc = 0;
|
pPage->nCell = pPage->nCellAlloc = 0;
|
||||||
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
|
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
|
||||||
hdr = pPage->hdrOffset;
|
hdr = pPage->hdrOffset;
|
||||||
@ -613,6 +613,8 @@ static int initPage(
|
|||||||
pPage->intKey = (c & PTF_INTKEY)!=0;
|
pPage->intKey = (c & PTF_INTKEY)!=0;
|
||||||
pPage->zeroData = (c & PTF_ZERODATA)!=0;
|
pPage->zeroData = (c & PTF_ZERODATA)!=0;
|
||||||
pPage->leaf = (c & PTF_LEAF)!=0;
|
pPage->leaf = (c & PTF_LEAF)!=0;
|
||||||
|
pPage->isOverfull = 0;
|
||||||
|
pPage->idxShift = 0;
|
||||||
pageSize = pPage->pBt->pageSize;
|
pageSize = pPage->pBt->pageSize;
|
||||||
|
|
||||||
/* Initialize the cell count and cell pointers */
|
/* Initialize the cell count and cell pointers */
|
||||||
@ -667,6 +669,8 @@ static void zeroPage(MemPage *pPage, int flags){
|
|||||||
int hdr = pPage->hdrOffset;
|
int hdr = pPage->hdrOffset;
|
||||||
int first;
|
int first;
|
||||||
|
|
||||||
|
assert( sqlite3pager_pagenumber(data)==pPage->pgno );
|
||||||
|
assert( &data[pBt->pageSize] == (unsigned char*)pPage );
|
||||||
assert( sqlite3pager_iswriteable(data) );
|
assert( sqlite3pager_iswriteable(data) );
|
||||||
memset(&data[hdr], 0, pBt->pageSize - hdr);
|
memset(&data[hdr], 0, pBt->pageSize - hdr);
|
||||||
data[hdr] = flags;
|
data[hdr] = flags;
|
||||||
@ -682,6 +686,9 @@ static void zeroPage(MemPage *pPage, int flags){
|
|||||||
pPage->leaf = (flags & PTF_LEAF)!=0;
|
pPage->leaf = (flags & PTF_LEAF)!=0;
|
||||||
pPage->zeroData = (flags & PTF_ZERODATA)!=0;
|
pPage->zeroData = (flags & PTF_ZERODATA)!=0;
|
||||||
pPage->hdrOffset = hdr;
|
pPage->hdrOffset = hdr;
|
||||||
|
pPage->isOverfull = 0;
|
||||||
|
pPage->idxShift = 0;
|
||||||
|
pPage->isInit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1002,6 +1009,24 @@ static void invalidateCursors(Btree *pBt){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SQLITE_TEST
|
||||||
|
/*
|
||||||
|
** Print debugging information about all cursors to standard output.
|
||||||
|
*/
|
||||||
|
void sqlite3BtreeCursorList(Btree *pBt){
|
||||||
|
BtCursor *pCur;
|
||||||
|
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||||
|
MemPage *pPage = pCur->pPage;
|
||||||
|
char *zMode = pCur->wrFlag ? "rw" : "ro";
|
||||||
|
printf("CURSOR %08x rooted at %4d(%s) currently at %d.%d%s\n",
|
||||||
|
(int)pCur, pCur->pgnoRoot, zMode,
|
||||||
|
pPage ? pPage->pgno : 0, pCur->idx,
|
||||||
|
pCur->isValid ? "" : " eof"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Rollback the transaction in progress. All cursors will be
|
** Rollback the transaction in progress. All cursors will be
|
||||||
** invalided by this operation. Any attempt to use a cursor
|
** invalided by this operation. Any attempt to use a cursor
|
||||||
@ -1536,8 +1561,9 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
|||||||
*/
|
*/
|
||||||
static int isRootPage(MemPage *pPage){
|
static int isRootPage(MemPage *pPage){
|
||||||
MemPage *pParent = pPage->pParent;
|
MemPage *pParent = pPage->pParent;
|
||||||
assert( pParent==0 || pParent->isInit );
|
if( pParent==0 ) return 1;
|
||||||
if( pParent==0 || (pParent->pgno==1 && pParent->nCell==0) ) return 1;
|
if( pParent->pgno>1 ) return 0;
|
||||||
|
if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2310,6 +2336,14 @@ static void relinkCellList(MemPage *pPage){
|
|||||||
put2byte(&pPage->aData[idxFrom], 0);
|
put2byte(&pPage->aData[idxFrom], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** GCC does not define the offsetof() macro so we'll have to do it
|
||||||
|
** ourselves.
|
||||||
|
*/
|
||||||
|
#ifndef offsetof
|
||||||
|
#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Move the content of the page at pFrom over to pTo. The pFrom->aCell[]
|
** Move the content of the page at pFrom over to pTo. The pFrom->aCell[]
|
||||||
** pointers that point into pFrom->aData[] must be adjusted to point
|
** pointers that point into pFrom->aData[] must be adjusted to point
|
||||||
@ -2318,7 +2352,7 @@ static void relinkCellList(MemPage *pPage){
|
|||||||
**
|
**
|
||||||
** Over this operation completes, the meta data for pFrom is zeroed.
|
** Over this operation completes, the meta data for pFrom is zeroed.
|
||||||
*/
|
*/
|
||||||
static void copyPage(MemPage *pTo, MemPage *pFrom){
|
static void movePage(MemPage *pTo, MemPage *pFrom){
|
||||||
uptr from, to;
|
uptr from, to;
|
||||||
int i;
|
int i;
|
||||||
int pageSize;
|
int pageSize;
|
||||||
@ -2326,10 +2360,12 @@ static void copyPage(MemPage *pTo, MemPage *pFrom){
|
|||||||
|
|
||||||
assert( pTo->hdrOffset==0 );
|
assert( pTo->hdrOffset==0 );
|
||||||
ofst = pFrom->hdrOffset;
|
ofst = pFrom->hdrOffset;
|
||||||
pageSize = pTo->pBt->pageSize;
|
pageSize = pFrom->pBt->pageSize;
|
||||||
sqliteFree(pTo->aCell);
|
sqliteFree(pTo->aCell);
|
||||||
memcpy(pTo->aData, &pFrom->aData[ofst], pageSize - ofst + sizeof(MemPage));
|
memcpy(pTo->aData, &pFrom->aData[ofst], pageSize - ofst);
|
||||||
memset(pFrom, 0, sizeof(MemPage));
|
memcpy(pTo, pFrom, offsetof(MemPage, aData));
|
||||||
|
pFrom->isInit = 0;
|
||||||
|
pFrom->aCell = 0;
|
||||||
assert( pTo->aData[5]<155 );
|
assert( pTo->aData[5]<155 );
|
||||||
pTo->aData[5] += ofst;
|
pTo->aData[5] += ofst;
|
||||||
pTo->isOverfull = pFrom->isOverfull;
|
pTo->isOverfull = pFrom->isOverfull;
|
||||||
@ -2408,6 +2444,7 @@ static int balance(MemPage *pPage){
|
|||||||
int usableSpace; /* Bytes in pPage beyond the header */
|
int usableSpace; /* Bytes in pPage beyond the header */
|
||||||
int pageFlags; /* Value of pPage->aData[0] */
|
int pageFlags; /* Value of pPage->aData[0] */
|
||||||
int subtotal; /* Subtotal of bytes in cells on one page */
|
int subtotal; /* Subtotal of bytes in cells on one page */
|
||||||
|
MemPage *extraUnref = 0; /* Unref this page if not zero */
|
||||||
MemPage *apOld[NB]; /* pPage and up to two siblings */
|
MemPage *apOld[NB]; /* pPage and up to two siblings */
|
||||||
Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */
|
Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */
|
||||||
MemPage *apCopy[NB]; /* Private copies of apOld[] pages */
|
MemPage *apCopy[NB]; /* Private copies of apOld[] pages */
|
||||||
@ -2510,15 +2547,17 @@ static int balance(MemPage *pPage){
|
|||||||
rc = allocatePage(pBt, &pChild, &pgnoChild, pPage->pgno);
|
rc = allocatePage(pBt, &pChild, &pgnoChild, pPage->pgno);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
assert( sqlite3pager_iswriteable(pChild->aData) );
|
assert( sqlite3pager_iswriteable(pChild->aData) );
|
||||||
copyPage(pChild, pPage);
|
movePage(pChild, pPage);
|
||||||
|
assert( pChild->aData[0]==pPage->aData[pPage->hdrOffset] );
|
||||||
pChild->pParent = pPage;
|
pChild->pParent = pPage;
|
||||||
pChild->idxParent = 0;
|
|
||||||
sqlite3pager_ref(pPage->aData);
|
sqlite3pager_ref(pPage->aData);
|
||||||
|
pChild->idxParent = 0;
|
||||||
pChild->isOverfull = 1;
|
pChild->isOverfull = 1;
|
||||||
zeroPage(pPage, pPage->aData[pPage->hdrOffset] & ~PTF_LEAF);
|
zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF);
|
||||||
put4byte(&pPage->aData[pPage->hdrOffset+6], pChild->pgno);
|
put4byte(&pPage->aData[pPage->hdrOffset+6], pChild->pgno);
|
||||||
pParent = pPage;
|
pParent = pPage;
|
||||||
pPage = pChild;
|
pPage = pChild;
|
||||||
|
extraUnref = pChild;
|
||||||
}
|
}
|
||||||
rc = sqlite3pager_write(pParent->aData);
|
rc = sqlite3pager_write(pParent->aData);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
@ -2593,10 +2632,11 @@ static int balance(MemPage *pPage){
|
|||||||
** process of being overwritten.
|
** process of being overwritten.
|
||||||
*/
|
*/
|
||||||
for(i=0; i<nOld; i++){
|
for(i=0; i<nOld; i++){
|
||||||
apCopy[i] = (MemPage*)&aCopy[i+1][-sizeof(MemPage)];
|
MemPage *p = apCopy[i] = (MemPage*)&aCopy[i+1][-sizeof(MemPage)];
|
||||||
memset(apCopy[i], 0, sizeof(MemPage));
|
p->aData = &((u8*)p)[-pBt->pageSize];
|
||||||
apCopy[i]->aData = &((u8*)apCopy)[-pBt->pageSize];
|
p->aCell = 0;
|
||||||
copyPage(apCopy[i], apOld[i]);
|
p->hdrOffset = 0;
|
||||||
|
movePage(p, apOld[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2621,11 +2661,12 @@ static int balance(MemPage *pPage){
|
|||||||
nCell++;
|
nCell++;
|
||||||
}
|
}
|
||||||
if( i<nOld-1 ){
|
if( i<nOld-1 ){
|
||||||
szCell[nCell] = cellSize(pParent, apDiv[i]) - leafCorrection;
|
szCell[nCell] = cellSize(pParent, apDiv[i]);
|
||||||
memcpy(aTemp[i], apDiv[i], szCell[nCell] + leafCorrection);
|
memcpy(aTemp[i], apDiv[i], szCell[nCell]);
|
||||||
apCell[nCell] = &aTemp[i][leafCorrection];
|
apCell[nCell] = &aTemp[i][leafCorrection];
|
||||||
dropCell(pParent, nxDiv, szCell[nCell]);
|
dropCell(pParent, nxDiv, szCell[nCell]);
|
||||||
assert( get4byte(&apCell[nCell][2])==pgnoOld[i] );
|
szCell[nCell] -= leafCorrection;
|
||||||
|
assert( get4byte(&aTemp[i][2])==pgnoOld[i] );
|
||||||
if( !pOld->leaf ){
|
if( !pOld->leaf ){
|
||||||
assert( leafCorrection==0 );
|
assert( leafCorrection==0 );
|
||||||
/* The right pointer of the child page pOld becomes the left
|
/* The right pointer of the child page pOld becomes the left
|
||||||
@ -2677,18 +2718,19 @@ static int balance(MemPage *pPage){
|
|||||||
assert( pPage->pgno>1 );
|
assert( pPage->pgno>1 );
|
||||||
pageFlags = pPage->aData[0];
|
pageFlags = pPage->aData[0];
|
||||||
for(i=0; i<k; i++){
|
for(i=0; i<k; i++){
|
||||||
|
MemPage *pNew;
|
||||||
if( i<nOld ){
|
if( i<nOld ){
|
||||||
apNew[i] = apOld[i];
|
pNew = apNew[i] = apOld[i];
|
||||||
pgnoNew[i] = pgnoOld[i];
|
pgnoNew[i] = pgnoOld[i];
|
||||||
apOld[i] = 0;
|
apOld[i] = 0;
|
||||||
sqlite3pager_write(apNew[i]);
|
sqlite3pager_write(pNew->aData);
|
||||||
}else{
|
}else{
|
||||||
rc = allocatePage(pBt, &apNew[i], &pgnoNew[i], pgnoNew[i-1]);
|
rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1]);
|
||||||
if( rc ) goto balance_cleanup;
|
if( rc ) goto balance_cleanup;
|
||||||
|
apNew[i] = pNew;
|
||||||
}
|
}
|
||||||
nNew++;
|
nNew++;
|
||||||
zeroPage(apNew[i], pageFlags);
|
zeroPage(pNew, pageFlags);
|
||||||
apNew[i]->isInit = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free any old pages that were not reused as new pages.
|
/* Free any old pages that were not reused as new pages.
|
||||||
@ -2696,7 +2738,7 @@ static int balance(MemPage *pPage){
|
|||||||
while( i<nOld ){
|
while( i<nOld ){
|
||||||
rc = freePage(apOld[i]);
|
rc = freePage(apOld[i]);
|
||||||
if( rc ) goto balance_cleanup;
|
if( rc ) goto balance_cleanup;
|
||||||
sqlite3pager_unref(apOld[i]->aData);
|
releasePage(apOld[i]);
|
||||||
apOld[i] = 0;
|
apOld[i] = 0;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -2790,7 +2832,10 @@ static int balance(MemPage *pPage){
|
|||||||
/*
|
/*
|
||||||
** balance the parent page.
|
** balance the parent page.
|
||||||
*/
|
*/
|
||||||
|
assert( pPage->isInit );
|
||||||
|
assert( pParent->isInit );
|
||||||
rc = balance(pParent);
|
rc = balance(pParent);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Cleanup before returning.
|
** Cleanup before returning.
|
||||||
@ -2799,7 +2844,6 @@ balance_cleanup:
|
|||||||
for(i=0; i<nOld; i++){
|
for(i=0; i<nOld; i++){
|
||||||
releasePage(apOld[i]);
|
releasePage(apOld[i]);
|
||||||
if( apCopy[i] ){
|
if( apCopy[i] ){
|
||||||
releasePage(apCopy[i]->pParent);
|
|
||||||
sqliteFree(apCopy[i]->aCell);
|
sqliteFree(apCopy[i]->aCell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2807,6 +2851,7 @@ balance_cleanup:
|
|||||||
releasePage(apNew[i]);
|
releasePage(apNew[i]);
|
||||||
}
|
}
|
||||||
releasePage(pParent);
|
releasePage(pParent);
|
||||||
|
releasePage(extraUnref);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2958,6 +3003,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
|||||||
unsigned char *pNext;
|
unsigned char *pNext;
|
||||||
int szNext;
|
int szNext;
|
||||||
int notUsed;
|
int notUsed;
|
||||||
|
unsigned char tempbuf[4];
|
||||||
getTempCursor(pCur, &leafCur);
|
getTempCursor(pCur, &leafCur);
|
||||||
rc = sqlite3BtreeNext(&leafCur, ¬Used);
|
rc = sqlite3BtreeNext(&leafCur, ¬Used);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
@ -2969,10 +3015,12 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
|||||||
dropCell(pPage, pCur->idx, cellSize(pPage, pCell));
|
dropCell(pPage, pCur->idx, cellSize(pPage, pCell));
|
||||||
pNext = leafCur.pPage->aCell[leafCur.idx];
|
pNext = leafCur.pPage->aCell[leafCur.idx];
|
||||||
szNext = cellSize(leafCur.pPage, pNext);
|
szNext = cellSize(leafCur.pPage, pNext);
|
||||||
insertCell(pPage, pCur->idx, &pNext[-4], szNext+4);
|
memcpy(tempbuf, &pNext[-2], 4);
|
||||||
put4byte(&pNext[-2], pgnoChild);
|
put4byte(&pNext[-2], pgnoChild);
|
||||||
|
insertCell(pPage, pCur->idx, &pNext[-4], szNext+4);
|
||||||
rc = balance(pPage);
|
rc = balance(pPage);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
|
memcpy(&pNext[-2], tempbuf, 4);
|
||||||
dropCell(leafCur.pPage, leafCur.idx, szNext);
|
dropCell(leafCur.pPage, leafCur.idx, szNext);
|
||||||
rc = balance(leafCur.pPage);
|
rc = balance(leafCur.pPage);
|
||||||
releaseTempCursor(&leafCur);
|
releaseTempCursor(&leafCur);
|
||||||
@ -3158,7 +3206,7 @@ int sqlite3BtreeUpdateMeta(Btree *pBt, int idx, u32 iMeta){
|
|||||||
int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
|
int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
|
||||||
int rc;
|
int rc;
|
||||||
MemPage *pPage;
|
MemPage *pPage;
|
||||||
int i, j;
|
int i, j, c;
|
||||||
int nFree;
|
int nFree;
|
||||||
u16 idx;
|
u16 idx;
|
||||||
int hdr;
|
int hdr;
|
||||||
@ -3172,6 +3220,10 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
|
|||||||
}
|
}
|
||||||
hdr = pPage->hdrOffset;
|
hdr = pPage->hdrOffset;
|
||||||
data = pPage->aData;
|
data = pPage->aData;
|
||||||
|
c = data[hdr];
|
||||||
|
pPage->intKey = (c & PTF_INTKEY)!=0;
|
||||||
|
pPage->zeroData = (c & PTF_ZERODATA)!=0;
|
||||||
|
pPage->leaf = (c & PTF_LEAF)!=0;
|
||||||
printf("PAGE %d: flags=0x%02x frag=%d\n", pgno,
|
printf("PAGE %d: flags=0x%02x frag=%d\n", pgno,
|
||||||
data[hdr], data[hdr+5]);
|
data[hdr], data[hdr+5]);
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
** subsystem. See comments in the source code for a detailed description
|
** subsystem. See comments in the source code for a detailed description
|
||||||
** of what each interface routine does.
|
** of what each interface routine does.
|
||||||
**
|
**
|
||||||
** @(#) $Id: btree.h,v 1.40 2004/05/08 08:23:23 danielk1977 Exp $
|
** @(#) $Id: btree.h,v 1.41 2004/05/08 20:07:40 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _BTREE_H_
|
#ifndef _BTREE_H_
|
||||||
#define _BTREE_H_
|
#define _BTREE_H_
|
||||||
@ -94,12 +94,10 @@ struct Pager *sqlite3BtreePager(Btree*);
|
|||||||
|
|
||||||
#ifdef SQLITE_TEST
|
#ifdef SQLITE_TEST
|
||||||
int sqlite3BtreeCursorDump(BtCursor*, int*);
|
int sqlite3BtreeCursorDump(BtCursor*, int*);
|
||||||
|
void sqlite3BtreeCursorList(Btree*);
|
||||||
int sqlite3BtreeFlags(BtCursor*);
|
int sqlite3BtreeFlags(BtCursor*);
|
||||||
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif /* _BTREE_H_ */
|
#endif /* _BTREE_H_ */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
26
src/pager.c
26
src/pager.c
@ -18,7 +18,7 @@
|
|||||||
** file simultaneously, or one process from reading the database while
|
** file simultaneously, or one process from reading the database while
|
||||||
** another is writing.
|
** another is writing.
|
||||||
**
|
**
|
||||||
** @(#) $Id: pager.c,v 1.104 2004/05/08 08:23:28 danielk1977 Exp $
|
** @(#) $Id: pager.c,v 1.105 2004/05/08 20:07:40 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "os.h" /* Must be first to enable large file support */
|
#include "os.h" /* Must be first to enable large file support */
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
@ -1115,11 +1115,14 @@ Pgno sqlite3pager_pagenumber(void *pData){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Increment the reference count for a page. If the page is
|
** The page_ref() function increments the reference count for a page.
|
||||||
** currently on the freelist (the reference count is zero) then
|
** If the page is currently on the freelist (the reference count is zero) then
|
||||||
** remove it from the freelist.
|
** remove it from the freelist.
|
||||||
|
**
|
||||||
|
** For non-test systems, page_ref() is a macro that calls _page_ref()
|
||||||
|
** online of the reference count is zero. For test systems, page_ref()
|
||||||
|
** is a real function so that we can set breakpoints and trace it.
|
||||||
*/
|
*/
|
||||||
#define page_ref(P) ((P)->nRef==0?_page_ref(P):(void)(P)->nRef++)
|
|
||||||
static void _page_ref(PgHdr *pPg){
|
static void _page_ref(PgHdr *pPg){
|
||||||
if( pPg->nRef==0 ){
|
if( pPg->nRef==0 ){
|
||||||
/* The page is currently on the freelist. Remove it. */
|
/* The page is currently on the freelist. Remove it. */
|
||||||
@ -1143,6 +1146,18 @@ static void _page_ref(PgHdr *pPg){
|
|||||||
pPg->nRef++;
|
pPg->nRef++;
|
||||||
REFINFO(pPg);
|
REFINFO(pPg);
|
||||||
}
|
}
|
||||||
|
#ifdef SQLITE_TEST
|
||||||
|
static void page_ref(PgHdr *pPg){
|
||||||
|
if( pPg->nRef==0 ){
|
||||||
|
_page_ref(pPg);
|
||||||
|
}else{
|
||||||
|
pPg->nRef++;
|
||||||
|
REFINFO(pPg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define page_ref(P) ((P)->nRef==0?_page_ref(P):(void)(P)->nRef++)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Increment the reference count for a page. The input pointer is
|
** Increment the reference count for a page. The input pointer is
|
||||||
@ -2220,6 +2235,3 @@ void sqlite3pager_refdump(Pager *pPager){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
29
src/test3.c
29
src/test3.c
@ -13,7 +13,7 @@
|
|||||||
** is not included in the SQLite library. It is used for automated
|
** is not included in the SQLite library. It is used for automated
|
||||||
** testing of the SQLite library.
|
** testing of the SQLite library.
|
||||||
**
|
**
|
||||||
** $Id: test3.c,v 1.30 2004/05/08 08:23:39 danielk1977 Exp $
|
** $Id: test3.c,v 1.31 2004/05/08 20:07:40 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
@ -508,6 +508,29 @@ static int btree_integrity_check(
|
|||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Usage: btree_cursor_list ID
|
||||||
|
**
|
||||||
|
** Print information about all cursors to standard output for debugging.
|
||||||
|
*/
|
||||||
|
static int btree_cursor_list(
|
||||||
|
void *NotUsed,
|
||||||
|
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||||
|
int argc, /* Number of arguments */
|
||||||
|
const char **argv /* Text of each argument */
|
||||||
|
){
|
||||||
|
Btree *pBt;
|
||||||
|
|
||||||
|
if( argc!=2 ){
|
||||||
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||||
|
" ID\"", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
|
||||||
|
sqlite3BtreeCursorList(pBt);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: btree_cursor ID TABLENUM WRITEABLE
|
** Usage: btree_cursor ID TABLENUM WRITEABLE
|
||||||
**
|
**
|
||||||
@ -1075,6 +1098,7 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
|
|||||||
{ "btree_first", (Tcl_CmdProc*)btree_first },
|
{ "btree_first", (Tcl_CmdProc*)btree_first },
|
||||||
{ "btree_last", (Tcl_CmdProc*)btree_last },
|
{ "btree_last", (Tcl_CmdProc*)btree_last },
|
||||||
{ "btree_cursor_dump", (Tcl_CmdProc*)btree_cursor_dump },
|
{ "btree_cursor_dump", (Tcl_CmdProc*)btree_cursor_dump },
|
||||||
|
{ "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
|
||||||
{ "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
|
{ "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
|
||||||
{ "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint },
|
{ "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint },
|
||||||
};
|
};
|
||||||
@ -1087,6 +1111,3 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
|
|||||||
TCL_LINK_INT);
|
TCL_LINK_INT);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this script is btree database backend
|
# focus of this script is btree database backend
|
||||||
#
|
#
|
||||||
# $Id: btree.test,v 1.19 2004/05/08 10:56:20 drh Exp $
|
# $Id: btree.test,v 1.20 2004/05/08 20:07:40 drh Exp $
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
@ -827,28 +827,31 @@ do_test btree-10.2 {
|
|||||||
lindex [btree_pager_stats $::b1] 1
|
lindex [btree_pager_stats $::b1] 1
|
||||||
} {2}
|
} {2}
|
||||||
do_test btree-10.3 {
|
do_test btree-10.3 {
|
||||||
for {set i 1} {$i<=20} {incr i} {
|
for {set i 1} {$i<=30} {incr i} {
|
||||||
set key [format %03d $i]
|
set key [format %03d $i]
|
||||||
set data "*** $key *** $key *** $key *** $key ***"
|
set data "*** $key *** $key *** $key *** $key ***"
|
||||||
btree_insert $::c1 $key $data
|
btree_insert $::c1 $key $data
|
||||||
}
|
}
|
||||||
select_keys $::c1
|
select_keys $::c1
|
||||||
} {001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020}
|
} {001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030}
|
||||||
#btree_page_dump $::b1 7
|
#btree_tree_dump $::b1 2
|
||||||
btree_page_dump $::b1 1
|
|
||||||
#btree_page_dump $::b1 6
|
|
||||||
do_test btree-10.4 {
|
do_test btree-10.4 {
|
||||||
btree_move_to $::c1 011
|
# The divider entry is 012. This is found by uncommenting the
|
||||||
|
# btree_tree_dump call above and looking at the tree. If the page size
|
||||||
|
# changes, this test will no longer work.
|
||||||
|
btree_move_to $::c1 012
|
||||||
btree_delete $::c1
|
btree_delete $::c1
|
||||||
select_keys $::c1
|
select_keys $::c1
|
||||||
} {001 002 003 004 005 006 007 008 009 010 012 013 014 015 016 017 018 019 020}
|
} {001 002 003 004 005 006 007 008 009 010 011 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030}
|
||||||
#btree_tree_dump $::b1 2
|
|
||||||
#btree_pager_ref_dump $::b1
|
#btree_pager_ref_dump $::b1
|
||||||
for {set i 1} {$i<=20} {incr i} {
|
#btree_tree_dump $::b1 2
|
||||||
|
for {set i 1} {$i<=30} {incr i} {
|
||||||
|
# Check the number of unreference pages. This should be 3 in most cases,
|
||||||
|
# but 2 when the cursor is pointing to the divider entry which is now 013.
|
||||||
do_test btree-10.5.$i {
|
do_test btree-10.5.$i {
|
||||||
btree_move_to $::c1 [format %03d $i]
|
btree_move_to $::c1 [format %03d $i]
|
||||||
lindex [btree_pager_stats $::b1] 1
|
lindex [btree_pager_stats $::b1] 1
|
||||||
} {2}
|
} [expr {$i==13?2:3}]
|
||||||
#btree_pager_ref_dump $::b1
|
#btree_pager_ref_dump $::b1
|
||||||
#btree_tree_dump $::b1 2
|
#btree_tree_dump $::b1 2
|
||||||
}
|
}
|
||||||
@ -857,18 +860,31 @@ for {set i 1} {$i<=20} {incr i} {
|
|||||||
#
|
#
|
||||||
catch {unset ::data}
|
catch {unset ::data}
|
||||||
catch {unset ::key}
|
catch {unset ::key}
|
||||||
for {set i 21} {$i<=1000} {incr i} {
|
for {set i 31} {$i<=1000} {incr i} {
|
||||||
|
if {$i==88} {
|
||||||
|
set pager_refinfo_enable 1
|
||||||
|
btree_tree_dump $b1 2
|
||||||
|
btree_pager_ref_dump $b1
|
||||||
|
btree_cursor_list $b1
|
||||||
|
}
|
||||||
do_test btree-11.1.$i.1 {
|
do_test btree-11.1.$i.1 {
|
||||||
set key [format %03d $i]
|
set key [format %03d $i]
|
||||||
set ::data "*** $key *** $key *** $key *** $key ***"
|
set ::data "*** $key *** $key *** $key *** $key ***"
|
||||||
btree_insert $::c1 $key $data
|
btree_insert $::c1 $key $data
|
||||||
|
btree_move_to $::c1 $key
|
||||||
btree_key $::c1
|
btree_key $::c1
|
||||||
} [format %03d $i]
|
} [format %03d $i]
|
||||||
|
if {$i==88} {
|
||||||
|
btree_pager_ref_dump $b1
|
||||||
|
btree_cursor_list $b1
|
||||||
|
btree_tree_dump $b1 2
|
||||||
|
exit
|
||||||
|
}
|
||||||
do_test btree-11.1.$i.2 {
|
do_test btree-11.1.$i.2 {
|
||||||
btree_data $::c1
|
btree_data $::c1
|
||||||
} $::data
|
} $::data
|
||||||
set ::key [format %03d [expr {$i/2}]]
|
set ::key [format %03d [expr {$i/2}]]
|
||||||
if {$::key=="011"} {set ::key 010}
|
if {$::key=="012"} {set ::key 013}
|
||||||
do_test btree-11.1.$i.3 {
|
do_test btree-11.1.$i.3 {
|
||||||
btree_move_to $::c1 $::key
|
btree_move_to $::c1 $::key
|
||||||
btree_key $::c1
|
btree_key $::c1
|
||||||
|
Reference in New Issue
Block a user