Modifications and bugfixes so that the test suite passes with the TCL statement cache turned on. (CVS 2271)

FossilOrigin-Name: d5233e0747789dea04d35a8350b408321d23a64d
diff --git a/src/attach.c b/src/attach.c
index f0bdc7a..095d2ab 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to implement the ATTACH and DETACH commands.
 **
-** $Id: attach.c,v 1.30 2005/01/23 13:14:55 drh Exp $
+** $Id: attach.c,v 1.31 2005/01/24 10:25:59 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -38,6 +38,7 @@
 
   v = sqlite3GetVdbe(pParse);
   if( !v ) return;
+  sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
   sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
   if( pParse->explain ) return;
   db = pParse->db;
@@ -126,7 +127,6 @@
   }
 #endif
   sqliteFree(zFile);
-  sqlite3ExpirePreparedStatements(db);
   db->flags &= ~SQLITE_Initialized;
   if( pParse->nErr==0 && rc==SQLITE_OK ){
     rc = sqlite3ReadSchema(pParse);
@@ -161,6 +161,7 @@
 
   v = sqlite3GetVdbe(pParse);
   if( !v ) return;
+  sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
   sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
   if( pParse->explain ) return;
   db = pParse->db;
@@ -191,7 +192,6 @@
   sqlite3BtreeClose(pDb->pBt);
   pDb->pBt = 0;
   sqlite3ResetInternalSchema(db, 0);
-  sqlite3ExpirePreparedStatements(db);
 }
 
 /*
diff --git a/src/build.c b/src/build.c
index 8b238ce..5d7111d 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.297 2005/01/21 11:55:27 danielk1977 Exp $
+** $Id: build.c,v 1.298 2005/01/24 10:25:59 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -760,12 +760,21 @@
     ** The rowid value is needed by the code that sqlite3EndTable will
     ** generate.
     */
+#ifndef SQLITE_OMIT_VIEW
+    if( isView ){
+      sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
+    }else
+#endif
+    {
+      sqlite3VdbeAddOp(v, OP_CreateTable, iDb, 0);
+    }
     sqlite3OpenMasterTable(v, iDb);
     sqlite3VdbeAddOp(v, OP_NewRecno, 0, 0);
     sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
     sqlite3VdbeAddOp(v, OP_String8, 0, 0);
     sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
     sqlite3VdbeAddOp(v, OP_Close, 0, 0);
+    sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
   }
 
   /* Normal (non-error) return. */
@@ -1404,13 +1413,13 @@
     */
     if( p->pSelect==0 ){
       /* A regular table */
-      sqlite3VdbeAddOp(v, OP_CreateTable, p->iDb, 0);
+      /* sqlite3VdbeAddOp(v, OP_CreateTable, p->iDb, 0); */
       zType = "table";
       zType2 = "TABLE";
 #ifndef SQLITE_OMIT_VIEW
     }else{
       /* A view */
-      sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
+    /*  sqlite3VdbeAddOp(v, OP_Integer, 0, 0); */
       zType = "view";
       zType2 = "VIEW";
 #endif
@@ -1884,9 +1893,11 @@
       destroyTable(pParse, pTab);
     }
 
-    /* Remove the table entry from SQLite's internal schema
+    /* Remove the table entry from SQLite's internal schema and modify
+    ** the schema cookie.
     */
     sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
+    sqlite3ChangeCookie(db, v, iDb);
   }
   sqliteViewResetAll(db, iDb);
 
@@ -2200,7 +2211,7 @@
         goto exit_create_index;
       }
     }
-  }else if( pName==0 ){
+  }else{
     char zBuf[30];
     int n;
     Index *pLoop;
@@ -2403,13 +2414,15 @@
     sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
     sqliteFree(zStmt);
 
-    /* Fill the index with data and reparse the schema
+    /* Fill the index with data and reparse the schema. Code an OP_Expire
+    ** to invalidate all pre-compiled statements.
     */
     if( pTblName ){
       sqlite3RefillIndex(pParse, pIndex, iMem);
       sqlite3ChangeCookie(db, v, iDb);
       sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
          sqlite3MPrintf("name='%q'", pIndex->zName), P3_DYNAMIC);
+      sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
     }
   }
 
diff --git a/src/main.c b/src/main.c
index e2ffd31..9ab3d75 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.273 2005/01/21 08:13:15 danielk1977 Exp $
+** $Id: main.c,v 1.274 2005/01/24 10:25:59 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -1287,6 +1287,14 @@
     );
     return SQLITE_ERROR;
   }
+
+  /* If removing a collation sequence, then set the expired flag for
+  ** all precompiled statements.
+  */
+  if( !xCompare ){
+    sqlite3ExpirePreparedStatements(db);
+  }
+
   pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
   if( 0==pColl ){
    rc = SQLITE_NOMEM;
diff --git a/src/pragma.c b/src/pragma.c
index 890cc39..0f3a502 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to implement the PRAGMA command.
 **
-** $Id: pragma.c,v 1.85 2005/01/22 03:03:54 drh Exp $
+** $Id: pragma.c,v 1.86 2005/01/24 10:25:59 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -155,18 +155,21 @@
     if( sqlite3StrICmp(zLeft, p->zName)==0 ){
       sqlite3 *db = pParse->db;
       Vdbe *v;
-      if( zRight==0 ){
-        v = sqlite3GetVdbe(pParse);
-        if( v ){
+      v = sqlite3GetVdbe(pParse);
+      if( v ){
+        if( zRight==0 ){
           returnSingleInt(pParse, p->zName, (db->flags & p->mask)!=0 );
-        }
-      }else{
-        if( getBoolean(zRight) ){
-          db->flags |= p->mask;
         }else{
-          db->flags &= ~p->mask;
+          if( getBoolean(zRight) ){
+            db->flags |= p->mask;
+          }else{
+            db->flags &= ~p->mask;
+          }
         }
-        sqlite3ExpirePreparedStatements(db);
+        /* If one of these pragmas is executed, any prepared statements
+        ** need to be recompiled.
+        */
+        sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
       }
       return 1;
     }
@@ -896,6 +899,14 @@
 #endif
 
   {}
+
+  if( v ){
+    /* Code an OP_Expire at the end of each PRAGMA program to cause
+    ** the VDBE implementing the pragma to expire. Most (all?) pragmas
+    ** are only valid for a single execution.
+    */
+    sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
+  }
 pragma_out:
   sqliteFree(zLeft);
   sqliteFree(zRight);
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 177ad40..dc05eab 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** A TCL Interface to SQLite
 **
-** $Id: tclsqlite.c,v 1.116 2005/01/24 00:28:43 drh Exp $
+** $Id: tclsqlite.c,v 1.117 2005/01/24 10:25:59 danielk1977 Exp $
 */
 #ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */
 
@@ -22,7 +22,7 @@
 #include <string.h>
 #include <assert.h>
 
-#define NUM_PREPARED_STMTS 0
+#define NUM_PREPARED_STMTS 10
 #define MAX_PREPARED_STMTS 100
 
 /*
diff --git a/src/vdbe.c b/src/vdbe.c
index 69b5c94..e581d1c 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.445 2005/01/21 08:13:15 danielk1977 Exp $
+** $Id: vdbe.c,v 1.446 2005/01/24 10:25:59 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -4495,6 +4495,24 @@
 }
 #endif /* SQLITE_OMIT_CURSOR */
 
+/* Opcode: Expire P1 * *
+**
+** Cause precompiled statements to become expired. An expired statement
+** fails with an error code of SQLITE_SCHEMA if it is ever executed 
+** (via sqlite3_step()).
+** 
+** If P1 is 0, then all SQL statements become expired. If P1 is non-zero,
+** then only the currently executing statement is affected. 
+*/
+case OP_Expire: {
+  if( !pOp->p1 ){
+    sqlite3ExpirePreparedStatements(db);
+  }else{
+    p->expired = 1;
+  }
+  break;
+}
+
 
 
 /* An other opcode is illegal...
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 348925a..ca16128 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -163,6 +163,12 @@
   if( p->aborted ){
     return SQLITE_ABORT;
   }
+  if( p->pc<=0 && p->expired ){
+    if( p->rc==SQLITE_OK ){
+      p->rc = SQLITE_SCHEMA;
+    }
+    return SQLITE_ERROR;
+  }
   db = p->db;
   if( sqlite3SafetyOn(db) ){
     p->rc = SQLITE_MISUSE;
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index aa45de8..aedc305 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1302,6 +1302,12 @@
     }else{
       sqlite3Error(p->db, SQLITE_OK, 0);
     }
+  }else if( p->rc && p->expired ){
+    /* The expired flag was set on the VDBE before the first call
+    ** to sqlite3_step(). For consistency (since sqlite3_step() was
+    ** called), set the database error in this case as well.
+    */
+    sqlite3Error(p->db, p->rc, 0);
   }
 
   /* Reclaim all memory used by the VDBE