Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -5612,10 +5612,21 @@ ** ^The aConstraint[] array only reports WHERE clause terms that are ** relevant 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 colUsed field indicates which columns of the virtual table may be +** required by the current scan. Virtual table columns are numbered from +** zero in the order in which they appear within the CREATE TABLE statement +** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62), +** the corresponding bit is set within the colUsed mask if the column may be +** required by SQLite. If the table has at least 64 columns and any column +** to the right of the first 63 is required, then bit 63 of colUsed is also +** set. In other words, column iCol may be required if the expression +** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to +** non-zero. ** ** The [xBestIndex] method must fill aConstraintUsage[] with information ** about what parameters to pass to xFilter. ^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 @@ -5692,10 +5703,12 @@ double estimatedCost; /* Estimated cost of using this index */ /* Fields below are only available in SQLite 3.8.2 and later */ sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ /* Fields below are only available in SQLite 3.9.0 and later */ int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */ + /* Fields below are only available in SQLite 3.10.0 and later */ + sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */ }; /* ** CAPI3REF: Virtual Table Scan Flags */ Index: src/test8.c ================================================================== --- src/test8.c +++ src/test8.c @@ -742,10 +742,38 @@ *pzStr = zIn; if( doFree ){ sqlite3_free(zAppend); } } + +/* +** This function returns a pointer to an sqlite3_malloc()ed buffer +** containing the select-list (the thing between keywords SELECT and FROM) +** to query the underlying real table with for the scan described by +** argument pIdxInfo. +** +** If the current SQLite version is earlier than 3.10.0, this is just "*" +** (select all columns). Or, for version 3.10.0 and greater, the list of +** columns identified by the pIdxInfo->colUsed mask. +*/ +static char *echoSelectList(echo_vtab *pTab, sqlite3_index_info *pIdxInfo){ + char *zRet = 0; + if( sqlite3_libversion_number()<3010000 ){ + zRet = sqlite3_mprintf(", *"); + }else{ + int i; + for(i=0; inCol; i++){ + if( pIdxInfo->colUsed & ((sqlite3_uint64)1 << (i>=63 ? 63 : i)) ){ + zRet = sqlite3_mprintf("%z, %s", zRet, pTab->aCol[i]); + }else{ + zRet = sqlite3_mprintf("%z, NULL", zRet); + } + if( !zRet ) break; + } + } + return zRet; +} /* ** The echo module implements the subset of query constraints and sort ** orders that may take advantage of SQLite indices on the underlying ** real table. For example, if the real table is declared as: @@ -768,10 +796,11 @@ ** by the contents of the structure pointed to by the pIdxInfo argument. */ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int ii; char *zQuery = 0; + char *zCol = 0; char *zNew; int nArg = 0; const char *zSep = "WHERE"; echo_vtab *pVtab = (echo_vtab *)tab; sqlite3_stmt *pStmt = 0; @@ -815,14 +844,15 @@ if( rc!=SQLITE_OK ){ return rc; } } - zQuery = sqlite3_mprintf("SELECT rowid, * FROM %Q", pVtab->zTableName); - if( !zQuery ){ - return SQLITE_NOMEM; - } + zCol = echoSelectList(pVtab, pIdxInfo); + if( !zCol ) return SQLITE_NOMEM; + zQuery = sqlite3_mprintf("SELECT rowid%z FROM %Q", zCol, pVtab->zTableName); + if( !zQuery ) return SQLITE_NOMEM; + for(ii=0; iinConstraint; ii++){ const struct sqlite3_index_constraint *pConstraint; struct sqlite3_index_constraint_usage *pUsage; int iCol; Index: src/update.c ================================================================== --- src/update.c +++ src/update.c @@ -261,14 +261,16 @@ assert( (chngRowid & chngPk)==0 ); assert( chngRowid==0 || chngRowid==1 ); assert( chngPk==0 || chngPk==1 ); chngKey = chngRowid + chngPk; - /* The SET expressions are not actually used inside the WHERE loop. - ** So reset the colUsed mask + /* The SET expressions are not actually used inside the WHERE loop. + ** So reset the colUsed mask. Unless this is a virtual table. In that + ** case, set all bits of the colUsed mask (to ensure that the virtual + ** table implementation makes all columns available). */ - pTabList->a[0].colUsed = 0; + pTabList->a[0].colUsed = IsVirtual(pTab) ? (Bitmask)-1 : 0; hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey); /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold Index: src/where.c ================================================================== --- src/where.c +++ src/where.c @@ -2862,10 +2862,11 @@ pIdxInfo->needToFreeIdxStr = 0; pIdxInfo->orderByConsumed = 0; pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; pIdxInfo->estimatedRows = 25; pIdxInfo->idxFlags = 0; + pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; rc = vtabBestIndex(pParse, pTab, pIdxInfo); if( rc ) goto whereLoopAddVtab_exit; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pNew->prereq = mExtra; mxTerm = -1; Index: test/tkt3871.test ================================================================== --- test/tkt3871.test +++ test/tkt3871.test @@ -30,12 +30,12 @@ do_test tkt3871-1.3 { set echo_module "" execsql { SELECT * FROM e WHERE a = 1 OR a = 2 } set echo_module } [list \ - xFilter {SELECT rowid, * FROM 't1' WHERE a = ?} 1 \ - xFilter {SELECT rowid, * FROM 't1' WHERE a = ?} 2 \ + xFilter {SELECT rowid, a, b FROM 't1' WHERE a = ?} 1 \ + xFilter {SELECT rowid, a, b FROM 't1' WHERE a = ?} 2 \ ] do_test tkt3871-1.4 { execsql { SELECT * FROM e WHERE a = 1 OR a = 2 OR b = 9 } } {1 1 2 4 3 9} @@ -42,12 +42,12 @@ do_test tkt3871-1.5 { set echo_module "" execsql { SELECT * FROM e WHERE a = 1 OR a = 2 OR b = 9 } set echo_module } [list \ - xFilter {SELECT rowid, * FROM 't1' WHERE a = ?} 1 \ - xFilter {SELECT rowid, * FROM 't1' WHERE a = ?} 2 \ - xFilter {SELECT rowid, * FROM 't1' WHERE b = ?} 9 + xFilter {SELECT rowid, a, b FROM 't1' WHERE a = ?} 1 \ + xFilter {SELECT rowid, a, b FROM 't1' WHERE a = ?} 2 \ + xFilter {SELECT rowid, a, b FROM 't1' WHERE b = ?} 9 ] finish_test Index: test/vtab1.test ================================================================== --- test/vtab1.test +++ test/vtab1.test @@ -391,11 +391,11 @@ do_test vtab1-3.7 { execsql { SELECT rowid, * FROM t1; } } {1 1 2 3 2 4 5 6} -do_test vtab1-3.8 { +do_test vtab1-3.8.1 { execsql { SELECT a AS d, b AS e, c AS f FROM t1; } } {1 2 3 4 5 6} @@ -402,48 +402,50 @@ # Execute some SELECT statements with WHERE clauses on the t1 table. # Then check the echo_module variable (written to by the module methods # in test8.c) to make sure the xBestIndex() and xFilter() methods were # called correctly. # -do_test vtab1-3.8 { +do_test vtab1-3.8.2 { set echo_module "" execsql { SELECT * FROM t1; } set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'treal'} \ - xFilter {SELECT rowid, * FROM 'treal'} ] +} [list xBestIndex {SELECT rowid, a, b, c FROM 'treal'} \ + xFilter {SELECT rowid, a, b, c FROM 'treal'} ] do_test vtab1-3.9 { set echo_module "" execsql { SELECT * FROM t1 WHERE b = 5; } } {4 5 6} do_test vtab1-3.10 { set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'treal' WHERE b = ?} \ - xFilter {SELECT rowid, * FROM 'treal' WHERE b = ?} 5 ] +} [list xBestIndex {SELECT rowid, a, b, c FROM 'treal' WHERE b = ?} \ + xFilter {SELECT rowid, a, b, c 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 -} [list xBestIndex {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} \ - xFilter {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} 5 10 ] +} [list xBestIndex {SELECT rowid, a, b, c FROM 'treal' WHERE b >= ? AND b <= ?}\ + xFilter {SELECT rowid, a, b, c FROM 'treal' WHERE b >= ? AND b <= ?}\ + 5 10 ] do_test vtab1-3.12 { set echo_module "" execsql { SELECT * FROM t1 WHERE b BETWEEN 2 AND 10; } } {1 2 3 4 5 6} do_test vtab1-3.13 { set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} \ - xFilter {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} 2 10 ] +} [list xBestIndex {SELECT rowid, a, b, c FROM 'treal' WHERE b >= ? AND b <= ?}\ + xFilter {SELECT rowid, a, b, c FROM 'treal' WHERE b >= ? AND b <= ?}\ + 2 10 ] # Add a function for the MATCH operator. Everything always matches! #proc test_match {lhs rhs} { # lappend ::echo_module MATCH $lhs $rhs # return 1 @@ -457,12 +459,12 @@ SELECT * FROM t1 WHERE a MATCH 'string'; } } {1 {unable to use function MATCH in the requested context}} do_test vtab1-3.13 { set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'treal'} \ - xFilter {SELECT rowid, * FROM 'treal'}] +} [list xBestIndex {SELECT rowid, a, b, c FROM 'treal'} \ + xFilter {SELECT rowid, a, b, c FROM 'treal'}] ifcapable subquery { # The echo module uses a subquery internally to implement the MATCH operator. do_test vtab1-3.14 { set echo_module "" execsql { @@ -470,13 +472,13 @@ } } {} do_test vtab1-3.15 { set echo_module } [list xBestIndex \ - {SELECT rowid, * FROM 'treal' WHERE b LIKE (SELECT '%'||?||'%')} \ + {SELECT rowid, a, b, c FROM 'treal' WHERE b LIKE (SELECT '%'||?||'%')} \ xFilter \ - {SELECT rowid, * FROM 'treal' WHERE b LIKE (SELECT '%'||?||'%')} \ + {SELECT rowid, a, b, c FROM 'treal' WHERE b LIKE (SELECT '%'||?||'%')} \ string ] }; #ifcapable subquery #---------------------------------------------------------------------- # Test case vtab1-3 test table scans and the echo module's @@ -503,32 +505,32 @@ SELECT b FROM t1 ORDER BY b; } } {2 5 nosort} do_test vtab1-4.2 { set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'treal' ORDER BY b ASC} \ - xFilter {SELECT rowid, * FROM 'treal' ORDER BY b ASC} ] +} [list xBestIndex {SELECT rowid, NULL, b, NULL FROM 'treal' ORDER BY b ASC} \ + xFilter {SELECT rowid, NULL, b, NULL FROM 'treal' ORDER BY b ASC} ] do_test vtab1-4.3 { set echo_module "" cksort { SELECT b FROM t1 ORDER BY b DESC; } } {5 2 nosort} do_test vtab1-4.4 { set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'treal' ORDER BY b DESC} \ - xFilter {SELECT rowid, * FROM 'treal' ORDER BY b DESC} ] +} [list xBestIndex {SELECT rowid, NULL, b, NULL FROM 'treal' ORDER BY b DESC} \ + xFilter {SELECT rowid, NULL, b, NULL FROM 'treal' ORDER BY b DESC} ] do_test vtab1-4.3 { set echo_module "" cksort { SELECT b FROM t1 ORDER BY b||''; } } {2 5 sort} do_test vtab1-4.4 { set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'treal'} \ - xFilter {SELECT rowid, * FROM 'treal'} ] +} [list xBestIndex {SELECT rowid, NULL, b, NULL FROM 'treal'} \ + xFilter {SELECT rowid, NULL, b, NULL FROM 'treal'} ] execsql { DROP TABLE t1; DROP TABLE treal; } @@ -573,13 +575,13 @@ 2 blue black 2 hearts diamonds \ ] do_test vtab1-5-3 { filter $echo_module } [list \ - xFilter {SELECT rowid, * FROM 't1'} \ - xFilter {SELECT rowid, * FROM 't2'} \ - xFilter {SELECT rowid, * FROM 't2'} \ + xFilter {SELECT rowid, a, b, c FROM 't1'} \ + xFilter {SELECT rowid, d, e, f FROM 't2'} \ + xFilter {SELECT rowid, d, e, f FROM 't2'} \ ] do_test vtab1-5-4 { set echo_module "" execsql { SELECT * FROM et1, et2 WHERE et2.d = 2; @@ -589,13 +591,13 @@ 2 blue black 2 hearts diamonds \ ] do_test vtab1-5-5 { filter $echo_module } [list \ - xFilter {SELECT rowid, * FROM 't1'} \ - xFilter {SELECT rowid, * FROM 't2'} \ - xFilter {SELECT rowid, * FROM 't2'} \ + xFilter {SELECT rowid, a, b, c FROM 't1'} \ + xFilter {SELECT rowid, d, e, f FROM 't2'} \ + xFilter {SELECT rowid, d, e, f FROM 't2'} \ ] do_test vtab1-5-6 { execsql { CREATE INDEX i1 ON t2(d); } @@ -613,13 +615,13 @@ 2 blue black 2 hearts diamonds \ ] do_test vtab1-5-7 { filter $::echo_module } [list \ - xFilter {SELECT rowid, * FROM 't1'} \ - xFilter {SELECT rowid, * FROM 't2' WHERE d = ?} \ - xFilter {SELECT rowid, * FROM 't2' WHERE d = ?} \ + xFilter {SELECT rowid, a, b, c FROM 't1'} \ + xFilter {SELECT rowid, d, e, f FROM 't2' WHERE d = ?} \ + xFilter {SELECT rowid, d, e, f FROM 't2' WHERE d = ?} \ ] execsql { DROP TABLE t1; DROP TABLE t2; @@ -965,12 +967,12 @@ execsql { SELECT * FROM e WHERE rowid||'' MATCH 'pattern'; } set echo_module } [list \ - xBestIndex {SELECT rowid, * FROM 'r'} \ - xFilter {SELECT rowid, * FROM 'r'} \ + xBestIndex {SELECT rowid, a, b, c FROM 'r'} \ + xFilter {SELECT rowid, a, b, c FROM 'r'} \ ] proc match_func {args} {return ""} do_test vtab1.10-6 { set echo_module "" db function match match_func @@ -977,12 +979,12 @@ execsql { SELECT * FROM e WHERE match('pattern', rowid, 'pattern2'); } set echo_module } [list \ - xBestIndex {SELECT rowid, * FROM 'r'} \ - xFilter {SELECT rowid, * FROM 'r'} \ + xBestIndex {SELECT rowid, a, b, c FROM 'r'} \ + xFilter {SELECT rowid, a, b, c FROM 'r'} \ ] # Testing the xFindFunction interface # @@ -1151,17 +1153,19 @@ do_test vtab1-14.2 { set echo_module "" execsql { SELECT * FROM echo_c WHERE rowid = 1 } set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'c' WHERE rowid = ?} xFilter {SELECT rowid, * FROM 'c' WHERE rowid = ?} 1] +} [list xBestIndex {SELECT rowid, a, b, c FROM 'c' WHERE rowid = ?} \ + xFilter {SELECT rowid, a, b, c FROM 'c' WHERE rowid = ?} 1] do_test vtab1-14.3 { set echo_module "" execsql { SELECT * FROM echo_c WHERE a = 1 } set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'c' WHERE a = ?} xFilter {SELECT rowid, * FROM 'c' WHERE a = ?} 1] +} [list xBestIndex {SELECT rowid, a, b, c FROM 'c' WHERE a = ?} \ + xFilter {SELECT rowid, a, b, c FROM 'c' WHERE a = ?} 1] #do_test vtab1-14.4 { # set echo_module "" # execsql { SELECT * FROM echo_c WHERE a IN (1, 2) } # set echo_module @@ -1298,33 +1302,33 @@ CREATE VIRTUAL TABLE e6 USING echo(t6); } foreach {tn sql res filter} { 1.1 "SELECT a FROM e6 WHERE b>'James'" {4 1 5} - {xFilter {SELECT rowid, * FROM 't6' WHERE b > ?} James} + {xFilter {SELECT rowid, a, b FROM 't6' WHERE b > ?} James} 1.2 "SELECT a FROM e6 WHERE b>='J' AND b<'K'" {3 4} - {xFilter {SELECT rowid, * FROM 't6' WHERE b >= ? AND b < ?} J K} + {xFilter {SELECT rowid, a, b FROM 't6' WHERE b >= ? AND b < ?} J K} 1.3 "SELECT a FROM e6 WHERE b LIKE 'J%'" {3 4} - {xFilter {SELECT rowid, * FROM 't6' WHERE b like ?} J%} + {xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} J%} 1.4 "SELECT a FROM e6 WHERE b LIKE 'j%'" {3 4} - {xFilter {SELECT rowid, * FROM 't6' WHERE b like ?} j%} + {xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} j%} } { set echo_module {} do_execsql_test 18.$tn.1 $sql $res do_test 18.$tn.2 { lrange $::echo_module 2 end } $filter } do_execsql_test 18.2.0 { PRAGMA case_sensitive_like = ON } foreach {tn sql res filter} { 2.1 "SELECT a FROM e6 WHERE b LIKE 'J%'" {3 4} - {xFilter {SELECT rowid, * FROM 't6' WHERE b like ?} J%} + {xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} J%} 2.2 "SELECT a FROM e6 WHERE b LIKE 'j%'" {} - {xFilter {SELECT rowid, * FROM 't6' WHERE b like ?} j%} + {xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} j%} } { set echo_module {} do_execsql_test 18.$tn.1 $sql $res do_test 18.$tn.2 { lrange $::echo_module 2 end } $filter } Index: test/vtab4.test ================================================================== --- test/vtab4.test +++ test/vtab4.test @@ -55,25 +55,25 @@ set echo_module [list] execsql { UPDATE techo SET a = 2; } set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'treal'} \ +} [list xBestIndex {SELECT rowid, a, b, c FROM 'treal'} \ xBegin echo(treal) \ - xFilter {SELECT rowid, * FROM 'treal'} \ + xFilter {SELECT rowid, a, b, c FROM 'treal'} \ xSync echo(treal) \ xCommit echo(treal) \ ] do_test vtab4-1.4 { set echo_module [list] execsql { DELETE FROM techo; } set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'treal'} \ +} [list xBestIndex {SELECT rowid, NULL, NULL, NULL FROM 'treal'} \ xBegin echo(treal) \ - xFilter {SELECT rowid, * FROM 'treal'} \ + xFilter {SELECT rowid, NULL, NULL, NULL FROM 'treal'} \ xSync echo(treal) \ xCommit echo(treal) \ ] # Ensure xBegin is not called more than once in a single transaction. @@ -103,16 +103,16 @@ INSERT INTO secho SELECT * FROM techo; DELETE FROM techo; COMMIT; } set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'treal'} \ +} [list xBestIndex {SELECT rowid, a, b, c FROM 'treal'} \ xBegin echo(sreal) \ - xFilter {SELECT rowid, * FROM 'treal'} \ - xBestIndex {SELECT rowid, * FROM 'treal'} \ + xFilter {SELECT rowid, a, b, c FROM 'treal'} \ + xBestIndex {SELECT rowid, NULL, NULL, NULL FROM 'treal'} \ xBegin echo(treal) \ - xFilter {SELECT rowid, * FROM 'treal'} \ + xFilter {SELECT rowid, NULL, NULL, NULL FROM 'treal'} \ xSync echo(sreal) \ xSync echo(treal) \ xCommit echo(sreal) \ xCommit echo(treal) \ ] @@ -135,16 +135,16 @@ INSERT INTO techo SELECT * FROM secho; DELETE FROM secho; ROLLBACK; } set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'sreal'} \ +} [list xBestIndex {SELECT rowid, a, b, c FROM 'sreal'} \ xBegin echo(treal) \ - xFilter {SELECT rowid, * FROM 'sreal'} \ - xBestIndex {SELECT rowid, * FROM 'sreal'} \ + xFilter {SELECT rowid, a, b, c FROM 'sreal'} \ + xBestIndex {SELECT rowid, NULL, NULL, NULL FROM 'sreal'} \ xBegin echo(sreal) \ - xFilter {SELECT rowid, * FROM 'sreal'} \ + xFilter {SELECT rowid, NULL, NULL, NULL FROM 'sreal'} \ xRollback echo(treal) \ xRollback echo(sreal) \ ] do_test vtab4-2.6 { execsql { @@ -176,18 +176,18 @@ INSERT INTO techo SELECT * FROM secho; DELETE FROM secho; COMMIT; } set echo_module -} [list xBestIndex {SELECT rowid, * FROM 'sreal'} \ +} [list xBestIndex {SELECT rowid, a, b, c FROM 'sreal'} \ xBegin echo(treal) \ - xFilter {SELECT rowid, * FROM 'sreal'} \ - xBestIndex {SELECT rowid, * FROM 'sreal'} \ + xFilter {SELECT rowid, a, b, c FROM 'sreal'} \ + xBestIndex {SELECT rowid, NULL, NULL, NULL FROM 'sreal'} \ xBegin echo(sreal) \ - xFilter {SELECT rowid, * FROM 'sreal'} \ + xFilter {SELECT rowid, NULL, NULL, NULL FROM 'sreal'} \ xSync echo(treal) \ xSync echo(sreal) \ xRollback echo(treal) \ xRollback echo(sreal) \ ] finish_test Index: test/vtabH.test ================================================================== --- test/vtabH.test +++ test/vtabH.test @@ -30,17 +30,17 @@ CREATE VIRTUAL TABLE e6 USING echo(t6); } foreach {tn sql expect} { 1 "SELECT * FROM e6 WHERE b LIKE 'abc'" { - xBestIndex {SELECT rowid, * FROM 't6' WHERE b like ?} - xFilter {SELECT rowid, * FROM 't6' WHERE b like ?} abc + xBestIndex {SELECT rowid, a, b FROM 't6' WHERE b like ?} + xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} abc } 2 "SELECT * FROM e6 WHERE b GLOB 'abc'" { - xBestIndex {SELECT rowid, * FROM 't6' WHERE b glob ?} - xFilter {SELECT rowid, * FROM 't6' WHERE b glob ?} abc + xBestIndex {SELECT rowid, a, b FROM 't6' WHERE b glob ?} + xFilter {SELECT rowid, a, b FROM 't6' WHERE b glob ?} abc } } { do_test 1.$tn { set echo_module {} execsql $sql ADDED test/vtabI.test Index: test/vtabI.test ================================================================== --- /dev/null +++ test/vtabI.test @@ -0,0 +1,126 @@ +# 2015 Nov 26 +# +# 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. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. Specifically, +# it tests the sqlite3_index_info.colUsed variable is set correctly. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix vtabI + +ifcapable !vtab { + finish_test + return +} + +register_echo_module db + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b, c, d, e); + CREATE VIRTUAL TABLE e1 USING echo(t1); +} + +foreach {tn query filter} { + 1 {SELECT * FROM e1} + {SELECT rowid, a, b, c, d, e FROM 't1'} + + 2 {SELECT a, b FROM e1} + {SELECT rowid, a, b, NULL, NULL, NULL FROM 't1'} + + 3 {SELECT count(*) FROM e1 GROUP BY b} + {SELECT rowid, NULL, b, NULL, NULL, NULL FROM 't1'} + + 4 {SELECT count(*) FROM e1 GROUP BY b HAVING a=?} + {SELECT rowid, a, b, NULL, NULL, NULL FROM 't1'} + + 5 {SELECT a FROM e1 WHERE c=?} + {SELECT rowid, a, NULL, c, NULL, NULL FROM 't1'} + + 6 {SELECT a FROM e1 ORDER BY e} + {SELECT rowid, a, NULL, NULL, NULL, e FROM 't1'} + + 7 {SELECT a FROM e1 ORDER BY e, d} + {SELECT rowid, a, NULL, NULL, d, e FROM 't1'} +} { + do_test 1.$tn { + set ::echo_module [list] + execsql $query + set idx [lsearch -exact $::echo_module xFilter] + lindex $::echo_module [expr $idx+1] + } $filter +} + +#------------------------------------------------------------------------- +# Tests with a table with more than 64 columns. +# +proc all_col_list {} { + set L [list] + for {set i 1} {$i <= 100} {incr i} { lappend L "c$i" } + set L +} + +proc part_col_list {cols} { + set L [list] + for {set i 1} {$i <= 100} {incr i} { + set c "c$i" + if {[lsearch $cols $c]>=0} { + lappend L "c$i" + } else { + lappend L NULL + } + } + set L +} +proc CL {args} { + join [part_col_list $args] ", " +} +proc CLT {args} { + set cols $args + for {set i 64} {$i <= 100} {incr i} { + lappend cols "c$i" + } + join [part_col_list $cols] ", " +} + +do_test 2.0 { + execsql "CREATE TABLE t2([join [all_col_list] ,])" + execsql "CREATE VIRTUAL TABLE e2 USING echo(t2)" +} {} + +foreach {tn query filter} { + 1 {SELECT c1, c10, c20 FROM e2} + {SELECT rowid, [CL c1 c10 c20] FROM 't2'} + + 2 {SELECT c40, c50, c60 FROM e2} + {SELECT rowid, [CL c40 c50 c60] FROM 't2'} + + 3 {SELECT c7, c80, c90 FROM e2} + {SELECT rowid, [CLT c7] FROM 't2'} + + 4 {SELECT c64 FROM e2} + {SELECT rowid, [CLT c64] FROM 't2'} + + 5 {SELECT c63 FROM e2} + {SELECT rowid, [CL c63] FROM 't2'} + + 6 {SELECT c22 FROM e2 ORDER BY c50, c70} + {SELECT rowid, [CLT c22 c50] FROM 't2'} + +} { + do_test 2.$tn { + set ::echo_module [list] + execsql $query + set idx [lsearch -exact $::echo_module xFilter] + lindex $::echo_module [expr $idx+1] + } [subst $filter] +} + +finish_test