-C Added\sa\sPRAGMA\sstatement.\s\sTook\sout\sthe\sspecial\scomment\sparsing.\s(CVS\s245)
-D 2001-09-14T18:54:08
+C Everything\sis\sworking\son\sLinux.\s\sThis\sis\srelease\s2.0-Alpha-1.\s(CVS\s246)
+D 2001-09-15T00:57:28
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in 7ecb2370b5cb34d390af1fcb3118ea6d84a253ca
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
F notes/notes2.txt 7e3fafd5e25906c1fe1e95f13b089aa398ca403e
F notes/notes2b.txt 1c17a5b7f6b44a75cd3eb98ed2c24db1eefb06c3
F notes/notes3.txt 71e47be517e3d2578b3b9343a45b772d43b7ba16
-F src/TODO f0ea267ab55c4d15127c1ac1667edbf781147438
+F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c 3adf545b8e072000923f7e0f7f91d33072a9f869
F src/btree.h a3d9c20fa876e837680745ac60500be697026b7b
-F src/build.c b5c682960b5889555cd059f3b5157668778b8834
-F src/delete.c 62500a09606c0f714b651756475cd42979ef08e8
+F src/build.c 8359e553db8138d09f44957e2d1bcc9b8720117b
+F src/delete.c c84b5a26e29fda3c3de51345073a76bb161271fd
F src/ex/README b745b00acce2d892f60c40111dacdfc48e0c1c7a
F src/ex/db.c f1419ae6c93e40b5ac6e39fe7efd95d868e6f9d7
F src/ex/db.h 3f2933ee20c147fe494835786e4c6f3a562def4e
F src/ex/pg.h 23a4ac807b0546ec2bb6239ec8bd3e06926572cd
F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7
F src/expr.c bcd91d0487c71cfa44413a46efe5e2c2244901b6
-F src/insert.c edf098ecbbe00e3ecde6b5f22404a8230590c9fd
-F src/main.c a2c142626b46e3eb3e01436626df6c2d0a8f3ae6
+F src/insert.c 750a44c0d205779b2c42b0791a163937cfb00e74
+F src/main.c 73be8d00a8a9bbec715a6260840a19020a074090
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
-F src/pager.c bb0891d49b9068711e4b8bab14db2959f56f5be9
+F src/pager.c 048c20ac85485ca87ed33d6b7711375a3444f817
F src/pager.h bb9136e833de46bc84aafd8403713d3c46fcbfdf
F src/parse.y 8b30e072208c3dfabd97c7d06f0924f194919533
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
F src/select.c f1673b4d06c24665097faf28d76c4533bce18b84
F src/shell.c 1fcdf8c4180098bcfdee12501e01b4c8eb21d726
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
-F src/sqlite.h.in 8faa2fed0513d188ced16e5f9094e57694594e70
-F src/sqliteInt.h 11d74bfd90777afafc529434b86c413fed44f0bf
+F src/sqlite.h.in 1d6a7d13284c3861e61bd0b71491fda613613c68
+F src/sqliteInt.h c7c0580ceb9b5ce92c6fc7ef9434320952b14dc0
F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6
F src/tclsqlite.c d328970848c028e13e61e173bef79adcc379568a
F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4
F src/test2.c b3177e061fabd20d48e4b1b4bca610a0d2b28670
F src/test3.c 1fc103f198cbd0447d1a12c3ce48795755ec1a53
F src/tokenize.c 2d4d1534b321422384de0f311d417ffce14fedc6
-F src/update.c ea8f2c0712cd4cd19314a26ef4766866013facda
-F src/util.c c77668fef860cfd2e4e682ef4f3ed8f9e68c551b
-F src/vdbe.c 244c86e406170c76b89ab07de4c7258f716c36ff
-F src/vdbe.h 9f32bd12c47bd2b4bdd7e93092bb796f2a3b649f
-F src/where.c fef978a9a2234b01e30e36833ab63e14bbc626d3
+F src/update.c 8a9d514c7f3bfe5d99fe3dfc1ad92ed3e9daea47
+F src/util.c f3f1550fb7a02348c3d0a0969951e489806e055b
+F src/vdbe.c d5bb5d8dda994779e4d20de5e4a31edf995269ff
+F src/vdbe.h b9d60d90aeb3acb5dbc1cdac6b0201991921b272
+F src/where.c b831b506e17cb592d9781ed066f3459cef768318
F test/all.test 5cefdb035b45639ddbb9f80324185b0f0a9ebda2
F test/btree.test 5e1eeb03cda22161eec827dc5224ce6c500eaaf9
F test/btree2.test 061365dfc2a6cd784e17a014b67b277a4cd374ee
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
-P 7da856cd94d2572070e40762e5bc477679e60042
-R 07caee6e3ed361d3efc95a7817451754
+P 5e3724603e6f52bb74deb1c62e6e8f323d7b64b7
+R f702824af0e6fb733e46f0ad203329d6
U drh
-Z 4e11150d8699ec673e8745d72c606c4d
+Z 7366e408d799dcad27172164daf780cc
-5e3724603e6f52bb74deb1c62e6e8f323d7b64b7
\ No newline at end of file
+14474fa144fe7c5dc63e0990d6cc92d769e6013e
\ No newline at end of file
* "OPTIMIZE select" statement to automatically create indices and/or
invoke a CLUSTER command.
* "CREATE INDEX FOR select" to automatically generate needed indices.
- * Implement a PRAGMA command
* Parse and use constraints.
** COPY
** VACUUM
**
-** $Id: build.c,v 1.34 2001/09/14 18:54:08 drh Exp $
+** $Id: build.c,v 1.35 2001/09/15 00:57:28 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
pParse->pVdbe = 0;
pParse->colNamesSet = 0;
pParse->rc = rc;
+ pParse->schemaVerified = 0;
}
}
void sqliteCommitInternalChanges(sqlite *db){
int i;
if( (db->flags & SQLITE_InternChanges)==0 ) return;
+ db->schema_cookie = db->next_cookie;
for(i=0; i<N_HASH; i++){
Table *pTable, *pNext;
for(pTable = db->apTblHash[i]; pTable; pTable=pNext){
void sqliteRollbackInternalChanges(sqlite *db){
int i;
if( (db->flags & SQLITE_InternChanges)==0 ) return;
+ db->next_cookie = db->schema_cookie;
for(i=0; i<N_HASH; i++){
Table *pTable, *pNext;
for(pTable = db->apTblHash[i]; pTable; pTable=pNext){
Vdbe *v = sqliteGetVdbe(pParse);
if( v ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
}
}
}
sqliteDequote(*pz);
}
+/*
+** Come up with a new random value for the schema cookie. Make sure
+** the new value is different from the old.
+**
+** The schema cookie is used to determine when the schema for the
+** database changes. After each schema change, the cookie value
+** changes. When a process first reads the schema it records the
+** cookie. Thereafter, whenever it goes to access the database,
+** it checks the cookie to make sure the schema has not changed
+** since it was last read.
+**
+** This plan is not completely bullet-proof. It is possible for
+** the schema to change multiple times and for the cookie to be
+** set back to prior value. But schema changes are infrequent
+** and the probability of hitting the same cookie value is only
+** 1 chance in 2^32. So we're safe enough.
+*/
+static void changeCookie(sqlite *db){
+ if( db->next_cookie==db->schema_cookie ){
+ db->next_cookie = db->schema_cookie + sqliteRandomByte() + 1;
+ db->flags |= SQLITE_InternChanges;
+ }
+}
+
/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.
{ OP_String, 0, 0, 0}, /* 6 */
{ OP_MakeRecord, 5, 0, 0},
{ OP_Put, 0, 0, 0},
+ { OP_SetCookie, 0, 0, 0}, /* 9 */
};
int n, base;
Vdbe *v;
sqliteVdbeTableRootAddr(v, &p->tnum);
sqliteVdbeChangeP3(v, base+5, p->zName, 0);
sqliteVdbeChangeP3(v, base+6, pParse->sFirstToken.z, n);
+ changeCookie(db);
+ sqliteVdbeChangeP1(v, base+9, db->next_cookie);
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
if( p->pIndex ){
/* If the table has a primary key, create an index in the database
{ OP_Delete, 0, 0, 0},
{ OP_Goto, 0, ADDR(3), 0},
{ OP_Destroy, 0, 0, 0}, /* 9 */
+ { OP_SetCookie, 0, 0, 0}, /* 10 */
{ OP_Close, 0, 0, 0},
};
Index *pIdx;
if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
}
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
sqliteVdbeChangeP1(v, base+9, pTable->tnum);
+ changeCookie(db);
+ sqliteVdbeChangeP1(v, base+10, db->next_cookie);
for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, 0, 0, 0);
}
{ OP_String, 0, 0, 0}, /* 8 */
{ OP_MakeRecord, 5, 0, 0},
{ OP_Put, 2, 0, 0},
+ { OP_SetCookie, 0, 0, 0}, /* 11 */
{ OP_Close, 2, 0, 0},
};
int n;
if( v==0 ) goto exit_create_index;
if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
}
if( pStart && pEnd ){
int base;
sqliteVdbeChangeP3(v, base+6, pIndex->zName, 0);
sqliteVdbeChangeP3(v, base+7, pTab->zName, 0);
sqliteVdbeChangeP3(v, base+8, pStart->z, n);
+ changeCookie(db);
+ sqliteVdbeChangeP1(v, base+11, db->next_cookie);
}
sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0);
lbl1 = sqliteVdbeMakeLabel(v);
{ OP_Ne, 0, ADDR(3), 0},
{ OP_Delete, 0, 0, 0},
{ OP_Destroy, 0, 0, 0}, /* 8 */
+ { OP_SetCookie, 0, 0, 0}, /* 9 */
{ OP_Close, 0, 0, 0},
};
int base;
if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
}
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
sqliteVdbeChangeP1(v, base+8, pIndex->tnum);
+ changeCookie(db);
+ sqliteVdbeChangeP1(v, base+9, db->next_cookie);
if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
if( v ){
if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
}
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
if( v==0 ) goto vacuum_cleanup;
if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
}
if( zName ){
sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, zName, 0);
v = sqliteGetVdbe(pParse);
if( v ){
sqliteVdbeAddOp(v, OP_Transaction, 1, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
}
db->flags |= SQLITE_InTrans;
}
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
-** $Id: delete.c,v 1.12 2001/09/13 21:53:10 drh Exp $
+** $Id: delete.c,v 1.13 2001/09/15 00:57:29 drh Exp $
*/
#include "sqliteInt.h"
if( v==0 ) goto delete_from_cleanup;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0);
}
** This file contains C code routines that are called by the parser
** to handle INSERT statements.
**
-** $Id: insert.c,v 1.16 2001/09/14 03:24:25 drh Exp $
+** $Id: insert.c,v 1.17 2001/09/15 00:57:29 drh Exp $
*/
#include "sqliteInt.h"
if( v==0 ) goto insert_cleanup;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0);
}
/* Figure out how many columns of data are supplied. If the data
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.35 2001/09/14 16:42:12 drh Exp $
+** $Id: main.c,v 1.36 2001/09/15 00:57:29 drh Exp $
*/
#include "sqliteInt.h"
#if defined(HAVE_USLEEP) && HAVE_USLEEP
assert( argc==4 );
switch( argv[0][0] ){
case 'm': { /* Meta information */
- sscanf(argv[1],"file format %d",&db->file_format);
+ if( strcmp(argv[1],"file-format")==0 ){
+ db->file_format = atoi(argv[3]);
+ }else if( strcmp(argv[1],"schema-cookie")==0 ){
+ db->schema_cookie = atoi(argv[3]);
+ db->next_cookie = db->schema_cookie;
+ }
break;
}
case 'i':
{ OP_Column, 0, 4, 0},
{ OP_Callback, 4, 0, 0},
{ OP_Goto, 0, 24, 0},
- { OP_Close, 0, 0, 0}, /* 34 */
+ { OP_String, 0, 0, "meta"}, /* 34 */
+ { OP_String, 0, 0, "schema-cookie"},
+ { OP_String, 0, 0, ""},
+ { OP_ReadCookie,0,0, 0},
+ { OP_Callback, 4, 0, 0},
+ { OP_Close, 0, 0, 0},
{ OP_Halt, 0, 0, 0},
};
}
/*
-** Close an existing SQLite database
+** Erase all schema information from the schema hash table.
+**
+** The database schema is normally read in once when the database
+** is first opened and stored in a hash table in the sqlite structure.
+** This routine erases the stored schema. This erasure occurs because
+** either the database is being closed or because some other process
+** changed the schema and this process needs to reread it.
*/
-void sqlite_close(sqlite *db){
+static void clearHashTable(sqlite *db){
int i;
- sqliteBtreeClose(db->pBe);
for(i=0; i<N_HASH; i++){
Table *pNext, *pList = db->apTblHash[i];
db->apTblHash[i] = 0;
pList = pNext;
}
}
+ db->flags &= ~SQLITE_Initialized;
+}
+
+/*
+** Close an existing SQLite database
+*/
+void sqlite_close(sqlite *db){
+ sqliteBtreeClose(db->pBe);
+ clearHashTable(db);
sqliteFree(db);
}
sParse.rc = SQLITE_NOMEM;
}
sqliteStrRealloc(pzErrMsg);
+ if( sParse.rc==SQLITE_SCHEMA ){
+ clearHashTable(db);
+ }
return sParse.rc;
}
** all writes in order to support rollback. Locking is used to limit
** access to one or more reader or to one writer.
**
-** @(#) $Id: pager.c,v 1.18 2001/09/14 18:54:09 drh Exp $
+** @(#) $Id: pager.c,v 1.19 2001/09/15 00:57:29 drh Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
return SQLITE_OK;
}
+/*
+** Sync the journal and write all free dirty pages to the database file.
+*/
+static int syncAllPages(Pager *pPager){
+ PgHdr *pPg;
+ int rc = SQLITE_OK;
+ if( pPager->needSync ){
+ rc = fsync(pPager->jfd);
+ if( rc!=0 ) return rc;
+ pPager->needSync = 0;
+ }
+ for(pPg=pPager->pFirst; pPg; pPg=pPg->pNextFree){
+ if( pPg->dirty ){
+ pager_seek(pPager->fd, (pPg->pgno-1)*SQLITE_PAGE_SIZE);
+ rc = pager_write(pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
+ if( rc!=SQLITE_OK ) break;
+ pPg->dirty = 0;
+ }
+ }
+ return SQLITE_OK;
+}
+
/*
** Acquire a page.
**
/* Recycle an older page. First locate the page to be recycled.
** Try to find one that is not dirty and is near the head of
** of the free list */
- /* int cnt = pPager->mxPage/2; */
- int cnt = 10;
+ int cnt = pPager->mxPage/2;
pPg = pPager->pFirst;
while( pPg->dirty && 0<cnt-- && pPg->pNextFree ){
pPg = pPg->pNextFree;
}
- if( pPg==0 || pPg->dirty ) pPg = pPager->pFirst;
+ if( pPg==0 || pPg->dirty ){
+ int rc = syncAllPages(pPager);
+ if( rc!=0 ){
+ sqlitepager_rollback(pPager);
+ *ppPage = 0;
+ return SQLITE_IOERR;
+ }
+ pPg = pPager->pFirst;
+ }
assert( pPg->nRef==0 );
+
+#if 0
+ /**** Since putting in the call to syncAllPages() above, this code
+ ** is no longer used. I've kept it here for historical reference
+ ** only.
+ */
/* If the page to be recycled is dirty, sync the journal and write
** the old page into the database. */
if( pPg->dirty ){
return rc;
}
}
+#endif
+ assert( pPg->dirty==0 );
/* Unlink the old page from the free list and the hash table
*/
** This header file defines the interface that the sqlite library
** presents to client programs.
**
-** @(#) $Id: sqlite.h.in,v 1.14 2001/09/13 13:46:57 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.15 2001/09/15 00:57:29 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#define SQLITE_CANTOPEN 13 /* Unable to open the database file */
#define SQLITE_PROTOCOL 14 /* Database lock protocol error */
#define SQLITE_EMPTY 15 /* Database table is empty */
+#define SQLITE_SCHEMA 16 /* The database schema changed */
/* This function causes any pending database operation to abort and
** return at its earliest opportunity. This routine is typically
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.47 2001/09/14 18:54:09 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.48 2001/09/15 00:57:29 drh Exp $
*/
#include "sqlite.h"
#include "vdbe.h"
Btree *pBe; /* The B*Tree backend */
int flags; /* Miscellanous flags. See below */
int file_format; /* What file format version is this database? */
+ int schema_cookie; /* Magic number that changes with the schema */
+ int next_cookie; /* Value of schema_cookie after commit */
int nTable; /* Number of tables in the database */
void *pBusyArg; /* 1st Argument to the busy callback */
int (*xBusyCallback)(void *,const char*,int); /* The busy callback */
int iAggCount; /* Index of the count(*) aggregate in aAgg[] */
int useAgg; /* If true, extract field values from the aggregator
** while generating expressions. Normally false */
+ int schemaVerified; /* True if an OP_VerifySchema has been coded someplace
+ ** other than after an OP_Transaction */
};
/*
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.12 2001/09/13 13:46:57 drh Exp $
+** $Id: update.c,v 1.13 2001/09/15 00:57:29 drh Exp $
*/
#include "sqliteInt.h"
if( v==0 ) goto update_cleanup;
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0);
}
/* Begin the database scan
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
-** $Id: util.c,v 1.22 2001/09/13 13:46:57 drh Exp $
+** $Id: util.c,v 1.23 2001/09/15 00:57:29 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
** argument.
*/
const char *sqliteErrStr(int rc){
- char *z = 0;
+ const char *z;
switch( rc ){
- case SQLITE_OK: z = "not an error"; break;
- case SQLITE_ERROR: z = "SQL logic error or missing database"; break;
- case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break;
- case SQLITE_PERM: z = "access permission denied"; break;
- case SQLITE_ABORT: z = "callback requested query abort"; break;
- case SQLITE_BUSY: z = "database in use by another process"; break;
- case SQLITE_NOMEM: z = "out of memory"; break;
- case SQLITE_READONLY: z = "attempt to write a readonly database"; break;
- case SQLITE_INTERRUPT: z = "interrupted"; break;
- case SQLITE_IOERR: z = "disk I/O error"; break;
- case SQLITE_CORRUPT: z = "database disk image is malformed"; break;
- case SQLITE_NOTFOUND: z = "table or record not found"; break;
- case SQLITE_FULL: z = "database is full"; break;
- case SQLITE_CANTOPEN: z = "unable to open database file"; break;
- case SQLITE_PROTOCOL: z = "database locking protocol failure"; break;
- case SQLITE_EMPTY: z = "table contains no data";
- default:
+ case SQLITE_OK: z = "not an error"; break;
+ case SQLITE_ERROR: z = "SQL logic error or missing database"; break;
+ case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break;
+ case SQLITE_PERM: z = "access permission denied"; break;
+ case SQLITE_ABORT: z = "callback requested query abort"; break;
+ case SQLITE_BUSY: z = "database in use by another process"; break;
+ case SQLITE_NOMEM: z = "out of memory"; break;
+ case SQLITE_READONLY: z = "attempt to write a readonly database"; break;
+ case SQLITE_INTERRUPT: z = "interrupted"; break;
+ case SQLITE_IOERR: z = "disk I/O error"; break;
+ case SQLITE_CORRUPT: z = "database disk image is malformed"; break;
+ case SQLITE_NOTFOUND: z = "table or record not found"; break;
+ case SQLITE_FULL: z = "database is full"; break;
+ case SQLITE_CANTOPEN: z = "unable to open database file"; break;
+ case SQLITE_PROTOCOL: z = "database locking protocol failure"; break;
+ case SQLITE_EMPTY: z = "table contains no data"; break;
+ case SQLITE_SCHEMA: z = "database schema has changed"; break;
+ default: z = "unknown error"; break;
}
return z;
}
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
-** $Id: vdbe.c,v 1.66 2001/09/14 16:42:12 drh Exp $
+** $Id: vdbe.c,v 1.67 2001/09/15 00:57:29 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
}
}
+/*
+** Close a cursor and release all the resources that cursor happens
+** to hold.
+*/
+static void cleanupCursor(Cursor *pCx){
+ if( pCx->pCursor ){
+ sqliteBtreeCloseCursor(pCx->pCursor);
+ }
+ if( pCx->zKey ){
+ sqliteFree(pCx->zKey);
+ }
+ if( pCx->pBt ){
+ sqliteBtreeClose(pCx->pBt);
+ }
+ memset(pCx, 0, sizeof(Cursor));
+}
+
/*
** Clean up the VM after execution.
**
sqliteFree(p->azColName);
p->azColName = 0;
for(i=0; i<p->nCursor; i++){
- Cursor *pCx = &p->aCsr[i];
- if( pCx->pCursor ){
- sqliteBtreeCloseCursor(pCx->pCursor);
- pCx->pCursor = 0;
- }
- if( pCx->zKey ){
- sqliteFree(pCx->zKey);
- pCx->zKey = 0;
- }
- if( pCx->pBt ){
- sqliteBtreeClose(pCx->pBt);
- pCx->pBt = 0;
- }
+ cleanupCursor(&p->aCsr[i]);
}
sqliteFree(p->aCsr);
p->aCsr = 0;
** this array, then copy and paste it into this file, if you want.
*/
static char *zOpName[] = { 0,
- "Transaction", "Commit", "Rollback", "Open",
- "OpenTemp", "Close", "MoveTo", "Fcnt",
- "NewRecno", "Put", "Distinct", "Found",
- "NotFound", "Delete", "Column", "KeyAsData",
- "Recno", "FullKey", "Rewind", "Next",
- "Destroy", "Clear", "CreateIndex", "CreateTable",
- "Reorganize", "BeginIdx", "NextIdx", "PutIdx",
- "DeleteIdx", "MemLoad", "MemStore", "ListOpen",
- "ListWrite", "ListRewind", "ListRead", "ListClose",
- "SortOpen", "SortPut", "SortMakeRec", "SortMakeKey",
- "Sort", "SortNext", "SortKey", "SortCallback",
- "SortClose", "FileOpen", "FileRead", "FileColumn",
- "FileClose", "AggReset", "AggFocus", "AggIncr",
- "AggNext", "AggSet", "AggGet", "SetInsert",
- "SetFound", "SetNotFound", "SetClear", "MakeRecord",
- "MakeKey", "MakeIdxKey", "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",
+ "Transaction", "Commit", "Rollback", "ReadCookie",
+ "SetCookie", "VerifyCookie", "Open", "OpenTemp",
+ "Close", "MoveTo", "Fcnt", "NewRecno",
+ "Put", "Distinct", "Found", "NotFound",
+ "Delete", "Column", "KeyAsData", "Recno",
+ "FullKey", "Rewind", "Next", "Destroy",
+ "Clear", "CreateIndex", "CreateTable", "Reorganize",
+ "BeginIdx", "NextIdx", "PutIdx", "DeleteIdx",
+ "MemLoad", "MemStore", "ListOpen", "ListWrite",
+ "ListRewind", "ListRead", "ListClose", "SortOpen",
+ "SortPut", "SortMakeRec", "SortMakeKey", "Sort",
+ "SortNext", "SortKey", "SortCallback", "SortClose",
+ "FileOpen", "FileRead", "FileColumn", "FileClose",
+ "AggReset", "AggFocus", "AggIncr", "AggNext",
+ "AggSet", "AggGet", "SetInsert", "SetFound",
+ "SetNotFound", "SetClear", "MakeRecord", "MakeKey",
+ "MakeIdxKey", "Goto", "If", "Halt",
+ "ColumnCount", "ColumnName", "Callback", "Integer",
+ "String", "Null", "Pop", "Dup",
+ "Pull", "Add", "AddImm", "Subtract",
+ "Multiply", "Divide", "Min", "Max",
+ "Like", "Glob", "Eq", "Ne",
+ "Lt", "Le", "Gt", "Ge",
+ "IsNull", "NotNull", "Negative", "And",
+ "Or", "Not", "Concat", "Noop",
+ "Strlen", "Substr",
};
/*
break;
}
+/* Opcode: ReadCookie * * *
+**
+** Read the magic cookie from the database file and push it onto the
+** stack. The magic cookie is an integer that is used like a version
+** number for the database schema. Everytime the schema changes, the
+** cookie changes to a new random value. This opcode is used during
+** initialization to read the initial cookie value so that subsequent
+** database accesses can verify that the cookie has not changed.
+**
+** There must be a read-lock on the database (either a transaction
+** must be started or there must be a prior OP_Open opcode) before
+** executing this instruction.
+*/
+case OP_ReadCookie: {
+ int i = ++p->tos;
+ int aMeta[SQLITE_N_BTREE_META];
+ VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
+ rc = sqliteBtreeGetMeta(pBt, aMeta);
+ aStack[i].i = aMeta[1];
+ aStack[i].flags = STK_Int;
+ break;
+}
+
+/* Opcode: SetCookie P1 * *
+**
+** This operation changes the value of the cookie on the database.
+** The new value is P1.
+**
+** The cookie changes its value whenever the database schema changes.
+** That way, other processes can recognize when the schema has changed
+** and reread it.
+**
+** A transaction must be started before executing this opcode.
+*/
+case OP_SetCookie: {
+ int aMeta[SQLITE_N_BTREE_META];
+ rc = sqliteBtreeGetMeta(pBt, aMeta);
+ if( rc==SQLITE_OK ){
+ aMeta[1] = pOp->p1;
+ rc = sqliteBtreeUpdateMeta(pBt, aMeta);
+ }
+ break;
+}
+
+/* Opcode: VerifyCookie P1 * *
+**
+** Check the current value of the database cookie and make sure it is
+** equal to P1. If it is not, abort with an SQLITE_SCHEMA error.
+**
+** The cookie changes its value whenever the database schema changes.
+** This operation is used to detech when that the cookie has changed
+** and that the current process needs to reread the schema.
+**
+** Either a transaction needs to have been started or an OP_Open needs
+** to be executed (to establish a read lock) before this opcode is
+** invoked.
+*/
+case OP_VerifyCookie: {
+ int aMeta[SQLITE_N_BTREE_META];
+ rc = sqliteBtreeGetMeta(pBt, aMeta);
+ if( rc==SQLITE_OK && aMeta[1]!=pOp->p1 ){
+ sqliteSetString(pzErrMsg, "database schema has changed", 0);
+ rc = SQLITE_SCHEMA;
+ }
+ break;
+}
+
/* Opcode: Open P1 P2 P3
**
** Open a new cursor for the database table whose root page is
memset(&p->aCsr[j], 0, sizeof(Cursor));
}
p->nCursor = i+1;
- }else if( p->aCsr[i].pCursor ){
- sqliteBtreeCloseCursor(p->aCsr[i].pCursor);
}
+ cleanupCursor(&p->aCsr[i]);
memset(&p->aCsr[i], 0, sizeof(Cursor));
do{
rc = sqliteBtreeCursor(pBt, p2, &p->aCsr[i].pCursor);
memset(&p->aCsr[j], 0, sizeof(Cursor));
}
p->nCursor = i+1;
- }else if( p->aCsr[i].pCursor ){
- sqliteBtreeCloseCursor(p->aCsr[i].pCursor);
}
pCx = &p->aCsr[i];
+ cleanupCursor(pCx);
memset(pCx, 0, sizeof(*pCx));
rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt);
if( rc==SQLITE_OK ){
case OP_Close: {
int i = pOp->p1;
if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
- Cursor *pCx = &p->aCsr[i];
- sqliteBtreeCloseCursor(pCx->pCursor);
- pCx->pCursor = 0;
- if( pCx->zKey ){
- sqliteFree(pCx->zKey);
- pCx->zKey = 0;
- }
- if( pCx->pBt ){
- sqliteBtreeClose(pCx->pBt);
- pCx->pBt = 0;
- }
+ cleanupCursor(&p->aCsr[i]);
}
break;
}
VERIFY( if( tos<0 ) goto not_enough_stack; )
if( i>=0 && i<p->nCursor && (pCrsr = &p->aCsr[i])->pCursor!=0 ){
if( Stringify(p, tos) ) goto no_mem;
+ if( pCrsr->zKey ) sqliteFree(pCrsr->zKey);
pCrsr->nKey = aStack[tos].n;
pCrsr->zKey = sqliteMalloc( 2*(pCrsr->nKey + 1) );
if( pCrsr->zKey==0 ) goto no_mem;
** 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.21 2001/09/13 21:53:10 drh Exp $
+** $Id: vdbe.h,v 1.22 2001/09/15 00:57:29 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#define OP_Commit 2
#define OP_Rollback 3
-#define OP_Open 4
-#define OP_OpenTemp 5
-#define OP_Close 6
-#define OP_MoveTo 7
-#define OP_Fcnt 8
-#define OP_NewRecno 9
-#define OP_Put 10
-#define OP_Distinct 11
-#define OP_Found 12
-#define OP_NotFound 13
-#define OP_Delete 14
-#define OP_Column 15
-#define OP_KeyAsData 16
-#define OP_Recno 17
-#define OP_FullKey 18
-#define OP_Rewind 19
-#define OP_Next 20
-
-#define OP_Destroy 21
-#define OP_Clear 22
-#define OP_CreateIndex 23
-#define OP_CreateTable 24
-#define OP_Reorganize 25
-
-#define OP_BeginIdx 26
-#define OP_NextIdx 27
-#define OP_PutIdx 28
-#define OP_DeleteIdx 29
-
-#define OP_MemLoad 30
-#define OP_MemStore 31
-
-#define OP_ListOpen 32
-#define OP_ListWrite 33
-#define OP_ListRewind 34
-#define OP_ListRead 35
-#define OP_ListClose 36
-
-#define OP_SortOpen 37
-#define OP_SortPut 38
-#define OP_SortMakeRec 39
-#define OP_SortMakeKey 40
-#define OP_Sort 41
-#define OP_SortNext 42
-#define OP_SortKey 43
-#define OP_SortCallback 44
-#define OP_SortClose 45
-
-#define OP_FileOpen 46
-#define OP_FileRead 47
-#define OP_FileColumn 48
-#define OP_FileClose 49
-
-#define OP_AggReset 50
-#define OP_AggFocus 51
-#define OP_AggIncr 52
-#define OP_AggNext 53
-#define OP_AggSet 54
-#define OP_AggGet 55
-
-#define OP_SetInsert 56
-#define OP_SetFound 57
-#define OP_SetNotFound 58
-#define OP_SetClear 59
-
-#define OP_MakeRecord 60
-#define OP_MakeKey 61
-#define OP_MakeIdxKey 62
-
-#define OP_Goto 63
-#define OP_If 64
-#define OP_Halt 65
-
-#define OP_ColumnCount 66
-#define OP_ColumnName 67
-#define OP_Callback 68
-
-#define OP_Integer 69
-#define OP_String 70
-#define OP_Null 71
-#define OP_Pop 72
-#define OP_Dup 73
-#define OP_Pull 74
-
-#define OP_Add 75
-#define OP_AddImm 76
-#define OP_Subtract 77
-#define OP_Multiply 78
-#define OP_Divide 79
-#define OP_Min 80
-#define OP_Max 81
-#define OP_Like 82
-#define OP_Glob 83
-#define OP_Eq 84
-#define OP_Ne 85
-#define OP_Lt 86
-#define OP_Le 87
-#define OP_Gt 88
-#define OP_Ge 89
-#define OP_IsNull 90
-#define OP_NotNull 91
-#define OP_Negative 92
-#define OP_And 93
-#define OP_Or 94
-#define OP_Not 95
-#define OP_Concat 96
-#define OP_Noop 97
-
-#define OP_Strlen 98
-#define OP_Substr 99
-
-#define OP_MAX 99
+#define OP_ReadCookie 4
+#define OP_SetCookie 5
+#define OP_VerifyCookie 6
+
+#define OP_Open 7
+#define OP_OpenTemp 8
+#define OP_Close 9
+#define OP_MoveTo 10
+#define OP_Fcnt 11
+#define OP_NewRecno 12
+#define OP_Put 13
+#define OP_Distinct 14
+#define OP_Found 15
+#define OP_NotFound 16
+#define OP_Delete 17
+#define OP_Column 18
+#define OP_KeyAsData 19
+#define OP_Recno 20
+#define OP_FullKey 21
+#define OP_Rewind 22
+#define OP_Next 23
+
+#define OP_Destroy 24
+#define OP_Clear 25
+#define OP_CreateIndex 26
+#define OP_CreateTable 27
+#define OP_Reorganize 28
+
+#define OP_BeginIdx 29
+#define OP_NextIdx 30
+#define OP_PutIdx 31
+#define OP_DeleteIdx 32
+
+#define OP_MemLoad 33
+#define OP_MemStore 34
+
+#define OP_ListOpen 35
+#define OP_ListWrite 36
+#define OP_ListRewind 37
+#define OP_ListRead 38
+#define OP_ListClose 39
+
+#define OP_SortOpen 40
+#define OP_SortPut 41
+#define OP_SortMakeRec 42
+#define OP_SortMakeKey 43
+#define OP_Sort 44
+#define OP_SortNext 45
+#define OP_SortKey 46
+#define OP_SortCallback 47
+#define OP_SortClose 48
+
+#define OP_FileOpen 49
+#define OP_FileRead 50
+#define OP_FileColumn 51
+#define OP_FileClose 52
+
+#define OP_AggReset 53
+#define OP_AggFocus 54
+#define OP_AggIncr 55
+#define OP_AggNext 56
+#define OP_AggSet 57
+#define OP_AggGet 58
+
+#define OP_SetInsert 59
+#define OP_SetFound 60
+#define OP_SetNotFound 61
+#define OP_SetClear 62
+
+#define OP_MakeRecord 63
+#define OP_MakeKey 64
+#define OP_MakeIdxKey 65
+
+#define OP_Goto 66
+#define OP_If 67
+#define OP_Halt 68
+
+#define OP_ColumnCount 69
+#define OP_ColumnName 70
+#define OP_Callback 71
+
+#define OP_Integer 72
+#define OP_String 73
+#define OP_Null 74
+#define OP_Pop 75
+#define OP_Dup 76
+#define OP_Pull 77
+
+#define OP_Add 78
+#define OP_AddImm 79
+#define OP_Subtract 80
+#define OP_Multiply 81
+#define OP_Divide 82
+#define OP_Min 83
+#define OP_Max 84
+#define OP_Like 85
+#define OP_Glob 86
+#define OP_Eq 87
+#define OP_Ne 88
+#define OP_Lt 89
+#define OP_Le 90
+#define OP_Gt 91
+#define OP_Ge 92
+#define OP_IsNull 93
+#define OP_NotNull 94
+#define OP_Negative 95
+#define OP_And 96
+#define OP_Or 97
+#define OP_Not 98
+#define OP_Concat 99
+#define OP_Noop 100
+
+#define OP_Strlen 101
+#define OP_Substr 102
+
+#define OP_MAX 102
/*
** Prototypes for the VDBE interface. See comments on the implementation
** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
-** $Id: where.c,v 1.18 2001/09/13 16:18:55 drh Exp $
+** $Id: where.c,v 1.19 2001/09/15 00:57:29 drh Exp $
*/
#include "sqliteInt.h"
for(i=0; i<pTabList->nId; i++){
sqliteVdbeAddOp(v, OP_Open, base+i, pTabList->a[i].pTab->tnum,
pTabList->a[i].pTab->zName, 0);
+ if( i==0 && !pParse->schemaVerified &&
+ (pParse->db->flags & SQLITE_InTrans)==0 ){
+ sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0);
+ pParse->schemaVerified = 1;
+ }
if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
sqliteVdbeAddOp(v, OP_Open, base+pTabList->nId+i, aIdx[i]->tnum,
aIdx[i]->zName, 0);