-C Back\sport\sthe\sunordered-index-hack\sto\sthe\s3.7.2\sbranch.
-D 2011-04-09T03:30:25.496
+C Backport\scheck-in\s[9f9f32882501ac9]\sto\sprovide\sEXPLAIN\sQUERY\sPLAN\soutput\sfor\nthe\scount(*)\soptimization.\s\sAlso\sbackport\scheck-in\s[a8761a9128de945aa]\sto\nprevent\sunordered\sindices\sfrom\sbeing\sused\son\sa\sfull\stable\sscan.\s\sThe\sfirst\nbackport\swas\snecessary\sin\sorder\sto\stest\sthe\ssecond.
+D 2011-04-15T15:18:34.932
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
-F src/select.c 7a673c43b49d5f05f76e9c5a8cafa02862cbb901
+F src/select.c a84089eb0147bdc16f487cf6f2670432eb673c2b
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
F src/sqlite.h.in 2d72a6242df41c517e38eec8791abcf5484a36f1
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
F test/types3.test a0f66bf12f80fad89493535474f7a6d16fa58150
F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
+F test/unordered.test 87ecfbb688f984d4aaf5716a343e260dd1fa2c6e
F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
F test/vacuum.test 15ae6784e70428b8db64e95c92d84b19e507b719
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 9eff470226c6f879bb1b24fb00b6786a816d8cfd
-R ec1275508098699736f727d15a36cea8
+P 803530209f9c8d4dcf8ed51b5a96aee1766ef79f
+R 725597da94f34e4749b884cb2782a777
U drh
-Z 5ab4f56fbd19b59b57d4609d1b0ffbc9
+Z 8cf57ecd3590b1d454de4a08c8b4d635
-803530209f9c8d4dcf8ed51b5a96aee1766ef79f
\ No newline at end of file
+8d924e160703e02958db9c9bc1fd2c600e01e606
\ No newline at end of file
sqlite3ExprCacheClear(pParse);
}
+/*
+** Add a single OP_Explain instruction to the VDBE to explain a simple
+** count(*) query ("SELECT count(*) FROM pTab").
+*/
+#ifndef SQLITE_OMIT_EXPLAIN
+static void explainSimpleCount(
+ Parse *pParse, /* Parse context */
+ Table *pTab, /* Table being queried */
+ Index *pIdx /* Index used to optimize scan, or NULL */
+){
+ if( pParse->explain==2 ){
+ char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s %s%s(~%d rows)",
+ pTab->zName,
+ pIdx ? "USING COVERING INDEX " : "",
+ pIdx ? pIdx->zName : "",
+ pTab->nRowEst
+ );
+ sqlite3VdbeAddOp4(
+ pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC
+ );
+ }
+}
+#else
+# define explainSimpleCount(a,b,c)
+#endif
+
/*
** Generate code for the SELECT statement given in the p argument.
**
** and pKeyInfo to the KeyInfo structure required to navigate the
** index.
**
+ ** (2011-04-15) Do not do a full scan of an unordered index.
+ **
** In practice the KeyInfo structure will not be used. It is only
** passed to keep OP_OpenRead happy.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( !pBest || pIdx->nColumn<pBest->nColumn ){
+ if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){
pBest = pIdx;
}
}
}
sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
+ explainSimpleCount(pParse, pTab, pBest);
}else
#endif /* SQLITE_OMIT_BTREECOUNT */
{
--- /dev/null
+# 2011 April 9
+#
+# 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.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+set testprefix unordered
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1(a, b);
+ CREATE INDEX i1 ON t1(a);
+ INSERT INTO t1 VALUES(1, 'xxx');
+ INSERT INTO t1 SELECT a+1, b FROM t1;
+ INSERT INTO t1 SELECT a+2, b FROM t1;
+ INSERT INTO t1 SELECT a+4, b FROM t1;
+ INSERT INTO t1 SELECT a+8, b FROM t1;
+ INSERT INTO t1 SELECT a+16, b FROM t1;
+ INSERT INTO t1 SELECT a+32, b FROM t1;
+ INSERT INTO t1 SELECT a+64, b FROM t1;
+ ANALYZE;
+} {}
+
+foreach idxmode {ordered unordered} {
+ if {$idxmode == "unordered"} {
+ execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' }
+ db close
+ sqlite3 db test.db
+ }
+ foreach {tn sql r(ordered) r(unordered)} {
+ 1 "SELECT * FROM t1 ORDER BY a"
+ {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}}
+ {0 0 0 {SCAN TABLE t1 (~128 rows)}}
+ 2 "SELECT * FROM t1 WHERE a >?"
+ {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~32 rows)}}
+ {0 0 0 {SCAN TABLE t1 (~42 rows)}}
+ 3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid"
+ {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
+ {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
+ 4 "SELECT max(a) FROM t1"
+ {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (~1 rows)}}
+ {0 0 0 {SEARCH TABLE t1 (~1 rows)}}
+ 5 "SELECT group_concat(b) FROM t1 GROUP BY a"
+ {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}}
+ {0 0 0 {SCAN TABLE t1 (~128 rows)}}
+
+ 6 "SELECT * FROM t1 WHERE a = ?"
+ {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
+ {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
+ 7 "SELECT count(*) FROM t1"
+ {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1(~128 rows)}}
+ {0 0 0 {SCAN TABLE t1 (~128 rows)}}
+ } {
+ do_eqp_test 1.$idxmode.$tn $sql $r($idxmode)
+ }
+}
+
+finish_test