Progress towards getting prepared statements and CREATE and DROP to play
nicely together.  Work is incomplete.  Some tests are known to fail. (CVS 1864)

FossilOrigin-Name: 49b991492496e104f5eca620a5d465a742b7ff3a
diff --git a/src/build.c b/src/build.c
index 7f27985..09427a9 100644
--- a/src/build.c
+++ b/src/build.c
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.240 2004/07/22 01:19:35 drh Exp $
+** $Id: build.c,v 1.241 2004/07/24 03:30:48 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -231,8 +231,8 @@
 
 /*
 ** Erase all schema information from the in-memory hash tables of
-** a sigle database.  This routine is called to reclaim memory
-** before the closes.  It is also called during a rollback
+** a single database.  This routine is called to reclaim memory
+** before the database closes.  It is also called during a rollback
 ** if there were schema changes during the transaction or if a
 ** schema-cookie mismatch occurs.
 **
@@ -1169,14 +1169,16 @@
 ** Measure the number of characters needed to output the given
 ** identifier.  The number returned includes any quotes used
 ** but does not include the null terminator.
+**
+** The estimate is conservative.  It might be larger that what is
+** really needed.
 */
 static int identLength(const char *z){
   int n;
-  int needQuote = 0;
   for(n=0; *z; n++, z++){
-    if( *z=='\'' ){ n++; needQuote=1; }
+    if( *z=='"' ){ n++; }
   }
-  return n + needQuote*2;
+  return n + 2;
 }
 
 /*
@@ -1191,12 +1193,12 @@
   }
   needQuote =  zIdent[j]!=0 || isdigit(zIdent[0])
                   || sqlite3KeywordCode(zIdent, j)!=TK_ID;
-  if( needQuote ) z[i++] = '\'';
+  if( needQuote ) z[i++] = '"';
   for(j=0; zIdent[j]; j++){
     z[i++] = zIdent[j];
-    if( zIdent[j]=='\'' ) z[i++] = '\'';
+    if( zIdent[j]=='"' ) z[i++] = '"';
   }
-  if( needQuote ) z[i++] = '\'';
+  if( needQuote ) z[i++] = '"';
   z[i] = 0;
   *pIdx = i;
 }
@@ -1209,16 +1211,18 @@
 static char *createTableStmt(Table *p){
   int i, k, n;
   char *zStmt;
-  char *zSep, *zSep2, *zEnd;
+  char *zSep, *zSep2, *zEnd, *z;
+  Column *pCol;
   n = 0;
-  for(i=0; i<p->nCol; i++){
-    n += identLength(p->aCol[i].zName);
-    if( p->aCol[i].zType ){
-      n += (strlen(p->aCol[i].zType) + 1);
+  for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){
+    n += identLength(pCol->zName);
+    z = pCol->zType;
+    if( z ){
+      n += (strlen(z) + 1);
     }
   }
   n += identLength(p->zName);
-  if( n<40 ){
+  if( n<50 ){
     zSep = "";
     zSep2 = ",";
     zEnd = ")";
@@ -1234,15 +1238,15 @@
   k = strlen(zStmt);
   identPut(zStmt, &k, p->zName);
   zStmt[k++] = '(';
-  for(i=0; i<p->nCol; i++){
+  for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
     strcpy(&zStmt[k], zSep);
     k += strlen(&zStmt[k]);
     zSep = zSep2;
-    identPut(zStmt, &k, p->aCol[i].zName);
-    if( p->aCol[i].zType ){
+    identPut(zStmt, &k, pCol->zName);
+    if( (z = pCol->zType)!=0 ){
       zStmt[k++] = ' ';
-      strcpy(&zStmt[k], p->aCol[i].zType);
-      k += strlen(p->aCol[i].zType);
+      strcpy(&zStmt[k], z);
+      k += strlen(z);
     }
   }
   strcpy(&zStmt[k], zEnd);
@@ -1305,12 +1309,11 @@
 
     if( p->pSelect==0 ){
       /* A regular table */
-      sqlite3VdbeOp3(v, OP_CreateTable, 0, p->iDb, (char*)&p->tnum, P3_POINTER);
+      sqlite3VdbeAddOp(v, OP_CreateTable, p->iDb, 0);
     }else{
       /* A view */
       sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
     }
-    p->tnum = 0;
 
     sqlite3VdbeAddOp(v, OP_Close, 0, 0);
 
@@ -1371,13 +1374,15 @@
     sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
     sqlite3ChangeCookie(db, v, p->iDb);
     sqlite3VdbeAddOp(v, OP_Close, 0, 0);
+    sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0,
+        sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC);
 
     sqlite3EndWriteOperation(pParse);
   }
 
   /* Add the table to the in-memory representation of the database.
   */
-  if( pParse->explain==0 && pParse->nErr==0 ){
+  if( db->init.busy && pParse->nErr==0 ){
     Table *pOld;
     FKey *pFKey;
     pOld = sqlite3HashInsert(&db->aDb[p->iDb].tblHash, 
@@ -1565,26 +1570,6 @@
   DbClearProperty(db, idx, DB_UnresetViews);
 }
 
-#if 0
-/*
-** Given a token, look up a table with that name.  If not found, leave
-** an error for the parser to find and return NULL.
-*/
-Table *sqlite3TableFromToken(Parse *pParse, Token *pTok){
-  char *zName;
-  Table *pTab;
-  zName = sqlite3NameFromToken(pTok);
-  if( zName==0 ) return 0;
-  pTab = sqlite3FindTable(pParse->db, zName, 0);
-  sqliteFree(zName);
-  if( pTab==0 ){
-    sqlite3ErrorMsg(pParse, "no such table: %T", pTok);
-    pParse->checkSchema = 1;
-  }
-  return pTab;
-}
-#endif
-
 /*
 ** This routine is called to do the work of a DROP TABLE statement.
 ** pName is the name of the table to be dropped.
@@ -2099,7 +2084,7 @@
   /* Link the new Index structure to its table and to the other
   ** in-memory database structures. 
   */
-  if( !pParse->explain ){
+  if( db->init.busy ){
     Index *p;
     p = sqlite3HashInsert(&db->aDb[pIndex->iDb].idxHash, 
                          pIndex->zName, strlen(pIndex->zName)+1, pIndex);
@@ -2108,14 +2093,9 @@
       goto exit_create_index;
     }
     db->flags |= SQLITE_InternChanges;
-  }
-
-  /* If the db->init.busy is 1 it means we are reading the SQL off the
-  ** "sqlite_master" table on the disk.  So do not write to the disk
-  ** again.  Extract the table number from the db->init.newTnum field.
-  */
-  if( db->init.busy && pTblName!=0 ){
-    pIndex->tnum = db->init.newTnum;
+    if( pTblName!=0 ){
+      pIndex->tnum = db->init.newTnum;
+    }
   }
 
   /* If the db->init.busy is 0 then create the index on disk.  This
@@ -2148,8 +2128,7 @@
     sqlite3VdbeOp3(v, OP_String8, 0, 0, "index", P3_STATIC);
     sqlite3VdbeOp3(v, OP_String8, 0, 0, pIndex->zName, 0);
     sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
-    sqlite3VdbeOp3(v, OP_CreateIndex, 0, iDb,(char*)&pIndex->tnum,P3_POINTER);
-    pIndex->tnum = 0;
+    sqlite3VdbeAddOp(v, OP_CreateIndex, iDb, 0);
     if( pTblName ){
       sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
       sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
@@ -2185,11 +2164,11 @@
       sqlite3VdbeResolveLabel(v, lbl2);
       sqlite3VdbeAddOp(v, OP_Close, 2, 0);
       sqlite3VdbeAddOp(v, OP_Close, 1, 0);
-    }
-    if( pTblName!=0 ){
       sqlite3ChangeCookie(db, v, iDb);
       sqlite3VdbeAddOp(v, OP_Close, 0, 0);
       sqlite3EndWriteOperation(pParse);
+      sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
+         sqlite3MPrintf("name='%q'", pIndex->zName), P3_DYNAMIC);
     }
   }
 
@@ -2198,19 +2177,21 @@
   ** OE_Ignore.  This is necessary for the correct operation of UPDATE
   ** and INSERT.
   */
-  if( onError!=OE_Replace || pTab->pIndex==0
-       || pTab->pIndex->onError==OE_Replace){
-    pIndex->pNext = pTab->pIndex;
-    pTab->pIndex = pIndex;
-  }else{
-    Index *pOther = pTab->pIndex;
-    while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
-      pOther = pOther->pNext;
+  if( db->init.busy || pTblName==0 ){
+    if( onError!=OE_Replace || pTab->pIndex==0
+         || pTab->pIndex->onError==OE_Replace){
+      pIndex->pNext = pTab->pIndex;
+      pTab->pIndex = pIndex;
+    }else{
+      Index *pOther = pTab->pIndex;
+      while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
+        pOther = pOther->pNext;
+      }
+      pIndex->pNext = pOther->pNext;
+      pOther->pNext = pIndex;
     }
-    pIndex->pNext = pOther->pNext;
-    pOther->pNext = pIndex;
+    pIndex = 0;
   }
-  pIndex = 0;
 
   /* Clean up before exiting */
 exit_create_index:
@@ -2244,13 +2225,6 @@
       "or PRIMARY KEY constraint cannot be dropped", 0);
     goto exit_drop_index;
   }
-/*
-  if( pIndex->iDb>1 ){
-    sqlite3ErrorMsg(pParse, "cannot alter schema of attached "
-       "databases", 0);
-    goto exit_drop_index;
-  }
-*/
 #ifndef SQLITE_OMIT_AUTHORIZATION
   {
     int code = SQLITE_DROP_INDEX;
@@ -2272,7 +2246,7 @@
   if( v ){
     static VdbeOpList dropIndex[] = {
       { OP_Rewind,     0, ADDR(9), 0}, 
-      { OP_String8,     0, 0,       0}, /* 1 */
+      { OP_String8,    0, 0,       0}, /* 1 */
       { OP_MemStore,   1, 1,       0},
       { OP_MemLoad,    1, 0,       0}, /* 3 */
       { OP_Column,     0, 1,       0},
diff --git a/src/main.c b/src/main.c
index 24a4c19..f6cce31 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,22 +14,13 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.246 2004/07/22 01:19:35 drh Exp $
+** $Id: main.c,v 1.247 2004/07/24 03:30:48 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
 #include <ctype.h>
 
 /*
-** A pointer to this structure is used to communicate information
-** from sqlite3Init into the sqlite3InitCallback.
-*/
-typedef struct {
-  sqlite *db;         /* The database being initialized */
-  char **pzErrMsg;    /* Error message stored here */
-} InitData;
-
-/*
 ** The following constant value is used by the SQLITE_BIGENDIAN and
 ** SQLITE_LITTLEENDIAN macros.
 */
@@ -49,89 +40,69 @@
 /*
 ** This is the callback routine for the code that initializes the
 ** database.  See sqlite3Init() below for additional information.
+** This routine is also called from the OP_ParseSchema opcode of the VDBE.
 **
 ** Each callback contains the following information:
 **
-**     argv[0] = "table" or "index" or "view" or "trigger"
-**     argv[1] = name of thing being created
-**     argv[2] = root page number for table or index.  NULL for trigger or view.
-**     argv[3] = SQL text for the CREATE statement.
-**     argv[4] = "1" for temporary files, "0" for main database, "2" or more
+**     argv[0] = name of thing being created
+**     argv[1] = root page number for table or index.  NULL for trigger or view.
+**     argv[2] = SQL text for the CREATE statement.
+**     argv[3] = "1" for temporary files, "0" for main database, "2" or more
 **               for auxiliary database files.
 **
 */
-static
 int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
   InitData *pData = (InitData*)pInit;
-  int nErr = 0;
+  sqlite *db = pData->db;
+  int iDb;
 
-  assert( argc==5 );
+  assert( argc==4 );
   if( argv==0 ) return 0;   /* Might happen if EMPTY_RESULT_CALLBACKS are on */
-  if( argv[0]==0 ){
+  if( argv[1]==0 || argv[3]==0 ){
     corruptSchema(pData, 0);
     return 1;
   }
-  switch( argv[0][0] ){
-    case 'v':
-    case 'i':
-    case 't': {  /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
-      sqlite *db = pData->db;
-      if( argv[2]==0 || argv[4]==0 ){
-        corruptSchema(pData, 0);
-        return 1;
-      }
-      if( argv[3] && argv[3][0] ){
-        /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
-        ** But because db->init.busy is set to 1, no VDBE code is generated
-        ** or executed.  All the parser does is build the internal data
-        ** structures that describe the table, index, or view.
-        */
-        char *zErr;
-        int rc;
-        assert( db->init.busy );
-        db->init.iDb = atoi(argv[4]);
-        assert( db->init.iDb>=0 && db->init.iDb<db->nDb );
-        db->init.newTnum = atoi(argv[2]);
-        rc = sqlite3_exec(db, argv[3], 0, 0, &zErr);
-        db->init.iDb = 0;
-        if( SQLITE_OK!=rc ){
-          corruptSchema(pData, zErr);
-          sqlite3_free(zErr);
-          return rc;
-        }
-      }else{
-        /* If the SQL column is blank it means this is an index that
-        ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
-        ** constraint for a CREATE TABLE.  The index should have already
-        ** been created when we processed the CREATE TABLE.  All we have
-        ** to do here is record the root page number for that index.
-        */
-        int iDb;
-        Index *pIndex;
-
-        iDb = atoi(argv[4]);
-        assert( iDb>=0 && iDb<db->nDb );
-        pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zName);
-        if( pIndex==0 || pIndex->tnum!=0 ){
-          /* This can occur if there exists an index on a TEMP table which
-          ** has the same name as another index on a permanent index.  Since
-          ** the permanent table is hidden by the TEMP table, we can also
-          ** safely ignore the index on the permanent table.
-          */
-          /* Do Nothing */;
-        }else{
-          pIndex->tnum = atoi(argv[2]);
-        }
-      }
+  iDb = atoi(argv[3]);
+  assert( iDb>=0 && iDb<db->nDb );
+  if( argv[2] && argv[2][0] ){
+    /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
+    ** But because db->init.busy is set to 1, no VDBE code is generated
+    ** or executed.  All the parser does is build the internal data
+    ** structures that describe the table, index, or view.
+    */
+    char *zErr;
+    int rc;
+    assert( db->init.busy );
+    db->init.iDb = iDb;
+    db->init.newTnum = atoi(argv[1]);
+    rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
+    db->init.iDb = 0;
+    if( SQLITE_OK!=rc ){
+      corruptSchema(pData, zErr);
+      sqlite3_free(zErr);
+      return rc;
     }
-    break;
-    default: {
-      /* This can not happen! */
-      nErr = 1;
-      assert( nErr==0 );
+  }else{
+    /* If the SQL column is blank it means this is an index that
+    ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
+    ** constraint for a CREATE TABLE.  The index should have already
+    ** been created when we processed the CREATE TABLE.  All we have
+    ** to do here is record the root page number for that index.
+    */
+    Index *pIndex;
+    pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName);
+    if( pIndex==0 || pIndex->tnum!=0 ){
+      /* This can occur if there exists an index on a TEMP table which
+      ** has the same name as another index on a permanent index.  Since
+      ** the permanent table is hidden by the TEMP table, we can also
+      ** safely ignore the index on the permanent table.
+      */
+      /* Do Nothing */;
+    }else{
+      pIndex->tnum = atoi(argv[1]);
     }
   }
-  return nErr;
+  return 0;
 }
 
 /*
@@ -147,7 +118,7 @@
   BtCursor *curMain;
   int size;
   Table *pTab;
-  char const *azArg[6];
+  char const *azArg[5];
   char zDbNum[30];
   int meta[10];
   InitData initData;
@@ -192,16 +163,15 @@
 
   /* Construct the schema tables.  */
   sqlite3SafetyOff(db);
-  azArg[0] = "table";
-  azArg[1] = zMasterName;
-  azArg[2] = "1";
-  azArg[3] = zMasterSchema;
+  azArg[0] = zMasterName;
+  azArg[1] = "1";
+  azArg[2] = zMasterSchema;
   sprintf(zDbNum, "%d", iDb);
-  azArg[4] = zDbNum;
-  azArg[5] = 0;
+  azArg[3] = zDbNum;
+  azArg[4] = 0;
   initData.db = db;
   initData.pzErrMsg = pzErrMsg;
-  rc = sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
+  rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0);
   if( rc!=SQLITE_OK ){
     sqlite3SafetyOn(db);
     return rc;
@@ -304,14 +274,14 @@
     /* For an empty database, there is nothing to read */
     rc = SQLITE_OK;
   }else{
-    char *zSql = 0;
+    char *zSql;
+    zSql = sqlite3MPrintf(
+        "SELECT name, rootpage, sql, %s FROM '%q'.%s",
+        zDbNum, db->aDb[iDb].zName, zMasterName);
     sqlite3SafetyOff(db);
-    sqlite3SetString(&zSql, 
-        "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
-        db->aDb[iDb].zName, "\".", zMasterName, (char*)0);
     rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
-    sqliteFree(zSql);
     sqlite3SafetyOn(db);
+    sqliteFree(zSql);
     sqlite3BtreeCloseCursor(curMain);
   }
   if( sqlite3_malloc_failed ){
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index d6cde4e..cdab05c 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.308 2004/07/22 15:02:25 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.309 2004/07/24 03:30:48 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1160,6 +1160,16 @@
 };
 
 /*
+** A pointer to this structure is used to communicate information
+** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback.
+*/
+typedef struct {
+  sqlite *db;         /* The database being initialized */
+  char **pzErrMsg;    /* Error message stored here */
+} InitData;
+
+
+/*
  * This global flag is set for performance testing of triggers. When it is set
  * SQLite will perform the overhead of building new and old trigger references 
  * even when no triggers exist
@@ -1210,6 +1220,7 @@
 ExprList *sqlite3ExprListAppend(ExprList*,Expr*,Token*);
 void sqlite3ExprListDelete(ExprList*);
 int sqlite3Init(sqlite*, char**);
+int sqlite3InitCallback(void*, int, char**, char**);
 void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
 void sqlite3ResetInternalSchema(sqlite*, int);
 void sqlite3BeginParse(Parse*,int);
diff --git a/src/tokenize.c b/src/tokenize.c
index 8600cc6..dde8091 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -15,7 +15,7 @@
 ** individual tokens and sends those tokens one-by-one over to the
 ** parser for analysis.
 **
-** $Id: tokenize.c,v 1.78 2004/06/18 06:02:35 danielk1977 Exp $
+** $Id: tokenize.c,v 1.79 2004/07/24 03:30:48 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -431,6 +431,11 @@
     sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
     return 1;
   }
+#ifndef NDEBUG
+  if( sqlite3OsFileExists("vdbe_sqltrace") ){
+    printf("SQL To Compiler: [%s]\n", zSql);
+  }
+#endif
   pParse->sLastToken.dyn = 0;
   pParse->zTail = zSql;
   while( sqlite3_malloc_failed==0 && zSql[i]!=0 ){
@@ -714,4 +719,3 @@
   sqlite3ValueFree(pVal);
   return rc;
 }
-
diff --git a/src/vdbe.c b/src/vdbe.c
index beeae2d..12e0978 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.403 2004/07/21 02:53:30 drh Exp $
+** $Id: vdbe.c,v 1.404 2004/07/24 03:30:48 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -3670,24 +3670,19 @@
   break;
 }
 
-/* Opcode: CreateTable * P2 P3
+/* Opcode: CreateTable P1 * *
 **
 ** Allocate a new table in the main database file if P2==0 or in the
 ** auxiliary database file if P2==1.  Push the page number
 ** for the root page of the new table onto the stack.
 **
-** The root page number is also written to a memory location that P3
-** points to.  This is the mechanism is used to write the root page
-** number into the parser's internal data structures that describe the
-** new table.
-**
 ** The difference between a table and an index is this:  A table must
 ** have a 4-byte integer key and can have arbitrary data.  An index
 ** has an arbitrary key but no data.
 **
 ** See also: CreateIndex
 */
-/* Opcode: CreateIndex * P2 P3
+/* Opcode: CreateIndex P1 * *
 **
 ** Allocate a new index in the main database file if P2==0 or in the
 ** auxiliary database file if P2==1.  Push the page number of the
@@ -3699,28 +3694,59 @@
 case OP_CreateTable: {
   int pgno;
   int flags;
-  assert( pOp->p3!=0 && pOp->p3type==P3_POINTER );
-  assert( pOp->p2>=0 && pOp->p2<db->nDb );
-  assert( db->aDb[pOp->p2].pBt!=0 );
+  Db *pDb;
+  assert( pOp->p1>=0 && pOp->p1<db->nDb );
+  pDb = &db->aDb[pOp->p1];
+  assert( pDb->pBt!=0 );
   if( pOp->opcode==OP_CreateTable ){
     /* flags = BTREE_INTKEY; */
     flags = BTREE_LEAFDATA|BTREE_INTKEY;
   }else{
     flags = BTREE_ZERODATA;
   }
-  rc = sqlite3BtreeCreateTable(db->aDb[pOp->p2].pBt, &pgno, flags);
+  rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
   pTos++;
   if( rc==SQLITE_OK ){
     pTos->i = pgno;
     pTos->flags = MEM_Int;
-    *(u32*)pOp->p3 = pgno;
-    pOp->p3 = 0;
   }else{
     pTos->flags = MEM_Null;
   }
   break;
 }
 
+/* Opcode: ParseSchema P1 * P3
+**
+** Read and parse all entries from the SQLITE_MASTER table of database P1
+** that match the WHERE clause P3.
+**
+** This opcode invokes the parser to create a new virtual machine,
+** then runs the new virtual machine.  It is thus a reentrant opcode.
+*/
+case OP_ParseSchema: {
+  char *zSql;
+  int iDb = pOp->p1;
+  const char *zMaster;
+  InitData initData;
+
+  assert( iDb>=0 && iDb<db->nDb );
+  zMaster = iDb==1 ? TEMP_MASTER_NAME : MASTER_NAME;
+  initData.db = db;
+  initData.pzErrMsg = &p->zErrMsg;
+  zSql = sqlite3MPrintf(
+     "SELECT name, rootpage, sql, %d FROM '%q'.%s WHERE %s",
+     pOp->p1, db->aDb[iDb].zName, zMaster, pOp->p3);
+  sqlite3SafetyOff(db);
+  assert( db->init.busy==0 );
+  db->init.busy = 1;
+  rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
+  db->init.busy = 0;
+  sqlite3SafetyOn(db);
+  sqliteFree(zSql);
+  break;  
+}
+
+
 /* Opcode: IntegrityCk * P2 *
 **
 ** Do an analysis of the currently open database.  Push onto the