]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Added code to iterate through virtual tables. All regression tests pass
authordrh <drh@noemail.net>
Mon, 12 Jun 2006 21:59:13 +0000 (21:59 +0000)
committerdrh <drh@noemail.net>
Mon, 12 Jun 2006 21:59:13 +0000 (21:59 +0000)
but the new code is completely untested. (CVS 3219)

FossilOrigin-Name: 010965433140fbe508a907d861dbad79343bf7c2

manifest
manifest.uuid
src/sqlite.h.in
src/sqliteInt.h
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
src/where.c

index dbea29700411cf2c2e17a5637b41ca96f05257ac..08d7532f242976f63d99054db266c0aaabb5cb42 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\scode\sto\sinvoke\sthe\sxDestroy\smethod\sof\sa\svirtual\stable\swhen\sit\sis\sdropped.\s(CVS\s3218)
-D 2006-06-12T16:01:22
+C Added\scode\sto\siterate\sthrough\svirtual\stables.\s\sAll\sregression\stests\spass\nbut\sthe\snew\scode\sis\scompletely\suntested.\s(CVS\s3219)
+D 2006-06-12T21:59:14
 F Makefile.in 56fd6261e83f60724e6dcd764e06ab68cbd53909
 F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -72,9 +72,9 @@ F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261
 F src/select.c 38eda11d950ed5e631ea9054f84a4a8b9e9b39d8
 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
 F src/shell.c 55bf6335dae7146f7a300039f5d6bb35010f1996
-F src/sqlite.h.in cad97e59cfad8337f9f43ea9662714a256ca80b2
+F src/sqlite.h.in 251b584d707939b38663f5ad9a1a1815d6cce9fb
 F src/sqlite3ext.h 127bd394c8eea481f2ac9b754bf399dbfc818b75
-F src/sqliteInt.h a617f13e11e05f78a8fa55756591eba9a59c9dbc
+F src/sqliteInt.h 9562411b336b77123d1f569d4144fe3ba1ecb3bf
 F src/table.c f64ec4fbfe333f8df925bc6ba494f55e05b0e75e
 F src/tclsqlite.c 0b2a04cfc1b4298adfbe90a754cfbbe207aca11a
 F src/test1.c 88291fa6674dcd409b1c9d76d3119151d4b81a50
@@ -94,15 +94,15 @@ F src/update.c 0186f09414a6578156d40666becc964f85c2a616
 F src/utf.c ab81ac59084ff1c07d421eb1a0a84ec809603b44
 F src/util.c ca6ee72772c0f5dc04d2e0ab1973fd3b6a9bf79d
 F src/vacuum.c 5b37d0f436f8e1ffacd17934e44720b38d2247f9
-F src/vdbe.c 7002df8e881e4a977c57d504287b5a30f84b8d37
+F src/vdbe.c 59cb0d8cd19f090061f41715c44b3ed2af6bf264
 F src/vdbe.h 190d85a37658c2397be75a4c70bbc02ebc4ec0ba
-F src/vdbeInt.h 85cd5f81d38edb1b8f4786f407c77a7a3ba636fb
+F src/vdbeInt.h 6ccb7eaae76ebd761470f6a035501ff33aa92c20
 F src/vdbeapi.c 7dc662e7c905ce666bb506dced932e0307115cbf
-F src/vdbeaux.c 4002e6b19d7c9719cb81f9797316b9ad118e4370
+F src/vdbeaux.c 60f84a2da6032a6fffa47ed623279b7dee25223b
 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
 F src/vdbemem.c 5f0afe3b92bb2c037f8d5d697f7c151fa50783a3
 F src/vtab.c 4ec6ac7e5e4fccb38401285d0e329d018622859f
-F src/where.c 3dc5269ba552c0db39247f6bbc98b312ae786863
+F src/where.c d312cf79d42e82cec5bddfa23f42bea6e65b4052
 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/all.test 5df90d015ca63fcef2a4b62c24f7316b66c4bfd4
@@ -363,7 +363,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 65c6e5e117b9194015e382b1ad9bb9c88704eeb7
-R 5c6b73fe0e6f68c2a41a34bb9e99f68c
-U danielk1977
-Z 4c06df1b2df27b4be5379aebd6a5dbae
+P f0c7c8d12c04376e48c6d53a29cfae3fa13b52cf
+R 24b1712dc081e34b63297df85eac34f4
+U drh
+Z 61dbf9364ee86b719872c787076d19e0
index 0affeedfe5906d2618168916eb7e69c478d8e7d1..afae5c32b42cac573f6c48d5b6459a9f5b4aac35 100644 (file)
@@ -1 +1 @@
-f0c7c8d12c04376e48c6d53a29cfae3fa13b52cf
\ No newline at end of file
+010965433140fbe508a907d861dbad79343bf7c2
\ No newline at end of file
index ecd8450bc097b010d623628f5b4bbaaf71278f0a..f07b4603c4dcdd6357cd7559bc29b1752c608bc5 100644 (file)
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the SQLite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.169 2006/06/12 11:24:37 danielk1977 Exp $
+** @(#) $Id: sqlite.h.in,v 1.170 2006/06/12 21:59:14 drh Exp $
 */
 #ifndef _SQLITE3_H_
 #define _SQLITE3_H_
@@ -1510,11 +1510,28 @@ int sqlite3_load_extension(
 
 /*
 ****** EXPERIMENTAL - subject to change without notice **************
+**
+** The interface to the virtual-table mechanism is currently considered
+** to be experimental.  The interface might change in incompatible ways.
+** If this is a problem for you, do not use the interface at this time.
+**
+** When the virtual-table mechanism stablizes, we will declare the
+** interface fixed, support it indefinitely, and remove this comment.
+*/
+
+/*
+** Structures used by the virtual table interface
 */
 typedef struct sqlite3_vtab sqlite3_vtab;
 typedef struct sqlite3_index_info sqlite3_index_info;
 typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;
 typedef struct sqlite3_module sqlite3_module;
+
+/*
+** A module is a class of virtual tables.  Each module is defined
+** by an instance of the following structure.  This structure consists
+** mostly of methods for the module.
+*/
 struct sqlite3_module {
   int iVersion;
   const char *zName;
@@ -1543,40 +1560,140 @@ struct sqlite3_module {
   int (*xRollback)(sqlite3_vtab *pVTab);
   int (*xIsInTrans)(sqlite3_vtab *pVTab);
 };
+
+/*
+** The sqlite3_index_info structure and its substructures is used to
+** pass information into and receive the reply from the xBestIndex
+** method of an sqlite3_module.  The fields under **Inputs** are the
+** inputs to xBestIndex and are read-only.  xBestIndex inserts its
+** results into the **Outputs** fields.
+**
+** The aConstraint[] array records WHERE clause constraints of the
+** form:
+**
+**         column OP expr
+**
+** Where OP is =, <, <=, >, or >=.  The particular operator is stored
+** in aConstraint[].op.  The index of the column is stored in 
+** aConstraint[].iColumn.  aConstraint[].usable is TRUE if the
+** expr on the right-hand side can be evaluated (and thus the constraint
+** is usable) and false if it cannot.
+**
+** The optimizer automatically inverts terms of the form "expr OP column"
+** and makes other simplificatinos to the WHERE clause in an attempt to
+** get as many WHERE clause terms into the form shown above as possible.
+** The aConstraint[] array only reports WHERE clause terms in the correct
+** form that refer to the particular virtual table being queried.
+**
+** Information about the ORDER BY clause is stored in aOrderBy[].
+** Each term of aOrderBy records a column of the ORDER BY clause.
+**
+** The xBestIndex method must fill aConstraintUsage[] with information
+** about what parameters to pass to xBestIndex.  If argvIndex>0 then
+** the right-hand side of the corresponding aConstraint[] is evaluated
+** and becomes the argvIndex-th entry in argv.  If aConstraintUsage[].omit
+** 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 orderByConsumed means that output from xFilter will occur in
+** the correct order to satisfy the ORDER BY clause so that no separate
+** sorting step is required.
+**
+** The estimatedCost value is an estimate of the cost of doing the
+** particular lookup.  A full scan of a table with N entries should have
+** a cost of N.  A binary search of a table of N entries should have a
+** cost of approximately log(N).
+*/
 struct sqlite3_index_info {
   /* Inputs */
-  int nConstraint;
-  struct sqlite3_index_constraint {
-     int iColumn;
-     unsigned char op;
-     unsigned char omit;
-  } *aConstraint;
-  int nOrderBy;
-  struct sqlite3_index_orderby {
-     int iColumn;
-     unsigned char desc;
-  } *aOrderBy;
+  const int nConstraint;     /* Number of entries in aConstraint */
+  const struct sqlite3_index_constraint {
+     int iColumn;              /* Column on left-hand side of constraint */
+     unsigned char op;         /* Constraint operator */
+     unsigned char usable;     /* True if this constraint is usable */
+     int iTermOffset;          /* Used internally - xBestIndex should ignore */
+  } *const aConstraint;      /* Table of WHERE clause constraints */
+  const int nOrderBy;        /* Number of terms in the ORDER BY clause */
+  const struct sqlite3_index_orderby {
+     int iColumn;              /* Column number */
+     unsigned char desc;       /* True for DESC.  False for ASC. */
+  } *const aOrderBy;         /* The ORDER BY clause */
 
   /* Outputs */
-  int idxNum;
-  int columnCount;
-  int *aColumn;
-  int orderByConsumed;
+  struct sqlite3_index_constraint_usage {
+    int argvIndex;           /* if >0, constraint is part of argv to xFilter */
+    unsigned char omit;      /* Do not code a test for this constraint */
+  } *const aConstraintUsage;
+  int idxNum;                /* Index number passed to xFilter */
+  int orderByConsumed;       /* True if output is already ordered */
+  double estimatedCost;      /* Estimated cost of using this index */
 };
-#define SQLITE_INDEX_CONSTRAINT_EQ    1
-#define SQLITE_INDEX_CONSTRAINT_GT    3
-#define SQLITE_INDEX_CONSTRAINT_LE    4
-#define SQLITE_INDEX_CONSTRAINT_LT    5
-#define SQLITE_INDEX_CONSTRAINT_GE    6
-#define SQLITE_INDEX_CONSTRAINT_MATCH 7
+#define SQLITE_INDEX_CONSTRAINT_EQ    2
+#define SQLITE_INDEX_CONSTRAINT_GT    4
+#define SQLITE_INDEX_CONSTRAINT_LE    8
+#define SQLITE_INDEX_CONSTRAINT_LT    16
+#define SQLITE_INDEX_CONSTRAINT_GE    32
+#define SQLITE_INDEX_CONSTRAINT_MATCH 64
+
+/*
+** This routine is used to register a new module name with an SQLite
+** connection.  Module names must be registered before creating new
+** virtual tables on the module, or before using preexisting virtual
+** tables of the module.
+*/
 int sqlite3_create_module(
-  sqlite3 *db, 
-  const char *zName,
-  const sqlite3_module *
+  sqlite3 *db,               /* SQLite connection to register module with */
+  const char *zName,         /* Name of the module */
+  const sqlite3_module *     /* Methods for the module */
 );
 
+/*
+** Every module implementation uses a subclass of the following structure
+** to describe a particular instance of the module.  Each subclass will
+** be taylored to the specific needs of the module implementation.   The
+** purpose of this superclass is to define certain fields that are common
+** to all module implementations.
+*/
+struct sqlite3_vtab {
+  sqlite3_module *pModule;  /* The module for this virtual table */
+  /* Virtual table implementations will typically add additional fields */
+};
+
+/* Every module implementation uses a subclass of the following structure
+** to describe cursors that point into the virtual table and are used
+** to loop through the virtual table.  Cursors are created using the
+** xOpen method of the module.  Each module implementation will define
+** the content of a cursor structure to suit its own needs.
+**
+** This superclass exists in order to define fields of the cursor that
+** are common to all implementations.
+*/
+struct sqlite3_vtab_cursor {
+  sqlite3_vtab *pVtab;      /* Virtual table of this cursor */
+  /* Virtual table implementations will typically add additional fields */
+};
+
+/*
+** The xCreate and xConnect methods of a module use the following API
+** to declare the format (the names and datatypes of the columns) of
+** the virtual tables they implement.
+*/
 int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);
 
+/*
+** 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.
+** If this is a problem for you, do not use the interface at this time.
+**
+** When the virtual-table mechanism stablizes, we will declare the
+** interface fixed, support it indefinitely, and remove this comment.
+**
+****** EXPERIMENTAL - subject to change without notice **************
+*/
+
 /*
 ** Undo the hack that converts floating point types to integer for
 ** builds on processors without floating point support.
index 739bffc2fd4f06db41bce909562bc237a3feddf8..f78bfb8d6013ea00c58d74fa63765bbe3f91122f 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.501 2006/06/12 16:01:22 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.502 2006/06/12 21:59:14 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1110,6 +1110,7 @@ struct WhereLevel {
   int nEq;              /* Number of == or IN constraints on this loop */
   int nIn;              /* Number of IN operators constraining this loop */
   int *aInLoop;         /* Loop terminators for IN operators */
+  sqlite3_index_info *pIdxInfo;  /* Index information for virtual tables */
 };
 
 /*
index da3c4333540697f413184bb6b5d5a0b286859f81..a98b703f6412fd68dd24c02b363b1a1c068d883c 100644 (file)
@@ -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.553 2006/06/12 16:01:22 danielk1977 Exp $
+** $Id: vdbe.c,v 1.554 2006/06/12 21:59:14 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -4557,6 +4557,73 @@ case OP_VDestroy: {
 }
 #endif /* SQLITE_OMIT_VIRTUALTABLE */
 
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VOpen P1 * P3
+**
+** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
+** P1 is a cursor number.  This opcode opens a cursor to the virtual
+** table and stores that cursor in P1.
+*/
+case OP_VOpen: {
+  break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VFilter P1 P2 *
+**
+** P1 is a cursor opened using VOpen.  P2 is an address to jump to if
+** the filtered result set is empty.
+**
+** This opcode invokes the xFilter method on the virtual table specified
+** by P1.  The index number 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 index number, 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.
+*/
+case OP_VFilter: {
+  break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VRowid P1 * *
+**
+** Push an integer onto the stack which is the rowid of
+** the virtual-table that the P1 cursor is pointing to.
+*/
+case OP_VRowid: {
+  break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VColumn P1 P2 *
+**
+** Push onto the stack the value of the P2-th column of
+** the row of the virtual-table that the P1 cursor is pointing to.
+*/
+case OP_VColumn: {
+  break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VNext P1 P2 *
+**
+** Advance virtual table P1 to the next row in its result set and
+** jump to instruction P2.  Or, if the virtual table has reached
+** the end of its result set, then fall through to the next instruction.
+*/
+case OP_VNext: {
+  break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
 /* An other opcode is illegal...
 */
 default: {
index 01d6a61f19934378bb133012fc6446d2b33b05f6..e4ab44cd89f8a72814911423adb3d5112b39fdb4 100644 (file)
@@ -83,6 +83,9 @@ struct Cursor {
   KeyInfo *pKeyInfo;    /* Info about index keys needed by index cursors */
   int nField;           /* Number of fields in the header */
   i64 seqCount;         /* Sequence counter */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  sqlite3_vtab_cursor *pVtabCursor;  /* The cursor for a virtual table */
+#endif
 
   /* Cached information about the header for the data record that the
   ** cursor is currently pointing to.  Only valid if cacheValid is true.
index f5710b121ae2c88a9437b003b05e97f84547289c..cab259f05f77df8054ad1c0d9860b188f9d4d2eb 100644 (file)
@@ -832,6 +832,14 @@ void sqlite3VdbeFreeCursor(Cursor *pCx){
   if( pCx->pBt ){
     sqlite3BtreeClose(pCx->pBt);
   }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  if( pCx->pVtabCursor ){
+    sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
+    sqlite3_vtab *pVtab = pVtabCursor->pVtab;
+    sqlite3_module *pModule = pVtab->pModule;
+    pModule->xClose(pVtabCursor);
+  }
+#endif
   sqliteFree(pCx->pData);
   sqliteFree(pCx->aType);
   sqliteFree(pCx);
index 515ed4421f8d1ccde460cc6a55cced9e0b1f9db8..ac806208791e8991d5ba9bf50dabdf82d3ae04ef 100644 (file)
@@ -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.210 2006/06/11 23:41:56 drh Exp $
+** $Id: where.c,v 1.211 2006/06/12 21:59:14 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -171,6 +171,7 @@ struct ExprMaskSet {
 #define WHERE_ORDERBY        0x1000   /* Output will appear in correct order */
 #define WHERE_REVERSE        0x2000   /* Scan in reverse order */
 #define WHERE_UNIQUE         0x4000   /* Selects no more than one row */
+#define WHERE_VIRTUALTABLE   0x8000   /* Use virtual-table processing */
 
 /*
 ** Initialize a preallocated WhereClause structure.
@@ -884,6 +885,139 @@ static double estLog(double N){
   return logN;
 }
 
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Compute the best index for a virtual table
+*/
+static double bestVirtualIndex(
+  Parse *pParse,                 /* The parsing context */
+  WhereClause *pWC,              /* The WHERE clause */
+  struct SrcList_item *pSrc,     /* The FROM clause term to search */
+  Bitmask notReady,              /* Mask of cursors that are not available */
+  ExprList *pOrderBy,            /* The order by clause */
+  int orderByUsable,             /* True if we can potential sort */
+  sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */
+){
+  Table *pTab = pSrc->pTab;
+  sqlite3_index_info *pIdxInfo;
+  struct sqlite3_index_constraint *pIdxCons;
+  struct sqlite3_index_orderby *pIdxOrderBy;
+  struct sqlite3_index_constraint_usage *pUsage;
+  WhereTerm *pTerm;
+  int i, j;
+  int nOrderBy;
+
+  /* If the sqlite3_index_info structure has not been previously
+  ** allocated and initialized for this virtual table, then allocate
+  ** and initialize it now
+  */
+  pIdxInfo = *ppIdxInfo;
+  if( pIdxInfo==0 ){
+    WhereTerm *pTerm;
+    int nTerm;
+
+    /* Count the number of possible WHERE clause constraints referring
+    ** to this virtual table */
+    for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
+      if( pTerm->leftCursor != pSrc->iCursor ) continue;
+      if( pTerm->eOperator==WO_IN ) continue;
+      nTerm++;
+    }
+
+    /* If the ORDER BY clause contains only columns in the current 
+    ** virtual table then allocate space for the aOrderBy part of
+    ** the sqlite3_index_info structure.
+    */
+    nOrderBy = 0;
+    if( pOrderBy ){
+      for(i=0; i<pOrderBy->nExpr; i++){
+        Expr *pExpr = pOrderBy->a[i].pExpr;
+        if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
+      }
+      if( i==pOrderBy->nExpr ){
+        nOrderBy = pOrderBy->nExpr;
+      }
+    }
+
+    /* Allocate the sqlite3_index_info structure
+    */
+    pIdxInfo = sqliteMalloc( sizeof(*pIdxInfo)
+                             + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
+                             + sizeof(*pIdxOrderBy)*nOrderBy );
+    if( pIdxInfo==0 ){
+      sqlite3ErrorMsg(pParse, "out of memory");
+      return 0.0;
+    }
+    *ppIdxInfo = pIdxInfo;
+
+    /* Initialize the structure.  The sqlite3_index_info structure contains
+    ** many fields that are declared "const" to prevent xBestIndex from
+    ** changing them.  We have to do some funky casting in order to
+    ** initialize those fields.
+    */
+    pIdxCons = (struct sqlite3_index_constraint*)&pIdxInfo[1];
+    pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
+    pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
+    *(int*)&pIdxInfo->nConstraint = nTerm;
+    *(int*)&pIdxInfo->nOrderBy = nOrderBy;
+    *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons;
+    *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy;
+    *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
+                                                                     pUsage;
+
+    for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
+      if( pTerm->leftCursor != pSrc->iCursor ) continue;
+      if( pTerm->eOperator==WO_IN ) continue;
+      pIdxCons[j].iColumn = pTerm->leftColumn;
+      pIdxCons[j].iTermOffset = i;
+      pIdxCons[j].op = pTerm->eOperator;
+      assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
+      assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
+      assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
+      assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
+      assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
+      assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE) );
+      j++;
+    }
+    for(i=0; i<nOrderBy; i++){
+      Expr *pExpr = pOrderBy->a[i].pExpr;
+      pIdxOrderBy[i].iColumn = pExpr->iColumn;
+      pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder;
+    }
+  }
+
+  /* The module name must be defined */
+  assert( pTab->azModuleArg && pTab->azModuleArg[0] );
+  if( pTab->pVtab==0 ){
+    sqlite3ErrorMsg(pParse, "undefined module %s for table %s",
+        pTab->azModuleArg[0], pTab->zName);
+    return 0.0;
+  }
+
+  /* Set the aConstraint[].usable fields and initialize all 
+  ** output variables
+  */
+  pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+  pUsage = pIdxInfo->aConstraintUsage;
+  for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
+    j = pIdxCons->iTermOffset;
+    pTerm = &pWC->a[j];
+    pIdxCons->usable =  (pTerm->prereqRight & notReady)==0;
+  }
+  memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
+  pIdxInfo->idxNum = 0;
+  pIdxInfo->orderByConsumed = 0;
+  pIdxInfo->estimatedCost = SQLITE_BIG_DBL;
+  nOrderBy = pIdxInfo->nOrderBy;
+  if( pIdxInfo->nOrderBy && !orderByUsable ){
+    *(int*)pIdxInfo->nOrderBy = 0;
+  }
+  pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
+  *(int*)pIdxInfo->nOrderBy = nOrderBy;
+  return pIdxInfo->estimatedCost;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
 /*
 ** Find the best index for accessing a particular table.  Return a pointer
 ** to the index, flags that describe how the index should be used, the
@@ -1327,6 +1461,19 @@ static int nQPlan = 0;              /* Next free slow in _query_plan[] */
 #endif /* SQLITE_TEST */
 
 
+/*
+** Free a WhereInfo structure
+*/
+static void whereInfoFree(WhereInfo *pWInfo){
+  if( pWInfo ){
+    int i;
+    for(i=0; i<pWInfo->nLevel; i++){
+      sqliteFree(pWInfo->a[i].pIdxInfo);
+    }
+    sqliteFree(pWInfo);
+  }
+}
+
 
 /*
 ** Generate the beginning of the loop used for WHERE clause processing.
@@ -1527,9 +1674,22 @@ WhereInfo *sqlite3WhereBegin(
         if( j==iFrom ) iFrom++;
         continue;
       }
-      cost = bestIndex(pParse, &wc, pTabItem, notReady,
-                       (i==0 && ppOrderBy) ? *ppOrderBy : 0,
-                       &pIdx, &flags, &nEq);
+      assert( pTabItem->pTab );
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+      if( pTabItem->pTab->isVirtual ){
+        cost = bestVirtualIndex(pParse, &wc, pTabItem, notReady,
+                                ppOrderBy ? *ppOrderBy : 0, i==0,
+                                &pLevel->pIdxInfo);
+        flags = WHERE_VIRTUALTABLE;
+        pIdx = 0;
+        nEq = 0;
+      }else 
+#endif
+      {
+        cost = bestIndex(pParse, &wc, pTabItem, notReady,
+                         (i==0 && ppOrderBy) ? *ppOrderBy : 0,
+                         &pIdx, &flags, &nEq);
+      }
       if( cost<lowestCost ){
         once = 1;
         lowestCost = cost;
@@ -1592,6 +1752,12 @@ WhereInfo *sqlite3WhereBegin(
       }else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
         zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg);
       }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+      else if( pLevel->pIdxInfo ){
+        zMsg = sqlite3MPrintf("%z VIRTUAL TABLE INDEX %d",
+                    pLevel->pIdxInfo->idxNum);
+      }
+#endif
       if( pLevel->flags & WHERE_ORDERBY ){
         zMsg = sqlite3MPrintf("%z ORDER BY", zMsg);
       }
@@ -1602,6 +1768,11 @@ WhereInfo *sqlite3WhereBegin(
     pTab = pTabItem->pTab;
     iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
     if( pTab->isEphem || pTab->pSelect ) continue;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+    if( pLevel->pIdxInfo ){
+      sqlite3VdbeAddOp(v, OP_VOpen, 0, 0);  /***** Fix Me *****/
+    }else
+#endif
     if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
       sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, OP_OpenRead);
       if( pTab->nCol<(sizeof(Bitmask)*8) ){
@@ -1669,6 +1840,34 @@ WhereInfo *sqlite3WhereBegin(
       VdbeComment((v, "# init LEFT JOIN no-match flag"));
     }
 
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+    if( pLevel->pIdxInfo ){
+      /* Case 0:  That table is a virtual-table.  Use the VFilter and VNext.
+      */
+      sqlite3_index_info *pIdxInfo = pLevel->pIdxInfo;
+      for(i=1; i<=pIdxInfo->nConstraint; i++){
+        int j;
+        for(j=0; j<pIdxInfo->nConstraint; j++){
+          if( pIdxInfo->aConstraintUsage[j].argvIndex==i ){
+            sqlite3ExprCode(pParse, wc.a[j].pExpr->pRight);
+            break;
+          }
+        }
+        if( j==pIdxInfo->nConstraint ) break;
+      }
+      sqlite3VdbeAddOp(v, OP_VFilter, iCur, pIdxInfo->idxNum);
+      if( i>1 ){
+        sqlite3VdbeAddOp(v, OP_Pop, i-1, 0);
+      }
+      for(i=0; i<pIdxInfo->nConstraint; i++){
+        if( pIdxInfo->aConstraintUsage[i].omit ){
+          disableTerm(pLevel, &wc.a[i]);
+        }
+      }
+      pLevel->op = OP_VNext;
+    }else
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
     if( pLevel->flags & WHERE_ROWID_EQ ){
       /* Case 1:  We can directly reference a single row using an
       **          equality comparison against the ROWID field.  Or
@@ -2032,7 +2231,7 @@ WhereInfo *sqlite3WhereBegin(
   /* Jump here if malloc fails */
 whereBeginNoMem:
   whereClauseClear(&wc);
-  sqliteFree(pWInfo);
+  whereInfoFree(pWInfo);
   return 0;
 }
 
@@ -2134,6 +2333,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
 
   /* Final cleanup
   */
-  sqliteFree(pWInfo);
+  whereInfoFree(pWInfo);
   return;
 }