diff options
author | drh <drh@noemail.net> | 2006-06-13 23:51:34 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2006-06-13 23:51:34 +0000 |
commit | 4be8b51ee19b19ee837cec8e79a4faec90994af7 (patch) | |
tree | 84222b4b34038c828690782f3575b20f28b90903 | |
parent | 88897a72e98ede8c4a90e0dede1ad3cf476ec470 (diff) | |
download | sqlite-4be8b51ee19b19ee837cec8e79a4faec90994af7.tar.gz sqlite-4be8b51ee19b19ee837cec8e79a4faec90994af7.zip |
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
-rw-r--r-- | Makefile.in | 1 | ||||
-rw-r--r-- | main.mk | 1 | ||||
-rw-r--r-- | manifest | 35 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/sqlite.h.in | 22 | ||||
-rw-r--r-- | src/tclsqlite.c | 4 | ||||
-rw-r--r-- | src/test8.c | 119 | ||||
-rw-r--r-- | src/test_tclvar.c | 193 | ||||
-rw-r--r-- | src/vdbe.c | 27 | ||||
-rw-r--r-- | src/vdbe.h | 3 | ||||
-rw-r--r-- | src/vdbeapi.c | 2 | ||||
-rw-r--r-- | src/vdbeaux.c | 11 | ||||
-rw-r--r-- | src/vtab.c | 12 | ||||
-rw-r--r-- | src/where.c | 53 | ||||
-rw-r--r-- | test/vtab1.test | 31 |
15 files changed, 357 insertions, 159 deletions
diff --git a/Makefile.in b/Makefile.in index 26ada6818..706246e06 100644 --- a/Makefile.in +++ b/Makefile.in @@ -211,6 +211,7 @@ TESTSRC = \ $(TOP)/src/test_async.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_server.c \ + $(TOP)/src/test_tclvar.c \ $(TOP)/src/utf.c \ $(TOP)/src/util.c \ $(TOP)/src/vdbe.c \ @@ -144,6 +144,7 @@ TESTSRC = \ $(TOP)/src/test_async.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_server.c \ + $(TOP)/src/test_tclvar.c \ $(TOP)/src/utf.c \ $(TOP)/src/util.c \ $(TOP)/src/vdbe.c \ @@ -1,6 +1,6 @@ -C The\s(unsupported)\ssoundex()\sfunction\sreturns\s'?000'\swhen\sgiven\sa\sNULL.\nTicket\s#1845.\s(CVS\s3233) -D 2006-06-13T19:26:11 -F Makefile.in 56fd6261e83f60724e6dcd764e06ab68cbd53909 +C The\secho\smodule\stest\sis\snow\srunning.\s\sAdded\sthe\stclvar\smodule\stest\sbut\shave\nnot\syet\sdone\sanything\swith\sit.\s(CVS\s3234) +D 2006-06-13T23:51:34 +F Makefile.in 200f6dc376ecfd9b01e5359c4e0c10c02f649b34 F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F VERSION 301ed2b2c08f5cca242ea56e50a9ed0264a3eb76 @@ -19,7 +19,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826 -F main.mk a7796b31f0d7e16ea57ff00ac88b97befe519977 +F main.mk 2f02a26044baa6126127e7231b1cea172355d721 F mkdll.sh 919df5efde876194e3102c6ebc60657d38949909 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5 @@ -72,11 +72,11 @@ F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261 F src/select.c 38eda11d950ed5e631ea9054f84a4a8b9e9b39d8 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c ad73192b30a338a58fe81183d4a5d5a1d4e51d36 -F src/sqlite.h.in 92cbeeacf040bffe109057d3af2db9dc63db8a67 +F src/sqlite.h.in 84522f48a0a044987267a82d680121194d31fb7a F src/sqlite3ext.h 127bd394c8eea481f2ac9b754bf399dbfc818b75 F src/sqliteInt.h e8710fd5c10c03ca4a2fb49802b8aae6689f27a0 F src/table.c f64ec4fbfe333f8df925bc6ba494f55e05b0e75e -F src/tclsqlite.c 0b2a04cfc1b4298adfbe90a754cfbbe207aca11a +F src/tclsqlite.c 4ad22f354b6e4e137889000e9f585a0590ca39c5 F src/test1.c 88291fa6674dcd409b1c9d76d3119151d4b81a50 F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b F src/test3.c 86e99724ee898b119ed575ef9f98618afe7e5e5d @@ -84,25 +84,26 @@ F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de F src/test7.c 03fa8d787f6aebc6d1f72504d52f33013ad2c8e3 -F src/test8.c 34b04bd826b3f7fa843c5b60052928412591c5c7 +F src/test8.c d21b301afbc35a5c4ded0ecc784d59bc8f795c75 F src/test_async.c e3deaedd4d86a56391b81808fde9e44fbd92f1d3 F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3 F src/test_server.c a6460daed0b92ecbc2531b6dc73717470e7a648c +F src/test_tclvar.c 3157e17194caa73434041d310b66ec93803aa1be F src/tokenize.c 6ebcafa6622839968dda4418a7b6945f277a128f F src/trigger.c 48bbb94c11954c8e132efcc04478efe8304c4196 F src/update.c 0186f09414a6578156d40666becc964f85c2a616 F src/utf.c ab81ac59084ff1c07d421eb1a0a84ec809603b44 F src/util.c ca6ee72772c0f5dc04d2e0ab1973fd3b6a9bf79d F src/vacuum.c 5b37d0f436f8e1ffacd17934e44720b38d2247f9 -F src/vdbe.c 1d5ae83b7122146c0193f52750e37aacd633bccc -F src/vdbe.h f72e5c00af759b7ed6fd606d508036d732098cc3 +F src/vdbe.c 51f94a1f1647a85f4e5eb6418624f8d1ef67622a +F src/vdbe.h 258b5d1c0aaa72192f09ff0568ce42b383f156fa F src/vdbeInt.h 6ccb7eaae76ebd761470f6a035501ff33aa92c20 -F src/vdbeapi.c 7dc662e7c905ce666bb506dced932e0307115cbf -F src/vdbeaux.c 0168d770d03f9815511780a49cd8360d9a5f1ec5 +F src/vdbeapi.c af663689ef57e5506f190bbd1068d28936b0fb34 +F src/vdbeaux.c c9474fd27f1735170feb4f6a46885d282cf22d52 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5 F src/vdbemem.c 5f0afe3b92bb2c037f8d5d697f7c151fa50783a3 -F src/vtab.c 12d83f7de893d06592d6d37c285defefebbd2d48 -F src/where.c 7e614b0278c688aec94c79d42f602b24e9e4119f +F src/vtab.c 7de1347022248edfb260c54f259148f413320cb7 +F src/where.c 299c385e32a7b98d42864c7c83cdc6a778fae562 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/all.test 5df90d015ca63fcef2a4b62c24f7316b66c4bfd4 @@ -287,7 +288,7 @@ F test/vacuum.test 37f998b841cb335397c26d9bbc3457182af2565f F test/vacuum2.test 5aea8c88a65cb29f7d175296e7c819c6158d838c F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/view.test 16e2774fe35e47a07ac4471b7f0bcc948b1aa6d5 -F test/vtab1.test c94c8bdadfdd9c474146874562925830ab0413c5 +F test/vtab1.test 86e4c90c96cbf7f2c3b31069ed8c2d5dfd3bf378 F test/where.test ee7c9a6659b07e1ee61177f6e7ff71565ee2c9df F test/where2.test a16476a5913e75cf65b38f2daa6157a6b7791394 F test/where3.test 3b5ad2c58069e12be2bd86bc5e211a82810521aa @@ -363,7 +364,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 136bed496b89943522310ec511199b78198d0844 -R 4d340ce3b4963ceb6566edfe12edcd3d +P 9372481f233e1563b5ee137535f0fbf19851ffad +R e6ce8e5a9dba6e782016ada2d5443cc3 U drh -Z 16c6d69d2baed957168638e44a48c1df +Z 6f9bc9c4a49544af7a028d3a571bcd52 diff --git a/manifest.uuid b/manifest.uuid index 4a18b8861..f77be546a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9372481f233e1563b5ee137535f0fbf19851ffad
\ No newline at end of file +29199eeea4c46168ccaa7535d4941bd740479dee
\ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index f21438038..9d59515b9 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 unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); 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 @@ struct sqlite3_module { 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 @@ struct sqlite3_module { ** 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 @@ struct sqlite3_index_info { 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 @@ struct sqlite3_vtab_cursor { 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 07783c1e4..9c3890b99 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 @@ int TCLSH_MAIN(int argc, char **argv){ 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 @@ int TCLSH_MAIN(int argc, char **argv){ 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 5f005e03c..24067b95a 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 @@ struct echo_vtab { 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 @@ static int echoConstructor( 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 @@ static int echoDestructor(sqlite3_vtab *pVtab){ sqliteFree(p->aCol[ii]); } sqliteFree(p->aCol); + sqliteFree(p->zTableName); sqliteFree(p); return 0; } @@ -310,28 +313,7 @@ static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ 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 echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ 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 echoFilter( */ 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 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ 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); - - 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); + appendToEchoModule(pVtab->interp, zQuery); + 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 000000000..00937c276 --- /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 22967d41f..30b52aff5 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 @@ case OP_VOpen: { ** 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 @@ case OP_VFilter: { /* 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 713d0f18b..46f6fe045 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 @@ typedef struct VdbeOpList VdbeOpList; #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 94f18aa60..60c8585b1 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -454,11 +454,9 @@ const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){ 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 fa3450c15..bc9468e57 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -263,8 +263,13 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){ } }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 @@ static void freeP3(int p3type, void *p3){ 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 f717831ff..30bff3267 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 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ 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 2bfb21cbf..d137d740f 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 @@ static double bestVirtualIndex( 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 @@ static void whereInfoFree(WhereInfo *pWInfo){ 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 @@ WhereInfo *sqlite3WhereBegin( } #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 @@ WhereInfo *sqlite3WhereBegin( /* 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]); diff --git a/test/vtab1.test b/test/vtab1.test index 2c29418eb..a48435ac2 100644 --- a/test/vtab1.test +++ b/test/vtab1.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is creating and dropping virtual tables. # -# $Id: vtab1.test,v 1.10 2006/06/13 15:00:55 danielk1977 Exp $ +# $Id: vtab1.test,v 1.11 2006/06/13 23:51:35 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -144,7 +144,7 @@ do_test vtab1-2.9 { do_test vtab1-3.1 { set echo_module "" execsql { - CREATE TABLE treal(a INTEGER, b VARCHAR(32), c); + CREATE TABLE treal(a INTEGER, b INTEGER, c); CREATE INDEX treal_idx ON treal(b); CREATE VIRTUAL TABLE t1 USING echo(treal); } @@ -181,29 +181,36 @@ do_test vtab1-3.6 { execsql { SELECT * FROM t1; } - set echo_module -} {xBestIndex {} {} xFilter {}} +} {1 2 3 4 5 6} do_test vtab1-3.7 { + set echo_module +} {xBestIndex {SELECT rowid, * FROM 'treal'} xFilter {SELECT rowid, * FROM 'treal'}} +do_test vtab1-3.8 { set echo_module "" execsql { - SELECT * FROM t1 WHERE b = 10; + SELECT * FROM t1 WHERE b = 5; } +} {4 5 6} +do_test vtab1-3.9 { set echo_module -} {xBestIndex {WHERE b = ?} {} xFilter {WHERE b = ?} 10} -do_test vtab1-3.8 { +} {xBestIndex {SELECT rowid, * FROM 'treal' WHERE b = ?} xFilter {SELECT rowid, * FROM 'treal' WHERE b = ?} 5} +do_test vtab1-3.10 { set echo_module "" execsql { SELECT * FROM t1 WHERE b >= 5 AND b <= 10; } +} {4 5 6} +do_test vtab1-3.11 { set echo_module -} {xBestIndex {WHERE b >= ? AND b <= ?} {} xFilter {WHERE b >= ? AND b <= ?} 5 10} -do_test vtab1-3.9 { +} {xBestIndex {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} xFilter {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} 5 10} +do_test vtab1-3.12 { set echo_module "" execsql { - SELECT * FROM t1 WHERE b BETWEEN 5 AND 10; + SELECT * FROM t1 WHERE b BETWEEN 2 AND 10; } +} {1 2 3 4 5 6} +do_test vtab1-3.13 { set echo_module -} {xBestIndex {WHERE b >= ? AND b <= ?} {} xFilter {WHERE b >= ? AND b <= ?} 5 10} +} {xBestIndex {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} xFilter {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} 2 10} finish_test - |