-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
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
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
-c0730217a04323a1a73d125e3e7da32bcc8d58fc
\ No newline at end of file
+c6ffb7ec6acb596907ead8992dfad94e18e83866
\ No newline at end of file
** 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"
*/
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 */
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 */
*/
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 */
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;
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 */
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);
--- /dev/null
+/*
+** 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*);
** 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
** 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;
}
limit = 4;
zFile = 0;
- zDir = pBe->zDir;
- if( zDir==0 ){
- zDir = "./";
- }
do{
sqliteRandomName(zBuf, "/_temp_file_");
sqliteFree(zFile);
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;
+}
** 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_
** 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);
*/
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 */
** 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>
Dbbe dbbe; /* The base class */
int write; /* True for write permission */
BeFile *pOpen; /* List of open files */
+ char *zDir; /* Directory hold the database */
};
/*
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.
*/
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);
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);
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 */
DbbeCursor *pCrsr;
int rc;
- rc = sqliteGdbmOpenCursor(pBe, zTable, 1, &pCrsr);
+ rc = sqliteGdbmOpenCursor(pBe, zTable, 1, 0, &pCrsr);
if( rc!=SQLITE_OK ){
return rc;
}
int iKey;
datum key;
int go = 1;
- int i;
if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
while( go ){
** 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;
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.
/* New */ sqliteGdbmNew,
/* Put */ sqliteGdbmPut,
/* Delete */ sqliteGdbmDelete,
- /* OpenTempFile */ sqliteDbbeOpenTempFile,
+ /* OpenTempFile */ sqliteGdbmOpenTempFile,
/* CloseTempFile */ sqliteDbbeCloseTempFile
};
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;
**
** 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>
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 */
};
*/
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);
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;
pTble->zName = 0;
pTble->delOnClose = 1;
}
+ pTble->intKeyOnly = intKeyOnly;
ArrayInit(&pTble->data);
}else{
+ assert( pTble->intKeyOnly==intKeyOnly );
sqliteFree(zName);
}
pCursr->pBe = pBe;
char *zName; /* Name of the table file */
Datum key, data;
MTable *pTble;
- ArrayElem *i;
Dbbex *pBe = (Dbbex*)pDbbe;
zName = sqliteNameOfTable(zTable);
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;
}
int iKey;
Datum key;
int go = 1;
- int i;
while( go ){
iKey = sqliteRandomInteger();
** 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);
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.
/* New */ sqliteMemNew,
/* Put */ sqliteMemPut,
/* Delete */ sqliteMemDelete,
- /* OpenTempFile */ sqliteDbbeOpenTempFile,
+ /* OpenTempFile */ sqliteMemOpenTempFile,
/* CloseTempFile */ sqliteDbbeCloseTempFile
};
}
ArrayInit(&pNew->tables);
pNew->dbbe.x = &memoryMethods;
- pNew->dbbe.zDir = 0;
return &pNew->dbbe;
}
** 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"
*/
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);
** 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"
** 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)
** 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"
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 );
** 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
** 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
** 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"},
char **pzErrMsg /* Write error messages here */
){
Parse sParse;
- int rc;
if( pzErrMsg ) *pzErrMsg = 0;
if( (db->flags & SQLITE_Initialized)==0 ){
--- /dev/null
+/*
+** 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;
+}
--- /dev/null
+/*
+** 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*);
** 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"
&& 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);
}
}
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".
/* 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);
/* 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;
** 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_
#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
*************************************************************************
** 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"
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*);
** 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"
*/
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
** 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>
** 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",
};
/*
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
** 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; )
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 ){
** 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_
** 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
** 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"
/* 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));