mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
:-) (CVS 218)
FossilOrigin-Name: 523d52dfa6ae3028cbcc88d406501f3ebb6cbd2d
This commit is contained in:
20
manifest
20
manifest
@@ -1,5 +1,5 @@
|
|||||||
C :-)\s(CVS\s217)
|
C :-)\s(CVS\s218)
|
||||||
D 2001-05-15T00:39:25
|
D 2001-05-21T13:45:10
|
||||||
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
||||||
F Makefile.in acef0f0275a5ca8e68bda165f7f05d810a207664
|
F Makefile.in acef0f0275a5ca8e68bda165f7f05d810a207664
|
||||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||||
@@ -12,7 +12,7 @@ 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 f6d724fccaf108c4452dba6589e6027ba8f3e88a
|
F src/btree.c bc1525234a8b169cae6f903f9cfacbcf971be942
|
||||||
F src/btree.h f21c240d0c95f93e2a128106d04a6c448ed0eb94
|
F src/btree.h f21c240d0c95f93e2a128106d04a6c448ed0eb94
|
||||||
F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
|
F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
|
||||||
F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
|
F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
|
||||||
@@ -31,7 +31,7 @@ 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 4081e3e9765c272554e22d1dcec0647ac71ea706
|
F src/pager.c e45946aaf080aed251653f21667d62c89e539a97
|
||||||
F src/pager.h ed12ac3ddebd3afe61a0ed4bf530e7846d578e46
|
F src/pager.h ed12ac3ddebd3afe61a0ed4bf530e7846d578e46
|
||||||
F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
|
F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
|
||||||
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
|
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
|
||||||
@@ -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 3416a155c2dc3b1b3c07d4bb0192cbb15b76a90c
|
F test/pager.test c1eb25faa0938f803d1e6eb5201e5e976ea88256
|
||||||
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
|
||||||
@@ -99,14 +99,14 @@ F www/changes.tcl 822b425cc50cb8e21563dd1aa0e4b79cf780f3dc
|
|||||||
F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
|
F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
|
||||||
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
||||||
F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9
|
F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9
|
||||||
F www/index.tcl 553a41c4157fe411465aefe391bec5687027e73f
|
F www/index.tcl 199abaf346d5fed6cf5b462a327faae39fb117b9
|
||||||
F www/lang.tcl 7fec414487ebee2cbb17c90addf5a026cd10396a
|
F www/lang.tcl 0969ba9f13b3555e54ccdb8ec462dee2de0bf223
|
||||||
F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
|
F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
|
||||||
F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
|
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 c3e521190f02120a34f1e9244fe1ea3a975a6caa
|
P ee6760fb62e81af95796c0fcf1e65e5dc0701194
|
||||||
R d3ffc66c90d6f5774a5954932275df58
|
R 6bf7ed657f22039e86c99aa04cca003e
|
||||||
U drh
|
U drh
|
||||||
Z 0f43bc31472b172caca9953860c2e8b6
|
Z 4c32ca5182d7191fa6afdab861fed35d
|
||||||
|
@@ -1 +1 @@
|
|||||||
ee6760fb62e81af95796c0fcf1e65e5dc0701194
|
523d52dfa6ae3028cbcc88d406501f3ebb6cbd2d
|
139
src/btree.c
139
src/btree.c
@@ -21,7 +21,7 @@
|
|||||||
** http://www.hwaci.com/drh/
|
** http://www.hwaci.com/drh/
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** $Id: btree.c,v 1.5 2001/05/15 00:39:25 drh Exp $
|
** $Id: btree.c,v 1.6 2001/05/21 13:45:10 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
@@ -39,8 +39,8 @@
|
|||||||
** database entry. If the entry contains more data than this, the
|
** database entry. If the entry contains more data than this, the
|
||||||
** extra goes onto overflow pages.
|
** extra goes onto overflow pages.
|
||||||
*/
|
*/
|
||||||
#define MX_LOCAL_PAYLOAD ((SQLITE_PAGE_SIZE-sizeof(PageHdr)-4*sizeof(Cell))/4)
|
#define MX_LOCAL_PAYLOAD \
|
||||||
|
((SQLITE_PAGE_SIZE-sizeof(PageHdr)-4*(sizeof(Cell)+sizeof(Pgno)))/4)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The in-memory image of a disk page has the auxiliary information appended
|
** The in-memory image of a disk page has the auxiliary information appended
|
||||||
@@ -54,9 +54,9 @@
|
|||||||
*/
|
*/
|
||||||
#define OVERFLOW_SIZE (SQLITE_PAGE_SIZE-sizeof(Pgno))
|
#define OVERFLOW_SIZE (SQLITE_PAGE_SIZE-sizeof(Pgno))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Primitive data types. u32 must be 4 bytes and u16 must be 2 bytes.
|
** Primitive data types. u32 must be 4 bytes and u16 must be 2 bytes.
|
||||||
|
** Change these typedefs when porting to new architectures.
|
||||||
*/
|
*/
|
||||||
typedef unsigned int u32;
|
typedef unsigned int u32;
|
||||||
typedef unsigned short int u16;
|
typedef unsigned short int u16;
|
||||||
@@ -74,10 +74,12 @@ typedef struct OverflowPage OverflowPage;
|
|||||||
/*
|
/*
|
||||||
** All structures on a database page are aligned to 4-byte boundries.
|
** All structures on a database page are aligned to 4-byte boundries.
|
||||||
** This routine rounds up a number of bytes to the next multiple of 4.
|
** This routine rounds up a number of bytes to the next multiple of 4.
|
||||||
|
**
|
||||||
|
** This might need to change for computer architectures that require
|
||||||
|
** and 8-byte alignment boundry for structures.
|
||||||
*/
|
*/
|
||||||
#define ROUNDUP(X) ((X+3) & ~3)
|
#define ROUNDUP(X) ((X+3) & ~3)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The first pages of the database file contains some additional
|
** The first pages of the database file contains some additional
|
||||||
** information used for housekeeping and sanity checking. Otherwise,
|
** information used for housekeeping and sanity checking. Otherwise,
|
||||||
@@ -92,7 +94,6 @@ struct Page1Header {
|
|||||||
#define MAGIC_1 0x7264dc61
|
#define MAGIC_1 0x7264dc61
|
||||||
#define MAGIC_2 0x54e55d9e
|
#define MAGIC_2 0x54e55d9e
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Each database page has a header as follows:
|
** Each database page has a header as follows:
|
||||||
**
|
**
|
||||||
@@ -102,17 +103,30 @@ struct Page1Header {
|
|||||||
** first_free Index of first free block
|
** first_free Index of first free block
|
||||||
**
|
**
|
||||||
** MemPage.pStart always points to the rightmost_pgno. First_free is
|
** MemPage.pStart always points to the rightmost_pgno. First_free is
|
||||||
** 0 if there is no free space on this page. Otherwise it points to
|
** 0 if there is no free space on this page. Otherwise, first_free is
|
||||||
** an area like this:
|
** the index in MemPage.aPage[] of a FreeBlk structure that describes
|
||||||
|
** the first block of free space. All free space is defined by a linked
|
||||||
|
** list of FreeBlk structures.
|
||||||
**
|
**
|
||||||
** nByte Number of free bytes in this block
|
** Data is stored in a linked list of Cell structures. First_cell is
|
||||||
** next_free Next free block or 0 if this is the end
|
** the index into MemPage.aPage[] of the first cell on the page. The
|
||||||
|
** Cells are kept in sorted order.
|
||||||
*/
|
*/
|
||||||
struct PageHdr {
|
struct PageHdr {
|
||||||
Pgno pgno; /* Child page that comes after all cells on this page */
|
Pgno pgno; /* Child page that comes after all cells on this page */
|
||||||
u16 firstCell; /* Index in MemPage.aPage[] of the first cell */
|
u16 firstCell; /* Index in MemPage.aPage[] of the first cell */
|
||||||
u16 firstFree; /* Index in MemPage.aPage[] of the first free block */
|
u16 firstFree; /* Index in MemPage.aPage[] of the first free block */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Data on a database page is stored as a linked list of Cell structures.
|
||||||
|
** Both the key and the data are stored in aData[]. The key always comes
|
||||||
|
** first. The aData[] field grows as necessary to hold the key and data,
|
||||||
|
** up to a maximum of MX_LOCAL_PAYLOAD bytes. If the size of the key and
|
||||||
|
** data combined exceeds MX_LOCAL_PAYLOAD bytes, then the 4 bytes beginning
|
||||||
|
** at Cell.aData[MX_LOCAL_PAYLOAD] are the page number of the first overflow
|
||||||
|
** page.
|
||||||
|
*/
|
||||||
struct Cell {
|
struct Cell {
|
||||||
Pgno pgno; /* Child page that comes before this cell */
|
Pgno pgno; /* Child page that comes before this cell */
|
||||||
u16 nKey; /* Number of bytes in the key */
|
u16 nKey; /* Number of bytes in the key */
|
||||||
@@ -120,10 +134,28 @@ struct Cell {
|
|||||||
u32 nData; /* Number of bytes of data */
|
u32 nData; /* Number of bytes of data */
|
||||||
char aData[4]; /* Key and data */
|
char aData[4]; /* Key and data */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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
|
||||||
|
** at least 4 bytes and is always aligned to a 4-byte boundry.
|
||||||
|
*/
|
||||||
struct FreeBlk {
|
struct FreeBlk {
|
||||||
u16 iSize; /* Number of u32-sized slots in the block of free space */
|
u16 iSize; /* Number of u32-sized slots in the 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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** When the key and data for a single entry in the BTree will not fit in
|
||||||
|
** the MX_LOACAL_PAYLOAD bytes of space available on the database page,
|
||||||
|
** then all extra data is written to a linked list of overflow pages.
|
||||||
|
** Each overflow page is an instance of the following structure.
|
||||||
|
**
|
||||||
|
** Unused pages in the database are also represented by instances of
|
||||||
|
** the OverflowPage structure. The Page1Header.freeList field is the
|
||||||
|
** page number of the first page in a linked list of unused database
|
||||||
|
** pages.
|
||||||
|
*/
|
||||||
struct OverflowPage {
|
struct OverflowPage {
|
||||||
Pgno next;
|
Pgno next;
|
||||||
char aData[SQLITE_PAGE_SIZE-sizeof(Pgno)];
|
char aData[SQLITE_PAGE_SIZE-sizeof(Pgno)];
|
||||||
@@ -132,11 +164,18 @@ struct OverflowPage {
|
|||||||
/*
|
/*
|
||||||
** For every page in the database file, an instance of the following structure
|
** 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
|
** is stored in memory. The aPage[] array contains the data obtained from
|
||||||
** the disk. The rest is auxiliary data that held in memory only.
|
** the disk. The rest is auxiliary data that held in memory only. The
|
||||||
|
** auxiliary data is only valid for regular database pages - the auxiliary
|
||||||
|
** data is meaningless for overflow pages and pages on the freelist.
|
||||||
|
**
|
||||||
|
** 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
|
||||||
|
** 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.
|
||||||
*/
|
*/
|
||||||
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 sequel is initialized */
|
unsigned char isInit; /* True if auxiliary data is initialized */
|
||||||
unsigned char validUp; /* True if MemPage.up is valid */
|
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 */
|
||||||
@@ -147,7 +186,7 @@ struct MemPage {
|
|||||||
PageHdr *pStart; /* Points to aPage[idxStart] */
|
PageHdr *pStart; /* Points to aPage[idxStart] */
|
||||||
int nFree; /* Number of free bytes in aPage[] */
|
int nFree; /* Number of free bytes in aPage[] */
|
||||||
int nCell; /* Number of entries on this page */
|
int nCell; /* Number of entries on this page */
|
||||||
u32 *aCell[MX_CELL]; /* All entires in sorted order */
|
Cell *aCell[MX_CELL]; /* All data entires in sorted order */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -155,9 +194,9 @@ struct MemPage {
|
|||||||
*/
|
*/
|
||||||
struct Btree {
|
struct Btree {
|
||||||
Pager *pPager; /* The page cache */
|
Pager *pPager; /* The page cache */
|
||||||
BtCursor *pCursor; /* All open cursors */
|
BtCursor *pCursor; /* A list of all open cursors */
|
||||||
MemPage *page1; /* First page of the database */
|
MemPage *page1; /* First page of the database */
|
||||||
int inTrans; /* True if a transaction is current */
|
int inTrans; /* True if a transaction is in progress */
|
||||||
};
|
};
|
||||||
typedef Btree Bt;
|
typedef Btree Bt;
|
||||||
|
|
||||||
@@ -213,7 +252,8 @@ static void defragmentPage(MemPage *pPage){
|
|||||||
** nByte bytes in size. (Actually, all allocations are rounded
|
** nByte bytes in size. (Actually, all allocations are rounded
|
||||||
** up to the next even multiple of 4.) Return the index into
|
** up to the next even multiple of 4.) Return the index into
|
||||||
** pPage->aPage[] of the first byte of the new allocation.
|
** pPage->aPage[] of the first byte of the new allocation.
|
||||||
** Or return 0 if there is not enough space.
|
** Or return 0 if there is not enough free space on the page to
|
||||||
|
** satisfy the allocation request.
|
||||||
**
|
**
|
||||||
** This routine will call defragmentPage if necessary to consolidate
|
** This routine will call defragmentPage if necessary to consolidate
|
||||||
** free space.
|
** free space.
|
||||||
@@ -249,7 +289,10 @@ static int allocSpace(MemPage *pPage, int nByte){
|
|||||||
/*
|
/*
|
||||||
** Return a section of the MemPage.aPage[] to the freelist.
|
** Return a section of the MemPage.aPage[] to the freelist.
|
||||||
** The first byte of the new free block is pPage->aPage[start]
|
** The first byte of the new free block is pPage->aPage[start]
|
||||||
** and there are a told of size bytes to be freed.
|
** and the size of the block is "size".
|
||||||
|
**
|
||||||
|
** Most of the effort here is involved in coalesing adjacent
|
||||||
|
** free blocks into a single big free block.
|
||||||
*/
|
*/
|
||||||
static void freeSpace(MemPage *pPage, int start, int size){
|
static void freeSpace(MemPage *pPage, int start, int size){
|
||||||
int end = start + size;
|
int end = start + size;
|
||||||
@@ -307,6 +350,7 @@ static int initPage(MemPage *pPage, Pgno pgnoThis, Pgno pgnoParent){
|
|||||||
idx = pPage->pStart->firstCell;
|
idx = pPage->pStart->firstCell;
|
||||||
while( idx!=0 ){
|
while( idx!=0 ){
|
||||||
if( idx>SQLITE_PAGE_SIZE-sizeof(Cell) ) goto page_format_error;
|
if( idx>SQLITE_PAGE_SIZE-sizeof(Cell) ) goto page_format_error;
|
||||||
|
if( idx<pPage->idxStart + sizeof(PageHeader) ) goto page_format_error;
|
||||||
pCell = (Cell*)&pPage->aPage[idx];
|
pCell = (Cell*)&pPage->aPage[idx];
|
||||||
pPage->aCell[pPage->nCell++] = pCell;
|
pPage->aCell[pPage->nCell++] = pCell;
|
||||||
idx = pCell->iNext;
|
idx = pCell->iNext;
|
||||||
@@ -315,6 +359,7 @@ static int initPage(MemPage *pPage, Pgno pgnoThis, Pgno pgnoParent){
|
|||||||
idx = pPage->pStart->firstFree;
|
idx = pPage->pStart->firstFree;
|
||||||
while( idx!=0 ){
|
while( idx!=0 ){
|
||||||
if( idx>SQLITE_PAGE_SIZE-sizeof(FreeBlk) ) goto page_format_error;
|
if( idx>SQLITE_PAGE_SIZE-sizeof(FreeBlk) ) goto page_format_error;
|
||||||
|
if( idx<pPage->idxStart + sizeof(PageHeader) ) goto page_format_error;
|
||||||
pFBlk = (FreeBlk*)&pPage->aPage[idx];
|
pFBlk = (FreeBlk*)&pPage->aPage[idx];
|
||||||
pPage->nFree += pFBlk->iSize;
|
pPage->nFree += pFBlk->iSize;
|
||||||
if( pFBlk->iNext <= idx ) goto page_format_error;
|
if( pFBlk->iNext <= idx ) goto page_format_error;
|
||||||
@@ -327,7 +372,11 @@ page_format_error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Open a new database
|
** Open a new database.
|
||||||
|
**
|
||||||
|
** Actually, this routine just sets up the internal data structures
|
||||||
|
** for accessing the database. We do not actually open the database
|
||||||
|
** file 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;
|
||||||
@@ -362,6 +411,41 @@ int sqliteBtreeClose(Btree *pBt){
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Get a reference to page1 of the database file. This will
|
||||||
|
** also acquire a readlock on that file.
|
||||||
|
**
|
||||||
|
** SQLITE_OK is returned on success. If the file is not a
|
||||||
|
** well-formed database file, then SQLITE_CORRUPT is returned.
|
||||||
|
** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM
|
||||||
|
** is returned if we run out of memory. SQLITE_PROTOCOL is returned
|
||||||
|
** if there is a locking protocol violation.
|
||||||
|
*/
|
||||||
|
static int lockBtree(Btree *pBt){
|
||||||
|
int rc;
|
||||||
|
if( pBt->page1 ) return SQLITE_OK;
|
||||||
|
rc = sqlitepager_get(pBt->pPager, 1, &pBt->page1);
|
||||||
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
|
rc = initPage(pBt->page1, 1, 0);
|
||||||
|
if( rc!=SQLITE_OK ) goto lock_failed;
|
||||||
|
|
||||||
|
/* Do some checking to help insure the file we opened really is
|
||||||
|
** a valid database file.
|
||||||
|
*/
|
||||||
|
if( sqlitepager_pagecount(pBt->pPager)>0 ){
|
||||||
|
Page1Header *pP1 = (Page1Header*)pBt->page1;
|
||||||
|
if( pP1->magic1!=MAGIC_1 || pP1->magic2!=MAGIC_2 ){
|
||||||
|
rc = SQLITE_CORRUPT;
|
||||||
|
goto lock_failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
lock_failed:
|
||||||
|
sqlitepager_unref(pBt->page1);
|
||||||
|
pBt->page1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Start a new transaction
|
** Start a new transaction
|
||||||
*/
|
*/
|
||||||
@@ -379,25 +463,6 @@ int sqliteBtreeBeginTrans(Btree *pBt){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** Get a reference to page1 of the database file. This will
|
|
||||||
** also acquire a readlock on that file.
|
|
||||||
*/
|
|
||||||
static int lockBtree(Btree *pBt){
|
|
||||||
int rc;
|
|
||||||
if( pBt->page1 ) return SQLITE_OK;
|
|
||||||
rc = sqlitepager_get(pBt->pPager, 1, &pBt->page1);
|
|
||||||
if( rc!=SQLITE_OK ) return rc;
|
|
||||||
rc = initPage(pBt->page1, 1, 0);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
sqlitepager_unref(pBt->page1);
|
|
||||||
pBt->page1 = 0;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
/* Sanity checking on the database file format */
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Remove the last reference to the database file. This will
|
** Remove the last reference to the database file. This will
|
||||||
** remove the read lock.
|
** remove the read lock.
|
||||||
|
44
src/pager.c
44
src/pager.c
@@ -25,9 +25,9 @@
|
|||||||
**
|
**
|
||||||
** The page cache is used to access a database file. The pager journals
|
** The page cache is used to access a database file. The pager journals
|
||||||
** 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 on writer.
|
** access to one or more reader or one writer.
|
||||||
**
|
**
|
||||||
** @(#) $Id: pager.c,v 1.5 2001/04/28 16:52:42 drh Exp $
|
** @(#) $Id: pager.c,v 1.6 2001/05/21 13:45:10 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
@@ -56,13 +56,16 @@
|
|||||||
** threads can be reading or writing while one
|
** threads can be reading or writing while one
|
||||||
** process is writing.
|
** process is writing.
|
||||||
**
|
**
|
||||||
** The page cache comes up in PCS_UNLOCK. The first time a
|
** The page cache comes up in SQLITE_UNLOCK. The first time a
|
||||||
** sqlite_page_get() occurs, the state transitions to PCS_READLOCK.
|
** sqlite_page_get() occurs, the state transitions to SQLITE_READLOCK.
|
||||||
** After all pages have been released using sqlite_page_unref(),
|
** After all pages have been released using sqlite_page_unref(),
|
||||||
** the state transitions back to PCS_UNLOCK. The first time
|
** the state transitions back to SQLITE_UNLOCK. The first time
|
||||||
** that sqlite_page_write() is called, the state transitions to
|
** that sqlite_page_write() is called, the state transitions to
|
||||||
** PCS_WRITELOCK. The sqlite_page_rollback() and sqlite_page_commit()
|
** SQLITE_WRITELOCK. (Note that sqlite_page_write() can only be
|
||||||
** functions transition the state back to PCS_READLOCK.
|
** called on an outstanding page which means that the pager must
|
||||||
|
** be in SQLITE_READLOCK before it transitions to SQLITE_WRITELOCK.)
|
||||||
|
** The sqlite_page_rollback() and sqlite_page_commit() functions
|
||||||
|
** transition the state from SQLITE_WRITELOCK back to SQLITE_READLOCK.
|
||||||
*/
|
*/
|
||||||
#define SQLITE_UNLOCK 0
|
#define SQLITE_UNLOCK 0
|
||||||
#define SQLITE_READLOCK 1
|
#define SQLITE_READLOCK 1
|
||||||
@@ -96,7 +99,7 @@ struct PgHdr {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** How big to make the hash table used for locating in-memory pages
|
** How big to make the hash table used for locating in-memory pages
|
||||||
** by page number.
|
** by page number. Knuth says this should be a prime number.
|
||||||
*/
|
*/
|
||||||
#define N_PG_HASH 101
|
#define N_PG_HASH 101
|
||||||
|
|
||||||
@@ -336,8 +339,9 @@ static int pager_unwritelock(Pager *pPager){
|
|||||||
** file-type string for sanity checking. Then there is a single
|
** file-type string for sanity checking. Then there is a single
|
||||||
** Pgno number which is the number of pages in the database before
|
** Pgno number which is the number of pages in the database before
|
||||||
** changes were made. The database is truncated to this size.
|
** changes were made. The database is truncated to this size.
|
||||||
** Next come zero or more page records which each page record
|
** Next come zero or more page records where each page record
|
||||||
** consists of a Pgno, SQLITE_PAGE_SIZE bytes of data.
|
** consists of a Pgno and SQLITE_PAGE_SIZE bytes of data. See
|
||||||
|
** the PageRecord structure for details.
|
||||||
**
|
**
|
||||||
** For playback, the pages have to be read from the journal in
|
** For playback, the pages have to be read from the journal in
|
||||||
** reverse order and put back into the original database file.
|
** reverse order and put back into the original database file.
|
||||||
@@ -568,6 +572,12 @@ static void sqlitepager_ref(PgHdr *pPg){
|
|||||||
** A read lock is obtained for the first page acquired. The lock
|
** A read lock is obtained for the first page acquired. The lock
|
||||||
** is dropped when the last page is released.
|
** is dropped when the last page is released.
|
||||||
**
|
**
|
||||||
|
** A _get works for any page number greater than 0. If the database
|
||||||
|
** file is smaller than the requested page, then no actual disk
|
||||||
|
** read occurs and the memory image of the page is initialized to
|
||||||
|
** all zeros. The extra data appended to a page is always initialized
|
||||||
|
** to zeros the first time a page is loaded into memory.
|
||||||
|
**
|
||||||
** The acquisition might fail for several reasons. In all cases,
|
** The acquisition might fail for several reasons. In all cases,
|
||||||
** an appropriate error code is returned and *ppPage is set to NULL.
|
** an appropriate error code is returned and *ppPage is set to NULL.
|
||||||
**
|
**
|
||||||
@@ -727,8 +737,13 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
|||||||
assert( pPg->pNextHash->pPrevHash==0 );
|
assert( pPg->pNextHash->pPrevHash==0 );
|
||||||
pPg->pNextHash->pPrevHash = pPg;
|
pPg->pNextHash->pPrevHash = pPg;
|
||||||
}
|
}
|
||||||
|
if( pPager->dbSize<0 ) sqlitepager_pagecount(pPager);
|
||||||
|
if( pPager->dbSize<pgno ){
|
||||||
|
memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);
|
||||||
|
}else{
|
||||||
pager_seek(pPager->fd, (pgno-1)*SQLITE_PAGE_SIZE);
|
pager_seek(pPager->fd, (pgno-1)*SQLITE_PAGE_SIZE);
|
||||||
pager_read(pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
|
pager_read(pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
|
||||||
|
}
|
||||||
if( pPager->nExtra>0 ){
|
if( pPager->nExtra>0 ){
|
||||||
memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
|
memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
|
||||||
}
|
}
|
||||||
@@ -749,8 +764,8 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
|||||||
** See also sqlitepager_get(). The difference between this routine
|
** See also sqlitepager_get(). The difference between this routine
|
||||||
** and sqlitepager_get() is that _get() will go to the disk and read
|
** 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
|
** 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
|
** returns NULL if the page is not in cache of if a disk I/O has ever
|
||||||
** occurs.
|
** happened.
|
||||||
*/
|
*/
|
||||||
void *sqlitepager_lookup(Pager *pPager, Pgno pgno){
|
void *sqlitepager_lookup(Pager *pPager, Pgno pgno){
|
||||||
PgHdr *pPg;
|
PgHdr *pPg;
|
||||||
@@ -824,7 +839,7 @@ int sqlitepager_unref(void *pData){
|
|||||||
** The first time this routine is called, the pager creates a new
|
** The first time this routine is called, the pager creates a new
|
||||||
** journal and acquires a write lock on the database. If the write
|
** journal and acquires a write lock on the database. If the write
|
||||||
** lock could not be acquired, this routine returns SQLITE_BUSY. The
|
** lock could not be acquired, this routine returns SQLITE_BUSY. The
|
||||||
** calling routine must check for that routine and be careful not to
|
** calling routine must check for that return value and be careful not to
|
||||||
** change any page data until this routine returns SQLITE_OK.
|
** change any page data until this routine returns SQLITE_OK.
|
||||||
**
|
**
|
||||||
** If the journal file could not be written because the disk is full,
|
** If the journal file could not be written because the disk is full,
|
||||||
@@ -889,6 +904,9 @@ int sqlitepager_write(void *pData){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pPg->inJournal = 1;
|
pPg->inJournal = 1;
|
||||||
|
if( pPager->dbSize<pPg->pgno ){
|
||||||
|
pPager->dbSize = pPg->pgno;
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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.3 2001/04/17 20:09:11 drh Exp $
|
# $Id: pager.test,v 1.4 2001/05/21 13:45:10 drh Exp $
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
@@ -75,7 +75,7 @@ do_test pager-2.3 {
|
|||||||
} {0}
|
} {0}
|
||||||
do_test pager-2.4 {
|
do_test pager-2.4 {
|
||||||
pager_stats $::p1
|
pager_stats $::p1
|
||||||
} {ref 1 page 1 max 10 size -1 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}
|
||||||
do_test pager-2.5 {
|
do_test pager-2.5 {
|
||||||
pager_pagecount $::p1
|
pager_pagecount $::p1
|
||||||
} {0}
|
} {0}
|
||||||
@@ -103,7 +103,7 @@ do_test pager-2.12 {
|
|||||||
} {1}
|
} {1}
|
||||||
do_test pager-2.13 {
|
do_test pager-2.13 {
|
||||||
pager_stats $::p1
|
pager_stats $::p1
|
||||||
} {ref 1 page 1 max 10 size -1 state 1 err 0 hit 0 miss 2 ovfl 0}
|
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 2 ovfl 0}
|
||||||
do_test pager-2.14 {
|
do_test pager-2.14 {
|
||||||
set v [catch {
|
set v [catch {
|
||||||
page_write $::g1 "Page-One"
|
page_write $::g1 "Page-One"
|
||||||
@@ -112,7 +112,7 @@ do_test pager-2.14 {
|
|||||||
} {0 {}}
|
} {0 {}}
|
||||||
do_test pager-2.15 {
|
do_test pager-2.15 {
|
||||||
pager_stats $::p1
|
pager_stats $::p1
|
||||||
} {ref 1 page 1 max 10 size 0 state 2 err 0 hit 0 miss 2 ovfl 0}
|
} {ref 1 page 1 max 10 size 1 state 2 err 0 hit 0 miss 2 ovfl 0}
|
||||||
do_test pager-2.16 {
|
do_test pager-2.16 {
|
||||||
page_read $::g1
|
page_read $::g1
|
||||||
} {Page-One}
|
} {Page-One}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Run this TCL script to generate HTML for the index.html file.
|
# Run this TCL script to generate HTML for the index.html file.
|
||||||
#
|
#
|
||||||
set rcsid {$Id: index.tcl,v 1.36 2001/04/05 16:49:44 drh Exp $}
|
set rcsid {$Id: index.tcl,v 1.37 2001/05/21 13:45:10 drh Exp $}
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head><title>SQLite: An SQL Database Library Built Atop GDBM</title></head>
|
<head><title>SQLite: An SQL Database Library Built Atop GDBM</title></head>
|
||||||
@@ -69,7 +69,7 @@ only reached when <tt>malloc()</tt> fails.</p>
|
|||||||
But it only ignores case for 7-bit Latin characters.
|
But it only ignores case for 7-bit Latin characters.
|
||||||
The case of 8-bit iso8859 characters or UTF-8 characters is
|
The case of 8-bit iso8859 characters or UTF-8 characters is
|
||||||
signification. Hence, <b>'a' LIKE 'A'</b> returns
|
signification. Hence, <b>'a' LIKE 'A'</b> returns
|
||||||
TRUE but <b>'æ' LIKE 'Æ'</b>" returns FALSE.
|
TRUE but <b>'æ' LIKE 'Æ'</b> returns FALSE.
|
||||||
</p></li>
|
</p></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -147,7 +147,7 @@ found <a href="crosscompile.html">here</a>.
|
|||||||
puts {<h2>Command-line Usage Example</h2>
|
puts {<h2>Command-line Usage Example</h2>
|
||||||
|
|
||||||
<p>Download the source archive and compile the <b>sqlite</b>
|
<p>Download the source archive and compile the <b>sqlite</b>
|
||||||
program as described above. The type:</p>
|
program as described above. Then type:</p>
|
||||||
|
|
||||||
<blockquote><pre>
|
<blockquote><pre>
|
||||||
bash$ sqlite ~/newdb <i>Directory ~/newdb created automatically</i>
|
bash$ sqlite ~/newdb <i>Directory ~/newdb created automatically</i>
|
||||||
|
16
www/lang.tcl
16
www/lang.tcl
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Run this Tcl script to generate the sqlite.html file.
|
# Run this Tcl script to generate the sqlite.html file.
|
||||||
#
|
#
|
||||||
set rcsid {$Id: lang.tcl,v 1.7 2001/04/04 11:48:58 drh Exp $}
|
set rcsid {$Id: lang.tcl,v 1.8 2001/05/21 13:45:10 drh Exp $}
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -384,10 +384,16 @@ to the right contains the wildcards.}
|
|||||||
puts "A percent symbol [Operator %] in the right operand
|
puts "A percent symbol [Operator %] in the right operand
|
||||||
matches any sequence of zero or more characters on the left.
|
matches any sequence of zero or more characters on the left.
|
||||||
An underscore [Operator _] on the right
|
An underscore [Operator _] on the right
|
||||||
matches any single character on the left. The LIKE operator is
|
matches any single character on the left."
|
||||||
|
puts {The LIKE operator is
|
||||||
not case sensitive and will match upper case characters on one
|
not case sensitive and will match upper case characters on one
|
||||||
side against lower case characters on the other.</p>"
|
side against lower case characters on the other.
|
||||||
puts {
|
(A bug: SQLite only understands upper/lower case for 7-bit Latin
|
||||||
|
characters. Hence the LIKE operator is case sensitive for
|
||||||
|
8-bit iso8859 characters or UTF-8 characters. For example,
|
||||||
|
the expression <b>'a' LIKE 'A'</b> is TRUE but
|
||||||
|
<b>'æ' LIKE 'Æ'</b> is FALSE.)
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>The GLOB operator is similar to LIKE but uses the Unix
|
<p>The GLOB operator is similar to LIKE but uses the Unix
|
||||||
file globbing syntax for its wildcards. Also, GLOB is case
|
file globbing syntax for its wildcards. Also, GLOB is case
|
||||||
@@ -398,7 +404,7 @@ the NOT keyword to invert the sense of the test.</p>
|
|||||||
statement or one of the following special identifiers: "<b>ROWID</b>",
|
statement or one of the following special identifiers: "<b>ROWID</b>",
|
||||||
"<b>OID</b>", or "<b>_ROWID_</b>".
|
"<b>OID</b>", or "<b>_ROWID_</b>".
|
||||||
These special identifiers all describe the
|
These special identifiers all describe the
|
||||||
unique random integer key (the "row key") associated every every
|
unique random integer key (the "row key") associated with every
|
||||||
row of every table.
|
row of every table.
|
||||||
The special identifiers only refer to the row key if the CREATE TABLE
|
The special identifiers only refer to the row key if the CREATE TABLE
|
||||||
statement does not define a real column with the same name. Row keys
|
statement does not define a real column with the same name. Row keys
|
||||||
|
Reference in New Issue
Block a user