mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
:-) (CVS 214)
FossilOrigin-Name: 73a1ed61265040925f1a41c9c0cfeea50db70b01
This commit is contained in:
196
src/btree.c
196
src/btree.c
@ -21,7 +21,7 @@
|
||||
** http://www.hwaci.com/drh/
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.1 2001/04/17 20:09:11 drh Exp $
|
||||
** $Id: btree.c,v 1.2 2001/04/28 16:52:41 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@ -30,17 +30,90 @@
|
||||
|
||||
typedef unsigned int u32;
|
||||
|
||||
/*
|
||||
** The maximum number of database entries that can be held in a single
|
||||
** page of the database. Each entry has a 16-byte header consisting of
|
||||
** 4 unsigned 32-bit numbers, as follows:
|
||||
**
|
||||
** nKey Number of byte in the key
|
||||
** nData Number of byte in the data
|
||||
** pgno Page number of the right child block
|
||||
** next index in MemPage.aPage[] of the next entry in sorted order
|
||||
**
|
||||
** The key and data follow this header. The key and data are packed together
|
||||
** and the total rounded up to the next multiple of 4 bytes. There must
|
||||
** be at least 4 bytes in the key/data packet, so each entry consumes at
|
||||
** least 20 bytes of space on the page.
|
||||
*/
|
||||
#define MX_CELL (SQLITE_PAGE_SIZE/20)
|
||||
|
||||
/*
|
||||
** Freeblocks are divided by cells, so there can be at most one more
|
||||
** free block than there are cells.
|
||||
*/
|
||||
#define MX_FREE (MX_CELL+1)
|
||||
|
||||
/*
|
||||
** The maximum amount of data (in bytes) that can be stored locally for a
|
||||
** database entry. If the entry contains more data than this, the
|
||||
** extra goes onto overflow pages.
|
||||
*/
|
||||
#define MX_LOCAL_PAYLOAD ((SQLITE_PAGE_SIZE-20-4*24)/4)
|
||||
|
||||
/*
|
||||
** On a single disk page, there are sections of the page that are used
|
||||
** to hold data and sections that are unused and available for holding
|
||||
** new data. A single instance of this structure describes a contiguous
|
||||
** block of free space on a disk page.
|
||||
*/
|
||||
struct FreeBlk {
|
||||
int idx; /* Index into MemPage.aPage[] of the start of freeblock */
|
||||
int size; /* Number of MemPage.aPage[] slots used by this block */
|
||||
};
|
||||
typedef struct FreeBlk;
|
||||
|
||||
/*
|
||||
** For every page in the database file, an instance of the following structure
|
||||
** is stored in memory. The aPage[] array contains the data obtained from
|
||||
** the disk. The rest is auxiliary data that held in memory only.
|
||||
*/
|
||||
struct MemPage {
|
||||
u32 aPage[SQLITE_PAGE_SIZE/sizeof(u32)]; /* Page data stored on disk */
|
||||
unsigned char isInit; /* True if sequel is initialized */
|
||||
unsigned char validUp; /* True if MemPage.up is valid */
|
||||
unsigned char validLeft; /* True if MemPage.left is valid */
|
||||
unsigned char validRight; /* True if MemPage.right is valid */
|
||||
Pgno up; /* The parent page. 0 means this is the root */
|
||||
Pgno left; /* Left sibling page. 0==none */
|
||||
Pgno right; /* Right sibling page. 0==none */
|
||||
int idxStart; /* Index in aPage[] of real data */
|
||||
int nCell; /* Number of entries on this page */
|
||||
u32 *aCell[MX_CELL]; /* All entires in sorted order */
|
||||
int nFree; /* Number of free blocks on this page */
|
||||
int nFreeSlot; /* Number of free elements of aPage[] */
|
||||
FreeBlk aFree[MX_FREE]; /* Free blocks in no particular order */
|
||||
}
|
||||
typedef struct MemPage;
|
||||
|
||||
/*
|
||||
** The in-memory image of a disk page has the auxiliary information appended
|
||||
** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
|
||||
** that extra information.
|
||||
*/
|
||||
#define EXTRA_SIZE (sizeof(MemPage)-SQLITE_PAGE_SIZE)
|
||||
|
||||
/*
|
||||
** Everything we need to know about an open database
|
||||
*/
|
||||
struct Btree {
|
||||
Pager *pPager; /* The page cache */
|
||||
BtCursor *pCursor; /* All open cursors */
|
||||
u32 *page1; /* First page of the database */
|
||||
MemPage *page1; /* First page of the database */
|
||||
int inTrans; /* True if a transaction is current */
|
||||
};
|
||||
typedef Btree Bt;
|
||||
|
||||
|
||||
/*
|
||||
** The maximum depth of a cursor
|
||||
*/
|
||||
@ -55,6 +128,7 @@ struct BtIdxpt {
|
||||
Pgno pgno; /* The page number */
|
||||
u32 *aPage; /* The page data */
|
||||
int idx; /* Index into pPage[] */
|
||||
u32 *aIdx; /* Pointer to pPage[idx] */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -65,6 +139,7 @@ struct BtCursor {
|
||||
BtCursor *pPrev, *pNext; /* Linked list of all cursors */
|
||||
int valid; /* True if the cursor points to something */
|
||||
int nLevel; /* Number of levels of indexing used */
|
||||
BtIdxpt *pLevel; /* Pointer to aLevel[nLevel] */
|
||||
BtIdxpt aLevel[MX_LEVEL]; /* The index levels */
|
||||
};
|
||||
|
||||
@ -79,6 +154,108 @@ struct BtCursor {
|
||||
#define MAGIC_1 0x7264dc61
|
||||
#define MAGIC_2 0x54e55d9e
|
||||
|
||||
/*
|
||||
** Each database page has a header as follows:
|
||||
**
|
||||
** page1_header Extra numbers found on page 1 only.
|
||||
** leftmost_pgno Page number of the leftmost child
|
||||
** first_cell Index into MemPage.aPage of first cell
|
||||
**
|
||||
** MemPage.pStart always points to the leftmost_pgno.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Mark a section of the memory block as in-use.
|
||||
*/
|
||||
static void useSpace(MemPage *pPage, int start, int size){
|
||||
int i;
|
||||
FreeBlk *p;
|
||||
|
||||
/* Some basic sanity checking */
|
||||
assert( pPage && pPage->isInit );
|
||||
assert( pPage->nFree>0 && pPage->nFree<=MX_FREE );
|
||||
assert( pPage->nFreeSlot >= size );
|
||||
assert( start > pPage->idxStart );
|
||||
assert( size>0 );
|
||||
assert( start + size < SQLITE_PAGE_SIZE/sizeof(pPage->aPage[0]) );
|
||||
|
||||
/* Search for the freeblock that describes the space to be used */
|
||||
for(i=0; i<pPage->nFree; i++){
|
||||
p = &pPage->aFree[i]
|
||||
if( p->idx<=start && p->idx+p->size>start ) break;
|
||||
}
|
||||
|
||||
/* The freeblock must contain all the space that is to be used */
|
||||
assert( i<pPage->nFree );
|
||||
assert( p->idx+p->size >= start+size );
|
||||
|
||||
/* Remove the used space from the freeblock */
|
||||
if( p->idx==start ){
|
||||
/* The space is at the beginning of the block
|
||||
p->size -= size;
|
||||
if( p->size==0 ){
|
||||
*p = pPage->aFree[pPage->nFree-1];
|
||||
pPage->nFree--;
|
||||
}
|
||||
}else if( p->idx+p->size==start+size ){
|
||||
/* Space at the end of the block */
|
||||
p->size -= size;
|
||||
}else{
|
||||
/* Space in the middle of the freeblock. We have to split the
|
||||
** freeblock in two */
|
||||
/******* TBD *********/
|
||||
}
|
||||
pPage->nFreeSlot -= size;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a section of the MemPage.aPage[] to the freelist.
|
||||
*/
|
||||
static void freeSpace(MemPage *pPage, int start, int size){
|
||||
}
|
||||
|
||||
/*
|
||||
** Defragment the freespace
|
||||
*/
|
||||
static void defragmentSpace(MemPage *pPage){
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize the auxiliary information for a disk block.
|
||||
*/
|
||||
static int initPage(MemPage *pPage, Pgno pgnoThis, Pgno pgnoParent){
|
||||
u32 idx;
|
||||
pPage->isInit = 1;
|
||||
pPage->validUp = 1;
|
||||
pPage->up = pgnoParent;
|
||||
pPage->nFreeSlot = SQLITE_PAGE_SIZE/sizeof(pPage->aPage[0]) - 2;
|
||||
pPage->nFree = 1;
|
||||
if( pgnoThis==1 ){
|
||||
pPage->idxStart = EXTRA_PAGE_1_CELLS;
|
||||
pPage->nFreeByte -= EXTRA_PAGE_1_CELLS;
|
||||
}
|
||||
pPage->aFree[0].idx = pPage->idxStart + 2;
|
||||
pPage->aFree[0].size = pPage->nFreeByte;
|
||||
pPage->nCell = 0;
|
||||
idx = pPage->aPage[pPage->idxStart+1];
|
||||
while( idx!=0 ){
|
||||
int size;
|
||||
pPage->aCell[pPage->nCell++] = idx;
|
||||
size = pPage->aPage[idx] + pPage->aPage[idx+1];
|
||||
if( size>MX_LOCAL_PAYLOAD ){
|
||||
if( size>MX_DIRECT_PAYLOAD ){
|
||||
size = MX_LOCAL_PAYLOAD + 2*sizeof(u32);
|
||||
}else{
|
||||
size = MX_LOCAL_PAYLOAD + sizeof(u32);
|
||||
}
|
||||
}
|
||||
size = (size + sizeof(u32) - 1)/sizeof(u32) + 4;
|
||||
useSpace(pPage, idx, size);
|
||||
idx = pPage->aPage[idx+3];
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a new database
|
||||
*/
|
||||
@ -90,7 +267,7 @@ int sqliteBtreeOpen(const char *zFilename, int mode, Btree **ppBtree){
|
||||
**ppBtree = 0;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
rc = sqlitepager_open(&pBt->pPager, zFilename, 100);
|
||||
rc = sqlitepager_open(&pBt->pPager, zFilename, 100, EXTRA_SPACE);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( pBt->pPager ) sqlitepager_close(pBt->pPager);
|
||||
sqliteFree(pBt);
|
||||
@ -122,7 +299,7 @@ int sqliteBtreeBeginTrans(Btree *pBt){
|
||||
int rc;
|
||||
if( pBt->inTrans ) return SQLITE_ERROR;
|
||||
if( pBt->page1==0 ){
|
||||
rc = sqlitepager_get(pBt->pPager, 1, &pBt->page1);
|
||||
rc = lockBtree(pBt);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
rc = sqlitepager_write(pBt->page1);
|
||||
@ -141,6 +318,12 @@ static int lockBtree(Btree *pBt){
|
||||
if( pBt->page1 ) return SQLITE_OK;
|
||||
rc = sqlitepager_get(pBt->pPager, 1, &pBt->page1);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
rc = initPage(pBt->page1);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlitepager_unref(pBt->page1);
|
||||
pBt->page1 = 0;
|
||||
return rc;
|
||||
}
|
||||
/* Sanity checking on the database file format */
|
||||
return rc;
|
||||
}
|
||||
@ -237,6 +420,11 @@ int sqliteBtreeCloseCursor(BtCursor *pCur){
|
||||
sqliteFree(pCur);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes in the key of the entry to which
|
||||
** the cursor is currently point. If the cursor has not been
|
||||
** initialized or is pointed to a deleted entry, then return 0.
|
||||
*/
|
||||
int sqliteBtreeKeySize(BtCursor *pCur){
|
||||
int nEntry;
|
||||
u32 *aPage;
|
||||
|
11
src/dbbe.c
11
src/dbbe.c
@ -30,10 +30,9 @@
|
||||
** relatively simple to convert to a different database such
|
||||
** as NDBM, SDBM, or BerkeleyDB.
|
||||
**
|
||||
** $Id: dbbe.c,v 1.27 2001/04/11 14:28:42 drh Exp $
|
||||
** $Id: dbbe.c,v 1.28 2001/04/28 16:52:41 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
@ -54,15 +53,21 @@ Dbbe *sqliteDbbeOpen(
|
||||
int createFlag, /* True to create database if it doesn't exist */
|
||||
char **pzErrMsg /* Write error messages (if any) here */
|
||||
){
|
||||
extern Dbbe *sqliteMemOpen(const char*,int,int,char**);
|
||||
#ifndef DISABLE_GDBM
|
||||
extern Dbbe *sqliteGdbmOpen(const char*,int,int,char**);
|
||||
if( strncmp(zName, "gdbm:", 5)==0 ){
|
||||
return sqliteGdbmOpen(&zName[5], writeFlag, createFlag, pzErrMsg);
|
||||
}
|
||||
#endif
|
||||
if( strncmp(zName, "memory:", 7)==0 ){
|
||||
extern Dbbe *sqliteMemOpen(const char*,int,int,char**);
|
||||
return sqliteMemOpen(&zName[7], writeFlag, createFlag, pzErrMsg);
|
||||
}
|
||||
#ifndef DISABLE_GDBM
|
||||
return sqliteGdbmOpen(zName, writeFlag, createFlag, pzErrMsg);
|
||||
#else
|
||||
return sqliteMemOpen(zName, writeFlag, createFlag, pzErrMsg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0 /* NOT USED */
|
||||
|
@ -30,8 +30,9 @@
|
||||
** relatively simple to convert to a different database such
|
||||
** as NDBM, SDBM, or BerkeleyDB.
|
||||
**
|
||||
** $Id: dbbegdbm.c,v 1.7 2001/04/11 14:28:42 drh Exp $
|
||||
** $Id: dbbegdbm.c,v 1.8 2001/04/28 16:52:41 drh Exp $
|
||||
*/
|
||||
#ifndef DISABLE_GDBM
|
||||
#include "sqliteInt.h"
|
||||
#include <gdbm.h>
|
||||
#include <sys/stat.h>
|
||||
@ -674,3 +675,4 @@ Dbbe *sqliteGdbmOpen(
|
||||
pNew->pOpen = 0;
|
||||
return &pNew->dbbe;
|
||||
}
|
||||
#endif /* DISABLE_GDBM */
|
||||
|
@ -30,13 +30,10 @@
|
||||
** Nothing is ever written to disk using this backend. All information
|
||||
** is forgotten when the program exits.
|
||||
**
|
||||
** $Id: dbbemem.c,v 1.14 2001/04/11 14:28:42 drh Exp $
|
||||
** $Id: dbbemem.c,v 1.15 2001/04/28 16:52:42 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
typedef struct Array Array;
|
||||
|
@ -26,10 +26,12 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.28 2001/04/11 14:28:42 drh Exp $
|
||||
** $Id: main.c,v 1.29 2001/04/28 16:52:42 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#if defined(HAVE_USLEEP) && HAVE_USLEEP
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This is the callback routine for the code that initializes the
|
||||
|
99
src/pager.c
99
src/pager.c
@ -27,7 +27,7 @@
|
||||
** all writes in order to support rollback. Locking is used to limit
|
||||
** access to one or more reader or on writer.
|
||||
**
|
||||
** @(#) $Id: pager.c,v 1.4 2001/04/15 02:27:25 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.5 2001/04/28 16:52:42 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@ -83,6 +83,7 @@ struct PgHdr {
|
||||
char inJournal; /* TRUE if has been written to journal */
|
||||
char dirty; /* TRUE if we need to write back changes */
|
||||
/* SQLITE_PAGE_SIZE bytes of page data follow this header */
|
||||
/* Pager.nExtra bytes of local data follow the page data */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -91,6 +92,7 @@ struct PgHdr {
|
||||
*/
|
||||
#define PGHDR_TO_DATA(P) ((void*)(&(P)[1]))
|
||||
#define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1])
|
||||
#define PGHDR_TO_EXTRA(P) ((void*)&((char*)(&(P)[1]))[SQLITE_PAGE_SIZE])
|
||||
|
||||
/*
|
||||
** How big to make the hash table used for locating in-memory pages
|
||||
@ -107,6 +109,7 @@ struct Pager {
|
||||
int fd, jfd; /* File descriptors for database and journal */
|
||||
int dbSize; /* Number of pages in the file */
|
||||
int origDbSize; /* dbSize before the current change */
|
||||
int nExtra; /* Add this many bytes to each in-memory page */
|
||||
int nPage; /* Total number of in-memory pages */
|
||||
int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
|
||||
int mxPage; /* Maximum number of pages to hold in cache */
|
||||
@ -427,7 +430,12 @@ static int pager_playback(Pager *pPager){
|
||||
** the first call to sqlitepager_get() and is only held open until the
|
||||
** last page is released using sqlitepager_unref().
|
||||
*/
|
||||
int sqlitepager_open(Pager **ppPager, const char *zFilename, int mxPage){
|
||||
int sqlitepager_open(
|
||||
Pager **ppPager, /* Return the Pager structure here */
|
||||
const char *zFilename, /* Name of the database file to open */
|
||||
int mxPage, /* Max number of in-memory cache pages */
|
||||
int nExtra /* Extra bytes append to each in-memory page */
|
||||
){
|
||||
Pager *pPager;
|
||||
int nameLen;
|
||||
int fd;
|
||||
@ -531,6 +539,29 @@ Pgno sqlitepager_pagenumber(void *pData){
|
||||
return p->pgno;
|
||||
}
|
||||
|
||||
/*
|
||||
** Increment the reference count for a page. If the page is
|
||||
** currently on the freelist (the reference count is zero) then
|
||||
** remove it from the freelist.
|
||||
*/
|
||||
static void sqlitepager_ref(PgHdr *pPg){
|
||||
if( pPg->nRef==0 ){
|
||||
/* The page is currently on the freelist. Remove it. */
|
||||
if( pPg->pPrevFree ){
|
||||
pPg->pPrevFree->pNextFree = pPg->pNextFree;
|
||||
}else{
|
||||
pPg->pPager->pFirst = pPg->pNextFree;
|
||||
}
|
||||
if( pPg->pNextFree ){
|
||||
pPg->pNextFree->pPrevFree = pPg->pPrevFree;
|
||||
}else{
|
||||
pPg->pPager->pLast = pPg->pPrevFree;
|
||||
}
|
||||
pPg->pPager->nRef++;
|
||||
}
|
||||
pPg->nRef++;
|
||||
}
|
||||
|
||||
/*
|
||||
** Acquire a page.
|
||||
**
|
||||
@ -539,6 +570,14 @@ Pgno sqlitepager_pagenumber(void *pData){
|
||||
**
|
||||
** The acquisition might fail for several reasons. In all cases,
|
||||
** an appropriate error code is returned and *ppPage is set to NULL.
|
||||
**
|
||||
** See also sqlitepager_lookup(). Both this routine and _lookup() attempt
|
||||
** to find a page in the in-memory cache first. If the page is not already
|
||||
** in cache, this routine goes to disk to read it in whereas _lookup()
|
||||
** just returns 0. This routine acquires a read-lock the first time it
|
||||
** has to go to disk, and could also playback an old journal if necessary.
|
||||
** Since _lookup() never goes to disk, it never has to deal with locks
|
||||
** or journal files.
|
||||
*/
|
||||
int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
PgHdr *pPg;
|
||||
@ -596,18 +635,17 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
}
|
||||
}
|
||||
pPg = 0;
|
||||
pPager->nMiss++;
|
||||
}else{
|
||||
/* Search for page in cache */
|
||||
pPg = pager_lookup(pPager, pgno);
|
||||
pPager->nHit++;
|
||||
}
|
||||
if( pPg==0 ){
|
||||
/* The requested page is not in the page cache. */
|
||||
int h;
|
||||
pPager->nMiss++;
|
||||
if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 ){
|
||||
/* Create a new page */
|
||||
pPg = sqliteMalloc( sizeof(*pPg) + SQLITE_PAGE_SIZE );
|
||||
pPg = sqliteMalloc( sizeof(*pPg) + SQLITE_PAGE_SIZE + pPager->nExtra );
|
||||
if( pPg==0 ){
|
||||
*ppPage = 0;
|
||||
pager_unwritelock(pPager);
|
||||
@ -691,28 +729,49 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
}
|
||||
pager_seek(pPager->fd, (pgno-1)*SQLITE_PAGE_SIZE);
|
||||
pager_read(pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
|
||||
if( pPager->nExtra>0 ){
|
||||
memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
|
||||
}
|
||||
}else{
|
||||
/* The requested page is in the page cache. */
|
||||
if( pPg->nRef==0 ){
|
||||
/* The page is currently on the freelist. Remove it. */
|
||||
if( pPg->pPrevFree ){
|
||||
pPg->pPrevFree->pNextFree = pPg->pNextFree;
|
||||
}else{
|
||||
pPager->pFirst = pPg->pNextFree;
|
||||
}
|
||||
if( pPg->pNextFree ){
|
||||
pPg->pNextFree->pPrevFree = pPg->pPrevFree;
|
||||
}else{
|
||||
pPager->pLast = pPg->pPrevFree;
|
||||
}
|
||||
pPager->nRef++;
|
||||
}
|
||||
pPg->nRef++;
|
||||
pPager->nHit++;
|
||||
sqlitepager_ref(pPg);
|
||||
}
|
||||
*ppPage = PGHDR_TO_DATA(pPg);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Acquire a page if it is already in the in-memory cache. Do
|
||||
** not read the page from disk. Return a pointer to the page,
|
||||
** or 0 if the page is not in cache.
|
||||
**
|
||||
** See also sqlitepager_get(). The difference between this routine
|
||||
** and sqlitepager_get() is that _get() will go to the disk and read
|
||||
** in the page if the page is not already in cache. This routine
|
||||
** returns NULL if the page is not in cache and no disk I/O ever
|
||||
** occurs.
|
||||
*/
|
||||
void *sqlitepager_lookup(Pager *pPager, Pgno pgno){
|
||||
PgHdr *pPg;
|
||||
|
||||
/* Make sure we have not hit any critical errors.
|
||||
*/
|
||||
if( pPager==0 || pgno==0 ){
|
||||
return 0;
|
||||
}
|
||||
if( pPager->errMask & ~(PAGER_ERR_FULL) ){
|
||||
return 0;
|
||||
}
|
||||
if( pPager->nRef==0 ){
|
||||
return 0;
|
||||
}
|
||||
pPg = pager_lookup(pPager, pgno);
|
||||
if( pPg==0 ) return 0;
|
||||
sqlitepager_ref(pPg);
|
||||
return PGHDR_TO_DATA(pPg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Release a page.
|
||||
**
|
||||
|
@ -25,7 +25,7 @@
|
||||
** subsystem. The page cache subsystem reads and writes a file a page
|
||||
** at a time and provides a journal for rollback.
|
||||
**
|
||||
** @(#) $Id: pager.h,v 1.2 2001/04/15 00:37:09 drh Exp $
|
||||
** @(#) $Id: pager.h,v 1.3 2001/04/28 16:52:42 drh Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -44,14 +44,14 @@ typedef unsigned int Pgno;
|
||||
*/
|
||||
typedef struct Pager Pager;
|
||||
|
||||
int sqlitepager_open(Pager **ppPager, const char *zFilename, int nPage);
|
||||
int sqlitepager_open(Pager **ppPager, const char *zFilename,int nPage,int nEx);
|
||||
int sqlitepager_close(Pager *pPager);
|
||||
int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage);
|
||||
void *sqlitepager_lookup(Pager *pPager, Pgno pgno);
|
||||
int sqlitepager_unref(void*);
|
||||
Pgno sqlitepager_pagenumber(void*);
|
||||
int sqlitepager_write(void*);
|
||||
int sqlitepager_pagecount(Pager*);
|
||||
int sqlitepager_commit(Pager*);
|
||||
int sqlitepager_rollback(Pager*);
|
||||
|
||||
int *sqlitepager_stats(Pager*);
|
||||
|
@ -23,13 +23,15 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.41 2001/04/11 14:28:43 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.42 2001/04/28 16:52:42 drh Exp $
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "dbbe.h"
|
||||
#include "vdbe.h"
|
||||
#include "parse.h"
|
||||
#ifndef DISABLE_GDBM
|
||||
#include <gdbm.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
36
src/test2.c
36
src/test2.c
@ -25,7 +25,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test2.c,v 1.1 2001/04/15 00:37:09 drh Exp $
|
||||
** $Id: test2.c,v 1.2 2001/04/28 16:52:42 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@ -80,7 +80,7 @@ static int pager_open(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
|
||||
rc = sqlitepager_open(&pPager, argv[1], nPage);
|
||||
rc = sqlitepager_open(&pPager, argv[1], nPage, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
@ -261,6 +261,37 @@ static int page_get(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: page_lookup ID PGNO
|
||||
**
|
||||
** Return a pointer to a page if the page is already in cache.
|
||||
** If not in cache, return an empty string.
|
||||
*/
|
||||
static int page_lookup(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
char zBuf[100];
|
||||
void *pPage;
|
||||
int pgno;
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" ID PGNO\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
|
||||
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
|
||||
pPage = sqlitepager_lookup(pPager, pgno);
|
||||
if( pPage ){
|
||||
sprintf(zBuf,"0x%x",(int)pPage);
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: page_unref PAGE
|
||||
**
|
||||
@ -376,6 +407,7 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateCommand(interp, "pager_stats", pager_stats, 0, 0);
|
||||
Tcl_CreateCommand(interp, "pager_pagecount", pager_pagecount, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_get", page_get, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_lookup", page_lookup, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_unref", page_unref, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_read", page_read, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_write", page_write, 0, 0);
|
||||
|
@ -41,10 +41,9 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.57 2001/04/11 14:28:43 drh Exp $
|
||||
** $Id: vdbe.c,v 1.58 2001/04/28 16:52:42 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user