-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
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
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
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
-f0c7c8d12c04376e48c6d53a29cfae3fa13b52cf
\ No newline at end of file
+010965433140fbe508a907d861dbad79343bf7c2
\ No newline at end of file
** 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_
/*
****** 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;
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.
*************************************************************************
** 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_
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 */
};
/*
** 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"
}
#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: {
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.
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);
** 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"
#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.
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
#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.
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;
}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);
}
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) ){
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
/* Jump here if malloc fails */
whereBeginNoMem:
whereClauseClear(&wc);
- sqliteFree(pWInfo);
+ whereInfoFree(pWInfo);
return 0;
}
/* Final cleanup
*/
- sqliteFree(pWInfo);
+ whereInfoFree(pWInfo);
return;
}