aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2000-06-02 01:17:37 +0000
committerdrh <drh@noemail.net>2000-06-02 01:17:37 +0000
commit58b9576b7ab3e6d06836f2a1cd8b2bdcfe9758bb (patch)
tree3a2924d36d72c801f074c8516f38722d8a5074ad /src
parent5494880a71a6086ee561b8365bf0d8a2a8cfff10 (diff)
downloadsqlite-58b9576b7ab3e6d06836f2a1cd8b2bdcfe9758bb.tar.gz
sqlite-58b9576b7ab3e6d06836f2a1cd8b2bdcfe9758bb.zip
:-) (CVS 34)
FossilOrigin-Name: 52338f4ab5990fefc61f615cd65c3a724b365199
Diffstat (limited to 'src')
-rw-r--r--src/build.c16
-rw-r--r--src/dbbe.c120
-rw-r--r--src/dbbe.h6
-rw-r--r--src/delete.c5
-rw-r--r--src/insert.c6
-rw-r--r--src/main.c84
-rw-r--r--src/sqlite.h22
-rw-r--r--src/sqliteInt.h10
-rw-r--r--src/tclsqlite.c4
-rw-r--r--src/update.c5
-rw-r--r--src/vdbe.c107
11 files changed, 240 insertions, 145 deletions
diff --git a/src/build.c b/src/build.c
index 380ce94a0..d5e98435c 100644
--- a/src/build.c
+++ b/src/build.c
@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** when syntax rules are reduced.
**
-** $Id: build.c,v 1.11 2000/05/31 15:34:52 drh Exp $
+** $Id: build.c,v 1.12 2000/06/02 01:17:37 drh Exp $
*/
#include "sqliteInt.h"
@@ -287,7 +287,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
*/
if( !pParse->initFlag ){
static VdbeOp addTable[] = {
- { OP_Open, 0, 0, MASTER_NAME },
+ { OP_Open, 0, 1, MASTER_NAME },
{ OP_New, 0, 0, 0},
{ OP_String, 0, 0, "table" },
{ OP_String, 0, 0, 0}, /* 3 */
@@ -353,7 +353,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
}
if( v ){
static VdbeOp dropTable[] = {
- { OP_Open, 0, 0, MASTER_NAME },
+ { OP_Open, 0, 1, MASTER_NAME },
{ OP_ListOpen, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 2 */
{ OP_Next, 0, ADDR(10), 0}, /* 3 */
@@ -529,7 +529,7 @@ void sqliteCreateIndex(
*/
if( pParse->initFlag==0 ){
static VdbeOp addTable[] = {
- { OP_Open, 0, 0, MASTER_NAME},
+ { OP_Open, 0, 1, MASTER_NAME},
{ OP_New, 0, 0, 0},
{ OP_String, 0, 0, "index"},
{ OP_String, 0, 0, 0}, /* 3 */
@@ -557,7 +557,7 @@ void sqliteCreateIndex(
sqliteVdbeChangeP3(v, base+5, pStart->z, n);
}
sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
- sqliteVdbeAddOp(v, OP_Open, 1, 0, pIndex->zName, 0);
+ sqliteVdbeAddOp(v, OP_Open, 1, 1, pIndex->zName, 0);
lbl1 = sqliteVdbeMakeLabel(v);
lbl2 = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1);
@@ -608,7 +608,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
if( v ){
static VdbeOp dropIndex[] = {
- { OP_Open, 0, 0, MASTER_NAME},
+ { OP_Open, 0, 1, MASTER_NAME},
{ OP_ListOpen, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 2 */
{ OP_Next, 0, ADDR(9), 0}, /* 3 */
@@ -781,9 +781,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, 0, pTab->zName, 0);
+ sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- sqliteVdbeAddOp(v, OP_Open, i, 0, pIdx->zName, 0);
+ sqliteVdbeAddOp(v, OP_Open, i, 1, pIdx->zName, 0);
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);
diff --git a/src/dbbe.c b/src/dbbe.c
index 6d8ed4222..321a5de2e 100644
--- a/src/dbbe.c
+++ b/src/dbbe.c
@@ -30,7 +30,7 @@
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
-** $Id: dbbe.c,v 1.6 2000/05/31 22:58:39 drh Exp $
+** $Id: dbbe.c,v 1.7 2000/06/02 01:17:37 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
@@ -48,6 +48,7 @@ struct BeFile {
GDBM_FILE dbf; /* The file itself */
int nRef; /* Number of references */
int delOnClose; /* Delete when closing */
+ int writeable; /* Opened for writing */
BeFile *pNext, *pPrev; /* Next and previous on list of open files */
};
@@ -128,21 +129,40 @@ static int rc4byte(struct rc4 *p){
*/
Dbbe *sqliteDbbeOpen(
const char *zName, /* The name of the database */
- int write, /* True if we will be writing to the database */
- int create, /* True to create database if it doesn't exist */
+ int writeFlag, /* True if we will be writing to the database */
+ int createFlag, /* True to create database if it doesn't exist */
char **pzErrMsg /* Write error messages (if any) here */
){
Dbbe *pNew;
struct stat statbuf;
+ char *zMaster;
+ if( !writeFlag ) createFlag = 0;
if( stat(zName, &statbuf)!=0 ){
- sqliteSetString(pzErrMsg, "can't find file \"", zName, "\"", 0);
- return 0;
+ if( createFlag ) mkdir(zName, 0750);
+ if( stat(zName, &statbuf)!=0 ){
+ sqliteSetString(pzErrMsg, "can't find or make directory \"",
+ zName, "\"", 0);
+ return 0;
+ }
}
if( !S_ISDIR(statbuf.st_mode) ){
sqliteSetString(pzErrMsg, "not a directory: \"", zName, "\"", 0);
return 0;
}
+ if( access(zName, writeFlag ? (X_OK|W_OK|R_OK) : (X_OK|R_OK)) ){
+ sqliteSetString(pzErrMsg, "access permission denied", 0);
+ return 0;
+ }
+ zMaster = 0;
+ sqliteSetString(&zMaster, zName, "/" MASTER_NAME, 0);
+ if( stat(zMaster, &statbuf)==0
+ && access(zMaster, writeFlag ? (W_OK|R_OK) : R_OK)!=0 ){
+ sqliteSetString(pzErrMsg, "access permission denied for ", zMaster, 0);
+ sqliteFree(zMaster);
+ return 0;
+ }
+ sqliteFree(zMaster);
pNew = sqliteMalloc(sizeof(Dbbe) + strlen(zName) + 1);
if( pNew==0 ){
sqliteSetString(pzErrMsg, "out of memory", 0);
@@ -150,7 +170,7 @@ Dbbe *sqliteDbbeOpen(
}
pNew->zDir = (char*)&pNew[1];
strcpy(pNew->zDir, zName);
- pNew->write = write;
+ pNew->write = writeFlag;
pNew->pOpen = 0;
time(&statbuf.st_ctime);
rc4init(&pNew->rc4, (char*)&statbuf, sizeof(statbuf));
@@ -212,17 +232,22 @@ static void randomName(struct rc4 *pRc4, char *zBuf, char *zPrefix){
/*
** Open a new table cursor
*/
-DbbeTable *sqliteDbbeOpenTable(
+int sqliteDbbeOpenTable(
Dbbe *pBe, /* The database the table belongs to */
const char *zTable, /* The name of the table */
- int writeable /* True to open for writing */
+ int writeable, /* True to open for writing */
+ DbbeTable **ppTable /* Write the resulting table pointer here */
){
char *zFile; /* Name of the table file */
DbbeTable *pTable; /* The new table cursor */
BeFile *pFile; /* 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 */
+ *ppTable = 0;
pTable = sqliteMalloc( sizeof(*pTable) );
- if( pTable==0 ) return 0;
+ if( pTable==0 ) return SQLITE_NOMEM;
if( zTable ){
zFile = sqliteFileOfTable(pBe, zTable);
for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
@@ -233,21 +258,20 @@ DbbeTable *sqliteDbbeOpenTable(
zFile = 0;
}
if( pFile==0 ){
+ if( writeable ){
+ rw_mask = GDBM_WRCREAT | GDBM_FAST;
+ mode = 0640;
+ }else{
+ rw_mask = GDBM_READER;
+ mode = 0640;
+ }
pFile = sqliteMalloc( sizeof(*pFile) );
if( pFile==0 ){
sqliteFree(zFile);
- return 0;
+ return SQLITE_NOMEM;
}
- pFile->zName = zFile;
- pFile->nRef = 1;
- pFile->pPrev = 0;
- if( pBe->pOpen ){
- pBe->pOpen->pPrev = pFile;
- }
- pFile->pNext = pBe->pOpen;
- pBe->pOpen = pFile;
if( pFile->zName ){
- pFile->dbf = gdbm_open(pFile->zName, 0, GDBM_WRCREAT|GDBM_FAST, 0640, 0);
+ pFile->dbf = gdbm_open(pFile->zName, 0, rw_mask, mode, 0);
}else{
int limit;
struct rc4 *pRc4;
@@ -259,20 +283,35 @@ DbbeTable *sqliteDbbeOpenTable(
randomName(&pBe->rc4, zRandom, "_temp_table_");
sqliteFree(zFile);
zFile = sqliteFileOfTable(pBe, zRandom);
- pFile->dbf = gdbm_open(zFile, 0, GDBM_WRCREAT|GDBM_FAST, 0640, 0);
+ pFile->dbf = gdbm_open(zFile, 0, rw_mask, mode, 0);
}while( pFile->dbf==0 && limit-- >= 0);
- pFile->zName = zFile;
pFile->delOnClose = 1;
}
+ pFile->writeable = writeable;
+ pFile->zName = zFile;
+ pFile->nRef = 1;
+ pFile->pPrev = 0;
+ if( pBe->pOpen ){
+ pBe->pOpen->pPrev = pFile;
+ }
+ pFile->pNext = pBe->pOpen;
+ pBe->pOpen = pFile;
+ if( pFile->dbf==0 ){
+ rc = SQLITE_BUSY;
+ }
}else{
sqliteFree(zFile);
pFile->nRef++;
+ if( writeable && !pFile->writeable ){
+ rc = SQLITE_READONLY;
+ }
}
pTable->pBe = pBe;
pTable->pFile = pFile;
pTable->readPending = 0;
pTable->needRewind = 1;
- return pTable;
+ *ppTable = pTable;
+ return rc;
}
/*
@@ -293,7 +332,9 @@ void sqliteDbbeReorganizeTable(Dbbe *pBe, const char *zTable){
char *zFile; /* Name of the table file */
DbbeTable *pTab;
- pTab = sqliteDbbeOpenTable(pBe, zTable, 1);
+ if( sqliteDbbeOpenTable(pBe, zTable, 1, &pTab)!=SQLITE_OK ){
+ return;
+ }
if( pTab && pTab->pFile && pTab->pFile->dbf ){
gdbm_reorganize(pTab->pFile->dbf);
}
@@ -448,7 +489,7 @@ int sqliteDbbeDataLength(DbbeTable *pTable){
*/
int sqliteDbbeRewind(DbbeTable *pTable){
pTable->needRewind = 1;
- return 0;
+ return SQLITE_OK;
}
/*
@@ -512,15 +553,17 @@ int sqliteDbbeNew(DbbeTable *pTable){
*/
int sqliteDbbePut(DbbeTable *pTable, int nKey,char *pKey,int nData,char *pData){
datum data, key;
- if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 0;
+ int rc;
+ if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return SQLITE_ERROR;
data.dsize = nData;
data.dptr = pData;
key.dsize = nKey;
key.dptr = pKey;
- gdbm_store(pTable->pFile->dbf, key, data, GDBM_REPLACE);
+ rc = gdbm_store(pTable->pFile->dbf, key, data, GDBM_REPLACE);
+ if( rc ) rc = SQLITE_ERROR;
datumClear(&pTable->key);
datumClear(&pTable->data);
- return 1;
+ return rc;
}
/*
@@ -528,23 +571,26 @@ int sqliteDbbePut(DbbeTable *pTable, int nKey,char *pKey,int nData,char *pData){
*/
int sqliteDbbeDelete(DbbeTable *pTable, int nKey, char *pKey){
datum key;
+ int rc;
datumClear(&pTable->key);
datumClear(&pTable->data);
- if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 0;
+ if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return SQLITE_ERROR;
key.dsize = nKey;
key.dptr = pKey;
- gdbm_delete(pTable->pFile->dbf, key);
- return 1;
+ rc = gdbm_delete(pTable->pFile->dbf, key);
+ if( rc ) rc = SQLITE_ERROR;
+ return rc;
}
/*
** Open a temporary file.
*/
-FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){
+int sqliteDbbeOpenTempFile(Dbbe *pBe, FILE **ppFile){
char *zFile;
char zBuf[50];
int i, j;
int limit;
+ int rc = SQLITE_OK;
for(i=0; i<pBe->nTemp; i++){
if( pBe->apTemp[i]==0 ) break;
@@ -553,7 +599,10 @@ FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){
pBe->nTemp++;
pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
}
- if( pBe->apTemp==0 ) return 0;
+ if( pBe->apTemp==0 ){
+ *ppFile = 0;
+ return SQLITE_NOMEM;
+ }
limit = 4;
zFile = 0;
do{
@@ -562,9 +611,12 @@ FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){
zFile = 0;
sqliteSetString(&zFile, pBe->zDir, zBuf, 0);
}while( access(zFile,0)==0 && limit-- >= 0 );
- pBe->apTemp[i] = fopen(zFile, "w+");
+ *ppFile = pBe->apTemp[i] = fopen(zFile, "w+");
+ if( pBe->apTemp[i]==0 ){
+ rc = SQLITE_ERROR;
+ }
sqliteFree(zFile);
- return pBe->apTemp[i];
+ return rc;
}
/*
diff --git a/src/dbbe.h b/src/dbbe.h
index b5e36011d..b30e04a7a 100644
--- a/src/dbbe.h
+++ b/src/dbbe.h
@@ -28,7 +28,7 @@
** This library was originally designed to support the following
** backends: GDBM, NDBM, SDBM, Berkeley DB.
**
-** $Id: dbbe.h,v 1.3 2000/05/31 20:00:52 drh Exp $
+** $Id: dbbe.h,v 1.4 2000/06/02 01:17:37 drh Exp $
*/
#ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_
@@ -63,7 +63,7 @@ void sqliteDbbeClose(Dbbe*);
** If zTableName is 0 or "", then a temporary table is created that
** will be deleted when closed.
*/
-DbbeTable *sqliteDbbeOpenTable(Dbbe*, const char *zTableName, int writeable);
+int sqliteDbbeOpenTable(Dbbe*, const char *zName, int writeable, DbbeTable **);
/* Delete a table from the database */
void sqliteDbbeDropTable(Dbbe*, const char *zTableName);
@@ -122,7 +122,7 @@ int sqliteDbbePut(DbbeTable*, int nKey, char *pKey, int nData, char *pData);
int sqliteDbbeDelete(DbbeTable*, int nKey, char *pKey);
/* Open a file suitable for temporary storage */
-FILE *sqliteDbbeOpenTempFile(Dbbe*);
+int sqliteDbbeOpenTempFile(Dbbe*, FILE**);
/* Close a temporary file */
void sqliteDbbeCloseTempFile(Dbbe *, FILE *);
diff --git a/src/delete.c b/src/delete.c
index 3ab5f5940..498c35f22 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
-** $Id: delete.c,v 1.1 2000/05/31 15:34:53 drh Exp $
+** $Id: delete.c,v 1.2 2000/06/02 01:17:37 drh Exp $
*/
#include "sqliteInt.h"
@@ -103,8 +103,9 @@ void sqliteDeleteFrom(
/* Delete every item identified in the list.
*/
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- sqliteVdbeAddOp(v, OP_Open, i, 0, pIdx->zName, 0);
+ sqliteVdbeAddOp(v, OP_Open, i, 1, pIdx->zName, 0);
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
diff --git a/src/insert.c b/src/insert.c
index 071e642c7..85f9af86d 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements.
**
-** $Id: insert.c,v 1.1 2000/05/31 15:34:53 drh Exp $
+** $Id: insert.c,v 1.2 2000/06/02 01:17:37 drh Exp $
*/
#include "sqliteInt.h"
@@ -104,7 +104,7 @@ void sqliteInsert(
v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
if( v ){
Index *pIdx;
- sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
+ sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
sqliteVdbeAddOp(v, OP_New, 0, 0, 0, 0);
if( pTab->pIndex ){
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
@@ -130,7 +130,7 @@ void sqliteInsert(
if( pIdx->pNext ){
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
}
- sqliteVdbeAddOp(v, OP_Open, 0, 0, pIdx->zName, 0);
+ sqliteVdbeAddOp(v, OP_Open, 0, 1, pIdx->zName, 0);
for(i=0; i<pIdx->nField; i++){
int idx = pIdx->aiField[i];
if( pField==0 ){
diff --git a/src/main.c b/src/main.c
index 4deac6de0..ec960e169 100644
--- a/src/main.c
+++ b/src/main.c
@@ -26,7 +26,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.2 2000/05/31 22:58:39 drh Exp $
+** $Id: main.c,v 1.3 2000/06/02 01:17:37 drh Exp $
*/
#include "sqliteInt.h"
@@ -51,14 +51,17 @@ static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
}
/*
-** Open a new SQLite database. Construct an "sqlite" structure to define
-** the state of this database and return a pointer to that structure.
+** Attempt to read the database schema and initialize internal
+** data structures. Return one of the SQLITE_ error codes to
+** indicate success or failure.
*/
-sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
- sqlite *db;
+static int sqliteInit(sqlite *db, char **pzErrMsg){
Vdbe *vdbe;
- Table *pTab;
- char *azArg[2];
+ int rc;
+
+ /*
+ ** The master database table has a structure like this
+ */
static char master_schema[] =
"CREATE TABLE " MASTER_NAME " (\n"
" type text,\n"
@@ -116,7 +119,44 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
{ OP_Halt, 0, 0, 0}, /* 16 */
};
- /* Allocate space to hold the main database structure */
+ /* Create a virtual machine to run the initialization program. Run
+ ** the program. The delete the virtual machine.
+ */
+ vdbe = sqliteVdbeCreate(db->pBe);
+ sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
+ rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg);
+ sqliteVdbeDelete(vdbe);
+ if( rc==SQLITE_OK ){
+ Table *pTab;
+ char *azArg[2];
+ azArg[0] = master_schema;
+ azArg[1] = 0;
+ sqliteOpenCb(db, 1, azArg, 0);
+ pTab = sqliteFindTable(db, MASTER_NAME);
+ if( pTab ){
+ pTab->readOnly = 1;
+ }
+ db->flags |= SQLITE_Initialized;
+ }else{
+ sqliteStrRealloc(pzErrMsg);
+ }
+ return rc;
+}
+
+/*
+** Open a new SQLite database. Construct an "sqlite" structure to define
+** the state of this database and return a pointer to that structure.
+**
+** An attempt is made to initialize the in-memory data structures that
+** hold the database schema. But if this fails (because the schema file
+** is locked) then that step is deferred until the first call to
+** sqlite_exec().
+*/
+sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
+ sqlite *db;
+ int rc;
+
+ /* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite) );
if( pzErrMsg ) *pzErrMsg = 0;
if( db==0 ){
@@ -132,20 +172,12 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
return 0;
}
- /* Create a virtual machine to run the initialization program. Run
- ** the program. The delete the virtual machine.
- */
- azArg[0] = master_schema;
- azArg[1] = 0;
- sqliteOpenCb(db, 1, azArg, 0);
- pTab = sqliteFindTable(db, MASTER_NAME);
- if( pTab ){
- pTab->readOnly = 1;
+ /* Attempt to read the schema */
+ rc = sqliteInit(db, pzErrMsg);
+ if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
+ sqlite_close(db);
+ return 0;
}
- vdbe = sqliteVdbeCreate(db->pBe);
- sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
- sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg);
- sqliteVdbeDelete(vdbe);
return db;
}
@@ -208,14 +240,18 @@ int sqlite_exec(
char **pzErrMsg /* Write error messages here */
){
Parse sParse;
- int nErr;
+ int rc;
if( pzErrMsg ) *pzErrMsg = 0;
+ if( (db->flags & SQLITE_Initialized)==0 ){
+ int rc = sqliteInit(db, pzErrMsg);
+ if( rc!=SQLITE_OK ) return rc;
+ }
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
sParse.xCallback = xCallback;
sParse.pArg = pArg;
- nErr = sqliteRunParser(&sParse, zSql, pzErrMsg);
+ rc = sqliteRunParser(&sParse, zSql, pzErrMsg);
sqliteStrRealloc(pzErrMsg);
- return nErr;
+ return rc;
}
diff --git a/src/sqlite.h b/src/sqlite.h
index 26b48746a..164ed11e1 100644
--- a/src/sqlite.h
+++ b/src/sqlite.h
@@ -24,7 +24,7 @@
** This header file defines the interface that the sqlite library
** presents to client programs.
**
-** @(#) $Id: sqlite.h,v 1.1 2000/05/29 14:26:01 drh Exp $
+** @(#) $Id: sqlite.h,v 1.2 2000/06/02 01:17:38 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
@@ -75,8 +75,7 @@ typedef int (*sqlite_callback)(void*,int,char**, char**);
** invoked once for each row of the query result. This callback
** should normally return 0. If the callback returns a non-zero
** value then the query is aborted, all subsequent SQL statements
-** are skipped and the sqlite_exec() function returns the same
-** value that the callback returned.
+** are skipped and the sqlite_exec() function returns the SQLITE_ABORT.
**
** The 4th parameter is an arbitrary pointer that is passed
** to the callback function as its first parameter.
@@ -95,7 +94,12 @@ typedef int (*sqlite_callback)(void*,int,char**, char**);
** message is written into memory obtained from malloc() and
** *errmsg is made to point to that message. If errmsg==NULL,
** then no error message is ever written. The return value is
-** non-zero if an error occurs.
+** SQLITE_ERROR if an error occurs.
+**
+** If the query could not be executed because a database file is
+** locked or busy, then this function returns SQLITE_BUSY. If
+** the query could not be executed because a file is missing or
+** has incorrect permissions, this function returns SQLITE_ERROR.
*/
int sqlite_exec(
sqlite*, /* An open database */
@@ -105,6 +109,16 @@ int sqlite_exec(
char **errmsg /* Error msg written here */
);
+/*
+** Return values fro sqlite_exec()
+*/
+#define SQLITE_OK 0 /* Successful result */
+#define SQLITE_INTERNAL 1 /* An internal logic error in SQLite */
+#define SQLITE_ERROR 2 /* SQL error or missing database */
+#define SQLITE_ABORT 3 /* Callback routine requested an abort */
+#define SQLITE_BUSY 4 /* One or more database files are locked */
+#define SQLITE_NOMEM 5 /* A malloc() failed */
+
/* This function returns true if the given input string comprises
** one or more complete SQL statements.
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 08deeb275..5fa1917e4 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -23,7 +23,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.7 2000/05/31 22:58:39 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.8 2000/06/02 01:17:38 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
@@ -101,6 +101,14 @@ struct sqlite {
** Possible values for the flags field of sqlite
*/
#define SQLITE_VdbeTrace 0x00000001
+#define SQLITE_Initialized 0x00000002
+
+/*
+** Values for SQLITE_OK, SQLITE_ERROR, etc are defined in sqlite.h.
+** The following are several new return codes that are used internally
+** only. Take care that these values do not overlap.
+*/
+#define SQLITE_READONLY 6 /* Table already opened as read-only */
/*
** Each table is represented in memory by
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index e261791cc..1499cf6e2 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -23,7 +23,7 @@
*************************************************************************
** A TCL Interface to SQLite
**
-** $Id: tclsqlite.c,v 1.3 2000/05/30 13:44:20 drh Exp $
+** $Id: tclsqlite.c,v 1.4 2000/06/02 01:17:38 drh Exp $
*/
#include "sqlite.h"
#include <tcl.h>
@@ -201,7 +201,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
return TCL_ERROR;
}
if( argc==3 ){
- mode = 0;
+ mode = 0666;
}else if( Tcl_GetInt(interp, argv[3], &mode)!=TCL_OK ){
return TCL_ERROR;
}
diff --git a/src/update.c b/src/update.c
index a19846a91..8bd2e5dd0 100644
--- a/src/update.c
+++ b/src/update.c
@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.1 2000/05/31 15:34:53 drh Exp $
+** $Id: update.c,v 1.2 2000/06/02 01:17:38 drh Exp $
*/
#include "sqliteInt.h"
@@ -155,8 +155,9 @@ void sqliteUpdate(
** open every index that needs updating.
*/
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
for(i=0; i<nIdx; i++){
- sqliteVdbeAddOp(v, OP_Open, i+1, 0, apIdx[i]->zName, 0);
+ sqliteVdbeAddOp(v, OP_Open, i+1, 1, apIdx[i]->zName, 0);
}
/* Loop over every record that needs updating. We have to load
diff --git a/src/vdbe.c b/src/vdbe.c
index 2c302ba08..766773e0d 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -41,7 +41,7 @@
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
-** $Id: vdbe.c,v 1.6 2000/06/01 11:16:52 drh Exp $
+** $Id: vdbe.c,v 1.7 2000/06/02 01:17:38 drh Exp $
*/
#include "sqliteInt.h"
@@ -452,16 +452,18 @@ int sqliteVdbeList(
azField[2] = zP1;
azField[3] = zP2;
azField[5] = 0;
- rc = 0;
+ rc = SQLITE_OK;
if( pzErrMsg ){ *pzErrMsg = 0; }
- for(i=0; rc==0 && i<p->nOp; i++){
+ for(i=0; rc==SQLITE_OK && i<p->nOp; i++){
sprintf(zAddr,"%d",i);
sprintf(zP1,"%d", p->aOp[i].p1);
sprintf(zP2,"%d", p->aOp[i].p2);
azField[4] = p->aOp[i].p3;
if( azField[4]==0 ) azField[4] = "";
azField[1] = zOpName[p->aOp[i].opcode];
- rc = xCallback(pArg, 5, azField, azColumnNames);
+ if( xCallback(pArg, 5, azField, azColumnNames) ){
+ rc = SQLITE_ABORT;
+ }
}
return rc;
}
@@ -566,8 +568,15 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight){
** The return parameter is the number of errors.
**
** If the callback every returns non-zero, then the program exits
-** immediately. No error message is written but the return value
-** from the callback because the return value of this routine.
+** immediately. No error message but the function does return SQLITE_ABORT.
+**
+** A memory allocation error causes this routine to return SQLITE_NOMEM
+** and abandon furture processing.
+**
+** Other fatal errors return SQLITE_ERROR.
+**
+** If a database file could not be opened because it is locked by
+** another database instance, then this routine returns SQLITE_BUSY.
*/
int sqliteVdbeExec(
Vdbe *p, /* The VDBE */
@@ -581,9 +590,9 @@ int sqliteVdbeExec(
char zBuf[100]; /* Space to sprintf() and integer */
p->tos = -1;
- rc = 0;
+ rc = SQLITE_OK;
if( pzErrMsg ){ *pzErrMsg = 0; }
- for(pc=0; rc==0 && pc<p->nOp && pc>=0; pc++){
+ for(pc=0; rc==SQLITE_OK && pc<p->nOp && pc>=0; pc++){
pOp = &p->aOp[pc];
if( p->trace ){
fprintf(p->trace,"%4d %-12s %4d %4d %s\n",
@@ -599,12 +608,7 @@ int sqliteVdbeExec(
** the program.
*/
case OP_Goto: {
- pc = pOp->p2;
- if( pc<0 || pc>p->nOp ){
- sqliteSetString(pzErrMsg, "jump destination out of range", 0);
- rc = 1;
- }
- pc--;
+ pc = pOp->p2 - 1;
break;
}
@@ -743,7 +747,9 @@ int sqliteVdbeExec(
if( Stringify(p, j) ) goto no_mem;
}
p->zStack[p->tos+1] = 0;
- rc = xCallback(pArg, pOp->p1, &p->zStack[i], p->azColName);
+ if( xCallback(pArg, pOp->p1, &p->zStack[i], p->azColName)!=0 ){
+ rc = SQLITE_ABORT;
+ }
PopStack(p, pOp->p1);
break;
}
@@ -821,7 +827,7 @@ int sqliteVdbeExec(
default: {
if( a==0 ){
sqliteSetString(pzErrMsg, "division by zero", 0);
- rc = 1;
+ rc = SQLITE_ERROR;
goto cleanup;
}
b /= a;
@@ -843,7 +849,7 @@ int sqliteVdbeExec(
default: {
if( a==0.0 ){
sqliteSetString(pzErrMsg, "division by zero", 0);
- rc = 1;
+ rc = SQLITE_ERROR;
goto cleanup;
}
b /= a;
@@ -1293,7 +1299,7 @@ int sqliteVdbeExec(
break;
}
- /* Open P1 P3 P2
+ /* Opcode: Open P1 P2 P3
**
** Open a new database table named P3. Give it an identifier P1.
** Open readonly if P2==0 and for reading and writing if P2!=0.
@@ -1316,7 +1322,7 @@ int sqliteVdbeExec(
}else if( p->aTab[i].pTable ){
sqliteDbbeCloseTable(p->aTab[i].pTable);
}
- p->aTab[i].pTable = sqliteDbbeOpenTable(p->pBe, pOp->p3, pOp->p2);
+ rc = sqliteDbbeOpenTable(p->pBe, pOp->p3, pOp->p2, &p->aTab[i].pTable);
p->aTab[i].index = 0;
break;
}
@@ -1351,7 +1357,8 @@ int sqliteVdbeExec(
sqliteDbbeFetch(p->aTab[i].pTable, sizeof(int),
(char*)&p->iStack[tos]);
}else{
- sqliteDbbeFetch(p->aTab[i].pTable, p->iStack[tos], p->zStack[tos]);
+ sqliteDbbeFetch(p->aTab[i].pTable, p->iStack[tos],
+ p->zStack[tos]);
}
}
PopStack(p, 1);
@@ -1380,12 +1387,7 @@ int sqliteVdbeExec(
}
}
if( !alreadyExists ){
- pc = pOp->p2;
- if( pc<0 || pc>p->nOp ){
- sqliteSetString(pzErrMsg, "jump destination out of range", 0);
- rc = 1;
- }
- pc--;
+ pc = pOp->p2 - 1;
}
break;
}
@@ -1536,12 +1538,7 @@ int sqliteVdbeExec(
int i = pOp->p1;
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
if( sqliteDbbeNextKey(p->aTab[i].pTable)==0 ){
- pc = pOp->p2;
- if( pc<0 || pc>p->nOp ){
- sqliteSetString(pzErrMsg, "jump destination out of range", 0);
- rc = 1;
- }
- pc--;
+ pc = pOp->p2 - 1;
}
}
break;
@@ -1587,12 +1584,7 @@ int sqliteVdbeExec(
}
if( j>=nIdx ){
j = -1;
- pc = pOp->p2;
- if( pc<0 || pc>p->nOp ){
- sqliteSetString(pzErrMsg, "jump destination out of range", 0);
- rc = 1;
- }
- pc--;
+ pc = pOp->p2 - 1;
PopStack(p, 1);
}
p->aTab[i].index = j+1;
@@ -1721,7 +1713,7 @@ int sqliteVdbeExec(
}else if( p->apList[i] ){
sqliteDbbeCloseTempFile(p->pBe, p->apList[i]);
}
- p->apList[i] = sqliteDbbeOpenTempFile(p->pBe);
+ rc = sqliteDbbeOpenTempFile(p->pBe, &p->apList[i]);
break;
}
@@ -1772,12 +1764,7 @@ int sqliteVdbeExec(
p->iStack[p->tos] = val;
p->zStack[p->tos] = 0;
}else{
- pc = pOp->p2;
- if( pc<0 || pc>p->nOp ){
- sqliteSetString(pzErrMsg, "jump destination out of range", 0);
- rc = 1;
- }
- pc--;
+ pc = pOp->p2 - 1;
}
break;
}
@@ -1980,12 +1967,7 @@ int sqliteVdbeExec(
sqliteFree(pSorter->zKey);
sqliteFree(pSorter);
}else{
- pc = pOp->p2;
- if( pc<0 || pc>p->nOp ){
- sqliteSetString(pzErrMsg, "jump destination out of range", 0);
- rc = 1;
- }
- pc--;
+ pc = pOp->p2 - 1;
}
break;
}
@@ -2018,7 +2000,9 @@ int sqliteVdbeExec(
case OP_SortCallback: {
int i = p->tos;
if( i<0 ) goto not_enough_stack;
- rc = xCallback(pArg, pOp->p1, (char**)p->zStack[i], p->azColName);
+ if( xCallback(pArg, pOp->p1, (char**)p->zStack[i], p->azColName) ){
+ rc = SQLITE_ABORT;
+ }
PopStack(p, 1);
break;
}
@@ -2060,7 +2044,7 @@ int sqliteVdbeExec(
}
if( p->pFile==0 ){
sqliteSetString(pzErrMsg,"unable to open file: ", pOp->p3, 0);
- rc = 1;
+ rc = SQLITE_ERROR;
goto cleanup;
}
break;
@@ -2160,12 +2144,7 @@ int sqliteVdbeExec(
/* If we reach end-of-file, or if anything goes wrong, jump here.
** This code will cause a jump to P2 */
fileread_jump:
- pc = pOp->p2;
- if( pc<0 || pc>p->nOp ){
- sqliteSetString(pzErrMsg, "jump destination out of range", 0);
- rc = 1;
- }
- pc--;
+ pc = pOp->p2 - 1;
break;
}
@@ -2195,10 +2174,14 @@ int sqliteVdbeExec(
default: {
sprintf(zBuf,"%d",pOp->opcode);
sqliteSetString(pzErrMsg, "unknown opcode ", zBuf, 0);
- rc = 1;
+ rc = SQLITE_INTERNAL;
break;
}
}
+ if( pc<-1 || pc>=p->nOp ){
+ sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+ rc = SQLITE_INTERNAL;
+ }
if( p->trace && p->tos>=0 ){
int i;
fprintf(p->trace, "Stack:");
@@ -2231,7 +2214,7 @@ no_mem:
not_enough_stack:
sprintf(zBuf,"%d",pc);
sqliteSetString(pzErrMsg, "too few operands on stack at ", zBuf, 0);
- rc = 1;
+ rc = SQLITE_INTERNAL;
goto cleanup;
/* Jump here if an illegal or illformed instruction is executed.
@@ -2239,7 +2222,7 @@ not_enough_stack:
bad_instruction:
sprintf(zBuf,"%d",pc);
sqliteSetString(pzErrMsg, "illegal operation at ", zBuf, 0);
- rc = 1;
+ rc = SQLITE_INTERNAL;
goto cleanup;
}