mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Continued work on btree (CVS 219)
FossilOrigin-Name: 18500cdcc1a42118cdf650681ebb1cbeac106aa7
This commit is contained in:
20
manifest
20
manifest
@@ -1,5 +1,5 @@
|
|||||||
C :-)\s(CVS\s218)
|
C Continued\swork\son\sbtree\s(CVS\s219)
|
||||||
D 2001-05-21T13:45:10
|
D 2001-05-24T21:06:35
|
||||||
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
||||||
F Makefile.in acef0f0275a5ca8e68bda165f7f05d810a207664
|
F Makefile.in acef0f0275a5ca8e68bda165f7f05d810a207664
|
||||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||||
@@ -12,8 +12,8 @@ F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464
|
|||||||
F notes/notes2.txt 49b4d7ba35f183feb1fb098a27272b82f5c76eca
|
F notes/notes2.txt 49b4d7ba35f183feb1fb098a27272b82f5c76eca
|
||||||
F notes/notes3.txt cd5e7bd2167d7ef89b1077abdfa68f0af6337744
|
F notes/notes3.txt cd5e7bd2167d7ef89b1077abdfa68f0af6337744
|
||||||
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
|
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
|
||||||
F src/btree.c bc1525234a8b169cae6f903f9cfacbcf971be942
|
F src/btree.c 5749821afaee09f1cf87b55a4897fd65ed197dd3
|
||||||
F src/btree.h f21c240d0c95f93e2a128106d04a6c448ed0eb94
|
F src/btree.h a0ef90514e16fab863c7825ab22724317894e1ac
|
||||||
F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
|
F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
|
||||||
F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
|
F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
|
||||||
F src/dbbe.h 7235b15c6c5d8be0c4da469cef9620cee70b1cc8
|
F src/dbbe.h 7235b15c6c5d8be0c4da469cef9620cee70b1cc8
|
||||||
@@ -31,8 +31,8 @@ F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7
|
|||||||
F src/expr.c c4c24c3af1eba094a816522eb0e085bed518ee16
|
F src/expr.c c4c24c3af1eba094a816522eb0e085bed518ee16
|
||||||
F src/insert.c aa528e20a787af85432a61daaea6df394bd251d7
|
F src/insert.c aa528e20a787af85432a61daaea6df394bd251d7
|
||||||
F src/main.c 0a13c7a2beb8ce36aee43daf8c95989b200727a7
|
F src/main.c 0a13c7a2beb8ce36aee43daf8c95989b200727a7
|
||||||
F src/pager.c e45946aaf080aed251653f21667d62c89e539a97
|
F src/pager.c debcf7b00e73c031c47ffc12cdeed5cb5f02b761
|
||||||
F src/pager.h ed12ac3ddebd3afe61a0ed4bf530e7846d578e46
|
F src/pager.h e527411d88e31085f07eba6776dc337b8b027921
|
||||||
F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
|
F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
|
||||||
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
|
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
|
||||||
F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a
|
F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a
|
||||||
@@ -64,7 +64,7 @@ F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6
|
|||||||
F test/lock.test bca7d53de73138b1f670a2fbdb1f481ff7eaa45a
|
F test/lock.test bca7d53de73138b1f670a2fbdb1f481ff7eaa45a
|
||||||
F test/main.test da635f9e078cd21ddf074e727381a715064489ff
|
F test/main.test da635f9e078cd21ddf074e727381a715064489ff
|
||||||
F test/malloc.test 3daa97f6a9577d8f4c6e468b274333af19ce5861
|
F test/malloc.test 3daa97f6a9577d8f4c6e468b274333af19ce5861
|
||||||
F test/pager.test c1eb25faa0938f803d1e6eb5201e5e976ea88256
|
F test/pager.test 475835b84cbec423a7dd3d0492b2c8701435d375
|
||||||
F test/printf.test 4c71871e1a75a2dacb673945fc13ddb30168798f
|
F test/printf.test 4c71871e1a75a2dacb673945fc13ddb30168798f
|
||||||
F test/rowid.test 128453599def7435e988216f7fe89c7450b8a9a3
|
F test/rowid.test 128453599def7435e988216f7fe89c7450b8a9a3
|
||||||
F test/select1.test 223507655cdb4f9901d83fa7f5c5328e022c211f
|
F test/select1.test 223507655cdb4f9901d83fa7f5c5328e022c211f
|
||||||
@@ -106,7 +106,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
|
|||||||
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
|
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
|
||||||
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
|
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
|
||||||
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
|
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
|
||||||
P ee6760fb62e81af95796c0fcf1e65e5dc0701194
|
P 523d52dfa6ae3028cbcc88d406501f3ebb6cbd2d
|
||||||
R 6bf7ed657f22039e86c99aa04cca003e
|
R a283ec9b97efb19cc771715467ad06bd
|
||||||
U drh
|
U drh
|
||||||
Z 4c32ca5182d7191fa6afdab861fed35d
|
Z b4b0b3463533c30725394cfe4ae63d4d
|
||||||
|
@@ -1 +1 @@
|
|||||||
523d52dfa6ae3028cbcc88d406501f3ebb6cbd2d
|
18500cdcc1a42118cdf650681ebb1cbeac106aa7
|
351
src/btree.c
351
src/btree.c
@@ -21,7 +21,7 @@
|
|||||||
** http://www.hwaci.com/drh/
|
** http://www.hwaci.com/drh/
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** $Id: btree.c,v 1.6 2001/05/21 13:45:10 drh Exp $
|
** $Id: btree.c,v 1.7 2001/05/24 21:06:35 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
@@ -97,7 +97,7 @@ struct Page1Header {
|
|||||||
/*
|
/*
|
||||||
** Each database page has a header as follows:
|
** Each database page has a header as follows:
|
||||||
**
|
**
|
||||||
** page1_header Extra numbers found on page 1 only.
|
** page1_header Optional instance of Page1Header structure
|
||||||
** rightmost_pgno Page number of the right-most child page
|
** rightmost_pgno Page number of the right-most child page
|
||||||
** first_cell Index into MemPage.aPage of first cell
|
** first_cell Index into MemPage.aPage of first cell
|
||||||
** first_free Index of first free block
|
** first_free Index of first free block
|
||||||
@@ -138,10 +138,11 @@ struct Cell {
|
|||||||
/*
|
/*
|
||||||
** Free space on a page is remembered using a linked list of the FreeBlk
|
** Free space on a page is remembered using a linked list of the FreeBlk
|
||||||
** structures. Space on a database page is allocated in increments of
|
** structures. Space on a database page is allocated in increments of
|
||||||
** at least 4 bytes and is always aligned to a 4-byte boundry.
|
** at least 4 bytes and is always aligned to a 4-byte boundry. The
|
||||||
|
** linked list of freeblocks is always kept in order by address.
|
||||||
*/
|
*/
|
||||||
struct FreeBlk {
|
struct FreeBlk {
|
||||||
u16 iSize; /* Number of u32-sized slots in the block of free space */
|
u16 iSize; /* Number of bytes in this block of free space */
|
||||||
u16 iNext; /* Index in MemPage.aPage[] of the next free block */
|
u16 iNext; /* Index in MemPage.aPage[] of the next free block */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ struct FreeBlk {
|
|||||||
*/
|
*/
|
||||||
struct OverflowPage {
|
struct OverflowPage {
|
||||||
Pgno next;
|
Pgno next;
|
||||||
char aData[SQLITE_PAGE_SIZE-sizeof(Pgno)];
|
char aData[OVERFLOW_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -169,17 +170,21 @@ struct OverflowPage {
|
|||||||
** data is meaningless for overflow pages and pages on the freelist.
|
** data is meaningless for overflow pages and pages on the freelist.
|
||||||
**
|
**
|
||||||
** Of particular interest in the auxiliary data is the aCell[] entry. Each
|
** Of particular interest in the auxiliary data is the aCell[] entry. Each
|
||||||
** aCell[] entry is a pointer to a Cell structure in aPage[]. The cells
|
** aCell[] entry is a pointer to a Cell structure in aPage[]. The cells are
|
||||||
** put in this array so that they can be accessed in constant time, rather
|
** put in this array so that they can be accessed in constant time, rather
|
||||||
** than in linear time which would be needed if we walked the linked list.
|
** than in linear time which would be needed if we walked the linked list.
|
||||||
|
**
|
||||||
|
** The pParent field points back to the parent page. This allows us to
|
||||||
|
** walk up the BTree from any leaf to the root. Care must be taken to
|
||||||
|
** unref() the parent page pointer when this page is no longer referenced.
|
||||||
|
** The pageDestructor() routine handles that.
|
||||||
*/
|
*/
|
||||||
struct MemPage {
|
struct MemPage {
|
||||||
char aPage[SQLITE_PAGE_SIZE]; /* Page data stored on disk */
|
char aPage[SQLITE_PAGE_SIZE]; /* Page data stored on disk */
|
||||||
unsigned char isInit; /* True if auxiliary data is initialized */
|
unsigned char isInit; /* True if auxiliary data is initialized */
|
||||||
unsigned char validUp; /* True if MemPage.up is valid */
|
|
||||||
unsigned char validLeft; /* True if MemPage.left is valid */
|
unsigned char validLeft; /* True if MemPage.left is valid */
|
||||||
unsigned char validRight; /* True if MemPage.right is valid */
|
unsigned char validRight; /* True if MemPage.right is valid */
|
||||||
Pgno up; /* The parent page. 0 means this is the root */
|
MemPage *pParent; /* The parent of this page. NULL for root */
|
||||||
Pgno left; /* Left sibling page. 0==none */
|
Pgno left; /* Left sibling page. 0==none */
|
||||||
Pgno right; /* Right sibling page. 0==none */
|
Pgno right; /* Right sibling page. 0==none */
|
||||||
int idxStart; /* Index in aPage[] of real data */
|
int idxStart; /* Index in aPage[] of real data */
|
||||||
@@ -205,18 +210,18 @@ typedef Btree Bt;
|
|||||||
** The entry is identified by its MemPage and the index in
|
** The entry is identified by its MemPage and the index in
|
||||||
** MemPage.aCell[] of the entry.
|
** MemPage.aCell[] of the entry.
|
||||||
*/
|
*/
|
||||||
struct Cursor {
|
struct BtCursor {
|
||||||
Btree *pBt; /* The pointer back to the BTree */
|
Btree *pBt; /* The pointer back to the BTree */
|
||||||
Cursor *pPrev, *pNext; /* List of all cursors */
|
BtCursor *pPrev, *pNext; /* List of all cursors */
|
||||||
MemPage *pPage; /* Page that contains the entry */
|
MemPage *pPage; /* Page that contains the entry */
|
||||||
int idx; /* Index of the entry in pPage->aCell[] */
|
int idx; /* Index of the entry in pPage->aCell[] */
|
||||||
int skip_incr; /* */
|
int skip_incr; /* */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Defragment the page given. All of the free space
|
** Defragment the page given. All Cells are moved to the
|
||||||
** is collected into one big block at the end of the
|
** beginning of the page and all free space is collected
|
||||||
** page.
|
** into one big FreeBlk at the end of the page.
|
||||||
*/
|
*/
|
||||||
static void defragmentPage(MemPage *pPage){
|
static void defragmentPage(MemPage *pPage){
|
||||||
int pc;
|
int pc;
|
||||||
@@ -238,7 +243,7 @@ static void defragmentPage(MemPage *pPage){
|
|||||||
pPage->aCell[i] = (Cell*)&pPage->aPage[pc];
|
pPage->aCell[i] = (Cell*)&pPage->aPage[pc];
|
||||||
pc += n;
|
pc += n;
|
||||||
}
|
}
|
||||||
assert( pPage->nFree==pc );
|
assert( pPage->nFree==SQLITE_PAGE_SIZE-pc );
|
||||||
memcpy(pPage->aPage, newPage, pc);
|
memcpy(pPage->aPage, newPage, pc);
|
||||||
pFBlk = &pPage->aPage[pc];
|
pFBlk = &pPage->aPage[pc];
|
||||||
pFBlk->iSize = SQLITE_PAGE_SIZE - pc;
|
pFBlk->iSize = SQLITE_PAGE_SIZE - pc;
|
||||||
@@ -255,13 +260,16 @@ static void defragmentPage(MemPage *pPage){
|
|||||||
** Or return 0 if there is not enough free space on the page to
|
** Or return 0 if there is not enough free space on the page to
|
||||||
** satisfy the allocation request.
|
** satisfy the allocation request.
|
||||||
**
|
**
|
||||||
** This routine will call defragmentPage if necessary to consolidate
|
** If the page contains nBytes of free space but does not contain
|
||||||
** free space.
|
** nBytes of contiguous free space, then defragementPage() is
|
||||||
|
** called to consolidate all free space before allocating the
|
||||||
|
** new chunk.
|
||||||
*/
|
*/
|
||||||
static int allocSpace(MemPage *pPage, int nByte){
|
static int allocSpace(MemPage *pPage, int nByte){
|
||||||
FreeBlk *p;
|
FreeBlk *p;
|
||||||
u16 *pIdx;
|
u16 *pIdx;
|
||||||
int start;
|
int start;
|
||||||
|
|
||||||
nByte = ROUNDUP(nByte);
|
nByte = ROUNDUP(nByte);
|
||||||
if( pPage->nFree<nByte ) return 0;
|
if( pPage->nFree<nByte ) return 0;
|
||||||
pIdx = &pPage->pStart->firstFree;
|
pIdx = &pPage->pStart->firstFree;
|
||||||
@@ -279,8 +287,11 @@ static int allocSpace(MemPage *pPage, int nByte){
|
|||||||
start = *pIdx;
|
start = *pIdx;
|
||||||
*pIdx = p->iNext;
|
*pIdx = p->iNext;
|
||||||
}else{
|
}else{
|
||||||
p->iSize -= nByte;
|
start = *pIdx;
|
||||||
start = *pIdx + p->iSize;
|
FreeBlk *pNew = (FreeBlk*)&pPage->aPage[start + nByte];
|
||||||
|
pNew->iNext = p->iNext;
|
||||||
|
pNew->iSize = p->iSize - nByte;
|
||||||
|
*pIdx = start + nByte;
|
||||||
}
|
}
|
||||||
pPage->nFree -= nByte;
|
pPage->nFree -= nByte;
|
||||||
return start;
|
return start;
|
||||||
@@ -335,8 +346,14 @@ static void freeSpace(MemPage *pPage, int start, int size){
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Initialize the auxiliary information for a disk block.
|
** Initialize the auxiliary information for a disk block.
|
||||||
|
**
|
||||||
|
** Return SQLITE_OK on success. If we see that the page does
|
||||||
|
** not contained a well-formed database page, then return
|
||||||
|
** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not
|
||||||
|
** guarantee that the page is well-formed. It only shows that
|
||||||
|
** we failed to detect any corruption.
|
||||||
*/
|
*/
|
||||||
static int initPage(MemPage *pPage, Pgno pgnoThis, Pgno pgnoParent){
|
static int initPage(MemPage *pPage, Pgno pgnoThis, MemPage *pParent){
|
||||||
int idx;
|
int idx;
|
||||||
Cell *pCell;
|
Cell *pCell;
|
||||||
FreeBlk *pFBlk;
|
FreeBlk *pFBlk;
|
||||||
@@ -344,8 +361,9 @@ static int initPage(MemPage *pPage, Pgno pgnoThis, Pgno pgnoParent){
|
|||||||
pPage->idxStart = (pgnoThis==1) ? sizeof(Page1Header) : 0;
|
pPage->idxStart = (pgnoThis==1) ? sizeof(Page1Header) : 0;
|
||||||
pPage->pStart = (PageHdr*)&pPage->aPage[pPage->idxStart];
|
pPage->pStart = (PageHdr*)&pPage->aPage[pPage->idxStart];
|
||||||
pPage->isInit = 1;
|
pPage->isInit = 1;
|
||||||
pPage->validUp = 1;
|
assert( pPage->pParent==0 );
|
||||||
pPage->up = pgnoParent;
|
pPage->pParent = pParent;
|
||||||
|
if( pParent ) sqlitepager_ref(pParent);
|
||||||
pPage->nCell = 0;
|
pPage->nCell = 0;
|
||||||
idx = pPage->pStart->firstCell;
|
idx = pPage->pStart->firstCell;
|
||||||
while( idx!=0 ){
|
while( idx!=0 ){
|
||||||
@@ -371,12 +389,26 @@ page_format_error:
|
|||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine is called when the reference count for a page
|
||||||
|
** reaches zero. We need to unref the pParent pointer when that
|
||||||
|
** happens.
|
||||||
|
*/
|
||||||
|
static void pageDestructor(void *pData){
|
||||||
|
MemPage *pPage = (MemPage*)pData;
|
||||||
|
if( pPage->pParent ){
|
||||||
|
MemPage *pParent = pPage->pParent;
|
||||||
|
pPage->pParent = 0;
|
||||||
|
sqlitepager_unref(pParent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Open a new database.
|
** Open a new database.
|
||||||
**
|
**
|
||||||
** Actually, this routine just sets up the internal data structures
|
** Actually, this routine just sets up the internal data structures
|
||||||
** for accessing the database. We do not actually open the database
|
** for accessing the database. We do not open the database file
|
||||||
** file until the first page is loaded.
|
** until the first page is loaded.
|
||||||
*/
|
*/
|
||||||
int sqliteBtreeOpen(const char *zFilename, int mode, Btree **ppBtree){
|
int sqliteBtreeOpen(const char *zFilename, int mode, Btree **ppBtree){
|
||||||
Btree *pBt;
|
Btree *pBt;
|
||||||
@@ -393,6 +425,7 @@ int sqliteBtreeOpen(const char *zFilename, int mode, Btree **ppBtree){
|
|||||||
*ppBtree = 0;
|
*ppBtree = 0;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
sqlitepager_set_destructor(pBt->pPager, pageDestructor);
|
||||||
pBt->pCursor = 0;
|
pBt->pCursor = 0;
|
||||||
pBt->page1 = 0;
|
pBt->page1 = 0;
|
||||||
*ppBtree = pBt;
|
*ppBtree = pBt;
|
||||||
@@ -427,7 +460,7 @@ static int lockBtree(Btree *pBt){
|
|||||||
rc = sqlitepager_get(pBt->pPager, 1, &pBt->page1);
|
rc = sqlitepager_get(pBt->pPager, 1, &pBt->page1);
|
||||||
if( rc!=SQLITE_OK ) return rc;
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
rc = initPage(pBt->page1, 1, 0);
|
rc = initPage(pBt->page1, 1, 0);
|
||||||
if( rc!=SQLITE_OK ) goto lock_failed;
|
if( rc!=SQLITE_OK ) goto page1_init_failed;
|
||||||
|
|
||||||
/* Do some checking to help insure the file we opened really is
|
/* Do some checking to help insure the file we opened really is
|
||||||
** a valid database file.
|
** a valid database file.
|
||||||
@@ -436,21 +469,23 @@ static int lockBtree(Btree *pBt){
|
|||||||
Page1Header *pP1 = (Page1Header*)pBt->page1;
|
Page1Header *pP1 = (Page1Header*)pBt->page1;
|
||||||
if( pP1->magic1!=MAGIC_1 || pP1->magic2!=MAGIC_2 ){
|
if( pP1->magic1!=MAGIC_1 || pP1->magic2!=MAGIC_2 ){
|
||||||
rc = SQLITE_CORRUPT;
|
rc = SQLITE_CORRUPT;
|
||||||
goto lock_failed;
|
goto page1_init_failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
lock_failed:
|
page1_init_failed:
|
||||||
sqlitepager_unref(pBt->page1);
|
sqlitepager_unref(pBt->page1);
|
||||||
pBt->page1 = 0;
|
pBt->page1 = 0;
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Start a new transaction
|
** Attempt to start a new transaction.
|
||||||
*/
|
*/
|
||||||
int sqliteBtreeBeginTrans(Btree *pBt){
|
int sqliteBtreeBeginTrans(Btree *pBt){
|
||||||
int rc;
|
int rc;
|
||||||
|
Page1Header *pP1;
|
||||||
if( pBt->inTrans ) return SQLITE_ERROR;
|
if( pBt->inTrans ) return SQLITE_ERROR;
|
||||||
if( pBt->page1==0 ){
|
if( pBt->page1==0 ){
|
||||||
rc = lockBtree(pBt);
|
rc = lockBtree(pBt);
|
||||||
@@ -460,6 +495,11 @@ int sqliteBtreeBeginTrans(Btree *pBt){
|
|||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
pBt->inTrans = 1;
|
pBt->inTrans = 1;
|
||||||
}
|
}
|
||||||
|
pP1 = (Page1Header*)pBt->page1;
|
||||||
|
if( pP1->magic1==0 ){
|
||||||
|
pP1->magic1 = MAGIC_1;
|
||||||
|
pP1->magic2 = MAGIC_2;
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,7 +521,7 @@ static void unlockBtree(Btree *pBt){
|
|||||||
*/
|
*/
|
||||||
int sqliteBtreeCommit(Btree *pBt){
|
int sqliteBtreeCommit(Btree *pBt){
|
||||||
int rc;
|
int rc;
|
||||||
assert( pBt->pCursor==0 );
|
if( pBt->pCursor!=0 ) return SQLITE_ERROR;
|
||||||
rc = sqlitepager_commit(pBt->pPager);
|
rc = sqlitepager_commit(pBt->pPager);
|
||||||
unlockBtree(pBt);
|
unlockBtree(pBt);
|
||||||
return rc;
|
return rc;
|
||||||
@@ -493,7 +533,7 @@ int sqliteBtreeCommit(Btree *pBt){
|
|||||||
*/
|
*/
|
||||||
int sqliteBtreeRollback(Btree *pBt){
|
int sqliteBtreeRollback(Btree *pBt){
|
||||||
int rc;
|
int rc;
|
||||||
assert( pBt->pCursor==0 );
|
if( pBt->pCursor!=0 ) return SQLITE_ERROR;
|
||||||
rc = sqlitepager_rollback(pBt->pPager);
|
rc = sqlitepager_rollback(pBt->pPager);
|
||||||
unlockBtree(pBt);
|
unlockBtree(pBt);
|
||||||
return rc;
|
return rc;
|
||||||
@@ -533,9 +573,11 @@ int sqliteBtreeCursor(Btree *pBt, BtCursor **ppCur){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
if( !pCur->pPage->isInit ){
|
if( !pCur->pPage->isInit ){
|
||||||
initPage(pCur->pPage);
|
initPage(pCur->pPage, 1, 0);
|
||||||
}
|
}
|
||||||
pCur->idx = 0;
|
pCur->idx = 0;
|
||||||
|
pCur->depth = 0;
|
||||||
|
pCur->aPage[0] = pCur->pPage;
|
||||||
*ppCur = pCur;
|
*ppCur = pCur;
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
@@ -562,23 +604,38 @@ int sqliteBtreeCloseCursor(BtCursor *pCur){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return the number of bytes in the key of the entry to which
|
** Write the number of bytes of key for the entry the cursor is
|
||||||
** the cursor is currently point. If the cursor has not been
|
** pointing to into *pSize. Return SQLITE_OK. Failure is not
|
||||||
** initialized or is pointed to a deleted entry, then return 0.
|
** possible.
|
||||||
*/
|
*/
|
||||||
int sqliteBtreeKeySize(BtCursor *pCur){
|
int sqliteBtreeKeySize(BtCursor *pCur, int *pSize){
|
||||||
Cell *pCell;
|
Cell *pCell;
|
||||||
MemPage *pPage;
|
MemPage *pPage;
|
||||||
|
|
||||||
pPage = pCur->pPage;
|
pPage = pCur->pPage;
|
||||||
if( pCur->idx >= pPage->nCell ) return 0;
|
assert( pPage!=0 );
|
||||||
|
if( pCur->idx >= pPage->nCell ){
|
||||||
|
*pSize = 0;
|
||||||
|
}else{
|
||||||
pCell = pPage->aCell[pCur->idx];
|
pCell = pPage->aCell[pCur->idx];
|
||||||
return pCell->nKey;
|
*psize = pCell->nKey;
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Read payload information from the entry that the pCur cursor is
|
||||||
|
** pointing to. Begin reading the payload at "offset" and read
|
||||||
|
** a total of "amt" bytes. Put the result in zBuf.
|
||||||
|
**
|
||||||
|
** This routine does not make a distinction between key and data.
|
||||||
|
** It just reads bytes from the payload area.
|
||||||
|
*/
|
||||||
static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){
|
static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){
|
||||||
char *aData;
|
char *aData;
|
||||||
Pgno nextPage;
|
Pgno nextPage;
|
||||||
|
assert( pCur!=0 && pCur->pPage!=0 );
|
||||||
|
assert( pCur->idx>=0 && pCur->idx<pCur->nCell );
|
||||||
aData = pCur->pPage->aCell[pCur->idx].aData;
|
aData = pCur->pPage->aCell[pCur->idx].aData;
|
||||||
if( offset<MX_LOCAL_PAYLOAD ){
|
if( offset<MX_LOCAL_PAYLOAD ){
|
||||||
int a = amt;
|
int a = amt;
|
||||||
@@ -619,10 +676,73 @@ static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){
|
|||||||
return amt==0 ? SQLITE_OK : SQLITE_CORRUPT;
|
return amt==0 ? SQLITE_OK : SQLITE_CORRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sqliteBtreeKey(BtCursor*, int offset, int amt, char *zBuf);
|
/*
|
||||||
int sqliteBtreeDataSize(BtCursor*);
|
** Read part of the key associated with cursor pCur. A total
|
||||||
int sqliteBtreeData(BtCursor*, int offset, int amt, char *zBuf);
|
** of "amt" bytes will be transfered into zBuf[]. The transfer
|
||||||
|
** begins at "offset". If the key does not contain enough data
|
||||||
|
** to satisfy the request, no data is fetched and this routine
|
||||||
|
** returns SQLITE_ERROR.
|
||||||
|
*/
|
||||||
|
int sqliteBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){
|
||||||
|
Cell *pCell;
|
||||||
|
MemPage *pPage;
|
||||||
|
|
||||||
|
if( amt<0 ) return SQLITE_ERROR;
|
||||||
|
if( offset<0 ) return SQLITE_ERROR;
|
||||||
|
if( amt==0 ) return SQLITE_OK;
|
||||||
|
pPage = pCur->pPage;
|
||||||
|
assert( pPage!=0 );
|
||||||
|
if( pCur->idx >= pPage->nCell ){
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
pCell = pPage->aCell[pCur->idx];
|
||||||
|
if( amt+offset > pCell->nKey ){
|
||||||
|
return getPayload(pCur, offset, amt, zBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Write the number of bytes of data on the entry that the cursor
|
||||||
|
** is pointing to into *pSize. Return SQLITE_OK. Failure is
|
||||||
|
** not possible.
|
||||||
|
*/
|
||||||
|
int sqliteBtreeDataSize(BtCursor *pCur, int *pSize){
|
||||||
|
Cell *pCell;
|
||||||
|
MemPage *pPage;
|
||||||
|
|
||||||
|
pPage = pCur->pPage;
|
||||||
|
assert( pPage!=0 );
|
||||||
|
if( pCur->idx >= pPage->nCell ){
|
||||||
|
*pSize = 0;
|
||||||
|
}else{
|
||||||
|
pCell = pPage->aCell[pCur->idx];
|
||||||
|
*pSize = pCell->nData;
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Read part of the data associated with cursor pCur. A total
|
||||||
|
** of "amt" bytes will be transfered into zBuf[]. The transfer
|
||||||
|
** begins at "offset". If the size of the data in the record
|
||||||
|
** is insufficent to satisfy this request then no data is read
|
||||||
|
** and this routine returns SQLITE_ERROR.
|
||||||
|
*/
|
||||||
|
int sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){
|
||||||
|
Cell *pCell;
|
||||||
|
MemPage *pPage;
|
||||||
|
|
||||||
|
if( amt<0 ) return SQLITE_ERROR;
|
||||||
|
if( offset<0 ) return SQLITE_ERROR;
|
||||||
|
if( amt==0 ) return SQLITE_OK;
|
||||||
|
pPage = pCur->pPage;
|
||||||
|
assert( pPage!=0 );
|
||||||
|
if( pCur->idx >= pPage->nCell ){
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
pCell = pPage->aCell[pCur->idx];
|
||||||
|
if( amt+offset > pCell->nKey ){
|
||||||
|
return getPayload(pCur, offset + pCell->nKey, amt, zBuf);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Compare the key for the entry that pCur points to against the
|
** Compare the key for the entry that pCur points to against the
|
||||||
@@ -665,7 +785,7 @@ static int compareKey(BtCursor *pCur, char *pKey, int nKeyOrig, int *pResult){
|
|||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT;
|
||||||
}
|
}
|
||||||
rc = sqlitepager_get(pCur->pBt->pPager, nextPage, &pOvfl);
|
rc = sqlitepager_get(pCur->pBt->pPager, nextPage, &pOvfl);
|
||||||
if( rc!=0 ){
|
if( rc ){
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
nextPage = pOvfl->next;
|
nextPage = pOvfl->next;
|
||||||
@@ -687,13 +807,152 @@ static int compareKey(BtCursor *pCur, char *pKey, int nKeyOrig, int *pResult){
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Move the cursor down to a new child page.
|
||||||
|
*/
|
||||||
|
static int childPage(BtCursor *pCur, int newPgno){
|
||||||
|
int rc;
|
||||||
|
MemPage *pNewPage;
|
||||||
|
|
||||||
|
rc = sqlitepager_get(pCur->pBt->pPager, newPgno, &pNewPage);
|
||||||
|
if( rc ){
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
if( !pNewPage->isInit ){
|
||||||
|
initPage(pNewPage, newPgno, pCur->pPage);
|
||||||
|
}
|
||||||
|
sqlitepager_unref(pCur->pPage);
|
||||||
|
pCur->pPage = pNewPage;
|
||||||
|
pCur->idx = 0;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Move the cursor up to the parent page
|
||||||
|
*/
|
||||||
|
static int parentPage(BtCursor *pCur){
|
||||||
|
Pgno oldPgno;
|
||||||
|
MemPage *pParent;
|
||||||
|
|
||||||
|
pParent = pCur->pPage->pParent;
|
||||||
|
oldPgno = sqlitepager_pagenumber(pCur->pPage);
|
||||||
|
if( pParent==0 ){
|
||||||
|
return SQLITE_INTERNAL;
|
||||||
|
}
|
||||||
|
sqlitepager_ref(pParent);
|
||||||
|
sqlitepager_unref(pCur->pPage);
|
||||||
|
pCur->pPage = pParent;
|
||||||
|
pCur->idx = pPage->nCell;
|
||||||
|
for(i=0; i<pPage->nCell; i++){
|
||||||
|
if( pPage->aCell[i].pgno==oldPgno ){
|
||||||
|
pCur->idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Move the cursor to the root page
|
||||||
|
*/
|
||||||
|
static int rootPage(BtCursor *pCur){
|
||||||
|
MemPage *pNew;
|
||||||
|
pNew = pCur->pBt->page1;
|
||||||
|
sqlitepager_ref(pNew);
|
||||||
|
sqlitepager_unref(pCur->pPage);
|
||||||
|
pCur->pPage = pNew;
|
||||||
|
pCur->idx = 0;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* Move the cursor so that it points to an entry near pKey.
|
/* Move the cursor so that it points to an entry near pKey.
|
||||||
** Return 0 if the cursor is left pointing exactly at pKey.
|
** Return a success code.
|
||||||
** Return -1 if the cursor points to the largest entry less than pKey.
|
**
|
||||||
** Return 1 if the cursor points to the smallest entry greater than pKey.
|
** If pRes!=NULL, then *pRes is written with an integer code to
|
||||||
|
** describe the results. *pRes is set to 0 if the cursor is left
|
||||||
|
** pointing at an entry that exactly matches pKey. *pRes is made
|
||||||
|
** negative if the cursor is on the largest entry less than pKey.
|
||||||
|
** *pRes is set positive if the cursor is on the smallest entry
|
||||||
|
** greater than pKey. *pRes is not changed if the return value
|
||||||
|
** is something other than SQLITE_OK;
|
||||||
*/
|
*/
|
||||||
int sqliteBtreeMoveto(BtCursor*, void *pKey, int nKey);
|
int sqliteBtreeMoveto(BtCursor *pCur, void *pKey, int nKey, int *pRes){
|
||||||
int sqliteBtreeDelete(BtCursor*);
|
int rc;
|
||||||
|
rc = rootPage(pCur);
|
||||||
|
if( rc ) return rc;
|
||||||
|
for(;;){
|
||||||
|
int lwr, upr;
|
||||||
|
Pgno chldPg;
|
||||||
|
MemPage *pPage = pCur->pPage;
|
||||||
|
lwr = 0;
|
||||||
|
upr = pPage->nCell-1;
|
||||||
|
while( lwr<=upr ){
|
||||||
|
int c;
|
||||||
|
pCur->idx = (lwr+upr)/2;
|
||||||
|
rc = compareKey(pCur, pKey, nKey, &c);
|
||||||
|
if( rc ) return rc;
|
||||||
|
if( c==0 ){
|
||||||
|
if( pRes ) *pRes = 0;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
if( c<0 ){
|
||||||
|
lwr = pCur->idx+1;
|
||||||
|
}else{
|
||||||
|
upr = pCur->idx-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert( lwr==upr+1 );
|
||||||
|
if( lwr>=pPage->nCell ){
|
||||||
|
chldPg = pPage->pStart->pgno;
|
||||||
|
}else{
|
||||||
|
chldPg = pPage->aCell[lwr].pgno;
|
||||||
|
}
|
||||||
|
if( chldPg==0 ){
|
||||||
|
if( pRes ) *pRes = c;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
rc = childPage(pCur, chldPg);
|
||||||
|
if( rc ) return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Advance the cursor to the next entry in the database. If pRes!=NULL
|
||||||
|
** then set *pRes=0 on success and set *pRes=1 if the cursor was
|
||||||
|
** pointing to the last entry in the database.
|
||||||
|
*/
|
||||||
|
int sqliteBtreeNext(BtCursor *pCur, int *pRes){
|
||||||
|
MemPage *pPage;
|
||||||
|
int rc;
|
||||||
|
int moved = 0;
|
||||||
|
if( pCur->skip_next ){
|
||||||
|
pCur->skip_next = 0;
|
||||||
|
if( pRes ) *pRes = 0;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
pPage = pCur->pPage;
|
||||||
|
pCur->idx++;
|
||||||
|
while( pCur->idx>=pPage->nCell ){
|
||||||
|
if( pCur->depth==0 ){
|
||||||
|
if( pRes ) *pRes = 1;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
rc = parentPage(pCur);
|
||||||
|
if( rc ) return rc;
|
||||||
|
moved = 1;
|
||||||
|
pPage = pCur->pPage;
|
||||||
|
}
|
||||||
|
if( moved ){
|
||||||
|
if( pRes ) *pRes = 0;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
while( pCur->idx<pPage->nCell && pPage->aCell[pCur->idx].pgno>0 ){
|
||||||
|
rc = childPage(pCur, pPage->aCell[pCur->idx].pgno);
|
||||||
|
if( rc ) return rc;
|
||||||
|
pPage = pCur->pPage;
|
||||||
|
}
|
||||||
|
if( pRes ) *pRes = 0;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
int sqliteBtreeInsert(BtCursor*, void *pKey, int nKey, void *pData, int nData);
|
int sqliteBtreeInsert(BtCursor*, void *pKey, int nKey, void *pData, int nData);
|
||||||
int sqliteBtreeNext(BtCursor*);
|
int sqliteBtreeDelete(BtCursor*);
|
||||||
|
16
src/btree.h
16
src/btree.h
@@ -24,7 +24,7 @@
|
|||||||
** This header file defines the interface that the sqlite B-Tree file
|
** This header file defines the interface that the sqlite B-Tree file
|
||||||
** subsystem.
|
** subsystem.
|
||||||
**
|
**
|
||||||
** @(#) $Id: btree.h,v 1.1 2001/04/17 20:09:11 drh Exp $
|
** @(#) $Id: btree.h,v 1.2 2001/05/24 21:06:36 drh Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct Btree Btree;
|
typedef struct Btree Btree;
|
||||||
@@ -39,18 +39,12 @@ int sqliteBtreeRollback(Btree*);
|
|||||||
|
|
||||||
|
|
||||||
int sqliteBtreeCursor(Btree*, BtCursor **ppCur);
|
int sqliteBtreeCursor(Btree*, BtCursor **ppCur);
|
||||||
|
int sqliteBtreeMoveto(BtCursor*, void *pKey, int nKey, *pRes);
|
||||||
/* Move the cursor so that it points to an entry near pKey.
|
|
||||||
** Return 0 if the cursor is left pointing exactly at pKey.
|
|
||||||
** Return -1 if the cursor points to the largest entry less than pKey.
|
|
||||||
** Return 1 if the cursor points to the smallest entry greater than pKey.
|
|
||||||
*/
|
|
||||||
int sqliteBtreeMoveto(BtCursor*, void *pKey, int nKey);
|
|
||||||
int sqliteBtreeDelete(BtCursor*);
|
int sqliteBtreeDelete(BtCursor*);
|
||||||
int sqliteBtreeInsert(BtCursor*, void *pKey, int nKey, void *pData, int nData);
|
int sqliteBtreeInsert(BtCursor*, void *pKey, int nKey, void *pData, int nData);
|
||||||
int sqliteBtreeNext(BtCursor*);
|
int sqliteBtreeNext(BtCursor*, int *pRes);
|
||||||
int sqliteBtreeKeySize(BtCursor*);
|
int sqliteBtreeKeySize(BtCursor*, int *pSize);
|
||||||
int sqliteBtreeKey(BtCursor*, int offset, int amt, char *zBuf);
|
int sqliteBtreeKey(BtCursor*, int offset, int amt, char *zBuf);
|
||||||
int sqliteBtreeDataSize(BtCursor*);
|
int sqliteBtreeDataSize(BtCursor*, int *pSize);
|
||||||
int sqliteBtreeData(BtCursor*, int offset, int amt, char *zBuf);
|
int sqliteBtreeData(BtCursor*, int offset, int amt, char *zBuf);
|
||||||
int sqliteBtreeCloseCursor(BtCursor*);
|
int sqliteBtreeCloseCursor(BtCursor*);
|
||||||
|
21
src/pager.c
21
src/pager.c
@@ -27,7 +27,7 @@
|
|||||||
** all writes in order to support rollback. Locking is used to limit
|
** all writes in order to support rollback. Locking is used to limit
|
||||||
** access to one or more reader or one writer.
|
** access to one or more reader or one writer.
|
||||||
**
|
**
|
||||||
** @(#) $Id: pager.c,v 1.6 2001/05/21 13:45:10 drh Exp $
|
** @(#) $Id: pager.c,v 1.7 2001/05/24 21:06:36 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
@@ -113,6 +113,7 @@ struct Pager {
|
|||||||
int dbSize; /* Number of pages in the file */
|
int dbSize; /* Number of pages in the file */
|
||||||
int origDbSize; /* dbSize before the current change */
|
int origDbSize; /* dbSize before the current change */
|
||||||
int nExtra; /* Add this many bytes to each in-memory page */
|
int nExtra; /* Add this many bytes to each in-memory page */
|
||||||
|
void (*xDestructor)(void*); /* Call this routine when freeing pages */
|
||||||
int nPage; /* Total number of in-memory pages */
|
int nPage; /* Total number of in-memory pages */
|
||||||
int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
|
int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
|
||||||
int mxPage; /* Maximum number of pages to hold in cache */
|
int mxPage; /* Maximum number of pages to hold in cache */
|
||||||
@@ -478,6 +479,17 @@ int sqlitepager_open(
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Set the destructor for this pager. If not NULL, the destructor is called
|
||||||
|
** when the reference count on the page reaches zero.
|
||||||
|
**
|
||||||
|
** The destructor is not called as a result sqlitepager_close().
|
||||||
|
** Destructors are only called by sqlitepager_unref().
|
||||||
|
*/
|
||||||
|
void sqlitepager_set_destructor(Pager *pPager, void (*xDesc)(void*)){
|
||||||
|
pPager->xDestructor = xDesc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return the total number of pages in the file opened by pPager.
|
** Return the total number of pages in the file opened by pPager.
|
||||||
*/
|
*/
|
||||||
@@ -806,8 +818,8 @@ int sqlitepager_unref(void *pData){
|
|||||||
pPager = pPg->pPager;
|
pPager = pPg->pPager;
|
||||||
pPg->nRef--;
|
pPg->nRef--;
|
||||||
|
|
||||||
/* When the number of references to a page reach 0, add the
|
/* When the number of references to a page reach 0, call the
|
||||||
** page to the freelist.
|
** destructor and add the page to the freelist.
|
||||||
*/
|
*/
|
||||||
if( pPg->nRef==0 ){
|
if( pPg->nRef==0 ){
|
||||||
pPg->pNextFree = 0;
|
pPg->pNextFree = 0;
|
||||||
@@ -818,6 +830,9 @@ int sqlitepager_unref(void *pData){
|
|||||||
}else{
|
}else{
|
||||||
pPager->pFirst = pPg;
|
pPager->pFirst = pPg;
|
||||||
}
|
}
|
||||||
|
if( pPager->xDestructor ){
|
||||||
|
pPager->xDestructor(pData);
|
||||||
|
}
|
||||||
|
|
||||||
/* When all pages reach the freelist, drop the read lock from
|
/* When all pages reach the freelist, drop the read lock from
|
||||||
** the database file.
|
** the database file.
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
** subsystem. The page cache subsystem reads and writes a file a page
|
** subsystem. The page cache subsystem reads and writes a file a page
|
||||||
** at a time and provides a journal for rollback.
|
** at a time and provides a journal for rollback.
|
||||||
**
|
**
|
||||||
** @(#) $Id: pager.h,v 1.3 2001/04/28 16:52:42 drh Exp $
|
** @(#) $Id: pager.h,v 1.4 2001/05/24 21:06:36 drh Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -45,6 +45,7 @@ typedef unsigned int Pgno;
|
|||||||
typedef struct Pager Pager;
|
typedef struct Pager Pager;
|
||||||
|
|
||||||
int sqlitepager_open(Pager **ppPager,const char *zFilename,int nPage,int nEx);
|
int sqlitepager_open(Pager **ppPager,const char *zFilename,int nPage,int nEx);
|
||||||
|
void sqiltepager_set_destructor(Pager*, void(*)(void*));
|
||||||
int sqlitepager_close(Pager *pPager);
|
int sqlitepager_close(Pager *pPager);
|
||||||
int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage);
|
int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage);
|
||||||
void *sqlitepager_lookup(Pager *pPager, Pgno pgno);
|
void *sqlitepager_lookup(Pager *pPager, Pgno pgno);
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this script is page cache subsystem.
|
# focus of this script is page cache subsystem.
|
||||||
#
|
#
|
||||||
# $Id: pager.test,v 1.4 2001/05/21 13:45:10 drh Exp $
|
# $Id: pager.test,v 1.5 2001/05/24 21:06:36 drh Exp $
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
@@ -66,13 +66,36 @@ do_test pager-2.2 {
|
|||||||
} msg]
|
} msg]
|
||||||
lappend v $msg
|
lappend v $msg
|
||||||
} {1 SQLITE_ERROR}
|
} {1 SQLITE_ERROR}
|
||||||
do_test pager-2.3 {
|
do_test pager-2.3.1 {
|
||||||
|
set ::gx [page_lookup $::p1 1]
|
||||||
|
} {}
|
||||||
|
do_test pager-2.3.2 {
|
||||||
|
pager_stats $::p1
|
||||||
|
} {ref 0 page 0 max 10 size -1 state 0 err 0 hit 0 miss 0 ovfl 0}
|
||||||
|
do_test pager-2.3.3 {
|
||||||
set v [catch {
|
set v [catch {
|
||||||
set ::g1 [page_get $::p1 1]
|
set ::g1 [page_get $::p1 1]
|
||||||
} msg]
|
} msg]
|
||||||
if {$v} {lappend v $msg}
|
if {$v} {lappend v $msg}
|
||||||
set v
|
set v
|
||||||
} {0}
|
} {0}
|
||||||
|
do_test pager-2.3.3 {
|
||||||
|
pager_stats $::p1
|
||||||
|
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0}
|
||||||
|
do_test pager-2.3.4 {
|
||||||
|
set ::gx [page_lookup $::p1 1]
|
||||||
|
expr {$::gx!=""}
|
||||||
|
} {1}
|
||||||
|
do_test pager-2.3.5 {
|
||||||
|
pager_stats $::p1
|
||||||
|
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0}
|
||||||
|
do_test pager-2.3.6 {
|
||||||
|
expr $::g1==$::gx
|
||||||
|
} {1}
|
||||||
|
do_test pager-2.3.7 {
|
||||||
|
page_unref $::gx
|
||||||
|
pager_stats $::p1
|
||||||
|
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0}
|
||||||
do_test pager-2.4 {
|
do_test pager-2.4 {
|
||||||
pager_stats $::p1
|
pager_stats $::p1
|
||||||
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0}
|
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0}
|
||||||
|
Reference in New Issue
Block a user