]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
:-) (CVS 1712)
authordrh <drh@noemail.net>
Thu, 25 Jan 2001 01:45:40 +0000 (01:45 +0000)
committerdrh <drh@noemail.net>
Thu, 25 Jan 2001 01:45:40 +0000 (01:45 +0000)
FossilOrigin-Name: edb01b1275c3de7c398522b5826c898917811247

manifest
manifest.uuid
src/db.c
src/db.h
src/pg.c

index 045776eb8d7e376f4d0d71d056aa4abce16db012..c83c70d72c2e1ff4a7eea4bcf5d55f5f9655bbcf 100644 (file)
--- a/manifest
+++ b/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
index fd1845f763314342dd6d36ab247392aad9e3bd15..d1cb80e42ded0eaedaa72fa21f2badddf4e06da0 100644 (file)
@@ -1 +1 @@
-98da825312fd4bb8a20ff33293131c02beb3ae63
\ No newline at end of file
+edb01b1275c3de7c398522b5826c898917811247
\ No newline at end of file
index 74c3dfdf7b089c227d8a08a3814898274a68cdda..440f6931bbad52ee4fe57a3d4b01fae1d69ae58e 100644 (file)
--- a/src/db.c
+++ b/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
-
-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;
+#define N_DIRECT  10
+
+/*
+** 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;
+    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;
+    }
+    sqlitePgUnref(indirPage);
+    if( rc!=SQLITE_OK ) return rc;
+    if( amt<=0 ) return SQLITE_OK;
+  }
+  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{
-      towrite = amt;
-      more = 0;
+      rc = allocPage(pDb, &aPage[0], &dblIndirPage);
     }
-    memcpy(&aData[base], pBuf, towrite);
-    sqlitePgUnref(aData);
-    if( !more ) return SQLITE_OK;
-    pBuf = &((char*)pBuf)[towrite];
-    amt -= towrite;
-    offset += towrite;
-  }
-  /* TBD.... */
+    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++;
+
+  /* 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;
+    }
+  }
+  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);
+    }
   }
-  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);
+  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);
     }
-    sqliteDbFreePage(pDb, dblIndirPage[i], indirPage);
-    sqlitePgUnder(indirPage);
   }
-  sqliteDbFreePage(pDb, aPage[0], 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);
index ef7247a96554f2a73f15618f07608e9a67a171fa..667d42ce9de8a3a88f4e4287525dcc27d847e0c0 100644 (file)
--- a/src/db.h
+++ b/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);
index 5dd8888542fdb87bbcefb2c493e5b2b2c80da4f0..f622a80d77d6d5e988d87be799ade400d18d183b 100644 (file)
--- a/src/pg.c
+++ b/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;
 }