- C Enhance\stest_bestindex.c\sso\sthat\sit\scan\sbe\sused\sto\stest\splans\sgenerated\sby\sxBestIndex.
- D 2016-03-02T16:01:41.146
-C Version\s3.11.1
-D 2016-03-03T16:17:53.102
++C Merge\s3.11.1\schanges\sinto\strunk.
++D 2016-03-03T17:54:30.421
F Makefile.in 4e90dc1521879022aa9479268a4cd141d1771142
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
-F Makefile.msc 56ea123a975690bf9ed38b31bb89ff87b02a7c2b
+F Makefile.msc 4f319afb7c049d40aff7af6e8c4e7cc2ba18e079
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
-F VERSION 1a9f17ac8a5066544976a390298fe62228c58a9e
+F VERSION c6b1f51809551d60ad001e6d87cf3ab2c7f54b6f
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
F ext/fts5/fts5_vocab.c dba72ca393d71c2588548b51380387f6b44c77a8
-F ext/fts5/fts5parse.y 59432ea369f1aa65511bad465f55d31a22f9f223
+F ext/fts5/fts5parse.y 86fe6ba094a47e02fe8be2571539e6833d197764
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
- F ext/fts5/test/fts5_common.tcl 61ff0d1a29d98a91c4553b20b3f410d858834ee9
+ F ext/fts5/test/fts5_common.tcl b9b1fed811c0390511cef8b254826ea15d380f4d
F ext/fts5/test/fts5aa.test 7e814df4a0e6c22a6fe2d84f210fdc0b5068a084
F ext/fts5/test/fts5ab.test 30325a89453280160106be411bba3acf138e6d1b
F ext/fts5/test/fts5ac.test 55cad4275a1f5acabfe14d8442a8046b47e49e5f
F ext/fts5/test/fts5full.test 6f6143af0c6700501d9fd597189dfab1555bb741
F ext/fts5/test/fts5hash.test 06f9309ccb4d5050a131594e9e47d0b21456837d
F ext/fts5/test/fts5integrity.test f5e4f8d284385875068ad0f3e894ce43e9de835d
-F ext/fts5/test/fts5matchinfo.test 86569026d20f1ed748236587ce798de8a96615f1
+F ext/fts5/test/fts5matchinfo.test f7dde99697bcb310ea8faa8eb2714d9f4dfc0e1b
F ext/fts5/test/fts5merge.test 8f3cdba2ec9c5e7e568246e81b700ad37f764367
- F ext/fts5/test/fts5merge2.test c0cb66eb38a41c26cc5848fb9e50093e0f59ac93
+ F ext/fts5/test/fts5merge2.test a6da3c16d694235938d1939f503cfa53f0943d75
F ext/fts5/test/fts5near.test b214cddb1c1f1bddf45c75af768f20145f7e71cc
F ext/fts5/test/fts5onepass.test 7ed9608e258132cb8d55e7c479b08676ad68810c
F ext/fts5/test/fts5optimize.test 42741e7c085ee0a1276140a752d4407d97c2c9f5
F ext/fts5/test/fts5rebuild.test 03935f617ace91ed23a6099c7c74d905227ff29b
F ext/fts5/test/fts5restart.test c17728fdea26e7d0f617d22ad5b4b2862b994c17
F ext/fts5/test/fts5rowid.test 16908a99d6efc9ba21081b4f2b86b3fc699839a6
- F ext/fts5/test/fts5simple.test 92e06be1c119f88a73ea11a05599a276ec3ff7fd
-F ext/fts5/test/fts5simple.test 09420cb1137f3a19d02dacb5b4b6831d2e683773
++F ext/fts5/test/fts5simple.test ac5006cc3d0d08b3538e1e76c7300de9f24fbed1
F ext/fts5/test/fts5simple2.test 98377ae1ff7749a42c21fe1a139c1ed312522c46
F ext/fts5/test/fts5simple3.test 8e71733b3d1b0e695011d02c68ebc5ca40b6124e
F ext/fts5/test/fts5synonym.test 6475d189c2e20d60795808f83e36bf9318708d48
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
-F ext/misc/series.c b8fb7befd85b3a9b4a10e701b30b2b79ca92b6d4
+F ext/misc/series.c e1ef8bc23328d4e2196835737f62b324bdcd1c0d
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
- F ext/misc/spellfix.c 525190484b7a9dbc6be646c4842274fff4f27d53
+ F ext/misc/spellfix.c 194b5fc3a9a63cb6c5680d8f713800012bddca7c
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
F src/test_backup.c 2e6e6a081870150f20c526a2e9d0d29cda47d803
- F src/test_bestindex.c a711473c79e812e4082fbf045ed6c18c99c16058
-F src/test_blob.c e5a7a81d61a780da79101aeb1e60d300af169e07
++F src/test_bestindex.c cd36324f05404df5f1a82608a321b91932a549ea
+F src/test_blob.c b2551a9b5573232db5f66f292307c37067937239
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
-F src/test_config.c 7985332c806d1cece793475c75a6abcccde9d331
+F src/test_config.c 0dee90328e3dedf8ba002ee94b6a7e7ea7726fe4
F src/test_demovfs.c 0de72c2c89551629f58486fde5734b7d90758852
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
-F src/test_fs.c a61f54247fdb843761d709879c3bcd1989b2050c
+F src/test_fs.c f10f840ca4f8c72e4837908bd8347ac4bcab074b
F src/test_func.c 37453d346cfcf118774efd5bf6187f7e6a7e3254
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32
F test/rbu.test 168573d353cd0fd10196b87b0caa322c144ef736
F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
+F test/regexp2.test aa7ffcc21350007a78361b82bcf3b74d12227144
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
- F test/releasetest.tcl 975449bf742b8bb9025208292208af816a1fcb58
+ F test/releasetest.tcl a246ecb14ed594bf44bf77bd21df873971d779bf
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
F test/rollback2.test 8435d6ff0f13f51d2a4181c232e706005fa90fc5
F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c
F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
-F tool/warnings.sh ef6ebc6fd8d2dc35db3b622015c16a023d4fef4f
+F tool/warnings.sh a98af506df552f3b3c0d904f94e4cdc4e1a6d598
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P b1258814f6100f594210775e9e3007b5b0c65025
-R da5680e10572eb2ee67e7f4f853b931e
-T +bgcolor * #d0c0ff
-T +sym-release *
-T +sym-version-3.11.1 *
+F vsixtest/App.xaml b76d3b48860e7454775c47ea38ffea9c4abe3e85
+F vsixtest/App.xaml.cpp c465147f50871165c60ca16955219f6c5812d6d8
+F vsixtest/App.xaml.h 4a9768e2983d05600ad1e1c2f1b00a132967da9f
+F vsixtest/Assets/LockScreenLogo.scale-200.png e820c9a3deb909197081b0bf3216c06e13905f0a
+F vsixtest/Assets/SplashScreen.scale-200.png cab70988ca71bebec7bfeb3b6dbafe17b9ab0b4a
+F vsixtest/Assets/Square150x150Logo.scale-200.png e17b40817db7a239fc239d83efcc951fb824e3ff
+F vsixtest/Assets/Square44x44Logo.scale-200.png 2f166237094dea94d952d10b9eeae81806844f1c
+F vsixtest/Assets/Square44x44Logo.targetsize-24_altform-unplated.png 5f6a6d391b95a3061ccca6e6fdd6955ede63b4ed
+F vsixtest/Assets/StoreLogo.png 0828b7257db74a4ecd5eeb6b7b4971f0fdc4d9d1
+F vsixtest/Assets/Wide310x150Logo.scale-200.png 04ddefe5bc5f43ae12a7433f6f236ddab101ac42
+F vsixtest/MainPage.xaml 34f49897e3ca533a7e74506ba0759b66eebce151
+F vsixtest/MainPage.xaml.cpp 7f31fc6de751b64676c0924c97a5485d950a91d7
+F vsixtest/MainPage.xaml.h cc05cca10d50a003f6c6e4448b701cdd07f52f29
+F vsixtest/Package.appxmanifest 6b6db1eb7df3a315c5d681059754d5f0e0c47a93
+F vsixtest/pch.cpp cb823cfac36f1a39a7eb0acbd7e9a0b0de8f23af
+F vsixtest/pch.h 9cab7980f2ac4baa40807d8b5e52af32a21cf78c
+F vsixtest/vsixtest.sln 77cadbe4e96c1fe1bf51cd77de9e9b0a12ada547
+F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
+F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
+F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
+F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P 3d9daa929c0abe6dc01e800ef343b0eef2f0c76a
- R 10e42f20a022f81e947260641e83d066
- U dan
- Z 32cbbe1a7e810bc34e8a7796bb6fedf4
++P 3c15a9bf45cd7dae2fbd99123b8dd75ce278d6e4 f047920ce16971e573bc6ec9a48b118c9de2b3a7
++R 7bed5868510318c8bb3057f2d53886a9
+ U drh
-Z ad71638129773a9e26cf148e72895b35
++Z 5d4c029f83980452f09894533c95c4c4
--- /dev/null
- tcl_vtab *pTab = (tcl_vtab*)(pVtabCursor->pVtab);
+/*
+** 2016-03-01
+**
+** 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 xBestIndex method and the query
+** planner.
+*/
+
+
+/*
+** INSTRUCTIONS
+**
+** This module exports a single tcl command - [register_tcl_module]. When
+** invoked, it registers a special virtual table module with a database
+** connection.
+**
+** The virtual table is currently read-only. And always returns zero rows.
+** It is created with a single argument - the name of a Tcl command - as
+** follows:
+**
+** CREATE VIRTUAL TABLE x1 USING tcl(tcl_command);
+**
+** The command [tcl_command] is invoked when the table is first created (or
+** connected), when the xBestIndex() method is invoked and when the xFilter()
+** method is called. When it is created (or connected), it is invoked as
+** follows:
+**
+** tcl_command xConnect
+**
+** In this case the return value of the script is passed to the
+** sqlite3_declare_vtab() function to create the virtual table schema.
+**
+** When the xBestIndex() method is called by SQLite, the Tcl command is
+** invoked as:
+**
+** tcl_command xBestIndex CONSTRAINTS ORDERBY MASK
+**
+** where CONSTRAINTS is a tcl representation of the aConstraints[] array,
+** ORDERBY is a representation of the contents of the aOrderBy[] array and
+** MASK is a copy of sqlite3_index_info.colUsed. For example if the virtual
+** table is declared as:
+**
+** CREATE TABLE x1(a, b, c)
+**
+** and the query is:
+**
+** SELECT * FROM x1 WHERE a=? AND c<? ORDER BY b, c;
+**
+** then the Tcl command is:
+**
+** tcl_command xBestIndex \
+** {{op eq column 0 usable 1} {op lt column 2 usable 1}} \
+** {{column 1 desc 0} {column 2 desc 0}} \
+** 7
+**
+** The return value of the script is a list of key-value pairs used to
+** populate the output fields of the sqlite3_index_info structure. Possible
+** keys and the usage of the accompanying values are:
+**
+** "orderby" (value of orderByConsumed flag)
+** "cost" (value of estimatedCost field)
+** "rows" (value of estimatedRows field)
+** "use" (index of used constraint in aConstraint[])
+** "omit" (like "use", but also sets omit flag)
+** "idxnum" (value of idxNum field)
+** "idxstr" (value of idxStr field)
+**
+** Refer to code below for further details.
+**
+** When SQLite calls the xFilter() method, this module invokes the following
+** Tcl script:
+**
+** tcl_command xFilter IDXNUM IDXSTR ARGLIST
+**
+** IDXNUM and IDXSTR are the values of the idxNum and idxStr parameters
+** passed to xFilter. ARGLIST is a Tcl list containing each of the arguments
+** passed to xFilter in text form.
+**
+** As with xBestIndex(), the return value of the script is interpreted as a
+** list of key-value pairs. There is currently only one key defined - "sql".
+** The value must be the full text of an SQL statement that returns the data
+** for the current scan. The leftmost column returned by the SELECT is assumed
+** to contain the rowid. Other columns must follow, in order from left to
+** right.
+*/
+
+
+#include "sqliteInt.h"
+#include "tcl.h"
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+typedef struct tcl_vtab tcl_vtab;
+typedef struct tcl_cursor tcl_cursor;
+
+/*
+** A fs virtual-table object
+*/
+struct tcl_vtab {
+ sqlite3_vtab base;
+ Tcl_Interp *interp;
+ Tcl_Obj *pCmd;
+ sqlite3 *db;
+};
+
+/* A tcl cursor object */
+struct tcl_cursor {
+ sqlite3_vtab_cursor base;
+ sqlite3_stmt *pStmt; /* Read data from here */
+};
+
+/*
+** This function is the implementation of both the xConnect and xCreate
+** methods of the fs virtual table.
+**
+** The argv[] array contains the following:
+**
+** argv[0] -> module name ("fs")
+** argv[1] -> database name
+** argv[2] -> table name
+** argv[...] -> other module argument fields.
+*/
+static int tclConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ Tcl_Interp *interp = (Tcl_Interp*)pAux;
+ tcl_vtab *pTab;
+ const char *zCmd;
+ Tcl_Obj *pScript = 0;
+ int rc;
+
+ if( argc!=4 ){
+ *pzErr = sqlite3_mprintf("wrong number of arguments");
+ return SQLITE_ERROR;
+ }
+ zCmd = argv[3];
+
+ pTab = (tcl_vtab*)sqlite3_malloc(sizeof(tcl_vtab));
+ if( pTab==0 ) return SQLITE_NOMEM;
+ memset(pTab, 0, sizeof(tcl_vtab));
+
+ pTab->pCmd = Tcl_NewStringObj(zCmd, -1);
+ pTab->interp = interp;
+ pTab->db = db;
+ Tcl_IncrRefCount(pTab->pCmd);
+
+ pScript = Tcl_DuplicateObj(pTab->pCmd);
+ Tcl_IncrRefCount(pScript);
+ Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xConnect", -1));
+
+ rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
+ if( rc!=TCL_OK ){
+ *pzErr = sqlite3_mprintf("%s", Tcl_GetStringResult(interp));
+ rc = SQLITE_ERROR;
+ }else{
+ rc = sqlite3_declare_vtab(db, Tcl_GetStringResult(interp));
+ }
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pTab);
+ pTab = 0;
+ }
+
+ *ppVtab = &pTab->base;
+ return rc;
+}
+
+/* The xDisconnect and xDestroy methods are also the same */
+static int tclDisconnect(sqlite3_vtab *pVtab){
+ tcl_vtab *pTab = (tcl_vtab*)pVtab;
+ Tcl_DecrRefCount(pTab->pCmd);
+ sqlite3_free(pTab);
+ return SQLITE_OK;
+}
+
+/*
+** Open a new tcl cursor.
+*/
+static int tclOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ tcl_cursor *pCur;
+ pCur = sqlite3_malloc(sizeof(tcl_cursor));
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(tcl_cursor));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Close a tcl cursor.
+*/
+static int tclClose(sqlite3_vtab_cursor *cur){
+ tcl_cursor *pCur = (tcl_cursor *)cur;
+ if( pCur ){
+ sqlite3_finalize(pCur->pStmt);
+ sqlite3_free(pCur);
+ }
+ return SQLITE_OK;
+}
+
+static int tclNext(sqlite3_vtab_cursor *pVtabCursor){
+ tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
- int iArgv = 1;
+ if( pCsr->pStmt ){
+ tcl_vtab *pTab = (tcl_vtab*)(pVtabCursor->pVtab);
+ int rc = sqlite3_step(pCsr->pStmt);
+ if( rc!=SQLITE_ROW ){
+ const char *zErr;
+ rc = sqlite3_finalize(pCsr->pStmt);
+ pCsr->pStmt = 0;
+ if( rc!=SQLITE_OK ){
+ zErr = sqlite3_errmsg(pTab->db);
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+static int tclFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
+ tcl_vtab *pTab = (tcl_vtab*)(pVtabCursor->pVtab);
+ Tcl_Interp *interp = pTab->interp;
+ Tcl_Obj *pScript;
+ Tcl_Obj *pArg;
+ int ii;
+ int rc;
+
+ pScript = Tcl_DuplicateObj(pTab->pCmd);
+ Tcl_IncrRefCount(pScript);
+ Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xFilter", -1));
+ Tcl_ListObjAppendElement(interp, pScript, Tcl_NewIntObj(idxNum));
+ if( idxStr ){
+ Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(idxStr, -1));
+ }else{
+ Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("", -1));
+ }
+
+ pArg = Tcl_NewObj();
+ Tcl_IncrRefCount(pArg);
+ for(ii=0; ii<argc; ii++){
+ const char *zVal = (const char*)sqlite3_value_text(argv[ii]);
+ Tcl_Obj *pVal;
+ if( zVal==0 ){
+ pVal = Tcl_NewObj();
+ }else{
+ pVal = Tcl_NewStringObj(zVal, -1);
+ }
+ Tcl_ListObjAppendElement(interp, pArg, pVal);
+ }
+ Tcl_ListObjAppendElement(interp, pScript, pArg);
+ Tcl_DecrRefCount(pArg);
+
+ rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
+ if( rc!=TCL_OK ){
+ const char *zErr = Tcl_GetStringResult(interp);
+ rc = SQLITE_ERROR;
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
+ }else{
+ /* Analyze the scripts return value. The return value should be a tcl
+ ** list object with an even number of elements. The first element of each
+ ** pair must be one of:
+ **
+ ** "sql" (SQL statement to return data)
+ */
+ Tcl_Obj *pRes = Tcl_GetObjResult(interp);
+ Tcl_Obj **apElem = 0;
+ int nElem;
+ rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
+ if( rc!=TCL_OK ){
+ const char *zErr = Tcl_GetStringResult(interp);
+ rc = SQLITE_ERROR;
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
+ }else{
+ for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){
+ const char *zCmd = Tcl_GetString(apElem[ii]);
+ Tcl_Obj *p = apElem[ii+1];
+ if( sqlite3_stricmp("sql", zCmd)==0 ){
+ const char *zSql = Tcl_GetString(p);
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
+ if( rc!=SQLITE_OK ){
+ const char *zErr = sqlite3_errmsg(pTab->db);
+ pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zErr);
+ }
+ }else{
+ rc = SQLITE_ERROR;
+ pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zCmd);
+ }
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = tclNext(pVtabCursor);
+ }
+ return rc;
+}
+
+static int tclColumn(
+ sqlite3_vtab_cursor *pVtabCursor,
+ sqlite3_context *ctx,
+ int i
+){
+ tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
+ sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, i+1));
+ return SQLITE_OK;
+}
+
+static int tclRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
+ tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
+ *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
+ return SQLITE_OK;
+}
+
+static int tclEof(sqlite3_vtab_cursor *pVtabCursor){
+ tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
+ return (pCsr->pStmt==0);
+}
+
+static int tclBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ tcl_vtab *pTab = (tcl_vtab*)tab;
+ Tcl_Interp *interp = pTab->interp;
+ Tcl_Obj *pArg;
+ Tcl_Obj *pScript;
+ int ii;
+ int rc = SQLITE_OK;
+
+ pScript = Tcl_DuplicateObj(pTab->pCmd);
+ Tcl_IncrRefCount(pScript);
+ Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xBestIndex", -1));
+
+ pArg = Tcl_NewObj();
+ Tcl_IncrRefCount(pArg);
+ for(ii=0; ii<pIdxInfo->nConstraint; ii++){
+ struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii];
+ Tcl_Obj *pElem = Tcl_NewObj();
+ const char *zOp = "?";
+
+ Tcl_IncrRefCount(pElem);
+
+ switch( pCons->op ){
+ case SQLITE_INDEX_CONSTRAINT_EQ:
+ zOp = "eq"; break;
+ case SQLITE_INDEX_CONSTRAINT_GT:
+ zOp = "gt"; break;
+ case SQLITE_INDEX_CONSTRAINT_LE:
+ zOp = "le"; break;
+ case SQLITE_INDEX_CONSTRAINT_LT:
+ zOp = "lt"; break;
+ case SQLITE_INDEX_CONSTRAINT_GE:
+ zOp = "ge"; break;
+ case SQLITE_INDEX_CONSTRAINT_MATCH:
+ zOp = "match"; break;
+ case SQLITE_INDEX_CONSTRAINT_LIKE:
+ zOp = "like"; break;
+ case SQLITE_INDEX_CONSTRAINT_GLOB:
+ zOp = "glob"; break;
+ case SQLITE_INDEX_CONSTRAINT_REGEXP:
+ zOp = "regexp"; break;
+ }
+
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1));
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zOp, -1));
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1));
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->iColumn));
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("usable", -1));
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->usable));
+
+ Tcl_ListObjAppendElement(0, pArg, pElem);
+ Tcl_DecrRefCount(pElem);
+ }
+
+ Tcl_ListObjAppendElement(0, pScript, pArg);
+ Tcl_DecrRefCount(pArg);
+
+ pArg = Tcl_NewObj();
+ Tcl_IncrRefCount(pArg);
+ for(ii=0; ii<pIdxInfo->nOrderBy; ii++){
+ struct sqlite3_index_orderby const *pOrder = &pIdxInfo->aOrderBy[ii];
+ Tcl_Obj *pElem = Tcl_NewObj();
+ Tcl_IncrRefCount(pElem);
+
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1));
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pOrder->iColumn));
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("desc", -1));
+ Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pOrder->desc));
+
+ Tcl_ListObjAppendElement(0, pArg, pElem);
+ Tcl_DecrRefCount(pElem);
+ }
+
+ Tcl_ListObjAppendElement(0, pScript, pArg);
+ Tcl_DecrRefCount(pArg);
+
+ Tcl_ListObjAppendElement(0, pScript, Tcl_NewWideIntObj(pIdxInfo->colUsed));
+
+ rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
+ Tcl_DecrRefCount(pScript);
+ if( rc!=TCL_OK ){
+ const char *zErr = Tcl_GetStringResult(interp);
+ rc = SQLITE_ERROR;
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
+ }else{
+ /* Analyze the scripts return value. The return value should be a tcl
+ ** list object with an even number of elements. The first element of each
+ ** pair must be one of:
+ **
+ ** "orderby" (value of orderByConsumed flag)
+ ** "cost" (value of estimatedCost field)
+ ** "rows" (value of estimatedRows field)
+ ** "use" (index of used constraint in aConstraint[])
+ ** "idxnum" (value of idxNum field)
+ ** "idxstr" (value of idxStr field)
+ ** "omit" (index of omitted constraint in aConstraint[])
+ */
+ Tcl_Obj *pRes = Tcl_GetObjResult(interp);
+ Tcl_Obj **apElem = 0;
+ int nElem;
+ rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
+ if( rc!=TCL_OK ){
+ const char *zErr = Tcl_GetStringResult(interp);
+ rc = SQLITE_ERROR;
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
+ }else{
+ int iArgv = 1;
+ for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){
+ const char *zCmd = Tcl_GetString(apElem[ii]);
+ Tcl_Obj *p = apElem[ii+1];
+ if( sqlite3_stricmp("cost", zCmd)==0 ){
+ rc = Tcl_GetDoubleFromObj(interp, p, &pIdxInfo->estimatedCost);
+ }else
+ if( sqlite3_stricmp("orderby", zCmd)==0 ){
+ rc = Tcl_GetIntFromObj(interp, p, &pIdxInfo->orderByConsumed);
+ }else
+ if( sqlite3_stricmp("idxnum", zCmd)==0 ){
+ rc = Tcl_GetIntFromObj(interp, p, &pIdxInfo->idxNum);
+ }else
+ if( sqlite3_stricmp("idxstr", zCmd)==0 ){
+ sqlite3_free(pIdxInfo->idxStr);
+ pIdxInfo->idxStr = sqlite3_mprintf("%s", Tcl_GetString(p));
+ pIdxInfo->needToFreeIdxStr = 1;
+ }else
+ if( sqlite3_stricmp("rows", zCmd)==0 ){
+ rc = Tcl_GetWideIntFromObj(interp, p, &pIdxInfo->estimatedRows);
+ }else
+ if( sqlite3_stricmp("use", zCmd)==0
+ || sqlite3_stricmp("omit", zCmd)==0
+ ){
+ int iCons;
+ rc = Tcl_GetIntFromObj(interp, p, &iCons);
+ if( rc==SQLITE_OK ){
+ if( iCons<0 || iCons>=pIdxInfo->nConstraint ){
+ rc = SQLITE_ERROR;
+ pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %d", iCons);
+ }else{
+ int bOmit = (zCmd[0]=='o' || zCmd[0]=='O');
+ pIdxInfo->aConstraintUsage[iCons].argvIndex = iArgv++;
+ pIdxInfo->aConstraintUsage[iCons].omit = bOmit;
+ }
+ }
+ }else{
+ rc = SQLITE_ERROR;
+ pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zCmd);
+ }
+ if( rc!=SQLITE_OK && pTab->base.zErrMsg==0 ){
+ const char *zErr = Tcl_GetStringResult(interp);
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+** A virtual table module that provides read-only access to a
+** Tcl global variable namespace.
+*/
+static sqlite3_module tclModule = {
+ 0, /* iVersion */
+ tclConnect,
+ tclConnect,
+ tclBestIndex,
+ tclDisconnect,
+ tclDisconnect,
+ tclOpen, /* xOpen - open a cursor */
+ tclClose, /* xClose - close a cursor */
+ tclFilter, /* xFilter - configure scan constraints */
+ tclNext, /* xNext - advance a cursor */
+ tclEof, /* xEof - check for end of scan */
+ tclColumn, /* xColumn - read data */
+ tclRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+};
+
+/*
+** Decode a pointer to an sqlite3 object.
+*/
+extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
+
+/*
+** Register the echo virtual table module.
+*/
+static int register_tcl_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;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ sqlite3_create_module(db, "tcl", &tclModule, (void *)interp);
+#endif
+ return TCL_OK;
+}
+
+#endif
+
+
+/*
+** Register commands with the TCL interpreter.
+*/
+int Sqlitetesttcl_Init(Tcl_Interp *interp){
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ static struct {
+ char *zName;
+ Tcl_ObjCmdProc *xProc;
+ void *clientData;
+ } aObjCmd[] = {
+ { "register_tcl_module", register_tcl_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);
+ }
+#endif
+ return TCL_OK;
+}