diff --git a/manifest b/manifest index 1a1d551049..c1b04d98f3 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 201ff7ea33..84569a2832 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c0730217a04323a1a73d125e3e7da32bcc8d58fc \ No newline at end of file +c6ffb7ec6acb596907ead8992dfad94e18e83866 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 531a9f16e5..a003cacb03 100644 --- a/src/build.c +++ b/src/build.c @@ -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 index 0000000000..97778ba317 --- /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*); diff --git a/src/dbbe.c b/src/dbbe.c index 907aa73801..8e3516a1e7 100644 --- a/src/dbbe.c +++ b/src/dbbe.c @@ -30,9 +30,10 @@ ** 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 /* ** 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; inTemp; 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; +} diff --git a/src/dbbe.h b/src/dbbe.h index 7d524cb037..09166469d5 100644 --- a/src/dbbe.h +++ b/src/dbbe.h @@ -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 */ diff --git a/src/dbbegdbm.c b/src/dbbegdbm.c index 6c2659a80b..eb4d482e7f 100644 --- a/src/dbbegdbm.c +++ b/src/dbbegdbm.c @@ -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 @@ -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; diff --git a/src/dbbemem.c b/src/dbbemem.c index 89b4aeed1e..4ac3bdbaf8 100644 --- a/src/dbbemem.c +++ b/src/dbbemem.c @@ -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 @@ -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; } diff --git a/src/delete.c b/src/delete.c index f6822f9ab5..d5e5a3b01e 100644 --- a/src/delete.c +++ b/src/delete.c @@ -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); diff --git a/src/expr.c b/src/expr.c index 94a41cf587..64376867e3 100644 --- a/src/expr.c +++ b/src/expr.c @@ -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) diff --git a/src/insert.c b/src/insert.c index a044bc1448..553a1c8516 100644 --- a/src/insert.c +++ b/src/insert.c @@ -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 diff --git a/src/main.c b/src/main.c index a707b67228..47f85d8210 100644 --- a/src/main.c +++ b/src/main.c @@ -26,9 +26,10 @@ ** 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 /* ** 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 index 0000000000..a4b6465b81 --- /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 +#include +#include +#include +#include +#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( got0 ); + assert( fd>=0 ); + lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE); + while( done>= 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; ifdMain, 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->nMemPgpLru==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 index 0000000000..e30668e2dc --- /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*); diff --git a/src/select.c b/src/select.c index e15f09ea6f..1dca4fdb39 100644 --- a/src/select.c +++ b/src/select.c @@ -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; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index deadbb0655..398b626667 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -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 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index b6e6021020..d2015570a5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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*); diff --git a/src/update.c b/src/update.c index 6902a94e3c..565e2fd9db 100644 --- a/src/update.c +++ b/src/update.c @@ -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; izName, 0); + sqliteVdbeAddOp(v, OP_OpenIdx, base+i+1, 1, apIdx[i]->zName, 0); } /* Loop over every record that needs updating. We have to load diff --git a/src/vdbe.c b/src/vdbe.c index 749f1e039c..31364bc5d8 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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 @@ -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. */ - case OP_Open: { + /* 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_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 ){ diff --git a/src/vdbe.h b/src/vdbe.h index 8e94ad365e..fe2cccb3f2 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -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_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 16 -#define OP_Reorganize 17 +#define OP_Destroy 17 +#define OP_Reorganize 18 -#define OP_ResetIdx 18 -#define OP_NextIdx 19 -#define OP_PutIdx 20 -#define OP_DeleteIdx 21 +#define OP_ResetIdx 19 +#define OP_NextIdx 20 +#define OP_PutIdx 21 +#define OP_DeleteIdx 22 -#define OP_MemLoad 22 -#define OP_MemStore 23 +#define OP_MemLoad 23 +#define OP_MemStore 24 -#define OP_ListOpen 24 -#define OP_ListWrite 25 -#define OP_ListRewind 26 -#define OP_ListRead 27 -#define OP_ListClose 28 +#define OP_ListOpen 25 +#define OP_ListWrite 26 +#define OP_ListRewind 27 +#define OP_ListRead 28 +#define OP_ListClose 29 -#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_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 38 -#define OP_FileRead 39 -#define OP_FileField 40 -#define OP_FileClose 41 +#define OP_FileOpen 39 +#define OP_FileRead 40 +#define OP_FileField 41 +#define OP_FileClose 42 -#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_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 48 -#define OP_SetFound 49 -#define OP_SetNotFound 50 -#define OP_SetClear 51 +#define OP_SetInsert 49 +#define OP_SetFound 50 +#define OP_SetNotFound 51 +#define OP_SetClear 52 -#define OP_MakeRecord 52 -#define OP_MakeKey 53 +#define OP_MakeRecord 53 +#define OP_MakeKey 54 -#define OP_Goto 54 -#define OP_If 55 -#define OP_Halt 56 +#define OP_Goto 55 +#define OP_If 56 +#define OP_Halt 57 -#define OP_ColumnCount 57 -#define OP_ColumnName 58 -#define OP_Callback 59 +#define OP_ColumnCount 58 +#define OP_ColumnName 59 +#define OP_Callback 60 -#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_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 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_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 89 -#define OP_Substr 90 +#define OP_Strlen 90 +#define OP_Substr 91 -#define OP_MAX 90 +#define OP_MAX 91 /* ** Prototypes for the VDBE interface. See comments on the implementation diff --git a/src/where.c b/src/where.c index a50ba4986b..6dde697274 100644 --- a/src/where.c +++ b/src/where.c @@ -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; inId; 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( inId+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));