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:
18
src/build.c
18
src/build.c
@ -33,7 +33,7 @@
|
||||
** COPY
|
||||
** VACUUM
|
||||
**
|
||||
** $Id: build.c,v 1.24 2000/10/16 22:06:42 drh Exp $
|
||||
** $Id: build.c,v 1.25 2001/01/15 22:51:09 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -341,7 +341,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
|
||||
*/
|
||||
if( !pParse->initFlag ){
|
||||
static VdbeOp addTable[] = {
|
||||
{ OP_Open, 0, 1, MASTER_NAME },
|
||||
{ OP_OpenTbl, 0, 1, MASTER_NAME },
|
||||
{ OP_New, 0, 0, 0},
|
||||
{ OP_String, 0, 0, "table" },
|
||||
{ OP_String, 0, 0, 0}, /* 3 */
|
||||
@ -416,7 +416,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
static VdbeOp dropTable[] = {
|
||||
{ OP_Open, 0, 1, MASTER_NAME },
|
||||
{ OP_OpenTbl, 0, 1, MASTER_NAME },
|
||||
{ OP_ListOpen, 0, 0, 0},
|
||||
{ OP_String, 0, 0, 0}, /* 2 */
|
||||
{ OP_Next, 0, ADDR(10), 0}, /* 3 */
|
||||
@ -593,7 +593,7 @@ void sqliteCreateIndex(
|
||||
*/
|
||||
if( pParse->initFlag==0 ){
|
||||
static VdbeOp addTable[] = {
|
||||
{ OP_Open, 2, 1, MASTER_NAME},
|
||||
{ OP_OpenTbl, 2, 1, MASTER_NAME},
|
||||
{ OP_New, 2, 0, 0},
|
||||
{ OP_String, 0, 0, "index"},
|
||||
{ OP_String, 0, 0, 0}, /* 3 */
|
||||
@ -610,8 +610,8 @@ void sqliteCreateIndex(
|
||||
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto exit_create_index;
|
||||
sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_Open, 1, 1, pIndex->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenTbl, 0, 0, pTab->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenIdx, 1, 1, pIndex->zName, 0);
|
||||
if( pStart && pEnd ){
|
||||
int base;
|
||||
n = (int)pEnd->z - (int)pStart->z + 1;
|
||||
@ -670,7 +670,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
static VdbeOp dropIndex[] = {
|
||||
{ OP_Open, 0, 1, MASTER_NAME},
|
||||
{ OP_OpenTbl, 0, 1, MASTER_NAME},
|
||||
{ OP_ListOpen, 0, 0, 0},
|
||||
{ OP_String, 0, 0, 0}, /* 2 */
|
||||
{ OP_Next, 0, ADDR(9), 0}, /* 3 */
|
||||
@ -843,9 +843,9 @@ void sqliteCopy(
|
||||
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
|
||||
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
|
||||
sqliteVdbeDequoteP3(v, addr);
|
||||
sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenTbl, 0, 1, pTab->zName, 0);
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
sqliteVdbeAddOp(v, OP_Open, i, 1, pIdx->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenIdx, i, 1, pIdx->zName, 0);
|
||||
}
|
||||
end = sqliteVdbeMakeLabel(v);
|
||||
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);
|
||||
|
53
src/db.h
Normal file
53
src/db.h
Normal 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*);
|
61
src/dbbe.c
61
src/dbbe.c
@ -30,9 +30,10 @@
|
||||
** relatively simple to convert to a different database such
|
||||
** as NDBM, SDBM, or BerkeleyDB.
|
||||
**
|
||||
** $Id: dbbe.c,v 1.22 2001/01/13 14:34:06 drh Exp $
|
||||
** $Id: dbbe.c,v 1.23 2001/01/15 22:51:10 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <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;
|
||||
}
|
||||
|
11
src/dbbe.h
11
src/dbbe.h
@ -28,7 +28,7 @@
|
||||
** This library was originally designed to support the following
|
||||
** backends: GDBM, NDBM, SDBM, Berkeley DB.
|
||||
**
|
||||
** $Id: dbbe.h,v 1.9 2001/01/13 14:34:06 drh Exp $
|
||||
** $Id: dbbe.h,v 1.10 2001/01/15 22:51:10 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_DBBE_H_
|
||||
#define _SQLITE_DBBE_H_
|
||||
@ -81,10 +81,16 @@ struct DbbeMethods {
|
||||
** an appropriate path and extension to the filename to locate the
|
||||
** actual file.
|
||||
**
|
||||
** The keyType parameter is TRUE if this table will only be accessed
|
||||
** using integer keys. This parameter allows the database backend to
|
||||
** use a faster algorithm for the special case of integer keys, if it
|
||||
** wants to.
|
||||
**
|
||||
** If zName is 0 or "", then a temporary file is created that
|
||||
** will be deleted when closed.
|
||||
*/
|
||||
int (*OpenCursor)(Dbbe*, const char *zName, int writeable, DbbeCursor**);
|
||||
int (*OpenCursor)(Dbbe*, const char *zName, int writeable,
|
||||
int intKeyOnly, DbbeCursor**);
|
||||
|
||||
/* Delete a table from the database */
|
||||
void (*DropTable)(Dbbe*, const char *zTableName);
|
||||
@ -164,7 +170,6 @@ struct DbbeMethods {
|
||||
*/
|
||||
struct Dbbe {
|
||||
struct DbbeMethods *x; /* Backend-specific methods for database access */
|
||||
char *zDir; /* The directory containing the database file(s) */
|
||||
int nTemp; /* Number of temporary files created */
|
||||
FILE **apTemp; /* Space to hold temporary file pointers */
|
||||
char **azTemp; /* Names of the temporary files */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
701
src/pg.c
Normal 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
43
src/pg.h
Normal 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*);
|
12
src/select.c
12
src/select.c
@ -24,7 +24,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements.
|
||||
**
|
||||
** $Id: select.c,v 1.27 2000/10/16 22:06:42 drh Exp $
|
||||
** $Id: select.c,v 1.28 2001/01/15 22:51:11 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -489,9 +489,11 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
&& matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){
|
||||
return 1;
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Open, unionTab, 1, 0, 0);
|
||||
if( p->op!=TK_ALL ){
|
||||
sqliteVdbeAddOp(v, OP_OpenIdx, unionTab, 1, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1, 0, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_OpenTbl, unionTab, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -549,7 +551,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
|
||||
return 1;
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Open, tab1, 1, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenIdx, tab1, 1, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1, 0, 0);
|
||||
|
||||
/* Code the SELECTs to our left into temporary table "tab1".
|
||||
@ -559,7 +561,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
|
||||
/* Code the current SELECT into temporary table "tab2"
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_Open, tab2, 1, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenIdx, tab2, 1, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1, 0, 0);
|
||||
p->pPrior = 0;
|
||||
rc = sqliteSelect(pParse, p, SRT_Union, tab2);
|
||||
@ -852,7 +854,7 @@ int sqliteSelect(
|
||||
/* Begin the database scan
|
||||
*/
|
||||
if( isDistinct ){
|
||||
sqliteVdbeAddOp(v, OP_Open, distinct, 1, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenIdx, distinct, 1, 0, 0);
|
||||
}
|
||||
pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
|
||||
if( pWInfo==0 ) return 1;
|
||||
|
@ -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
|
||||
|
@ -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*);
|
||||
|
@ -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
|
||||
|
75
src/vdbe.c
75
src/vdbe.c
@ -41,7 +41,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.50 2001/01/13 14:34:07 drh Exp $
|
||||
** $Id: vdbe.c,v 1.51 2001/01/15 22:51:12 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <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 ){
|
||||
|
185
src/vdbe.h
185
src/vdbe.h
@ -27,7 +27,7 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.14 2000/10/16 22:06:43 drh Exp $
|
||||
** $Id: vdbe.h,v 1.15 2001/01/15 22:51:12 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@ -71,112 +71,113 @@ typedef struct VdbeOp VdbeOp;
|
||||
** The source tree contains an AWK script named renumberOps.awk that
|
||||
** can be used to renumber these opcodes when new opcodes are inserted.
|
||||
*/
|
||||
#define OP_Open 1
|
||||
#define OP_Close 2
|
||||
#define OP_Fetch 3
|
||||
#define OP_Fcnt 4
|
||||
#define OP_New 5
|
||||
#define OP_Put 6
|
||||
#define OP_Distinct 7
|
||||
#define OP_Found 8
|
||||
#define OP_NotFound 9
|
||||
#define OP_Delete 10
|
||||
#define OP_Field 11
|
||||
#define OP_KeyAsData 12
|
||||
#define OP_Key 13
|
||||
#define OP_Rewind 14
|
||||
#define OP_Next 15
|
||||
#define OP_OpenIdx 1
|
||||
#define OP_OpenTbl 2
|
||||
#define OP_Close 3
|
||||
#define OP_Fetch 4
|
||||
#define OP_Fcnt 5
|
||||
#define OP_New 6
|
||||
#define OP_Put 7
|
||||
#define OP_Distinct 8
|
||||
#define OP_Found 9
|
||||
#define OP_NotFound 10
|
||||
#define OP_Delete 11
|
||||
#define OP_Field 12
|
||||
#define OP_KeyAsData 13
|
||||
#define OP_Key 14
|
||||
#define OP_Rewind 15
|
||||
#define OP_Next 16
|
||||
|
||||
#define OP_Destroy 16
|
||||
#define OP_Reorganize 17
|
||||
#define OP_Destroy 17
|
||||
#define OP_Reorganize 18
|
||||
|
||||
#define OP_ResetIdx 18
|
||||
#define OP_NextIdx 19
|
||||
#define OP_PutIdx 20
|
||||
#define OP_DeleteIdx 21
|
||||
#define OP_ResetIdx 19
|
||||
#define OP_NextIdx 20
|
||||
#define OP_PutIdx 21
|
||||
#define OP_DeleteIdx 22
|
||||
|
||||
#define OP_MemLoad 22
|
||||
#define OP_MemStore 23
|
||||
#define OP_MemLoad 23
|
||||
#define OP_MemStore 24
|
||||
|
||||
#define OP_ListOpen 24
|
||||
#define OP_ListWrite 25
|
||||
#define OP_ListRewind 26
|
||||
#define OP_ListRead 27
|
||||
#define OP_ListClose 28
|
||||
#define OP_ListOpen 25
|
||||
#define OP_ListWrite 26
|
||||
#define OP_ListRewind 27
|
||||
#define OP_ListRead 28
|
||||
#define OP_ListClose 29
|
||||
|
||||
#define OP_SortOpen 29
|
||||
#define OP_SortPut 30
|
||||
#define OP_SortMakeRec 31
|
||||
#define OP_SortMakeKey 32
|
||||
#define OP_Sort 33
|
||||
#define OP_SortNext 34
|
||||
#define OP_SortKey 35
|
||||
#define OP_SortCallback 36
|
||||
#define OP_SortClose 37
|
||||
#define OP_SortOpen 30
|
||||
#define OP_SortPut 31
|
||||
#define OP_SortMakeRec 32
|
||||
#define OP_SortMakeKey 33
|
||||
#define OP_Sort 34
|
||||
#define OP_SortNext 35
|
||||
#define OP_SortKey 36
|
||||
#define OP_SortCallback 37
|
||||
#define OP_SortClose 38
|
||||
|
||||
#define OP_FileOpen 38
|
||||
#define OP_FileRead 39
|
||||
#define OP_FileField 40
|
||||
#define OP_FileClose 41
|
||||
#define OP_FileOpen 39
|
||||
#define OP_FileRead 40
|
||||
#define OP_FileField 41
|
||||
#define OP_FileClose 42
|
||||
|
||||
#define OP_AggReset 42
|
||||
#define OP_AggFocus 43
|
||||
#define OP_AggIncr 44
|
||||
#define OP_AggNext 45
|
||||
#define OP_AggSet 46
|
||||
#define OP_AggGet 47
|
||||
#define OP_AggReset 43
|
||||
#define OP_AggFocus 44
|
||||
#define OP_AggIncr 45
|
||||
#define OP_AggNext 46
|
||||
#define OP_AggSet 47
|
||||
#define OP_AggGet 48
|
||||
|
||||
#define OP_SetInsert 48
|
||||
#define OP_SetFound 49
|
||||
#define OP_SetNotFound 50
|
||||
#define OP_SetClear 51
|
||||
#define OP_SetInsert 49
|
||||
#define OP_SetFound 50
|
||||
#define OP_SetNotFound 51
|
||||
#define OP_SetClear 52
|
||||
|
||||
#define OP_MakeRecord 52
|
||||
#define OP_MakeKey 53
|
||||
#define OP_MakeRecord 53
|
||||
#define OP_MakeKey 54
|
||||
|
||||
#define OP_Goto 54
|
||||
#define OP_If 55
|
||||
#define OP_Halt 56
|
||||
#define OP_Goto 55
|
||||
#define OP_If 56
|
||||
#define OP_Halt 57
|
||||
|
||||
#define OP_ColumnCount 57
|
||||
#define OP_ColumnName 58
|
||||
#define OP_Callback 59
|
||||
#define OP_ColumnCount 58
|
||||
#define OP_ColumnName 59
|
||||
#define OP_Callback 60
|
||||
|
||||
#define OP_Integer 60
|
||||
#define OP_String 61
|
||||
#define OP_Null 62
|
||||
#define OP_Pop 63
|
||||
#define OP_Dup 64
|
||||
#define OP_Pull 65
|
||||
#define OP_Integer 61
|
||||
#define OP_String 62
|
||||
#define OP_Null 63
|
||||
#define OP_Pop 64
|
||||
#define OP_Dup 65
|
||||
#define OP_Pull 66
|
||||
|
||||
#define OP_Add 66
|
||||
#define OP_AddImm 67
|
||||
#define OP_Subtract 68
|
||||
#define OP_Multiply 69
|
||||
#define OP_Divide 70
|
||||
#define OP_Min 71
|
||||
#define OP_Max 72
|
||||
#define OP_Like 73
|
||||
#define OP_Glob 74
|
||||
#define OP_Eq 75
|
||||
#define OP_Ne 76
|
||||
#define OP_Lt 77
|
||||
#define OP_Le 78
|
||||
#define OP_Gt 79
|
||||
#define OP_Ge 80
|
||||
#define OP_IsNull 81
|
||||
#define OP_NotNull 82
|
||||
#define OP_Negative 83
|
||||
#define OP_And 84
|
||||
#define OP_Or 85
|
||||
#define OP_Not 86
|
||||
#define OP_Concat 87
|
||||
#define OP_Noop 88
|
||||
#define OP_Add 67
|
||||
#define OP_AddImm 68
|
||||
#define OP_Subtract 69
|
||||
#define OP_Multiply 70
|
||||
#define OP_Divide 71
|
||||
#define OP_Min 72
|
||||
#define OP_Max 73
|
||||
#define OP_Like 74
|
||||
#define OP_Glob 75
|
||||
#define OP_Eq 76
|
||||
#define OP_Ne 77
|
||||
#define OP_Lt 78
|
||||
#define OP_Le 79
|
||||
#define OP_Gt 80
|
||||
#define OP_Ge 81
|
||||
#define OP_IsNull 82
|
||||
#define OP_NotNull 83
|
||||
#define OP_Negative 84
|
||||
#define OP_And 85
|
||||
#define OP_Or 86
|
||||
#define OP_Not 87
|
||||
#define OP_Concat 88
|
||||
#define OP_Noop 89
|
||||
|
||||
#define OP_Strlen 89
|
||||
#define OP_Substr 90
|
||||
#define OP_Strlen 90
|
||||
#define OP_Substr 91
|
||||
|
||||
#define OP_MAX 90
|
||||
#define OP_MAX 91
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
|
@ -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));
|
||||
|
Reference in New Issue
Block a user