]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Everything is working on Linux. This is release 2.0-Alpha-1. (CVS 246)
authordrh <drh@noemail.net>
Sat, 15 Sep 2001 00:57:28 +0000 (00:57 +0000)
committerdrh <drh@noemail.net>
Sat, 15 Sep 2001 00:57:28 +0000 (00:57 +0000)
FossilOrigin-Name: 14474fa144fe7c5dc63e0990d6cc92d769e6013e

15 files changed:
manifest
manifest.uuid
src/TODO
src/build.c
src/delete.c
src/insert.c
src/main.c
src/pager.c
src/sqlite.h.in
src/sqliteInt.h
src/update.c
src/util.c
src/vdbe.c
src/vdbe.h
src/where.c

index bcf51987e84ab12b8c27e2be0bc25b61a9210685..5e0c6287e84d863c89fbd84e35a4c599bb350043 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
@@ -12,11 +12,11 @@ F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464
 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
@@ -26,10 +26,10 @@ F src/ex/pg.c 2bbf6a94f37226d06337868b6bf4d7affc60197f
 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
@@ -37,19 +37,19 @@ F src/random.c b626726c4f0066610739e52e7431adae7ccd9651
 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
@@ -107,7 +107,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
 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
index af847db2fcd23cc64935240baf2a506aede3a046..29687e51d541791e1056bb2c56cfeed645af6c46 100644 (file)
@@ -1 +1 @@
-5e3724603e6f52bb74deb1c62e6e8f323d7b64b7
\ No newline at end of file
+14474fa144fe7c5dc63e0990d6cc92d769e6013e
\ No newline at end of file
index fcfd5921800673780910d0e47934fdc3da4201c2..bc0b6bae3eaedaf7f0a53478def1fee83dade810 100644 (file)
--- a/src/TODO
+++ b/src/TODO
@@ -3,5 +3,4 @@
   *  "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.
index 9befe97cf90937899299a641e311a7211e78909c..eb9ea05a0f19202329a8e8f5cb2c1276599cbcb5 100644 (file)
@@ -33,7 +33,7 @@
 **     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>
@@ -67,6 +67,7 @@ void sqliteExec(Parse *pParse){
     pParse->pVdbe = 0;
     pParse->colNamesSet = 0;
     pParse->rc = rc;
+    pParse->schemaVerified = 0;
   }
 }
 
@@ -278,6 +279,7 @@ static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *pTable){
 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){
@@ -314,6 +316,7 @@ void sqliteCommitInternalChanges(sqlite *db){
 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){
@@ -398,6 +401,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
     Vdbe *v = sqliteGetVdbe(pParse);
     if( v ){
       sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
     }
   }
 }
@@ -450,6 +454,30 @@ void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){
   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.
@@ -503,6 +531,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
       { 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;
@@ -515,6 +544,8 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
     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
@@ -586,15 +617,19 @@ void sqliteDropTable(Parse *pParse, Token *pName){
       { 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);
     }
@@ -772,6 +807,7 @@ void sqliteCreateIndex(
       { 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;
@@ -783,6 +819,7 @@ void sqliteCreateIndex(
     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;
@@ -793,6 +830,8 @@ void sqliteCreateIndex(
       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);
@@ -861,16 +900,20 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
       { 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);
     }
@@ -1037,6 +1080,7 @@ void sqliteCopy(
   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);
@@ -1109,6 +1153,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){
   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);
@@ -1147,6 +1192,7 @@ void sqliteBeginTransaction(Parse *pParse){
   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;
 }
index 523bc2ec049c417f1c42040d68d62f9868134fae..3d2cff99b25c825d28aacb4a7d6ba352531fd0f0 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.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"
 
@@ -92,6 +92,7 @@ void sqliteDeleteFrom(
   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);
   }
 
 
index b8f110c62bc5043002dc35291536ce07eaa710e7..28a13cdd01c59d488348cffadaa02e76f385a439 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements.
 **
-** $Id: insert.c,v 1.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"
 
@@ -87,6 +87,7 @@ void sqliteInsert(
   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
index cbbe5dc8f7dbb8d9a800ef22a8a660b0e34e1f89..e3863e2131562ad730293057f565b9b642d33709 100644 (file)
@@ -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.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
@@ -51,7 +51,12 @@ static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
   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':
@@ -170,7 +175,12 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
     { 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},
   };
 
@@ -281,11 +291,16 @@ no_mem_on_open:
 }
 
 /*
-** 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;
@@ -296,6 +311,15 @@ void sqlite_close(sqlite *db){
       pList = pNext;
     }
   }
+  db->flags &= ~SQLITE_Initialized;
+}
+
+/*
+** Close an existing SQLite database
+*/
+void sqlite_close(sqlite *db){
+  sqliteBtreeClose(db->pBe);
+  clearHashTable(db);
   sqliteFree(db);
 }
 
@@ -387,6 +411,9 @@ int sqlite_exec(
     sParse.rc = SQLITE_NOMEM;
   }
   sqliteStrRealloc(pzErrMsg);
+  if( sParse.rc==SQLITE_SCHEMA ){
+    clearHashTable(db);
+  }
   return sParse.rc;
 }
 
index 8d4f9696d93ec4ae046511d6d88882a30acd6fc3..4ca2b20a1793fbdf116be39100644c7b939dbac9 100644 (file)
@@ -27,7 +27,7 @@
 ** 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"
@@ -683,6 +683,28 @@ int sqlitepager_ref(void *pData){
   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.
 **
@@ -791,15 +813,28 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
       /* 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 ){
@@ -825,6 +860,8 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
           return rc;
         }
       }
+#endif
+      assert( pPg->dirty==0 );
 
       /* Unlink the old page from the free list and the hash table
       */
index d8baf6beae9d926d0646a3aca9796cfbf664d116..60aa491bf24ebb555139d4d66177dfb2ad1cf29a 100644 (file)
@@ -24,7 +24,7 @@
 ** This header file defines the interface that the sqlite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.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_
@@ -160,6 +160,7 @@ int sqlite_exec(
 #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
index 7a69341358931f79c7611c9f9b3ea26af88396fb..134653bc7fc2fa453ae75615fa1899b6cb712fa3 100644 (file)
@@ -23,7 +23,7 @@
 *************************************************************************
 ** 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"
@@ -143,6 +143,8 @@ struct sqlite {
   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 */
@@ -376,6 +378,8 @@ struct Parse {
   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 */
 };
 
 /*
index ccdecc9c07a1ecb4d0eccb5c28e8a3d90465885b..d84aaa5b9b31d0161a4322293b62c18b0900fd7b 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.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"
 
@@ -146,6 +146,7 @@ void sqliteUpdate(
   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
index 77e854fad9def01b8bb6966882816de3a6cc8566..b894f2300ae07fcb86f4fb6791d943d247db6b4e 100644 (file)
@@ -26,7 +26,7 @@
 ** 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>
@@ -978,25 +978,26 @@ sqliteLikeCompare(const unsigned char *zPattern, const unsigned char *zString){
 ** 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;
 }
index 604fa93605874572ddae1fc4e18f42418a4794bf..e25dca46466d828110cb16ff509fe0111b49f200 100644 (file)
@@ -41,7 +41,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.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>
@@ -759,6 +759,23 @@ static void KeylistFree(Keylist *p){
   }
 }
 
+/*
+** 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.
 **
@@ -771,19 +788,7 @@ static void Cleanup(Vdbe *p){
   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;
@@ -871,31 +876,32 @@ void sqliteVdbeDelete(Vdbe *p){
 ** 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",          
 };
 
 /*
@@ -1974,6 +1980,73 @@ case OP_Rollback: {
   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
@@ -2013,9 +2086,8 @@ case OP_Open: {
       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);
@@ -2058,10 +2130,9 @@ case OP_OpenTemp: {
       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 ){
@@ -2081,17 +2152,7 @@ case OP_OpenTemp: {
 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;
 }
@@ -2523,6 +2584,7 @@ case OP_BeginIdx: {
   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;
index cbf7e08c971ff0b53c189dfc57815ad5a8292bcb..46ebf99555033ba100eea57592024f5451567f98 100644 (file)
@@ -27,7 +27,7 @@
 ** or VDBE.  The VDBE implements an abstract machine that runs a
 ** simple program to access and modify the underlying database.
 **
-** $Id: vdbe.h,v 1.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_
@@ -75,118 +75,122 @@ typedef struct VdbeOp VdbeOp;
 #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
index 91ffa143eeff95c98b749bec6faf164cfb807e8a..bc99942d655a43a83bba2a343551fd384d5a157a 100644 (file)
@@ -25,7 +25,7 @@
 ** the WHERE clause of SQL statements.  Also found here are subroutines
 ** to generate VDBE code to evaluate expressions.
 **
-** $Id: where.c,v 1.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"
 
@@ -299,6 +299,11 @@ WhereInfo *sqliteWhereBegin(
   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);