1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

continued progress toward version 2.0 (CVS 177)

FossilOrigin-Name: c6ffb7ec6acb596907ead8992dfad94e18e83866
This commit is contained in:
drh
2001-01-15 22:51:08 +00:00
parent ae85dc8b0b
commit 345fda3ef5
21 changed files with 1125 additions and 216 deletions

View File

@ -33,7 +33,7 @@
** COPY
** VACUUM
**
** $Id: build.c,v 1.24 2000/10/16 22:06:42 drh Exp $
** $Id: build.c,v 1.25 2001/01/15 22:51:09 drh Exp $
*/
#include "sqliteInt.h"
@ -341,7 +341,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
*/
if( !pParse->initFlag ){
static VdbeOp addTable[] = {
{ OP_Open, 0, 1, MASTER_NAME },
{ OP_OpenTbl, 0, 1, MASTER_NAME },
{ OP_New, 0, 0, 0},
{ OP_String, 0, 0, "table" },
{ OP_String, 0, 0, 0}, /* 3 */
@ -416,7 +416,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
v = sqliteGetVdbe(pParse);
if( v ){
static VdbeOp dropTable[] = {
{ OP_Open, 0, 1, MASTER_NAME },
{ OP_OpenTbl, 0, 1, MASTER_NAME },
{ OP_ListOpen, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 2 */
{ OP_Next, 0, ADDR(10), 0}, /* 3 */
@ -593,7 +593,7 @@ void sqliteCreateIndex(
*/
if( pParse->initFlag==0 ){
static VdbeOp addTable[] = {
{ OP_Open, 2, 1, MASTER_NAME},
{ OP_OpenTbl, 2, 1, MASTER_NAME},
{ OP_New, 2, 0, 0},
{ OP_String, 0, 0, "index"},
{ OP_String, 0, 0, 0}, /* 3 */
@ -610,8 +610,8 @@ void sqliteCreateIndex(
v = sqliteGetVdbe(pParse);
if( v==0 ) goto exit_create_index;
sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_Open, 1, 1, pIndex->zName, 0);
sqliteVdbeAddOp(v, OP_OpenTbl, 0, 0, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, 1, 1, pIndex->zName, 0);
if( pStart && pEnd ){
int base;
n = (int)pEnd->z - (int)pStart->z + 1;
@ -670,7 +670,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
v = sqliteGetVdbe(pParse);
if( v ){
static VdbeOp dropIndex[] = {
{ OP_Open, 0, 1, MASTER_NAME},
{ OP_OpenTbl, 0, 1, MASTER_NAME},
{ OP_ListOpen, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 2 */
{ OP_Next, 0, ADDR(9), 0}, /* 3 */
@ -843,9 +843,9 @@ void sqliteCopy(
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
sqliteVdbeDequoteP3(v, addr);
sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_OpenTbl, 0, 1, pTab->zName, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
sqliteVdbeAddOp(v, OP_Open, i, 1, pIdx->zName, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, i, 1, pIdx->zName, 0);
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);

53
src/db.h Normal file
View File

@ -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*);

View File

@ -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 <unistd.h>
/*
** This routine opens a new database. It looks at the first
@ -70,13 +71,12 @@ Dbbe *sqliteDbbeOpen(
** and then immediately unlinking the file. That works great
** under Unix, but fails when we try to port to Windows.
*/
int sqliteDbbeOpenTempFile(Dbbe *pBe, FILE **ppFile){
int sqliteDbbeOpenTempFile(const char *zDir, Dbbe *pBe, FILE **ppFile){
char *zFile; /* Full name of the temporary file */
char zBuf[50]; /* Base name of the temporary file */
int i; /* Loop counter */
int limit; /* Prevent an infinite loop */
int rc = SQLITE_OK; /* Value returned by this function */
char *zDir; /* Directory to hold the file */
for(i=0; i<pBe->nTemp; i++){
if( pBe->apTemp[i]==0 ) break;
@ -92,10 +92,6 @@ int sqliteDbbeOpenTempFile(Dbbe *pBe, FILE **ppFile){
}
limit = 4;
zFile = 0;
zDir = pBe->zDir;
if( zDir==0 ){
zDir = "./";
}
do{
sqliteRandomName(zBuf, "/_temp_file_");
sqliteFree(zFile);
@ -149,3 +145,54 @@ void sqliteDbbeCloseAllTempFiles(Dbbe *pBe){
sqliteFree(pBe->azTemp);
sqliteFree(pBe->apTemp);
}
/*
** Translate the name of an SQL table (or index) into the name
** of a file that holds the key/data pairs for that table or
** index. Space to hold the filename is obtained from
** sqliteMalloc() and must be freed by the calling function.
**
** zDir is the name of the directory in which the file should
** be located. zSuffix is the filename extension to use for
** the file.
*/
char *sqliteDbbeNameToFile(
const char *zDir, /* Directory containing the file */
const char *zTable, /* Name of the SQL table that the file contains */
const char *zSuffix /* Suffix for the file. Includes the "." */
){
char *zFile = 0;
int i, k, c;
int nChar = 0;
for(i=0; (c = zTable[i])!=0; i++){
if( !isalnum(c) && c!='_' ){
nChar += 3;
}else{
nChar ++;
}
}
nChar += strlen(zDir) + strlen(zSuffix) + 2;
zFile = sqliteMalloc( nChar );
if( zFile==0 ) return 0;
for(i=0; (c = zDir[i])!=0; i++){
zFile[i] = c;
}
zFile[i++] = '/';
for(k=0; (c = zTable[k])!=0; k++){
if( isupper(c) ){
zFile[i++] = tolower(c);
}else if( isalnum(c) || c=='_' ){
zFile[i++] = c;
}else{
zFile[i++] = '~';
zFile[i++] = "0123456789abcdef"[c & 0xf];
zFile[i++] = "0123456789abcdef"[(c>>8)&0xf];
}
}
for(k=0; (c = zSuffix[k])!=0; k++){
zFile[i++] = c;
}
zFile[i] = 0;
return zFile;
}

View File

@ -28,7 +28,7 @@
** This library was originally designed to support the following
** backends: GDBM, NDBM, SDBM, Berkeley DB.
**
** $Id: dbbe.h,v 1.9 2001/01/13 14:34:06 drh Exp $
** $Id: dbbe.h,v 1.10 2001/01/15 22:51:10 drh Exp $
*/
#ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_
@ -81,10 +81,16 @@ struct DbbeMethods {
** an appropriate path and extension to the filename to locate the
** actual file.
**
** The keyType parameter is TRUE if this table will only be accessed
** using integer keys. This parameter allows the database backend to
** use a faster algorithm for the special case of integer keys, if it
** wants to.
**
** If zName is 0 or "", then a temporary file is created that
** will be deleted when closed.
*/
int (*OpenCursor)(Dbbe*, const char *zName, int writeable, DbbeCursor**);
int (*OpenCursor)(Dbbe*, const char *zName, int writeable,
int intKeyOnly, DbbeCursor**);
/* Delete a table from the database */
void (*DropTable)(Dbbe*, const char *zTableName);
@ -164,7 +170,6 @@ struct DbbeMethods {
*/
struct Dbbe {
struct DbbeMethods *x; /* Backend-specific methods for database access */
char *zDir; /* The directory containing the database file(s) */
int nTemp; /* Number of temporary files created */
FILE **apTemp; /* Space to hold temporary file pointers */
char **azTemp; /* Names of the temporary files */

View File

@ -30,7 +30,7 @@
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbegdbm.c,v 1.2 2001/01/13 14:34:06 drh Exp $
** $Id: dbbegdbm.c,v 1.3 2001/01/15 22:51:10 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
@ -66,6 +66,7 @@ struct Dbbex {
Dbbe dbbe; /* The base class */
int write; /* True for write permission */
BeFile *pOpen; /* List of open files */
char *zDir; /* Directory hold the database */
};
/*
@ -85,13 +86,6 @@ struct DbbeCursor {
int readPending; /* The fetch hasn't actually been done yet */
};
/*
**
*/
struct DbbeList {
FILE *pOut;
Dbbe *pDbbe;
};
/*
** The "mkdir()" function only takes one argument under Windows.
*/
@ -110,7 +104,6 @@ static void sqliteGdbmCloseCursor(DbbeCursor *pCursr);
static void sqliteGdbmClose(Dbbe *pDbbe){
Dbbex *pBe = (Dbbex*)pDbbe;
BeFile *pFile, *pNext;
int i;
for(pFile=pBe->pOpen; pFile; pFile=pNext){
pNext = pFile->pNext;
gdbm_close(pFile->dbf);
@ -131,9 +124,9 @@ static void sqliteGdbmClose(Dbbe *pDbbe){
static char *sqliteFileOfTable(Dbbex *pBe, const char *zTable){
char *zFile = 0;
int i;
sqliteSetString(&zFile, pBe->dbbe.zDir, "/", zTable, ".tbl", 0);
sqliteSetString(&zFile, pBe->zDir, "/", zTable, ".tbl", 0);
if( zFile==0 ) return 0;
for(i=strlen(pBe->dbbe.zDir)+1; zFile[i]; i++){
for(i=strlen(pBe->zDir)+1; zFile[i]; i++){
int c = zFile[i];
if( isupper(c) ){
zFile[i] = tolower(c);
@ -172,6 +165,7 @@ static int sqliteGdbmOpenCursor(
Dbbe *pDbbe, /* The database the table belongs to */
const char *zTable, /* The SQL name of the file to be opened */
int writeable, /* True to open for writing */
int intKeyOnly, /* True if only integer keys are used */
DbbeCursor **ppCursr /* Write the resulting table pointer here */
){
char *zFile; /* Name of the table file */
@ -330,7 +324,7 @@ static int sqliteGdbmReorganizeTable(Dbbe *pBe, const char *zTable){
DbbeCursor *pCrsr;
int rc;
rc = sqliteGdbmOpenCursor(pBe, zTable, 1, &pCrsr);
rc = sqliteGdbmOpenCursor(pBe, zTable, 1, 0, &pCrsr);
if( rc!=SQLITE_OK ){
return rc;
}
@ -494,7 +488,6 @@ static int sqliteGdbmNew(DbbeCursor *pCursr){
int iKey;
datum key;
int go = 1;
int i;
if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
while( go ){
@ -511,8 +504,13 @@ static int sqliteGdbmNew(DbbeCursor *pCursr){
** Write an entry into the table. Overwrite any prior entry with the
** same key.
*/
static int
sqliteGdbmPut(DbbeCursor *pCursr, int nKey,char *pKey,int nData,char *pData){
static int sqliteGdbmPut(
DbbeCursor *pCursr, /* Write to the database associated with this cursor */
int nKey, /* Number of bytes in the key */
char *pKey, /* The data for the key */
int nData, /* Number of bytes of data */
char *pData /* The data */
){
datum data, key;
int rc;
if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
@ -543,6 +541,15 @@ static int sqliteGdbmDelete(DbbeCursor *pCursr, int nKey, char *pKey){
return rc;
}
/*
** Open a temporary file. The file is located in the same directory
** as the rest of the database.
*/
static int sqliteGdbmOpenTempFile(Dbbe *pDbbe, FILE **ppFile){
Dbbex *pBe = (Dbbex*)pDbbe;
return sqliteDbbeOpenTempFile(pBe->zDir, pDbbe, ppFile);
}
/*
** This variable contains pointers to all of the access methods
** used to implement the GDBM backend.
@ -566,7 +573,7 @@ static struct DbbeMethods gdbmMethods = {
/* New */ sqliteGdbmNew,
/* Put */ sqliteGdbmPut,
/* Delete */ sqliteGdbmDelete,
/* OpenTempFile */ sqliteDbbeOpenTempFile,
/* OpenTempFile */ sqliteGdbmOpenTempFile,
/* CloseTempFile */ sqliteDbbeCloseTempFile
};
@ -623,8 +630,8 @@ Dbbe *sqliteGdbmOpen(
return 0;
}
pNew->dbbe.x = &gdbmMethods;
pNew->dbbe.zDir = (char*)&pNew[1];
strcpy(pNew->dbbe.zDir, zName);
pNew->zDir = (char*)&pNew[1];
strcpy(pNew->zDir, zName);
pNew->write = writeFlag;
pNew->pOpen = 0;
return &pNew->dbbe;

View File

@ -28,7 +28,7 @@
**
** This file uses an in-memory hash table as the database backend.
**
** $Id: dbbemem.c,v 1.6 2001/01/13 14:34:06 drh Exp $
** $Id: dbbemem.c,v 1.7 2001/01/15 22:51:10 drh Exp $
*/
#include "sqliteInt.h"
#include <sys/stat.h>
@ -339,6 +339,7 @@ typedef struct MTable MTable;
struct MTable {
char *zName; /* Name of the table */
int delOnClose; /* Delete when closing */
int intKeyOnly; /* Use only integer keys on this table */
Array data; /* The data in this stable */
};
@ -391,9 +392,8 @@ static void deleteMTable(MTable *p){
*/
static void sqliteMemClose(Dbbe *pDbbe){
Dbbex *pBe = (Dbbex*)pDbbe;
MTable *pTble, *pNext;
int i;
ArrayElem *j, *k;
MTable *pTble;
ArrayElem *j;
for(j=ArrayFirst(&pBe->tables); j; j=ArrayNext(j)){
pTble = ArrayData(j);
deleteMTable(pTble);
@ -452,14 +452,13 @@ static int sqliteMemOpenCursor(
Dbbe *pDbbe, /* The database the table belongs to */
const char *zTable, /* The SQL name of the file to be opened */
int writeable, /* True to open for writing */
int intKeyOnly, /* True if only integer keys are used */
DbbeCursor **ppCursr /* Write the resulting table pointer here */
){
DbbeCursor *pCursr; /* The new table cursor */
char *zName; /* Canonical table name */
MTable *pTble; /* The underlying data file for this table */
int rc = SQLITE_OK; /* Return value */
int rw_mask; /* Permissions mask for opening a table */
int mode; /* Mode for opening a table */
Dbbex *pBe = (Dbbex*)pDbbe;
*ppCursr = 0;
@ -494,8 +493,10 @@ static int sqliteMemOpenCursor(
pTble->zName = 0;
pTble->delOnClose = 1;
}
pTble->intKeyOnly = intKeyOnly;
ArrayInit(&pTble->data);
}else{
assert( pTble->intKeyOnly==intKeyOnly );
sqliteFree(zName);
}
pCursr->pBe = pBe;
@ -513,7 +514,6 @@ static void sqliteMemDropTable(Dbbe *pDbbe, const char *zTable){
char *zName; /* Name of the table file */
Datum key, data;
MTable *pTble;
ArrayElem *i;
Dbbex *pBe = (Dbbex*)pDbbe;
zName = sqliteNameOfTable(zTable);
@ -565,6 +565,7 @@ static int sqliteMemFetch(DbbeCursor *pCursr, int nKey, char *pKey){
Datum key;
key.n = nKey;
key.p = pKey;
assert( nKey==4 || pCursr->pTble->intKeyOnly==0 );
pCursr->elem = ArrayFindElement(&pCursr->pTble->data, key);
return pCursr->elem!=0;
}
@ -665,7 +666,6 @@ static int sqliteMemNew(DbbeCursor *pCursr){
int iKey;
Datum key;
int go = 1;
int i;
while( go ){
iKey = sqliteRandomInteger();
@ -681,14 +681,18 @@ static int sqliteMemNew(DbbeCursor *pCursr){
** Write an entry into the table. Overwrite any prior entry with the
** same key.
*/
static int
sqliteMemPut(DbbeCursor *pCursr, int nKey,char *pKey, int nData, char *pData){
static int sqliteMemPut(
DbbeCursor *pCursr, /* Write new entry into this database table */
int nKey, char *pKey, /* The key of the new entry */
int nData, char *pData /* The data of the new entry */
){
Datum data, key;
data.n = nData;
data.p = sqliteMalloc( data.n );
memcpy(data.p, pData, data.n);
key.n = nKey;
key.p = pKey;
assert( nKey==4 || pCursr->pTble->intKeyOnly==0 );
data = ArrayInsert(&pCursr->pTble->data, key, data);
if( data.p ){
sqliteFree(data.p);
@ -712,6 +716,26 @@ static int sqliteMemDelete(DbbeCursor *pCursr, int nKey, char *pKey){
return SQLITE_OK;
}
/*
** Open a temporary file. The file is located in the current working
** directory.
*/
static int sqliteMemOpenTempFile(Dbbe *pDbbe, FILE **ppFile){
const char *zTemps[] = { "/usr/tmp", "/var/tmp", "/tmp", "/temp", 0};
const char *zDir;
int i;
struct stat statbuf;
for(i=0; zTemps[i]; i++){
zDir = zTemps[i];
if( stat("/usr/tmp", &statbuf)==0 && S_ISDIR(statbuf.st_mode)
&& access("/usr/tmp", W_OK|X_OK)==0 ){
break;
}
}
if( zDir==0 ) zDir = ".";
return sqliteDbbeOpenTempFile(zDir, pDbbe, ppFile);
}
/*
** This variable contains pointers to all of the access methods
** used to implement the MEMORY backend.
@ -735,7 +759,7 @@ static struct DbbeMethods memoryMethods = {
/* New */ sqliteMemNew,
/* Put */ sqliteMemPut,
/* Delete */ sqliteMemDelete,
/* OpenTempFile */ sqliteDbbeOpenTempFile,
/* OpenTempFile */ sqliteMemOpenTempFile,
/* CloseTempFile */ sqliteDbbeCloseTempFile
};
@ -763,6 +787,5 @@ Dbbe *sqliteMemOpen(
}
ArrayInit(&pNew->tables);
pNew->dbbe.x = &memoryMethods;
pNew->dbbe.zDir = 0;
return &pNew->dbbe;
}

View File

@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.6 2000/06/21 13:59:11 drh Exp $
** $Id: delete.c,v 1.7 2001/01/15 22:51:10 drh Exp $
*/
#include "sqliteInt.h"
@ -105,9 +105,9 @@ void sqliteDeleteFrom(
*/
base = pParse->nTab;
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Open, base+i, 1, pIdx->zName, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, base+i, 1, pIdx->zName, 0);
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);

View File

@ -24,7 +24,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions.
**
** $Id: expr.c,v 1.20 2000/11/28 20:47:18 drh Exp $
** $Id: expr.c,v 1.21 2001/01/15 22:51:10 drh Exp $
*/
#include "sqliteInt.h"
@ -216,7 +216,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
** table. The cursor number of the temporary table has already
** been put in iTable by sqliteExprResolveInSelect().
*/
sqliteVdbeAddOp(v, OP_Open, pExpr->iTable, 1, 0, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, pExpr->iTable, 1, 0, 0);
if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) );
}else if( pExpr->pList ){
/* Case 2: expr IN (exprlist)

View File

@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements.
**
** $Id: insert.c,v 1.11 2000/06/21 13:59:12 drh Exp $
** $Id: insert.c,v 1.12 2001/01/15 22:51:11 drh Exp $
*/
#include "sqliteInt.h"
@ -92,7 +92,7 @@ void sqliteInsert(
if( pSelect ){
int rc;
srcTab = pParse->nTab++;
sqliteVdbeAddOp(v, OP_Open, srcTab, 1, 0, 0);
sqliteVdbeAddOp(v, OP_OpenTbl, srcTab, 1, 0, 0);
rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab);
if( rc ) goto insert_cleanup;
assert( pSelect->pEList );
@ -156,9 +156,9 @@ void sqliteInsert(
** all indices of that table.
*/
base = pParse->nTab;
sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
sqliteVdbeAddOp(v, OP_Open, idx+base, 1, pIdx->zName, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, idx+base, 1, pIdx->zName, 0);
}
/* If the data source is a SELECT statement, then we have to create

View File

@ -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 <unistd.h>
/*
** This is the callback routine for the code that initializes the
@ -123,7 +124,7 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
** database scheme.
*/
static VdbeOp initProg[] = {
{ OP_Open, 0, 0, MASTER_NAME},
{ OP_OpenTbl, 0, 0, MASTER_NAME},
{ OP_Next, 0, 9, 0}, /* 1 */
{ OP_Field, 0, 0, 0},
{ OP_String, 0, 0, "meta"},
@ -321,7 +322,6 @@ int sqlite_exec(
char **pzErrMsg /* Write error messages here */
){
Parse sParse;
int rc;
if( pzErrMsg ) *pzErrMsg = 0;
if( (db->flags & SQLITE_Initialized)==0 ){

701
src/pg.c Normal file
View File

@ -0,0 +1,701 @@
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA 02111-1307, USA.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: pg.c,v 1.1 2001/01/15 22:51:11 drh Exp $
*/
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "sqliteInt.h"
#include "pg.h"
/*
** Uncomment the following for a debug trace
*/
#if 1
# define TRACE(X) printf X; fflush(stdout);
#endif
#ifndef SQLITE_IOERR
# define SQLITE_IOERR SQLITE_ERROR
#endif
/*
** Hash table sizes
*/
#define J_HASH_SIZE 127 /* Size of the journal page hash table */
#define PG_HASH_SIZE 349 /* Size of the database page hash table */
/*
** Forward declaration of structure
*/
typedef struct Pghdr Pghdr;
/*
** All information about a single paging file is contained in an
** instance of the following structure.
*/
struct Pgr {
int fdMain; /* The main database file */
char *zMain; /* Name of the database file */
int fdJournal; /* The journal file */
char *zJournal; /* Name of the journal file */
int nMemPg; /* Number of memory-resident pages */
int nJPg; /* Number of pages in the journal */
int nDbPg; /* Number of pages in the database */
int nRefPg; /* Number of pages currently in use */
Pghdr *pLru, *pMru; /* Least and most recently used mem-page */
Pghdr *pJidx; /* List of journal index pages */
Pghdr *pAll; /* All pages, except journal index pages */
u32 aJHash[J_HASH_SIZE]; /* Journal page hash table */
Pghdr *aPgHash[PG_HASH_SIZE]; /* Mem-page hash table */
};
/*
** Each memory-resident page of the paging file has a header which
** is an instance of the following structure.
*/
struct Pghdr {
Pgr *p; /* Pointer back to the Pgr structure */
int nRef; /* Number of references to this page */
int isDirty; /* TRUE if needs to be written to disk */
u32 dbpgno; /* Page number in the database file */
u32 jpgno; /* Page number in the journal file */
Pghdr *pNx; /* Next page on a list of them all */
Pghdr *pLru; /* Less recently used pages */
Pghdr *pMru; /* More recently used pages */
Pghdr *pNxHash; /* Next with same dbpgno hash */
Pghdr *pPvHash; /* Previous with the same dbpgno hash */
};
/*
** For a memory-resident page, the page data comes immediately after
** the page header. The following macros can be used to change a
** pointer to a page header into a pointer to the data, or vice
** versa.
*/
#define PG_TO_DATA(X) ((void*)&(X)[1])
#define DATA_TO_PG(X) (&((Pghdr*)(X))[-1])
/*
** The number of in-memory pages that we accumulate before trying
** to reuse older pages when new ones are requested.
*/
#define MX_MEM_PAGE 100
/*
** The number of journal data pages that come between consecutive
** journal index pages.
*/
#define N_J_DATAPAGE (SQLITE_PAGE_SIZE/(2*sizeof(u32)))
/*
** An index page in the journal consists of an array of N_J_DATAPAGE
** of the following structures. There is one instance of the following
** structure for each of the N_J_DATAPAGE data pages that follow the
** index.
**
** Let the journal page number that a JidxEntry describes be J. Then
** the JidxEntry.dbpgno field is the page of the database file that
** corresponds to the J page in the journal. The JidxEntry.next_jpgno
** field hold the number of another journal page that contains
** a database file page with the same hash as JidxEntry.dbpgno.
**
** All information is written to the journal index in big-endian
** notation.
*/
typedef struct JidxEntry JidxEntry;
struct JidxEntry {
char dbpgno[sizeof(u32)]; /* Database page number for this entry */
char next_jpgno[sizeof(u32)]; /* Next entry with same hash on dbpgno */
};
/*
** Read a page from a file into memory. Return SQLITE_OK if successful.
** The "pgno" parameter tells where in the file to read the page.
** The first page is 1. Files do not contain a page 0 since a page
** number of 0 is used to indicate "no such page".
*/
static int sqlitePgRead(int fd, char *zBuf, u32 pgno){
int got = 0;
int amt;
assert( pgno>0 );
assert( fd>=0 );
lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE);
while( got<SQLITE_PAGE_SIZE ){
amt = read(fd, &zBuf[got], SQLITE_PAGE_SIZE - got);
if( amt<=0 ){
memset(&zBuf[got], 0, SQLITE_PAGE_SIZE - got);
return amt==0 ? SQLITE_OK : SQLITE_IOERR;
}
got += amt;
}
return SQLITE_OK;
}
/*
** Read a page from a file into memory. Return SQLITE_OK if successful.
** The "pgno" parameter tells where in the file to write the page.
** The first page is 1. Files do not contain a page 0 since a page
** number of 0 is used to indicate "no such page".
*/
static int sqlitePgWrite(int fd, char *zBuf, u32 pgno){
int done = 0;
int amt;
assert( pgno>0 );
assert( fd>=0 );
lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE);
while( done<SQLITE_PAGE_SIZE ){
amt = write(fd, &zBuf[done], SQLITE_PAGE_SIZE - done);
if( amt<=0 ) return SQLITE_IOERR;
done += amt;
}
return SQLITE_OK;
}
/*
** Turn four bytes into an integer. The first byte is always the
** most significant 8 bits.
*/
static u32 sqlitePgGetInt(const char *p){
return ((p[0]&0xff)<<24) | ((p[1]&0xff)<<16) | ((p[2]&0xff)<<8) | (p[3]&0xff);
}
/*
** Turn an integer into 4 bytes. The first byte is always the
** most significant 8 bits.
*/
static void sqlitePgPutInt(u32 v, char *p){
p[3] = v & 0xff;
v >>= 8;
p[2] = v & 0xff;
v >>= 8;
p[1] = v & 0xff;
v >>= 8;
p[0] = v & 0xff;
}
/*
** Check the hash table for an in-memory page. Return a pointer to
** the page header if found. Return NULL if the page is not in memory.
*/
static Pghdr *sqlitePgFind(Pgr *p, u32 pgno){
int h;
Pghdr *pPg;
if( pgno==0 ) return 0;
h = pgno % PG_HASH_SIZE;
for(pPg = p->aPgHash[h]; pPg; pPg=pPg->pNxHash){
if( pPg->dbpgno==pgno ) return pPg;
}
TRACE(("PG: data page %u is %#x\n", pgno, (u32)pPg));
return 0;
}
/*
** Locate and return an index page from the journal.
**
** The first page of a journal is the primary index. Additional
** index pages are called secondary indices. Index pages appear
** in the journal as often as needed. (If SQLITE_PAGE_SIZE==1024,
** then there are 1024/sizeof(int)*2 = 128 database between each
** pair of index pages.) Journal index pages are not hashed and
** do no appear on the Pgr.pAll list. Index pages are on the
** Pgr.pJidx list only. Index pages have Pghdr.dbpgno==0.
**
** If the requested index page is not already in memory, then a
** new memory page is created to hold the index.
**
** This routine will return a NULL pointer if we run out of memory.
*/
static Pghdr *sqlitePgFindJidx(Pgr *p, u32 pgno){
Pghdr *pPg;
assert( pgno % (N_J_DATAPAGE+1) == 1 );
for(pPg=p->pJidx; pPg; pPg=pPg->pNx){
if( pPg->jpgno==pgno ){
TRACE(("PG: found j-index %u at %#x\n", pgno, (u32)pPg));
return pPg;
}
}
pPg = sqliteMalloc( sizeof(Pghdr)+SQLITE_PAGE_SIZE );
if( pPg==0 ) return 0;
pPg->jpgno = pgno;
pPg->pNx = p->pJidx;
p->pJidx = pPg;
sqlitePgRead(p->fdJournal, PG_TO_DATA(pPg), pgno);
TRACE(("PG: create j-index %u at %#x\n", pgno, (u32)pPg));
return pPg;
}
/*
** Look in the journal to see if the given database page is stored
** in the journal. If it is, return its journal page number. If
** not, return 0.
*/
static u32 sqlitePgJournalPageNumber(Pgr *p, u32 dbpgno){
u32 jpgno;
assert( dbpgno>0 );
jpgno = p->aJHash[dbpgno % J_HASH_SIZE];
while( jpgno!=0 ){
int idx_num; /* Which journal index describes page jpgno */
int ipgno; /* Page number for the journal index */
int idx_slot; /* Which entry in index idx_num describes jpgno */
Pghdr *pIdxPg; /* The index page for jpgno */
JidxEntry *aIdx; /* The data for the index page */
idx_num = (jpgno - 1)/(N_J_DATAPAGE + 1);
idx_slot = (jpgno - 1) % (N_J_DATAPAGE + 1) - 2;
ipgno = idx_num * (N_J_DATAPAGE + 1) + 1;
if( ipgno>p->nJPg ){
jpgno = 0;
break;
}
pIdxPg = sqlitePgFindJidx(p, ipgno);
assert( pIdxPg!=0 );
aIdx = PG_TO_DATA(pIdxPg);
if( dbpgno==sqlitePgGetInt(aIdx[idx_slot].dbpgno) ){
break;
}
jpgno = sqlitePgGetInt(aIdx[idx_slot].next_jpgno);
}
return jpgno;
}
/*
** Make a page not dirty by writing it to the journal.
*/
static int sqlitePgMakeClean(Pghdr *pPg){
Pgr *p = pPg->p;
int rc;
assert( pPg->isDirty );
assert( p->fdJournal>=0 );
if( pPg->jpgno==0 ){
int jpgno; /* A newly allocate page in the journal */
int idx_num; /* Which journal index describes page jpgno */
int idx_slot; /* Which entry in index idx_num describes jpgno */
Pghdr *pIdxPg; /* The index page for jpgno */
JidxEntry *aIdx; /* The data for the index page */
int h; /* The hash value for pPg->dbpgno */
jpgno = p->nJPg + 1;
if( jpgno % (N_J_DATAPAGE + 1) == 1 ){
jpgno++;
}
idx_num = (jpgno - 1)/(N_J_DATAPAGE + 1);
idx_slot = (jpgno - 1) % (N_J_DATAPAGE + 1) - 2;
pIdxPg = sqlitePgFindJidx(p, idx_num * (N_J_DATAPAGE + 1) + 1);
assert( pIdxPg!=0 );
aIdx = PG_TO_DATA(pIdxPg);
sqlitePgPutInt(pPg->dbpgno, aIdx[idx_slot].dbpgno);
h = pPg->dbpgno % J_HASH_SIZE;
sqlitePgPutInt(p->aJHash[h], aIdx[idx_slot].next_jpgno);
p->aJHash[h] = jpgno;
p->nJPg = jpgno;
pPg->jpgno = jpgno;
TRACE(("PG: assign d-page %u to j-page %u\n", jpgno, pPg->dbpgno));
}
rc = sqlitePgWrite(p->fdJournal, PG_TO_DATA(pPg), pPg->jpgno);
if( rc==SQLITE_OK ){
pPg->isDirty = 0;
}
return rc;
}
/*
** Find the number of pages in the given file by measuring the size
** of the file. Return 0 if there is any problem.
*/
static int sqlitePgPageCount(int fd){
struct stat statbuf;
if( fstat(fd, &statbuf)!=0 ) return 0;
return statbuf.st_size/SQLITE_PAGE_SIZE;
}
/*
** This routine reads the journal and transfers pages from the
** journal to the database.
*/
static int sqlitePgJournalPlayback(Pgr *p){
Pghdr *pPg;
JidxEntry *aIdx;
int nJpg;
int jpgno = 1;
int i;
int dbpgno;
int rc;
char idx[SQLITE_PAGE_SIZE];
char pgbuf[SQLITE_PAGE_SIZE];
assert( p->fdJournal>=0 );
nJpg = sqlitePgPageCount(p->fdJournal);
while( jpgno<=nJpg ){
if( !sqlitePgRead(p->fdJournal, idx, jpgno++) ) break;
aIdx = (JidxEntry*)idx;
for(i=0; i<N_J_DATAPAGE; i++){
dbpgno = sqlitePgGetInt(&idx[i]);
if( dbpgno==0 ){
jpgno = nJpg+1;
break;
}
pPg = sqlitePgFind(p, dbpgno);
if( pPg ){
rc = sqlitePgWrite(p->fdMain, PG_TO_DATA(pPg), dbpgno);
TRACE(("PG: commit j-page %u to d-page %u from memory\n",jpgno,dbpgno));
}else{
rc = sqlitePgRead(p->fdJournal, pgbuf, jpgno);
if( rc!=SQLITE_OK ){
return rc;
}
rc = sqlitePgWrite(p->fdMain, pgbuf, dbpgno);
TRACE(("PG: commit j-page %u to d-page %u from disk\n",jpgno,dbpgno));
}
jpgno++;
if( rc!=SQLITE_OK ){
return rc;
}
}
}
TRACE(("PG: commit complete. deleting the journal.\n"));
fsync(p->fdMain);
close(p->fdJournal);
p->fdJournal = -1;
unlink(p->zJournal);
for(pPg=p->pAll; pPg; pPg=pPg->pNx){
pPg->isDirty = 0;
pPg->jpgno = 0;
}
while( (pPg = p->pJidx)!=0 ){
p->pAll = pPg->pNx;
sqliteFree(pPg);
}
return SQLITE_OK;
}
/*
** Remove the given page from the LRU list.
*/
static void sqlitePgUnlinkLru(Pghdr *pPg){
Pgr *p = pPg->p;
if( pPg->pLru ){
pPg->pLru->pMru = pPg->pLru;
}
if( pPg->pMru ){
pPg->pMru->pLru = pPg->pMru;
}
if( p->pLru==pPg ){
p->pLru = pPg->pLru;
}
if( p->pMru==pPg ){
p->pMru = pPg->pMru;
}
pPg->pLru = pPg->pMru = 0;
}
/*
** Open the database file and make *ppPgr pointer to a structure describing it.
** Return SQLITE_OK on success or an error code if there is a failure.
**
** If there was an unfinished commit, complete it before returnning.
*/
int sqlitePgOpen(const char *zFilename, Pgr **ppPgr){
Pgr *p;
int n;
n = strlen(zFilename);
p = sqliteMalloc( sizeof(*p) + n*2 + 4 );
if( p==0 ){
*ppPgr = 0;
return SQLITE_NOMEM;
}
p->zMain = (char*)&p[1];
strcpy(p->zMain, zFilename);
p->zJournal = &p->zMain[n+1];
strcpy(p->zJournal, p->zMain);
p->zJournal[n] = '~';
p->zJournal[n+1] = 0;
p->fdJournal = -1;
p->fdMain = open(p->zMain, O_CREAT|O_RDWR, 0600);
if( p->fdMain<0 ){
*ppPgr = 0;
sqliteFree(p);
return SQLITE_PERM;
}
p->nDbPg = sqlitePgPageCount(p->fdMain);
if( access(p->zJournal, R_OK)==0 ){
sqlitePgJournalPlayback(p);
}
*ppPgr = p;
return SQLITE_OK;
}
/*
** Close the database file. Any outstanding transactions are abandoned.
*/
int sqlitePgClose(Pgr *p){
Pghdr *pPg;
if( p->fdMain ) close(p->fdMain);
if( p->fdJournal ) close(p->fdJournal);
unlink(p->zJournal);
while( (pPg = p->pAll)!=0 ){
p->pAll = pPg->pNx;
sqliteFree(pPg);
}
while( (pPg = p->pJidx)!=0 ){
p->pAll = pPg->pNx;
sqliteFree(pPg);
}
sqliteFree(p);
return SQLITE_OK;
}
/*
** Begin a new transaction. Return SQLITE_OK on success or an error
** code if something goes wrong.
*/
int sqlitePgBeginTransaction(Pgr *p){
assert( p->fdJournal<0 );
if( p->nRefPg>0 ){
/* release the read lock */
}
/* write lock the database */
p->fdJournal = open(p->zJournal, O_CREAT|O_EXCL|O_RDWR, 0600);
if( p->fdJournal<0 ){
return SQLITE_PERM;
}
p->nJPg = 0;
TRACE(("PG: begin transaction\n"));
return SQLITE_OK;
}
/*
** Commit the current transaction. Return SQLITE_OK or an error code.
*/
int sqlitePgCommit(Pgr *p){
Pghdr *pPrimaryIdx = 0;
Pghdr *pPg;
int rc;
for(pPg=p->pAll; pPg; pPg=pPg->pNx){
if( pPg->isDirty ){
rc = sqlitePgMakeClean(pPg);
if( rc!=SQLITE_OK ){
return rc;
}
}
}
for(pPg=p->pJidx; pPg; pPg=pPg->pNx){
if( pPg->jpgno==1 ){
pPrimaryIdx = pPg;
}else{
TRACE(("PG: writing j-index %u\n", pPg->jpgno));
rc = sqlitePgMakeClean(pPg);
if( rc!=SQLITE_OK ){
return rc;
}
}
}
assert( pPrimaryIdx!=0 );
fsync(p->fdJournal);
TRACE(("PG: writing j-index %u\n", pPrimaryIdx->jpgno));
rc = sqlitePgMakeClean(pPrimaryIdx);
if( rc!=SQLITE_OK ){
return rc;
}
fsync(p->fdJournal);
rc = sqlitePgJournalPlayback(p);
if( rc!=SQLITE_OK ){
return rc;
}
/* remove write lock from database */
if( p->nRefPg>0 ){
/* acquire read lock on database */
}
return SQLITE_OK;
}
/*
** Abandon the current transaction.
*/
int sqlitePgRollback(Pgr *p){
Pghdr *pPg;
TRACE(("PG: begin rollback\n"));
for(pPg=p->pAll; pPg; pPg=pPg->pNx){
if( pPg->isDirty || pPg->jpgno!=0 ){
pPg->isDirty = 0;
pPg->jpgno = 0;
if( pPg->nRef>0 ){
TRACE(("PG: reloading d-page %u\n", pPg->dbpgno));
sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
}else{
sqlitePgUnlinkLru(pPg);
}
}
}
close(p->fdJournal);
p->fdJournal = -1;
unlink(p->zJournal);
while( (pPg = p->pJidx)!=0 ){
p->pAll = pPg->pNx;
sqliteFree(pPg);
}
p->nDbPg = sqlitePgPageCount(p->fdMain);
/* remove write lock from database */
if( p->nRefPg>0 ){
/* acquire read lock on database */
}
return SQLITE_OK;
}
/*
** Get a page from the database. Return a pointer to the data for that
** page.
**
** A NULL pointer will be returned if we run out of memory.
*/
int sqlitePgGet(Pgr *p, u32 pgno, void **ppData){
Pghdr *pPg;
int h;
pPg = sqlitePgFind(p, pgno);
if( pPg ){
pPg->nRef++;
if( pPg->nRef==1 ){
sqlitePgUnlinkLru(pPg);
TRACE(("PG: d-page %u pulled from cache\n", pgno));
}
p->nRefPg++;
if( p->nRefPg==1 ){
/* Acquire a read lock */
}
*ppData = PG_TO_DATA(pPg);
return SQLITE_OK;
}
if( p->nMemPg<MX_MEM_PAGE || p->pLru==0 ){
pPg = sqliteMalloc( sizeof(Pghdr) + SQLITE_PAGE_SIZE );
if( pPg==0 ) return SQLITE_NOMEM;
p->nMemPg++;
pPg->pNx = p->pAll;
p->pAll = pPg;
pPg->p = p;
TRACE(("PG: new page %d created.\n", p->nMemPg));
}else{
int rc;
pPg = p->pLru;
if( pPg->isDirty ){
rc = sqlitePgMakeClean(pPg);
if( rc!=SQLITE_OK ) return rc;
}
sqlitePgUnlinkLru(pPg);
h = pPg->dbpgno % PG_HASH_SIZE;
if( pPg->pPvHash ){
pPg->pPvHash->pNxHash = pPg->pNxHash;
}else{
assert( p->aPgHash[h]==pPg );
p->aPgHash[h] = pPg->pNxHash;
}
if( pPg->pNxHash ){
pPg->pNxHash->pPvHash = pPg->pPvHash;
}
TRACE(("PG: recycling d-page %u to d-page %u\n", pPg->dbpgno, pgno));
}
pPg->dbpgno = pgno;
if( pgno>p->nDbPg ){
p->nDbPg = pgno;
}
h = pgno % PG_HASH_SIZE;
pPg->pPvHash = 0;
pPg->pNxHash = p->aPgHash[h];
if( pPg->pNxHash ){
pPg->pNxHash->pPvHash = pPg;
}
p->aPgHash[h] = pPg;
pPg->jpgno = sqlitePgJournalPageNumber(p, pgno);
if( pPg->jpgno!=0 ){
TRACE(("PG: reading d-page %u content from j-page %u\n", pgno, pPg->jpgno));
sqlitePgRead(p->fdJournal, PG_TO_DATA(pPg), pPg->jpgno);
}else{
TRACE(("PG: reading d-page %u from database\n", pgno));
sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
}
pPg->isDirty = 0;
pPg->nRef = 1;
p->nRefPg++;
if( p->nRefPg==1 ){
/* Acquire a read lock */
}
*ppData = PG_TO_DATA(pPg);
return SQLITE_OK;
}
/*
** Release a reference to a database data page.
*/
int sqlitePgUnref(void *pData){
Pghdr *pPg = DATA_TO_PG(pData);
pPg->nRef--;
assert( pPg->nRef>=0 );
if( pPg->nRef==0 ){
Pgr *p = pPg->p;
pPg->pMru = 0;
pPg->pLru = p->pLru;
p->pLru = pPg;
TRACE(("PG: d-page %u is unused\n", pPg->dbpgno));
p->nRefPg--;
if( p->nRefPg==0 ){
/* Release the read lock */
}
}
return SQLITE_OK;
}
/*
** The database page in the argument has been modified. Write it back
** to the database file on the next commit.
*/
int sqlitePgTouch(void *pD){
Pghdr *pPg = DATA_TO_PG(pD);
assert( pPg->p->fdJournal>=0 );
if( pPg->isDirty==0 ){
pPg->isDirty = 1;
TRACE(("PG: d-page %u is dirty\n", pPg->dbpgno));
}
return SQLITE_OK;
}
/*
** Return the number of the first unused page at the end of the
** database file.
*/
int sqlitePgAlloc(Pgr *p, int *pPgno){
*pPgno = p->nDbPg;
return SQLITE_OK;
}

43
src/pg.h Normal file
View File

@ -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*);

View File

@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements.
**
** $Id: select.c,v 1.27 2000/10/16 22:06:42 drh Exp $
** $Id: select.c,v 1.28 2001/01/15 22:51:11 drh Exp $
*/
#include "sqliteInt.h"
@ -489,9 +489,11 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
&& matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){
return 1;
}
sqliteVdbeAddOp(v, OP_Open, unionTab, 1, 0, 0);
if( p->op!=TK_ALL ){
sqliteVdbeAddOp(v, OP_OpenIdx, unionTab, 1, 0, 0);
sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1, 0, 0);
}else{
sqliteVdbeAddOp(v, OP_OpenTbl, unionTab, 1, 0, 0);
}
}
@ -549,7 +551,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
return 1;
}
sqliteVdbeAddOp(v, OP_Open, tab1, 1, 0, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, tab1, 1, 0, 0);
sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1, 0, 0);
/* Code the SELECTs to our left into temporary table "tab1".
@ -559,7 +561,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
/* Code the current SELECT into temporary table "tab2"
*/
sqliteVdbeAddOp(v, OP_Open, tab2, 1, 0, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, tab2, 1, 0, 0);
sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1, 0, 0);
p->pPrior = 0;
rc = sqliteSelect(pParse, p, SRT_Union, tab2);
@ -852,7 +854,7 @@ int sqliteSelect(
/* Begin the database scan
*/
if( isDistinct ){
sqliteVdbeAddOp(v, OP_Open, distinct, 1, 0, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, distinct, 1, 0, 0);
}
pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
if( pWInfo==0 ) return 1;

View File

@ -24,7 +24,7 @@
** This header file defines the interface that the sqlite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.7 2000/11/28 20:47:20 drh Exp $
** @(#) $Id: sqlite.h.in,v 1.8 2001/01/15 22:51:11 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
@ -138,6 +138,7 @@ int sqlite_exec(
#define SQLITE_NOMEM 6 /* A malloc() failed */
#define SQLITE_READONLY 7 /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 8 /* Operation terminated by sqlite_interrupt() */
#define SQLITE_IOERR 9 /* Disk full or other I/O error */
/* This function causes any pending database operation to abort and
** return at its earliest opportunity. This routine is typically

View File

@ -23,7 +23,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.34 2001/01/13 14:34:07 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.35 2001/01/15 22:51:11 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
@ -422,5 +422,7 @@ Vdbe *sqliteGetVdbe(Parse*);
int sqliteRandomByte(void);
int sqliteRandomInteger(void);
void sqliteRandomName(char*,char*);
int sqliteDbbeOpenTempFile(Dbbe*, FILE**);
int sqliteDbbeOpenTempFile(const char*, Dbbe*, FILE**);
void sqliteDbbeCloseTempFile(Dbbe*, FILE*);
void sqliteDbbeCloseAllTempFiles(Dbbe*);
char *sqliteDbbeNameToFile(const char*,const char*,const char*);

View File

@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.8 2000/06/21 13:59:12 drh Exp $
** $Id: update.c,v 1.9 2001/01/15 22:51:11 drh Exp $
*/
#include "sqliteInt.h"
@ -159,9 +159,9 @@ void sqliteUpdate(
*/
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
base = pParse->nTab;
sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
for(i=0; i<nIdx; i++){
sqliteVdbeAddOp(v, OP_Open, base+i+1, 1, apIdx[i]->zName, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, base+i+1, 1, apIdx[i]->zName, 0);
}
/* Loop over every record that needs updating. We have to load

View File

@ -41,7 +41,7 @@
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.50 2001/01/13 14:34:07 drh Exp $
** $Id: vdbe.c,v 1.51 2001/01/15 22:51:12 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>
@ -786,29 +786,29 @@ void sqliteVdbeDelete(Vdbe *p){
** this array, then copy and paste it into this file, if you want.
*/
static char *zOpName[] = { 0,
"Open", "Close", "Fetch", "Fcnt",
"New", "Put", "Distinct", "Found",
"NotFound", "Delete", "Field", "KeyAsData",
"Key", "Rewind", "Next", "Destroy",
"Reorganize", "ResetIdx", "NextIdx", "PutIdx",
"DeleteIdx", "MemLoad", "MemStore", "ListOpen",
"ListWrite", "ListRewind", "ListRead", "ListClose",
"SortOpen", "SortPut", "SortMakeRec", "SortMakeKey",
"Sort", "SortNext", "SortKey", "SortCallback",
"SortClose", "FileOpen", "FileRead", "FileField",
"FileClose", "AggReset", "AggFocus", "AggIncr",
"AggNext", "AggSet", "AggGet", "SetInsert",
"SetFound", "SetNotFound", "SetClear", "MakeRecord",
"MakeKey", "Goto", "If", "Halt",
"ColumnCount", "ColumnName", "Callback", "Integer",
"String", "Null", "Pop", "Dup",
"Pull", "Add", "AddImm", "Subtract",
"Multiply", "Divide", "Min", "Max",
"Like", "Glob", "Eq", "Ne",
"Lt", "Le", "Gt", "Ge",
"IsNull", "NotNull", "Negative", "And",
"Or", "Not", "Concat", "Noop",
"Strlen", "Substr",
"OpenIdx", "OpenTbl", "Close", "Fetch",
"Fcnt", "New", "Put", "Distinct",
"Found", "NotFound", "Delete", "Field",
"KeyAsData", "Key", "Rewind", "Next",
"Destroy", "Reorganize", "ResetIdx", "NextIdx",
"PutIdx", "DeleteIdx", "MemLoad", "MemStore",
"ListOpen", "ListWrite", "ListRewind", "ListRead",
"ListClose", "SortOpen", "SortPut", "SortMakeRec",
"SortMakeKey", "Sort", "SortNext", "SortKey",
"SortCallback", "SortClose", "FileOpen", "FileRead",
"FileField", "FileClose", "AggReset", "AggFocus",
"AggIncr", "AggNext", "AggSet", "AggGet",
"SetInsert", "SetFound", "SetNotFound", "SetClear",
"MakeRecord", "MakeKey", "Goto", "If",
"Halt", "ColumnCount", "ColumnName", "Callback",
"Integer", "String", "Null", "Pop",
"Dup", "Pull", "Add", "AddImm",
"Subtract", "Multiply", "Divide", "Min",
"Max", "Like", "Glob", "Eq",
"Ne", "Lt", "Le", "Gt",
"Ge", "IsNull", "NotNull", "Negative",
"And", "Or", "Not", "Concat",
"Noop", "Strlen", "Substr",
};
/*
@ -1782,7 +1782,7 @@ int sqliteVdbeExec(
break;
}
/* Opcode: Open P1 P2 P3
/* Opcode: OpenIdx P1 P2 P3
**
** Open a new cursor for the database file named P3. Give the
** cursor an identifier P1. The P1 values need not be
@ -1798,8 +1798,28 @@ int sqliteVdbeExec(
** If P3 is null or an empty string, a temporary database file
** is created. This temporary database file is automatically
** deleted when the cursor is closed.
**
** The database file opened must be able to map arbitrary length
** keys into arbitrary data. A similar opcode, OpenTbl, opens
** a database file that maps integer keys into arbitrary length
** data. This opcode opens database files used as
** SQL indices and OpenTbl opens database files used for SQL
** tables.
*/
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 ){

View File

@ -27,7 +27,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.14 2000/10/16 22:06:43 drh Exp $
** $Id: vdbe.h,v 1.15 2001/01/15 22:51:12 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@ -71,112 +71,113 @@ typedef struct VdbeOp VdbeOp;
** The source tree contains an AWK script named renumberOps.awk that
** can be used to renumber these opcodes when new opcodes are inserted.
*/
#define OP_Open 1
#define OP_Close 2
#define OP_Fetch 3
#define OP_Fcnt 4
#define OP_New 5
#define OP_Put 6
#define OP_Distinct 7
#define OP_Found 8
#define OP_NotFound 9
#define OP_Delete 10
#define OP_Field 11
#define OP_KeyAsData 12
#define OP_Key 13
#define OP_Rewind 14
#define OP_Next 15
#define OP_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

View File

@ -25,7 +25,7 @@
** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
** $Id: where.c,v 1.9 2000/08/22 18:29:34 drh Exp $
** $Id: where.c,v 1.10 2001/01/15 22:51:12 drh Exp $
*/
#include "sqliteInt.h"
@ -271,9 +271,9 @@ WhereInfo *sqliteWhereBegin(
/* Open all tables in the pTabList and all indices in aIdx[].
*/
for(i=0; i<pTabList->nId; i++){
sqliteVdbeAddOp(v, OP_Open, base+i, 0, pTabList->a[i].pTab->zName, 0);
sqliteVdbeAddOp(v, OP_OpenTbl, base+i, 0, pTabList->a[i].pTab->zName, 0);
if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
sqliteVdbeAddOp(v, OP_Open, base+pTabList->nId+i, 0, aIdx[i]->zName, 0);
sqliteVdbeAddOp(v, OP_OpenIdx, base+pTabList->nId+i, 0, aIdx[i]->zName,0);
}
}
memcpy(pWInfo->aIdx, aIdx, sizeof(aIdx));