]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
continued progress toward version 2.0 (CVS 177)
authordrh <drh@noemail.net>
Mon, 15 Jan 2001 22:51:08 +0000 (22:51 +0000)
committerdrh <drh@noemail.net>
Mon, 15 Jan 2001 22:51:08 +0000 (22:51 +0000)
FossilOrigin-Name: c6ffb7ec6acb596907ead8992dfad94e18e83866

21 files changed:
manifest
manifest.uuid
src/build.c
src/db.h [new file with mode: 0644]
src/dbbe.c
src/dbbe.h
src/dbbegdbm.c
src/dbbemem.c
src/delete.c
src/expr.c
src/insert.c
src/main.c
src/pg.c [new file with mode: 0644]
src/pg.h [new file with mode: 0644]
src/select.c
src/sqlite.h.in
src/sqliteInt.h
src/update.c
src/vdbe.c
src/vdbe.h
src/where.c

index 1a1d55104967e74289c112bb7f25d5b080762f29..c1b04d98f3897ede24def7a132b61fcec6e5a29c 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Changes\sto\sthe\sDBBE.\s\sMoving\stoward\shaving\smany\smore\nbackend\sdriver\schoices.\s(CVS\s176)
-D 2001-01-13T14:34:06
+C continued\sprogress\stoward\sversion\s2.0\s(CVS\s177)
+D 2001-01-15T22:51:09
 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
 F Makefile.in 7efa81e2985b45ba73db27d55b70cc927f5abfd7
 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
@@ -7,31 +7,34 @@ F VERSION 05e17b646a817240c206186f94f8f4c70974d5dc
 F configure 3dc1edb9dcf60215e31ff72b447935ab62211442 x
 F configure.in d892ca33db7e88a055519ce2f36dcb11020e8fff
 F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
-F src/build.c e2ceba852dc45ca899e68a042b29c3daab011575
-F src/dbbe.c 50e97d6dced263ce55ee992905a68dd65d15f9e8
-F src/dbbe.h c447dad03396ab7da690ba7b31dd37cb30cd64af
-F src/dbbegdbm.c 9684095a11a2aad60322df0084d7e6cae3509ecc
-F src/dbbemem.c f443a831e131eaf4e344ee96b3f52fec22cf04e0
-F src/delete.c 4d491eaf61b515516749c7ed68fa3b2ee8a09065
-F src/expr.c 7d7646afd52d1448237e5f517454cfb2d3d394d6
-F src/insert.c f146f149ad2422a1dc3bfa7a1651a25940f98958
-F src/main.c 340e5b04ce1222e4a75df7cb96bc2d0a236e881c
+F src/build.c 7aa5879bf58ea6bbff22c26c59d1130021fa6ca4
+F src/db.h 6eac00c2ccc30f5880f37d43c0552b0ad24ed708
+F src/dbbe.c 162d29b09ac379f160892c5795efc14099dcc8eb
+F src/dbbe.h 0435a36906a839cce062608f51bd9d3e79878fec
+F src/dbbegdbm.c 5bfcb1b4ee47a98c5eae83041e9716cd3233fd0e
+F src/dbbemem.c 215e107830ddf0d5a565bb7c20dd7200a925ef75
+F src/delete.c b83dc815f83220a82df13f1f1f479187d305fe6a
+F src/expr.c 49bc261fdc4f4fb91c74cd668a9a952c00e85931
+F src/insert.c 4bc1cab84f7805d560a1417734a532843e30b762
+F src/main.c 92fcd6d967ceee1f96a5b9543779eef6e9b56913
 F src/parse.y 25ee4d8efccc4b247c32fe4ab194e3dd8fd5a4ee
+F src/pg.c eb34521ec18454941b0823c6ce5c0e3c9394e733
+F src/pg.h 57e690df89a64a9a94be7efdb60fd057fbbc9a65
 F src/printf.c 1efb6b3e7f28a93be57132de3f8f400d2ac1460e
 F src/random.c 3dc42fb35d834901577aa547308ff3c8941fea25
-F src/select.c c1de8ac34131324fa05664b06b0ae1ee9c02905d
+F src/select.c 0cadab95c8011ddbffe804de94f12f3c0e317863
 F src/shell.c 441e20913cde0bb71281f4027623c623530241cd
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
-F src/sqlite.h.in fd86903777f1ee7bd0465243224a0fd2100eedc8
-F src/sqliteInt.h c5d2cc9ab270c24d6f7d705b03c801135b50fb39
+F src/sqlite.h.in ce548e14c257889b1d30157e5481220073a25d19
+F src/sqliteInt.h 449877f3fee866f5154616d60d6b543ab3ec1667
 F src/table.c 5be76051a8ed6f6bfa641f4adc52529efa34fbf9
 F src/tclsqlite.c 178adf318eab2ff480c288a87541d4ab1c37d985
 F src/tokenize.c 6843f1d7a5d2ee08ceb10bdecfcc8684131ffcf7
-F src/update.c 51b9ef7434b15e31096155da920302e9db0d27fc
+F src/update.c 9692fbac8e95fdbc5318d39db576aa6c57b9c8ab
 F src/util.c 0298100e6427a4b644f767ede12276fa7170fbb6
-F src/vdbe.c 46abf920b03a33e724c23049ab4017703ba18e28
-F src/vdbe.h 140cdec3c56f70483e169f8ae657bd90f9fd6e98
-F src/where.c 3dfad2ffd0aa994d5eceac88852f7189c8d1d3c8
+F src/vdbe.c 6e613f25b0fe1c81b097f46a8fe68c68c39a6abf
+F src/vdbe.h d94224ad39c8e9de83dda8d8f960059eb71c0780
+F src/where.c fcc2c2c84fe81a008485a32c680db3eb0aee5d22
 F test/all.test 15cac2f6b2d4c55bf896212aff3cc9d6597b0490
 F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
 F test/dbbe.test bd2cd9fe84c6d69b6ae42ac5f55b1e940bdca886
@@ -77,7 +80,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
 F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
 F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
-P 46b86abb1cc8e550acddba24e510d36eaf8ac6b9
-R 1d32d650ba38f8b6672c17c49e299816
+P c0730217a04323a1a73d125e3e7da32bcc8d58fc
+R b80dc777f56bf909f70a5edbd987dadf
 U drh
-Z d3d2bca8c08f700ef95bd56e0b8b1082
+Z 4eb2cf72a91b309ee3730e1dfd3dfa42
index 201ff7ea33e4106769b590448ba1673bbc77062c..84569a2832f98830c83837bdf886461b146e5bf8 100644 (file)
@@ -1 +1 @@
-c0730217a04323a1a73d125e3e7da32bcc8d58fc
\ No newline at end of file
+c6ffb7ec6acb596907ead8992dfad94e18e83866
\ No newline at end of file
index 531a9f16e580cc79472cb655ca83b37dc5f54f6c..a003cacb03154427953f574ed2c00a41825c306c 100644 (file)
@@ -33,7 +33,7 @@
 **     COPY
 **     VACUUM
 **
-** $Id: build.c,v 1.24 2000/10/16 22:06:42 drh Exp $
+** $Id: build.c,v 1.25 2001/01/15 22:51:09 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -341,7 +341,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
   */
   if( !pParse->initFlag ){
     static VdbeOp addTable[] = {
-      { OP_Open,        0, 1, MASTER_NAME },
+      { OP_OpenTbl,     0, 1, MASTER_NAME },
       { OP_New,         0, 0, 0},
       { OP_String,      0, 0, "table"     },
       { OP_String,      0, 0, 0},            /* 3 */
@@ -416,7 +416,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
   v = sqliteGetVdbe(pParse);
   if( v ){
     static VdbeOp dropTable[] = {
-      { OP_Open,       0, 1,        MASTER_NAME },
+      { OP_OpenTbl,    0, 1,        MASTER_NAME },
       { OP_ListOpen,   0, 0,        0},
       { OP_String,     0, 0,        0}, /* 2 */
       { OP_Next,       0, ADDR(10), 0}, /* 3 */
@@ -593,7 +593,7 @@ void sqliteCreateIndex(
   */
   if( pParse->initFlag==0 ){
     static VdbeOp addTable[] = {
-      { OP_Open,        2, 1, MASTER_NAME},
+      { OP_OpenTbl,     2, 1, MASTER_NAME},
       { OP_New,         2, 0, 0},
       { OP_String,      0, 0, "index"},
       { OP_String,      0, 0, 0},  /* 3 */
@@ -610,8 +610,8 @@ void sqliteCreateIndex(
 
     v = sqliteGetVdbe(pParse);
     if( v==0 ) goto exit_create_index;
-    sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
-    sqliteVdbeAddOp(v, OP_Open, 1, 1, pIndex->zName, 0);
+    sqliteVdbeAddOp(v, OP_OpenTbl, 0, 0, pTab->zName, 0);
+    sqliteVdbeAddOp(v, OP_OpenIdx, 1, 1, pIndex->zName, 0);
     if( pStart && pEnd ){
       int base;
       n = (int)pEnd->z - (int)pStart->z + 1;
@@ -670,7 +670,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
   v = sqliteGetVdbe(pParse);
   if( v ){
     static VdbeOp dropIndex[] = {
-      { OP_Open      0, 1,       MASTER_NAME},
+      { OP_OpenTbl,      0, 1,       MASTER_NAME},
       { OP_ListOpen,   0, 0,       0},
       { OP_String,     0, 0,       0}, /* 2 */
       { OP_Next,       0, ADDR(9), 0}, /* 3 */
@@ -843,9 +843,9 @@ void sqliteCopy(
     addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
     sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
     sqliteVdbeDequoteP3(v, addr);
-    sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
+    sqliteVdbeAddOp(v, OP_OpenTbl, 0, 1, pTab->zName, 0);
     for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
-      sqliteVdbeAddOp(v, OP_Open, i, 1, pIdx->zName, 0);
+      sqliteVdbeAddOp(v, OP_OpenIdx, i, 1, pIdx->zName, 0);
     }
     end = sqliteVdbeMakeLabel(v);
     addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);
diff --git a/src/db.h b/src/db.h
new file mode 100644 (file)
index 0000000..97778ba
--- /dev/null
+++ b/src/db.h
@@ -0,0 +1,53 @@
+/*
+** Copyright (c) 2001 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** $Id: db.h,v 1.1 2001/01/15 22:51:10 drh Exp $
+*/
+
+typedef struct Db Db;
+typedef struct DbCursor DbCursor;
+
+int sqliteDbOpen(const char *filename, Db**);
+int sqliteDbClose(Db*);
+int sqliteDbBeginTransaction(Db*);
+int sqliteDbCommit(Db*);
+int sqliteDbRollback(Db*);
+
+int sqliteDbCreateTable(Db*, int *pPgno);
+int sqliteDbDropTable(Db*, int pgno);
+
+int sqliteDbCursorOpen(Db*, int pgno, DbCursor**);
+int sqliteDbCursorClose(DbCursor*);
+
+int sqliteDbCursorMoveTo(DbCursor*, int key);
+int sqliteDbCursorFirst(DbCursor*);
+int sqliteDbCursorNext(DbCursor*);
+int sqliteDbCursorDelete(DbCursor*);
+int sqliteDbCursorDatasize(DbCursor*);
+int sqliteDbCursorRead(DbCursor*, int amt, int offset, char *buf);
+int sqliteDbCursorInsert(DbCursor*, int key, int nData, char *pData);
+
+int sqliteDbCursorMoveToIdx(DbCursor*, int nKey, char *pKey);
+int sqliteDbCursorKeysize(DbCursor*);
+int sqliteDbCursorReadKey(DbCursor*, int amt, int offset, char *buf);
+int sqliteDbCursorInsertIdx(DbCursor*, int nKey, char *pKey, int nData, char*);
index 907aa738010787a4e43145b4e5819c9996183244..8e3516a1e7a90c35ebf70ac6980f967070fa88d4 100644 (file)
 ** relatively simple to convert to a different database such
 ** as NDBM, SDBM, or BerkeleyDB.
 **
-** $Id: dbbe.c,v 1.22 2001/01/13 14:34:06 drh Exp $
+** $Id: dbbe.c,v 1.23 2001/01/15 22:51:10 drh Exp $
 */
 #include "sqliteInt.h"
+#include <unistd.h>
 
 /*
 ** This routine opens a new database.  It looks at the first
@@ -70,13 +71,12 @@ Dbbe *sqliteDbbeOpen(
 ** and then immediately unlinking the file.  That works great
 ** under Unix, but fails when we try to port to Windows.
 */
-int sqliteDbbeOpenTempFile(Dbbe *pBe, FILE **ppFile){
+int sqliteDbbeOpenTempFile(const char *zDir, Dbbe *pBe, FILE **ppFile){
   char *zFile;         /* Full name of the temporary file */
   char zBuf[50];       /* Base name of the temporary file */
   int i;               /* Loop counter */
   int limit;           /* Prevent an infinite loop */
   int rc = SQLITE_OK;  /* Value returned by this function */
-  char *zDir;          /* Directory to hold the file */
 
   for(i=0; i<pBe->nTemp; i++){
     if( pBe->apTemp[i]==0 ) break;
@@ -92,10 +92,6 @@ int sqliteDbbeOpenTempFile(Dbbe *pBe, FILE **ppFile){
   }
   limit = 4;
   zFile = 0;
-  zDir = pBe->zDir;
-  if( zDir==0 ){
-    zDir = "./";
-  }
   do{
     sqliteRandomName(zBuf, "/_temp_file_");
     sqliteFree(zFile);
@@ -149,3 +145,54 @@ void sqliteDbbeCloseAllTempFiles(Dbbe *pBe){
   sqliteFree(pBe->azTemp);
   sqliteFree(pBe->apTemp);
 }
+
+/*
+** Translate the name of an SQL table (or index) into the name 
+** of a file that holds the key/data pairs for that table or
+** index.  Space to hold the filename is obtained from
+** sqliteMalloc() and must be freed by the calling function.
+**
+** zDir is the name of the directory in which the file should
+** be located.  zSuffix is the filename extension to use for
+** the file.
+*/
+char *sqliteDbbeNameToFile(
+  const char *zDir,      /* Directory containing the file */
+  const char *zTable,    /* Name of the SQL table that the file contains */
+  const char *zSuffix    /* Suffix for the file.  Includes the "." */
+){
+  char *zFile = 0;
+  int i, k, c;
+  int nChar = 0;
+
+  for(i=0; (c = zTable[i])!=0; i++){
+    if( !isalnum(c) && c!='_' ){
+      nChar += 3;
+    }else{
+      nChar ++;
+    }
+  }
+  nChar += strlen(zDir) + strlen(zSuffix) + 2;
+  zFile = sqliteMalloc( nChar );
+  if( zFile==0 ) return 0;
+  for(i=0; (c = zDir[i])!=0; i++){
+    zFile[i] = c;
+  }
+  zFile[i++] = '/';
+  for(k=0; (c = zTable[k])!=0; k++){
+    if( isupper(c) ){
+      zFile[i++] = tolower(c);
+    }else if( isalnum(c) || c=='_' ){
+      zFile[i++] = c;
+    }else{
+      zFile[i++] = '~';
+      zFile[i++] = "0123456789abcdef"[c & 0xf];
+      zFile[i++] = "0123456789abcdef"[(c>>8)&0xf];
+    }
+  }
+  for(k=0; (c = zSuffix[k])!=0; k++){
+    zFile[i++] = c;
+  }
+  zFile[i] = 0;
+  return zFile;
+}
index 7d524cb037d6db55e2f575a6049e85c81dc5c64b..09166469d5125f9013da4e162995d5744aab18aa 100644 (file)
@@ -28,7 +28,7 @@
 ** This library was originally designed to support the following
 ** backends: GDBM, NDBM, SDBM, Berkeley DB.
 **
-** $Id: dbbe.h,v 1.9 2001/01/13 14:34:06 drh Exp $
+** $Id: dbbe.h,v 1.10 2001/01/15 22:51:10 drh Exp $
 */
 #ifndef _SQLITE_DBBE_H_
 #define _SQLITE_DBBE_H_
@@ -81,10 +81,16 @@ struct DbbeMethods {
   ** an appropriate path and extension to the filename to locate the 
   ** actual file.
   **
+  ** The keyType parameter is TRUE if this table will only be accessed
+  ** using integer keys.  This parameter allows the database backend to
+  ** use a faster algorithm for the special case of integer keys, if it
+  ** wants to.
+  **
   ** If zName is 0 or "", then a temporary file is created that
   ** will be deleted when closed.
   */
-  int (*OpenCursor)(Dbbe*, const char *zName, int writeable, DbbeCursor**);
+  int (*OpenCursor)(Dbbe*, const char *zName, int writeable, 
+                    int intKeyOnly, DbbeCursor**);
 
   /* Delete a table from the database */
   void (*DropTable)(Dbbe*, const char *zTableName);
@@ -164,7 +170,6 @@ struct DbbeMethods {
 */
 struct Dbbe {
   struct DbbeMethods *x; /* Backend-specific methods for database access */
-  char *zDir;            /* The directory containing the database file(s) */
   int nTemp;             /* Number of temporary files created */
   FILE **apTemp;         /* Space to hold temporary file pointers */
   char **azTemp;         /* Names of the temporary files */
index 6c2659a80b513b4bc03658a4678427ba860cec50..eb4d482e7f24fb62b08dd7235352acaf44adfc59 100644 (file)
@@ -30,7 +30,7 @@
 ** relatively simple to convert to a different database such
 ** as NDBM, SDBM, or BerkeleyDB.
 **
-** $Id: dbbegdbm.c,v 1.2 2001/01/13 14:34:06 drh Exp $
+** $Id: dbbegdbm.c,v 1.3 2001/01/15 22:51:10 drh Exp $
 */
 #include "sqliteInt.h"
 #include <gdbm.h>
@@ -66,6 +66,7 @@ struct Dbbex {
   Dbbe dbbe;         /* The base class */
   int write;         /* True for write permission */
   BeFile *pOpen;     /* List of open files */
+  char *zDir;        /* Directory hold the database */
 };
 
 /*
@@ -85,13 +86,6 @@ struct DbbeCursor {
   int readPending;   /* The fetch hasn't actually been done yet */
 };
 
-/*
-**
-*/
-struct DbbeList {
-  FILE *pOut;
-  Dbbe *pDbbe;
-};
 /*
 ** The "mkdir()" function only takes one argument under Windows.
 */
@@ -110,7 +104,6 @@ static void sqliteGdbmCloseCursor(DbbeCursor *pCursr);
 static void sqliteGdbmClose(Dbbe *pDbbe){
   Dbbex *pBe = (Dbbex*)pDbbe;
   BeFile *pFile, *pNext;
-  int i;
   for(pFile=pBe->pOpen; pFile; pFile=pNext){
     pNext = pFile->pNext;
     gdbm_close(pFile->dbf);
@@ -131,9 +124,9 @@ static void sqliteGdbmClose(Dbbe *pDbbe){
 static char *sqliteFileOfTable(Dbbex *pBe, const char *zTable){
   char *zFile = 0;
   int i;
-  sqliteSetString(&zFile, pBe->dbbe.zDir, "/", zTable, ".tbl", 0);
+  sqliteSetString(&zFile, pBe->zDir, "/", zTable, ".tbl", 0);
   if( zFile==0 ) return 0;
-  for(i=strlen(pBe->dbbe.zDir)+1; zFile[i]; i++){
+  for(i=strlen(pBe->zDir)+1; zFile[i]; i++){
     int c = zFile[i];
     if( isupper(c) ){
       zFile[i] = tolower(c);
@@ -172,6 +165,7 @@ static int sqliteGdbmOpenCursor(
   Dbbe *pDbbe,            /* The database the table belongs to */
   const char *zTable,     /* The SQL name of the file to be opened */
   int writeable,          /* True to open for writing */
+  int intKeyOnly,         /* True if only integer keys are used */
   DbbeCursor **ppCursr    /* Write the resulting table pointer here */
 ){
   char *zFile;            /* Name of the table file */
@@ -330,7 +324,7 @@ static int sqliteGdbmReorganizeTable(Dbbe *pBe, const char *zTable){
   DbbeCursor *pCrsr;
   int rc;
 
-  rc = sqliteGdbmOpenCursor(pBe, zTable, 1, &pCrsr);
+  rc = sqliteGdbmOpenCursor(pBe, zTable, 1, 0, &pCrsr);
   if( rc!=SQLITE_OK ){
     return rc;
   }
@@ -494,7 +488,6 @@ static int sqliteGdbmNew(DbbeCursor *pCursr){
   int iKey;
   datum key;
   int go = 1;
-  int i;
 
   if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
   while( go ){
@@ -511,8 +504,13 @@ static int sqliteGdbmNew(DbbeCursor *pCursr){
 ** Write an entry into the table.  Overwrite any prior entry with the
 ** same key.
 */
-static int
-sqliteGdbmPut(DbbeCursor *pCursr, int nKey,char *pKey,int nData,char *pData){
+static int sqliteGdbmPut(
+  DbbeCursor *pCursr,  /* Write to the database associated with this cursor */
+  int nKey,            /* Number of bytes in the key */
+  char *pKey,          /* The data for the key */
+  int nData,           /* Number of bytes of data */
+  char *pData          /* The data */
+){
   datum data, key;
   int rc;
   if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
@@ -543,6 +541,15 @@ static int sqliteGdbmDelete(DbbeCursor *pCursr, int nKey, char *pKey){
   return rc;
 }
 
+/*
+** Open a temporary file.  The file is located in the same directory
+** as the rest of the database.
+*/
+static int sqliteGdbmOpenTempFile(Dbbe *pDbbe, FILE **ppFile){
+  Dbbex *pBe = (Dbbex*)pDbbe;
+  return sqliteDbbeOpenTempFile(pBe->zDir, pDbbe, ppFile);
+}
+
 /*
 ** This variable contains pointers to all of the access methods
 ** used to implement the GDBM backend.
@@ -566,7 +573,7 @@ static struct DbbeMethods gdbmMethods = {
   /*             New */   sqliteGdbmNew,
   /*             Put */   sqliteGdbmPut,
   /*          Delete */   sqliteGdbmDelete,
-  /*    OpenTempFile */   sqliteDbbeOpenTempFile,
+  /*    OpenTempFile */   sqliteGdbmOpenTempFile,
   /*   CloseTempFile */   sqliteDbbeCloseTempFile
 };
 
@@ -623,8 +630,8 @@ Dbbe *sqliteGdbmOpen(
     return 0;
   }
   pNew->dbbe.x = &gdbmMethods;
-  pNew->dbbe.zDir = (char*)&pNew[1];
-  strcpy(pNew->dbbe.zDir, zName);
+  pNew->zDir = (char*)&pNew[1];
+  strcpy(pNew->zDir, zName);
   pNew->write = writeFlag;
   pNew->pOpen = 0;
   return &pNew->dbbe;
index 89b4aeed1e3cdf766a43fef1e2fc92d808e5a1e1..4ac3bdbaf8d0fd6690d495a29df862432d58fe8c 100644 (file)
@@ -28,7 +28,7 @@
 **
 ** This file uses an in-memory hash table as the database backend. 
 **
-** $Id: dbbemem.c,v 1.6 2001/01/13 14:34:06 drh Exp $
+** $Id: dbbemem.c,v 1.7 2001/01/15 22:51:10 drh Exp $
 */
 #include "sqliteInt.h"
 #include <sys/stat.h>
@@ -339,6 +339,7 @@ typedef struct MTable MTable;
 struct MTable {
   char *zName;            /* Name of the table */
   int delOnClose;         /* Delete when closing */
+  int intKeyOnly;         /* Use only integer keys on this table */
   Array data;             /* The data in this stable */
 };
 
@@ -391,9 +392,8 @@ static void deleteMTable(MTable *p){
 */
 static void sqliteMemClose(Dbbe *pDbbe){
   Dbbex *pBe = (Dbbex*)pDbbe;
-  MTable *pTble, *pNext;
-  int i;
-  ArrayElem *j, *k;
+  MTable *pTble;
+  ArrayElem *j;
   for(j=ArrayFirst(&pBe->tables); j; j=ArrayNext(j)){
     pTble = ArrayData(j);
     deleteMTable(pTble);
@@ -452,14 +452,13 @@ static int sqliteMemOpenCursor(
   Dbbe *pDbbe,            /* The database the table belongs to */
   const char *zTable,     /* The SQL name of the file to be opened */
   int writeable,          /* True to open for writing */
+  int intKeyOnly,         /* True if only integer keys are used */
   DbbeCursor **ppCursr    /* Write the resulting table pointer here */
 ){
   DbbeCursor *pCursr;     /* The new table cursor */
   char *zName;            /* Canonical table name */
   MTable *pTble;          /* The underlying data file for this table */
   int rc = SQLITE_OK;     /* Return value */
-  int rw_mask;            /* Permissions mask for opening a table */
-  int mode;               /* Mode for opening a table */
   Dbbex *pBe = (Dbbex*)pDbbe;
 
   *ppCursr = 0;
@@ -494,8 +493,10 @@ static int sqliteMemOpenCursor(
       pTble->zName = 0;
       pTble->delOnClose = 1;
     }
+    pTble->intKeyOnly = intKeyOnly;
     ArrayInit(&pTble->data);
   }else{
+    assert( pTble->intKeyOnly==intKeyOnly );
     sqliteFree(zName);
   }
   pCursr->pBe = pBe;
@@ -513,7 +514,6 @@ static void sqliteMemDropTable(Dbbe *pDbbe, const char *zTable){
   char *zName;            /* Name of the table file */
   Datum key, data;
   MTable *pTble;
-  ArrayElem *i;
   Dbbex *pBe = (Dbbex*)pDbbe;
 
   zName = sqliteNameOfTable(zTable);
@@ -565,6 +565,7 @@ static int sqliteMemFetch(DbbeCursor *pCursr, int nKey, char *pKey){
   Datum key;
   key.n = nKey;
   key.p = pKey;
+  assert( nKey==4 || pCursr->pTble->intKeyOnly==0 );
   pCursr->elem = ArrayFindElement(&pCursr->pTble->data, key);
   return pCursr->elem!=0;
 }
@@ -665,7 +666,6 @@ static int sqliteMemNew(DbbeCursor *pCursr){
   int iKey;
   Datum key;
   int go = 1;
-  int i;
 
   while( go ){
     iKey = sqliteRandomInteger();
@@ -681,14 +681,18 @@ static int sqliteMemNew(DbbeCursor *pCursr){
 ** Write an entry into the table.  Overwrite any prior entry with the
 ** same key.
 */
-static int
-sqliteMemPut(DbbeCursor *pCursr, int nKey,char *pKey, int nData, char *pData){
+static int sqliteMemPut(
+  DbbeCursor *pCursr,       /* Write new entry into this database table */
+  int nKey, char *pKey,     /* The key of the new entry */
+  int nData, char *pData    /* The data of the new entry */
+){
   Datum data, key;
   data.n = nData;
   data.p = sqliteMalloc( data.n );
   memcpy(data.p, pData, data.n);
   key.n = nKey;
   key.p = pKey;
+  assert( nKey==4 || pCursr->pTble->intKeyOnly==0 );
   data = ArrayInsert(&pCursr->pTble->data, key, data);
   if( data.p ){
     sqliteFree(data.p);
@@ -712,6 +716,26 @@ static int sqliteMemDelete(DbbeCursor *pCursr, int nKey, char *pKey){
   return SQLITE_OK;
 }
 
+/*
+** Open a temporary file.  The file is located in the current working
+** directory.
+*/
+static int sqliteMemOpenTempFile(Dbbe *pDbbe, FILE **ppFile){
+  const char *zTemps[] = { "/usr/tmp", "/var/tmp", "/tmp", "/temp", 0};
+  const char *zDir;
+  int i;
+  struct stat statbuf;
+  for(i=0; zTemps[i]; i++){
+    zDir = zTemps[i];
+    if( stat("/usr/tmp", &statbuf)==0 && S_ISDIR(statbuf.st_mode) 
+      && access("/usr/tmp", W_OK|X_OK)==0 ){
+        break;
+    }
+  }
+  if( zDir==0 ) zDir = ".";
+  return sqliteDbbeOpenTempFile(zDir, pDbbe, ppFile);
+}
+
 /*
 ** This variable contains pointers to all of the access methods
 ** used to implement the MEMORY backend.
@@ -735,7 +759,7 @@ static struct DbbeMethods memoryMethods = {
   /*             New */   sqliteMemNew,
   /*             Put */   sqliteMemPut,
   /*          Delete */   sqliteMemDelete,
-  /*    OpenTempFile */   sqliteDbbeOpenTempFile,
+  /*    OpenTempFile */   sqliteMemOpenTempFile,
   /*   CloseTempFile */   sqliteDbbeCloseTempFile
 };
 
@@ -763,6 +787,5 @@ Dbbe *sqliteMemOpen(
   }
   ArrayInit(&pNew->tables);
   pNew->dbbe.x = &memoryMethods;
-  pNew->dbbe.zDir = 0;
   return &pNew->dbbe;
 }
index f6822f9ab5806f49a05f6a2a5192d04b6afb226d..d5e5a3b01e84029f4ff03b7628cec1758b980625 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.6 2000/06/21 13:59:11 drh Exp $
+** $Id: delete.c,v 1.7 2001/01/15 22:51:10 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -105,9 +105,9 @@ void sqliteDeleteFrom(
   */
   base = pParse->nTab;
   sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
-  sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
+  sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
   for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
-    sqliteVdbeAddOp(v, OP_Open, base+i, 1, pIdx->zName, 0);
+    sqliteVdbeAddOp(v, OP_OpenIdx, base+i, 1, pIdx->zName, 0);
   }
   end = sqliteVdbeMakeLabel(v);
   addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
index 94a41cf5875814b02f720d0a4f67d7afe24a0616..64376867e34953955a5e3d1c9cefbe763a39ab24 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions.
 **
-** $Id: expr.c,v 1.20 2000/11/28 20:47:18 drh Exp $
+** $Id: expr.c,v 1.21 2001/01/15 22:51:10 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -216,7 +216,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
         ** table.  The cursor number of the temporary table has already
         ** been put in iTable by sqliteExprResolveInSelect().
         */
-        sqliteVdbeAddOp(v, OP_Open, pExpr->iTable, 1, 0, 0);
+        sqliteVdbeAddOp(v, OP_OpenIdx, pExpr->iTable, 1, 0, 0);
         if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) );
       }else if( pExpr->pList ){
         /* Case 2:     expr IN (exprlist)
index a044bc144894148090df156a40fb8cd3d0d8af0c..553a1c85163f243548ea3c5a2cb015b47f04b78c 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements.
 **
-** $Id: insert.c,v 1.11 2000/06/21 13:59:12 drh Exp $
+** $Id: insert.c,v 1.12 2001/01/15 22:51:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -92,7 +92,7 @@ void sqliteInsert(
   if( pSelect ){
     int rc;
     srcTab = pParse->nTab++;
-    sqliteVdbeAddOp(v, OP_Open, srcTab, 1, 0, 0);
+    sqliteVdbeAddOp(v, OP_OpenTbl, srcTab, 1, 0, 0);
     rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab);
     if( rc ) goto insert_cleanup;
     assert( pSelect->pEList );
@@ -156,9 +156,9 @@ void sqliteInsert(
   ** all indices of that table.
   */
   base = pParse->nTab;
-  sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
+  sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
   for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
-    sqliteVdbeAddOp(v, OP_Open, idx+base, 1, pIdx->zName, 0);
+    sqliteVdbeAddOp(v, OP_OpenIdx, idx+base, 1, pIdx->zName, 0);
   }
 
   /* If the data source is a SELECT statement, then we have to create
index a707b6722803787223ce7903b3e37e6a09a6efca..47f85d82104c380034b8fc27d5813ba54e736515 100644 (file)
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.23 2001/01/13 14:34:06 drh Exp $
+** $Id: main.c,v 1.24 2001/01/15 22:51:11 drh Exp $
 */
 #include "sqliteInt.h"
+#include <unistd.h>
 
 /*
 ** This is the callback routine for the code that initializes the
@@ -123,7 +124,7 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
   ** database scheme.
   */
   static VdbeOp initProg[] = {
-    { OP_Open    0, 0,  MASTER_NAME},
+    { OP_OpenTbl,    0, 0,  MASTER_NAME},
     { OP_Next,     0, 9,  0},           /* 1 */
     { OP_Field,    0, 0,  0},
     { OP_String,   0, 0,  "meta"},
@@ -321,7 +322,6 @@ int sqlite_exec(
   char **pzErrMsg             /* Write error messages here */
 ){
   Parse sParse;
-  int rc;
 
   if( pzErrMsg ) *pzErrMsg = 0;
   if( (db->flags & SQLITE_Initialized)==0 ){
diff --git a/src/pg.c b/src/pg.c
new file mode 100644 (file)
index 0000000..a4b6465
--- /dev/null
+++ b/src/pg.c
@@ -0,0 +1,701 @@
+/*
+** Copyright (c) 2001 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** $Id: pg.c,v 1.1 2001/01/15 22:51:11 drh Exp $
+*/
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "sqliteInt.h"
+#include "pg.h"
+
+/*
+** Uncomment the following for a debug trace
+*/
+#if 1
+# define TRACE(X)  printf X; fflush(stdout);
+#endif  
+
+#ifndef SQLITE_IOERR
+# define SQLITE_IOERR SQLITE_ERROR
+#endif
+
+/*
+** Hash table sizes
+*/
+#define J_HASH_SIZE  127  /* Size of the journal page hash table */
+#define PG_HASH_SIZE 349  /* Size of the database page hash table */
+
+/*
+** Forward declaration of structure
+*/
+typedef struct Pghdr Pghdr;
+
+/*
+** All information about a single paging file is contained in an
+** instance of the following structure.
+*/
+struct Pgr {
+  int fdMain;                    /* The main database file */
+  char *zMain;                   /* Name of the database file */
+  int fdJournal;                 /* The journal file */
+  char *zJournal;                /* Name of the journal file */
+  int nMemPg;                    /* Number of memory-resident pages */
+  int nJPg;                      /* Number of pages in the journal */
+  int nDbPg;                     /* Number of pages in the database */
+  int nRefPg;                    /* Number of pages currently in use */
+  Pghdr *pLru, *pMru;            /* Least and most recently used mem-page */
+  Pghdr *pJidx;                  /* List of journal index pages */
+  Pghdr *pAll;                   /* All pages, except journal index pages */
+  u32 aJHash[J_HASH_SIZE];       /* Journal page hash table */
+  Pghdr *aPgHash[PG_HASH_SIZE];  /* Mem-page hash table */
+};
+
+/*
+** Each memory-resident page of the paging file has a header which
+** is an instance of the following structure.
+*/
+struct Pghdr {
+  Pgr *p;            /* Pointer back to the Pgr structure */
+  int nRef;          /* Number of references to this page */
+  int isDirty;       /* TRUE if needs to be written to disk */
+  u32 dbpgno;        /* Page number in the database file */
+  u32 jpgno;         /* Page number in the journal file */
+  Pghdr *pNx;        /* Next page on a list of them all */
+  Pghdr *pLru;       /* Less recently used pages */
+  Pghdr *pMru;       /* More recently used pages */
+  Pghdr *pNxHash;    /* Next with same dbpgno hash */
+  Pghdr *pPvHash;    /* Previous with the same dbpgno hash */
+};
+
+/*
+** For a memory-resident page, the page data comes immediately after
+** the page header.  The following macros can be used to change a 
+** pointer to a page header into a pointer to the data, or vice
+** versa.
+*/
+#define PG_TO_DATA(X)  ((void*)&(X)[1])
+#define DATA_TO_PG(X)  (&((Pghdr*)(X))[-1])
+
+/*
+** The number of in-memory pages that we accumulate before trying
+** to reuse older pages when new ones are requested.
+*/
+#define MX_MEM_PAGE  100
+
+/*
+** The number of journal data pages that come between consecutive 
+** journal index pages.
+*/
+#define N_J_DATAPAGE  (SQLITE_PAGE_SIZE/(2*sizeof(u32)))
+
+/*
+** An index page in the journal consists of an array of N_J_DATAPAGE
+** of the following structures.  There is one instance of the following
+** structure for each of the N_J_DATAPAGE data pages that follow the
+** index.
+**
+** Let the journal page number that a JidxEntry describes be J.  Then
+** the JidxEntry.dbpgno field is the page of the database file that
+** corresponds to the J page in the journal.  The JidxEntry.next_jpgno
+** field hold the number of another journal page that contains
+** a database file page with the same hash as JidxEntry.dbpgno.
+**
+** All information is written to the journal index in big-endian
+** notation.
+*/
+typedef struct JidxEntry JidxEntry;
+struct JidxEntry {
+  char dbpgno[sizeof(u32)];        /* Database page number for this entry */
+  char next_jpgno[sizeof(u32)];    /* Next entry with same hash on dbpgno */
+};
+
+/*
+** Read a page from a file into memory.  Return SQLITE_OK if successful.
+** The "pgno" parameter tells where in the file to read the page.
+** The first page is 1.  Files do not contain a page 0 since a page
+** number of 0 is used to indicate "no such page".
+*/
+static int sqlitePgRead(int fd, char *zBuf, u32 pgno){
+  int got = 0;
+  int amt;
+
+  assert( pgno>0 );
+  assert( fd>=0 );
+  lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE);
+  while( got<SQLITE_PAGE_SIZE ){
+    amt = read(fd, &zBuf[got], SQLITE_PAGE_SIZE - got);
+    if( amt<=0 ){
+      memset(&zBuf[got], 0, SQLITE_PAGE_SIZE - got);
+      return amt==0 ? SQLITE_OK : SQLITE_IOERR;
+    }
+    got += amt;
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Read a page from a file into memory.  Return SQLITE_OK if successful.
+** The "pgno" parameter tells where in the file to write the page.
+** The first page is 1.  Files do not contain a page 0 since a page
+** number of 0 is used to indicate "no such page".
+*/
+static int sqlitePgWrite(int fd, char *zBuf, u32 pgno){
+  int done = 0;
+  int amt;
+
+  assert( pgno>0 );
+  assert( fd>=0 );
+  lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE);
+  while( done<SQLITE_PAGE_SIZE ){
+    amt = write(fd, &zBuf[done], SQLITE_PAGE_SIZE - done);
+    if( amt<=0 ) return SQLITE_IOERR;
+    done += amt;
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Turn four bytes into an integer.  The first byte is always the
+** most significant 8 bits.
+*/
+static u32 sqlitePgGetInt(const char *p){
+  return ((p[0]&0xff)<<24) | ((p[1]&0xff)<<16) | ((p[2]&0xff)<<8) | (p[3]&0xff);
+}
+
+/*
+** Turn an integer into 4 bytes.  The first byte is always the
+** most significant 8 bits.
+*/
+static void sqlitePgPutInt(u32 v, char *p){
+  p[3] = v & 0xff;
+  v >>= 8;
+  p[2] = v & 0xff;
+  v >>= 8;
+  p[1] = v & 0xff;
+  v >>= 8;
+  p[0] = v & 0xff;
+}
+
+/*
+** Check the hash table for an in-memory page.  Return a pointer to
+** the page header if found.  Return NULL if the page is not in memory.
+*/
+static Pghdr *sqlitePgFind(Pgr *p, u32 pgno){
+  int h;
+  Pghdr *pPg;
+
+  if( pgno==0 ) return 0;
+  h = pgno % PG_HASH_SIZE;
+  for(pPg = p->aPgHash[h]; pPg; pPg=pPg->pNxHash){
+    if( pPg->dbpgno==pgno ) return pPg;
+  }
+  TRACE(("PG: data page %u is %#x\n", pgno, (u32)pPg));
+  return 0;
+}
+
+/*
+** Locate and return an index page from the journal.
+**
+** The first page of a journal is the primary index.  Additional
+** index pages are called secondary indices.  Index pages appear
+** in the journal as often as needed.  (If SQLITE_PAGE_SIZE==1024,
+** then there are 1024/sizeof(int)*2 = 128 database between each
+** pair of index pages.)  Journal index pages are not hashed and
+** do no appear on the Pgr.pAll list.  Index pages are on the
+** Pgr.pJidx list only.  Index pages have Pghdr.dbpgno==0.
+**
+** If the requested index page is not already in memory, then a
+** new memory page is created to hold the index.
+**
+** This routine will return a NULL pointer if we run out of memory.
+*/
+static Pghdr *sqlitePgFindJidx(Pgr *p, u32 pgno){
+  Pghdr *pPg;
+
+  assert( pgno % (N_J_DATAPAGE+1) == 1 );
+  for(pPg=p->pJidx; pPg; pPg=pPg->pNx){
+    if( pPg->jpgno==pgno ){
+      TRACE(("PG: found j-index %u at %#x\n", pgno, (u32)pPg));
+      return pPg;
+    }
+  }
+  pPg = sqliteMalloc( sizeof(Pghdr)+SQLITE_PAGE_SIZE );
+  if( pPg==0 ) return 0;
+  pPg->jpgno = pgno;
+  pPg->pNx = p->pJidx;
+  p->pJidx = pPg;
+  sqlitePgRead(p->fdJournal, PG_TO_DATA(pPg), pgno);
+  TRACE(("PG: create j-index %u at %#x\n", pgno, (u32)pPg));
+  return pPg;
+}
+
+/*
+** Look in the journal to see if the given database page is stored
+** in the journal.  If it is, return its journal page number.  If
+** not, return 0.
+*/
+static u32 sqlitePgJournalPageNumber(Pgr *p, u32 dbpgno){
+  u32 jpgno;
+  
+  assert( dbpgno>0 );
+  jpgno = p->aJHash[dbpgno % J_HASH_SIZE];
+  while( jpgno!=0 ){
+    int idx_num;     /* Which journal index describes page jpgno */
+    int ipgno;       /* Page number for the journal index */
+    int idx_slot;    /* Which entry in index idx_num describes jpgno */
+    Pghdr *pIdxPg;   /* The index page for jpgno */
+    JidxEntry *aIdx; /* The data for the index page */
+
+    idx_num = (jpgno - 1)/(N_J_DATAPAGE + 1);
+    idx_slot = (jpgno - 1) % (N_J_DATAPAGE + 1) - 2;
+    ipgno = idx_num * (N_J_DATAPAGE + 1) + 1;
+    if( ipgno>p->nJPg ){
+      jpgno = 0;
+      break;
+    }
+    pIdxPg = sqlitePgFindJidx(p, ipgno);
+    assert( pIdxPg!=0 );
+    aIdx = PG_TO_DATA(pIdxPg);
+    if( dbpgno==sqlitePgGetInt(aIdx[idx_slot].dbpgno) ){
+      break;
+    }
+    jpgno = sqlitePgGetInt(aIdx[idx_slot].next_jpgno);
+  }
+  return jpgno;
+}
+
+/*
+** Make a page not dirty by writing it to the journal.
+*/
+static int sqlitePgMakeClean(Pghdr *pPg){
+  Pgr *p = pPg->p;
+  int rc;
+
+  assert( pPg->isDirty );
+  assert( p->fdJournal>=0 );
+  if( pPg->jpgno==0 ){
+    int jpgno;       /* A newly allocate page in the journal */
+    int idx_num;     /* Which journal index describes page jpgno */
+    int idx_slot;    /* Which entry in index idx_num describes jpgno */
+    Pghdr *pIdxPg;   /* The index page for jpgno */
+    JidxEntry *aIdx; /* The data for the index page */
+    int h;           /* The hash value for pPg->dbpgno */
+
+    jpgno = p->nJPg + 1;
+    if( jpgno % (N_J_DATAPAGE + 1) == 1 ){
+      jpgno++;
+    }
+    idx_num = (jpgno - 1)/(N_J_DATAPAGE + 1);
+    idx_slot = (jpgno - 1) % (N_J_DATAPAGE + 1) - 2;
+    pIdxPg = sqlitePgFindJidx(p, idx_num * (N_J_DATAPAGE + 1) + 1);
+    assert( pIdxPg!=0 );
+    aIdx = PG_TO_DATA(pIdxPg);
+    sqlitePgPutInt(pPg->dbpgno, aIdx[idx_slot].dbpgno);
+    h = pPg->dbpgno % J_HASH_SIZE;
+    sqlitePgPutInt(p->aJHash[h], aIdx[idx_slot].next_jpgno);
+    p->aJHash[h] = jpgno;
+    p->nJPg = jpgno;
+    pPg->jpgno = jpgno;
+    TRACE(("PG: assign d-page %u to j-page %u\n", jpgno, pPg->dbpgno));
+  }
+  rc = sqlitePgWrite(p->fdJournal, PG_TO_DATA(pPg), pPg->jpgno);
+  if( rc==SQLITE_OK ){
+    pPg->isDirty = 0;
+  }
+  return rc;
+}
+
+/*
+** Find the number of pages in the given file by measuring the size
+** of the file.  Return 0 if there is any problem.
+*/
+static int sqlitePgPageCount(int fd){
+  struct stat statbuf;
+  if( fstat(fd, &statbuf)!=0 ) return 0;
+  return statbuf.st_size/SQLITE_PAGE_SIZE;
+}
+
+/*
+** This routine reads the journal and transfers pages from the
+** journal to the database.
+*/
+static int sqlitePgJournalPlayback(Pgr *p){
+  Pghdr *pPg;
+  JidxEntry *aIdx;
+  int nJpg;
+  int jpgno = 1;
+  int i;
+  int dbpgno;
+  int rc;
+  char idx[SQLITE_PAGE_SIZE];
+  char pgbuf[SQLITE_PAGE_SIZE];
+  
+  assert( p->fdJournal>=0 );
+  nJpg = sqlitePgPageCount(p->fdJournal);
+  while( jpgno<=nJpg ){
+    if( !sqlitePgRead(p->fdJournal, idx, jpgno++) ) break;
+    aIdx = (JidxEntry*)idx;
+    for(i=0; i<N_J_DATAPAGE; i++){
+      dbpgno = sqlitePgGetInt(&idx[i]);
+      if( dbpgno==0 ){
+        jpgno = nJpg+1;
+        break;
+      }
+      pPg = sqlitePgFind(p, dbpgno);
+      if( pPg ){
+        rc = sqlitePgWrite(p->fdMain, PG_TO_DATA(pPg), dbpgno);
+        TRACE(("PG: commit j-page %u to d-page %u from memory\n",jpgno,dbpgno));
+      }else{
+        rc = sqlitePgRead(p->fdJournal, pgbuf, jpgno);
+        if( rc!=SQLITE_OK ){
+          return rc;
+        }
+        rc = sqlitePgWrite(p->fdMain, pgbuf, dbpgno);
+        TRACE(("PG: commit j-page %u to d-page %u from disk\n",jpgno,dbpgno));
+      }
+      jpgno++;
+      if( rc!=SQLITE_OK ){
+        return rc;
+      }
+    }
+  }
+  TRACE(("PG: commit complete. deleting the journal.\n"));
+  fsync(p->fdMain);
+  close(p->fdJournal);
+  p->fdJournal = -1;
+  unlink(p->zJournal);
+  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
+    pPg->isDirty = 0;
+    pPg->jpgno = 0;
+  }
+  while( (pPg = p->pJidx)!=0 ){
+    p->pAll = pPg->pNx;
+    sqliteFree(pPg);
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Remove the given page from the LRU list.
+*/
+static void sqlitePgUnlinkLru(Pghdr *pPg){
+  Pgr *p = pPg->p;
+  if( pPg->pLru ){
+    pPg->pLru->pMru = pPg->pLru;
+  }
+  if( pPg->pMru ){
+    pPg->pMru->pLru = pPg->pMru;
+  }
+  if( p->pLru==pPg ){
+    p->pLru = pPg->pLru;
+  }
+  if( p->pMru==pPg ){
+    p->pMru = pPg->pMru;
+  }
+  pPg->pLru = pPg->pMru = 0;
+}
+
+/*
+** Open the database file and make *ppPgr pointer to a structure describing it.
+** Return SQLITE_OK on success or an error code if there is a failure.
+**
+** If there was an unfinished commit, complete it before returnning.
+*/
+int sqlitePgOpen(const char *zFilename, Pgr **ppPgr){
+  Pgr *p;
+  int n;
+
+  n = strlen(zFilename);
+  p = sqliteMalloc( sizeof(*p) + n*2 + 4 );
+  if( p==0 ){
+    *ppPgr = 0;
+    return SQLITE_NOMEM;
+  }
+  p->zMain = (char*)&p[1];
+  strcpy(p->zMain, zFilename);
+  p->zJournal = &p->zMain[n+1];
+  strcpy(p->zJournal, p->zMain);
+  p->zJournal[n] = '~';
+  p->zJournal[n+1] = 0;
+  p->fdJournal = -1;
+  p->fdMain = open(p->zMain, O_CREAT|O_RDWR, 0600);
+  if( p->fdMain<0 ){
+    *ppPgr = 0;
+    sqliteFree(p);
+    return SQLITE_PERM;
+  }
+  p->nDbPg = sqlitePgPageCount(p->fdMain);
+  if( access(p->zJournal, R_OK)==0 ){
+    sqlitePgJournalPlayback(p);
+  }
+  *ppPgr = p;
+  return SQLITE_OK;
+}
+
+/*
+** Close the database file.  Any outstanding transactions are abandoned.
+*/
+int sqlitePgClose(Pgr *p){
+  Pghdr *pPg;
+
+  if( p->fdMain ) close(p->fdMain);
+  if( p->fdJournal ) close(p->fdJournal);
+  unlink(p->zJournal);
+  while( (pPg = p->pAll)!=0 ){
+    p->pAll = pPg->pNx;
+    sqliteFree(pPg);
+  }
+  while( (pPg = p->pJidx)!=0 ){
+    p->pAll = pPg->pNx;
+    sqliteFree(pPg);
+  }
+  sqliteFree(p);
+  return SQLITE_OK;
+}
+
+/*
+** Begin a new transaction.  Return SQLITE_OK on success or an error
+** code if something goes wrong.
+*/
+int sqlitePgBeginTransaction(Pgr *p){
+  assert( p->fdJournal<0 );
+  if( p->nRefPg>0 ){
+     /* release the read lock */
+  }
+  /* write lock the database */
+  p->fdJournal = open(p->zJournal, O_CREAT|O_EXCL|O_RDWR, 0600);
+  if( p->fdJournal<0 ){
+    return SQLITE_PERM;
+  }
+  p->nJPg = 0;
+  TRACE(("PG: begin transaction\n"));
+  return SQLITE_OK;
+}
+
+/*
+** Commit the current transaction.  Return SQLITE_OK or an error code.
+*/
+int sqlitePgCommit(Pgr *p){
+  Pghdr *pPrimaryIdx = 0;
+  Pghdr *pPg;
+  int rc;
+
+  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
+    if( pPg->isDirty ){
+      rc = sqlitePgMakeClean(pPg);
+      if( rc!=SQLITE_OK ){
+        return rc;
+      }
+    }
+  }
+  for(pPg=p->pJidx; pPg; pPg=pPg->pNx){
+    if( pPg->jpgno==1 ){
+      pPrimaryIdx = pPg;
+    }else{
+      TRACE(("PG: writing j-index %u\n", pPg->jpgno));
+      rc = sqlitePgMakeClean(pPg);
+      if( rc!=SQLITE_OK ){
+        return rc;
+      }
+    }
+  }
+  assert( pPrimaryIdx!=0 );
+  fsync(p->fdJournal);
+  TRACE(("PG: writing j-index %u\n", pPrimaryIdx->jpgno));
+  rc = sqlitePgMakeClean(pPrimaryIdx);
+  if( rc!=SQLITE_OK ){
+    return rc;
+  }
+  fsync(p->fdJournal);
+  rc = sqlitePgJournalPlayback(p);
+  if( rc!=SQLITE_OK ){
+    return rc;
+  }
+  /* remove write lock from database */
+  if( p->nRefPg>0 ){
+    /* acquire read lock on database */
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Abandon the current transaction.
+*/
+int sqlitePgRollback(Pgr *p){
+  Pghdr *pPg;
+
+  TRACE(("PG: begin rollback\n"));
+  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
+    if( pPg->isDirty || pPg->jpgno!=0 ){
+      pPg->isDirty = 0;
+      pPg->jpgno = 0;
+      if( pPg->nRef>0 ){
+        TRACE(("PG: reloading d-page %u\n", pPg->dbpgno));
+        sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
+      }else{
+        sqlitePgUnlinkLru(pPg);
+      }
+    }
+  }
+  close(p->fdJournal);
+  p->fdJournal = -1;
+  unlink(p->zJournal);
+  while( (pPg = p->pJidx)!=0 ){
+    p->pAll = pPg->pNx;
+    sqliteFree(pPg);
+  }
+  p->nDbPg = sqlitePgPageCount(p->fdMain);
+  /* remove write lock from database */
+  if( p->nRefPg>0 ){
+    /* acquire read lock on database */
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Get a page from the database.  Return a pointer to the data for that
+** page.
+**
+** A NULL pointer will be returned if we run out of memory.
+*/
+int sqlitePgGet(Pgr *p, u32 pgno, void **ppData){
+  Pghdr *pPg;
+  int h;
+
+  pPg = sqlitePgFind(p, pgno);
+  if( pPg ){
+    pPg->nRef++;
+    if( pPg->nRef==1 ){
+      sqlitePgUnlinkLru(pPg);
+      TRACE(("PG: d-page %u pulled from cache\n", pgno));
+    }
+    p->nRefPg++;
+    if( p->nRefPg==1 ){
+      /* Acquire a read lock */
+    }
+    *ppData = PG_TO_DATA(pPg);
+    return SQLITE_OK;
+  }
+  if( p->nMemPg<MX_MEM_PAGE || p->pLru==0 ){
+    pPg = sqliteMalloc( sizeof(Pghdr) + SQLITE_PAGE_SIZE );
+    if( pPg==0 ) return SQLITE_NOMEM;
+    p->nMemPg++;
+    pPg->pNx = p->pAll;
+    p->pAll = pPg;
+    pPg->p = p;
+    TRACE(("PG: new page %d created.\n", p->nMemPg));
+  }else{
+    int rc;
+    pPg = p->pLru;
+    if( pPg->isDirty ){
+      rc = sqlitePgMakeClean(pPg);
+      if( rc!=SQLITE_OK ) return rc;
+    }
+    sqlitePgUnlinkLru(pPg);
+    h = pPg->dbpgno % PG_HASH_SIZE;
+    if( pPg->pPvHash ){
+      pPg->pPvHash->pNxHash = pPg->pNxHash;
+    }else{
+      assert( p->aPgHash[h]==pPg );
+      p->aPgHash[h] = pPg->pNxHash;
+    }
+    if( pPg->pNxHash ){
+      pPg->pNxHash->pPvHash = pPg->pPvHash;
+    }
+    TRACE(("PG: recycling d-page %u to d-page %u\n", pPg->dbpgno, pgno));
+  }
+  pPg->dbpgno = pgno;
+  if( pgno>p->nDbPg ){
+    p->nDbPg = pgno;
+  }
+  h = pgno % PG_HASH_SIZE;
+  pPg->pPvHash = 0;
+  pPg->pNxHash = p->aPgHash[h];
+  if( pPg->pNxHash ){
+    pPg->pNxHash->pPvHash = pPg;
+  }
+  p->aPgHash[h] = pPg;
+  pPg->jpgno = sqlitePgJournalPageNumber(p, pgno);
+  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{
+    TRACE(("PG: reading d-page %u from database\n", pgno));
+    sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
+  }
+  pPg->isDirty = 0;
+  pPg->nRef = 1;
+  p->nRefPg++;
+  if( p->nRefPg==1 ){
+    /* Acquire a read lock */
+  }
+  *ppData = PG_TO_DATA(pPg);
+  return SQLITE_OK;
+}
+
+/*
+** Release a reference to a database data page.
+*/
+int sqlitePgUnref(void *pData){
+  Pghdr *pPg = DATA_TO_PG(pData);
+  pPg->nRef--;
+  assert( pPg->nRef>=0 );
+  if( pPg->nRef==0 ){
+    Pgr *p = pPg->p;
+    pPg->pMru = 0;
+    pPg->pLru = p->pLru;
+    p->pLru = pPg;
+    TRACE(("PG: d-page %u is unused\n", pPg->dbpgno));
+    p->nRefPg--;
+    if( p->nRefPg==0 ){
+      /* Release the read lock */
+    }
+  }
+  return SQLITE_OK;
+}
+
+/*
+** The database page in the argument has been modified.  Write it back
+** to the database file on the next commit.
+*/
+int sqlitePgTouch(void *pD){
+  Pghdr *pPg = DATA_TO_PG(pD);
+  assert( pPg->p->fdJournal>=0 );
+  if( pPg->isDirty==0 ){
+    pPg->isDirty = 1;
+    TRACE(("PG: d-page %u is dirty\n", pPg->dbpgno));
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Return the number of the first unused page at the end of the
+** database file.
+*/
+int sqlitePgAlloc(Pgr *p, int *pPgno){
+  *pPgno = p->nDbPg;
+  return SQLITE_OK;
+}
diff --git a/src/pg.h b/src/pg.h
new file mode 100644 (file)
index 0000000..e30668e
--- /dev/null
+++ b/src/pg.h
@@ -0,0 +1,43 @@
+/*
+** Copyright (c) 2001 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** $Id: pg.h,v 1.1 2001/01/15 22:51:11 drh Exp $
+*/
+
+typedef struct Pgr Pgr;
+#define SQLITE_PAGE_SIZE 1024
+
+/*
+** The paging system deals with 32-bit integers.
+*/
+typedef unsigned int u32;
+
+int sqlitePgOpen(const char *filename, Pgr **pp);
+int sqlitePgClose(Pgr*);
+int sqlitePgBeginTransaction(Pgr*);
+int sqlitePgCommit(Pgr*);
+int sqlitePgRollback(Pgr*);
+int sqlitePgGet(Pgr*, u32 pgno, void **);
+int sqlitePgUnref(void*);
+int sqlitePgTouch(void*);
+int sqlitePgAlloc(Pgr*, int*);
index e15f09ea6f55c61d33e15b7ef278123e25238c0b..1dca4fdb391724b35966a11a030f1dc30deee405 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements.
 **
-** $Id: select.c,v 1.27 2000/10/16 22:06:42 drh Exp $
+** $Id: select.c,v 1.28 2001/01/15 22:51:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -489,9 +489,11 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
         && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){
           return 1;
         }
-        sqliteVdbeAddOp(v, OP_Open, unionTab, 1, 0, 0);
         if( p->op!=TK_ALL ){
+          sqliteVdbeAddOp(v, OP_OpenIdx, unionTab, 1, 0, 0);
           sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1, 0, 0);
+        }else{
+          sqliteVdbeAddOp(v, OP_OpenTbl, unionTab, 1, 0, 0);
         }
       }
 
@@ -549,7 +551,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
       if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
         return 1;
       }
-      sqliteVdbeAddOp(v, OP_Open, tab1, 1, 0, 0);
+      sqliteVdbeAddOp(v, OP_OpenIdx, tab1, 1, 0, 0);
       sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1, 0, 0);
 
       /* Code the SELECTs to our left into temporary table "tab1".
@@ -559,7 +561,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
 
       /* Code the current SELECT into temporary table "tab2"
       */
-      sqliteVdbeAddOp(v, OP_Open, tab2, 1, 0, 0);
+      sqliteVdbeAddOp(v, OP_OpenIdx, tab2, 1, 0, 0);
       sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1, 0, 0);
       p->pPrior = 0;
       rc = sqliteSelect(pParse, p, SRT_Union, tab2);
@@ -852,7 +854,7 @@ int sqliteSelect(
   /* Begin the database scan
   */
   if( isDistinct ){
-    sqliteVdbeAddOp(v, OP_Open, distinct, 1, 0, 0);
+    sqliteVdbeAddOp(v, OP_OpenIdx, distinct, 1, 0, 0);
   }
   pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
   if( pWInfo==0 ) return 1;
index deadbb0655a5870afd10564c8d927ddf62ed1935..398b626667aace161f64ac29a398dc4a31979d7e 100644 (file)
@@ -24,7 +24,7 @@
 ** This header file defines the interface that the sqlite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.7 2000/11/28 20:47:20 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.8 2001/01/15 22:51:11 drh Exp $
 */
 #ifndef _SQLITE_H_
 #define _SQLITE_H_
@@ -138,6 +138,7 @@ int sqlite_exec(
 #define SQLITE_NOMEM     6    /* A malloc() failed */
 #define SQLITE_READONLY  7    /* Attempt to write a readonly database */
 #define SQLITE_INTERRUPT 8    /* Operation terminated by sqlite_interrupt() */
+#define SQLITE_IOERR     9    /* Disk full or other I/O error */
 
 /* This function causes any pending database operation to abort and
 ** return at its earliest opportunity.  This routine is typically
index b6e60210200c1c8c2217386985dcb2a3be8250e2..d2015570a5cb7484c8b511f45b9ecc649aea6b76 100644 (file)
@@ -23,7 +23,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.34 2001/01/13 14:34:07 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.35 2001/01/15 22:51:11 drh Exp $
 */
 #include "sqlite.h"
 #include "dbbe.h"
@@ -422,5 +422,7 @@ Vdbe *sqliteGetVdbe(Parse*);
 int sqliteRandomByte(void);
 int sqliteRandomInteger(void);
 void sqliteRandomName(char*,char*);
-int sqliteDbbeOpenTempFile(Dbbe*, FILE**);
+int sqliteDbbeOpenTempFile(const char*, Dbbe*, FILE**);
 void sqliteDbbeCloseTempFile(Dbbe*, FILE*);
+void sqliteDbbeCloseAllTempFiles(Dbbe*);
+char *sqliteDbbeNameToFile(const char*,const char*,const char*);
index 6902a94e3cc163e041852c76060cbeffae97d0c1..565e2fd9db531e5ea26bc4e1e0a44b7fb3991fad 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.8 2000/06/21 13:59:12 drh Exp $
+** $Id: update.c,v 1.9 2001/01/15 22:51:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -159,9 +159,9 @@ void sqliteUpdate(
   */
   sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
   base = pParse->nTab;
-  sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
+  sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
   for(i=0; i<nIdx; i++){
-    sqliteVdbeAddOp(v, OP_Open, base+i+1, 1, apIdx[i]->zName, 0);
+    sqliteVdbeAddOp(v, OP_OpenIdx, base+i+1, 1, apIdx[i]->zName, 0);
   }
 
   /* Loop over every record that needs updating.  We have to load
index 749f1e039ca1eb21b6c4fd9500965bbeb674cab3..31364bc5d8e702a6b9dae055c2018d500f0b2bd4 100644 (file)
@@ -41,7 +41,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.50 2001/01/13 14:34:07 drh Exp $
+** $Id: vdbe.c,v 1.51 2001/01/15 22:51:12 drh Exp $
 */
 #include "sqliteInt.h"
 #include <unistd.h>
@@ -786,29 +786,29 @@ void sqliteVdbeDelete(Vdbe *p){
 ** this array, then copy and paste it into this file, if you want.
 */
 static char *zOpName[] = { 0,
-  "Open",           "Close",          "Fetch",          "Fcnt",
-  "New",            "Put",            "Distinct",       "Found",
-  "NotFound",       "Delete",         "Field",          "KeyAsData",
-  "Key",            "Rewind",         "Next",           "Destroy",
-  "Reorganize",     "ResetIdx",       "NextIdx",        "PutIdx",
-  "DeleteIdx",      "MemLoad",        "MemStore",       "ListOpen",
-  "ListWrite",      "ListRewind",     "ListRead",       "ListClose",
-  "SortOpen",       "SortPut",        "SortMakeRec",    "SortMakeKey",
-  "Sort",           "SortNext",       "SortKey",        "SortCallback",
-  "SortClose",      "FileOpen",       "FileRead",       "FileField",
-  "FileClose",      "AggReset",       "AggFocus",       "AggIncr",
-  "AggNext",        "AggSet",         "AggGet",         "SetInsert",
-  "SetFound",       "SetNotFound",    "SetClear",       "MakeRecord",
-  "MakeKey",        "Goto",           "If",             "Halt",
-  "ColumnCount",    "ColumnName",     "Callback",       "Integer",
-  "String",         "Null",           "Pop",            "Dup",
-  "Pull",           "Add",            "AddImm",         "Subtract",
-  "Multiply",       "Divide",         "Min",            "Max",
-  "Like",           "Glob",           "Eq",             "Ne",
-  "Lt",             "Le",             "Gt",             "Ge",
-  "IsNull",         "NotNull",        "Negative",       "And",
-  "Or",             "Not",            "Concat",         "Noop",
-  "Strlen",         "Substr",       
+  "OpenIdx",        "OpenTbl",        "Close",          "Fetch",
+  "Fcnt",           "New",            "Put",            "Distinct",
+  "Found",          "NotFound",       "Delete",         "Field",
+  "KeyAsData",      "Key",            "Rewind",         "Next",
+  "Destroy",        "Reorganize",     "ResetIdx",       "NextIdx",
+  "PutIdx",         "DeleteIdx",      "MemLoad",        "MemStore",
+  "ListOpen",       "ListWrite",      "ListRewind",     "ListRead",
+  "ListClose",      "SortOpen",       "SortPut",        "SortMakeRec",
+  "SortMakeKey",    "Sort",           "SortNext",       "SortKey",
+  "SortCallback",   "SortClose",      "FileOpen",       "FileRead",
+  "FileField",      "FileClose",      "AggReset",       "AggFocus",
+  "AggIncr",        "AggNext",        "AggSet",         "AggGet",
+  "SetInsert",      "SetFound",       "SetNotFound",    "SetClear",
+  "MakeRecord",     "MakeKey",        "Goto",           "If",
+  "Halt",           "ColumnCount",    "ColumnName",     "Callback",
+  "Integer",        "String",         "Null",           "Pop",
+  "Dup",            "Pull",           "Add",            "AddImm",
+  "Subtract",       "Multiply",       "Divide",         "Min",
+  "Max",            "Like",           "Glob",           "Eq",
+  "Ne",             "Lt",             "Le",             "Gt",
+  "Ge",             "IsNull",         "NotNull",        "Negative",
+  "And",            "Or",             "Not",            "Concat",
+  "Noop",           "Strlen",         "Substr",       
 };
 
 /*
@@ -1782,7 +1782,7 @@ int sqliteVdbeExec(
         break;
       }
 
-      /* Opcode: Open P1 P2 P3
+      /* Opcode: OpenIdx P1 P2 P3
       **
       ** Open a new cursor for the database file named P3.  Give the
       ** cursor an identifier P1.  The P1 values need not be
@@ -1798,8 +1798,28 @@ int sqliteVdbeExec(
       ** If P3 is null or an empty string, a temporary database file
       ** is created.  This temporary database file is automatically 
       ** deleted when the cursor is closed.
+      **
+      ** The database file opened must be able to map arbitrary length
+      ** keys into arbitrary data.  A similar opcode, OpenTbl, opens
+      ** a database file that maps integer keys into arbitrary length
+      ** data.  This opcode opens database files used as
+      ** SQL indices and OpenTbl opens database files used for SQL
+      ** tables.
+      */
+      /* Opcode: OpenTbl P1 P2 P3
+      **
+      ** This works just like the OpenIdx operation except that the database
+      ** file that is opened is one that will only accept integers as
+      ** keys.  Some database backends are able to operate more efficiently
+      ** if keys are always integers.  So if SQLite knows in advance that
+      ** all keys will be integers, it uses this opcode rather than Open
+      ** in order to give the backend an opportunity to run faster.
+      **
+      ** This opcode opens database files used for storing SQL tables.
+      ** The OpenIdx opcode opens files used for SQL indices.
       */
-      case OP_Open: {
+      case OP_OpenIdx: 
+      case OP_OpenTbl: {
         int busy = 0;
         int i = pOp->p1;
         VERIFY( if( i<0 ) goto bad_instruction; )
@@ -1813,7 +1833,8 @@ int sqliteVdbeExec(
           pBex->CloseCursor(p->aCsr[i].pCursor);
         }
         do {
-          rc = pBex->OpenCursor(pBe,pOp->p3,pOp->p2,&p->aCsr[i].pCursor);
+          rc = pBex->OpenCursor(pBe,pOp->p3, pOp->p2,
+                                pOp->opcode==OP_OpenTbl, &p->aCsr[i].pCursor);
           switch( rc ){
             case SQLITE_BUSY: {
               if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
index 8e94ad365e8982127453631d5bbccfe463d34dc5..fe2cccb3f2331d55ea17a4e05003ca3e5d30d803 100644 (file)
@@ -27,7 +27,7 @@
 ** or VDBE.  The VDBE implements an abstract machine that runs a
 ** simple program to access and modify the underlying database.
 **
-** $Id: vdbe.h,v 1.14 2000/10/16 22:06:43 drh Exp $
+** $Id: vdbe.h,v 1.15 2001/01/15 22:51:12 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -71,112 +71,113 @@ typedef struct VdbeOp VdbeOp;
 ** The source tree contains an AWK script named renumberOps.awk that
 ** can be used to renumber these opcodes when new opcodes are inserted.
 */
-#define OP_Open                1
-#define OP_Close               2
-#define OP_Fetch               3
-#define OP_Fcnt                4
-#define OP_New                 5
-#define OP_Put                 6
-#define OP_Distinct            7
-#define OP_Found               8
-#define OP_NotFound            9
-#define OP_Delete             10
-#define OP_Field              11
-#define OP_KeyAsData          12
-#define OP_Key                13
-#define OP_Rewind             14
-#define OP_Next               15
-
-#define OP_Destroy            16
-#define OP_Reorganize         17
-
-#define OP_ResetIdx           18
-#define OP_NextIdx            19
-#define OP_PutIdx             20
-#define OP_DeleteIdx          21
-
-#define OP_MemLoad            22
-#define OP_MemStore           23
-
-#define OP_ListOpen           24
-#define OP_ListWrite          25
-#define OP_ListRewind         26
-#define OP_ListRead           27
-#define OP_ListClose          28
-
-#define OP_SortOpen           29
-#define OP_SortPut            30
-#define OP_SortMakeRec        31
-#define OP_SortMakeKey        32
-#define OP_Sort               33
-#define OP_SortNext           34
-#define OP_SortKey            35
-#define OP_SortCallback       36
-#define OP_SortClose          37
-
-#define OP_FileOpen           38
-#define OP_FileRead           39
-#define OP_FileField          40
-#define OP_FileClose          41
-
-#define OP_AggReset           42
-#define OP_AggFocus           43
-#define OP_AggIncr            44
-#define OP_AggNext            45
-#define OP_AggSet             46
-#define OP_AggGet             47
-
-#define OP_SetInsert          48
-#define OP_SetFound           49
-#define OP_SetNotFound        50
-#define OP_SetClear           51
-
-#define OP_MakeRecord         52
-#define OP_MakeKey            53
-
-#define OP_Goto               54
-#define OP_If                 55
-#define OP_Halt               56
-
-#define OP_ColumnCount        57
-#define OP_ColumnName         58
-#define OP_Callback           59
-
-#define OP_Integer            60
-#define OP_String             61
-#define OP_Null               62
-#define OP_Pop                63
-#define OP_Dup                64
-#define OP_Pull               65
-
-#define OP_Add                66
-#define OP_AddImm             67
-#define OP_Subtract           68
-#define OP_Multiply           69
-#define OP_Divide             70
-#define OP_Min                71
-#define OP_Max                72
-#define OP_Like               73
-#define OP_Glob               74
-#define OP_Eq                 75
-#define OP_Ne                 76
-#define OP_Lt                 77
-#define OP_Le                 78
-#define OP_Gt                 79
-#define OP_Ge                 80
-#define OP_IsNull             81
-#define OP_NotNull            82
-#define OP_Negative           83
-#define OP_And                84
-#define OP_Or                 85
-#define OP_Not                86
-#define OP_Concat             87
-#define OP_Noop               88
-
-#define OP_Strlen             89
-#define OP_Substr             90
-
-#define OP_MAX                90
+#define OP_OpenIdx             1
+#define OP_OpenTbl             2
+#define OP_Close               3
+#define OP_Fetch               4
+#define OP_Fcnt                5
+#define OP_New                 6
+#define OP_Put                 7
+#define OP_Distinct            8
+#define OP_Found               9
+#define OP_NotFound           10
+#define OP_Delete             11
+#define OP_Field              12
+#define OP_KeyAsData          13
+#define OP_Key                14
+#define OP_Rewind             15
+#define OP_Next               16
+
+#define OP_Destroy            17
+#define OP_Reorganize         18
+
+#define OP_ResetIdx           19
+#define OP_NextIdx            20
+#define OP_PutIdx             21
+#define OP_DeleteIdx          22
+
+#define OP_MemLoad            23
+#define OP_MemStore           24
+
+#define OP_ListOpen           25
+#define OP_ListWrite          26
+#define OP_ListRewind         27
+#define OP_ListRead           28
+#define OP_ListClose          29
+
+#define OP_SortOpen           30
+#define OP_SortPut            31
+#define OP_SortMakeRec        32
+#define OP_SortMakeKey        33
+#define OP_Sort               34
+#define OP_SortNext           35
+#define OP_SortKey            36
+#define OP_SortCallback       37
+#define OP_SortClose          38
+
+#define OP_FileOpen           39
+#define OP_FileRead           40
+#define OP_FileField          41
+#define OP_FileClose          42
+
+#define OP_AggReset           43
+#define OP_AggFocus           44
+#define OP_AggIncr            45
+#define OP_AggNext            46
+#define OP_AggSet             47
+#define OP_AggGet             48
+
+#define OP_SetInsert          49
+#define OP_SetFound           50
+#define OP_SetNotFound        51
+#define OP_SetClear           52
+
+#define OP_MakeRecord         53
+#define OP_MakeKey            54
+
+#define OP_Goto               55
+#define OP_If                 56
+#define OP_Halt               57
+
+#define OP_ColumnCount        58
+#define OP_ColumnName         59
+#define OP_Callback           60
+
+#define OP_Integer            61
+#define OP_String             62
+#define OP_Null               63
+#define OP_Pop                64
+#define OP_Dup                65
+#define OP_Pull               66
+
+#define OP_Add                67
+#define OP_AddImm             68
+#define OP_Subtract           69
+#define OP_Multiply           70
+#define OP_Divide             71
+#define OP_Min                72
+#define OP_Max                73
+#define OP_Like               74
+#define OP_Glob               75
+#define OP_Eq                 76
+#define OP_Ne                 77
+#define OP_Lt                 78
+#define OP_Le                 79
+#define OP_Gt                 80
+#define OP_Ge                 81
+#define OP_IsNull             82
+#define OP_NotNull            83
+#define OP_Negative           84
+#define OP_And                85
+#define OP_Or                 86
+#define OP_Not                87
+#define OP_Concat             88
+#define OP_Noop               89
+
+#define OP_Strlen             90
+#define OP_Substr             91
+
+#define OP_MAX                91
 
 /*
 ** Prototypes for the VDBE interface.  See comments on the implementation
index a50ba4986b4a6cd5839de9afd8dfc4e9c483afda..6dde69727487e6f666716f762d9a7afeb58e4892 100644 (file)
@@ -25,7 +25,7 @@
 ** the WHERE clause of SQL statements.  Also found here are subroutines
 ** to generate VDBE code to evaluate expressions.
 **
-** $Id: where.c,v 1.9 2000/08/22 18:29:34 drh Exp $
+** $Id: where.c,v 1.10 2001/01/15 22:51:12 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -271,9 +271,9 @@ WhereInfo *sqliteWhereBegin(
   /* Open all tables in the pTabList and all indices in aIdx[].
   */
   for(i=0; i<pTabList->nId; i++){
-    sqliteVdbeAddOp(v, OP_Open, base+i, 0, pTabList->a[i].pTab->zName, 0);
+    sqliteVdbeAddOp(v, OP_OpenTbl, base+i, 0, pTabList->a[i].pTab->zName, 0);
     if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
-      sqliteVdbeAddOp(v, OP_Open, base+pTabList->nId+i, 0, aIdx[i]->zName, 0);
+      sqliteVdbeAddOp(v, OP_OpenIdx, base+pTabList->nId+i, 0, aIdx[i]->zName,0);
     }
   }
   memcpy(pWInfo->aIdx, aIdx, sizeof(aIdx));