From: drh Date: Mon, 12 Jun 2006 21:59:13 +0000 (+0000) Subject: Added code to iterate through virtual tables. All regression tests pass X-Git-Tag: version-3.6.10~2948 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9eff61675098356bbd31a73451266e10af0914ec;p=thirdparty%2Fsqlite.git Added code to iterate through virtual tables. All regression tests pass but the new code is completely untested. (CVS 3219) FossilOrigin-Name: 010965433140fbe508a907d861dbad79343bf7c2 --- diff --git a/manifest b/manifest index dbea297004..08d7532f24 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 0affeedfe5..afae5c32b4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f0c7c8d12c04376e48c6d53a29cfae3fa13b52cf \ No newline at end of file +010965433140fbe508a907d861dbad79343bf7c2 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index ecd8450bc0..f07b4603c4 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.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. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 739bffc2fd..f78bfb8d60 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 */ }; /* diff --git a/src/vdbe.c b/src/vdbe.c index da3c433354..a98b703f64 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.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: { diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 01d6a61f19..e4ab44cd89 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -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. diff --git a/src/vdbeaux.c b/src/vdbeaux.c index f5710b121a..cab259f05f 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -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); diff --git a/src/where.c b/src/where.c index 515ed4421f..ac80620879 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.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; inTerm; 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; inExpr; 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; inTerm; 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; ia[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; inConstraint; 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; inLevel; 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( costflags & (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; jnConstraint; 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; inConstraint; 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; }