mirror of https://github.com/sqlite/sqlite
:-) (CVS 1712)
FossilOrigin-Name: edb01b1275c3de7c398522b5826c898917811247
This commit is contained in:
parent
acbcdc49c6
commit
b5b452cb58
16
manifest
16
manifest
|
@ -1,5 +1,5 @@
|
|||
C :-)\s(CVS\s180)
|
||||
D 2001-01-22T00:31:53
|
||||
C :-)\s(CVS\s1712)
|
||||
D 2001-01-25T01:45:40
|
||||
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
||||
F Makefile.in 7efa81e2985b45ba73db27d55b70cc927f5abfd7
|
||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||
|
@ -10,8 +10,8 @@ F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
|
|||
F doc/report1.txt ad0a41513479f1be0355d1f3f074e66779ff2282
|
||||
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
|
||||
F src/build.c 7aa5879bf58ea6bbff22c26c59d1130021fa6ca4
|
||||
F src/db.c 8e841538cc1079c99b050ba8694c7bd544b0a355
|
||||
F src/db.h 488f01d3c0182568b0ec1186149603e271e79c43
|
||||
F src/db.c 387cbf95f95bf4d2668cd01f64a60ffd59f43874
|
||||
F src/db.h f5ab793ad888c7905fbaaf9a675f576f4a3918bc
|
||||
F src/dbbe.c 162d29b09ac379f160892c5795efc14099dcc8eb
|
||||
F src/dbbe.h 0435a36906a839cce062608f51bd9d3e79878fec
|
||||
F src/dbbegdbm.c 5bfcb1b4ee47a98c5eae83041e9716cd3233fd0e
|
||||
|
@ -21,7 +21,7 @@ F src/expr.c 49bc261fdc4f4fb91c74cd668a9a952c00e85931
|
|||
F src/insert.c 4bc1cab84f7805d560a1417734a532843e30b762
|
||||
F src/main.c 92fcd6d967ceee1f96a5b9543779eef6e9b56913
|
||||
F src/parse.y 25ee4d8efccc4b247c32fe4ab194e3dd8fd5a4ee
|
||||
F src/pg.c 8bf498216976bea261e7a02724c4fdcc96f6ee2f
|
||||
F src/pg.c 2981173b2a752ef3578168e7af1a32ff22b70db6
|
||||
F src/pg.h a95c4803a1aae99449aa2c0a1af0c8d863a3f340
|
||||
F src/printf.c 1efb6b3e7f28a93be57132de3f8f400d2ac1460e
|
||||
F src/random.c 3dc42fb35d834901577aa547308ff3c8941fea25
|
||||
|
@ -84,7 +84,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
|
|||
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
|
||||
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
|
||||
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
|
||||
P 0529c979fd17995aff82e21b91b5cc833f23d8ef
|
||||
R 190eb04a63af8235aad9df6267107e4c
|
||||
P 98da825312fd4bb8a20ff33293131c02beb3ae63
|
||||
R 65625e73d51d03039a82df767d26bb25
|
||||
U drh
|
||||
Z da6be622c2a2caa5949500b0c0127edd
|
||||
Z aad6c859441db92bc7fcd45e2633d4de
|
||||
|
|
|
@ -1 +1 @@
|
|||
98da825312fd4bb8a20ff33293131c02beb3ae63
|
||||
edb01b1275c3de7c398522b5826c898917811247
|
592
src/db.c
592
src/db.c
|
@ -21,7 +21,7 @@
|
|||
** http://www.hwaci.com/drh/
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: db.c,v 1.3 2001/01/22 00:31:53 drh Exp $
|
||||
** $Id: db.c,v 1.4 2001/01/25 01:45:40 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pg.h"
|
||||
|
@ -52,6 +52,8 @@ struct DbIdxpt {
|
|||
int pgno; /* The page number */
|
||||
u32 *aPage; /* The page data */
|
||||
int idx; /* Index into pPage[] */
|
||||
int hashLB; /* Lower bound on hash at this level */
|
||||
int hashUB; /* Upper bound on hash at this level */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -120,35 +122,84 @@ struct DbCursor {
|
|||
** 4... root pages numbers of tables
|
||||
*/
|
||||
|
||||
/*
|
||||
** The number of u32-sized objects that will fit on one page.
|
||||
*/
|
||||
#define U32_PER_PAGE (SQLITE_PAGE_SIZE/sizeof(u32))
|
||||
#deifne LOCAL_PAYLOAD (SQLITE_PAGE_SIZE - 18*sizeof(u32))
|
||||
|
||||
/*
|
||||
** Byte swapping code.
|
||||
** Number of direct overflow pages per database entry
|
||||
*/
|
||||
#ifdef BIG_ENDIAN
|
||||
# SWB(x) (x)
|
||||
#else
|
||||
# SWB(x) sqliteDbSwapBytes(x)
|
||||
#endif
|
||||
#define N_DIRECT 10
|
||||
|
||||
static u32 sqliteDbSwapBytes(u32 x){
|
||||
unsigned char c, *s, *d;
|
||||
s = (unsigned char*)&x;
|
||||
d = (unsigned char*)&r;
|
||||
d[0] = s[3];
|
||||
d[1] = s[2];
|
||||
d[2] = s[1];
|
||||
d[3] = s[0];
|
||||
return r;
|
||||
/*
|
||||
** The maximum amount of payload that will fit on on the same
|
||||
** page as a leaf, assuming the leaf contains only a single
|
||||
** database entry and the entry uses no overflow pages.
|
||||
*/
|
||||
#define LOCAL_PAYLOAD (SQLITE_PAGE_SIZE - (8+N_DIRECT)*sizeof(u32))
|
||||
|
||||
/*
|
||||
** Allocate a new page. Return both the page number and a pointer
|
||||
** to the page data. The calling function is responsible for unref-ing
|
||||
** the page when it is no longer needed.
|
||||
*/
|
||||
int allocPage(Db *pDb, u32 *pPgno, u32 **ppPage){
|
||||
u32 pgno;
|
||||
int rc;
|
||||
|
||||
if( pDb->aContent==0 ) return SQLITE_NOMEM;
|
||||
|
||||
/* Try to reuse a page from the freelist
|
||||
*/
|
||||
pgno = pDb->aContent[0];
|
||||
if( pgno!=0 ){
|
||||
rc = sqlitePgGet(pDb->pPgr, pgno, (void**)ppPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
pDb->aContent[0] = pFree[1];
|
||||
*pPgno = pgno;
|
||||
memset(*ppPage, 0, SQLITE_PAGE_SIZE);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the freelist is empty, or we cannot access it,
|
||||
** then allocate a new page from the end of the file.
|
||||
*/
|
||||
if( (rc = sqlitePgCount(pDb->pPgr, &pgno))==SQLITE_OK &&
|
||||
(rc = sqlitePgGet(pDb->pPgr, pgno, (void**)ppPage))==SQLITE_OK ){
|
||||
*pPgno = pgno;
|
||||
memset(*ppPage, 0, SQLITE_PAGE_SIZE);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
** Return a page to the freelist and dereference the page.
|
||||
*/
|
||||
static void freePage(DB *pDb, u32 pgno, u32 *aPage){
|
||||
if( pDb->aContent==0 ) return;
|
||||
if( pgno==0 ) return
|
||||
if( aPage==0 ){
|
||||
int rc;
|
||||
rc = sqlitePgGet(pDb->pPgr, pgno, &aPage);
|
||||
if( rc!=SQLITE_OK ) return;
|
||||
}
|
||||
aPage[0] = BLOCK_MAGIC | BLOCK_FREE;
|
||||
aPage[1] = pDb->aContent[0];
|
||||
memset(&aPage[2], 0, SQLITE_PAGE_SIZE - 2*sizeof(u32));
|
||||
pDb->aContent[0] = pgno;
|
||||
sqlitePgTouch(aPage);
|
||||
sqlitePgUnref(aPage);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes of payload storage required on the leaf
|
||||
** node to hold the key and data given. Overflow pages do not count.
|
||||
** The argument is the total size of the payload.
|
||||
** node to hold the amount of payload specified by the argument.
|
||||
** Overflow pages do not count, only memory on the leaf page.
|
||||
**
|
||||
** Return -1 if nTotal is more than sqlite is able to store.
|
||||
*/
|
||||
static int payloadLocalSize(int nTotal){
|
||||
int nLocal, i;
|
||||
|
@ -162,8 +213,8 @@ static int payloadLocalSize(int nTotal){
|
|||
if( nTotal < 10*SQLITE_PAGE_SIZE ){
|
||||
return nLocal + ((nTotal+SQLITE_PAGE_SIZE-1)/SQLITE_PAGE_SIZE)*sizeof(u32);
|
||||
}
|
||||
nLocal += 10*sizeof(u32);
|
||||
nTotal -= 10*SQLITE_PAGE_SIZE;
|
||||
nLocal += N_DIRECT*sizeof(u32);
|
||||
nTotal -= N_DIRECT*SQLITE_PAGE_SIZE;
|
||||
if( nTotal < U32_PER_PAGE*SQLITE_PAGE_SIZE ){
|
||||
return nLocal + sizeof(u32);
|
||||
}
|
||||
|
@ -184,116 +235,132 @@ static int payloadLocalSize(int nTotal){
|
|||
*/
|
||||
static int payloadRead(Db *pDb, u32 *aPage, int offset, int amt, void *pBuf){
|
||||
int rc;
|
||||
int toread, more;
|
||||
int tomove;
|
||||
int i;
|
||||
|
||||
/* First read local data off of the leaf page itself.
|
||||
** This is all that ever happens in 99% of accesses.
|
||||
*/
|
||||
assert( offset>=0 && amt>=0 );
|
||||
if( offset < LOCAL_PAYLOAD ){
|
||||
/* Data stored directly in the leaf block of the BTree */
|
||||
if( amt+offset>LOCAL_PAYLOAD ){
|
||||
toread = LOCAL_PAYLOAD - offset;
|
||||
more = 1;
|
||||
tomove = LOCAL_PAYLOAD - offset;
|
||||
}else{
|
||||
toread = amt;
|
||||
more = 0;
|
||||
tomove = amt;
|
||||
}
|
||||
memcpy(pBuf, &((char*)aPage)[offset], toread);
|
||||
if( !more ) return SQLITE_OK;
|
||||
pBuf = &((char*)pBuf)[toread];
|
||||
offset += toread;
|
||||
amt -= toread;
|
||||
memcpy(pBuf, &((char*)aPage)[offset], tomove);
|
||||
pBuf = &((char*)pBuf)[tomove];
|
||||
offset += tomove;
|
||||
amt -= tomove;
|
||||
if( amt<=0 ) return SQLITE_OK;
|
||||
}
|
||||
offset -= LOCAL_PAYLOAD;
|
||||
aPage += LOCAL_PAYLOAD/sizeof(aPage[0]);
|
||||
while( offset < 10*SQLITE_PAGE_SIZE ){
|
||||
/* Data stored in one of 10 direct pages */
|
||||
int iDir;
|
||||
char *aData;
|
||||
iDir = offset/SQLITE_PAGE_SIZE;
|
||||
base = offset - iDir*SQLITE_PAGE_SIZE;
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[iDir], &aData);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( amt+base > SQLITE_PAGE_SIZE ){
|
||||
toread = SQLITE_PAGE_SIZE - base;
|
||||
more = 1;
|
||||
}else{
|
||||
toread = amt;
|
||||
more = 0;
|
||||
|
||||
/* If not all of the data fits locally, read from the first
|
||||
** ten direct-access overflow pages.
|
||||
*/
|
||||
if( offset < N_DIRECT*SQLITE_PAGE_SIZE ){
|
||||
for(i=offset/SQLITE_PAGE_SIZE; i<N_DIRECT && amt>0; i++){
|
||||
char *aData;
|
||||
base = offset - i*SQLITE_PAGE_SIZE;
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[i], &aData);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( amt+base > SQLITE_PAGE_SIZE ){
|
||||
tomove = SQLITE_PAGE_SIZE - base;
|
||||
}else{
|
||||
tomove = amt;
|
||||
}
|
||||
memcpy(pBuf, &aData[base], tomove);
|
||||
sqlitePgUnref(aData);
|
||||
pBuf = &((char*)pBuf)[tomove];
|
||||
amt -= tomove;
|
||||
}
|
||||
memcpy(pBuf, &aData[base], toread);
|
||||
sqlitePgUnref(aData);
|
||||
if( !more ) return SQLITE_OK;
|
||||
pBuf = &((char*)pBuf)[toread];
|
||||
amt -= toread;
|
||||
offset += toread;
|
||||
}
|
||||
offset -= 10*SQLITE_PAGE_SIZE;
|
||||
aPage += 10;
|
||||
offset -= N_DIRECT*SQLITE_PAGE_SIZE;
|
||||
aPage += N_DIRECT;
|
||||
|
||||
/* If the first N_DIRECT overflow pages do not contain everything, then
|
||||
** read from an overflow page that is filled with pointer to
|
||||
** U32_PER_PAGE more overflow pages.
|
||||
*/
|
||||
if( offset < U32_PER_PAGE*SQLITE_PAGE_SIZE ){
|
||||
/* Data stored in an indirect page */
|
||||
u32 *indirPage;
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[0], &indirPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
while( amt>0 && offset < U32_PER_PAGE*SQLITE_PAGE_SIZE ){
|
||||
int idx, base;
|
||||
for(i=offset/SQLITE_PAGE_SIZE; i<U32_PER_PAGE && amt>0; i++){
|
||||
int base;
|
||||
char *aData;
|
||||
idx = offset/SQLITE_PAGE_SIZE;
|
||||
base = offset - idx*SQLITE_PAGE_SIZE;
|
||||
base = offset - i*SQLITE_PAGE_SIZE;
|
||||
rc = sqlitePgGet(pDb->pPgr, indirPage[idx], &aData);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
if( amt+base > SQLITE_PAGE_SIZE ){
|
||||
toread = SQLITE_PAGE_SIZE - base;
|
||||
tomove = SQLITE_PAGE_SIZE - base;
|
||||
}else{
|
||||
toread = amt;
|
||||
tomove = amt;
|
||||
}
|
||||
memcpy(pBuf, &aData[base], toread);
|
||||
memcpy(pBuf, &aData[base], tomove);
|
||||
sqlitePgUnref(aData);
|
||||
pBuf = &((char*)pBuf)[toread];
|
||||
amt -= toread;
|
||||
offset += toread;
|
||||
pBuf = &((char*)pBuf)[tomove];
|
||||
amt -= tomove;
|
||||
}
|
||||
sqlitePgUnref(indirPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( amt<=0 ) return SQLITE_OK;
|
||||
}
|
||||
offset -= U32_PER_PAGE*SQLITE_PAGE_SIZE;
|
||||
aPage++;
|
||||
|
||||
/* If there is still more data, then read using a double-indirect
|
||||
** overflow. The overflow page points to U32_PER_PAGE additional
|
||||
** overflow pages, each of which pointer to U32_PER_PAGE more overflow
|
||||
** pages which contain data.
|
||||
**
|
||||
** This is hard to test. To exercise this code, you have to make
|
||||
** a database entry of more than 273336 bytes in side, assuming a
|
||||
** pagesize of 1024 bytes and 10 direct overflow pages. By the
|
||||
** time this code runs, you have already used 267 overflow pages.
|
||||
*/
|
||||
if( offset < U32_PER_PAGE*U32_PER_PAGE*SQLITE_PAGE_SIZE ){
|
||||
/* Data stored in a double-indirect page */
|
||||
u32 *dblIndirPage;
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
while( amt>0 && offset < U32_PER_PAGE*U32_PER_PAGE*SQLITE_PAGE_SIZE ){
|
||||
int dblidx;
|
||||
i = offset/(U32_PER_PAGE*SQLITE_PAGE_SIZE);
|
||||
for(; i<U32_PER_PAGE && amt>0; i++){
|
||||
u32 *indirPage;
|
||||
int basis;
|
||||
dblidx = offset/(U32_PER_PAGE*SQLITE_PAGE_SIZE);
|
||||
rc = sqlitePgGet(pDb->pPgr, dblIndirPage[dblidx], &indirPage);
|
||||
int j;
|
||||
rc = sqlitePgGet(pDb->pPgr, dblIndirPage[i], &indirPage);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
basis = dblidx*U32_PER_PAGE*SQLITE_PAGE_SIZE;
|
||||
while( amt>0 && offset < basis + U32_PER_PAGE*SQLITE_PAGE_SIZE ){
|
||||
int idx, base;
|
||||
basis = i*U32_PER_PAGE*SQLITE_PAGE_SIZE;
|
||||
j = (offset - basis)/SQLITE_PAGE_SIZE;
|
||||
for(; j<U32_PER_PAGE && amt>0; j++){
|
||||
char *aData;
|
||||
idx = (offset - basis)/SQLITE_PAGE_SIZE;
|
||||
base = (offset - basis) - idx*SQLITE_PAGE_SIZE;
|
||||
rc = sqlitePgGet(pDb->pPgr, indirPage[idx], &aData);
|
||||
base = (offset - basis) - ij*SQLITE_PAGE_SIZE;
|
||||
rc = sqlitePgGet(pDb->pPgr, indirPage[j], &aData);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
if( amt+base > SQLITE_PAGE_SIZE ){
|
||||
toread = SQLITE_PAGE_SIZE - base;
|
||||
tomove = SQLITE_PAGE_SIZE - base;
|
||||
}else{
|
||||
toread = amt;
|
||||
tomove = amt;
|
||||
}
|
||||
memcpy(pBuf, &aData[base], toread);
|
||||
memcpy(pBuf, &aData[base], tomove);
|
||||
sqlitePgUnref(aData);
|
||||
pBuf = &((char*)pBuf)[toread];
|
||||
amt -= toread;
|
||||
offset += toread;
|
||||
pBuf = &((char*)pBuf)[tomove];
|
||||
amt -= tomove;
|
||||
}
|
||||
sqlitePgUnref(indirPage);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
sqlitePgUnref(dblIndirPage);
|
||||
return rc;
|
||||
}
|
||||
memset(pBuf, 0, amt);
|
||||
|
||||
/* Anything beyond the double-indirect pages, just fill in with
|
||||
** zeros. You have to write 67382200 bytes to go past the
|
||||
** double-indirect pages, assuming a 1024 byte page size.
|
||||
*/
|
||||
if( amt>0 ) memset(pBuf, 0, amt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -308,96 +375,241 @@ static int payloadRead(Db *pDb, u32 *aPage, int offset, int amt, void *pBuf){
|
|||
*/
|
||||
static int payloadWrite(Db *pDb, u32 *aPage, int offset, int amt, void *pBuf){
|
||||
assert( offset>=0 && amt>=0 );
|
||||
|
||||
/* Local data
|
||||
*/
|
||||
if( offset < LOCAL_PAYLOAD ){
|
||||
if( amt+offset>LOCAL_PAYLOAD ){
|
||||
towrite = LOCAL_PAYLOAD - offset;
|
||||
more = 1;
|
||||
tomove = LOCAL_PAYLOAD - offset;
|
||||
}else{
|
||||
towrite = amt;
|
||||
more = 0;
|
||||
tomove = amt;
|
||||
}
|
||||
memcpy(&((char*)aPage)[offset], pBuf, towrite);
|
||||
if( !more ) return SQLITE_OK;
|
||||
pBuf = &((char*)pBuf)[towrite];
|
||||
offset += toread;
|
||||
amt -= toread;
|
||||
memcpy(&((char*)aPage)[offset], pBuf, tomove);
|
||||
pBuf = &((char*)pBuf)[tomove];
|
||||
offset += tomove;
|
||||
amt -= tomove;
|
||||
if( amt<=0 ) return SQLITE_OK;
|
||||
}
|
||||
offset -= LOCAL_PAYLOAD;
|
||||
aPage += LOCAL_PAYLOAD/sizeof(aPage[0]);
|
||||
while( offset < 10*SQLITE_PAGE_SIZE ){
|
||||
int iDir;
|
||||
char *aData;
|
||||
iDir = offset/SQLITE_PAGE_SIZE;
|
||||
base = offset - iDir*SQLITE_PAGE_SIZE;
|
||||
if( aPage[iDir] ){
|
||||
rc = sqliteGet(pDb->pPgr, aPage[iDir], &aData);
|
||||
|
||||
/* Direct overflow pages
|
||||
*/
|
||||
if( offset < N_DIRECT*SQLITE_PAGE_SIZE ){
|
||||
for(i=offset/SQLITE_PAGE_SIZE; i<N_DIRECT && amt>0; i++){
|
||||
base = offset - i*SQLITE_PAGE_SIZE;
|
||||
if( aPage[i] ){
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[i], &aData);
|
||||
}else{
|
||||
rc = allocPage(pDb, &aPage[i], &aData);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( amt+base > SQLITE_PAGE_SIZE ){
|
||||
tomove = SQLITE_PAGE_SIZE - base;
|
||||
}else{
|
||||
tomove = amt;
|
||||
}
|
||||
memcpy(&aData[base], pBuf, tomove);
|
||||
sqlitePgTouch(aData);
|
||||
sqlitePgUnref(aData);
|
||||
pBuf = &((char*)pBuf)[tomove];
|
||||
amt -= tomove;
|
||||
}
|
||||
if( amt<=0 ) return SQLITE_OK;
|
||||
}
|
||||
offset -= N_DIRECT*SQLITE_PAGE_SIZE;
|
||||
aPage += N_DIRECT;
|
||||
|
||||
/* Indirect overflow pages
|
||||
*/
|
||||
if( offset < U32_PER_PAGE*SQLITE_PAGE_SIZE ){
|
||||
u32 *indirPage;
|
||||
if( aPage[0] ){
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[0], &indirPage);
|
||||
}else{
|
||||
rc = sqliteDbAllocPage(pDb, &aPage[iDir], &aData);
|
||||
rc = allocPage(pDb, &aPage[0], &indirPage);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( amt+base > SQLITE_PAGE_SIZE ){
|
||||
towrite = SQLITE_PAGE_SIZE - base;
|
||||
more = 1;
|
||||
}else{
|
||||
towrite = amt;
|
||||
more = 0;
|
||||
for(i=offset/SQLITE_PAGE_SIZE; i<U32_PER_PAGE && amt>0; i++){
|
||||
int base;
|
||||
char *aData;
|
||||
base = offset - i*SQLITE_PAGE_SIZE;
|
||||
if( indirPage[i] ){
|
||||
rc = sqlitePgGet(pDb->pPgr, indirPage[i], &aData);
|
||||
}else{
|
||||
rc = allocPage(pDb, &indirPage[i], &aData);
|
||||
sqlitePgTouch(indirPage);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
if( amt+base > SQLITE_PAGE_SIZE ){
|
||||
tomove = SQLITE_PAGE_SIZE - base;
|
||||
}else{
|
||||
tomove = amt;
|
||||
}
|
||||
memcpy(&aData[base], pBuf, tomove);
|
||||
sqlitePgUnref(aData);
|
||||
pBuf = &((char*)pBuf)[tomove];
|
||||
amt -= tomove;
|
||||
}
|
||||
memcpy(&aData[base], pBuf, towrite);
|
||||
sqlitePgUnref(aData);
|
||||
if( !more ) return SQLITE_OK;
|
||||
pBuf = &((char*)pBuf)[towrite];
|
||||
amt -= towrite;
|
||||
offset += towrite;
|
||||
sqlitePgUnref(indirPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( amt<=0 ) return SQLITE_OK;
|
||||
}
|
||||
/* TBD.... */
|
||||
offset -= U32_PER_PAGE*SQLITE_PAGE_SIZE;
|
||||
aPage++;
|
||||
|
||||
/* Double-indirect overflow pages
|
||||
*/
|
||||
if( offset < U32_PER_PAGE*U32_PER_PAGE*SQLITE_PAGE_SIZE ){
|
||||
u32 *dblIndirPage;
|
||||
if( aPage[0] ){
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
|
||||
}else{
|
||||
rc = allocPage(pDb, &aPage[0], &dblIndirPage);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
i = offset/(U32_PER_PAGE*SQLITE_PAGE_SIZE);
|
||||
for(; i<U32_PER_PAGE && amt>0; i++){
|
||||
u32 *indirPage;
|
||||
int basis;
|
||||
int j;
|
||||
if( aPage[0] ){
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
|
||||
}else{
|
||||
rc = allocPage(pDb, &aPage[0], &dblIndirPage);
|
||||
sqlitePgTouch(dblIndirPage);
|
||||
}
|
||||
rc = sqlitePgGet(pDb->pPgr, dblIndirPage[i], &indirPage);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
basis = i*U32_PER_PAGE*SQLITE_PAGE_SIZE;
|
||||
j = (offset - basis)/SQLITE_PAGE_SIZE;
|
||||
for(; j<U32_PER_PAGE && amt>0; j++){
|
||||
char *aData;
|
||||
base = (offset - basis) - ij*SQLITE_PAGE_SIZE;
|
||||
if( indirPage[j] ){
|
||||
rc = sqlitePgGet(pDb->pPgr, indirPage[j], &aData);
|
||||
}else{
|
||||
rc = allocPage(pDb, &indirPage[j], &aData);
|
||||
sqlitePgTouch(indirPage);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
if( amt+base > SQLITE_PAGE_SIZE ){
|
||||
tomove = SQLITE_PAGE_SIZE - base;
|
||||
}else{
|
||||
tomove = amt;
|
||||
}
|
||||
memcpy(&aData[base], pBuf, tomove);
|
||||
sqlitePgTouch(aData);
|
||||
sqlitePgUnref(aData);
|
||||
pBuf = &((char*)pBuf)[tomove];
|
||||
amt -= tomove;
|
||||
}
|
||||
sqlitePgUnref(indirPage);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
sqlitePgUnref(dblIndirPage);
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Release any and all overflow pages associated with data starting
|
||||
** with byte "newSize" up to but not including "oldSize".
|
||||
** with byte "newSize". oldSize is the amount of payload before doing
|
||||
** the free operation.
|
||||
*/
|
||||
static int payloadFree(Db *pDb, u32 *aPage, int newSize, int oldSize){
|
||||
int i;
|
||||
int i, j; /* Loop counters */
|
||||
int first, last; /* Indices of first and last pages to be freed */
|
||||
int rc; /* Return code from sqlitePgGet() */
|
||||
|
||||
if( newSize>=oldSize ) return;
|
||||
/* Skip over the local data. We do not need to free it.
|
||||
*/
|
||||
if( newSize>=oldSize ) return SQLITE_OK;
|
||||
oldSize -= LOCAL_PAYLOAD;
|
||||
if( oldSize<=0 ) return SQLITE_OK;
|
||||
newSize -= LOCAL_PAYLOAD;
|
||||
if( newSize<0 ) newSize = 0;
|
||||
aPage += LOCAL_PAYLOAD/sizeof(u32);
|
||||
*************
|
||||
for(i=0; i<10; i++){
|
||||
sqliteDbFreePage(pDb, aPage[0], 0);
|
||||
amt -= SQLITE_PAGE_SIZE;
|
||||
if( amt<=0 ) return SQLITE_OK;
|
||||
aPage++;
|
||||
}
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[0], &indirPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
for(i=0; i<U32_PER_PAGE; i++){
|
||||
if( indirPage[i]==0 ) continue;
|
||||
sqliteDbFreePage(pDb, indirPage[i], 0);
|
||||
}
|
||||
sqliteDbFreePage(pDb, aPage[0], indirPage);
|
||||
sqlitePgUnref(indirPage);
|
||||
amt -= U32_PER_PAGE*SQLITE_PAGE_SIZE;
|
||||
if( amt<=0 ) return SQLITE_OK;
|
||||
aPage++;
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
for(i=0; i<U32_PER_PAGE; i++){
|
||||
if( dblIndirPage[i]==0 ) continue;
|
||||
rc = sqlitePgGet(pDb->pPgr, dblIndirPage[i], &indirPage);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
for(j=0; j<U32_PER_PAGE; j++){
|
||||
if( indirPage[j]==0 ) continue;
|
||||
sqliteDbFreePage(pDb, dblIndirPage[i], 0);
|
||||
|
||||
/* Compute the indices of the first and last overflow pages to
|
||||
** be freed.
|
||||
*/
|
||||
first = (newSize - 1)/SQLITE_PAGE_SIZE + 1;
|
||||
last = (oldSize - 1)/SQLITE_PAGE_SIZE;
|
||||
|
||||
/* Free the direct overflow pages
|
||||
*/
|
||||
if( first < N_DIRECT ){
|
||||
for(i=first; i<N_DIRECT && i<=last; i++){
|
||||
freePage(pDb, aPage[i], 0);
|
||||
aPage[i] = 0;
|
||||
}
|
||||
sqliteDbFreePage(pDb, dblIndirPage[i], indirPage);
|
||||
sqlitePgUnder(indirPage);
|
||||
}
|
||||
sqliteDbFreePage(pDb, aPage[0], dblIndirPage);
|
||||
sqlitePgUnref(dblIndirPage);
|
||||
aPage += N_DIRECT;
|
||||
first -= N_DIRECT;
|
||||
last -= N_DIRECT;
|
||||
if( last<0 ) return SQLITE_OK;
|
||||
if( first<0 ) first = 0;
|
||||
|
||||
/* Free indirect overflow pages
|
||||
*/
|
||||
if( first < U32_PER_PAGE ){
|
||||
u32 *indirPage;
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[0], &indirPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
for(i=first; i<U32_PER_PAGE && i<=last; i++){
|
||||
freePage(pDb, indirPage[i], 0);
|
||||
indirPage[i] = 0;
|
||||
touch = 1;
|
||||
}
|
||||
if( first<=0 ){
|
||||
freepage(pDb, aPage[0], indirPage);
|
||||
aPage[0] = 0;
|
||||
}else{
|
||||
sqlitePgTouch(indirPage);
|
||||
sqlitePgUnref(indirPage);
|
||||
}
|
||||
}
|
||||
aPage++;
|
||||
first -= U32_PER_PAGE;
|
||||
last -= U32_PER_PAGE;
|
||||
if( last<0 ) return SQLITE_OK;
|
||||
if( first<0 ) first = 0;
|
||||
|
||||
/* Free double-indirect overflow pages
|
||||
*/
|
||||
if( first < U32_PER_PAGE*U32_PER_PAGE ){
|
||||
u32 *dblIndirPage;
|
||||
rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
for(i=first/U32_PER_PAGE; i<U32_PER_PAGE; i++){
|
||||
u32 *indirPage;
|
||||
basis = i*U32_PER_PAGE;
|
||||
if( last < basis ) break;
|
||||
rc = sqlitePgGet(pDb->pPgr, dblIndirPage[i], &indirPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
for(j=first>basis?first-basis:0 ; j<U32_PER_PAGE; j++){
|
||||
if( j + basis > last ) break;
|
||||
freePage(pDb, indirPage[j], 0);
|
||||
indirPage[j] = 0;
|
||||
}
|
||||
if( first<=basis ){
|
||||
freepage(pDb, dblIndirPage[i], 0);
|
||||
dblIndirPage[i] = 0;
|
||||
}else{
|
||||
sqlitePgTouch(indirPage);
|
||||
sqlitePgUnref(indirPage);
|
||||
}
|
||||
}
|
||||
if( first<=0 ){
|
||||
freepage(pDb, aPage[0], dblIndirPage);
|
||||
aPage[0] = 0;
|
||||
}else{
|
||||
sqlitePgTouch(dblIndirPage);
|
||||
sqlitePgUnref(dblIndirPage);
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -418,46 +630,6 @@ static int sqliteDbExpandContent(Db *pDb, int newSize){
|
|||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate a new page. Return both the page number and a pointer
|
||||
** to the page data. The calling function is responsible for unref-ing
|
||||
** the page when it is no longer needed.
|
||||
*/
|
||||
int sqliteDbAllocPage(Db *pDb, u32 *pPgno, u32 **ppPage){
|
||||
u32 pgno;
|
||||
int rc;
|
||||
|
||||
if( pDb->aContent==0 ) return SQLITE_NOMEM;
|
||||
pgno = SWB(pDb->aContent[0]);
|
||||
if( pgno!=0 ){
|
||||
rc = sqlitePgGet(pDb->pPgr, pgno, (void**)ppPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
pDb->aContent[0] = pFree[1];
|
||||
*pPgno = pgno;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
if( (rc = sqlitePgCount(pDb->pPgr, &pgno))==SQLITE_OK &&
|
||||
(rc = sqlitePgGet(pDb->pPgr, pgno, (void**)ppPage))==SQLITE_OK ){
|
||||
*pPgno = pgno;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a page to the freelist and dereference the page.
|
||||
*/
|
||||
static void sqliteDbFreePage(DB *pDb, u32 pgno, u32 *aPage){
|
||||
if( pDb->aContent==0 ) return;
|
||||
aPage[0] = SWB(BLOCK_MAGIC | BLOCK_FREE);
|
||||
aPage[1] = pDb->aContent[0];
|
||||
memset(&aPage[2], 0, SQLITE_PAGE_SIZE - 2*sizeof(u32));
|
||||
pDb->aContent[0] = SWB(pgno);
|
||||
sqlitePgTouch(aPage);
|
||||
sqlitePgUnref(aPage);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a database.
|
||||
*/
|
||||
|
@ -589,7 +761,7 @@ int sqliteDbCreateTable(Db *pDb, int *pTblno){
|
|||
int swTblno;
|
||||
int i;
|
||||
|
||||
rc = sqliteDbAllocPage(pDb, &pgno, &pPage);
|
||||
rc = allocPage(pDb, &pgno, &pPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
@ -629,15 +801,15 @@ static int sqliteDbDropPage(Db *pDb, u32 pgno){
|
|||
|
||||
rc = sqlitePgGet(pDb->pPgr, pgno, (void**)&aPage);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
switch( SWB(aPage[0]) ){
|
||||
switch( aPage[0] ){
|
||||
case BLOCK_MAGIC | BLOCK_INDEX: {
|
||||
int n, i;
|
||||
n = SWB(aPage[2]);
|
||||
n = aPage[2];
|
||||
for(i=0; i<n; i++){
|
||||
u32 subpgno = SWB(aPage[3+i*2]);
|
||||
u32 subpgno = aPage[3+i*2];
|
||||
sqliteDbDropPage(pDb, subpgno);
|
||||
}
|
||||
sqliteDbFreePage(pDb, pgno, aPage);
|
||||
freePage(pDb, pgno, aPage);
|
||||
break;
|
||||
}
|
||||
case BLOCK_MAGIC | BLOCK_LEAF: {
|
||||
|
@ -648,18 +820,7 @@ static int sqliteDbDropPage(Db *pDb, u32 pgno){
|
|||
sqliteDbClearEntry(pDb, &aPage[i]);
|
||||
i += entrySize;
|
||||
}
|
||||
sqliteDbFreePage(pDb, pgno, aPage);
|
||||
break;
|
||||
}
|
||||
case BLOCK_MAGIC | BLOCK_OVERFLOW: {
|
||||
for(;;){
|
||||
u32 nx = SWB(aPage[1]);
|
||||
sqliteDbFreePage(pDb, pgno, aPage);
|
||||
if( nx==0 ) break;
|
||||
pgno = nx;
|
||||
sqlitePgUnref(aPage);
|
||||
sqlitePgGet(pDb->pPgr, pgno, &aPage);
|
||||
}
|
||||
freePage(pDb, pgno, aPage);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -675,21 +836,6 @@ static int sqliteDbDropPage(Db *pDb, u32 pgno){
|
|||
** this entry.
|
||||
*/
|
||||
static int sqliteDbClearEntry(Db *pDb, u32 *aEntry){
|
||||
int nByte;
|
||||
int idx;
|
||||
|
||||
idx = 4;
|
||||
nByte = SWB(aEntry[2]);
|
||||
if( nByte & 0x80000000 ){
|
||||
sqliteDbDropPage(pDb, SWB(aEntry[idx]));
|
||||
idx++;
|
||||
}else{
|
||||
idx += (nByte + 3)/4;
|
||||
}
|
||||
nByte = SWB(aEntry[3]);
|
||||
if( nByte & 0x80000000 ){
|
||||
sqliteDbDropPage(pDb, SWB(aEntry[idx]));
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -1249,7 +1395,7 @@ int sqliteDbCursorInsert(
|
|||
}else{
|
||||
u32 newPgno, *newPage;
|
||||
aPage[i+2] = SWB(nKey | 0x80000000);
|
||||
rc = sqliteDbAllocPage(pCur->pDb, &newPgno, &newPage);
|
||||
rc = allocPage(pCur->pDb, &newPgno, &newPage);
|
||||
if( rc!=SQLITE_OK ) goto write_err;
|
||||
aPage[i+4] = SWB(newPgno);
|
||||
newPage[0] = SWB(BLOCK_MAGIC | BLOCK_OVERFLOW);
|
||||
|
@ -1266,7 +1412,7 @@ int sqliteDbCursorInsert(
|
|||
}else{
|
||||
u32 newPgno, *newPage;
|
||||
aPage[i+3] = SWB(nData | 0x80000000);
|
||||
rc = sqliteDbAllocPage(pCur->pDb, &newPgno, &newPage);
|
||||
rc = allocPage(pCur->pDb, &newPgno, &newPage);
|
||||
if( rc!=SQLITE_OK ) goto write_err;
|
||||
aPage[j] = SWB(newPgno);
|
||||
newPage[0] = SWB(BLOCK_MAGIC | BLOCK_OVERFLOW);
|
||||
|
|
14
src/db.h
14
src/db.h
|
@ -21,7 +21,7 @@
|
|||
** http://www.hwaci.com/drh/
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: db.h,v 1.2 2001/01/20 19:52:49 drh Exp $
|
||||
** $Id: db.h,v 1.3 2001/01/25 01:45:40 drh Exp $
|
||||
*/
|
||||
|
||||
typedef struct Db Db;
|
||||
|
@ -43,10 +43,8 @@ int sqliteDbCursorFirst(DbCursor*);
|
|||
int sqliteDbCursorNext(DbCursor*);
|
||||
int sqliteDbCursorDatasize(DbCursor*);
|
||||
int sqliteDbCursorKeysize(DbCursor*);
|
||||
int sqliteDbCursorRead(DbCursor*, int amt, int offset, char *buf);
|
||||
int sqliteDbCursorReadKey(DbCursor*, int amt, int offset, char *buf);
|
||||
int sqliteDbCursorMoveTo(DbCursor*, int nKey, void *pKey);
|
||||
int sqliteDbCursorDelete(DbCursor*);
|
||||
int sqliteDbCursorInsert(DbCursor*, int nKey, void *pKey, int nData, void *pD);
|
||||
|
||||
int sqliteDbReorganize(Db*);
|
||||
int sqliteDbCursorRead(DbCursor*, int amt, int offset, void *buf);
|
||||
int sqliteDbCursorReadKey(DbCursor*, int amt, int offset, void *buf);
|
||||
int sqliteDbCursorFind(DbCursor*, int nKey, const void *pKey, int createSize);
|
||||
int sqliteDbCursorResize(DbCursor*, int nData);
|
||||
int sqliteDbCursorWrite(DbCursor*, int amt, int offset, const void *buf);
|
||||
|
|
11
src/pg.c
11
src/pg.c
|
@ -21,7 +21,7 @@
|
|||
** http://www.hwaci.com/drh/
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: pg.c,v 1.3 2001/01/21 00:58:08 drh Exp $
|
||||
** $Id: pg.c,v 1.4 2001/01/25 01:45:41 drh Exp $
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -256,7 +256,7 @@ static Pghdr *sqlitePgFindJidx(Pgr *p, u32 pgno){
|
|||
static u32 sqlitePgJournalPageNumber(Pgr *p, u32 dbpgno){
|
||||
u32 jpgno;
|
||||
|
||||
assert( dbpgno>0 );
|
||||
if( dbpgno==0 ) return 0;
|
||||
jpgno = p->aJHash[dbpgno % J_HASH_SIZE];
|
||||
while( jpgno!=0 ){
|
||||
int idx_num; /* Which journal index describes page jpgno */
|
||||
|
@ -638,9 +638,12 @@ int sqlitePgGet(Pgr *p, u32 pgno, void **ppData){
|
|||
if( pPg->jpgno!=0 ){
|
||||
TRACE(("PG: reading d-page %u content from j-page %u\n", pgno, pPg->jpgno));
|
||||
sqlitePgRead(p->fdJournal, PG_TO_DATA(pPg), pPg->jpgno);
|
||||
}else{
|
||||
}else if( pPg->dbpgno!=0 ){
|
||||
TRACE(("PG: reading d-page %u from database\n", pgno));
|
||||
sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
|
||||
}else{
|
||||
TRACE(("PG: reading zero page\n");
|
||||
memset(PG_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);
|
||||
}
|
||||
pPg->isDirty = 0;
|
||||
pPg->nRef = 1;
|
||||
|
@ -691,7 +694,7 @@ int sqlitePgTouch(void *pD){
|
|||
** Return the number of the first unused page at the end of the
|
||||
** database file.
|
||||
*/
|
||||
int sqlitePgAlloc(Pgr *p, u32 *pPgno){
|
||||
int sqlitePgCount(Pgr *p, u32 *pPgno){
|
||||
*pPgno = p->nDbPg;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue