The echo module test is now running.  Added the tclvar module test but have
not yet done anything with it. (CVS 3234)

FossilOrigin-Name: 29199eeea4c46168ccaa7535d4941bd740479dee
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index f214380..9d59515 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the SQLite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.173 2006/06/13 15:00:55 danielk1977 Exp $
+** @(#) $Id: sqlite.h.in,v 1.174 2006/06/13 23:51:34 drh Exp $
 */
 #ifndef _SQLITE3_H_
 #define _SQLITE3_H_
@@ -926,6 +926,7 @@
 const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
 int sqlite3_column_type(sqlite3_stmt*, int iCol);
 int sqlite3_column_numeric_type(sqlite3_stmt*, int iCol);
+sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
 
 /*
 ** The sqlite3_finalize() function is called to delete a compiled
@@ -1547,7 +1548,7 @@
   int (*xDestroy)(sqlite3_vtab *pVTab);
   int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
   int (*xClose)(sqlite3_vtab_cursor*);
-  int (*xFilter)(sqlite3_vtab_cursor*, char *zPlan, int nPlan,
+  int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
                 int argc, sqlite3_value **argv);
   int (*xNext)(sqlite3_vtab_cursor*);
   int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
@@ -1595,7 +1596,8 @@
 ** is true, then the constraint is assumed to be fully handled by the
 ** virtual table and is not checked again by SQLite.
 **
-** The idxNum value is recorded and passed into xFilter.  
+** The idxNum and idxPtr values are recorded and passed into xFilter.
+** sqlite3_free() is used to free idxPtr if needToFreeIdxPtr is true.
 **
 ** The orderByConsumed means that output from xFilter will occur in
 ** the correct order to satisfy the ORDER BY clause so that no separate
@@ -1626,10 +1628,9 @@
     int argvIndex;           /* if >0, constraint is part of argv to xFilter */
     unsigned char omit;      /* Do not code a test for this constraint */
   } *const aConstraintUsage;
-
-  char *zPlan;               /* xBestIndex blob passed to xFilter */
-  int nPlan;                 /* Size of nPlan */
-
+  int idxNum;                /* Number used to identify the index */
+  char *idxStr;              /* String, possibly obtained from sqlite3_malloc */
+  int needToFreeIdxStr;      /* Free idxStr using sqlite3_free() if true */
   int orderByConsumed;       /* True if output is already ordered */
   double estimatedCost;      /* Estimated cost of using this index */
 };
@@ -1686,13 +1687,6 @@
 int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);
 
 /*
-** This function is called by the xBestIndex method of a module to 
-** allocate space to store the query-plan passed to the corresponding
-** xFilter invocation(s).
-*/
-char *sqlite3_allocate_queryplan(sqlite3_index_info *, int);
-
-/*
 ** The interface to the virtual-table mechanism defined above (back up
 ** to a comment remarkably similar to this one) is currently considered
 ** to be experimental.  The interface might change in incompatible ways.
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 07783c1..9c3890b 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** A TCL Interface to SQLite
 **
-** $Id: tclsqlite.c,v 1.157 2006/06/11 23:41:56 drh Exp $
+** $Id: tclsqlite.c,v 1.158 2006/06/13 23:51:35 drh Exp $
 */
 #ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */
 
@@ -2155,6 +2155,7 @@
     extern int Md5_Init(Tcl_Interp*);
     extern int Sqlitetestsse_Init(Tcl_Interp*);
     extern int Sqlitetestasync_Init(Tcl_Interp*);
+    extern int Sqlitetesttclvar_Init(Tcl_Interp*);
 
     Sqlitetest1_Init(interp);
     Sqlitetest2_Init(interp);
@@ -2165,6 +2166,7 @@
     Sqlitetest7_Init(interp);
     Sqlitetest8_Init(interp);
     Sqlitetestasync_Init(interp);
+    Sqlitetesttclvar_Init(interp);
     Md5_Init(interp);
 #ifdef SQLITE_SSE
     Sqlitetestsse_Init(interp);
diff --git a/src/test8.c b/src/test8.c
index 5f005e0..24067b9 100644
--- a/src/test8.c
+++ b/src/test8.c
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test8.c,v 1.10 2006/06/13 15:00:55 danielk1977 Exp $
+** $Id: test8.c,v 1.11 2006/06/13 23:51:35 drh Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -35,6 +35,7 @@
   sqlite3_vtab base;
   Tcl_Interp *interp;
   sqlite3 *db;
+  char *zTableName;       /* Name of the real table */
   char *zStmt;                 /* "SELECT rowid, * FROM <real-table-name> " */
 
   int *aIndex;
@@ -224,6 +225,7 @@
   pVtab->base.pModule = pModule;
   pVtab->interp = pModule->pAux;
   pVtab->db = db;
+  pVtab->zTableName = sqlite3MPrintf("%s", argv[1]);
   for(i=0; i<argc; i++){
     appendToEchoModule(pVtab->interp, argv[i]);
   }
@@ -261,6 +263,7 @@
     sqliteFree(p->aCol[ii]);
   }
   sqliteFree(p->aCol);
+  sqliteFree(p->zTableName);
   sqliteFree(p);
   return 0;
 }
@@ -310,28 +313,7 @@
   sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
 
   assert( sqlite3_data_count(pStmt)>iCol );
-  switch( sqlite3_column_type(pStmt, iCol) ){
-    case SQLITE_INTEGER:
-      sqlite3_result_int64(ctx, sqlite3_column_int64(pStmt, iCol));
-      break;
-    case SQLITE_FLOAT:
-      sqlite3_result_double(ctx, sqlite3_column_double(pStmt, iCol));
-      break;
-    case SQLITE_TEXT:
-      sqlite3_result_text(ctx, 
-          sqlite3_column_text(pStmt, iCol),
-          sqlite3_column_bytes(pStmt, iCol),
-          SQLITE_TRANSIENT
-      );
-      break;
-    case SQLITE_BLOB:
-      sqlite3_result_blob(ctx, 
-          sqlite3_column_blob(pStmt, iCol),
-          sqlite3_column_bytes(pStmt, iCol),
-          SQLITE_TRANSIENT
-      );
-      break;
-  }
+  sqlite3_result_value(ctx, sqlite3_column_value(pStmt, iCol));
   return SQLITE_OK;
 }
 
@@ -344,31 +326,55 @@
 
 static int echoFilter(
   sqlite3_vtab_cursor *pVtabCursor, 
-  char *zPlan, int nPlan,
-  int argc, 
-  sqlite3_value **argv
+  int idxNum, const char *idxStr,
+  int argc, sqlite3_value **argv
 ){
   int rc;
-  int ii;
+  int i;
 
   echo_cursor *pCur = (echo_cursor *)pVtabCursor;
   echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab;
   sqlite3 *db = pVtab->db;
 
-  appendToEchoModule(pVtab->interp, "xFilter");
-  appendToEchoModule(pVtab->interp, zPlan);
-  for(ii=0; ii<argc; ii++){
-    appendToEchoModule(pVtab->interp, sqlite3_value_text(argv[ii]));
-  }
-
   sqlite3_finalize(pCur->pStmt);
   pCur->pStmt = 0;
-  rc = sqlite3_prepare(db, pVtab->zStmt, -1, &pCur->pStmt, 0);
-
+  rc = sqlite3_prepare(db, idxStr, -1, &pCur->pStmt, 0);
+  for(i=0; i<argc; i++){
+    switch( sqlite3_value_type(argv[i]) ){
+      case SQLITE_INTEGER: {
+        sqlite3_bind_int64(pCur->pStmt, i+1, sqlite3_value_int64(argv[i]));
+        break;
+      }
+      case SQLITE_FLOAT: {
+        sqlite3_bind_double(pCur->pStmt, i+1, sqlite3_value_double(argv[i]));
+        break;
+      }
+      case SQLITE_NULL: {
+        sqlite3_bind_null(pCur->pStmt, i+1);
+        break;
+      }
+      case SQLITE_TEXT: {
+        sqlite3_bind_text(pCur->pStmt, i+1, sqlite3_value_text(argv[i]),
+                          sqlite3_value_bytes(argv[i]), SQLITE_TRANSIENT);
+        break;
+      }
+      case SQLITE_BLOB: {
+        sqlite3_bind_blob(pCur->pStmt, i+1, sqlite3_value_blob(argv[i]),
+                          sqlite3_value_bytes(argv[i]), SQLITE_TRANSIENT);
+        break;
+      }
+    }
+  }
   if( rc==SQLITE_OK ){
     rc = echoNext(pVtabCursor);
   }
 
+  appendToEchoModule(pVtab->interp, "xFilter");
+  appendToEchoModule(pVtab->interp, idxStr);
+  for(i=0; i<argc; i++){
+    appendToEchoModule(pVtab->interp, sqlite3_value_text(argv[i]));
+  }
+
   return rc;
 }
 
@@ -386,13 +392,13 @@
 */
 static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
   int ii;
-  char *zWhere = 0;
-  char *zOrder = 0;
-  char *zPlan = 0;
-  int nPlan = 0;
+  char *zQuery = 0;
+  char *zNew;
   int nArg = 0;
+  const char *zSep = "WHERE";
   echo_vtab *pVtab = (echo_vtab *)tab;
 
+  zQuery = sqlite3_mprintf("SELECT rowid, * FROM %Q", pVtab->zTableName);
   for(ii=0; ii<pIdxInfo->nConstraint; ii++){
     const struct sqlite3_index_constraint *pConstraint;
     struct sqlite3_index_constraint_usage *pUsage;
@@ -418,39 +424,20 @@
         case SQLITE_INDEX_CONSTRAINT_MATCH:
           zOp = "MATCH"; break;
       }
-      if( zWhere ){
-        char *zTmp = zWhere;
-        zWhere = sqlite3MPrintf("%s AND %s %s ?", zWhere, zCol, zOp);
-        sqliteFree(zTmp);
-      } else {
-        zWhere = sqlite3MPrintf("WHERE %s %s ?", zCol, zOp);
-      }
-
+      zNew = sqlite3_mprintf("%s %s %s %s ?", zQuery, zSep, zCol, zOp);
+      sqlite3_free(zQuery);
+      zQuery = zNew;
+      zSep = "AND";
       pUsage->argvIndex = ++nArg;
       pUsage->omit = 1;
     }
   }
-
   appendToEchoModule(pVtab->interp, "xBestIndex");;
-  appendToEchoModule(pVtab->interp, zWhere);
-  appendToEchoModule(pVtab->interp, zOrder);
+  appendToEchoModule(pVtab->interp, zQuery);
 
-  nPlan = 2;
-  if( zWhere ){
-    nPlan += strlen(zWhere);
-  }
-  if( zOrder ){
-    nPlan += strlen(zWhere);
-  }
-  zPlan = sqlite3_allocate_queryplan(pIdxInfo, nPlan);
-  if( zPlan ){
-    sprintf(zPlan, "%s%s%s", 
-        zWhere?zWhere:"", (zOrder&&zWhere)?" ":"", zOrder?zOrder:"");
-  }
-
-  sqliteFree(zWhere);
-  sqliteFree(zOrder);
-
+  pIdxInfo->idxStr = zQuery;
+  pIdxInfo->needToFreeIdxStr = 1;
+  pIdxInfo->estimatedCost = 1.0;
   return SQLITE_OK;
 }
 
diff --git a/src/test_tclvar.c b/src/test_tclvar.c
new file mode 100644
index 0000000..00937c2
--- /dev/null
+++ b/src/test_tclvar.c
@@ -0,0 +1,193 @@
+/*
+** 2006 June 13
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** Code for testing the virtual table interfaces.  This code
+** is not included in the SQLite library.  It is used for automated
+** testing of the SQLite library.
+**
+** The emphasis of this file is a virtual table that provides
+** access to TCL variables.
+**
+** $Id: test_tclvar.c,v 1.1 2006/06/13 23:51:35 drh Exp $
+*/
+#include "sqliteInt.h"
+#include "tcl.h"
+#include "os.h"
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct tclvar_vtab tclvar_vtab;
+typedef struct tclvar_cursor tclvar_cursor;
+
+/* 
+** A tclvar virtual-table object 
+*/
+struct tclvar_vtab {
+  sqlite3_vtab base;
+  Tcl_Interp *interp;
+};
+
+/* A tclvar cursor object */
+struct tclvar_cursor {
+  sqlite3_vtab_cursor base;
+  Tcl_Obj *pList1, *pList2;
+  int i, j;
+};
+
+/* Methods for the tclvar module */
+static int tclvarConnect(
+  sqlite3 *db,
+  const sqlite3_module *pModule,
+  int argc, char **argv,
+  sqlite3_vtab **ppVtab
+){
+  tclvar_vtab *pVtab;
+  static const char zSchema[] = 
+     "CREATE TABLE whatever(name TEXT, arrayname TEXT, value TEXT)";
+  pVtab = sqliteMalloc( sizeof(*pVtab) );
+  if( pVtab==0 ) return SQLITE_NOMEM;
+  *ppVtab = &pVtab->base;
+  pVtab->base.pModule = pModule;
+  pVtab->interp = pModule->pAux;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  sqlite3_declare_vtab(db, zSchema);
+#endif
+  return SQLITE_OK;
+}
+/* Note that for this virtual table, the xCreate and xConnect
+** methods are identical. */
+static int tclvarDisconnect(sqlite3_vtab *pVtab){
+  free(pVtab);
+}
+/* The xDisconnect and xDestroy methods are also the same */
+
+static int tclvarOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+  tclvar_cursor *pCur;
+  pCur = sqliteMalloc(sizeof(tclvar_cursor));
+  *ppCursor = &pCur->base;
+  return SQLITE_OK;
+}
+
+static int tclvarClose(sqlite3_vtab_cursor *cur){
+  tclvar_cursor *pCur = (tclvar_cursor *)cur;
+  if( pCur->pList1 ){
+    Tcl_DecrRefCount(pCur->pList1);
+  }
+  if( pCur->pList2 ){
+    Tcl_DecrRefCount(pCur->pList2);
+  }
+  sqliteFree(pCur);
+  return SQLITE_OK;
+}
+
+static int tclvarNext(sqlite3_vtab_cursor *cur){
+  tclvar_cursor *pCur = (tclvar_cursor *)cur;
+  return 0;
+}
+
+static int tclvarColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
+  tclvar_cursor *pCur = (tclvar_cursor*)cur;
+  return SQLITE_OK;
+}
+
+static int tclvarRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+  tclvar_cursor *pCur = (tclvar_cursor*)cur;
+  return SQLITE_OK;
+}
+
+static int tclvarFilter(
+  sqlite3_vtab_cursor *pVtabCursor, 
+  int idxNum, const char *idxStr,
+  int argc, sqlite3_value **argv
+){
+  tclvar_cursor *pCur = (tclvar_cursor *)pVtabCursor;
+  tclvar_vtab *pVtab = (tclvar_vtab *)pCur->base.pVtab;
+  return 0;
+}
+
+/*
+*/
+static int tclvarBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+  tclvar_vtab *pVtab = (tclvar_vtab *)tab;
+  return SQLITE_OK;
+}
+
+/*
+** A virtual table module that merely echos method calls into TCL
+** variables.
+*/
+static sqlite3_module tclvarModule = {
+  0,                         /* iVersion */
+  "tclvar",                  /* zName */
+  0,                         /* pAux */
+  tclvarConnect,
+  tclvarConnect,
+  tclvarBestIndex,
+  tclvarDisconnect, 
+  tclvarDisconnect,
+  tclvarOpen,                  /* xOpen - open a cursor */
+  tclvarClose,                 /* xClose - close a cursor */
+  tclvarFilter,                /* xFilter - configure scan constraints */
+  tclvarNext,                  /* xNext - advance a cursor */
+  tclvarColumn,                /* xColumn - read data */
+  tclvarRowid                  /* xRowid - read data */
+};
+
+/*
+** Decode a pointer to an sqlite3 object.
+*/
+static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
+  *ppDb = (sqlite3*)sqlite3TextToPtr(zA);
+  return TCL_OK;
+}
+
+
+/*
+** Register the echo virtual table module.
+*/
+static int register_tclvar_module(
+  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  sqlite3 *db;
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "DB");
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+  tclvarModule.pAux = interp;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  sqlite3_create_module(db, "tclvar", &tclvarModule);
+#endif
+  return TCL_OK;
+}
+
+
+/*
+** Register commands with the TCL interpreter.
+*/
+int Sqlitetesttclvar_Init(Tcl_Interp *interp){
+  static struct {
+     char *zName;
+     Tcl_ObjCmdProc *xProc;
+     void *clientData;
+  } aObjCmd[] = {
+     { "register_tclvar_module",   register_tclvar_module, 0 },
+  };
+  int i;
+  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
+    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 
+        aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
+  }
+  return TCL_OK;
+}
diff --git a/src/vdbe.c b/src/vdbe.c
index 22967d4..30b52af 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.557 2006/06/13 15:00:55 danielk1977 Exp $
+** $Id: vdbe.c,v 1.558 2006/06/13 23:51:35 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -4593,17 +4593,19 @@
 ** P1 is a cursor opened using VOpen.  P2 is an address to jump to if
 ** the filtered result set is empty.
 **
-** P3 points to enough free space to use to marshall the arguments.
+** P3 is either NULL or a string that was generated by the xBestIndex
+** method of the module.  The interpretation of the P3 string is left
+** to the module implementation.
 **
 ** This opcode invokes the xFilter method on the virtual table specified
-** by P1.  The query plan parameter to xFilter is the top of the stack.
-** Next down on the stack is the argc parameter.  Beneath the
+** by P1.  The integer query plan parameter to xFilter is the top of the
+** stack.  Next down on the stack is the argc parameter.  Beneath the
 ** next of stack are argc additional parameters which are passed to
 ** xFilter as argv. The topmost parameter (i.e. 3rd element popped from
 ** the stack) becomes argv[argc-1] when passed to xFilter.
 **
-** The query plan, argc, and all argv stack values are popped from the
-** stack before this instruction completes.
+** The integer query plan parameter, argc, and all argv stack values 
+** are popped from the stack before this instruction completes.
 **
 ** A jump is made to P2 if the result set after filtering would be 
 ** empty.
@@ -4619,20 +4621,21 @@
 
   /* Grab the index number and argc parameters off the top of the stack. */
   assert( (&pTos[-1])>=p->aStack );
-  assert( pTos[0].flags&MEM_Blob && pTos[-1].flags==MEM_Int );
+  assert( (pTos[0].flags&MEM_Int)!=0 && pTos[-1].flags==MEM_Int );
   nArg = pTos[-1].i;
 
   /* Invoke the xFilter method if one is defined. */
   if( pModule->xFilter ){
     int res;
-    int ii;
-    Mem **apArg = (Mem **)pOp->p3;
-    for(ii = 0; ii<nArg; ii++){
-      apArg[ii] = &pTos[ii+1-2-nArg];
+    int i;
+    Mem **apArg = p->apArg;
+    for(i = 0; i<nArg; i++){
+      apArg[i] = &pTos[i+1-2-nArg];
+      storeTypeInfo(apArg[i], 0);
     }
 
     if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
-    res = pModule->xFilter(pCur->pVtabCursor, pTos->z, pTos->n, nArg, apArg);
+    res = pModule->xFilter(pCur->pVtabCursor, pTos->i, pOp->p3, nArg, apArg);
     if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
 
     if( res==0 ){
diff --git a/src/vdbe.h b/src/vdbe.h
index 713d0f1..46f6fe0 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -15,7 +15,7 @@
 ** or VDBE.  The VDBE implements an abstract machine that runs a
 ** simple program to access and modify the underlying database.
 **
-** $Id: vdbe.h,v 1.104 2006/06/13 01:04:53 drh Exp $
+** $Id: vdbe.h,v 1.105 2006/06/13 23:51:35 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -71,6 +71,7 @@
 #define P3_MEM      (-8)  /* P3 is a pointer to a Mem*    structure */
 #define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */
 #define P3_VTAB     (-10) /* P3 is a pointer to an sqlite3_vtab structure */
+#define P3_MPRINTF  (-11) /* P3 is a string obtained from sqlite3_mprintf() */
 
 /* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
 ** is made.  That copy is freed when the Vdbe is finalized.  But if the
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 94f18aa..60c8585 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -454,11 +454,9 @@
   columnMallocFailure(pStmt);
   return val;
 }
-#if 0
 sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
   return columnMem(pStmt, i);
 }
-#endif
 #ifndef SQLITE_OMIT_UTF16
 const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
   const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index fa3450c..bc9468e 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -263,8 +263,13 @@
       }
     }else if( opcode==OP_Statement ){
       hasStatementBegin = 1;
+    }else if( opcode==OP_VFilter ){
+      int n;
+      assert( p->nOp - i >= 3 );
+      assert( pOp[-2].opcode==OP_Integer );
+      n = pOp[-2].p1;
+      if( n>nMaxArgs ) nMaxArgs = n;
     }
-
     if( opcodeNoPush(opcode) ){
       nMaxStack--;
     }
@@ -380,6 +385,10 @@
         sqliteFree(p3);
         break;
       }
+      case P3_MPRINTF: {
+        sqlite3_free(p3);
+        break;
+      }
       case P3_VDBEFUNC: {
         VdbeFunc *pVdbeFunc = (VdbeFunc *)p3;
         sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
diff --git a/src/vtab.c b/src/vtab.c
index f717831..30bff32 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to help implement virtual tables.
 **
-** $Id: vtab.c,v 1.7 2006/06/13 15:00:55 danielk1977 Exp $
+** $Id: vtab.c,v 1.8 2006/06/13 23:51:35 drh Exp $
 */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 #include "sqliteInt.h"
@@ -277,16 +277,6 @@
   return rc;
 }
 
-/*
-** Resize pInfo->zPlan to nBytes bytes using realloc(). Set pInfo->nPlan
-** to nBytes and return a pointer to the allocated memory.
-*/
-char *sqlite3_allocate_queryplan(sqlite3_index_info *pInfo, int nBytes){
-  pInfo->nPlan = nBytes;
-  sqlite3ReallocOrFree(&pInfo->zPlan, nBytes);
-  return pInfo->zPlan;
-}
-
 
 /*
 ** This function is used to set the schema of a virtual table.  It is only
diff --git a/src/where.c b/src/where.c
index 2bfb21c..d137d74 100644
--- a/src/where.c
+++ b/src/where.c
@@ -16,7 +16,7 @@
 ** so is applicable.  Because this module is responsible for selecting
 ** indices, you might also think of this module as the "query optimizer".
 **
-** $Id: where.c,v 1.215 2006/06/13 17:39:01 drh Exp $
+** $Id: where.c,v 1.216 2006/06/13 23:51:35 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -1108,8 +1108,12 @@
     pIdxCons->usable =  (pTerm->prereqRight & notReady)==0;
   }
   memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
-  pIdxInfo->zPlan = 0;
-  pIdxInfo->nPlan = 0;
+  if( pIdxInfo->needToFreeIdxStr ){
+    sqlite3_free(pIdxInfo->idxStr);
+  }
+  pIdxInfo->idxStr = 0;
+  pIdxInfo->idxNum = 0;
+  pIdxInfo->needToFreeIdxStr = 0;
   pIdxInfo->orderByConsumed = 0;
   pIdxInfo->estimatedCost = SQLITE_BIG_DBL;
   nOrderBy = pIdxInfo->nOrderBy;
@@ -1572,10 +1576,13 @@
   if( pWInfo ){
     int i;
     for(i=0; i<pWInfo->nLevel; i++){
-      if( pWInfo->a[i].pIdxInfo ){
-        sqliteFree(pWInfo->a[i].pIdxInfo->zPlan);
+      sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
+      if( pInfo ){
+        if( pInfo->needToFreeIdxStr ){
+          sqlite3_free(pInfo->idxStr);
+        }
+        sqliteFree(pInfo);
       }
-      sqliteFree(pWInfo->a[i].pIdxInfo);
     }
     sqliteFree(pWInfo);
   }
@@ -1861,8 +1868,9 @@
       }
 #ifndef SQLITE_OMIT_VIRTUALTABLE
       else if( pLevel->pIdxInfo ){
-        zMsg = sqlite3MPrintf("%z VIRTUAL TABLE INDEX %s",
-                    pLevel->pIdxInfo->zPlan);
+        sqlite3_index_info *pIdxInfo = pLevel->pIdxInfo;
+        zMsg = sqlite3MPrintf("%z VIRTUAL TABLE INDEX %d:%s",
+                    pIdxInfo->idxNum, pIdxInfo->idxStr);
       }
 #endif
       if( pLevel->flags & WHERE_ORDERBY ){
@@ -1952,26 +1960,29 @@
       /* Case 0:  The table is a virtual-table.  Use the VFilter and VNext
       **          to access the data.
       */
-      char *zSpace;     /* Space for OP_VFilter to marshall it's arguments */
-
       sqlite3_index_info *pIdxInfo = pLevel->pIdxInfo;
-      for(i=1; i<=pIdxInfo->nConstraint; i++){
+      int nConstraint = pIdxInfo->nConstraint;
+      struct sqlite3_index_constraint_usage *aUsage =
+                                                  pIdxInfo->aConstraintUsage;
+      const struct sqlite3_index_constraint *aConstraint =
+                                                  pIdxInfo->aConstraint;
+
+      for(i=1; i<=nConstraint; i++){
         int j;
-        for(j=0; j<pIdxInfo->nConstraint; j++){
-          if( pIdxInfo->aConstraintUsage[j].argvIndex==i ){
-            sqlite3ExprCode(pParse, wc.a[j].pExpr->pRight);
+        for(j=0; j<nConstraint; j++){
+          if( aUsage[j].argvIndex==i ){
+            int k = aConstraint[j].iTermOffset;
+            sqlite3ExprCode(pParse, wc.a[k].pExpr->pRight);
             break;
           }
         }
-        if( j==pIdxInfo->nConstraint ) break;
+        if( j==nConstraint ) break;
       }
       sqlite3VdbeAddOp(v, OP_Integer, i-1, 0);
-      sqlite3VdbeAddOp(v, OP_Blob, pIdxInfo->nPlan, 0);
-      sqlite3VdbeChangeP3(v, -1, pIdxInfo->zPlan, P3_DYNAMIC);
-      pIdxInfo->zPlan = 0;
-      sqlite3VdbeAddOp(v, OP_VFilter, iCur, brk);
-      zSpace = (char *)sqliteMalloc(sizeof(sqlite3_value*)*(i-1));
-      sqlite3VdbeChangeP3(v, -1, zSpace, P3_DYNAMIC);
+      sqlite3VdbeAddOp(v, OP_Integer, pIdxInfo->idxNum, 0);
+      sqlite3VdbeOp3(v, OP_VFilter, iCur, brk, pIdxInfo->idxStr,
+                      pIdxInfo->needToFreeIdxStr ? P3_MPRINTF : P3_STATIC);
+      pIdxInfo->needToFreeIdxStr = 0;
       for(i=0; i<pIdxInfo->nConstraint; i++){
         if( pIdxInfo->aConstraintUsage[i].omit ){
           disableTerm(pLevel, &wc.a[i]);