initial check-in of the new version (CVS 1)

FossilOrigin-Name: 6f3655f79f9b6fc9fb7baaa10a7e0f2b6a512dfa
diff --git a/src/build.c b/src/build.c
new file mode 100644
index 0000000..ba4eb17
--- /dev/null
+++ b/src/build.c
@@ -0,0 +1,1435 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This file contains C code routines that are called by the parser
+** when syntax rules are reduced.
+**
+** $Id: build.c,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include "sqliteInt.h"
+
+/*
+** This routine is called after a single SQL statement has been
+** parsed and we want to execute the code to implement 
+** the statement.  Prior action routines should have already
+** constructed VDBE code to do the work of the SQL statement.
+** This routine just has to execute the VDBE code.
+**
+** Note that if an error occurred, it might be the case that
+** no VDBE code was generated.
+*/
+void sqliteExec(Parse *pParse){
+  if( pParse->pVdbe ){
+    if( pParse->explain ){
+      sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg, 
+                     &pParse->zErrMsg);
+    }else{
+      FILE *trace = (pParse->db->flags & SQLITE_VdbeTrace)!=0 ? stderr : 0;
+      sqliteVdbeTrace(pParse->pVdbe, trace);
+      sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg, 
+                     &pParse->zErrMsg);
+    }
+    sqliteVdbeDelete(pParse->pVdbe);
+    pParse->pVdbe = 0;
+  }
+}
+
+/*
+** Construct a new expression node and return a pointer to it.
+*/
+Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
+  Expr *pNew;
+  pNew = sqliteMalloc( sizeof(Expr) );
+  if( pNew==0 ) return 0;
+  pNew->op = op;
+  pNew->pLeft = pLeft;
+  pNew->pRight = pRight;
+  if( pToken ){
+    pNew->token = *pToken;
+  }else{
+    pNew->token.z = "";
+    pNew->token.n = 0;
+  }
+  return pNew;
+}
+
+/*
+** Construct a new expression node for a function with multiple
+** arguments.
+*/
+Expr *sqliteExprFunction(ExprList *pList, Token *pToken){
+  Expr *pNew;
+  pNew = sqliteMalloc( sizeof(Expr) );
+  if( pNew==0 ) return 0;
+  pNew->op = TK_FUNCTION;
+  pNew->pList = pList;
+  if( pToken ){
+    pNew->token = *pToken;
+  }else{
+    pNew->token.z = "";
+    pNew->token.n = 0;
+  }
+  return pNew;
+}
+
+/*
+** Recursively delete an expression tree.
+*/
+void sqliteExprDelete(Expr *p){
+  if( p==0 ) return;
+  if( p->pLeft ) sqliteExprDelete(p->pLeft);
+  if( p->pRight ) sqliteExprDelete(p->pRight);
+  sqliteFree(p);
+}
+
+/*
+** Locate the in-memory structure that describes the
+** format of a particular database table given the name
+** of that table.  Return NULL if not found.
+*/
+Table *sqliteFindTable(sqlite *db, char *zName){
+  Table *pTable;
+  int h;
+
+  h = sqliteHashNoCase(zName, 0) % N_HASH;
+  for(pTable=db->apTblHash[h]; pTable; pTable=pTable->pHash){
+    if( sqliteStrICmp(pTable->zName, zName)==0 ) return pTable;
+  }
+  return 0;
+}
+
+/*
+** Locate the in-memory structure that describes the
+** format of a particular index table given the name
+** of that table.  Return NULL if not found.
+*/
+Index *sqliteFindIndex(sqlite *db, char *zName){
+  Index *p;
+  int h;
+
+  h = sqliteHashNoCase(zName, 0) % N_HASH;
+  for(p=db->apIdxHash[h]; p; p=p->pHash){
+    if( sqliteStrICmp(p->zName, zName)==0 ) return p;
+  }
+  return 0;
+}
+
+/*
+** Remove the given index from the index hash table, and free
+** its memory structures.
+**
+** The index is removed from the database hash table, but it is
+** not unlinked from the table that is being indexed.  Unlinking
+** from the table must be done by the calling function.
+*/
+static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
+  int h;
+  if( pIndex->zName ){
+    h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH;
+    if( db->apIdxHash[h]==pIndex ){
+      db->apIdxHash[h] = pIndex->pHash;
+    }else{
+      Index *p;
+      for(p=db->apIdxHash[h]; p && p->pHash!=pIndex; p=p->pHash){}
+      if( p && p->pHash==pIndex ){
+        p->pHash = pIndex->pHash;
+      }
+    }
+  }
+  sqliteFree(pIndex);
+}
+
+/*
+** Remove the memory data structures associated with the given
+** table.  No changes are made to disk by this routine.
+**
+** This routine just deletes the data structure.  It does not unlink
+** the table data structure from the hash table.  But does it destroy
+** memory structures of the indices associated with the table.
+*/
+void sqliteDeleteTable(sqlite *db, Table *pTable){
+  int i;
+  Index *pIndex, *pNext;
+  if( pTable==0 ) return;
+  for(i=0; i<pTable->nCol; i++){
+    if( pTable->azCol[i] ) sqliteFree(pTable->azCol[i]);
+  }
+  for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
+    pNext = pIndex->pNext;
+    sqliteDeleteIndex(db, pIndex);
+  }
+  sqliteFree(pTable->azCol);
+  sqliteFree(pTable);
+}
+
+/*
+** Construct the name of a user table from a token.
+**
+** Space to hold the name is obtained from sqliteMalloc() and must
+** be freed by the calling function.
+*/
+static char *sqliteTableNameFromToken(Token *pName){
+  char *zName = 0;
+  sqliteSetNString(&zName, pName->z, pName->n, 0);
+  return zName;
+}
+
+/*
+** Begin constructing a new table representation in memory.  This is
+** the first of several action routines that get called in response
+** to a CREATE TABLE statement.
+*/
+void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
+  Table *pTable;
+  char *zName;
+
+  pParse->sFirstToken = *pStart;
+  zName = sqliteTableNameFromToken(pName);
+  pTable = sqliteFindTable(pParse->db, zName);
+  if( pTable!=0 ){
+    sqliteSetNString(&pParse->zErrMsg, "table \"", 0, pName->z, pName->n,
+        "\" already exists", 0, 0);
+    sqliteFree(zName);
+    pParse->nErr++;
+    return;
+  }
+  if( sqliteFindIndex(pParse->db, zName) ){
+    sqliteSetString(&pParse->zErrMsg, "there is already an index named \"", 
+       zName, "\"", 0);
+    sqliteFree(zName);
+    pParse->nErr++;
+    return;
+  }
+  pTable = sqliteMalloc( sizeof(Table) );
+  if( pTable==0 ){
+    sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
+    pParse->nErr++;
+    return;
+  }
+  pTable->zName = zName;
+  pTable->pHash = 0;
+  pTable->nCol = 0;
+  pTable->azCol = 0;
+  pTable->pIndex = 0;
+  if( pParse->pNewTable ) sqliteDeleteTable(pParse->db, pParse->pNewTable);
+  pParse->pNewTable = pTable;
+}
+
+/*
+** Add a new column to the table currently being constructed.
+*/
+void sqliteAddColumn(Parse *pParse, Token *pName){
+  Table *p;
+  char **pz;
+  if( (p = pParse->pNewTable)==0 ) return;
+  if( (p->nCol & 0x7)==0 ){
+    p->azCol = sqliteRealloc( p->azCol, p->nCol+8);
+  }
+  if( p->azCol==0 ){
+    p->nCol = 0;
+    return;
+  }
+  pz = &p->azCol[p->nCol++];
+  *pz = 0;
+  sqliteSetNString(pz, pName->z, pName->n, 0);
+}
+
+/*
+** This routine is called to report the final ")" that terminates
+** a CREATE TABLE statement.
+**
+** The table structure is added to the internal hash tables.  
+**
+** An entry for the table is made in the master table, unless 
+** initFlag==1.  When initFlag==1, it means we are reading the
+** master table because we just connected to the database, so 
+** the entry for this table already exists in the master table.
+** We do not want to create it again.
+*/
+void sqliteEndTable(Parse *pParse, Token *pEnd){
+  Table *p;
+  int h;
+
+  if( pParse->nErr ) return;
+
+  /* Add the table to the in-memory representation of the database
+  */
+  if( (p = pParse->pNewTable)!=0 && pParse->explain==0 ){
+    h = sqliteHashNoCase(p->zName, 0) % N_HASH;
+    p->pHash = pParse->db->apTblHash[h];
+    pParse->db->apTblHash[h] = p;
+    pParse->pNewTable = 0;
+  }
+
+  /* If not initializing, then create the table on disk.
+  */
+  if( !pParse->initFlag ){
+    static VdbeOp addTable[] = {
+      { OP_Open,        0, 0, MASTER_NAME },
+      { OP_New,         0, 0, 0},
+      { OP_String,      0, 0, "table"     },
+      { OP_String,      0, 0, 0},            /* 2 */
+      { OP_String,      0, 0, 0},            /* 3 */
+      { OP_String,      0, 0, 0},            /* 4 */
+      { OP_MakeRecord,  4, 0, 0},
+      { OP_Put,         0, 0, 0},
+      { OP_Close,       0, 0, 0},
+    };
+    int n, base;
+    Vdbe *v = pParse->pVdbe;
+
+    if( v==0 ){
+      v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+    }
+    if( v==0 ) return;
+    n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1;
+    base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
+    sqliteVdbeChangeP3(v, base+2, p->zName, 0);
+    sqliteVdbeChangeP3(v, base+3, p->zName, 0);
+    sqliteVdbeChangeP3(v, base+4, pParse->sFirstToken.z, n);
+  }
+}
+
+/*
+** Given a token, look up a table with that name.  If not found, leave
+** an error for the parser to find and return NULL.
+*/
+static Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
+  char *zName = sqliteTableNameFromToken(pTok);
+  Table *pTab = sqliteFindTable(pParse->db, zName);
+  sqliteFree(zName);
+  if( pTab==0 ){
+    sqliteSetNString(&pParse->zErrMsg, "no such table: \"", 0, 
+        pTok->z, pTok->n, "\"", 1, 0);
+    pParse->nErr++;
+  }
+  return pTab;
+}
+
+/*
+** This routine is called to do the work of a DROP TABLE statement.
+*/
+void sqliteDropTable(Parse *pParse, Token *pName){
+  Table *pTable;
+  int h;
+  Vdbe *v;
+  int base;
+
+  pTable = sqliteTableFromToken(pParse, pName);
+  if( pTable==0 ) return;
+  if( pTable->readOnly ){
+    sqliteSetString(&pParse->zErrMsg, "table \"", pTable->zName, 
+       "\" may not be dropped", 0);
+    pParse->nErr++;
+    return;
+  }
+
+  /* Generate code to remove the table and its reference in sys_master */
+  v = pParse->pVdbe;
+  if( v==0 ){
+    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  }
+  if( v ){
+    static VdbeOp dropTable[] = {
+      { OP_Open,       0, 0,        MASTER_NAME },
+      { OP_ListOpen,   0, 0,        0},
+      { OP_String,     0, 0,        0}, /* 2 */
+      { OP_Next,       0, ADDR(10), 0}, /* 3 */
+      { OP_Dup,        0, 0,        0},
+      { OP_Field,      0, 2,        0},
+      { OP_Ne,         0, ADDR(3),  0},
+      { OP_Key,        0, 0,        0},
+      { OP_ListWrite,  0, 0,        0},
+      { OP_Goto,       0, ADDR(3),  0},
+      { OP_ListRewind, 0, 0,        0}, /* 10 */
+      { OP_ListRead,   0, ADDR(14), 0}, /* 11 */
+      { OP_Delete,     0, 0,        0},
+      { OP_Goto,       0, ADDR(11), 0},
+      { OP_Destroy,    0, 0,        0}, /* 14 */
+      { OP_Close,      0, 0,        0},
+    };
+    Index *pIdx;
+    base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
+    sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
+    sqliteVdbeChangeP3(v, base+14, pTable->zName, 0);
+    for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
+      sqliteVdbeAddOp(v, OP_Destroy, 0, 0, pIdx->zName, 0);
+    }
+  }
+
+  /* Remove the table structure and free its memory.
+  **
+  ** Exception: if the SQL statement began with the EXPLAIN keyword,
+  ** then no changes are made.
+  */
+  if( !pParse->explain ){
+    h = sqliteHashNoCase(pTable->zName, 0) % N_HASH;
+    if( pParse->db->apTblHash[h]==pTable ){
+      pParse->db->apTblHash[h] = pTable->pHash;
+    }else{
+      Table *p;
+      for(p=pParse->db->apTblHash[h]; p && p->pHash!=pTable; p=p->pHash){}
+      if( p && p->pHash==pTable ){
+        p->pHash = pTable->pHash;
+      }
+    }
+    sqliteDeleteTable(pParse->db, pTable);
+  }
+}
+
+/*
+** Create a new index for an SQL table.  pIndex is the name of the index 
+** and pTable is the name of the table that is to be indexed.  Both will 
+** be NULL for a primary key.  In that case, use pParse->pNewTable as the 
+** table to be indexed.
+**
+** pList is a list of fields to be indexed.  pList will be NULL if the
+** most recently added field of the table is labeled as the primary key.
+*/
+void sqliteCreateIndex(
+  Parse *pParse,   /* All information about this parse */
+  Token *pName,    /* Name of the index.  May be NULL */
+  Token *pTable,   /* Name of the table to index.  Use pParse->pNewTable if 0 */
+  IdList *pList,   /* A list of fields to be indexed */
+  Token *pStart,   /* The CREATE token that begins a CREATE TABLE statement */
+  Token *pEnd      /* The ")" that closes the CREATE INDEX statement */
+){
+  Table *pTab;     /* Table to be indexed */
+  Index *pIndex;   /* The index to be created */
+  char *zName = 0;
+  int i, j, h;
+  Token nullId;    /* Fake token for an empty ID list */
+
+  /*
+  ** Find the table that is to be indexed.  Return early if not found.
+  */
+  if( pTable!=0 ){
+    pTab =  sqliteTableFromToken(pParse, pTable);
+  }else{
+    pTab =  pParse->pNewTable;
+  }
+  if( pTab==0 || pParse->nErr ) goto exit_create_index;
+  if( pTab->readOnly ){
+    sqliteSetString(&pParse->zErrMsg, "table \"", pTab->zName, 
+      "\" may not have new indices added", 0);
+    pParse->nErr++;
+    goto exit_create_index;
+  }
+
+  /*
+  ** Find the name of the index.  Make sure there is not already another
+  ** index or table with the same name.
+  */
+  if( pName ){
+    zName = sqliteTableNameFromToken(pName);
+  }else{
+    zName = 0;
+    sqliteSetString(&zName, pTab->zName, "__primary_key", 0);
+  }
+  if( sqliteFindIndex(pParse->db, zName) ){
+    sqliteSetString(&pParse->zErrMsg, "index \"", zName, 
+       "\" already exists", 0);
+    pParse->nErr++;
+    goto exit_create_index;
+  }
+  if( sqliteFindTable(pParse->db, zName) ){
+    sqliteSetString(&pParse->zErrMsg, "there is already a table named \"",
+       zName, "\"", 0);
+    pParse->nErr++;
+    goto exit_create_index;
+  }
+
+  /* If pList==0, it means this routine was called to make a primary
+  ** key out of the last field added to the table under construction.
+  ** So create a fake list to simulate this.
+  */
+  if( pList==0 ){
+    nullId.z = pTab->azCol[pTab->nCol-1];
+    nullId.n = strlen(nullId.z);
+    pList = sqliteIdListAppend(0, &nullId);
+    if( pList==0 ) goto exit_create_index;
+  }
+
+  /* 
+  ** Allocate the index structure. 
+  */
+  pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 
+                        sizeof(int)*pList->nId );
+  if( pIndex==0 ){
+    sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
+    pParse->nErr++;
+    goto exit_create_index;
+  }
+  pIndex->aiField = (int*)&pIndex[1];
+  pIndex->zName = (char*)&pIndex->aiField[pList->nId];
+  strcpy(pIndex->zName, zName);
+  pIndex->pTable = pTab;
+  pIndex->nField = pList->nId;
+
+  /* Scan the names of the fields of the table to be indexed and
+  ** load the field indices into the Index structure.  Report an error
+  ** if any field is not found.
+  */
+  for(i=0; i<pList->nId; i++){
+    for(j=0; j<pTab->nCol; j++){
+      if( sqliteStrICmp(pList->a[i].zName, pTab->azCol[j])==0 ) break;
+    }
+    if( j>=pTab->nCol ){
+      sqliteSetString(&pParse->zErrMsg, "table being indexed has no field "
+        "named \"", pList->a[i].zName, "\"", 0);
+      pParse->nErr++;
+      sqliteFree(pIndex);
+      goto exit_create_index;
+    }
+    pIndex->aiField[i] = j;
+  }
+
+  /* Link the new Index structure to its table and to the other
+  ** in-memory database structures.
+  */
+  if( pParse->explain==0 ){
+    h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH;
+    pIndex->pHash = pParse->db->apIdxHash[h];
+    pParse->db->apIdxHash[h] = pIndex;
+    pIndex->pNext = pTab->pIndex;
+    pTab->pIndex = pIndex;
+  }
+
+  /* If the initFlag is 0 then create the index on disk.  This
+  ** involves writing the index into the master table and filling in the
+  ** index with the current table contents.
+  **
+  ** The initFlag is 0 when the user first enters a CREATE INDEX 
+  ** command.  The initFlag is 1 when a database is opened and 
+  ** CREATE INDEX statements are read out of the master table.  In
+  ** the latter case the index already exists on disk, which is why
+  ** we don't want to recreate it.
+  */
+  if( pParse->initFlag==0 ){
+    static VdbeOp addTable[] = {
+      { OP_Open,        0, 0, MASTER_NAME},
+      { OP_New,         0, 0, 0},
+      { OP_String,      0, 0, "index"},
+      { OP_String,      0, 0, 0},  /* 2 */
+      { OP_String,      0, 0, 0},  /* 3 */
+      { OP_String,      0, 0, 0},  /* 4 */
+      { OP_MakeRecord,  4, 0, 0},
+      { OP_Put,         0, 0, 0},
+      { OP_Close,       0, 0, 0},
+    };
+    int n;
+    Vdbe *v = pParse->pVdbe;
+    int lbl1, lbl2;
+    int i;
+
+    if( v==0 ){
+      v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+    }
+    if( v==0 ) goto exit_create_index;
+    if( pStart && pEnd ){
+      int base;
+      n = (int)pEnd->z - (int)pStart->z + 1;
+      base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
+      sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
+      sqliteVdbeChangeP3(v, base+3, pTab->zName, 0);
+      sqliteVdbeChangeP3(v, base+4, pStart->z, n);
+    }
+    sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
+    sqliteVdbeAddOp(v, OP_Open, 1, 0, pIndex->zName, 0);
+    lbl1 = sqliteVdbeMakeLabel(v);
+    lbl2 = sqliteVdbeMakeLabel(v);
+    sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1);
+    sqliteVdbeAddOp(v, OP_Key, 0, 0, 0, 0);
+    for(i=0; i<pIndex->nField; i++){
+      sqliteVdbeAddOp(v, OP_Field, 0, pIndex->aiField[i], 0, 0);
+    }
+    sqliteVdbeAddOp(v, OP_MakeKey, pIndex->nField, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_PutIdx, 1, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0);
+    sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2);
+    sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Close, 1, 0, 0, 0);
+  }
+
+  /* Reclaim memory on an EXPLAIN call.
+  */
+  if( pParse->explain ){
+    sqliteFree(pIndex);
+  }
+
+  /* Clean up before exiting */
+exit_create_index:
+  sqliteIdListDelete(pList);
+  sqliteFree(zName);
+  return;
+}
+
+/*
+** This routine will drop an existing named index.
+*/
+void sqliteDropIndex(Parse *pParse, Token *pName){
+  Index *pIndex;
+  char *zName;
+  Vdbe *v;
+
+  zName = sqliteTableNameFromToken(pName);
+  pIndex = sqliteFindIndex(pParse->db, zName);
+  sqliteFree(zName);
+  if( pIndex==0 ){
+    sqliteSetNString(&pParse->zErrMsg, "no such index: \"", 0, 
+        pName->z, pName->n, "\"", 1, 0);
+    pParse->nErr++;
+    return;
+  }
+
+  /* Generate code to remove the index and from the master table */
+  v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  if( v ){
+    static VdbeOp dropIndex[] = {
+      { OP_Open,       0, 0,       MASTER_NAME},
+      { OP_ListOpen,   0, 0,       0},
+      { OP_String,     0, 0,       0}, /* 2 */
+      { OP_Next,       0, ADDR(9), 0}, /* 3 */
+      { OP_Dup,        0, 0,       0},
+      { OP_Field,      0, 1,       0},
+      { OP_Ne,         0, ADDR(3), 0},
+      { OP_Key,        0, 0,       0},
+      { OP_Delete,     0, 0,       0},
+      { OP_Destroy,    0, 0,       0}, /* 9 */
+      { OP_Close,      0, 0,       0},
+    };
+    int base;
+
+    base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
+    sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
+    sqliteVdbeChangeP3(v, base+9, pIndex->zName, 0);
+  }
+
+  /* Remove the index structure and free its memory.  Except if the
+  ** EXPLAIN keyword is present, no changes are made.
+  */
+  if( !pParse->explain ){
+    if( pIndex->pTable->pIndex==pIndex ){
+      pIndex->pTable->pIndex = pIndex->pNext;
+    }else{
+      Index *p;
+      for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){}
+      if( p && p->pNext==pIndex ){
+        p->pNext = pIndex->pNext;
+      }
+    }
+    sqliteDeleteIndex(pParse->db, pIndex);
+  }
+}
+
+/*
+** Add a new element to the end of an expression list.  If pList is
+** initially NULL, then create a new expression list.
+*/
+ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
+  int i;
+  if( pList==0 ){
+    pList = sqliteMalloc( sizeof(ExprList) );
+  }
+  if( pList==0 ) return 0;
+  if( (pList->nExpr & 7)==0 ){
+    int n = pList->nExpr + 8;
+    pList->a = sqliteRealloc(pList->a, n*sizeof(pList->a[0]));
+    if( pList->a==0 ){
+      pList->nExpr = 0;
+      return pList;
+    }
+  }
+  i = pList->nExpr++;
+  pList->a[i].pExpr = pExpr;
+  pList->a[i].zName = 0;
+  if( pName ){
+    sqliteSetNString(&pList->a[i].zName, pName->z, pName->n, 0);
+  }
+  return pList;
+}
+
+/*
+** Delete an entire expression list.
+*/
+void sqliteExprListDelete(ExprList *pList){
+  int i;
+  if( pList==0 ) return;
+  for(i=0; i<pList->nExpr; i++){
+    sqliteExprDelete(pList->a[i].pExpr);
+    sqliteFree(pList->a[i].zName);
+  }
+  sqliteFree(pList->a);
+  sqliteFree(pList);
+}
+
+/*
+** Append a new element to the given IdList.  Create a new IdList if
+** need be.
+*/
+IdList *sqliteIdListAppend(IdList *pList, Token *pToken){
+  if( pList==0 ){
+    pList = sqliteMalloc( sizeof(IdList) );
+    if( pList==0 ) return 0;
+  }
+  if( (pList->nId & 7)==0 ){
+    pList->a = sqliteRealloc(pList->a, (pList->nId+8)*sizeof(pList->a[0]) );
+    if( pList->a==0 ){
+      pList->nId = 0;
+      return pList;
+    }
+  }
+  memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
+  if( pToken ){
+    sqliteSetNString(&pList->a[pList->nId].zName, pToken->z, pToken->n, 0);
+  }
+  pList->nId++;
+  return pList;
+}
+
+/*
+** Add an alias to the last identifier on the given identifier list.
+*/
+void sqliteIdListAddAlias(IdList *pList, Token *pToken){
+  if( pList && pList->nId>0 ){
+    int i = pList->nId - 1;
+    sqliteSetNString(&pList->a[i].zAlias, pToken->z, pToken->n, 0);
+  }
+}
+
+/*
+** Delete an entire IdList
+*/
+void sqliteIdListDelete(IdList *pList){
+  int i;
+  if( pList==0 ) return;
+  for(i=0; i<pList->nId; i++){
+    sqliteFree(pList->a[i].zName);
+    sqliteFree(pList->a[i].zAlias);
+  }
+  sqliteFree(pList->a);
+  sqliteFree(pList);
+}
+
+/*
+** This routine is call to handle SQL of the following form:
+**
+**    insert into TABLE (IDLIST) values(EXPRLIST)
+**
+** The parameters are the table name and the expression list.
+*/
+void sqliteInsert(
+  Parse *pParse,        /* Parser context */
+  Token *pTableName,    /* Name of table into which we are inserting */
+  ExprList *pList,      /* List of values to be inserted */
+  IdList *pField        /* Field name corresponding to pList.  Might be NULL */
+){
+  Table *pTab;
+  char *zTab;
+  int i, j;
+  Vdbe *v;
+
+  zTab = sqliteTableNameFromToken(pTableName);
+  pTab = sqliteFindTable(pParse->db, zTab);
+  sqliteFree(zTab);
+  if( pTab==0 ){
+    sqliteSetNString(&pParse->zErrMsg, "no such table: \"", 0, 
+        pTableName->z, pTableName->n, "\"", 1, 0);
+    pParse->nErr++;
+    goto insert_cleanup;
+  }
+  if( pTab->readOnly ){
+    sqliteSetString(&pParse->zErrMsg, "table \"", pTab->zName,
+        "\" may not be modified", 0);
+    pParse->nErr++;
+    goto insert_cleanup;
+  }
+  if( pField==0 && pList->nExpr!=pTab->nCol ){
+    char zNum1[30];
+    char zNum2[30];
+    sprintf(zNum1,"%d", pList->nExpr);
+    sprintf(zNum2,"%d", pTab->nCol);
+    sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
+       " has ", zNum2, " columns but only ",
+       zNum1, " values were supplied", 0);
+    pParse->nErr++;
+    goto insert_cleanup;
+  }
+  if( pField!=0 && pList->nExpr!=pField->nId ){
+    char zNum1[30];
+    char zNum2[30];
+    sprintf(zNum1,"%d", pList->nExpr);
+    sprintf(zNum2,"%d", pTab->nCol);
+    sqliteSetString(&pParse->zErrMsg, zNum1, " values for ",
+       zNum2, " columns", 0);
+    pParse->nErr++;
+    goto insert_cleanup;
+  }
+  if( pField ){
+    for(i=0; i<pField->nId; i++){
+      pField->a[i].idx = -1;
+    }
+    for(i=0; i<pField->nId; i++){
+      for(j=0; j<pTab->nCol; j++){
+        if( sqliteStrICmp(pField->a[i].zName, pTab->azCol[j])==0 ){
+          pField->a[i].idx = j;
+          break;
+        }
+      }
+      if( j>=pTab->nCol ){
+        sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
+           " has no column named ", pField->a[i].zName, 0);
+        pParse->nErr++;
+        goto insert_cleanup;
+      }
+    }
+  }
+  v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  if( v ){
+    Index *pIdx;
+    sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
+    sqliteVdbeAddOp(v, OP_New, 0, 0, 0, 0);
+    if( pTab->pIndex ){
+      sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+    }
+    for(i=0; i<pTab->nCol; i++){
+      if( pField==0 ){
+        j = i;
+      }else{
+        for(j=0; j<pField->nId; j++){
+          if( pField->a[j].idx==i ) break;
+        }
+      }
+      if( pField && j>=pField->nId ){
+        sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
+      }else{
+        sqliteExprCode(pParse, pList->a[j].pExpr);
+      }
+    }
+    sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
+    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+      if( pIdx->pNext ){
+        sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+      }
+      sqliteVdbeAddOp(v, OP_Open, 0, 0, pIdx->zName, 0);
+      for(i=0; i<pIdx->nField; i++){
+        int idx = pIdx->aiField[i];
+        if( pField==0 ){
+          j = idx;
+        }else{
+          for(j=0; j<pField->nId; j++){
+            if( pField->a[j].idx==idx ) break;
+          }
+        }
+        if( pField && j>=pField->nId ){
+          sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
+        }else{
+          sqliteExprCode(pParse, pList->a[j].pExpr);
+        }
+      }
+      sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_PutIdx, 0, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
+    }
+  }
+
+insert_cleanup:
+  sqliteExprListDelete(pList);
+  sqliteIdListDelete(pField);
+}
+
+/*
+** This routine walks an expression tree and resolves references to
+** table fields.  Nodes of the form ID.ID or ID resolve into an
+** index to the table in the table list and a field offset.  The opcode
+** for such nodes is changed to TK_FIELD.  The iTable value is changed
+** to the index of the referenced table in pTabList, and the iField value
+** is changed to the index of the field of the referenced table.
+**
+** Unknown fields or tables provoke an error.  The function returns
+** the number of errors seen and leaves an error message on pParse->zErrMsg.
+*/
+int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
+  if( pExpr==0 ) return 0;
+  switch( pExpr->op ){
+    /* A lone identifier */
+    case TK_ID: {
+      int cnt = 0;   /* Number of matches */
+      int i;         /* Loop counter */
+      char *z = pExpr->token.z;
+      int n = pExpr->token.n;
+      for(i=0; i<pTabList->nId; i++){
+        int j;
+        Table *pTab = pTabList->a[i].pTab;
+        if( pTab==0 ) continue;
+        for(j=0; j<pTab->nCol; j++){
+          if( sqliteStrNICmp(pTab->azCol[j], z, n)==0 ){
+            cnt++;
+            pExpr->iTable = i;
+            pExpr->iField = j;
+          }
+        }
+      }
+      if( cnt==0 ){
+        sqliteSetNString(&pParse->zErrMsg, "unknown field name: \"", -1,  
+          pExpr->token.z, pExpr->token.n, "\"", -1, 0);
+        pParse->nErr++;
+        return 1;
+      }else if( cnt>1 ){
+        sqliteSetNString(&pParse->zErrMsg, "ambiguous field name: \"", -1,  
+          pExpr->token.z, pExpr->token.n, "\"", -1, 0);
+        pParse->nErr++;
+        return 1;
+      }
+      pExpr->op = TK_FIELD;
+      break; 
+    }
+  
+    /* A table name and field name:  ID.ID */
+    case TK_DOT: {
+      int cnt = 0;   /* Number of matches */
+      int i;         /* Loop counter */
+      Expr *pLeft, *pRight;    /* Left and right subbranches of the expr */
+      int n;                   /* Length of an identifier */
+      char *z;                 /* Text of an identifier */
+
+      pLeft = pExpr->pLeft;
+      pRight = pExpr->pRight;
+      assert( pLeft && pLeft->op==TK_ID );
+      assert( pRight && pRight->op==TK_ID );
+      n = pRight->token.n;
+      z = pRight->token.z;      
+      for(i=0; i<pTabList->nId; i++){
+        int j;
+        char *zTab;
+        Table *pTab = pTabList->a[i].pTab;
+        if( pTab==0 ) continue;
+        if( pTabList->a[i].zAlias ){
+          zTab = pTabList->a[i].zAlias;
+        }else{
+          zTab = pTab->zName;
+        }
+        if( sqliteStrNICmp(zTab, pLeft->token.z, pLeft->token.n)!=0 ) continue;
+        for(j=0; j<pTab->nCol; j++){
+          if( sqliteStrNICmp(pTab->azCol[j], z, n)==0 ){
+            cnt++;
+            pExpr->iTable = i;
+            pExpr->iField = j;
+          }
+        }
+      }
+      if( cnt==0 ){
+        sqliteSetNString(&pParse->zErrMsg, "unknown field name: \"", -1,  
+          pLeft->token.z, pLeft->token.n, ".", 1, z, n, "\"", 1, 0);
+        pParse->nErr++;
+        return 1;
+      }else if( cnt>1 ){
+        sqliteSetNString(&pParse->zErrMsg, "ambiguous field name: \"", -1,  
+          pExpr->token.z, pExpr->token.n, ".", 1, z, n, "\"", 1, 0);
+        pParse->nErr++;
+        return 1;
+      }
+      sqliteExprDelete(pLeft);
+      pExpr->pLeft = 0;
+      sqliteExprDelete(pRight);
+      pExpr->pRight = 0;
+      pExpr->op = TK_FIELD;
+      break;
+    }
+
+    /* For all else, just recursively walk the tree */
+    default: {
+      if( pExpr->pLeft 
+            && sqliteExprResolveIds(pParse, pTabList, pExpr->pLeft) ){
+        return 1;
+      }
+      if( pExpr->pRight 
+            && sqliteExprResolveIds(pParse, pTabList, pExpr->pRight) ){
+        return 1;
+      }
+      if( pExpr->pList ){
+        int i;
+        ExprList *pList = pExpr->pList;
+        for(i=0; i<pList->nExpr; i++){
+          if( sqliteExprResolveIds(pParse, pTabList, pList->a[i].pExpr) ){
+            return 1;
+          }
+        }
+      }
+    }
+  }
+  return 0;
+}
+
+/*
+** Process a SELECT statement.
+*/
+void sqliteSelect(
+  Parse *pParse,         /* The parser context */
+  ExprList *pEList,      /* List of fields to extract.  NULL means "*" */
+  IdList *pTabList,      /* List of tables to select from */
+  Expr *pWhere,          /* The WHERE clause.  May be NULL */
+  ExprList *pOrderBy     /* The ORDER BY clause.  May be NULL */
+){
+  int i, j;
+  WhereInfo *pWInfo;
+  Vdbe *v;
+
+  if( pParse->nErr>0 ) goto select_cleanup;
+
+  /* Look up every table in the table list.
+  */
+  for(i=0; i<pTabList->nId; i++){
+    pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
+    if( pTabList->a[i].pTab==0 ){
+      sqliteSetString(&pParse->zErrMsg, "unknown table \"", 
+         pTabList->a[i].zName, "\"", 0);
+      pParse->nErr++;
+      goto select_cleanup;
+    }
+  }
+
+  /* If the list of fields to retrieve is "*" then replace it with
+  ** a list of all fields from all tables.
+  */
+  if( pEList==0 ){
+    for(i=0; i<pTabList->nId; i++){
+      Table *pTab = pTabList->a[i].pTab;
+      for(j=0; j<pTab->nCol; j++){
+        Expr *pExpr = sqliteExpr(TK_FIELD, 0, 0, 0);
+        pExpr->iTable = i;
+        pExpr->iField = j;
+        pEList = sqliteExprListAppend(pEList, pExpr, 0);
+      }
+    }
+  }
+
+  /* Resolve the field names in all the expressions.
+  */
+  for(i=0; i<pEList->nExpr; i++){
+    if( sqliteExprResolveIds(pParse, pTabList, pEList->a[i].pExpr) ){
+      goto select_cleanup;
+    }
+  }
+  if( pWhere && sqliteExprResolveIds(pParse, pTabList, pWhere) ){
+    goto select_cleanup;
+  }
+  if( pOrderBy ){
+    for(i=0; i<pOrderBy->nExpr; i++){
+      if( sqliteExprResolveIds(pParse, pTabList, pOrderBy->a[i].pExpr) ){
+        goto select_cleanup;
+      }
+    }
+  }
+
+  /* Begin generating code.
+  */
+  v = pParse->pVdbe;
+  if( v==0 ){
+    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  }
+  if( v==0 ) goto select_cleanup;
+  if( pOrderBy ){
+    sqliteVdbeAddOp(v, OP_SortOpen, 0, 0, 0, 0);
+  }
+
+
+  /* Identify column names
+  */
+  sqliteVdbeAddOp(v, OP_ColumnCount, pEList->nExpr, 0, 0, 0);
+  for(i=0; i<pEList->nExpr; i++){
+    Expr *p;
+    if( pEList->a[i].zName ){
+      char *zName = pEList->a[i].zName;
+      int addr = sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
+      if( zName[0]=='\'' || zName[0]=='"' ){
+        sqliteVdbeDequoteP3(v, addr);
+      }
+      continue;
+    }
+    p = pEList->a[i].pExpr;
+    if( p->op!=TK_FIELD ){
+      char zName[30];
+      sprintf(zName, "field%d", i+1);
+      sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
+    }else{
+      if( pTabList->nId>1 ){
+        char *zName = 0;
+        Table *pTab = pTabList->a[p->iTable].pTab;
+        sqliteSetString(&zName, pTab->zName, ".", 
+               pTab->azCol[p->iField], 0);
+        sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
+        sqliteFree(zName);
+      }else{
+        Table *pTab = pTabList->a[0].pTab;
+        sqliteVdbeAddOp(v, OP_ColumnName, i, 0, pTab->azCol[p->iField], 0);
+      }
+    }
+  }
+
+  /* Begin the database scan
+  */  
+  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
+  if( pWInfo==0 ) goto select_cleanup;
+
+  /* Pull the requested fields.
+  */
+  for(i=0; i<pEList->nExpr; i++){
+    sqliteExprCode(pParse, pEList->a[i].pExpr);
+  }
+  
+  /* If there is no ORDER BY clause, then we can invoke the callback
+  ** right away.  If there is an ORDER BY, then we need to put the
+  ** data into an appropriate sorter record.
+  */
+  if( pOrderBy==0 ){
+    sqliteVdbeAddOp(v, OP_Callback, pEList->nExpr, 0, 0, 0);
+  }else{
+    char *zSortOrder;
+    sqliteVdbeAddOp(v, OP_SortMakeRec, pEList->nExpr, 0, 0, 0);
+    zSortOrder = sqliteMalloc( pOrderBy->nExpr + 1 );
+    if( zSortOrder==0 ) goto select_cleanup;
+    for(i=0; i<pOrderBy->nExpr; i++){
+      zSortOrder[i] = pOrderBy->a[i].idx ? '-' : '+';
+      sqliteExprCode(pParse, pOrderBy->a[i].pExpr);
+    }
+    zSortOrder[pOrderBy->nExpr] = 0;
+    sqliteVdbeAddOp(v, OP_SortMakeKey, pOrderBy->nExpr, 0, zSortOrder, 0);
+    sqliteVdbeAddOp(v, OP_SortPut, 0, 0, 0, 0);
+  }
+
+  /* End the database scan loop.
+  */
+  sqliteWhereEnd(pWInfo);
+
+  /* If there is an ORDER BY clause, then we need to sort the results
+  ** and send them to the callback one by one.
+  */
+  if( pOrderBy ){
+    int end = sqliteVdbeMakeLabel(v);
+    int addr;
+    sqliteVdbeAddOp(v, OP_Sort, 0, 0, 0, 0);
+    addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end, 0, 0);
+    sqliteVdbeAddOp(v, OP_SortCallback, pEList->nExpr, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
+    sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, end);
+  }
+
+  /* Always execute the following code before exiting, in order to
+  ** release resources.
+  */
+select_cleanup:
+  sqliteExprListDelete(pEList);
+  sqliteIdListDelete(pTabList);
+  sqliteExprDelete(pWhere);
+  sqliteExprListDelete(pOrderBy);
+  return;
+}
+
+/*
+** Process a DELETE FROM statement.
+*/
+void sqliteDeleteFrom(
+  Parse *pParse,         /* The parser context */
+  Token *pTableName,     /* The table from which we should delete things */
+  Expr *pWhere           /* The WHERE clause.  May be null */
+){
+  Vdbe *v;               /* The virtual database engine */
+  Table *pTab;           /* The table from which records will be deleted */
+  IdList *pTabList;      /* An ID list holding pTab and nothing else */
+  int end, addr;         /* A couple addresses of generated code */
+  int i;                 /* Loop counter */
+  WhereInfo *pWInfo;     /* Information about the WHERE clause */
+  Index *pIdx;           /* For looping over indices of the table */
+
+  /* Locate the table which we want to update.  This table has to be
+  ** put in an IdList structure because some of the subroutines will
+  ** will be calling are designed to work with multiple tables and expect
+  ** an IdList* parameter instead of just a Table* parameger.
+  */
+  pTabList = sqliteIdListAppend(0, pTableName);
+  for(i=0; i<pTabList->nId; i++){
+    pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
+    if( pTabList->a[i].pTab==0 ){
+      sqliteSetString(&pParse->zErrMsg, "unknown table \"", 
+         pTabList->a[i].zName, "\"", 0);
+      pParse->nErr++;
+      goto delete_from_cleanup;
+    }
+    if( pTabList->a[i].pTab->readOnly ){
+      sqliteSetString(&pParse->zErrMsg, "table \"", pTabList->a[i].zName,
+        "\" may not be modified", 0);
+      pParse->nErr++;
+      goto delete_from_cleanup;
+    }
+  }
+  pTab = pTabList->a[0].pTab;
+
+  /* Resolve the field names in all the expressions.
+  */
+  if( pWhere && sqliteExprResolveIds(pParse, pTabList, pWhere) ){
+    goto delete_from_cleanup;
+  }
+
+  /* Begin generating code.
+  */
+  v = pParse->pVdbe;
+  if( v==0 ){
+    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  }
+  if( v==0 ) goto delete_from_cleanup;
+
+  /* Begin the database scan
+  */
+  sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
+  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
+  if( pWInfo==0 ) goto delete_from_cleanup;
+
+  /* Remember the index of every item to be deleted.
+  */
+  sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
+
+  /* End the database scan loop.
+  */
+  sqliteWhereEnd(pWInfo);
+
+  /* Delete every item identified in the list.
+  */
+  sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
+  for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
+    sqliteVdbeAddOp(v, OP_Open, i, 0, pIdx->zName, 0);
+  }
+  end = sqliteVdbeMakeLabel(v);
+  addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
+  if( pTab->pIndex ){
+    sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Fetch, 0, 0, 0, 0);
+    for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
+      int j;
+      sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+      for(j=0; j<pIdx->nField; j++){
+        sqliteVdbeAddOp(v, OP_Field, 0, pIdx->aiField[j], 0, 0);
+      }
+      sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_DeleteIdx, i, 0, 0, 0);
+    }
+  }
+  sqliteVdbeAddOp(v, OP_Delete, 0, 0, 0, 0);
+  sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
+  sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
+
+delete_from_cleanup:
+  sqliteIdListDelete(pTabList);
+  sqliteExprDelete(pWhere);
+  return;
+}
+
+/*
+** Process an UPDATE statement.
+*/
+void sqliteUpdate(
+  Parse *pParse,         /* The parser context */
+  Token *pTableName,     /* The table in which we should change things */
+  ExprList *pChanges,    /* Things to be changed */
+  Expr *pWhere           /* The WHERE clause.  May be null */
+){
+  int i, j;              /* Loop counters */
+  Table *pTab;           /* The table to be updated */
+  IdList *pTabList = 0;  /* List containing only pTab */
+  int end, addr;         /* A couple of addresses in the generated code */
+  WhereInfo *pWInfo;     /* Information about the WHERE clause */
+  Vdbe *v;               /* The virtual database engine */
+  Index *pIdx;           /* For looping over indices */
+  int nIdx;              /* Number of indices that need updating */
+  Index **apIdx = 0;     /* An array of indices that need updating too */
+  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
+                         ** an expression for the i-th field of the table.
+                         ** aXRef[i]==-1 if the i-th field is not changed. */
+
+  /* Locate the table which we want to update.  This table has to be
+  ** put in an IdList structure because some of the subroutines will
+  ** will be calling are designed to work with multiple tables and expect
+  ** an IdList* parameter instead of just a Table* parameger.
+  */
+  pTabList = sqliteIdListAppend(0, pTableName);
+  for(i=0; i<pTabList->nId; i++){
+    pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
+    if( pTabList->a[i].pTab==0 ){
+      sqliteSetString(&pParse->zErrMsg, "unknown table \"", 
+         pTabList->a[i].zName, "\"", 0);
+      pParse->nErr++;
+      goto update_cleanup;
+    }
+    if( pTabList->a[i].pTab->readOnly ){
+      sqliteSetString(&pParse->zErrMsg, "table \"", pTabList->a[i].zName,
+        "\" may not be modified", 0);
+      pParse->nErr++;
+      goto update_cleanup;
+    }
+  }
+  pTab = pTabList->a[0].pTab;
+  aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
+  if( aXRef==0 ) goto update_cleanup;
+  for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
+
+  /* Resolve the field names in all the expressions in both the
+  ** WHERE clause and in the new values.  Also find the field index
+  ** for each field to be updated in the pChanges array.
+  */
+  if( pWhere && sqliteExprResolveIds(pParse, pTabList, pWhere) ){
+    goto update_cleanup;
+  }
+  for(i=0; i<pChanges->nExpr; i++){
+    if( sqliteExprResolveIds(pParse, pTabList, pChanges->a[i].pExpr) ){
+      goto update_cleanup;
+    }
+    for(j=0; j<pTab->nCol; j++){
+      if( strcmp(pTab->azCol[j], pChanges->a[i].zName)==0 ){
+        pChanges->a[i].idx = j;
+        aXRef[j] = i;
+        break;
+      }
+    }
+    if( j>=pTab->nCol ){
+      sqliteSetString(&pParse->zErrMsg, "no such field: \"", 
+         pChanges->a[i].zName, "\"", 0);
+      pParse->nErr++;
+      goto update_cleanup;
+    }
+  }
+
+  /* Allocate memory for the array apIdx[] and fill it pointers to every
+  ** index that needs to be updated.  Indices only need updating if their
+  ** key includes one of the fields named in pChanges.
+  */
+  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+    for(i=0; i<pIdx->nField; i++){
+      if( aXRef[pIdx->aiField[i]]>=0 ) break;
+    }
+    if( i<pIdx->nField ) nIdx++;
+  }
+  apIdx = sqliteMalloc( sizeof(Index*) * nIdx );
+  if( apIdx==0 ) goto update_cleanup;
+  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+    for(i=0; i<pIdx->nField; i++){
+      if( aXRef[pIdx->aiField[i]]>=0 ) break;
+    }
+    if( i<pIdx->nField ) apIdx[nIdx++] = pIdx;
+  }
+
+  /* Begin generating code.
+  */
+  v = pParse->pVdbe;
+  if( v==0 ){
+    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  }
+  if( v==0 ) goto update_cleanup;
+
+  /* Begin the database scan
+  */
+  sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
+  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
+  if( pWInfo==0 ) goto update_cleanup;
+
+  /* Remember the index of every item to be updated.
+  */
+  sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
+
+  /* End the database scan loop.
+  */
+  sqliteWhereEnd(pWInfo);
+
+  /* Rewind the list of records that need to be updated and
+  ** open every index that needs updating.
+  */
+  sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
+  for(i=0; i<nIdx; i++){
+    sqliteVdbeAddOp(v, OP_Open, i+1, 0, apIdx[i]->zName, 0);
+  }
+
+  /* Loop over every record that needs updating.  We have to load
+  ** the old data for each record to be updated because some fields
+  ** might not change and we will need to copy the old value, therefore.
+  ** Also, the old data is needed to delete the old index entires.
+  */
+  end = sqliteVdbeMakeLabel(v);
+  addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
+  sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+  sqliteVdbeAddOp(v, OP_Fetch, 0, 0, 0, 0);
+
+  /* Delete the old indices for the current record.
+  */
+  for(i=0; i<nIdx; i++){
+    sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+    pIdx = apIdx[i];
+    for(j=0; j<pIdx->nField; j++){
+      sqliteVdbeAddOp(v, OP_Field, 0, pIdx->aiField[j], 0, 0);
+    }
+    sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_DeleteIdx, i+1, 0, 0, 0);
+  }
+
+  /* Compute a completely new data for this record.  
+  */
+  for(i=0; i<pTab->nCol; i++){
+    j = aXRef[i];
+    if( j<0 ){
+      sqliteVdbeAddOp(v, OP_Field, 0, i, 0, 0);
+    }else{
+      sqliteExprCode(pParse, pChanges->a[j].pExpr);
+    }
+  }
+
+  /* Insert new index entries that correspond to the new data
+  */
+  for(i=0; i<nIdx; i++){
+    sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0, 0, 0); /* The KEY */
+    pIdx = apIdx[i];
+    for(j=0; j<pIdx->nField; j++){
+      sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiField[j], 0, 0, 0);
+    }
+    sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_PutIdx, i+1, 0, 0, 0);
+  }
+
+  /* Write the new data back into the database.
+  */
+  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
+  sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
+
+  /* Repeat the above with the next record to be updated, until
+  ** all record selected by the WHERE clause have been updated.
+  */
+  sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
+  sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
+
+update_cleanup:
+  sqliteFree(apIdx);
+  sqliteFree(aXRef);
+  sqliteIdListDelete(pTabList);
+  sqliteExprListDelete(pChanges);
+  sqliteExprDelete(pWhere);
+  return;
+}
diff --git a/src/dbbe.c b/src/dbbe.c
new file mode 100644
index 0000000..808d342
--- /dev/null
+++ b/src/dbbe.c
@@ -0,0 +1,510 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This file contains code to implement the database baseend (DBBE)
+** for sqlite.  The database backend is the interface between
+** sqlite and the code that does the actually reading and writing
+** of information to the disk.
+**
+** This file uses GDBM as the database backend.  It should be
+** relatively simple to convert to a different database such
+** as NDBM, SDBM, or BerkeleyDB.
+**
+** $Id: dbbe.c,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include "sqliteInt.h"
+#include <gdbm.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+
+/*
+** Each open database file is an instance of this structure.
+*/
+typedef struct BeFile BeFile;
+struct BeFile {
+  char *zName;            /* Name of the file */
+  GDBM_FILE dbf;          /* The file itself */
+  int nRef;               /* Number of references */
+  BeFile *pNext, *pPrev;  /* Next and previous on list of open files */
+};
+
+/*
+** The complete database is an instance of the following structure.
+*/
+struct Dbbe {
+  char *zDir;        /* The directory containing the database */
+  int write;         /* True for write permission */
+  BeFile *pOpen;     /* List of open files */
+  int nTemp;         /* Number of temporary files created */
+  FILE **apTemp;     /* Space to hold temporary file pointers */
+};
+
+/*
+** Each file within the database is an instance of this
+** structure.
+*/
+struct DbbeTable {
+  Dbbe *pBe;         /* The database of which this record is a part */
+  BeFile *pFile;     /* The database file for this table */
+  datum key;         /* Most recently used key */
+  datum data;        /* Most recent data */
+  int needRewind;    /* Next key should be the first */
+  int readPending;   /* The fetch hasn't actually been done yet */
+};
+
+/*
+** This routine opens a new database.  For the current driver scheme,
+** the database name is the name of the directory
+** containing all the files of the database.
+*/
+Dbbe *sqliteDbbeOpen(
+  const char *zName,     /* The name of the database */
+  int write,             /* True if we will be writing to the database */
+  int create,            /* True to create database if it doesn't exist */
+  char **pzErrMsg        /* Write error messages (if any) here */
+){
+  Dbbe *pNew;
+  struct stat statbuf;
+
+  if( stat(zName, &statbuf)!=0 ){
+    sqliteSetString(pzErrMsg, "can't find file \"", zName, "\"", 0);
+    return 0;
+  }
+  if( !S_ISDIR(statbuf.st_mode) ){
+    sqliteSetString(pzErrMsg, "not a directory: \"", zName, "\"", 0);
+    return 0;
+  }
+  pNew = sqliteMalloc(sizeof(Dbbe) + strlen(zName) + 1);
+  if( pNew==0 ){
+    sqliteSetString(pzErrMsg, "out of memory", 0);
+    return 0;
+  }
+  pNew->zDir = (char*)&pNew[1];
+  strcpy(pNew->zDir, zName);
+  pNew->write = write;
+  pNew->pOpen = 0;
+  return pNew;
+}
+
+/*
+** Completely shutdown the given database.  Close all files.  Free all memory.
+*/
+void sqliteDbbeClose(Dbbe *pBe){
+  BeFile *pFile, *pNext;
+  for(pFile=pBe->pOpen; pFile; pFile=pNext){
+    pNext = pFile->pNext;
+    gdbm_close(pFile->dbf);
+    memset(pFile, 0, sizeof(*pFile));   
+    sqliteFree(pFile);
+  }
+  memset(pBe, 0, sizeof(*pBe));
+  sqliteFree(pBe);
+}
+
+/*
+** Translate the name of a table into the name of a file that holds
+** that table.  Space to hold the filename is obtained from
+** sqliteMalloc() and must be freed by the calling function.
+*/
+static char *sqliteFileOfTable(Dbbe *pBe, const char *zTable){
+  char *zFile = 0;
+  int i;
+  sqliteSetString(&zFile, pBe->zDir, "/", zTable, ".tbl", 0);
+  if( zFile==0 ) return 0;
+  for(i=strlen(pBe->zDir)+1; zFile[i]; i++){
+    int c = zFile[i];
+    if( isupper(c) ){
+      zFile[i] = tolower(c);
+    }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){
+      zFile[i] = '+';
+    }
+  }
+  return zFile;
+}
+
+/*
+** Open a new table cursor
+*/
+DbbeTable *sqliteDbbeOpenTable(
+  Dbbe *pBe,              /* The database the table belongs to */
+  const char *zTable,     /* The name of the table */
+  int writeable           /* True to open for writing */
+){
+  char *zFile;            /* Name of the table file */
+  DbbeTable *pTable;      /* The new table cursor */
+  BeFile *pFile;          /* The underlying data file for this table */
+
+  pTable = sqliteMalloc( sizeof(*pTable) );
+  if( pTable==0 ) return 0;
+  zFile = sqliteFileOfTable(pBe, zTable);
+  for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
+    if( strcmp(pFile->zName,zFile)==0 ) break;
+  }
+  if( pFile==0 ){
+    pFile = sqliteMalloc( sizeof(*pFile) );
+    if( pFile==0 ){
+      sqliteFree(zFile);
+      return 0;
+    }
+    pFile->zName = zFile;
+    pFile->nRef = 1;
+    pFile->pPrev = 0;
+    if( pBe->pOpen ){
+      pBe->pOpen->pPrev = pFile;
+    }
+    pFile->pNext = pBe->pOpen;
+    pBe->pOpen = pFile;
+    pFile->dbf = gdbm_open(pFile->zName, 0, GDBM_WRCREAT, 0640, 0);
+  }else{
+    sqliteFree(zFile);
+    pFile->nRef++;
+  }
+  pTable->pBe = pBe;
+  pTable->pFile = pFile;
+  pTable->readPending = 0;
+  pTable->needRewind = 1;
+  return pTable;
+}
+
+/*
+** Drop a table from the database.
+*/
+void sqliteDbbeDropTable(Dbbe *pBe, const char *zTable){
+  char *zFile;            /* Name of the table file */
+
+  zFile = sqliteFileOfTable(pBe, zTable);
+  unlink(zFile);
+  sqliteFree(zFile);
+}
+
+/*
+** Close a table previously opened by sqliteDbbeOpenTable().
+*/
+void sqliteDbbeCloseTable(DbbeTable *pTable){
+  BeFile *pFile;
+  Dbbe *pBe;
+  if( pTable==0 ) return;
+  pFile = pTable->pFile;
+  pBe = pTable->pBe;
+  pFile->nRef--;
+  if( pFile->nRef<=0 ){
+    if( pFile->dbf!=NULL ){
+      gdbm_close(pFile->dbf);
+    }
+    if( pFile->pPrev ){
+      pFile->pPrev->pNext = pFile->pNext;
+    }else{
+      pBe->pOpen = pFile->pNext;
+    }
+    if( pFile->pNext ){
+      pFile->pNext->pPrev = pFile->pPrev;
+    }
+    sqliteFree(pFile->zName);
+    memset(pFile, 0, sizeof(*pFile));
+    sqliteFree(pFile);
+  }
+  if( pTable->key.dptr ) free(pTable->key.dptr);
+  if( pTable->data.dptr ) free(pTable->data.dptr);
+  memset(pTable, 0, sizeof(*pTable));
+  sqliteFree(pTable);
+}
+
+/*
+** Clear the given datum
+*/
+static void datumClear(datum *p){
+  if( p->dptr ) free(p->dptr);
+  p->dptr = 0;
+  p->dsize = 0;
+}
+
+/*
+** Fetch a single record from an open table.  Return 1 on success
+** and 0 on failure.
+*/
+int sqliteDbbeFetch(DbbeTable *pTable, int nKey, char *pKey){
+  datum key;
+  key.dsize = nKey;
+  key.dptr = pKey;
+  datumClear(&pTable->key);
+  datumClear(&pTable->data);
+  if( pTable->pFile && pTable->pFile->dbf ){
+    pTable->data = gdbm_fetch(pTable->pFile->dbf, key);
+  }
+  return pTable->data.dptr!=0;
+}
+
+/*
+** Copy bytes from the current key or data into a buffer supplied by
+** the calling function.  Return the number of bytes copied.
+*/
+int sqliteDbbeCopyKey(DbbeTable *pTable, int offset, int size, char *zBuf){
+  int n;
+  if( offset>=pTable->key.dsize ) return 0;
+  if( offset+size>pTable->key.dsize ){
+    n = pTable->key.dsize - offset;
+  }else{
+    n = size;
+  }
+  memcpy(zBuf, &pTable->key.dptr[offset], n);
+  return n;
+}
+int sqliteDbbeCopyData(DbbeTable *pTable, int offset, int size, char *zBuf){
+  int n;
+  if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){
+    pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key);
+    pTable->readPending = 0;
+  }
+  if( offset>=pTable->data.dsize ) return 0;
+  if( offset+size>pTable->data.dsize ){
+    n = pTable->data.dsize - offset;
+  }else{
+    n = size;
+  }
+  memcpy(zBuf, &pTable->data.dptr[offset], n);
+  return n;
+}
+
+/*
+** Return a pointer to bytes from the key or data.  The data returned
+** is ephemeral.
+*/
+char *sqliteDbbeReadKey(DbbeTable *pTable, int offset){
+  if( offset<0 || offset>=pTable->key.dsize ) return "";
+  return &pTable->key.dptr[offset];
+}
+char *sqliteDbbeReadData(DbbeTable *pTable, int offset){
+  if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){
+    pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key);
+    pTable->readPending = 0;
+  }
+  if( offset<0 || offset>=pTable->data.dsize ) return "";
+  return &pTable->data.dptr[offset];
+}
+
+/*
+** Return the total number of bytes in either data or key.
+*/
+int sqliteDbbeKeyLength(DbbeTable *pTable){
+  return pTable->key.dsize;
+}
+int sqliteDbbeDataLength(DbbeTable *pTable){
+  if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){
+    pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key);
+    pTable->readPending = 0;
+  }
+  return pTable->data.dsize;
+}
+
+/*
+** Make is so that the next call to sqliteNextKey() finds the first
+** key of the table.
+*/
+int sqliteDbbeRewind(DbbeTable *pTable){
+  pTable->needRewind = 1;
+  return 0;
+}
+
+/*
+** Read the next key from the table.  Return 1 on success.  Return
+** 0 if there are no more keys.
+*/
+int sqliteDbbeNextKey(DbbeTable *pTable){
+  datum nextkey;
+  int rc;
+  if( pTable==0 || pTable->pFile==0 || pTable->pFile->dbf==0 ){
+    pTable->readPending = 0;
+    return 0;
+  }
+  if( pTable->needRewind ){
+    nextkey = gdbm_firstkey(pTable->pFile->dbf);
+    pTable->needRewind = 0;
+  }else{
+    nextkey = gdbm_nextkey(pTable->pFile->dbf, pTable->key);
+  }
+  datumClear(&pTable->key);
+  datumClear(&pTable->data);
+  pTable->key = nextkey;
+  if( pTable->key.dptr ){
+    pTable->readPending = 1;
+    rc = 1;
+  }else{
+    pTable->needRewind = 1;
+    pTable->readPending = 0;
+    rc = 0;
+  }
+  return rc;
+}
+
+/*
+** The following are state variables for the RC4 algorithm.  We
+** use RC4 as a random number generator.  Each call to RC4 gives
+** a random 8-bit number.
+*/
+static struct {
+  int i, j;
+  int s[256];
+} rc4;
+
+/*
+** Initialize the RC4 algorithm.
+*/
+static void rc4init(char *key, int keylen){
+  int i;
+  char k[256];
+  rc4.j = 0;
+  rc4.i = 0;
+  for(i=0; i<256; i++){
+    rc4.s[i] = i;
+    k[i] = key[i%keylen];
+  }
+  for(i=0; i<256; i++){
+    int t;
+    rc4.j = (rc4.j + rc4.s[i] + k[i]) & 0xff;
+    t = rc4.s[rc4.j];
+    rc4.s[rc4.j] = rc4.s[i];
+    rc4.s[i] = t;
+  }
+}
+
+/*
+** Get a single 8-bit random value from the RC4 algorithm.
+*/
+static int rc4byte(void){
+  int t;
+  rc4.i = (rc4.i + 1) & 0xff;
+  rc4.j = (rc4.j + rc4.s[rc4.i]) & 0xff;
+  t = rc4.s[rc4.i];
+  rc4.s[rc4.i] = rc4.s[rc4.j];
+  rc4.s[rc4.j] = t;
+  t = rc4.s[rc4.i] + rc4.s[rc4.j];
+  return t & 0xff;
+}
+
+/*
+** Get a new integer key.
+*/
+int sqliteDbbeNew(DbbeTable *pTable){
+  static int isInit = 0;
+  int iKey;
+  datum key;
+  int go = 1;
+  int i;
+
+  if( !isInit ){
+    struct stat statbuf;
+    stat(pTable->pFile->zName, &statbuf);
+    time(&statbuf.st_ctime);
+    rc4init((char*)&statbuf, sizeof(statbuf));
+    isInit = 1;
+  }
+  if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 1;
+  while( go ){
+    iKey = 0;
+    for(i=0; i<4; i++){
+      iKey = (iKey<<8) + rc4byte();
+    }
+    key.dptr = (char*)&iKey;
+    key.dsize = 4;
+    go = gdbm_exists(pTable->pFile->dbf, key);
+  }
+  return iKey;
+}   
+
+/*
+** Write an entry into the table.  Overwrite any prior entry with the
+** same key.
+*/
+int sqliteDbbePut(DbbeTable *pTable, int nKey,char *pKey,int nData,char *pData){
+  datum data, key;
+  if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 0;
+  data.dsize = nData;
+  data.dptr = pData;
+  key.dsize = nKey;
+  key.dptr = pKey;
+  gdbm_store(pTable->pFile->dbf, key, data, GDBM_REPLACE);
+  datumClear(&pTable->key);
+  datumClear(&pTable->data);
+  return 1;
+}
+
+/*
+** Remove an entry from a table, if the entry exists.
+*/
+int sqliteDbbeDelete(DbbeTable *pTable, int nKey, char *pKey){
+  datum key;
+  datumClear(&pTable->key);
+  datumClear(&pTable->data);
+  if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 0;
+  key.dsize = nKey;
+  key.dptr = pKey;
+  gdbm_delete(pTable->pFile->dbf, key);
+  return 1;
+}
+
+/*
+** Open a temporary file.
+*/
+FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){
+  char *zFile;
+  char zBuf[30];
+  int i;
+
+  for(i=0; i<pBe->nTemp; i++){
+    if( pBe->apTemp[i]==0 ) break;
+  }
+  if( i>=pBe->nTemp ){
+    pBe->nTemp++;
+    pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
+  }
+  if( pBe->apTemp==0 ) return 0;
+  sprintf(zBuf, "/_temp_%d~", i);
+  zFile = 0;
+  sqliteSetString(&zFile, pBe->zDir, zBuf, 0);
+  pBe->apTemp[i] = fopen(zFile, "w+");
+  sqliteFree(zFile);
+  return pBe->apTemp[i];
+}
+
+/*
+** Close a temporary file opened using sqliteDbbeOpenTempFile()
+*/
+void sqliteDbbeCloseTempFile(Dbbe *pBe, FILE *f){
+  int i;
+  for(i=0; i<pBe->nTemp; i++){
+    if( pBe->apTemp[i]==f ){
+      char *zFile;
+      char zBuf[30];
+      sprintf(zBuf, "/_temp_%d~", i);
+      zFile = 0;
+      sqliteSetString(&zFile, pBe->zDir, zBuf, 0);
+      unlink(zFile);
+      sqliteFree(zFile);
+      pBe->apTemp[i] = 0;
+      break;
+    }
+  }
+  fclose(f);
+}
diff --git a/src/dbbe.h b/src/dbbe.h
new file mode 100644
index 0000000..26e83a6
--- /dev/null
+++ b/src/dbbe.h
@@ -0,0 +1,119 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This file defines the interface to the database backend (Dbbe).
+**
+** The database backend is designed to be as general as possible
+** so that it can easily be replaced by a different backend.
+** This library was originally designed to support the following
+** backends: GDBM, NDBM, SDBM, Berkeley DB.
+**
+** $Id: dbbe.h,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#ifndef _SQLITE_DBBE_H_
+#define _SQLITE_DBBE_H_
+#include <stdio.h>
+
+/*
+** The database backend supports two opaque structures.  A Dbbe is
+** a context for the entire set of tables forming a complete
+** database.  A DbbeTable is a single table.  
+**
+** The DbbeTable structure holds some state information, such as
+** the key and data from the last retrieval.  For this reason, 
+** the backend must allow the creation of multiple independent
+** DbbeTable structures for each table in the database.
+*/
+typedef struct Dbbe Dbbe;
+typedef struct DbbeTable DbbeTable;
+
+/*
+** The 18 interface routines.
+*/
+
+/* Open a complete database */
+Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr);
+
+/* Close the whole database. */
+void sqliteDbbeClose(Dbbe*);
+
+/* Open a particular table of a previously opened database.
+** Create the table if it doesn't already exist and writeable!=0.
+*/
+DbbeTable *sqliteDbbeOpenTable(Dbbe*, const char *zTableName, int writeable);
+
+/* Delete a table from the database */
+void sqliteDbbeDropTable(Dbbe*, const char *zTableName);
+
+/* Close a table */
+void sqliteDbbeCloseTable(DbbeTable*);
+
+/* Fetch an entry from a table with the given key.  Return 1 if
+** successful and 0 if no such entry exists.
+*/
+int sqliteDbbeFetch(DbbeTable*, int nKey, char *pKey);
+
+/* Retrieve the key or data used for the last fetch.  Only size
+** bytes are read beginning with the offset-th byte.  The return
+** value is the actual number of bytes read.
+*/
+int sqliteDbbeCopyKey(DbbeTable*, int offset, int size, char *zBuf);
+int sqliteDbbeCopyData(DbbeTable*, int offset, int size, char *zBuf);
+
+/* Retrieve the key or data.  The result is ephemeral.
+*/
+char *sqliteDbbeReadKey(DbbeTable*, int offset);
+char *sqliteDbbeReadData(DbbeTable*, int offset);
+
+/* Return the length of the most recently fetched key or data. */
+int sqliteDbbeKeyLength(DbbeTable*);
+int sqliteDbbeDataLength(DbbeTable*);
+
+/* Retrieve the next entry in the table.  The first key is retrieved
+** the first time this routine is called, or after a call to
+** sqliteDbbeRewind().  The return value is 1 if there is another
+** entry, or 0 if there are no more entries. */
+int sqliteDbbeNextKey(DbbeTable*);
+
+/* Make it so that the next call to sqliteDbbeNextKey() returns
+** the first entry of the table. */
+int sqliteDbbeRewind(DbbeTable*);
+
+/* Get a new integer key for this table. */
+int sqliteDbbeNew(DbbeTable*);
+
+/* Write an entry into a table.  If another entry already exists with
+** the same key, the old entry is discarded first.
+*/
+int sqliteDbbePut(DbbeTable*, int nKey, char *pKey, int nData, char *pData);
+
+/* Remove an entry from the table */
+int sqliteDbbeDelete(DbbeTable*, int nKey, char *pKey);
+
+/* Open a file suitable for temporary storage */
+FILE *sqliteDbbeOpenTempFile(Dbbe*);
+
+/* Close a temporary file */
+void sqliteDbbeCloseTempFile(Dbbe *, FILE *);
+
+#endif /* defined(_SQLITE_DBBE_H_) */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..4bbc75c
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,219 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** Main file for the SQLite library.  The routines in this file
+** implement the programmer interface to the library.  Routines in
+** other files are for internal use by SQLite and should not be
+** accessed by users of the library.
+**
+** $Id: main.c,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include "sqliteInt.h"
+
+/*
+** This is the callback routine for the code that initializes the
+** database.  Each callback contains text of a CREATE TABLE or
+** CREATE INDEX statement that must be parsed to yield the internal
+** structures that describe the tables.
+*/
+static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
+  sqlite *db = (sqlite*)pDb;
+  Parse sParse;
+  int nErr;
+  char *zErrMsg = 0;
+
+  if( argc!=1 ) return 0;
+  memset(&sParse, 0, sizeof(sParse));
+  sParse.db = db;
+  sParse.initFlag = 1;
+  nErr = sqliteRunParser(&sParse, argv[0], &zErrMsg);
+  return nErr;
+}
+
+/*
+** Open a new SQLite database.  Construct an "sqlite" structure to define
+** the state of this database and return a pointer to that structure.
+*/
+sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
+  sqlite *db;
+  Vdbe *vdbe;
+  Table *pTab;
+  char *azArg[2];
+  static char master_schema[] = 
+     "CREATE TABLE " MASTER_NAME " (\n"
+     "  type text,\n"
+     "  name text,\n"
+     "  tbl_name text,\n"
+     "  sql text\n"
+     ")"
+  ;
+
+  /* The following program is used to initialize the internal
+  ** structure holding the tables and indexes of the database.
+  ** The database contains a special table named "sqlite_master"
+  ** defined as follows:
+  **
+  **    CREATE TABLE sqlite_master (
+  **        type       text,    --  Either "table" or "index"
+  **        name       text,    --  Name of table or index
+  **        tbl_name   text,    --  Associated table 
+  **        sql        text     --  The CREATE statement for this object
+  **    );
+  **
+  ** The sqlite_master table contains a single entry for each table
+  ** and each index.  The "type" field tells whether the entry is
+  ** a table or index.  The "name" field is the name of the object.
+  ** The "tbl_name" is the name of the associated table.  For tables,
+  ** the tbl_name field is always the same as name.  For indices, the
+  ** tbl_name field contains the name of the table that the index
+  ** indexes.  Finally, the sql field contains the complete text of
+  ** the CREATE TABLE or CREATE INDEX statement that originally created
+  ** the table or index.
+  **
+  ** The following program invokes its callback on the SQL for each
+  ** table then goes back and invokes the callback on the
+  ** SQL for each index.  The callback will invoke the
+  ** parser to build the internal representation of the
+  ** database scheme.
+  */
+  static VdbeOp initProg[] = {
+    { OP_Open,     0, 0,  MASTER_NAME},
+    { OP_Next,     0, 8,  0},           /* 1 */
+    { OP_Field,    0, 0,  0},
+    { OP_String,   0, 0,  "table"},
+    { OP_Ne,       0, 1,  0},
+    { OP_Field,    0, 3,  0},
+    { OP_Callback, 1, 0,  0},
+    { OP_Goto,     0, 1,  0},
+    { OP_Rewind,   0, 0,  0},           /* 8 */
+    { OP_Next,     0, 16, 0},           /* 9 */
+    { OP_Field,    0, 0,  0},
+    { OP_String,   0, 0,  "index"},
+    { OP_Ne,       0, 9,  0},
+    { OP_Field,    0, 3,  0},
+    { OP_Callback, 1, 0,  0},
+    { OP_Goto,     0, 9,  0},
+    { OP_Halt,     0, 0,  0},           /* 16 */
+  };
+
+  /* Allocate space to hold the main database structure */
+  db = sqliteMalloc( sizeof(sqlite) );
+  if( pzErrMsg ) *pzErrMsg = 0;
+  if( db==0 ){
+    sqliteSetString(pzErrMsg, "out of memory", 0);
+    return 0;
+  }
+  
+  /* Open the backend database driver */
+  db->pBe = sqliteDbbeOpen(zFilename, (mode&0222)!=0, mode!=0, pzErrMsg);
+  if( db->pBe==0 ){
+    sqliteFree(db);
+    return 0;
+  }
+
+  /* Create a virtual machine to run the initialization program.  Run
+  ** the program.  The delete the virtual machine.
+  */
+  azArg[0] = master_schema;
+  azArg[1] = 0;
+  sqliteOpenCb(db, 1, azArg, 0);
+  pTab = sqliteFindTable(db, MASTER_NAME);
+  if( pTab ){
+    pTab->readOnly = 1;
+  }
+  vdbe = sqliteVdbeCreate(db->pBe);
+  sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
+  sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg);
+  sqliteVdbeDelete(vdbe);
+  return db;
+}
+
+/*
+** Close an existing SQLite database
+*/
+void sqlite_close(sqlite *db){
+  int i;
+  sqliteDbbeClose(db->pBe);
+  for(i=0; i<N_HASH; i++){
+    Table *pNext, *pList = db->apTblHash[i];
+    db->apTblHash[i] = 0;
+    while( pList ){
+      pNext = pList->pHash;
+      pList->pHash = 0;
+      sqliteDeleteTable(db, pList);
+      pList = pNext;
+    }
+  }
+  sqliteFree(db);
+}
+
+/*
+** Return TRUE if the given SQL string ends in a semicolon.
+*/
+int sqlite_complete(const char *zSql){
+  int i;
+  int lastWasSemi = 0;
+
+  i = 0;
+  while( i>=0 && zSql[i]!=0 ){
+    int tokenType;
+    int n;
+
+    n = sqliteGetToken(&zSql[i], &tokenType);
+    switch( tokenType ){
+      case TK_SPACE:
+      case TK_COMMENT:
+        break;
+      case TK_SEMI:
+        lastWasSemi = 1;
+        break;
+      default:
+        lastWasSemi = 0;
+        break;
+    }
+    i += n;
+  }
+  return lastWasSemi;
+}
+
+/*
+** Execute SQL code 
+*/
+int sqlite_exec(
+  sqlite *db,                 /* The database on which the SQL executes */
+  char *zSql,                 /* The SQL to be executed */
+  sqlite_callback xCallback,  /* Invoke this callback routine */
+  void *pArg,                 /* First argument to xCallback() */
+  char **pzErrMsg             /* Write error messages here */
+){
+  Parse sParse;
+  int nErr;
+
+  if( pzErrMsg ) *pzErrMsg = 0;
+  memset(&sParse, 0, sizeof(sParse));
+  sParse.db = db;
+  sParse.xCallback = xCallback;
+  sParse.pArg = pArg;
+  nErr = sqliteRunParser(&sParse, zSql, pzErrMsg);
+  return nErr;
+}
diff --git a/src/shell.c b/src/shell.c
new file mode 100644
index 0000000..0812747
--- /dev/null
+++ b/src/shell.c
@@ -0,0 +1,384 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This file contains code to implement the "sqlite" command line
+** utility for accessing SQLite databases.
+**
+** $Id: shell.c,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "sqlite.h"
+#include <unistd.h>
+#include <ctype.h>
+
+#if !defined(NO_READLINE)
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+/*
+** An pointer to an instance of this structure is passed from
+** the main program to the callback.  This is used to communicate
+** state and mode information.
+*/
+struct callback_data {
+  int cnt;           /* Number of records displayed so far */
+  FILE *out;         /* Write results here */
+  int mode;          /* An output mode setting */
+  int showHeader;    /* True to show column names in List or Column mode */
+  char separator[20];/* Separator character for MODE_List */
+  int colWidth[30];  /* Width of each column when in column mode */
+};
+
+/*
+** These are the allowed modes.
+*/
+#define MODE_Line     0  /* One field per line.  Blank line between records */
+#define MODE_Column   1  /* One record per line in neat columns */
+#define MODE_List     2  /* One record per line with a separator */
+
+/*
+** Number of elements in an array
+*/
+#define ArraySize(X)  (sizeof(X)/sizeof(X[0]))
+
+/*
+** This is the callback routine that the SQLite library
+** invokes for each row of a query result.
+*/
+static int callback(void *pArg, int nArg, char **azArg, char **azCol){
+  int i;
+  struct callback_data *p = (struct callback_data*)pArg;
+  switch( p->mode ){
+    case MODE_Line: {
+      if( p->cnt++>0 ) fprintf(p->out,"\n");
+      for(i=0; i<nArg; i++){
+        fprintf(p->out,"%s = %s\n", azCol[i], azArg[i]);
+      }
+      break;
+    }
+    case MODE_Column: {
+      if( p->cnt++==0 && p->showHeader ){
+        for(i=0; i<nArg; i++){
+          int w;
+          if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
+             w = p->colWidth[i]; 
+          }else{
+             w = 10;
+          }
+          fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": "  ");
+        }
+        for(i=0; i<nArg; i++){
+          int w;
+          if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
+             w = p->colWidth[i];
+          }else{
+             w = 10;
+          }
+          fprintf(p->out,"%-*.*s%s",w,w,"-------------------------------------",
+                  i==nArg-1 ? "\n": "  ");
+        }
+      }
+      for(i=0; i<nArg; i++){
+        int w;
+        if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
+           w = p->colWidth[i];
+        }else{
+           w = 10;
+        }
+        fprintf(p->out,"%-*.*s%s",w,w,azArg[i], i==nArg-1 ? "\n": "  ");
+      }
+      break;
+    }
+    case MODE_List: {
+      if( p->cnt++==0 && p->showHeader ){
+        for(i=0; i<nArg; i++){
+          fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
+        }
+      }
+      for(i=0; i<nArg; i++){
+        fprintf(p->out,"%s%s",azArg[i], i==nArg-1 ? "\n" : p->separator);
+      }
+      break;
+    }
+  }      
+  return 0;
+}
+
+/*
+** Text of a help message
+*/
+static char zHelp[] = 
+  ".exit                  Exit this program\n"
+  ".explain               Set output mode suitable for EXPLAIN\n"
+  ".header ON|OFF         Turn display of headers on or off\n"
+  ".help                  Show this message\n"
+  ".indices TABLE         Show names of all indices on TABLE\n"
+  ".mode MODE             Set mode to one of \"line\", \"column\", or"
+                                      " \"list\"\n"
+  ".output FILENAME       Send output to FILENAME\n"
+  ".output stdout         Send output to the screen\n"
+  ".schema ?TABLE?        Show the CREATE statements\n"
+  ".separator STRING      Change separator string for \"list\" mode\n"
+  ".tables                List names all tables in the database\n"
+  ".width NUM NUM ...     Set column widths for \"column\" mode\n"
+;
+
+/*
+** If an input line begins with "." then invoke this routine to
+** process that line.
+*/
+static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
+  int i = 1;
+  int nArg = 0;
+  int n, c;
+  char *azArg[50];
+
+  /* Parse the input line into tokens.
+  */
+  while( zLine[i] && nArg<ArraySize(azArg) ){
+    while( isspace(zLine[i]) ){ i++; }
+    if( zLine[i]=='\'' || zLine[i]=='"' ){
+      int delim = zLine[i++];
+      azArg[nArg++] = &zLine[i];
+      while( zLine[i] && zLine[i]!=delim ){ i++; }
+      if( zLine[i]==delim ){
+        zLine[i++] = 0;
+      }
+    }else{
+      azArg[nArg++] = &zLine[i];
+      while( zLine[i] && !isspace(zLine[i]) ){ i++; }
+      if( zLine[i] ) zLine[i++] = 0;
+    }
+  }
+
+  /* Process the input line.
+  */
+  if( nArg==0 ) return;
+  n = strlen(azArg[0]);
+  c = azArg[0][0];
+
+  if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
+    exit(0);
+  }else
+
+  if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
+    p->mode = MODE_Column;
+    p->showHeader = 1;
+    p->colWidth[0] = 4;
+    p->colWidth[1] = 12;
+    p->colWidth[2] = 5;
+    p->colWidth[3] = 5;
+    p->colWidth[4] = 40;
+  }else
+
+  if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
+    int j;
+    char *z = azArg[1];
+    int val = atoi(azArg[1]);
+    for(j=0; z[j]; j++){
+      if( isupper(z[j]) ) z[j] = tolower(z[j]);
+    }
+    if( strcmp(z,"on")==0 ){
+      val = 1;
+    }else if( strcmp(z,"yes")==0 ){
+      val = 1;
+    } 
+    p->showHeader = val;
+  }else
+
+  if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
+    fprintf(stderr,zHelp);
+  }else
+
+  if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
+    struct callback_data data;
+    char *zErrMsg = 0;
+    char zSql[1000];
+    memcpy(&data, p, sizeof(data));
+    data.showHeader = 0;
+    data.mode = MODE_List;
+    sprintf(zSql, "SELECT name FROM sqlite_master "
+                  "WHERE type='index' AND tbl_name='%.900s'", azArg[1]);
+    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      free(zErrMsg);
+    }
+  }else
+
+  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
+    int n2 = strlen(azArg[1]);
+    if( strncmp(azArg[1],"line",n2)==0 ){
+      p->mode = MODE_Line;
+    }else if( strncmp(azArg[1],"column",n2)==0 ){
+      p->mode = MODE_Column;
+    }else if( strncmp(azArg[1],"list",n2)==0 ){
+      p->mode = MODE_List;
+    }
+  }else
+
+  if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
+    if( p->out!=stdout ){
+      fclose(p->out);
+    }
+    if( strcmp(azArg[1],"stdout")==0 ){
+      p->out = stdout;
+    }else{
+      p->out = fopen(azArg[1], "w");
+      if( p->out==0 ){
+        fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
+        p->out = stdout;
+      }
+    }
+  }else
+
+  if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
+    struct callback_data data;
+    char *zErrMsg = 0;
+    char zSql[1000];
+    memcpy(&data, p, sizeof(data));
+    data.showHeader = 0;
+    data.mode = MODE_List;
+    if( nArg>1 ){
+      sprintf(zSql, "SELECT sql FROM sqlite_master WHERE name='%.900s'",
+         azArg[1]);
+    }else{
+      sprintf(zSql, "SELECT sql FROM sqlite_master "
+         "ORDER BY tbl_name, type DESC, name");
+    }
+    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      free(zErrMsg);
+    }
+  }else
+
+  if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
+    sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
+  }else
+
+  if( c=='t' && strncmp(azArg[0], "tables", n)==0 ){
+    struct callback_data data;
+    char *zErrMsg = 0;
+    static char zSql[] = "SELECT name FROM sqlite_master WHERE type='table'";
+    memcpy(&data, p, sizeof(data));
+    data.showHeader = 0;
+    data.mode = MODE_List;
+    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      free(zErrMsg);
+    }
+  }else
+
+  if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
+    int j;
+    for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
+      p->colWidth[j-1] = atoi(azArg[j]);
+    }
+  }else
+
+  {
+    fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
+      azArg[0]);
+  }
+}
+
+int main(int argc, char **argv){
+  sqlite *db;
+  char *zErrMsg = 0;
+  struct callback_data data;
+
+  if( argc!=2 && argc!=3 ){
+    fprintf(stderr,"Usage: %s FILENAME ?SQL?\n", *argv);
+    exit(1);
+  }
+  db = sqlite_open(argv[1], 0666, &zErrMsg);
+  if( db==0 ){
+    fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1], zErrMsg);
+    exit(1);
+  }
+  memset(&data, 0, sizeof(data));
+  data.out = stdout;
+  if( argc==3 ){
+    data.mode = MODE_List;
+    strcpy(data.separator,"|");
+    if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
+      fprintf(stderr,"SQL error: %s\n", zErrMsg);
+      exit(1);
+    }
+  }else{
+    char *zLine;
+    char *zSql = 0;
+    int nSql = 0;
+    int istty = isatty(0);
+    data.mode = MODE_Line;
+    strcpy(data.separator,"|");
+    data.showHeader = 0;
+    if( istty ){
+      printf(
+        "Enter \".help\" for instructions\n"
+      );
+    }
+    while( (zLine = readline(istty ? (zSql==0 ? "sql> " : ".... ") : 0))!=0 ){
+      if( zLine && zLine[0]=='.' ){
+        do_meta_command(zLine, db, &data);
+        free(zLine);
+        continue;
+      }
+      if( zSql==0 ){
+        nSql = strlen(zLine);
+        zSql = malloc( nSql+1 );
+        strcpy(zSql, zLine);
+      }else{
+        int len = strlen(zLine);
+        zSql = realloc( zSql, nSql + len + 2 );
+        if( zSql==0 ){
+          fprintf(stderr,"%s: out of memory!\n", *argv);
+          exit(1);
+        }
+        strcpy(&zSql[nSql++], "\n");
+        strcpy(&zSql[nSql], zLine);
+        nSql += len;
+      }
+      free(zLine);
+      if( sqlite_complete(zSql) ){
+        data.cnt = 0;
+        if( sqlite_exec(db, zSql, callback, &data, &zErrMsg)!=0 
+             && zErrMsg!=0 ){
+          printf("SQL error: %s\n", zErrMsg);
+          free(zErrMsg);
+          zErrMsg = 0;
+        }
+        free(zSql);
+        zSql = 0;
+        nSql = 0;
+      }
+    }
+  }
+  sqlite_close(db);
+  return 0;
+}
diff --git a/src/sqlite.h b/src/sqlite.h
new file mode 100644
index 0000000..26b4874
--- /dev/null
+++ b/src/sqlite.h
@@ -0,0 +1,118 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This header file defines the interface that the sqlite library
+** presents to client programs.
+**
+** @(#) $Id: sqlite.h,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#ifndef _SQLITE_H_
+#define _SQLITE_H_
+
+/*
+** Each open sqlite database is represented by an instance of the
+** following opaque structure.
+*/
+typedef struct sqlite sqlite;
+
+/*
+** A function to open a new sqlite database.  
+**
+** If the database does not exist and mode indicates write
+** permission, then a new database is created.  If the database
+** does not exist and mode does not indicate write permission,
+** then the open fails, an error message generated (if errmsg!=0)
+** and the function returns 0.
+** 
+** If mode does not indicates user write permission, then the 
+** database is opened read-only.
+**
+** The Truth:  As currently implemented, all databases are opened
+** for writing all the time.  Maybe someday we will provide the
+** ability to open a database readonly.  The mode parameters is
+** provide in anticipation of that enhancement.
+*/
+sqlite *sqlite_open(const char *filename, int mode, char **errmsg);
+
+/*
+** A function to close the database.
+**
+** Call this function with a pointer to a structure that was previously
+** returned from sqlite_open() and the corresponding database will by closed.
+*/
+void sqlite_close(sqlite *);
+
+/*
+** The type for a callback function.
+*/
+typedef int (*sqlite_callback)(void*,int,char**, char**);
+
+/*
+** A function to executes one or more statements of SQL.
+**
+** If one or more of the SQL statements are queries, then
+** the callback function specified by the 3rd parameter is
+** invoked once for each row of the query result.  This callback
+** should normally return 0.  If the callback returns a non-zero
+** value then the query is aborted, all subsequent SQL statements
+** are skipped and the sqlite_exec() function returns the same
+** value that the callback returned.
+**
+** The 4th parameter is an arbitrary pointer that is passed
+** to the callback function as its first parameter.
+**
+** The 2nd parameter to the callback function is the number of
+** columns in the query result.  The 3rd parameter is an array
+** of string holding the values for each column.  The 4th parameter
+** is an array of strings holding the names of each column.
+**
+** The callback function may be NULL, even for queries.  A NULL
+** callback is not an error.  It just means that no callback
+** will be invoked.
+**
+** If an error occurs while parsing or evaluating the SQL (but
+** not while executing the callback) then an appropriate error
+** message is written into memory obtained from malloc() and
+** *errmsg is made to point to that message.  If errmsg==NULL,
+** then no error message is ever written.  The return value is
+** non-zero if an error occurs.
+*/
+int sqlite_exec(
+  sqlite*,                      /* An open database */
+  char *sql,                    /* SQL to be executed */
+  sqlite_callback,              /* Callback function */
+  void *,                       /* 1st argument to callback function */
+  char **errmsg                 /* Error msg written here */
+);
+
+
+/* This function returns true if the given input string comprises
+** one or more complete SQL statements.
+**
+** The algorithm is simple.  If the last token other than spaces
+** and comments is a semicolon, then return true.  otherwise return
+** false.
+*/
+int sqlite_complete(const char *sql);
+
+#endif /* _SQLITE_H_ */
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
new file mode 100644
index 0000000..b2bf129
--- /dev/null
+++ b/src/sqliteInt.h
@@ -0,0 +1,235 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** Internal interface definitions for SQLite.
+**
+** @(#) $Id: sqliteInt.h,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include "sqlite.h"
+#include "dbbe.h"
+#include "vdbe.h"
+#include "parse.h"
+#include <gdbm.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/*
+** The number of entries in the in-memory hash table holding the
+** schema.
+*/
+#define N_HASH        51
+
+/*
+** Name of the master database table.  The master database table
+** is a special table that holds the names and attributes of all
+** user tables and indices.
+*/
+#define MASTER_NAME   "sqlite_master"
+
+/*
+** A convenience macro that returns the number of elements in
+** an array.
+*/
+#define ArraySize(X)    (sizeof(X)/sizeof(X[0]))
+
+/*
+** Forward references to structures
+*/
+typedef struct Table Table;
+typedef struct Index Index;
+typedef struct Instruction Instruction;
+typedef struct Expr Expr;
+typedef struct ExprList ExprList;
+typedef struct Parse Parse;
+typedef struct Token Token;
+typedef struct IdList IdList;
+typedef struct WhereInfo WhereInfo;
+
+/*
+** Each database is an instance of the following structure
+*/
+struct sqlite {
+  Dbbe *pBe;                 /* The backend driver */
+  int flags;                 /* Miscellanous flags */
+  Table *apTblHash[N_HASH];  /* All tables of the database */
+  Index *apIdxHash[N_HASH];  /* All indices of the database */
+};
+
+/*
+** Possible values for the flags field of sqlite
+*/
+#define SQLITE_VdbeTrace    0x00000001
+
+/*
+** Each table is represented in memory by
+** an instance of the following structure
+*/
+struct Table {
+  char *zName;        /* Name of the table */
+  Table *pHash;       /* Next table with same hash on zName */
+  int nCol;           /* Number of columns in this table */
+  int readOnly;       /* True if this table should not be written by the user */
+  char **azCol;       /* Name of each column */
+  Index *pIndex;      /* List of indices on this table. */
+};
+
+/*
+** Each index is represented in memory by and
+** instance of the following structure.
+*/
+struct Index {
+  char *zName;        /* Name of this index */
+  Index *pHash;       /* Next index with the same hash on zName */
+  int nField;         /* Number of fields in the table indexed by this index */
+  int *aiField;       /* Indices of fields used by this index.  1st is 0 */
+  Table *pTable;      /* The table being indexed */
+  Index *pNext;       /* The next index associated with the same table */
+};
+
+/*
+** Each token coming out of the lexer is an instance of
+** this structure.
+*/
+struct Token {
+  char *z;      /* Text of the token */
+  int n;        /* Number of characters in this token */
+};
+
+/*
+** Each node of an expression in the parse tree is an instance
+** of this structure
+*/
+struct Expr {
+  int op;                /* Operation performed by this node */
+  Expr *pLeft, *pRight;  /* Left and right subnodes */
+  ExprList *pList;       /* A list of expressions used as a function argument */
+  Token token;           /* An operand token */
+  int iTable, iField;    /* When op==TK_FIELD, then this node means the
+                         ** iField-th field of the iTable-th table */
+};
+
+/*
+** A list of expressions.  Each expression may optionally have a
+** name.  An expr/name combination can be used in several ways, such
+** as the list of "expr AS ID" fields following a "SELECT" or in the
+** list of "ID = expr" items in an UPDATE.  A list of expressions can
+** also be used as the argument to a function, in which case the azName
+** field is not used.
+*/
+struct ExprList {
+  int nExpr;             /* Number of expressions on the list */
+  struct {
+    Expr *pExpr;           /* The list of expressions */
+    char *zName;           /* Token associated with this expression */
+    int idx;               /* ... */
+  } *a;                  /* One entry for each expression */
+};
+
+/*
+** A list of identifiers.
+*/
+struct IdList {
+  int nId;         /* Number of identifiers on the list */
+  struct {
+    char *zName;      /* Text of the identifier. */
+    char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
+    Table *pTab;      /* Table corresponding to zName */
+    int idx;          /* Index of a field name in the table */
+  } *a;            /* One entry for each identifier on the list */
+};
+
+/*
+** The WHERE clause processing routine has two halves.  The
+** first part does the start of the WHERE loop and the second
+** half does the tail of the WHERE loop.  An instance of
+** this structure is returned by the first half and passed
+** into the second half to give some continuity.
+*/
+struct WhereInfo {
+  Parse *pParse;
+  IdList *pTabList;
+  int iContinue;
+  int iBreak;
+};
+
+/*
+** An SQL parser context
+*/
+struct Parse {
+  sqlite *db;          /* The main database structure */
+  sqlite_callback xCallback;  /* The callback function */
+  void *pArg;          /* First argument to the callback function */
+  char *zErrMsg;       /* An error message */
+  Token sErrToken;     /* The token at which the error occurred */
+  Token sFirstToken;   /* The first token parsed */
+  Token sLastToken;    /* The last token parsed */
+  Table *pNewTable;    /* A table being constructed by CREATE TABLE */
+  Vdbe *pVdbe;         /* An engine for executing database bytecode */
+  int explain;         /* True if the EXPLAIN flag is found on the query */
+  int initFlag;        /* True if reparsing CREATE TABLEs */
+  int nErr;            /* Number of errors seen */
+};
+
+/*
+** Internal function prototypes
+*/
+int sqliteStrICmp(const char *, const char *);
+int sqliteStrNICmp(const char *, const char *, int);
+int sqliteHashNoCase(const char *, int);
+int sqliteCompare(const char *, const char *);
+int sqliteSortCompare(const char *, const char *);
+void *sqliteMalloc(int);
+void sqliteFree(void*);
+void *sqliteRealloc(void*,int);
+int sqliteGetToken(const char*, int *);
+void sqliteSetString(char **, const char *, ...);
+void sqliteSetNString(char **, ...);
+int sqliteRunParser(Parse*, char*, char **);
+void sqliteExec(Parse*);
+Expr *sqliteExpr(int, Expr*, Expr*, Token*);
+Expr *sqliteExprFunction(ExprList*, Token*);
+void sqliteExprDelete(Expr*);
+ExprList *sqliteExprListAppend(ExprList*,Expr*,Token*);
+void sqliteExprListDelete(ExprList*);
+void sqliteStartTable(Parse*,Token*,Token*);
+void sqliteAddColumn(Parse*,Token*);
+void sqliteEndTable(Parse*,Token*);
+void sqliteDropTable(Parse*, Token*);
+void sqliteDeleteTable(sqlite*, Table*);
+void sqliteInsert(Parse*, Token*, ExprList*, IdList*);
+IdList *sqliteIdListAppend(IdList*, Token*);
+void sqliteIdListAddAlias(IdList*, Token*);
+void sqliteIdListDelete(IdList*);
+void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, Token*, Token*);
+void sqliteDropIndex(Parse*, Token*);
+void sqliteSelect(Parse*, ExprList*, IdList*, Expr*, ExprList*);
+void sqliteDeleteFrom(Parse*, Token*, Expr*);
+void sqliteUpdate(Parse*, Token*, ExprList*, Expr*);
+WhereInfo *sqliteWhereBegin(Parse*, IdList*, Expr*, int);
+void sqliteWhereEnd(WhereInfo*);
+void sqliteExprCode(Parse*, Expr*);
+void sqliteExprIfTrue(Parse*, Expr*, int);
+void sqliteExprIfFalse(Parse*, Expr*, int);
+Table *sqliteFindTable(sqlite*,char*);
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
new file mode 100644
index 0000000..55e9a85
--- /dev/null
+++ b/src/tclsqlite.c
@@ -0,0 +1,241 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** A TCL Interface to SQLite
+**
+** $Id: tclsqlite.c,v 1.1 2000/05/29 14:26:01 drh Exp $
+*/
+#include "sqlite.h"
+#include <tcl.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+** An instance of this structure passes information thru the sqlite
+** logic from the original TCL command into the callback routine.
+*/
+typedef struct CallbackData CallbackData;
+struct CallbackData {
+  Tcl_Interp *interp;       /* The TCL interpreter */
+  char *zArray;             /* The array into which data is written */
+  char *zCode;              /* The code to execute for each row */
+  int once;                 /* Set only for the first invocation of callback */
+};
+
+/*
+** Called for each row of the result.
+*/
+static int DbEvalCallback(
+  void *clientData,      /* An instance of CallbackData */
+  int nCol,              /* Number of columns in the result */
+  char ** azCol,         /* Data for each column */
+  char ** azN            /* Name for each column */
+){
+  CallbackData *cbData = (CallbackData*)clientData;
+  int i, rc;
+  if( cbData->zArray[0] ){
+    if( cbData->once ){
+      for(i=0; i<nCol; i++){
+        Tcl_SetVar2(cbData->interp, cbData->zArray, "*", azN[i],
+           TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
+      }
+    }
+    for(i=0; i<nCol; i++){
+      Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], azCol[i], 0);
+    }
+  }else{
+    for(i=0; i<nCol; i++){
+      Tcl_SetVar(cbData->interp, azN[i], azCol[i], 0);
+    }
+  }
+  cbData->once = 0;
+  rc = Tcl_Eval(cbData->interp, cbData->zCode);
+  return rc;
+}
+
+/*
+** Called when the command is deleted.
+*/
+static void DbDeleteCmd(void *db){
+  sqlite_close((sqlite*)db);
+}
+
+/*
+** The "sqlite" command below creates a new Tcl command for each
+** connection it opens to an SQLite database.  This routine is invoked
+** whenever one of those connection-specific commands is executed
+** in Tcl.  For example, if you run Tcl code like this:
+**
+**       sqlite db1  "my_database"
+**       db1 close
+**
+** The first command opens a connection to the "my_database" database
+** and calls that connection "db1".  The second command causes this
+** subroutine to be invoked.
+*/
+static int DbCmd(void *cd, Tcl_Interp *interp, int argc, char **argv){
+  char *z;
+  int n, c;
+  sqlite *db = cd;
+  if( argc<2 ){
+    Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+        " SUBCOMMAND ...\"", 0);
+    return TCL_ERROR;
+  }
+  z = argv[1];
+  n = strlen(z);
+  c = z[0];
+
+  /*    $db close
+  **
+  ** Shutdown the database
+  */
+  if( c=='c' && n>=2 && strncmp(z,"close",n)==0 ){
+    Tcl_DeleteCommand(interp, argv[0]);
+  }else
+
+  /*    $db complete SQL
+  **
+  ** Return TRUE if SQL is a complete SQL statement.  Return FALSE if
+  ** additional lines of input are needed.  This is similar to the
+  ** built-in "info complete" command of Tcl.
+  */
+  if( c=='c' && n>=2 && strncmp(z,"complete",n)==0 ){
+    char *zRes;
+    if( argc!=3 ){
+      Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+          " complete SQL\"", 0);
+      return TCL_ERROR;
+    }
+    zRes = sqlite_complete(argv[2]) ? "1" : "0";
+    Tcl_SetResult(interp, zRes, TCL_VOLATILE);
+  }else
+   
+  /*
+  **    $db eval $sql ?array {  ...code... }?
+  **
+  ** The SQL statement in $sql is evaluated.  For each row, the values are
+  ** placed in elements of the array named "array" and ...code.. is executed.
+  ** If "array" and "code" are omitted, then no callback is every invoked.
+  ** If "array" is an empty string, then the values are placed in variables
+  ** that have the same name as the fields extracted by the query.
+  */
+  if( c=='e' && strncmp(z,"eval",n)==0 ){
+    CallbackData cbData;
+    char *zErrMsg;
+    int rc;
+
+    if( argc!=5 && argc!=3 ){
+      Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+         " eval SQL ?ARRAY-NAME CODE?", 0);
+      return TCL_ERROR;
+    }
+    if( argc==5 ){
+      cbData.interp = interp;
+      cbData.zArray = argv[3];
+      cbData.zCode = argv[4];
+      zErrMsg = 0;
+      rc = sqlite_exec(db, argv[2], DbEvalCallback, &cbData, &zErrMsg);
+    }else{
+      rc = sqlite_exec(db, argv[2], 0, 0, &zErrMsg);
+    }
+    if( zErrMsg ){
+      Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
+      free(zErrMsg);
+    }
+    return rc;
+  }
+
+  /* The default
+  */
+  else{
+    Tcl_AppendResult(interp,"unknown subcommand \"", z, 
+        "\" - should be one of: close complete eval", 0);
+    return TCL_ERROR;
+  }
+  return TCL_OK;
+}
+
+/*
+**   sqlite DBNAME FILENAME ?MODE?
+**
+** This is the main Tcl command.  When the "sqlite" Tcl command is
+** invoked, this routine runs to process that command.
+**
+** The first argument, DBNAME, is an arbitrary name for a new
+** database connection.  This command creates a new command named
+** DBNAME that is used to control that connection.  The database
+** connection is deleted when the DBNAME command is deleted.
+**
+** The second argument is the name of the directory that contains
+** the sqlite database that is to be accessed.
+*/
+static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
+  int mode;
+  sqlite *p;
+  char *zErrMsg;
+  if( argc!=3 && argc!=4 ){
+    Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+       " HANDLE FILENAME ?MODE?\"", 0);
+    return TCL_ERROR;
+  }
+  if( argc==3 ){
+    mode = 0;
+  }else if( Tcl_GetInt(interp, argv[3], &mode)!=TCL_OK ){
+    return TCL_ERROR;
+  }
+  zErrMsg = 0;
+  p = sqlite_open(argv[2], mode, &zErrMsg);
+  if( p==0 ){
+    Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
+    free(zErrMsg);
+    return TCL_ERROR;
+  }
+  Tcl_CreateCommand(interp, argv[1], DbCmd, p, DbDeleteCmd);
+  return TCL_OK;
+}
+
+/*
+** Initialize this module.
+**
+** This Tcl module contains only a single new Tcl command named "sqlite".
+** (Hence there is no namespace.  There is no point in using a namespace
+** if the extension only supplies one new name!)  The "sqlite" command is
+** used to open a new SQLite database.  See the DbMain() routine above
+** for additional information.
+*/
+int Sqlite_Init(Tcl_Interp *interp){
+  Tcl_CreateCommand(interp, "sqlite", DbMain, 0, 0);
+  return TCL_OK;
+}
+int Sqlite_SafeInit(Tcl_Interp *interp){
+  return TCL_OK;
+}
+
+/*
+** If compiled using mktclapp, this routine runs to initialize
+** everything.
+*/
+int Et_AppInit(Tcl_Interp *interp){
+  return Sqlite_Init(interp);
+}
diff --git a/src/tokenize.c b/src/tokenize.c
new file mode 100644
index 0000000..f762b67
--- /dev/null
+++ b/src/tokenize.c
@@ -0,0 +1,375 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** An tokenizer for SQL
+**
+** This file contains C code that splits an SQL input string up into
+** individual tokens and sends those tokens one-by-one over to the
+** parser for analysis.
+**
+** $Id: tokenize.c,v 1.1 2000/05/29 14:26:02 drh Exp $
+*/
+#include "sqliteInt.h"
+#include <ctype.h>
+
+/*
+** All the keywords of the SQL language are stored as in a hash
+** table composed of instances of the following structure.
+*/
+typedef struct Keyword Keyword;
+struct Keyword {
+  char *zName;             /* The keyword name */
+  int len;                 /* Number of characters in the keyword */
+  int tokenType;           /* The token value for this keyword */
+  Keyword *pNext;          /* Next keyword with the same hash */
+};
+
+/*
+** These are the keywords
+*/
+static Keyword aKeywordTable[] = {
+  { "AND",               0, TK_AND,              0 },
+  { "AS",                0, TK_AS,               0 },
+  { "ASC",               0, TK_ASC,              0 },
+  { "BY",                0, TK_BY,               0 },
+  { "CHECK",             0, TK_CHECK,            0 },
+  { "CONSTRAINT",        0, TK_CONSTRAINT,       0 },
+  { "CREATE",            0, TK_CREATE,           0 },
+  { "DEFAULT",           0, TK_DEFAULT,          0 },
+  { "DELETE",            0, TK_DELETE,           0 },
+  { "DESC",              0, TK_DESC,             0 },
+  { "DROP",              0, TK_DROP,             0 },
+  { "EXPLAIN",           0, TK_EXPLAIN,          0 },
+  { "FROM",              0, TK_FROM,             0 },
+  { "INDEX",             0, TK_INDEX,            0 },
+  { "INSERT",            0, TK_INSERT,           0 },
+  { "INTO",              0, TK_INTO,             0 },
+  { "IS",                0, TK_IS,               0 },
+  { "ISNULL",            0, TK_ISNULL,           0 },
+  { "KEY",               0, TK_KEY,              0 },
+  { "NOT",               0, TK_NOT,              0 },
+  { "NOTNULL",           0, TK_NOTNULL,          0 },
+  { "NULL",              0, TK_NULL,             0 },
+  { "ON",                0, TK_ON,               0 },
+  { "OR",                0, TK_OR,               0 },
+  { "ORDER",             0, TK_ORDER,            0 },
+  { "PRIMARY",           0, TK_PRIMARY,          0 },
+  { "SELECT",            0, TK_SELECT,           0 },
+  { "SET",               0, TK_SET,              0 },
+  { "TABLE",             0, TK_TABLE,            0 },
+  { "UNIQUE",            0, TK_UNIQUE,           0 },
+  { "UPDATE",            0, TK_UPDATE,           0 },
+  { "VALUES",            0, TK_VALUES,           0 },
+  { "WHERE",             0, TK_WHERE,            0 },
+};
+
+/*
+** This is the hash table
+*/
+#define KEY_HASH_SIZE 37
+static Keyword *apHashTable[KEY_HASH_SIZE];
+
+
+/*
+** This function looks up an identifier to determine if it is a
+** keyword.  If it is a keyword, the token code of that keyword is 
+** returned.  If the input is not a keyword, TK_ID is returned.
+*/
+static int sqliteKeywordCode(const char *z, int n){
+  int h;
+  Keyword *p;
+  if( aKeywordTable[0].len==0 ){
+    /* Initialize the keyword hash table */
+    int i;
+    int n;
+    n = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]);
+    for(i=0; i<n; i++){
+      aKeywordTable[i].len = strlen(aKeywordTable[i].zName);
+      h = sqliteHashNoCase(aKeywordTable[i].zName, aKeywordTable[i].len);
+      h %= KEY_HASH_SIZE;
+      aKeywordTable[i].pNext = apHashTable[h];
+      apHashTable[h] = &aKeywordTable[i];
+    }
+  }
+  h = sqliteHashNoCase(z, n) % KEY_HASH_SIZE;
+  for(p=apHashTable[h]; p; p=p->pNext){
+    if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){
+      return p->tokenType;
+    }
+  }
+  return TK_ID;
+}
+
+/*
+** Return the length of the token that begins at z[0].  Return
+** -1 if the token is (or might be) incomplete.  Store the token
+** type in *tokenType before returning.
+*/
+int sqliteGetToken(const char *z, int *tokenType){
+  int i;
+  switch( *z ){
+    case ' ': case '\t': case '\n': case '\f': {
+      for(i=1; z[i] && isspace(z[i]); i++){}
+      *tokenType = TK_SPACE;
+      return i;
+    }
+    case '-': {
+      if( z[1]==0 ) return -1;
+      if( z[1]=='-' ){
+        for(i=2; z[i] && z[i]!='\n'; i++){}
+        *tokenType = TK_COMMENT;
+        return i;
+      }
+      *tokenType = TK_MINUS;
+      return 1;
+    }
+    case '(': {
+      *tokenType = TK_LP;
+      return 1;
+    }
+    case ')': {
+      *tokenType = TK_RP;
+      return 1;
+    }
+    case ';': {
+      *tokenType = TK_SEMI;
+      return 1;
+    }
+    case '+': {
+      *tokenType = TK_PLUS;
+      return 1;
+    }
+    case '*': {
+      *tokenType = TK_STAR;
+      return 1;
+    }
+    case '/': {
+      *tokenType = TK_SLASH;
+      return 1;
+    }
+    case '=': {
+      *tokenType = TK_EQ;
+      return 1 + (z[1]=='=');
+    }
+    case '<': {
+      if( z[1]=='=' ){
+        *tokenType = TK_LE;
+        return 2;
+      }else if( z[1]=='>' ){
+        *tokenType = TK_NE;
+        return 2;
+      }else{
+        *tokenType = TK_LT;
+        return 1;
+      }
+    }
+    case '>': {
+      if( z[1]=='=' ){
+        *tokenType = TK_GE;
+        return 2;
+      }else{
+        *tokenType = TK_GT;
+        return 1;
+      }
+    }
+    case '!': {
+      if( z[1]!='=' ){
+        *tokenType = TK_ILLEGAL;
+        return 1;
+      }else{
+        *tokenType = TK_NE;
+        return 2;
+      }
+    }
+    case ',': {
+      *tokenType = TK_COMMA;
+      return 1;
+    }
+    case '\'': case '"': {
+      int delim = z[0];
+      for(i=1; z[i]; i++){
+        if( z[i]==delim ){
+          if( z[i+1]==delim ){
+            i++;
+          }else{
+            break;
+          }
+        }
+      }
+      if( z[i] ) i++;
+      *tokenType = TK_STRING;
+      return i;
+    }
+    case '.': {
+      if( !isdigit(z[1]) ){
+        *tokenType = TK_DOT;
+        return 1;
+      }
+      /* Fall thru into the next case */
+    }
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9': {
+      for(i=1; z[i] && isdigit(z[i]); i++){}
+      if( z[i]=='.' ){
+        i++;
+        while( z[i] && isdigit(z[i]) ){ i++; }
+        if( (z[i]=='e' || z[i]=='E') &&
+           ( isdigit(z[i+1]) 
+            || ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
+           )
+        ){
+          i += 2;
+          while( z[i] && isdigit(z[i]) ){ i++; }
+        }
+        *tokenType = TK_FLOAT;
+      }else if( z[0]=='.' ){
+        *tokenType = TK_FLOAT;
+      }else{
+        *tokenType = TK_INTEGER;
+      }
+      return i;
+    }
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z': case '_':
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z': {
+      for(i=1; z[i] && (isalnum(z[i]) || z[i]=='_'); i++){}
+      *tokenType = sqliteKeywordCode(z, i);
+      return i;
+    }
+    default: {
+      break;
+    }
+  }
+  *tokenType = TK_ILLEGAL;
+  return 1;
+}
+
+/*
+** Run the parser on the given SQL string.  The parser structure is
+** passed in.  Return the number of errors.
+*/
+int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
+  int nErr = 0;
+  int i;
+  void *pEngine;
+  int once = 1;
+  static FILE *trace = 0;
+  extern void *sqliteParserAlloc(void*(*)(int));
+  extern void sqliteParserFree(void*, void(*)(void*));
+  extern int sqliteParser(void*, int, ...);
+  extern void sqliteParserTrace(FILE*, char *);
+
+  i = 0;
+  pEngine = sqliteParserAlloc(sqliteMalloc);
+  if( pEngine==0 ){
+    sqliteSetString(pzErrMsg, "out of memory", 0);
+    return 1;
+  }
+  sqliteParserTrace(trace, "parser: ");
+  while( nErr==0 && i>=0 && zSql[i]!=0 ){
+    int tokenType;
+    
+    pParse->sLastToken.z = &zSql[i];
+    pParse->sLastToken.n = sqliteGetToken(&zSql[i], &tokenType);
+    i += pParse->sLastToken.n;
+    if( once ){
+      pParse->sFirstToken = pParse->sLastToken;
+      once = 0;
+    }
+    switch( tokenType ){
+      case TK_SPACE:
+        break;
+      case TK_COMMENT: {
+        /* Various debugging modes can be turned on and off using
+        ** special SQL comments.  Check for the special comments
+        ** here and take approriate action if found.
+        */
+        char *z = pParse->sLastToken.z;
+        if( sqliteStrNICmp(z,"--parser-trace-on--",19)==0 ){
+          trace = stderr;
+          sqliteParserTrace(trace, "parser: ");
+        }else if( sqliteStrNICmp(z,"--parser-trace-off--", 20)==0 ){
+          trace = 0;
+          sqliteParserTrace(trace, "parser: ");
+        }else if( sqliteStrNICmp(z,"--vdbe-trace-on--",17)==0 ){
+          pParse->db->flags |= SQLITE_VdbeTrace;
+        }else if( sqliteStrNICmp(z,"--vdbe-trace-off--", 19)==0 ){
+          pParse->db->flags &= ~SQLITE_VdbeTrace;
+        }
+        break;
+      }
+      case TK_ILLEGAL:
+        sqliteSetNString(pzErrMsg, "illegal token: \"", -1, 
+           pParse->sLastToken.z, pParse->sLastToken.n, 0);
+        nErr++;
+        break;
+      default:
+        sqliteParser(pEngine, tokenType, pParse->sLastToken, pParse);
+        if( pParse->zErrMsg ){
+          sqliteSetNString(pzErrMsg, "near \"", -1, 
+             pParse->sErrToken.z, pParse->sErrToken.n,
+             "\": ", -1,
+             pParse->zErrMsg, -1,
+             0);
+          nErr++;
+        }
+        break;
+    }
+  }
+  if( nErr==0 ){
+    sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
+    if( pParse->zErrMsg ){
+       sqliteSetNString(pzErrMsg, "near \"", -1, 
+          pParse->sErrToken.z, pParse->sErrToken.n,
+          "\": ", -1,
+          pParse->zErrMsg, -1,
+          0);
+       nErr++;
+    }
+  }
+  sqliteParserFree(pEngine, sqliteFree);
+  if( pParse->zErrMsg ){
+    if( pzErrMsg ){
+      *pzErrMsg = pParse->zErrMsg;
+    }else{
+      sqliteFree(pParse->zErrMsg);
+    }
+    if( !nErr ) nErr++;
+  }
+  if( pParse->pVdbe ){
+    sqliteVdbeDelete(pParse->pVdbe);
+    pParse->pVdbe = 0;
+  }
+  if( pParse->pNewTable ){
+    sqliteDeleteTable(pParse->db, pParse->pNewTable);
+    pParse->pNewTable = 0;
+  }
+  return nErr;
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..1306345
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,445 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** Utility functions used throughout sqlite.
+**
+** This file contains functions for allocating memory, comparing
+** strings, and stuff like that.
+**
+** $Id: util.c,v 1.1 2000/05/29 14:26:02 drh Exp $
+*/
+#include "sqliteInt.h"
+#include <stdarg.h>
+#include <ctype.h>
+
+/*
+** Allocate new memory and set it to zero.  Return NULL if
+** no memory is available.
+*/
+void *sqliteMalloc(int n){
+  void *p = malloc(n);
+  if( p==0 ) return 0;
+  memset(p, 0, n);
+  return p;
+}
+
+/*
+** Free memory previously obtained from sqliteMalloc()
+*/
+void sqliteFree(void *p){
+  if( p ) free(p);
+}
+
+/*
+** Resize a prior allocation.  If p==0, then this routine
+** works just like sqliteMalloc().  If n==0, then this routine
+** works just like sqliteFree().
+*/
+void *sqliteRealloc(void *p, int n){
+  if( p==0 ){
+    return sqliteMalloc(n);
+  }
+  if( n==0 ){
+    sqliteFree(p);
+    return 0;
+  }
+  return realloc(p, n);
+}
+
+/*
+** Create a string from the 2nd and subsequent arguments (up to the
+** first NULL argument), store the string in memory obtained from
+** sqliteMalloc() and make the pointer indicated by the 1st argument
+** point to that string.
+*/
+void sqliteSetString(char **pz, const char *zFirst, ...){
+  va_list ap;
+  int nByte;
+  const char *z;
+  char *zResult;
+
+  if( pz==0 ) return;
+  nByte = strlen(zFirst) + 1;
+  va_start(ap, zFirst);
+  while( (z = va_arg(ap, const char*))!=0 ){
+    nByte += strlen(z);
+  }
+  va_end(ap);
+  sqliteFree(*pz);
+  *pz = zResult = sqliteMalloc( nByte );
+  if( zResult==0 ) return;
+  strcpy(zResult, zFirst);
+  zResult += strlen(zResult);
+  va_start(ap, zFirst);
+  while( (z = va_arg(ap, const char*))!=0 ){
+    strcpy(zResult, z);
+    zResult += strlen(zResult);
+  }
+  va_end(ap);
+}
+
+/*
+** Works like sqliteSetString, but each string is now followed by
+** a length integer.  -1 means use the whole string.
+*/
+void sqliteSetNString(char **pz, ...){
+  va_list ap;
+  int nByte;
+  const char *z;
+  char *zResult;
+  int n;
+
+  if( pz==0 ) return;
+  nByte = 0;
+  va_start(ap, pz);
+  while( (z = va_arg(ap, const char*))!=0 ){
+    n = va_arg(ap, int);
+    if( n<=0 ) n = strlen(z);
+    nByte += n;
+  }
+  va_end(ap);
+  sqliteFree(*pz);
+  *pz = zResult = sqliteMalloc( nByte + 1 );
+  if( zResult==0 ) return;
+  va_start(ap, pz);
+  while( (z = va_arg(ap, const char*))!=0 ){
+    n = va_arg(ap, int);
+    if( n<=0 ) n = strlen(z);
+    strncpy(zResult, z, n);
+    zResult += n;
+  }
+  *zResult = 0;
+  va_end(ap);
+}
+
+/* An array to map all upper-case characters into their corresponding
+** lower-case character. 
+*/
+static unsigned char UpperToLower[] = {
+      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
+     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+     36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+     54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
+    104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
+    122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
+    108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
+    126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+    144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
+    162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
+    180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
+    198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
+    216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
+    234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
+    252,253,254,255
+};
+
+/*
+** This function computes a hash on the name of a keyword.
+** Case is not significant.
+*/
+int sqliteHashNoCase(const char *z, int n){
+  int h = 0;
+  int c;
+  if( n<=0 ) n = strlen(z);
+  while( n-- > 0 && (c = *z++)!=0 ){
+    h = h<<3 ^ h ^ UpperToLower[c];
+  }
+  if( h<0 ) h = -h;
+  return h;
+}
+
+/*
+** Some system shave stricmp().  Others have strcasecmp().  Because
+** there is no consistency, we will define our own.
+*/
+int sqliteStrICmp(const char *zLeft, const char *zRight){
+  register unsigned char *a, *b;
+  a = (unsigned char *)zLeft;
+  b = (unsigned char *)zRight;
+  while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
+  return *a - *b;
+}
+int sqliteStrNICmp(const char *zLeft, const char *zRight, int N){
+  register unsigned char *a, *b;
+  a = (unsigned char *)zLeft;
+  b = (unsigned char *)zRight;
+  while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
+  return N<=0 ? 0 : *a - *b;
+}
+
+/* Notes on string comparisions.
+**
+** We want the main string comparision function used for sorting to
+** sort both numbers and alphanumeric words into the correct sequence.
+** The same routine should do both without prior knowledge of which
+** type of text the input represents.  It should even work for strings
+** which are a mixture of text and numbers.
+**
+** To accomplish this, we keep track of a state number while scanning
+** the two strings.  The states are as follows:
+**
+**    1      Beginning of word
+**    2      Arbitrary text
+**    3      Integer
+**    4      Negative integer
+**    5      Real number
+**    6      Negative real
+**
+** The scan begins in state 1, beginning of word.  Transitions to other
+** states are determined by characters seen, as shown in the following
+** chart:
+**
+**      Current State         Character Seen  New State
+**      --------------------  --------------  -------------------
+**      0 Beginning of word   "-"             3 Negative integer
+**                            digit           2 Integer
+**                            space           0 Beginning of word
+**                            otherwise       1 Arbitrary text
+**
+**      1 Arbitrary text      space           0 Beginning of word
+**                            digit           2 Integer
+**                            otherwise       1 Arbitrary text
+**
+**      2 Integer             space           0 Beginning of word
+**                            "."             4 Real number
+**                            digit           2 Integer
+**                            otherwise       1 Arbitrary text
+**
+**      3 Negative integer    space           0 Beginning of word
+**                            "."             5 Negative Real num
+**                            digit           3 Negative integer
+**                            otherwise       1 Arbitrary text
+**
+**      4 Real number         space           0 Beginning of word
+**                            digit           4 Real number
+**                            otherwise       1 Arbitrary text
+**
+**      5 Negative real num   space           0 Beginning of word
+**                            digit           5 Negative real num
+**                            otherwise       1 Arbitrary text
+**
+** To implement this state machine, we first classify each character
+** into on of the following categories:
+**
+**      0  Text
+**      1  Space
+**      2  Digit
+**      3  "-"
+**      4  "."
+**
+** Given an arbitrary character, the array charClass[] maps that character
+** into one of the atove categories.
+*/
+static const unsigned char charClass[] = {
+        /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
+/* 0x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0,
+/* 1x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 2x */   1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 0,
+/* 3x */   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+/* 4x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 5x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 6x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 7x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 8x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 9x */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Ax */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Bx */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Cx */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Dx */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Ex */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* Fx */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define N_CHAR_CLASS 5
+
+/*
+** Given the current state number (0 thru 5), this array figures
+** the new state number given the character class.
+*/
+static const unsigned char stateMachine[] = {
+ /* Text,  Space, Digit, "-", "." */
+      1,      0,    2,    3,   1,      /* State 0: Beginning of word */
+      1,      0,    2,    1,   1,      /* State 1: Arbitrary text */
+      1,      0,    2,    1,   4,      /* State 2: Integer */
+      1,      0,    3,    1,   5,      /* State 3: Negative integer */
+      1,      0,    4,    1,   1,      /* State 4: Real number */
+      1,      0,    5,    1,   1,      /* State 5: Negative real num */
+};
+
+/* This routine does a comparison of two strings.  Case is used only
+** if useCase!=0.  Numbers compare in numerical order.
+*/
+static int privateStrCmp(const char *atext, const char *btext, int useCase){
+  register unsigned char *a, *b, *map, ca, cb;
+  int result;
+  register int cclass = 0;
+
+  a = (unsigned char *)atext;
+  b = (unsigned char *)btext;
+  if( useCase ){
+    do{
+      if( (ca= *a++)!=(cb= *b++) ) break;
+      cclass = stateMachine[cclass*N_CHAR_CLASS + charClass[ca]];
+    }while( ca!=0 );
+  }else{
+    map = UpperToLower;
+    do{
+      if( (ca=map[*a++])!=(cb=map[*b++]) ) break;
+      cclass = stateMachine[cclass*N_CHAR_CLASS + charClass[ca]];
+    }while( ca!=0 );
+  }
+  switch( cclass ){
+    case 0:
+    case 1: {
+      if( isdigit(ca) && isdigit(cb) ){
+        cclass = 2;
+      }
+      break;
+    }
+    default: {
+      break;
+    }
+  }
+  switch( cclass ){
+    case 2:
+    case 3: {
+      if( isdigit(ca) ){
+        if( isdigit(cb) ){
+          int acnt, bcnt;
+          acnt = bcnt = 0;
+          while( isdigit(*a++) ) acnt++;
+          while( isdigit(*b++) ) bcnt++;
+          result = acnt - bcnt;
+          if( result==0 ) result = ca-cb;
+        }else{
+          result = 1;
+        }
+      }else if( isdigit(cb) ){
+        result = -1;
+      }else if( ca=='.' ){
+        result = 1;
+      }else if( cb=='.' ){
+        result = -1;
+      }else{
+        result = ca - cb;
+        cclass = 2;
+      }
+      if( cclass==3 ) result = -result;
+      break;
+    }
+    case 0:
+    case 1:
+    case 4: {
+      result = ca - cb;
+      break;
+    }
+    case 5: {
+      result = cb - ca;
+    };
+  }
+  return result;
+}
+
+/* This comparison routine is what we use for comparison operations
+** in an SQL expression.  (Ex:  name<'Hello' or value<5).  Compare two
+** strings.  Use case only as a tie-breaker.  Numbers compare in
+** numerical order.
+*/
+int sqliteCompare(const char *atext, const char *btext){
+  int result;
+  result = privateStrCmp(atext, btext, 0);
+  if( result==0 ) result = privateStrCmp(atext, btext, 1);
+  return result;
+}
+
+/*
+** If you compile just this one file with the -DTEST_COMPARE=1 option,
+** it generates a program to test the comparisons routines.  
+*/
+#ifdef TEST_COMPARE
+#include <stdlib.h>
+#include <stdio.h>
+int sortCmp(const char **a, const char **b){
+  return sqliteCompare(*a, *b);
+}
+int main(int argc, char **argv){
+  int i, j, k, n;
+  static char *azStr[] = {
+     "abc", "aBc", "abcd", "aBcd", 
+     "123", "124", "1234", "-123", "-124", "-1234", 
+     "123.45", "123.456", "123.46", "-123.45", "-123.46", "-123.456", 
+     "x9", "x10", "x-9", "x-10", "X9", "X10",
+  };
+  n = sizeof(azStr)/sizeof(azStr[0]);
+  qsort(azStr, n, sizeof(azStr[0]), sortCmp);
+  for(i=0; i<n; i++){
+    printf("%s\n", azStr[i]);
+  }
+  printf("Sanity1...");
+  fflush(stdout);
+  for(i=0; i<n-1; i++){
+    char *a = azStr[i];
+    for(j=i+1; j<n; j++){
+      char *b = azStr[j];
+      if( sqliteCompare(a,b) != -sqliteCompare(b,a) ){
+        printf("Failed!  \"%s\" vs \"%s\"\n", a, b);
+        i = j = n;
+      }
+    }
+  }
+  if( i<n ){
+    printf(" OK\n");
+  }
+  return 0;
+}
+#endif
+
+/*
+** This routine is used for sorting.  Each key is a list one or more
+** null-terminated strings.  The list is terminated by two null in
+** a row.  For example, the following text is strings:
+**
+**            +one\000-two\000+three\000\000
+**
+** Both arguments will have the same number of strings.  This routine
+** returns negative, zero, or positive if the first argument is less
+** than, equal to, or greater than the first.  (Result is a-b).
+**
+** Every string begins with either a "+" or "-" character.  If the
+** character is "-" then the return value is negated.  This is done
+** to implement a sort in descending order.
+*/
+int sqliteSortCompare(const char *a, const char *b){
+  int len;
+  int res = 0;
+
+  while( res==0 && *a && *b ){
+    res = sqliteCompare(&a[1], &b[1]);
+    if( res==0 ){
+      len = strlen(a) + 1;
+      a += len;
+      b += len;
+    }
+  }
+  if( *a=='-' ) res = -res;
+  return res;
+}
diff --git a/src/vdbe.c b/src/vdbe.c
new file mode 100644
index 0000000..a93c237
--- /dev/null
+++ b/src/vdbe.c
@@ -0,0 +1,1973 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** The code in this file implements the Virtual Database Engine (VDBE)
+**
+** The SQL parser generates a program which is then executed by
+** the VDBE to do the work of the SQL statement.  VDBE programs are 
+** similar in form to assembly language.  The program consists of
+** a linear sequence of operations.  Each operation has an opcode 
+** and 3 operands.  Operands P1 and P2 are integers.  Operand P3 
+** is a null-terminated string.   The P2 operand must be non-negative.
+** Opcodes will typically ignore one or more operands.  Many opcodes
+** ignore all three operands.
+**
+** Computation results are stored on a stack.  Each entry on the
+** stack is either an integer or a null-terminated string.  An
+** inplicit conversion from one type to the other occurs as necessary.
+** 
+** Most of the code in this file is taken up by the sqliteVdbeExec()
+** function which does the work of interpreting a VDBE program.
+** But other routines are also provided to help in building up
+** a program instruction by instruction.
+**
+** $Id: vdbe.c,v 1.1 2000/05/29 14:26:02 drh Exp $
+*/
+#include "sqliteInt.h"
+
+/*
+** SQL is translated into a sequence of instructions to be
+** executed by a virtual machine.  Each instruction is an instance
+** of the following structure.
+*/
+typedef struct VdbeOp Op;
+
+/*
+** Every table that the virtual machine has open is represented by an
+** instance of the following structure.
+*/
+struct VdbeTable {
+  DbbeTable *pTable;    /* The table structure of the backend */
+  int index;            /* The next index to extract */
+};
+typedef struct VdbeTable VdbeTable;
+
+/*
+** A sorter builds a list of elements to be sorted.  Each element of
+** the list is an instance of the following structure.
+*/
+typedef struct Sorter Sorter;
+struct Sorter {
+  int nKey;           /* Number of bytes in the key */
+  char *zKey;         /* The key by which we will sort */
+  int nData;          /* Number of bytes in the data */
+  char *pData;        /* The data associated with this key */
+  Sorter *pNext;      /* Next in the list */
+};
+
+/* 
+** Number of buckets used for merge-sort.  
+*/
+#define NSORT 30
+
+/*
+** An instance of the virtual machine
+*/
+struct Vdbe {
+  Dbbe *pBe;          /* Opaque context structure used by DB backend */
+  FILE *trace;        /* Write an execution trace here, if not NULL */
+  int nOp;            /* Number of instructions in the program */
+  int nOpAlloc;       /* Number of slots allocated for aOp[] */
+  Op *aOp;            /* Space to hold the virtual machine's program */
+  int nLabel;         /* Number of labels used */
+  int nLabelAlloc;    /* Number of slots allocated in aLabel[] */
+  int *aLabel;        /* Space to hold the labels */
+  int tos;            /* Index of top of stack */
+  int nStackAlloc;    /* Size of the stack */
+  int *iStack;        /* Integer values of the stack */
+  char **zStack;      /* Text or binary values of the stack */
+  char **azColName;   /* Becomes the 4th parameter to callbacks */
+  int nTable;         /* Number of slots in aTab[] */
+  VdbeTable *aTab;    /* On element of this array for each open table */
+  int nList;          /* Number of slots in apList[] */
+  FILE **apList;      /* An open file for each list */
+  int nSort;          /* Number of slots in apSort[] */
+  Sorter **apSort;    /* An open sorter list */
+};
+
+/*
+** Create a new virtual database engine.
+*/
+Vdbe *sqliteVdbeCreate(Dbbe *pBe){
+  Vdbe *p;
+
+  p = sqliteMalloc( sizeof(Vdbe) );
+  p->pBe = pBe;
+  return p;
+}
+
+/*
+** Turn tracing on or off
+*/
+void sqliteVdbeTrace(Vdbe *p, FILE *trace){
+  p->trace = trace;
+}
+
+/*
+** Add a new instruction to the list of instructions current in the
+** VDBE.  Return the address of the new instruction.
+**
+** Parameters:
+**
+**    p               Pointer to the VDBE
+**
+**    op              The opcode for this instruction
+**
+**    p1, p2, p3      Three operands.
+**
+**    lbl             A symbolic label for this instruction.
+**
+** Symbolic labels are negative numbers that stand for the address
+** of instructions that have yet to be coded.  When the instruction
+** is coded, its real address is substituted in the p2 field of
+** prior and subsequent instructions that have the lbl value in
+** their p2 fields.
+*/
+int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2, const char *p3, int lbl){
+  int i, j;
+
+  i = p->nOp;
+  p->nOp++;
+  if( i>=p->nOpAlloc ){
+    int oldSize = p->nOpAlloc;
+    p->nOpAlloc = p->nOpAlloc*2 + 10;
+    p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));
+    if( p->aOp==0 ){
+      p->nOp = 0;
+      p->nOpAlloc = 0;
+      return 0;
+    }
+    memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));
+  }
+  p->aOp[i].opcode = op;
+  p->aOp[i].p1 = p1;
+  if( p2<0 && (-1-p2)<p->nLabel && p->aLabel[-1-p2]>=0 ){
+    p2 = p->aLabel[-1-p2];
+  }
+  p->aOp[i].p2 = p2;
+  if( p3 && p3[0] ){
+    sqliteSetString(&p->aOp[i].p3, p3, 0);
+  }else{
+    p->aOp[i].p3 = 0;
+  }
+  if( lbl<0 && (-lbl)<=p->nLabel ){
+    p->aLabel[-1-lbl] = i;
+    for(j=0; j<i; j++){
+      if( p->aOp[j].p2==lbl ) p->aOp[j].p2 = i;
+    }
+  }
+  return i;
+}
+
+/*
+** Resolve label "x" to be the address of the next instruction to
+** be inserted.
+*/
+void sqliteVdbeResolveLabel(Vdbe *p, int x){
+  int j;
+  if( x<0 && (-x)<=p->nLabel ){
+    p->aLabel[-1-x] = p->nOp;
+    for(j=0; j<p->nOp; j++){
+      if( p->aOp[j].p2==x ) p->aOp[j].p2 = p->nOp;
+    }
+  }
+}
+
+/*
+** Return the address of the next instruction to be inserted.
+*/
+int sqliteVdbeCurrentAddr(Vdbe *p){
+  return p->nOp;
+}
+
+/*
+** Add a whole list of operations to the operation stack.  Return the
+** address of the first operation added.
+*/
+int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){
+  int addr;
+  if( p->nOp + nOp >= p->nOpAlloc ){
+    int oldSize = p->nOpAlloc;
+    p->nOpAlloc = p->nOpAlloc*2 + nOp + 10;
+    p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));
+    if( p->aOp==0 ){
+      p->nOp = 0;
+      p->nOpAlloc = 0;
+      return 0;
+    }
+    memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));
+  }
+  addr = p->nOp;
+  if( nOp>0 ){
+    int i;
+    for(i=0; i<nOp; i++){
+      int p2 = aOp[i].p2;
+      if( p2<0 ) p2 = addr + ADDR(p2);
+      sqliteVdbeAddOp(p, aOp[i].opcode, aOp[i].p1, p2, aOp[i].p3, 0);
+    }
+  }
+  return addr;
+}
+
+/*
+** Change the value of the P3 operand for a specific instruction.
+** This routine is useful when a large program is loaded from a
+** static array using sqliteVdbeAddOpList but we want to make a
+** few minor changes to the program.
+*/
+void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
+  if( p && addr>=0 && p->nOp>addr && zP3 ){
+    sqliteSetNString(&p->aOp[addr].p3, zP3, n, 0);
+  }
+}
+
+/*
+** If the P3 operand to the specified instruction appears
+** to be a quoted string token, then this procedure removes 
+** the quotes.
+**
+** The quoting operator can be either a grave ascent (ASCII 0x27)
+** or a double quote character (ASCII 0x22).  Two quotes in a row
+** resolve to be a single actual quote character within the string.
+*/
+void sqliteVdbeDequoteP3(Vdbe *p, int addr){
+  int quote;
+  int i, j;
+  char *z;
+  if( addr<0 || addr>=p->nOp ) return;
+  z = p->aOp[addr].p3;
+  quote = z[0];
+  if( quote!='\'' && quote!='"' ) return;
+  for(i=1, j=0; z[i]; i++){
+    if( z[i]==quote ){
+      if( z[i+1]==quote ){
+        z[j++] = quote;
+        i++;
+      }else{
+        z[j++] = 0;
+        break;
+      }
+    }else{
+      z[j++] = z[i];
+    }
+  }
+}
+
+/*
+** Create a new symbolic label for an instruction that has yet to be
+** coded.  The symbolic label is really just a negative number.  The
+** label can be used as the P2 value of an operation.  Later, when
+** the label is resolved to a specific address, the VDBE will scan
+** through its operation list and change all values of P2 which match
+** the label into the resolved address.
+**
+** The VDBE knows that a P2 value is a label because labels are
+** always negative and P2 values are suppose to be non-negative.
+** Hence, a negative P2 value is a label that has yet to be resolved.
+*/
+int sqliteVdbeMakeLabel(Vdbe *p){
+  int i;
+  i = p->nLabel++;
+  if( i>=p->nLabelAlloc ){
+    p->nLabelAlloc = p->nLabelAlloc*2 + 10;
+    p->aLabel = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(int));
+  }
+  if( p->aLabel==0 ){
+    p->nLabel = 0;
+    p->nLabelAlloc = 0;
+    return 0;
+  }
+  p->aLabel[i] = -1;
+  return -1-i;
+}
+
+/*
+** Pop the stack N times.  Free any memory associated with the
+** popped stack elements.
+*/
+static void PopStack(Vdbe *p, int N){
+  if( p->zStack==0 ) return;
+  while( p->tos>=0 && N-->0 ){
+    int i = p->tos--;
+    sqliteFree(p->zStack[i]);
+    p->zStack[i] = 0;
+  }    
+}
+
+/*
+** Clean up the VM after execution.
+**
+** This routine will automatically close any tables, list, and/or
+** sorters that were left open.
+*/
+static void Cleanup(Vdbe *p){
+  int i;
+  PopStack(p, p->tos+1);
+  sqliteFree(p->azColName);
+  p->azColName = 0;
+  for(i=0; i<p->nTable; i++){
+    if( p->aTab[i].pTable ){
+      sqliteDbbeCloseTable(p->aTab[i].pTable);
+      p->aTab[i].pTable = 0;
+    }
+  }
+  sqliteFree(p->aTab);
+  p->aTab = 0;
+  p->nTable = 0;
+  for(i=0; i<p->nList; i++){
+    if( p->apList[i] ){
+      sqliteDbbeCloseTempFile(p->pBe, p->apList[i]);
+      p->apList[i] = 0;
+    }
+  }
+  sqliteFree(p->apList);
+  p->apList = 0;
+  p->nList = 0;
+  for(i=0; i<p->nSort; i++){
+    Sorter *pSorter;
+    while( (pSorter = p->apSort[i])!=0 ){
+      p->apSort[i] = pSorter->pNext;
+      sqliteFree(pSorter->zKey);
+      sqliteFree(pSorter->pData);
+      sqliteFree(pSorter);
+    }
+  }
+  sqliteFree(p->apSort);
+  p->apSort = 0;
+  p->nSort = 0;
+}
+
+/*
+** Delete an entire VDBE.
+*/
+void sqliteVdbeDelete(Vdbe *p){
+  int i;
+  if( p==0 ) return;
+  Cleanup(p);
+  if( p->nOpAlloc==0 ){
+    p->aOp = 0;
+    p->nOp = 0;
+  }
+  for(i=0; i<p->nOp; i++){
+    sqliteFree(p->aOp[i].p3);
+  }
+  sqliteFree(p->aOp);
+  sqliteFree(p->aLabel);
+  sqliteFree(p->iStack);
+  sqliteFree(p->zStack);
+  sqliteFree(p);
+}
+
+/*
+** A translation from opcode numbers to opcode names.  Used for testing
+** and debugging only.
+**
+** If any of the numeric OP_ values for opcodes defined in sqliteVdbe.h
+** change, be sure to change this array to match.  You can use the
+** "opNames.awk" awk script which is part of the source tree to regenerate
+** this array, then copy and paste it into this file, if you want.
+*/
+static char *zOpName[] = { 0,
+  "Open",           "Close",          "Destroy",        "Fetch",
+  "New",            "Put",            "Delete",         "Field",
+  "Key",            "Rewind",         "Next",           "ResetIdx",
+  "NextIdx",        "PutIdx",         "DeleteIdx",      "ListOpen",
+  "ListWrite",      "ListRewind",     "ListRead",       "ListClose",
+  "SortOpen",       "SortPut",        "SortMakeRec",    "SortMakeKey",
+  "Sort",           "SortNext",       "SortKey",        "SortCallback",
+  "SortClose",      "MakeRecord",     "MakeKey",        "Goto",
+  "If",             "Halt",           "ColumnCount",    "ColumnName",
+  "Callback",       "Integer",        "String",         "Pop",
+  "Dup",            "Pull",           "Add",            "AddImm",
+  "Subtract",       "Multiply",       "Divide",         "Min",
+  "Max",            "Eq",             "Ne",             "Lt",
+  "Le",             "Gt",             "Ge",             "IsNull",
+  "NotNull",        "Negative",       "And",            "Or",
+  "Not",            "Concat",         "Noop",         
+};
+
+/*
+** Given the name of an opcode, return its number.  Return 0 if
+** there is no match.
+**
+** This routine is used for testing and debugging.
+*/
+int sqliteVdbeOpcode(const char *zName){
+  int i;
+  for(i=1; i<=OP_MAX; i++){
+    if( sqliteStrICmp(zName, zOpName[i])==0 ) return i;
+  }
+  return 0;
+}
+
+/*
+** Give a listing of the program in the virtual machine.
+**
+** The interface is the same as sqliteVdbeExec().  But instead of
+** running the code, it invokes the callback once for each instruction.
+** This feature is used to implement "EXPLAIN".
+*/
+int sqliteVdbeList(
+  Vdbe *p,                   /* The VDBE */
+  sqlite_callback xCallback, /* The callback */
+  void *pArg,                /* 1st argument to callback */
+  char **pzErrMsg            /* Error msg written here */
+){
+  int i, rc;
+  char *azField[6];
+  char zAddr[20];
+  char zP1[20];
+  char zP2[20];
+  static char *azColumnNames[] = {
+     "addr", "opcode", "p1", "p2", "p3", 0
+  };
+
+  if( xCallback==0 ) return 0;
+  azField[0] = zAddr;
+  azField[2] = zP1;
+  azField[3] = zP2;
+  azField[5] = 0;
+  rc = 0;
+  if( pzErrMsg ){ *pzErrMsg = 0; }
+  for(i=0; rc==0 && i<p->nOp; i++){
+    sprintf(zAddr,"%d",i);
+    sprintf(zP1,"%d", p->aOp[i].p1);
+    sprintf(zP2,"%d", p->aOp[i].p2);
+    azField[4] = p->aOp[i].p3;
+    if( azField[4]==0 ) azField[4] = "";
+    azField[1] = zOpName[p->aOp[i].opcode];
+    rc = xCallback(pArg, 5, azField, azColumnNames);
+  }
+  return rc;
+}
+
+/*
+** Make sure space has been allocated to hold at least N
+** stack elements.  Allocate additional stack space if
+** necessary.
+**
+** Return 0 on success and non-zero if there are memory
+** allocation errors.
+*/
+static int NeedStack(Vdbe *p, int N){
+  int oldAlloc;
+  int i;
+  if( N>=p->nStackAlloc ){
+    oldAlloc = p->nStackAlloc;
+    p->nStackAlloc = N + 20;
+    p->iStack = sqliteRealloc(p->iStack, p->nStackAlloc*sizeof(int));
+    p->zStack = sqliteRealloc(p->zStack, p->nStackAlloc*sizeof(char*));
+    if( p->iStack==0 || p->zStack==0 ){
+      sqliteFree(p->iStack);
+      sqliteFree(p->zStack);
+      p->iStack = 0;
+      p->zStack = 0;
+      p->nStackAlloc = 0;
+      return 1;
+    }
+    for(i=oldAlloc; i<p->nStackAlloc; i++){
+      p->zStack[i] = 0;
+    }
+  }
+  return 0;
+}
+
+/*
+** Convert the given stack entity into a string if it isn't one
+** already.  Return non-zero if we run out of memory.
+*/
+static int Stringify(Vdbe *p, int i){
+  if( p->zStack[i]==0 ){
+    char zBuf[30];
+    sprintf(zBuf,"%d",p->iStack[i]);
+    sqliteSetString(&p->zStack[i], zBuf, 0);
+    if( p->zStack[i]==0 ) return 1;
+    p->iStack[i] = strlen(p->zStack[i])+1;
+  }
+  return 0;
+}
+
+/*
+** Convert the given stack entity into a integer if it isn't one
+** already.
+*/
+static int Integerify(Vdbe *p, int i){
+  if( p->zStack[i]!=0 ){
+    p->iStack[i] = atoi(p->zStack[i]);
+    sqliteFree(p->zStack[i]);
+    p->zStack[i] = 0;
+  }
+  return p->iStack[i];
+}
+
+/*
+** The parameters are pointers to the head of two sorted lists
+** of Sorter structures.  Merge these two lists together and return
+** a single sorted list.  This routine forms the core of the merge-sort
+** algorithm.
+**
+** In the case of a tie, left sorts in front of right.
+*/
+static Sorter *Merge(Sorter *pLeft, Sorter *pRight){
+  Sorter sHead;
+  Sorter *pTail;
+  pTail = &sHead;
+  pTail->pNext = 0;
+  while( pLeft && pRight ){
+    int c = sqliteSortCompare(pLeft->zKey, pRight->zKey);
+    if( c<=0 ){
+      pTail->pNext = pLeft;
+      pLeft = pLeft->pNext;
+    }else{
+      pTail->pNext = pRight;
+      pRight = pRight->pNext;
+    }
+    pTail = pTail->pNext;
+  }
+  if( pLeft ){
+    pTail->pNext = pLeft;
+  }else if( pRight ){
+    pTail->pNext = pRight;
+  }
+  return sHead.pNext;
+}
+
+
+/*
+** Execute the program in the VDBE.
+**
+** If an error occurs, an error message is written to memory obtained
+** from sqliteMalloc() and *pzErrMsg is made to point to that memory.
+** The return parameter is the number of errors.
+**
+** If the callback every returns non-zero, then the program exits
+** immediately.  No error message is written but the return value
+** from the callback because the return value of this routine.
+*/
+int sqliteVdbeExec(
+  Vdbe *p,                   /* The VDBE */
+  sqlite_callback xCallback, /* The callback */
+  void *pArg,                /* 1st argument to callback */
+  char **pzErrMsg            /* Error msg written here */
+){
+  int pc;                    /* The program counter */
+  Op *pOp;                   /* Current operation */
+  int rc;                    /* Value to return */
+  char zBuf[100];            /* Space to sprintf() and integer */
+
+  p->tos = -1;
+  rc = 0;
+  if( pzErrMsg ){ *pzErrMsg = 0; }
+  for(pc=0; rc==0 && pc<p->nOp && pc>=0; pc++){
+    pOp = &p->aOp[pc];
+    if( p->trace ){
+      fprintf(p->trace,"%4d %-12s %4d %4d %s\n",
+        pc, zOpName[pOp->opcode], pOp->p1, pOp->p2,
+           pOp->p3 ? pOp->p3 : "");
+    }
+    switch( pOp->opcode ){
+      /* Opcode:  Goto P2 * *
+      **
+      ** An unconditional jump to address P2.
+      ** The next instruction executed will be 
+      ** the one at index P2 from the beginning of
+      ** the program.
+      */
+      case OP_Goto: {
+        pc = pOp->p2;
+        if( pc<0 || pc>p->nOp ){
+          sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+          rc = 1;
+        }
+        pc--;
+        break;
+      }
+
+      /* Opcode:  Halt * * *
+      **
+      ** Exit immediately.  All open DBs, Lists, Sorts, etc are closed
+      ** automatically.
+      */
+      case OP_Halt: {
+        pc = p->nOp-1;
+        break;
+      }
+
+      /* Opcode: Integer P1 * *
+      **
+      ** The integer value P1 is pushed onto the stack.
+      */
+      case OP_Integer: {
+        int i = ++p->tos;
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        p->iStack[i] = pOp->p1;
+        p->zStack[i] = 0;
+        break;
+      }
+
+      /* Opcode: String * * P3
+      **
+      ** The string value P3 is pushed onto the stack.
+      */
+      case OP_String: {
+        int i = ++p->tos;
+        char *z;
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        z = pOp->p3;
+        if( z==0 ) z = "";
+        p->iStack[i] = strlen(z) + 1;
+        sqliteSetString(&p->zStack[i], z, 0);
+        break;
+      }
+
+      /* Opcode: Pop P1 * *
+      **
+      ** P1 elements are popped off of the top of stack and discarded.
+      */
+      case OP_Pop: {
+        PopStack(p, pOp->p1);
+        break;
+      }
+
+      /* Opcode: Dup P1 * *
+      **
+      ** A copy of the P1-th element of the stack 
+      ** is made and pushed onto the top of the stack.
+      ** The top of the stack is element 0.  So the
+      ** instruction "Dup 0 0 0" will make a copy of the
+      ** top of the stack.
+      */
+      case OP_Dup: {
+        int i = p->tos - pOp->p1;
+        int j = ++p->tos;
+        if( i<0 ) goto not_enough_stack;
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        p->iStack[j] = p->iStack[i];
+        if( p->zStack[i] ){
+          p->zStack[j] = sqliteMalloc( p->iStack[j] );
+          if( p->zStack[j] ) memcpy(p->zStack[j], p->zStack[i], p->iStack[j]);
+        }else{
+          p->zStack[j] = 0;
+        }
+        break;
+      }
+
+      /* Opcode: Pull P1 * *
+      **
+      ** The P1-th element is removed its current location on 
+      ** the stack and pushed back on top of the stack.  The
+      ** top of the stack is element 0, so "Pull 0 0 0" is
+      ** a no-op.
+      */
+      case OP_Pull: {
+        int from = p->tos - pOp->p1;
+        int to = p->tos;
+        int i;
+        int ti;
+        char *tz;
+        if( from<0 ) goto not_enough_stack;
+        ti = p->iStack[from];
+        tz = p->zStack[from];
+        for(i=from; i<to; i++){
+          p->iStack[i] = p->iStack[i+1];
+          p->zStack[i] = p->zStack[i+1];
+        }
+        p->iStack[to] = ti;
+        p->zStack[to] = tz;
+        break;
+      }
+
+      /* Opcode: ColumnCount P1 * *
+      **
+      ** Specify the number of column values that will appear in the
+      ** array passed as the 4th parameter to the callback.  No checking
+      ** is done.  If this value is wrong, a coredump can result.
+      */
+      case OP_ColumnCount: {
+        p->azColName = sqliteRealloc(p->azColName, (pOp->p1+1)*sizeof(char*));
+        if( p->azColName==0 ) goto no_mem;
+        p->azColName[pOp->p1] = 0;
+        break;
+      }
+
+      /* Opcode: ColumnName P1 * P3
+      **
+      ** P3 becomes the P1-th column name (first is 0).  An array of pointers
+      ** to all column names is passed as the 4th parameter to the callback.
+      ** The ColumnCount opcode must be executed first to allocate space to
+      ** hold the column names.  Failure to do this will likely result in
+      ** a coredump.
+      */
+      case OP_ColumnName: {
+        p->azColName[pOp->p1] = pOp->p3 ? pOp->p3 : "";
+        break;
+      }
+
+      /* Opcode: Callback P1 * *
+      **
+      ** Pop P1 values off the stack and form them into an array.  Then
+      ** invoke the callback function using the newly formed array as the
+      ** 3rd parameter.
+      */
+      case OP_Callback: {
+        int i = p->tos - pOp->p1 + 1;
+        int j;
+        if( i<0 ) goto not_enough_stack;
+        if( NeedStack(p, p->tos+2) ) goto no_mem;
+        for(j=i; j<=p->tos; j++){
+          if( Stringify(p, j) ) goto no_mem;
+        }
+        p->zStack[p->tos+1] = 0;
+        rc = xCallback(pArg, pOp->p1, &p->zStack[i], p->azColName);
+        PopStack(p, pOp->p1);
+        break;
+      }
+
+      /* Opcode: Concat * * *
+      **
+      ** Pop two elements from the stack.  Append the first (what used
+      ** to be the top of stack) to the second (the next on stack) to 
+      ** form a new string.  Push the new string back onto the stack.
+      */
+      case OP_Concat: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        char *z;
+        if( nos<0 ) goto not_enough_stack;
+        Stringify(p, tos);
+        Stringify(p, nos);
+        z = 0;
+        sqliteSetString(&z, p->zStack[nos], p->zStack[tos], 0);
+        PopStack(p, 1);
+        sqliteFree(p->zStack[nos]);
+        p->zStack[nos] = z;
+        p->iStack[nos] = strlen(p->zStack[nos])+1;
+        break;
+      }
+
+      /* Opcode: Add * * *
+      **
+      ** Pop the top two elements from the stack, add them together,
+      ** and push the result back onto the stack.  If either element
+      ** is a string then it is converted to a double using the atof()
+      ** function before the addition.
+      */
+      /* Opcode: Multiply * * *
+      **
+      ** Pop the top two elements from the stack, multiply them together,
+      ** and push the result back onto the stack.  If either element
+      ** is a string then it is converted to a double using the atof()
+      ** function before the multiplication.
+      */
+      /* Opcode: Subtract * * *
+      **
+      ** Pop the top two elements from the stack, subtract the
+      ** first (what was on top of the stack) from the second (the
+      ** next on stack)
+      ** and push the result back onto the stack.  If either element
+      ** is a string then it is converted to a double using the atof()
+      ** function before the subtraction.
+      */
+      /* Opcode: Divide * * *
+      **
+      ** Pop the top two elements from the stack, divide the
+      ** first (what was on top of the stack) from the second (the
+      ** next on stack)
+      ** and push the result back onto the stack.  If either element
+      ** is a string then it is converted to a double using the atof()
+      ** function before the division.  Division by zero causes the
+      ** program to abort with an error.
+      */
+      case OP_Add:
+      case OP_Subtract:
+      case OP_Multiply:
+      case OP_Divide: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        if( nos<0 ) goto not_enough_stack;
+        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
+          int a, b;
+          a = p->iStack[tos];
+          b = p->iStack[nos];
+          switch( pOp->opcode ){
+            case OP_Add:         b += a;       break;
+            case OP_Subtract:    b -= a;       break;
+            case OP_Multiply:    b *= a;       break;
+            default: {
+              if( a==0 ){ 
+                sqliteSetString(pzErrMsg, "division by zero", 0);
+                rc = 1;
+                goto cleanup;
+              }
+              b /= a;
+              break;
+            }
+          }
+          PopStack(p, 1);
+          p->iStack[nos] = b;
+        }else{
+          double a, b;
+          Stringify(p, tos);
+          Stringify(p, nos);
+          a = atof(p->zStack[tos]);
+          b = atof(p->zStack[nos]);
+          switch( pOp->opcode ){
+            case OP_Add:         b += a;       break;
+            case OP_Subtract:    b -= a;       break;
+            case OP_Multiply:    b *= a;       break;
+            default: {
+              if( a==0.0 ){ 
+                sqliteSetString(pzErrMsg, "division by zero", 0);
+                rc = 1;
+                goto cleanup;
+              }
+              b /= a;
+              break;
+            }
+          }
+          sprintf(zBuf,"%g",b);
+          PopStack(p, 1);
+          sqliteSetString(&p->zStack[nos], zBuf, 0);
+          if( p->zStack[nos]==0 ) goto no_mem;
+          p->iStack[nos] = strlen(p->zStack[nos]) + 1;
+        }
+        break;
+      }
+
+      /* Opcode: Max * * *
+      **
+      ** Pop the top two elements from the stack then push back the
+      ** largest of the two.
+      */
+      case OP_Max: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        if( nos<0 ) goto not_enough_stack;
+        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
+          if( p->iStack[nos]<p->iStack[tos] ){
+            p->iStack[nos] = p->iStack[tos];
+          }
+        }else{
+          Stringify(p, tos);
+          Stringify(p, nos);
+          if( sqliteCompare(p->zStack[nos], p->zStack[tos])<0 ){
+            sqliteFree(p->zStack[nos]);
+            p->zStack[nos] = p->zStack[tos];
+            p->iStack[nos] = p->iStack[tos];
+          }
+        }
+        p->tos--;
+        break;
+      }
+
+      /* Opcode: Min * * *
+      **
+      ** Pop the top two elements from the stack then push back the
+      ** smaller of the two.
+      */
+      case OP_Min: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        if( nos<0 ) goto not_enough_stack;
+        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
+          if( p->iStack[nos]>p->iStack[tos] ){
+            p->iStack[nos] = p->iStack[tos];
+          }
+        }else{
+          Stringify(p, tos);
+          Stringify(p, nos);
+          if( sqliteCompare(p->zStack[nos], p->zStack[tos])>0 ){
+            sqliteFree(p->zStack[nos]);
+            p->zStack[nos] = p->zStack[tos];
+            p->iStack[nos] = p->iStack[tos];
+          }
+        }
+        p->tos--;
+        break;
+      }
+
+      /* Opcode: AddImm  P1 * *
+      ** 
+      ** Add the value P1 to whatever is on top of the stack.
+      */
+      case OP_AddImm: {
+        int tos = p->tos;
+        if( tos<0 ) goto not_enough_stack;
+        Integerify(p, tos);
+        p->iStack[tos] += pOp->p1;
+        break;
+      }
+
+      /* Opcode: Eq * P2 *
+      **
+      ** Pop the top two elements from the stack.  If they are equal, then
+      ** jump to instruction P2.  Otherwise, continue to the next instruction.
+      */
+      /* Opcode: Ne * P2 *
+      **
+      ** Pop the top two elements from the stack.  If they are not equal, then
+      ** jump to instruction P2.  Otherwise, continue to the next instruction.
+      */
+      /* Opcode: Lt * P2 *
+      **
+      ** Pop the top two elements from the stack.  If second element (the
+      ** next on stack) is less than the first (the top of stack), then
+      ** jump to instruction P2.  Otherwise, continue to the next instruction.
+      ** In other words, jump if NOS<TOS.
+      */
+      /* Opcode: Le * P2 *
+      **
+      ** Pop the top two elements from the stack.  If second element (the
+      ** next on stack) is less than or equal to the first (the top of stack),
+      ** then jump to instruction P2. In other words, jump if NOS<=TOS.
+      */
+      /* Opcode: Gt * P2 *
+      **
+      ** Pop the top two elements from the stack.  If second element (the
+      ** next on stack) is greater than the first (the top of stack),
+      ** then jump to instruction P2. In other words, jump if NOS>TOS.
+      */
+      /* Opcode: Ge * P2 *
+      **
+      ** Pop the top two elements from the stack.  If second element (the next
+      ** on stack) is greater than or equal to the first (the top of stack),
+      ** then jump to instruction P2. In other words, jump if NOS>=TOS.
+      */
+      case OP_Eq:
+      case OP_Ne:
+      case OP_Lt:
+      case OP_Le:
+      case OP_Gt:
+      case OP_Ge: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        int c;
+        if( nos<0 ) goto not_enough_stack;
+        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
+          int a, b;
+          a = p->iStack[tos];
+          b = p->iStack[nos];
+          switch( pOp->opcode ){
+            case OP_Eq:    c = b==a;     break;
+            case OP_Ne:    c = b!=a;     break;
+            case OP_Lt:    c = b<a;      break;
+            case OP_Le:    c = b<=a;     break;
+            case OP_Gt:    c = b>a;      break;
+            default:       c = b>=a;     break;
+          }
+        }else{
+          Stringify(p, tos);
+          Stringify(p, nos);
+          c = sqliteCompare(p->zStack[nos], p->zStack[tos]);
+          switch( pOp->opcode ){
+            case OP_Eq:    c = c==0;     break;
+            case OP_Ne:    c = c!=0;     break;
+            case OP_Lt:    c = c<0;      break;
+            case OP_Le:    c = c<=0;     break;
+            case OP_Gt:    c = c>0;      break;
+            default:       c = c>=0;     break;
+          }
+        }
+        PopStack(p, 2);
+        if( c ) pc = pOp->p2-1;
+        break;
+      }
+
+      /* Opcode: And * * *
+      **
+      ** Pop two values off the stack.  Take the logical AND of the
+      ** two values and push the resulting boolean value back onto the
+      ** stack.  Integers are considered false if zero and true otherwise.
+      ** Strings are considered false if their length is zero and true
+      ** otherwise.
+      */
+      /* Opcode: Or * * *
+      **
+      ** Pop two values off the stack.  Take the logical OR of the
+      ** two values and push the resulting boolean value back onto the
+      ** stack.  Integers are considered false if zero and true otherwise.
+      ** Strings are considered false if their length is zero and true
+      ** otherwise.
+      */
+      case OP_And:
+      case OP_Or: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        int x, y, c;
+        if( nos<0 ) goto not_enough_stack;
+        x = p->zStack[nos] ? p->zStack[nos][0] : p->iStack[nos];
+        y = p->zStack[tos] ? p->zStack[tos][0] : p->iStack[tos];
+        if( pOp->opcode==OP_And ){
+          c = x && y;
+        }else{
+          c = x || y;
+        }
+        PopStack(p, 2);
+        p->tos++;
+        p->iStack[nos] = c;
+        break;
+      }
+
+      /* Opcode: Negative * * *
+      **
+      ** Treat the top of the stack as a numeric quantity.  Replace it
+      ** with its additive inverse.  If the top of stack is a string,
+      ** then it is converted into a number using atof().
+      */
+      case OP_Negative: {
+        int tos;
+        if( (tos = p->tos)<0 ) goto not_enough_stack;
+        if( p->zStack[tos] ){
+          double r = atof(p->zStack[tos]);
+          sprintf(zBuf, "%g", -r);
+          sqliteSetString(&p->zStack[tos], zBuf, 0);
+          p->iStack[tos] = strlen(zBuf) + 1;
+        }else{
+          p->iStack[tos] = -p->iStack[tos];
+        }
+        break;
+      }
+
+      /* Opcode: Not * * *
+      **
+      ** Treat the top of the stack as a boolean value.  Replace it
+      ** with its complement.  Integers are false if zero and true
+      ** otherwise.  Strings are false if zero-length and true otherwise.
+      */
+      case OP_Not: {
+        int c;
+        if( p->tos<0 ) goto not_enough_stack;
+        c = p->zStack[p->tos] ? p->zStack[p->tos][0] : p->iStack[p->tos];
+        PopStack(p, 1);
+        p->tos++;
+        p->iStack[p->tos] = !c;
+        break;
+      }
+
+      /* Opcode: Noop * * *
+      **
+      ** Do nothing.  This instruction is often useful as a jump
+      ** destination.
+      */
+      case OP_Noop: {
+        break;
+      }
+
+      /* Opcode: If * P2 *
+      **
+      ** Pop a single boolean from the stack.  If the boolean popped is
+      ** true, then jump to p2.  Otherwise continue to the next instruction.
+      ** An integer is false if zero and true otherwise.  A string is
+      ** false if it has zero length and true otherwise.
+      */
+      case OP_If: {
+        int c;
+        if( p->tos<0 ) goto not_enough_stack;
+        c = p->zStack[p->tos] ? p->zStack[p->tos][0] : p->iStack[p->tos];
+        PopStack(p, 1);
+        if( c ) pc = pOp->p2-1;
+        break;
+      }
+
+      /* Opcode: IsNull * P2 *
+      **
+      ** Pop a single value from the stack.  If the value popped is the
+      ** empty string, then jump to p2.  Otherwise continue to the next 
+      ** instruction.
+      */
+      case OP_IsNull: {
+        int c;
+        if( p->tos<0 ) goto not_enough_stack;
+        c = p->zStack[p->tos]!=0 && p->zStack[p->tos][0]==0;
+        PopStack(p, 1);
+        if( c ) pc = pOp->p2-1;
+        break;
+      }
+
+      /* Opcode: NotNull * P2 *
+      **
+      ** Pop a single value from the stack.  If the value popped is not an
+      ** empty string, then jump to p2.  Otherwise continue to the next 
+      ** instruction.
+      */
+      case OP_NotNull: {
+        int c;
+        if( p->tos<0 ) goto not_enough_stack;
+        c = p->zStack[p->tos]==0 || p->zStack[p->tos][0]!=0;
+        PopStack(p, 1);
+        if( c ) pc = pOp->p2-1;
+        break;
+      }
+
+      /* Opcode: MakeRecord P1 * *
+      **
+      ** Convert the top P1 entries of the stack into a single entry
+      ** suitable for use as a data record in the database.  To do this
+      ** each entry is converted to a string and all the strings are
+      ** concatenated.  The null-terminators are preserved by the concatation
+      ** and serve as a boundry marker between fields.  The lowest entry
+      ** on the stack is the first in the concatenation and the top of
+      ** the stack is the last.  After all fields are concatenated, an
+      ** index header is added.  The index header consists of P1 integers
+      ** which hold the offset of the beginning of each field from the
+      ** beginning of the completed record including the header.
+      */
+      case OP_MakeRecord: {
+        char *zNewRecord;
+        int nByte;
+        int nField;
+        int i, j;
+        int addr;
+
+        nField = pOp->p1;
+        if( p->tos+1<nField ) goto not_enough_stack;
+        nByte = 0;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( Stringify(p, i) ) goto no_mem;
+          nByte += p->iStack[i];
+        }
+        nByte += sizeof(int)*nField;
+        zNewRecord = sqliteMalloc( nByte );
+        if( zNewRecord==0 ) goto no_mem;
+        j = 0;
+        addr = sizeof(int)*nField;
+        for(i=p->tos-nField+1; i<p->tos; i++){
+          memcpy(&zNewRecord[j], (char*)&addr, sizeof(int));
+          addr += p->iStack[i];
+          j += sizeof(int);
+        }
+        memcpy(&zNewRecord[j], (char*)&addr, sizeof(int));
+        j += sizeof(int);
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          memcpy(&zNewRecord[j], p->zStack[i], p->iStack[i]);
+          j += p->iStack[i];
+        }
+        PopStack(p, nField);
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->iStack[p->tos] = nByte;
+        p->zStack[p->tos] = zNewRecord;
+        break;
+      }
+
+      /* Opcode: MakeKey P1 * *
+      **
+      ** Convert the top P1 entries of the stack into a single entry suitable
+      ** for use as the key in an index or a sort.  The top P1 records are
+      ** concatenated with a tab character (ASCII 0x09) used as a record
+      ** separator.  The entire concatenation is null-terminated.  The
+      ** lowest entry in the stack is the first field and the top of the
+      ** stack becomes the last.
+      **
+      ** See also the SortMakeKey opcode.
+      */
+      case OP_MakeKey: {
+        char *zNewKey;
+        int nByte;
+        int nField;
+        int i, j;
+
+        nField = pOp->p1;
+        if( p->tos+1<nField ) goto not_enough_stack;
+        nByte = 0;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( Stringify(p, i) ) goto no_mem;
+          nByte += p->iStack[i]+1;
+        }
+        zNewKey = sqliteMalloc( nByte );
+        if( zNewKey==0 ) goto no_mem;
+        j = 0;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          memcpy(&zNewKey[j], p->zStack[i], p->iStack[i]-1);
+          j += p->iStack[i]-1;
+          if( i<p->tos ) zNewKey[j++] = '\t';
+        }
+        zNewKey[j] = 0;
+        PopStack(p, nField);
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->iStack[p->tos] = nByte;
+        p->zStack[p->tos] = zNewKey;
+        break;
+      }
+
+      /*  Open P1 P3 P2
+      **
+      ** Open a new database table named P3.  Give it an identifier P1.
+      ** Open readonly if P2==0 and for reading and writing if P2!=0.
+      ** The table is created if it does not already exist and P2!=0.
+      ** If there is already another table opened on P1, then the old
+      ** table is closed first.  All tables are automatically closed when
+      ** the VDBE finishes execution.  The P1 values need not be
+      ** contiguous but all P1 values should be small integers.  It is
+      ** an error for P1 to be negative.
+      */
+      case OP_Open: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i>=p->nTable ){
+          int j;
+          p->aTab = sqliteRealloc( p->aTab, (i+1)*sizeof(VdbeTable) );
+          if( p->aTab==0 ){ p->nTable = 0; goto no_mem; }
+          for(j=p->nTable; j<=i; j++) p->aTab[j].pTable = 0;
+          p->nTable = i+1;
+        }else if( p->aTab[i].pTable ){
+          sqliteDbbeCloseTable(p->aTab[i].pTable);
+        }
+        p->aTab[i].pTable = sqliteDbbeOpenTable(p->pBe, pOp->p3, pOp->p2);
+        p->aTab[i].index = 0;
+        break;
+      }
+
+      /* Opcode: Close P1 * *
+      **
+      ** Close a database table previously opened as P1.  If P1 is not
+      ** currently open, this instruction is a no-op.
+      */
+      case OP_Close: {
+        int i = pOp->p1;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable ){
+          sqliteDbbeCloseTable(p->aTab[i].pTable);
+          p->aTab[i].pTable = 0;
+        }
+        break;
+      }
+
+      /* Opcode: Fetch P1 * *
+      **
+      ** Pop the top of the stack and use its value as a key to fetch
+      ** a record from database table or index P1.  The data is held
+      ** in the P1 cursor until needed.  The data is not pushed onto the
+      ** stack or anything like that.
+      */
+      case OP_Fetch: {
+        int i = pOp->p1;
+        int tos = p->tos;
+        if( tos<0 ) goto not_enough_stack;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable ){
+          if( p->zStack[tos]==0 ){
+            sqliteDbbeFetch(p->aTab[i].pTable, sizeof(int), 
+                           (char*)&p->iStack[tos]);
+          }else{
+            sqliteDbbeFetch(p->aTab[i].pTable, p->iStack[tos], p->zStack[tos]);
+          }
+        }
+        PopStack(p, 1);
+        break;
+      }
+
+      /* Opcode: New P1 * *
+      **
+      ** Get a new integer key not previous used by table P1 and
+      ** push it onto the stack.
+      */
+      case OP_New: {
+        int i = pOp->p1;
+        int v;
+        if( i<0 || i>=p->nTable || p->aTab[i].pTable==0 ){
+          v = 0;
+        }else{
+          v = sqliteDbbeNew(p->aTab[i].pTable);
+        }
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->iStack[p->tos] = v;
+        break;
+      }
+
+      /* Opcode: Put P1 * *
+      **
+      ** Write an entry into the database table P1.  A new entry is
+      ** created if it doesn't already exist, or the data for an existing
+      ** entry is overwritten.  The data is the value on the top of the
+      ** stack.  The key is the next value down on the stack.  The stack
+      ** is popped twice by this instruction.
+      */
+      case OP_Put: {
+        int tos = p->tos;
+        int nos = p->tos-1;
+        int i = pOp->p1;
+        if( nos<0 ) goto not_enough_stack;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
+          char *zKey;
+          int nKey;
+          Stringify(p, tos);
+          if( p->zStack[nos]!=0 ){
+            nKey = p->iStack[nos];
+            zKey = p->zStack[nos];
+          }else{
+            nKey = sizeof(int);
+            zKey = (char*)&p->iStack[nos];
+          }
+          sqliteDbbePut(p->aTab[i].pTable, nKey, zKey,
+                        p->iStack[tos], p->zStack[tos]);
+        }
+        PopStack(p, 2);
+        break;
+      }
+
+      /* Opcode: Delete P1 * *
+      **
+      ** The top of the stack is a key.  Remove this key and its data
+      ** from database table P1.  Then pop the stack to discard the key.
+      */
+      case OP_Delete: {
+        int tos = p->tos;
+        int i = pOp->p1;
+        if( tos<0 ) goto not_enough_stack;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
+          char *zKey;
+          int nKey;
+          if( p->zStack[tos]!=0 ){
+            nKey = p->iStack[tos];
+            zKey = p->zStack[tos];
+          }else{
+            nKey = sizeof(int);
+            zKey = (char*)&p->iStack[tos];
+          }
+          sqliteDbbeDelete(p->aTab[i].pTable, nKey, zKey);
+        }
+        PopStack(p, 1);
+        break;
+      }
+
+      /* Opcode: Field P1 P2 *
+      **
+      ** Push onto the stack the value of the P2-th field from the
+      ** most recent Fetch from table P1.
+      */
+      case OP_Field: {
+        int *pAddr;
+        int amt;
+        int i = pOp->p1;
+        int p2 = pOp->p2;
+        int tos = ++p->tos;
+        DbbeTable *pTab;
+        char *z;
+
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
+          amt = sqliteDbbeDataLength(pTab);
+          if( amt<=sizeof(int)*(p2+1) ){
+            sqliteSetString(&p->zStack[tos], "", 0);
+            break;
+          }
+          pAddr = (int*)sqliteDbbeReadData(pTab, sizeof(int)*p2);
+          z = sqliteDbbeReadData(pTab, *pAddr);
+          sqliteSetString(&p->zStack[tos], z, 0);
+          p->iStack[tos] = strlen(z)+1;
+        }
+        break;
+      }
+
+      /* Opcode: Key P1 * *
+      **
+      ** Push onto the stack an integer which is the first 4 bytes of the
+      ** the key to the current entry in a sequential scan of the table P1.
+      ** A sequential scan is started using the Next opcode.
+      */
+      case OP_Key: {
+        int i = pOp->p1;
+        int tos = ++p->tos;
+        DbbeTable *pTab;
+
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
+          char *z = sqliteDbbeReadKey(pTab, 0);
+          memcpy(&p->iStack[tos], z, sizeof(int));
+          p->zStack[tos] = 0;
+        }
+        break;
+      }
+
+      /* Opcode: Rewind P1 * *
+      **
+      ** The next use of the Key or Field or Next instruction for P1 
+      ** will refer to the first entry in the table.
+      */
+      case OP_Rewind: {
+        int i = pOp->p1;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
+          sqliteDbbeRewind(p->aTab[i].pTable);
+        }
+        break;
+      }
+
+      /* Opcode: Next P1 P2 *
+      **
+      ** Advance P1 to the next entry in the table.  Or, if there are no
+      ** more entries, rewind P1 and jump to location P2.
+      */
+      case OP_Next: {
+        int i = pOp->p1;
+        if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
+          if( sqliteDbbeNextKey(p->aTab[i].pTable)==0 ){
+            pc = pOp->p2;
+            if( pc<0 || pc>p->nOp ){
+              sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+              rc = 1;
+            }
+            pc--;
+          }
+        }
+        break;
+      }
+
+      /* Opcode: ResetIdx P1 * *
+      **
+      ** Begin treating the current row of table P1 as an index.  The next
+      ** NextIdx instruction will refer to the first index in the table.
+      */
+      case OP_ResetIdx: {
+        int i = pOp->p1;
+        if( i>=0 && i<p->nTable ){
+          p->aTab[i].index = 0;
+        }
+        break;
+      }
+
+      /* Opcode: NextIdx P1 P2 *
+      **
+      ** Push the next index from the current entry of table P1 onto the
+      ** stack and advance the pointer.  If there are no more indices, then
+      ** reset the table entry and jump to P2
+      */
+      case OP_NextIdx: {
+        int i = pOp->p1;
+        int tos = ++p->tos;
+        DbbeTable *pTab;
+
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        p->zStack[tos] = 0;
+        if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
+          int *aIdx;
+          int nIdx;
+          int j;
+          nIdx = sqliteDbbeDataLength(pTab)/sizeof(int);
+          aIdx = (int*)sqliteDbbeReadData(pTab, 0);
+          for(j=p->aTab[i].index; j<nIdx; j++){
+            if( aIdx[j]!=0 ){
+              p->iStack[tos] = aIdx[j];
+              break;
+            }
+          }
+          if( j>=nIdx ){
+            j = -1;
+            pc = pOp->p2;
+            if( pc<0 || pc>p->nOp ){
+              sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+              rc = 1;
+            }
+            pc--;
+          }
+          p->aTab[i].index = j+1;
+        }
+        break;
+      }
+
+      /* Opcode: PutIdx P1 * *
+      **
+      ** The top of the stack hold an index key (proably made using the
+      ** MakeKey instruction) and next on stack holds an index value for
+      ** a table.  Locate the record in the index P1 that has the key 
+      ** and insert the index value into its
+      ** data.  Write the results back to the index.
+      ** If the key doesn't exist it is created.
+      */
+      case OP_PutIdx: {
+        int i = pOp->p1;
+        int tos = p->tos;
+        int nos = tos - 1;
+        DbbeTable *pTab;
+        if( nos<0 ) goto not_enough_stack;
+        if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
+          int r;
+          int newVal = Integerify(p, nos);
+          Stringify(p, tos);
+          r = sqliteDbbeFetch(pTab, p->iStack[tos], p->zStack[tos]);
+          if( r==0 ){
+            /* Create a new record for this index */
+            sqliteDbbePut(pTab, p->iStack[tos], p->zStack[tos],
+                          sizeof(int), (char*)&newVal);
+          }else{
+            /* Extend the existing record */
+            int nIdx;
+            int *aIdx;
+            nIdx = sqliteDbbeDataLength(pTab)/sizeof(int);
+            aIdx = sqliteMalloc( sizeof(int)*(nIdx+1) );
+            if( aIdx==0 ) goto no_mem;
+            sqliteDbbeCopyData(pTab, 0, nIdx*sizeof(int), (char*)aIdx);
+            aIdx[nIdx] = newVal;
+            sqliteDbbePut(pTab, p->iStack[tos], p->zStack[tos],
+                          sizeof(int)*(nIdx+1), (char*)aIdx);
+            sqliteFree(aIdx);
+          }
+        }
+        PopStack(p, 2);
+        break;
+      }
+
+      /* Opcode: DeleteIdx P1 * *
+      **
+      ** The top of the stack is a key and next on stack is an index value.
+      ** Locate the record
+      ** in index P1 that has the key and remove the index value from its
+      ** data.  Write the results back to the table.  If after removing
+      ** the index value no more indices remain in the record, then the
+      ** record is removed from the table.
+      */
+      case OP_DeleteIdx: {
+        int i = pOp->p1;
+        int tos = p->tos;
+        int nos = tos - 1;
+        DbbeTable *pTab;
+        if( nos<0 ) goto not_enough_stack;
+        if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
+          int *aIdx;
+          int nIdx;
+          int j;
+          int r;
+          int oldVal = Integerify(p, nos);
+          Stringify(p, tos);
+          r = sqliteDbbeFetch(pTab, p->iStack[tos], p->zStack[tos]);
+          if( r==0 ) break;
+          nIdx = sqliteDbbeDataLength(pTab)/sizeof(int);
+          aIdx = (int*)sqliteDbbeReadData(pTab, 0);
+          for(j=0; j<nIdx && aIdx[j]!=oldVal; j++){}
+          if( j>=nIdx ) break;
+          aIdx[j] = aIdx[nIdx-1];
+          if( nIdx==1 ){
+            sqliteDbbeDelete(pTab, p->iStack[tos], p->zStack[tos]);
+          }else{
+            sqliteDbbePut(pTab, p->iStack[tos], p->zStack[tos], 
+                          sizeof(int)*(nIdx-1), (char*)aIdx);
+          }
+        }
+        PopStack(p, 2);
+        break;
+      }
+
+      /* Opcode: Destroy * * P3
+      **
+      ** Drop the table whose name is P3.  The file that holds this table
+      ** is removed from the disk drive.
+      */
+      case OP_Destroy: {
+        sqliteDbbeDropTable(p->pBe, pOp->p3);
+        break;
+      }
+
+      /* Opcode: ListOpen P1 * *
+      **
+      ** Open a file used for temporary storage of index numbers.  P1
+      ** will server as a handle to this temporary file for future
+      ** interactions.  If another temporary file with the P1 handle is
+      ** already opened, the prior file is closed and a new one opened
+      ** in its place.
+      */
+      case OP_ListOpen: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i>=p->nList ){
+          int j;
+          p->apList = sqliteRealloc( p->apList, (i+1)*sizeof(FILE*) );
+          if( p->apList==0 ){ p->nList = 0; goto no_mem; }
+          for(j=p->nList; j<=i; j++) p->apList[j] = 0;
+          p->nList = i+1;
+        }else if( p->apList[i] ){
+          sqliteDbbeCloseTempFile(p->pBe, p->apList[i]);
+        }
+        p->apList[i] = sqliteDbbeOpenTempFile(p->pBe);
+        break;
+      }
+
+      /* Opcode: ListWrite P1 * *
+      **
+      ** Write the integer on the top of the stack
+      ** into the temporary storage file P1.
+      */
+      case OP_ListWrite: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( p->tos<0 ) goto not_enough_stack;
+        if( i<p->nList && p->apList[i]!=0 ){
+          int val = Integerify(p, p->tos);
+          PopStack(p, 1);
+          fwrite(&val, sizeof(int), 1, p->apList[i]);
+        }
+        break;
+      }
+
+      /* Opcode: ListRewind P1 * *
+      **
+      ** Rewind the temporary buffer P1 back to the beginning.
+      */
+      case OP_ListRewind: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i<p->nList && p->apList[i]!=0 ){
+          rewind(p->apList[i]);
+        }
+        break;
+      }
+
+      /* Opcode: ListRead P1 P2 *
+      **
+      ** Attempt to read an integer from temporary storage buffer P1
+      ** and push it onto the stack.  If the storage buffer is empty
+      ** push nothing but instead jump to P2.
+      */
+      case OP_ListRead: {
+        int i = pOp->p1;
+        int val, amt;
+        if( i<0 || i>=p->nList || p->apList[i]==0 ) goto bad_instruction;
+        amt = fread(&val, sizeof(int), 1, p->apList[i]);
+        if( amt==1 ){
+          p->tos++;
+          if( NeedStack(p, p->tos) ) goto no_mem;
+          p->iStack[p->tos] = val;
+          p->zStack[p->tos] = 0;
+        }else{
+          pc = pOp->p2;
+          if( pc<0 || pc>p->nOp ){
+            sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+            rc = 1;
+          }
+          pc--;
+        }
+        break;
+      }
+
+      /* Opcode: ListClose P1 * *
+      **
+      ** Close the temporary storage buffer and discard its contents.
+      */
+      case OP_ListClose: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i<p->nList && p->apList[i]!=0 ){
+          sqliteDbbeCloseTempFile(p->pBe, p->apList[i]);
+          p->apList[i] = 0;
+        }
+        break;
+      }
+
+      /* Opcode: SortOpen P1 * *
+      **
+      ** Create a new sorter with index P1
+      */
+      case OP_SortOpen: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i>=p->nSort ){
+          int j;
+          p->apSort = sqliteRealloc( p->apSort, (i+1)*sizeof(Sorter*) );
+          if( p->apSort==0 ){ p->nSort = 0; goto no_mem; }
+          for(j=p->nSort; j<=i; j++) p->apSort[j] = 0;
+          p->nSort = i+1;
+        }
+        break;
+      }
+
+      /* Opcode: SortPut P1 * *
+      **
+      ** The TOS is the key and the NOS is the data.  Pop both from the stack
+      ** and put them on the sorter.
+      */
+      case OP_SortPut: {
+        int i = pOp->p1;
+        Sorter *pSorter;
+        if( i<0 || i>=p->nSort ) goto bad_instruction;
+        if( p->tos<1 ) goto not_enough_stack;
+        Stringify(p, p->tos);
+        Stringify(p, p->tos-1);
+        pSorter = sqliteMalloc( sizeof(Sorter) );
+        if( pSorter==0 ) goto no_mem;
+        pSorter->pNext = p->apSort[i];
+        p->apSort[i] = pSorter;
+        pSorter->nKey = p->iStack[p->tos];
+        pSorter->zKey = p->zStack[p->tos];
+        pSorter->nData = p->iStack[p->tos-1];
+        pSorter->pData = p->zStack[p->tos-1];
+        p->zStack[p->tos] = p->zStack[p->tos-1] = 0;
+        PopStack(p, 2);
+        break;
+      }
+
+      /* Opcode: SortMakeRec P1 * *
+      **
+      ** The top P1 elements are the arguments to a callback.  Form these
+      ** elements into a single data entry that can be stored on a sorter
+      ** using SortPut and later fed to a callback using SortCallback.
+      */
+      case OP_SortMakeRec: {
+        char *z;
+        char **azArg;
+        int nByte;
+        int nField;
+        int i, j;
+
+        nField = pOp->p1;
+        if( p->tos+1<nField ) goto not_enough_stack;
+        nByte = 0;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( Stringify(p, i) ) goto no_mem;
+          nByte += p->iStack[i];
+        }
+        nByte += sizeof(char*)*(nField+1);
+        azArg = sqliteMalloc( nByte );
+        if( azArg==0 ) goto no_mem;
+        z = (char*)&azArg[nField+1];
+        for(j=0, i=p->tos-nField+1; i<=p->tos; i++, j++){
+          azArg[j] = z;
+          strcpy(z, p->zStack[i]);
+          z += p->iStack[i];
+        }
+        PopStack(p, nField);
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->iStack[p->tos] = nByte;
+        p->zStack[p->tos] = (char*)azArg;
+        break;
+      }
+
+      /* Opcode: SortMakeKey P1 * P3
+      **
+      ** Convert the top few entries of the stack into a sort key.  The
+      ** number of stack entries consumed is the number of characters in 
+      ** the string P3.  One character from P3 is prepended to each entry.
+      ** The first character of P3 is prepended to the element lowest in
+      ** the stack and the last character of P3 is appended to the top of
+      ** the stack.  All stack entries are separated by a \000 character
+      ** in the result.  The whole key is terminated by two \000 characters
+      ** in a row.
+      **
+      ** See also the MakeKey opcode.
+      */
+      case OP_SortMakeKey: {
+        char *zNewKey;
+        int nByte;
+        int nField;
+        int i, j, k;
+
+        nField = strlen(pOp->p3);
+        if( p->tos+1<nField ) goto not_enough_stack;
+        nByte = 1;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( Stringify(p, i) ) goto no_mem;
+          nByte += p->iStack[i]+2;
+        }
+        zNewKey = sqliteMalloc( nByte );
+        if( zNewKey==0 ) goto no_mem;
+        j = 0;
+        k = nField-1;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          zNewKey[j++] = pOp->p3[k--];
+          memcpy(&zNewKey[j], p->zStack[i], p->iStack[i]-1);
+          j += p->iStack[i]-1;
+          zNewKey[j++] = 0;
+        }
+        zNewKey[j] = 0;
+        PopStack(p, nField);
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->iStack[p->tos] = nByte;
+        p->zStack[p->tos] = zNewKey;
+        break;
+      }
+
+      /* Opcode: Sort P1 * *
+      **
+      ** Sort all elements on the given sorter.  The algorithm is a
+      ** mergesort.
+      */
+      case OP_Sort: {
+        int j;
+        j = pOp->p1;
+        if( j<0 ) goto bad_instruction;
+        if( j<p->nSort ){
+          int i;
+          Sorter *pElem;
+          Sorter *apSorter[NSORT];
+          for(i=0; i<NSORT; i++){
+            apSorter[i] = 0;
+          }
+          while( p->apSort[j] ){
+            pElem = p->apSort[j];
+            p->apSort[j] = pElem->pNext;
+            pElem->pNext = 0;
+            for(i=0; i<NSORT-1; i++){
+              if( apSorter[i]==0 ){
+                apSorter[i] = pElem;
+                break;
+              }else{
+                pElem = Merge(apSorter[i], pElem);
+                apSorter[i] = 0;
+              }
+            }
+            if( i>=NSORT-1 ){
+              apSorter[NSORT-1] = Merge(apSorter[NSORT-1],pElem);
+            }
+          }
+          pElem = 0;
+          for(i=0; i<NSORT; i++){
+            pElem = Merge(apSorter[i], pElem);
+          }
+          p->apSort[j] = pElem;
+        }
+        break;
+      }
+
+      /* Opcode: SortNext P1 P2 *
+      **
+      ** Push the data for the topmost element in the given sorter onto the
+      ** stack, then remove the element from the sorter.
+      */
+      case OP_SortNext: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i<p->nSort && p->apSort[i]!=0 ){
+          Sorter *pSorter = p->apSort[i];
+          p->apSort[i] = pSorter->pNext;
+          p->tos++;
+          NeedStack(p, p->tos);
+          p->zStack[p->tos] = pSorter->pData;
+          p->iStack[p->tos] = pSorter->nData;
+          sqliteFree(pSorter->zKey);
+          sqliteFree(pSorter);
+        }else{
+          pc = pOp->p2;
+          if( pc<0 || pc>p->nOp ){
+            sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+            rc = 1;
+          }
+          pc--;
+        }
+        break;
+      }
+
+      /* Opcode: SortKey P1 * *
+      **
+      ** Push the key for the topmost element of the sorter onto the stack.
+      ** But don't change the sorter an any other way.
+      */
+      case OP_SortKey: {
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i<p->nSort && p->apSort[i]!=0 ){
+          Sorter *pSorter = p->apSort[i];
+          p->tos++;
+          NeedStack(p, p->tos);
+          sqliteSetString(&p->zStack[p->tos], pSorter->zKey, 0);
+          p->iStack[p->tos] = pSorter->nKey;
+        }
+        break;
+      }
+
+      /* Opcode: SortCallback P1 P2 *
+      **
+      ** The top of the stack contains a callback record built using
+      ** the SortMakeRec operation with the same P1 value as this
+      ** instruction.  Pop this record from the stack and invoke the
+      ** callback on it.
+      */
+      case OP_SortCallback: {
+        int i = p->tos;
+        if( i<0 ) goto not_enough_stack;
+        rc = xCallback(pArg, pOp->p1, (char**)p->zStack[i], p->azColName);
+        PopStack(p, 1);
+        break;
+      }
+
+      /* Opcode: SortClose P1 * *
+      **
+      ** Close the given sorter and remove all its elements.
+      */
+      case OP_SortClose: {
+        Sorter *pSorter;
+        int i = pOp->p1;
+        if( i<0 ) goto bad_instruction;
+        if( i<p->nSort ){
+           while( (pSorter = p->apSort[i])!=0 ){
+             p->apSort[i] = pSorter->pNext;
+             sqliteFree(pSorter->zKey);
+             sqliteFree(pSorter->pData);
+             sqliteFree(pSorter);
+           }
+        }
+        break;
+      }
+
+      /* An other opcode is illegal...
+      */
+      default: {
+        sprintf(zBuf,"%d",pOp->opcode);
+        sqliteSetString(pzErrMsg, "unknown opcode ", zBuf, 0);
+        rc = 1;
+        break;
+      }
+    }
+    if( p->trace && p->tos>=0 ){
+      int i;
+      fprintf(p->trace, "Stack:");
+      for(i=p->tos; i>=0 && i>p->tos-5; i--){
+        if( p->zStack[i] ){
+          fprintf(p->trace, " [%.11s]", p->zStack[i]);
+        }else{
+          fprintf(p->trace, " [%d]", p->iStack[i]);
+        }
+      }
+      fprintf(p->trace,"\n");
+    }
+  }
+
+cleanup:
+  Cleanup(p);
+  return rc;
+
+  /* Jump to here if a malloc() fails.  It's hard to get a malloc()
+  ** to fail on a modern VM computer, so this code is untested.
+  */
+no_mem:
+  Cleanup(p);
+  sqliteSetString(pzErrMsg, "out or memory", 0);
+  return 1;
+
+  /* Jump to here if a operator is encountered that requires more stack
+  ** operands than are currently available on the stack.
+  */
+not_enough_stack:
+  sprintf(zBuf,"%d",pc);
+  sqliteSetString(pzErrMsg, "too few operands on stack at ", zBuf, 0);
+  rc = 1;
+  goto cleanup;
+
+  /* Jump here if an illegal or illformed instruction is executed.
+  */
+bad_instruction:
+  sprintf(zBuf,"%d",pc);
+  sqliteSetString(pzErrMsg, "illegal operation at ", zBuf, 0);
+  rc = 1;
+  goto cleanup;
+
+}
diff --git a/src/vdbe.h b/src/vdbe.h
new file mode 100644
index 0000000..5bafa99
--- /dev/null
+++ b/src/vdbe.h
@@ -0,0 +1,166 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** Header file for the Virtual DataBase Engine (VDBE)
+**
+** This header defines the interface to the virtual database engine
+** 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.1 2000/05/29 14:26:02 drh Exp $
+*/
+#ifndef _SQLITE_VDBE_H_
+#define _SQLITE_VDBE_H_
+#include <stdio.h>
+
+/*
+** A single VDBE is an opaque structure named "Vdbe".  Only routines
+** in the source file sqliteVdbe.c are allowed to see the insides
+** of this structure.
+*/
+typedef struct Vdbe Vdbe;
+
+/*
+** A single instruction of the virtual machine has an opcode
+** and as many as three operands.  The instruction is recorded
+** as an instance of the following structure:
+*/
+struct VdbeOp {
+  int opcode;         /* What operation to perform */
+  int p1;             /* First operand */
+  int p2;             /* Second parameter (often the jump destination) */
+  char *p3;           /* Third parameter */
+};
+typedef struct VdbeOp VdbeOp;
+
+/*
+** The following macro converts a relative address in the p2 field
+** of a VdbeOp structure into a negative number so that 
+** sqliteVdbeAddOpList() knows that the address is relative.  Calling
+** the macro again restores the address.
+*/
+#define ADDR(X)  (-1-(X))
+
+/*
+** These are the available opcodes.
+**
+** If any of the values changes or if opcodes are added or removed,
+** be sure to also update the zOpName[] array in sqliteVdbe.c to
+** mirror the change.
+**
+** The source tree contains an AWK script named renumberOps.awk that
+** can be used to renumber these opcodes when new opcodes are inserted.
+*/
+#define OP_Open                1
+#define OP_Close               2
+#define OP_Destroy             3
+#define OP_Fetch               4
+#define OP_New                 5
+#define OP_Put                 6
+#define OP_Delete              7
+#define OP_Field               8
+#define OP_Key                 9
+#define OP_Rewind             10
+#define OP_Next               11
+#define OP_ResetIdx           12
+#define OP_NextIdx            13
+#define OP_PutIdx             14
+#define OP_DeleteIdx          15
+
+#define OP_ListOpen           16
+#define OP_ListWrite          17
+#define OP_ListRewind         18
+#define OP_ListRead           19
+#define OP_ListClose          20
+
+#define OP_SortOpen           21
+#define OP_SortPut            22
+#define OP_SortMakeRec        23
+#define OP_SortMakeKey        24
+#define OP_Sort               25
+#define OP_SortNext           26
+#define OP_SortKey            27
+#define OP_SortCallback       28
+#define OP_SortClose          29
+
+#define OP_MakeRecord         30
+#define OP_MakeKey            31
+
+#define OP_Goto               32
+#define OP_If                 33
+#define OP_Halt               34
+
+#define OP_ColumnCount        35
+#define OP_ColumnName         36
+#define OP_Callback           37
+
+#define OP_Integer            38
+#define OP_String             39
+#define OP_Pop                40
+#define OP_Dup                41
+#define OP_Pull               42
+
+#define OP_Add                43
+#define OP_AddImm             44
+#define OP_Subtract           45
+#define OP_Multiply           46
+#define OP_Divide             47
+#define OP_Min                48
+#define OP_Max                49
+#define OP_Eq                 50
+#define OP_Ne                 51
+#define OP_Lt                 52
+#define OP_Le                 53
+#define OP_Gt                 54
+#define OP_Ge                 55
+#define OP_IsNull             56
+#define OP_NotNull            57
+#define OP_Negative           58
+#define OP_And                59
+#define OP_Or                 60
+#define OP_Not                61
+#define OP_Concat             62
+#define OP_Noop               63
+
+#define OP_MAX                63
+
+/*
+** Prototypes for the VDBE interface.  See comments on the implementation
+** for a description of what each of these routines does.
+*/
+Vdbe *sqliteVdbeCreate(Dbbe*);
+int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);
+int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOp const *aOp);
+void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
+void sqliteVdbeDequoteP3(Vdbe*, int addr);
+int sqliteVdbeMakeLabel(Vdbe*);
+void sqliteVdbeDelete(Vdbe*);
+int sqliteVdbeOpcode(const char *zName);
+int sqliteVdbeExec(Vdbe*,sqlite_callback,void*,char**);
+int sqliteVdbeList(Vdbe*,sqlite_callback,void*,char**);
+void sqliteVdbeResolveLabel(Vdbe*, int);
+int sqliteVdbeCurrentAddr(Vdbe*);
+void sqliteVdbeTrace(Vdbe*,FILE*);
+
+
+#endif
diff --git a/src/where.c b/src/where.c
new file mode 100644
index 0000000..ea15a5e
--- /dev/null
+++ b/src/where.c
@@ -0,0 +1,566 @@
+/*
+** Copyright (c) 1999, 2000 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*************************************************************************
+** This module contains C code that generates VDBE code used to process
+** the WHERE clause of SQL statements.  Also found here are subroutines
+** to generate VDBE code to evaluate expressions.
+**
+** $Id: where.c,v 1.1 2000/05/29 14:26:02 drh Exp $
+*/
+#include "sqliteInt.h"
+
+/*
+** The query generator uses an array of instances of this structure to
+** help it analyze the subexpressions of the WHERE clause.  Each WHERE
+** clause subexpression is separated from the others by an AND operator.
+*/
+typedef struct ExprInfo ExprInfo;
+struct ExprInfo {
+  Expr *p;                /* Pointer to the subexpression */
+  int indexable;          /* True if this subexprssion is usable by an index */
+  int idxLeft;            /* p->pLeft is a field in this table number. -1 if
+                          ** p->pLeft is not the field of any table */
+  int idxRight;           /* p->pRight is a field in this table number. -1 if
+                          ** p->pRight is not the field of any table */
+  unsigned prereqLeft;    /* Tables referenced by p->pLeft */
+  unsigned prereqRight;   /* Tables referenced by p->pRight */
+};
+
+/*
+** Determine the number of elements in an array.
+*/
+#define ARRAYSIZE(X)  (sizeof(X)/sizeof(X[0]))
+
+/*
+** This routine is used to divide the WHERE expression into subexpressions
+** separated by the AND operator.
+**
+** aSlot[] is an array of subexpressions structures.
+** There are nSlot spaces left in this array.  This routine attempts to
+** split pExpr into subexpressions and fills aSlot[] with those subexpressions.
+** The return value is the number of slots filled.
+*/
+static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){
+  int cnt = 0;
+  if( pExpr==0 || nSlot<1 ) return 0;
+  if( nSlot==1 || pExpr->op!=TK_AND ){
+    aSlot[0].p = pExpr;
+    return 1;
+  }
+  if( pExpr->pLeft->op!=TK_AND ){
+    aSlot[0].p = pExpr->pLeft;
+    cnt = 1 + exprSplit(nSlot-1, &aSlot[1], pExpr->pRight);
+  }else{
+    cnt = exprSplit(nSlot, aSlot, pExpr->pRight);
+    cnt += exprSplit(nSlot-cnt, &aSlot[cnt], pExpr->pLeft);
+  }
+  return cnt;
+}
+
+/*
+** This routine walks (recursively) an expression tree and generates
+** a bitmask indicating which tables are used in that expression
+** tree.  Bit 0 of the mask is set if table 0 is used.  But 1 is set
+** if table 1 is used.  And so forth.
+**
+** In order for this routine to work, the calling function must have
+** previously invoked sqliteExprResolveIds() on the expression.  See
+** the header comment on that routine for additional information.
+*/
+static int exprTableUsage(Expr *p){
+  unsigned int mask = 0;
+  if( p==0 ) return 0;
+  if( p->op==TK_FIELD ){
+    return 1<<p->iTable;
+  }
+  if( p->pRight ){
+    mask = exprTableUsage(p->pRight);
+  }
+  if( p->pLeft ){
+    mask |= exprTableUsage(p->pLeft);
+  }
+  return mask;
+}
+
+/*
+** The input to this routine is an ExprInfo structure with only the
+** "p" field filled in.  The job of this routine is to analyze the
+** subexpression and populate all the other fields of the ExprInfo
+** structure.
+*/
+static void exprAnalyze(ExprInfo *pInfo){
+  Expr *pExpr = pInfo->p;
+  pInfo->prereqLeft = exprTableUsage(pExpr->pLeft);
+  pInfo->prereqRight = exprTableUsage(pExpr->pRight);
+  pInfo->indexable = 0;
+  pInfo->idxLeft = -1;
+  pInfo->idxRight = -1;
+  if( pExpr->op==TK_EQ && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
+    if( pExpr->pRight->op==TK_FIELD ){
+      pInfo->idxRight = pExpr->pRight->iTable;
+      pInfo->indexable = 1;
+    }
+    if( pExpr->pLeft->op==TK_FIELD ){
+      pInfo->idxLeft = pExpr->pLeft->iTable;
+      pInfo->indexable = 1;
+    }
+  }
+}
+
+/*
+** Generating the beginning of the loop used for WHERE clause processing.
+** The return value is a pointer to an (opaque) structure that contains
+** information needed to terminate the loop.  Later, the calling routine
+** should invoke sqliteWhereEnd() with the return value of this function
+** in order to complete the WHERE clause processing.
+**
+** If an error occurs, this routine returns NULL.
+*/
+WhereInfo *sqliteWhereBegin(
+  Parse *pParse,       /* The parser context */
+  IdList *pTabList,    /* A list of all tables */
+  Expr *pWhere,        /* The WHERE clause */
+  int pushKey          /* If TRUE, leave the table key on the stack */
+){
+  int i;                     /* Loop counter */
+  WhereInfo *pWInfo;         /* Will become the return value of this function */
+  Vdbe *v = pParse->pVdbe;   /* The virtual database engine */
+  int brk, cont;             /* Addresses used during code generation */
+  int *aOrder;         /* Order in which pTabList entries are searched */
+  int nExpr;           /* Number of subexpressions in the WHERE clause */
+  int loopMask;        /* One bit set for each outer loop */
+  int haveKey;         /* True if KEY is on the stack */
+  Index *aIdx[32];     /* Index to use on each nested loop.  */
+  ExprInfo aExpr[50];  /* The WHERE clause is divided into these expressions */
+
+  /* Allocate space for aOrder[]. */
+  aOrder = sqliteMalloc( sizeof(int) * pTabList->nId );
+
+  /* Allocate and initialize the WhereInfo structure that will become the
+  ** return value.
+  */
+  pWInfo = sqliteMalloc( sizeof(WhereInfo) );
+  if( pWInfo==0 ){
+    sqliteFree(aOrder);
+    return 0;
+  }
+  pWInfo->pParse = pParse;
+  pWInfo->pTabList = pTabList;
+
+  /* Split the WHERE clause into as many as 32 separate subexpressions
+  ** where each subexpression is separated by an AND operator.  Any additional
+  ** subexpressions are attached in the aExpr[32] and will not enter
+  ** into the query optimizer computations.  32 is chosen as the cutoff
+  ** since that is the number of bits in an integer that we use for an
+  ** expression-used mask.  
+  */
+  memset(aExpr, 0, sizeof(aExpr));
+  nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere);
+
+  /* Analyze all of the subexpressions.
+  */
+  for(i=0; i<nExpr; i++){
+    exprAnalyze(&aExpr[i]);
+  }
+
+  /* Figure out a good nesting order for the tables.  aOrder[0] will
+  ** be the index in pTabList of the outermost table.  aOrder[1] will
+  ** be the first nested loop and so on.  aOrder[pTabList->nId-1] will
+  ** be the innermost loop.
+  **
+  ** Someday will put in a good algorithm here to reorder to the loops
+  ** for an effiecient query.  But for now, just use whatever order the
+  ** tables appear in in the pTabList.
+  */
+  for(i=0; i<pTabList->nId; i++){
+    aOrder[i] = i;
+  }
+
+  /* Figure out what index to use (if any) for each nested loop.
+  ** Make aIdx[i] point to the index to use for the i-th nested loop
+  ** where i==0 is the outer loop and i==pTabList->nId-1 is the inner
+  ** loop.
+  **
+  ** Actually, if there are more than 32 tables in the join, only the
+  ** first 32 tables are candidates for indices.
+  */
+  loopMask = 0;
+  for(i=0; i<pTabList->nId && i<ARRAYSIZE(aIdx); i++){
+    int idx = aOrder[i];
+    Table *pTab = pTabList->a[idx].pTab;
+    Index *pIdx;
+    Index *pBestIdx = 0;
+
+    /* Do a search for usable indices.  Leave pBestIdx pointing to
+    ** most specific usable index.
+    **
+    ** "Most specific" means that pBestIdx is the usable index that
+    ** has the largest value for nField.  A usable index is one for
+    ** which there are subexpressions to compute every field of the
+    ** index.
+    */
+    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+      int j;
+      int fieldMask = 0;
+
+      if( pIdx->nField>32 ) continue;
+      for(j=0; j<nExpr; j++){
+        if( aExpr[j].idxLeft==idx 
+             && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
+          int iField = aExpr[j].p->pLeft->iField;
+          int k;
+          for(k=0; k<pIdx->nField; k++){
+            if( pIdx->aiField[k]==iField ){
+              fieldMask |= 1<<k;
+              break;
+            }
+          }
+        }
+        if( aExpr[j].idxRight==idx 
+             && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
+          int iField = aExpr[j].p->pRight->iField;
+          int k;
+          for(k=0; k<pIdx->nField; k++){
+            if( pIdx->aiField[k]==iField ){
+              fieldMask |= 1<<k;
+              break;
+            }
+          }
+        }
+      }
+      if( fieldMask + 1 == (1<<pIdx->nField) ){
+        if( pBestIdx==0 || pBestIdx->nField<pIdx->nField ){
+          pBestIdx = pIdx;
+        }
+      }
+    }
+    aIdx[i] = pBestIdx;
+  }
+
+  /* Open all tables in the pTabList and all indices in aIdx[].
+  */
+  for(i=0; i<pTabList->nId; i++){
+    sqliteVdbeAddOp(v, OP_Open, i, 0, pTabList->a[i].pTab->zName, 0);
+    if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
+      sqliteVdbeAddOp(v, OP_Open, pTabList->nId+i, 0, aIdx[i]->zName, 0);
+    }
+  }
+
+  /* Generate the code to do the search
+  */
+  pWInfo->iBreak = brk = sqliteVdbeMakeLabel(v);
+  loopMask = 0;
+  for(i=0; i<pTabList->nId; i++){
+    int j, k;
+    int idx = aOrder[i];
+    Index *pIdx = i<ARRAYSIZE(aIdx) ? aIdx[i] : 0;
+
+    cont = sqliteVdbeMakeLabel(v);
+    if( pIdx==0 ){
+      /* Case 1:  There was no usable index.  We must do a complete
+      ** scan of the table.
+      */
+      sqliteVdbeAddOp(v, OP_Next, idx, brk, 0, cont);
+      haveKey = 0;
+    }else{
+      /* Case 2:  We do have a usable index in pIdx.
+      */
+      for(j=0; j<pIdx->nField; j++){
+        for(k=0; k<nExpr; k++){
+          if( aExpr[k].p==0 ) continue;
+          if( aExpr[k].idxLeft==idx 
+             && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
+             && aExpr[k].p->pLeft->iField==pIdx->aiField[j]
+          ){
+            sqliteExprCode(pParse, aExpr[k].p->pRight);
+            aExpr[k].p = 0;
+            break;
+          }
+          if( aExpr[k].idxRight==idx 
+             && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
+             && aExpr[k].p->pRight->iField==pIdx->aiField[j]
+          ){
+            sqliteExprCode(pParse, aExpr[k].p->pLeft);
+            aExpr[k].p = 0;
+            break;
+          }
+        }
+      }
+      sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_Fetch, pTabList->nId+i, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_NextIdx, pTabList->nId+i, brk, 0, cont);
+      if( i==pTabList->nId-1 && pushKey ){
+        haveKey = 1;
+      }else{
+        sqliteVdbeAddOp(v, OP_Fetch, idx, 0, 0, 0);
+        haveKey = 0;
+      }
+    }
+    loopMask |= 1<<idx;
+
+    /* Insert code to test every subexpression that can be completely
+    ** computed using the current set of tables.
+    */
+    for(j=0; j<nExpr; j++){
+      if( aExpr[j].p==0 ) continue;
+      if( (aExpr[j].prereqRight & loopMask)!=aExpr[j].prereqRight ) continue;
+      if( (aExpr[j].prereqLeft & loopMask)!=aExpr[j].prereqLeft ) continue;
+      if( haveKey ){
+        sqliteVdbeAddOp(v, OP_Fetch, idx, 0, 0, 0);
+        haveKey = 0;
+      }
+      sqliteExprIfFalse(pParse, aExpr[j].p, cont);
+      aExpr[j].p = 0;
+    }
+    brk = cont;
+  }
+  pWInfo->iContinue = cont;
+  if( pushKey && !haveKey ){
+    sqliteVdbeAddOp(v, OP_Key, 0, 0, 0, 0);
+  }
+  sqliteFree(aOrder);
+  return pWInfo;
+}
+
+/*
+** Generate the end of the WHERE loop.
+*/
+void sqliteWhereEnd(WhereInfo *pWInfo){
+  Vdbe *v = pWInfo->pParse->pVdbe;
+  sqliteVdbeAddOp(v, OP_Goto, 0, pWInfo->iContinue, 0, 0);
+  sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, pWInfo->iBreak);
+  sqliteFree(pWInfo);
+  return;
+}
+
+/*
+** Generate code into the current Vdbe to evaluate the given
+** expression and leave the result on the stack.
+*/
+void sqliteExprCode(Parse *pParse, Expr *pExpr){
+  Vdbe *v = pParse->pVdbe;
+  int op;
+  switch( pExpr->op ){
+    case TK_PLUS:     op = OP_Add;      break;
+    case TK_MINUS:    op = OP_Subtract; break;
+    case TK_STAR:     op = OP_Multiply; break;
+    case TK_SLASH:    op = OP_Divide;   break;
+    case TK_AND:      op = OP_And;      break;
+    case TK_OR:       op = OP_Or;       break;
+    case TK_LT:       op = OP_Lt;       break;
+    case TK_LE:       op = OP_Le;       break;
+    case TK_GT:       op = OP_Gt;       break;
+    case TK_GE:       op = OP_Ge;       break;
+    case TK_NE:       op = OP_Ne;       break;
+    case TK_EQ:       op = OP_Eq;       break;
+    case TK_ISNULL:   op = OP_IsNull;   break;
+    case TK_NOTNULL:  op = OP_NotNull;  break;
+    case TK_NOT:      op = OP_Not;      break;
+    case TK_UMINUS:   op = OP_Negative; break;
+    default: break;
+  }
+  switch( pExpr->op ){
+    case TK_FIELD: {
+      sqliteVdbeAddOp(v, OP_Field, pExpr->iTable, pExpr->iField, 0, 0);
+      break;
+    }
+    case TK_INTEGER: {
+      int i = atoi(pExpr->token.z);
+      sqliteVdbeAddOp(v, OP_Integer, i, 0, 0, 0);
+      break;
+    }
+    case TK_FLOAT: {
+      int addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
+      sqliteVdbeChangeP3(v, addr, pExpr->token.z, pExpr->token.n);
+      break;
+    }
+    case TK_STRING: {
+      int addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
+      sqliteVdbeChangeP3(v, addr, pExpr->token.z, pExpr->token.n);
+      sqliteVdbeDequoteP3(v, addr);
+      break;
+    }
+    case TK_NULL: {
+      sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
+      break;
+    }
+    case TK_AND:
+    case TK_OR:
+    case TK_PLUS:
+    case TK_STAR:
+    case TK_MINUS:
+    case TK_SLASH: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteExprCode(pParse, pExpr->pRight);
+      sqliteVdbeAddOp(v, op, 0, 0, 0, 0);
+      break;
+    }
+    case TK_LT:
+    case TK_LE:
+    case TK_GT:
+    case TK_GE:
+    case TK_NE:
+    case TK_EQ: {
+      int dest;
+      sqliteVdbeAddOp(v, OP_Integer, 0, 0, 0, 0);
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteExprCode(pParse, pExpr->pRight);
+      dest = sqliteVdbeCurrentAddr(v) + 2;
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      sqliteVdbeAddOp(v, OP_AddImm, 1, 0, 0, 0);
+      break;
+    }
+    case TK_NOT:
+    case TK_UMINUS: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteVdbeAddOp(v, op, 0, 0, 0, 0);
+      break;
+    }
+    case TK_ISNULL:
+    case TK_NOTNULL: {
+      int dest;
+      sqliteVdbeAddOp(v, OP_Integer, 0, 0, 0, 0);
+      sqliteExprCode(pParse, pExpr->pLeft);
+      dest = sqliteVdbeCurrentAddr(v) + 2;
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      sqliteVdbeAddOp(v, OP_AddImm, 1, 0, 0, 0);
+      break;
+    }
+  }
+  return;
+}
+
+/*
+** Generate code for a boolean expression such that a jump is made
+** to the label "dest" if the expression is true but execution
+** continues straight thru if the expression is false.
+*/
+void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
+  Vdbe *v = pParse->pVdbe;
+  int op = 0;
+  switch( pExpr->op ){
+    case TK_LT:       op = OP_Lt;       break;
+    case TK_LE:       op = OP_Le;       break;
+    case TK_GT:       op = OP_Gt;       break;
+    case TK_GE:       op = OP_Ge;       break;
+    case TK_NE:       op = OP_Ne;       break;
+    case TK_EQ:       op = OP_Eq;       break;
+    case TK_ISNULL:   op = OP_IsNull;   break;
+    case TK_NOTNULL:  op = OP_NotNull;  break;
+    default:  break;
+  }
+  switch( pExpr->op ){
+    case TK_AND: {
+      int d2 = sqliteVdbeMakeLabel(v);
+      sqliteExprIfFalse(pParse, pExpr->pLeft, d2);
+      sqliteExprIfTrue(pParse, pExpr->pRight, dest);
+      sqliteVdbeResolveLabel(v, d2);
+      break;
+    }
+    case TK_OR: {
+      sqliteExprIfTrue(pParse, pExpr->pLeft, dest);
+      sqliteExprIfTrue(pParse, pExpr->pRight, dest);
+      break;
+    }
+    case TK_LT:
+    case TK_LE:
+    case TK_GT:
+    case TK_GE:
+    case TK_NE:
+    case TK_EQ: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteExprCode(pParse, pExpr->pRight);
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      break;
+    }
+    case TK_ISNULL:
+    case TK_NOTNULL: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      break;
+    }
+    default: {
+      sqliteExprCode(pParse, pExpr);
+      sqliteVdbeAddOp(v, OP_If, 0, dest, 0, 0);
+      break;
+    }
+  }
+}
+
+/*
+** Generate code for boolean expression such that a jump is made
+** to the label "dest" if the expression is false but execution
+** continues straight thru if the expression is true.
+*/
+void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){
+  Vdbe *v = pParse->pVdbe;
+  int op = 0;
+  switch( pExpr->op ){
+    case TK_LT:       op = OP_Ge;       break;
+    case TK_LE:       op = OP_Gt;       break;
+    case TK_GT:       op = OP_Le;       break;
+    case TK_GE:       op = OP_Lt;       break;
+    case TK_NE:       op = OP_Eq;       break;
+    case TK_EQ:       op = OP_Ne;       break;
+    case TK_ISNULL:   op = OP_NotNull;  break;
+    case TK_NOTNULL:  op = OP_IsNull;   break;
+    default:  break;
+  }
+  switch( pExpr->op ){
+    case TK_AND: {
+      sqliteExprIfFalse(pParse, pExpr->pLeft, dest);
+      sqliteExprIfFalse(pParse, pExpr->pRight, dest);
+      break;
+    }
+    case TK_OR: {
+      int d2 = sqliteVdbeMakeLabel(v);
+      sqliteExprIfTrue(pParse, pExpr->pLeft, d2);
+      sqliteExprIfFalse(pParse, pExpr->pRight, dest);
+      sqliteVdbeResolveLabel(v, d2);
+      break;
+    }
+    case TK_LT:
+    case TK_LE:
+    case TK_GT:
+    case TK_GE:
+    case TK_NE:
+    case TK_EQ: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteExprCode(pParse, pExpr->pRight);
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      break;
+    }
+    case TK_ISNULL:
+    case TK_NOTNULL: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
+      break;
+    }
+    default: {
+      sqliteExprCode(pParse, pExpr);
+      sqliteVdbeAddOp(v, OP_Not, 0, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_If, 0, dest, 0, 0);
+      break;
+    }
+  }
+}