-C The\snew\soptimizer\snow\spasses\sall\sregression\stests.\s(CVS\s2566)
-D 2005-07-28T16:51:51
+C Test\scases\sand\stuning\sof\sthe\snew\soptimizer\scode.\s(CVS\s2567)
+D 2005-07-28T20:51:19
F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
F src/util.c 668d31be592753e5b8ea00e69ea8d3eedb29fa22
F src/vacuum.c 829d9e1a6d7c094b80e0899686670932eafd768c
-F src/vdbe.c 0145d877d0e086d5d4bc28f52552883105373163
+F src/vdbe.c 69f33e22c7d0a64b23fbb69e6da95a1bb6869032
F src/vdbe.h 75e466d84d362b0c4498978a9d6b1e6bd32ecf3b
F src/vdbeInt.h 9be9a6c43d38124bd03cc5cf05715605b1789fd9
F src/vdbeapi.c 7f392f0792d1258c958083d7de9eae7c3530c9a6
F src/vdbeaux.c 3732a86566a6be4da4c606e9334baf3fd98667af
F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e
F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03
-F src/where.c efed9d45672ea5fc550072272d86e28a2649c256
+F src/where.c 6c3de6ee253256d58ef07acb0f07458605477cd4
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/view.test 3c79232a2ee45918c62a0cf90411525899404a76
F test/where.test b6ab0f64adc5fbb4259f284b19da6cd9aeadc711
+F test/where2.test 6427619390385bf4fc357b3907b8733012964a92
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/lemon.c c88936c67f6411608db8fa4254d254f509fa40f6
F tool/lempar.c f0c30abcae762a7d1eb37cd88b2232ab8dd625fb
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
-P ee3a08e353f563c36e904479393fcb56f96ee975
-R 0f7ba5ada7ced4acb01d1d193cdec9c1
+P a21212843359fb9fdbd60799ae50ad3566f4399a
+R b3b6fd7089d32b94d5badcc51bbe97b5
U drh
-Z 28da42b8f7133daabbc46de020ba7352
+Z 603aecf655d7fb47a89068df78f35d0c
-a21212843359fb9fdbd60799ae50ad3566f4399a
\ No newline at end of file
+4b02703dec71aa78e5f8d8cab5b950966a4c6abc
\ No newline at end of file
** 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.477 2005/07/23 03:18:40 drh Exp $
+** $Id: vdbe.c,v 1.478 2005/07/28 20:51:19 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
int rc = SQLITE_OK; /* Value to return */
sqlite3 *db = p->db; /* The database */
Mem *pTos; /* Top entry in the operand stack */
- char zBuf[100]; /* Space to sprintf() an integer */
#ifdef VDBE_PROFILE
unsigned long long start; /* CPU clock count at start of opcode */
int origPc; /* Program counter at start of opcode */
p2 = pTos->i;
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
- if( p2<2 ){
- sqlite3SetString(&p->zErrMsg, "root page number less than 2", (char*)0);
- rc = SQLITE_INTERNAL;
- break;
- }
+ assert( p2>=2 );
}
assert( i>=0 );
pCur = allocateCursor(p, i);
/* An other opcode is illegal...
*/
default: {
- sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",pOp->opcode);
- sqlite3SetString(&p->zErrMsg, "unknown opcode ", zBuf, (char*)0);
- rc = SQLITE_INTERNAL;
+ assert( 0 );
break;
}
if( pTos>=p->aStack ){
sqlite3VdbeMemSanity(pTos, db->enc);
}
- if( pc<-1 || pc>=p->nOp ){
- sqlite3SetString(&p->zErrMsg, "jump destination out of range", (char*)0);
- rc = SQLITE_INTERNAL;
- }
+ assert( pc>=-1 && pc<p->nOp );
#ifdef SQLITE_DEBUG
/* Code for tracing the vdbe stack. */
if( p->trace && pTos>=p->aStack ){
** 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.154 2005/07/28 16:51:51 drh Exp $
+** $Id: where.c,v 1.155 2005/07/28 20:51:19 drh Exp $
*/
#include "sqliteInt.h"
** terms in the where clause.
*/
#define WO_IN 1
-#define WO_LIST 2
-#define WO_SELECT 4
-#define WO_EQ 8
+#define WO_EQ 2
#define WO_LT (WO_EQ<<(TK_LT-TK_EQ))
#define WO_LE (WO_EQ<<(TK_LE-TK_EQ))
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
pTerm->leftCursor = pLeft->iTable;
pTerm->leftColumn = pLeft->iColumn;
pTerm->operator = operatorMask(pExpr->op);
- if( pTerm->operator==WO_IN ){
- if( pExpr->pSelect ){
- pTerm->operator |= WO_SELECT;
- }else if( pExpr->pList ){
- pTerm->operator |= WO_LIST;
- }
- }
}
if( pRight && pRight->op==TK_COLUMN ){
WhereTerm *pNew;
/*
** 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
-** number of equality constraints and the "cost" for this index.
+** number of equality constraints, and the "cost" for this index.
**
** The lowest cost index wins. The cost is an estimate of the amount of
** CPU and disk I/O need to process the request using the selected index.
*/
pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
if( pTerm ){
+ Expr *pExpr;
*ppIndex = 0;
bestFlags = WHERE_ROWID_EQ;
if( pTerm->operator & WO_EQ ){
if( pOrderBy ) *pFlags |= WHERE_ORDERBY;
TRACE(("... best is rowid\n"));
return 0.0;
- }else if( pTerm->operator & WO_LIST ){
+ }else if( (pExpr = pTerm->pExpr)->pList!=0 ){
/* Rowid IN (LIST): cost is NlogN where N is the number of list
** elements. */
- lowestCost = pTerm->pExpr->pList->nExpr;
+ lowestCost = pExpr->pList->nExpr;
lowestCost *= estLog(lowestCost);
}else{
/* Rowid IN (SELECT): cost is NlogN where N is the number of rows
if( pTerm==0 ) break;
flags |= WHERE_COLUMN_EQ;
if( pTerm->operator & WO_IN ){
+ Expr *pExpr = pTerm->pExpr;
flags |= WHERE_COLUMN_IN;
- if( pTerm->operator & WO_SELECT ){
+ if( pExpr->pSelect!=0 ){
inMultiplier *= 100.0;
- }else if( pTerm->operator & WO_LIST ){
- inMultiplier *= pTerm->pExpr->pList->nExpr + 1.0;
+ }else if( pExpr->pList!=0 ){
+ inMultiplier *= pExpr->pList->nExpr + 1.0;
}
}
}
int j = pProbe->aiColumn[nEq];
pTerm = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pProbe);
if( pTerm ){
- flags = WHERE_COLUMN_RANGE;
+ flags |= WHERE_COLUMN_RANGE;
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){
flags |= WHERE_TOP_LIMIT;
cost *= 0.333;
if( cost < lowestCost ){
bestIdx = pProbe;
lowestCost = cost;
- if( flags==0 ){
- flags = WHERE_COLUMN_RANGE;
- }
+ assert( flags!=0 );
bestFlags = flags;
bestNEq = nEq;
}
aIn[0] = OP_Next;
aIn[1] = iTab;
aIn[2] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
+ }else{
+ pLevel->nIn = 0;
}
#endif
}
WhereTerm *pStart, *pEnd;
assert( omitTable==0 );
- if( pLevel->flags & WHERE_BTM_LIMIT ){
- pStart = findTerm(&wc, iCur, -1, notReady, WO_GT|WO_GE, 0);
- assert( pStart!=0 );
- }else{
- pStart = 0;
- }
- if( pLevel->flags & WHERE_TOP_LIMIT ){
- pEnd = findTerm(&wc, iCur, -1, notReady, WO_LT|WO_LE, 0);
- assert( pEnd!=0 );
- }else{
- pEnd = 0;
- }
+ pStart = findTerm(&wc, iCur, -1, notReady, WO_GT|WO_GE, 0);
+ pEnd = findTerm(&wc, iCur, -1, notReady, WO_LT|WO_LE, 0);
if( bRev ){
pTerm = pStart;
pStart = pEnd;
/* Case 5: There is no usable index. We must do a complete
** scan of the entire table.
*/
- int opRewind;
-
assert( omitTable==0 );
- if( bRev ){
- opRewind = OP_Last;
- pLevel->op = OP_Prev;
- }else{
- opRewind = OP_Rewind;
- pLevel->op = OP_Next;
- }
+ assert( bRev==0 );
+ pLevel->op = OP_Next;
pLevel->p1 = iCur;
- pLevel->p2 = 1 + sqlite3VdbeAddOp(v, opRewind, iCur, brk);
+ pLevel->p2 = 1 + sqlite3VdbeAddOp(v, OP_Rewind, iCur, brk);
}
notReady &= ~getMask(&maskSet, iCur);
--- /dev/null
+# 2005 July 28
+#
+# 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. The
+# focus of this file is testing the use of indices in WHERE clauses
+# based on recent changes to the optimizer.
+#
+# $Id: where2.test,v 1.1 2005/07/28 20:51:19 drh Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# Build some test data
+#
+do_test where2-1.0 {
+ execsql {
+ BEGIN;
+ CREATE TABLE t1(w int, x int, y int, z int);
+ }
+ for {set i 1} {$i<=100} {incr i} {
+ set w $i
+ set x [expr {int(log($i)/log(2))}]
+ set y [expr {$i*$i + 2*$i + 1}]
+ set z [expr {$x+$y}]
+ execsql {INSERT INTO t1 VALUES($::w,$::x,$::y,$::z)}
+ }
+ execsql {
+ CREATE UNIQUE INDEX i1w ON t1(w);
+ CREATE INDEX i1xy ON t1(x,y);
+ CREATE INDEX i1zyx ON t1(z,y,x);
+ COMMIT;
+ }
+} {}
+
+# Do an SQL statement. Append the search count to the end of the result.
+#
+proc count sql {
+ set ::sqlite_search_count 0
+ return [concat [execsql $sql] $::sqlite_search_count]
+}
+
+# This procedure executes the SQL. Then it checks to see if the OP_Sort
+# opcode was executed. If an OP_Sort did occur, then "sort" is appended
+# to the result. If no OP_Sort happened, then "nosort" is appended.
+#
+# This procedure is used to check to make sure sorting is or is not
+# occurring as expected.
+#
+proc cksort {sql} {
+ set ::sqlite_sort_count 0
+ set data [execsql $sql]
+ if {$::sqlite_sort_count} {set x sort} {set x nosort}
+ lappend data $x
+ return $data
+}
+
+# This procedure executes the SQL. Then it appends to the result the
+# "sort" or "nosort" keyword (as in the cksort procedure above) then
+# it appends the ::sqlite_query_plan variable.
+#
+proc queryplan {sql} {
+ set ::sqlite_sort_count 0
+ set data [execsql $sql]
+ if {$::sqlite_sort_count} {set x sort} {set x nosort}
+ lappend data $x
+ return [concat $data $::sqlite_query_plan]
+}
+
+
+# Prefer a UNIQUE index over another index.
+#
+do_test where2-1.1 {
+ queryplan {
+ SELECT * FROM t1 WHERE w=85 AND x=6 AND y=7396
+ }
+} {85 6 7396 7402 nosort t1 i1w}
+
+# Always prefer a rowid== constraint over any other index.
+#
+do_test where2-1.3 {
+ queryplan {
+ SELECT * FROM t1 WHERE w=85 AND x=6 AND y=7396 AND rowid=85
+ }
+} {85 6 7396 7402 nosort t1 *}
+
+# When constrained by a UNIQUE index, the ORDER BY clause is always ignored.
+#
+do_test where2-2.1 {
+ queryplan {
+ SELECT * FROM t1 WHERE w=85 ORDER BY random(5);
+ }
+} {85 6 7396 7402 nosort t1 i1w}
+do_test where2-2.2 {
+ queryplan {
+ SELECT * FROM t1 WHERE x=6 AND y=7396 ORDER BY random(5);
+ }
+} {85 6 7396 7402 sort t1 i1xy}
+do_test where2-2.3 {
+ queryplan {
+ SELECT * FROM t1 WHERE rowid=85 AND x=6 AND y=7396 ORDER BY random(5);
+ }
+} {85 6 7396 7402 nosort t1 *}
+
+
+# Efficient handling of forward and reverse table scans.
+#
+do_test where2-3.1 {
+ queryplan {
+ SELECT * FROM t1 ORDER BY rowid LIMIT 2
+ }
+} {1 0 4 4 2 1 9 10 nosort t1 *}
+do_test where2-3.2 {
+ queryplan {
+ SELECT * FROM t1 ORDER BY rowid DESC LIMIT 2
+ }
+} {100 6 10201 10207 99 6 10000 10006 nosort t1 *}
+
+# The IN operator can be used by indices at multiple layers
+#
+do_test where2-4.1 {
+ queryplan {
+ SELECT * FROM t1 WHERE z IN (10207,10006) AND y IN (10000,10201)
+ AND x>0 AND x<10
+ ORDER BY w
+ }
+} {99 6 10000 10006 100 6 10201 10207 sort t1 i1zyx}
+do_test where2-4.2 {
+ queryplan {
+ SELECT * FROM t1 WHERE z IN (10207,10006) AND y=10000
+ AND x>0 AND x<10
+ ORDER BY w
+ }
+} {99 6 10000 10006 sort t1 i1zyx}
+do_test where2-4.3 {
+ queryplan {
+ SELECT * FROM t1 WHERE z=10006 AND y IN (10000,10201)
+ AND x>0 AND x<10
+ ORDER BY w
+ }
+} {99 6 10000 10006 sort t1 i1zyx}
+do_test where2-4.4 {
+ queryplan {
+ SELECT * FROM t1 WHERE z IN (SELECT 10207 UNION SELECT 10006)
+ AND y IN (10000,10201)
+ AND x>0 AND x<10
+ ORDER BY w
+ }
+} {99 6 10000 10006 100 6 10201 10207 sort t1 i1zyx}
+do_test where2-4.5 {
+ queryplan {
+ SELECT * FROM t1 WHERE z IN (SELECT 10207 UNION SELECT 10006)
+ AND y IN (SELECT 10000 UNION SELECT 10201)
+ AND x>0 AND x<10
+ ORDER BY w
+ }
+} {99 6 10000 10006 100 6 10201 10207 sort t1 i1zyx}
+do_test where2-4.6 {
+ queryplan {
+ SELECT * FROM t1
+ WHERE x IN (1,2,3,4,5,6,7,8)
+ AND y IN (10000,10001,10002,10003,10004,10005)
+ ORDER BY 2
+ }
+} {99 6 10000 10006 sort t1 i1xy}
+
+# Duplicate entires on the RHS of an IN operator do not cause duplicate
+# output rows.
+#
+do_test where2-4.6 {
+ queryplan {
+ SELECT * FROM t1 WHERE z IN (10207,10006,10006,10207)
+ ORDER BY w
+ }
+} {99 6 10000 10006 100 6 10201 10207 sort t1 i1zyx}
+do_test where2-4.7 {
+ queryplan {
+ SELECT * FROM t1 WHERE z IN (
+ SELECT 10207 UNION ALL SELECT 10006
+ UNION ALL SELECT 10006 UNION ALL SELECT 10207)
+ ORDER BY w
+ }
+} {99 6 10000 10006 100 6 10201 10207 sort t1 i1zyx}
+
+# The use of an IN operator disables the index as a sorter.
+#
+do_test where2-5.1 {
+ queryplan {
+ SELECT * FROM t1 WHERE w=99 ORDER BY w
+ }
+} {99 6 10000 10006 nosort t1 i1w}
+do_test where2-5.2 {
+ queryplan {
+ SELECT * FROM t1 WHERE w IN (99) ORDER BY w
+ }
+} {99 6 10000 10006 sort t1 i1w}
+
+
+integrity_check {where2-99.0}
+
+finish_test