-C Fix\sa\sproblem\swith\sthe\ssavepoint\scode\sand\sin-memory\sjournals.\s(CVS\s6061)
-D 2008-12-23T19:15:57
+C Continuing\simprovements\sto\sthe\smulti-index\sOR-clause\soptimizer.\s\sAdded\sa\nfew\ssimple\stest\scases.\s(CVS\s6062)
+D 2008-12-23T23:56:22
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 77635d0909c2067cee03889a1e04ce910d8fb809
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F src/callback.c bee8949d619b1b7b1e4dfac8a19c5116ae1dd12a
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
F src/date.c e010095d85c895761627bb1d0d61d021aea930a9
-F src/delete.c e2392b6808496fc0a7f54662af3ba677a3e8e44a
+F src/delete.c 6249005bdd8f85db6ec5f31ddb5c07de023693cc
F src/expr.c a385202af56d622b11d05e8d386def256155152b
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
F src/func.c b0e1c61301f33d67b72ab15d85c80ed76e7c98ac
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
F src/resolve.c 18dc9f0df1d60048e012ce6632251063e0dd356a
F src/rowset.c 2256fa4a928f750e2f3d6fc733523034beceb1d6
-F src/select.c a4316c5e8a417687e159b3d3ae689363d1dec5df
+F src/select.c 6c2a5675c21bef11d8160f3dc97e1adfbf26bbb9
F src/shell.c 65d19f8996a160f288087e31810f24025439c62a
F src/sqlite.h.in 065a828e299960316aa34f05b9f0f10f33afe4c8
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
-F src/sqliteInt.h 9411acda2959c3494bafb1ac98048a53ee920ea3
+F src/sqliteInt.h 2362e805d375c547f6d91d4732da8f93e1e668af
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c 23db1e5f27c03160987c122a078b4bb51ef0b2f8
F src/test_wsd.c c297d7d6b8a990239e1bd25935e81d612d8ae31d
F src/tokenize.c aaa5fa6a4536a9dd7c855a3f66f32508f1612138
F src/trigger.c 5a669d8fc9197db393ff85fa95ec882282162bb5
-F src/update.c 080889d241e4dcd1c545c8051eb6de86f4939295
+F src/update.c 8c4925f9ca664effc8a1faaad67449d2074567b1
F src/utf.c 1da9c832dba0fa8f865b5b902d93f420a1ee4245
F src/util.c ea62608f66f33a7e8322de83024ae37c415c0c7f
F src/vacuum.c 383d6297bddc011ab04a9eed110db6eaf523e8e9
F src/vdbemem.c f9c859ac17e2e05a0f249868ce4f191f69edd31d
F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d
-F src/where.c 3f4e8020d605b06139b877a9714a10cc3ba63906
+F src/where.c ef69833cdf0e19a91ec1b305b506d100ac3f648f
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 42c4373595f4409d9c6a9987b4a60000ad664faf
+F test/where7.test b04da5cee08a573c120c95781d7413a7e25ac8d5
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/zeroblob.test 792124852ec61458a2eb527b5091791215e0be95
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P d2105f617eeb04c8177546c45bf6c63e72757f91
-R 62a2a7b3ecef75a74f7c0626bd24ccb4
-U danielk1977
-Z 52a2a6db5bd35226b01afc59433c7e60
+P 26ceebf38e7ae7bbda3284995b03f829a2d2493f
+R 7db5298c8cbec76d68072c3747b105ad
+U drh
+Z 555ee7a0ef7229cf7451a3a18c0b778e
-26ceebf38e7ae7bbda3284995b03f829a2d2493f
\ No newline at end of file
+55d4f493e7df8515574a75caec9967d6c71b6012
\ No newline at end of file
** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements.
**
-** $Id: delete.c,v 1.190 2008/12/10 21:19:57 drh Exp $
+** $Id: delete.c,v 1.191 2008/12/23 23:56:22 drh Exp $
*/
#include "sqliteInt.h"
int iRowid = ++pParse->nMem; /* Used for storing rowid values. */
int iRowSet = ++pParse->nMem; /* Register for rowset of rows to delete */
- /* Begin the database scan
+ /* Collect rowids of every row to be deleted.
*/
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
+ WHERE_FILL_ROWSET, iRowSet);
if( pWInfo==0 ) goto delete_from_cleanup;
-
- /* Remember the rowid of every item to be deleted.
- */
- sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, iRowid);
- sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iRowid);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
}
-
- /* End the database scan loop.
- */
sqlite3WhereEnd(pWInfo);
/* Open the pseudo-table used to store OLD if there are triggers.
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
-** $Id: select.c,v 1.494 2008/12/10 22:15:00 drh Exp $
+** $Id: select.c,v 1.495 2008/12/23 23:56:22 drh Exp $
*/
#include "sqliteInt.h"
/* This case is for non-aggregate queries
** Begin the database scan
*/
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0, 0);
if( pWInfo==0 ) goto select_end;
/* If sorting index that was created by a prior OP_OpenEphemeral
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0);
if( pWInfo==0 ) goto select_end;
if( pGroupBy==0 ){
/* The optimizer is able to deliver rows in group by order so
** of output.
*/
resetAccumulator(pParse, &sAggInfo);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag, 0);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel);
goto select_end;
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.814 2008/12/23 13:35:23 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.815 2008/12/23 23:56:22 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
/*
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin().
*/
-#define WHERE_ORDERBY_NORMAL 0 /* No-op */
-#define WHERE_ORDERBY_MIN 1 /* ORDER BY processing for min() func */
-#define WHERE_ORDERBY_MAX 2 /* ORDER BY processing for max() func */
-#define WHERE_ONEPASS_DESIRED 4 /* Want to do one-pass UPDATE/DELETE */
+#define WHERE_ORDERBY_NORMAL 0x000 /* No-op */
+#define WHERE_ORDERBY_MIN 0x001 /* ORDER BY processing for min() func */
+#define WHERE_ORDERBY_MAX 0x002 /* ORDER BY processing for max() func */
+#define WHERE_ONEPASS_DESIRED 0x004 /* Want to do one-pass UPDATE/DELETE */
+#define WHERE_FILL_ROWSET 0x008 /* Save results in a RowSet object */
/*
** The WHERE clause processing routine has two halves. The
struct WhereInfo {
Parse *pParse; /* Parsing and code generating context */
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
+ int regRowSet; /* Store rowids in this rowset if >=0 */
SrcList *pTabList; /* List of tables in the join */
int iTop; /* The very beginning of the WHERE loop */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
int nLevel; /* Number of nested loop */
struct WhereClause *pWC; /* Decomposition of the WHERE clause */
- sqlite3_index_info **apInfo; /* Array of pointers to index info objects */
WhereLevel a[1]; /* Information about each nest loop in WHERE */
};
#endif
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
-WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
+WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8, int);
void sqlite3WhereEnd(WhereInfo*);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int);
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.190 2008/12/10 22:15:00 drh Exp $
+** $Id: update.c,v 1.191 2008/12/23 23:56:22 drh Exp $
*/
#include "sqliteInt.h"
*/
sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
- WHERE_ONEPASS_DESIRED);
+ WHERE_ONEPASS_DESIRED, 0);
if( pWInfo==0 ) goto update_cleanup;
okOnePass = pWInfo->okOnePass;
** 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.342 2008/12/23 16:23:05 drh Exp $
+** $Id: where.c,v 1.343 2008/12/23 23:56:22 drh Exp $
*/
#include "sqliteInt.h"
}
}
-#if SQLITE_ENABLE_MULTI_OR
+#ifndef SQLITE_OMIT_OR_OPTIMIZATION
/* Search for an OR-clause that can be used to look up the table.
*/
maskSrc = getMask(pWC->pMaskSet, iCur);
}
}
}
-#endif
+#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
/* If the pSrc table is the right table of a LEFT JOIN then we may not
** use an index to satisfy IS NULL constraints on that table. This is
return regBase;
}
+/*
+** Return TRUE if the WhereClause pWC contains no terms that
+** are not virtual and which have not been coded.
+**
+** To put it another way, return TRUE if no additional WHERE clauses
+** tests are required in order to establish that the current row
+** should go to output and return FALSE if there are some terms of
+** the WHERE clause that need to be validated before outputing the row.
+*/
+static int whereRowReadyForOutput(WhereClause *pWC){
+ WhereTerm *pTerm;
+ int j;
+
+ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
+ if( (pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED))==0 ) return 0;
+ }
+ return 1;
+}
+
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
Parse *pParse; /* Parsing context */
Vdbe *v; /* The prepared stmt under constructions */
struct SrcList_item *pTabItem; /* FROM clause term being coded */
- int addrBrk;
- int addrCont;
+ int addrBrk; /* Jump here to break out of the loop */
+ int addrCont; /* Jump here to continue with next cycle */
+ int regRowSet; /* Write rowids to this RowSet if non-negative */
+ int codeRowSetEarly; /* True if index fully constrains the search */
pParse = pWInfo->pParse;
iCur = pTabItem->iCursor;
bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0;
+ regRowSet = pWInfo->regRowSet;
+ codeRowSetEarly = 0;
/* Create labels for the "break" and "continue" instructions
** for the current loop. Jump to addrBrk to break out of a loop.
sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr,
pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC);
- sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
pVtabIdx->needToFreeIdxStr = 0;
for(j=0; j<nConstraint; j++){
if( aUsage[j].omit ){
pLevel->op = OP_VNext;
pLevel->p1 = iCur;
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
+ codeRowSetEarly = regRowSet>=0 ? whereRowReadyForOutput(pWC) : 0;
+ if( codeRowSetEarly ){
+ sqlite3VdbeAddOp2(v, OP_VRowid, iCur, iReg);
+ sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, iReg);
+ }
+ sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
}else
#endif /* SQLITE_OMIT_VIRTUALTABLE */
addrNxt = pLevel->addrNxt;
sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, addrNxt);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, r1);
+ codeRowSetEarly = (pWC->nTerm==1 && regRowSet>=0) ?1:0;
+ if( codeRowSetEarly ){
+ sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, r1);
+ }
sqlite3ReleaseTempReg(pParse, rtmp);
VdbeComment((v, "pk"));
pLevel->op = OP_Noop;
pLevel->op = bRev ? OP_Prev : OP_Next;
pLevel->p1 = iCur;
pLevel->p2 = start;
- if( testOp!=OP_Noop ){
+ codeRowSetEarly = regRowSet>=0 ? whereRowReadyForOutput(pWC) : 0;
+ if( codeRowSetEarly || testOp!=OP_Noop ){
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
- sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, r1);
- sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
+ if( testOp!=OP_Noop ){
+ sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, r1);
+ sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
+ }
+ if( codeRowSetEarly ){
+ sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, r1);
+ }
sqlite3ReleaseTempReg(pParse, r1);
}
}else if( pLevel->plan.wsFlags & (WHERE_COLUMN_RANGE|WHERE_COLUMN_EQ) ){
}
/* Seek the table cursor, if required */
- if( !omitTable ){
+ disableTerm(pLevel, pRangeStart);
+ disableTerm(pLevel, pRangeEnd);
+ codeRowSetEarly = regRowSet>=0 ? whereRowReadyForOutput(pWC) : 0;
+ if( !omitTable || codeRowSetEarly ){
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1);
- sqlite3VdbeAddOp2(v, OP_Seek, iCur, r1); /* Deferred seek */
+ if( codeRowSetEarly ){
+ sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, r1);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Seek, iCur, r1); /* Deferred seek */
+ }
}
sqlite3ReleaseTempReg(pParse, r1);
*/
pLevel->op = bRev ? OP_Prev : OP_Next;
pLevel->p1 = iIdxCur;
- disableTerm(pLevel, pRangeStart);
- disableTerm(pLevel, pRangeEnd);
}else
-#if SQLITE_ENABLE_MULTI_OR
+#ifndef SQLITE_OMIT_OR_OPTIMIZATION
if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
/* Case 4: Two or more separately indexed terms connected by OR
**
** Goto 0, A
** B:
*/
- int regRowset; /* Register holding the RowSet object */
+ int regOrRowset; /* Register holding the RowSet object */
int regNextRowid; /* Register holding next rowid */
WhereTerm *pTerm; /* The complete OR-clause */
WhereClause *pOrWc; /* The OR-clause broken out into subterms */
assert( pTerm->eOperator==WO_OR );
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
pOrWc = &pTerm->u.pOrInfo->wc;
-
- regRowset = sqlite3GetTempReg(pParse);
- regNextRowid = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
+ codeRowSetEarly = (regRowSet>=0 && pWC->nTerm==1) ?1:0;
+
+ if( codeRowSetEarly ){
+ regOrRowset = regRowSet;
+ }else{
+ regOrRowset = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regOrRowset);
+ }
oneTab.nSrc = 1;
oneTab.nAlloc = 1;
oneTab.a[0] = *pTabItem;
for(j=0, pOrTerm=pOrWc->a; j<pOrWc->nTerm; j++, pOrTerm++){
WhereInfo *pSubWInfo;
if( pOrTerm->leftCursor!=iCur ) continue;
- pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0, 0);
+ pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0,
+ WHERE_FILL_ROWSET, regOrRowset);
if( pSubWInfo ){
- sqlite3VdbeAddOp2(v, OP_Rowid, oneTab.a[0].iCursor, regNextRowid);
- sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowset, regNextRowid);
pSubWInfo->a[0].plan.wsFlags |= WHERE_IDX_ONLY;
sqlite3WhereEnd(pSubWInfo);
}
}
sqlite3VdbeResolveLabel(v, addrCont);
- addrCont =
- sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowset, addrBrk, regNextRowid);
- sqlite3VdbeAddOp2(v, OP_Seek, iCur, regNextRowid);
- sqlite3ReleaseTempReg(pParse, regNextRowid);
- pLevel->op = OP_Goto;
- pLevel->p2 = addrCont;
+ if( !codeRowSetEarly ){
+ regNextRowid = sqlite3GetTempReg(pParse);
+ addrCont =
+ sqlite3VdbeAddOp3(v, OP_RowSetRead, regOrRowset,addrBrk,regNextRowid);
+ sqlite3VdbeAddOp2(v, OP_Seek, iCur, regNextRowid);
+ sqlite3ReleaseTempReg(pParse, regNextRowid);
+ /* sqlite3ReleaseTempReg(pParse, regOrRowset); // Preserve the RowSet */
+ pLevel->op = OP_Goto;
+ pLevel->p2 = addrCont;
+ }
+ disableTerm(pLevel, pTerm);
}else
-#endif /* SQLITE_ENABLE_MULTI_OR */
+#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
{
/* Case 5: There is no usable index. We must do a complete
pLevel->p1 = iCur;
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addrBrk);
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
+ codeRowSetEarly = 0;
}
notReady &= ~getMask(pWC->pMaskSet, iCur);
pTerm->wtFlags |= TERM_CODED;
}
}
+
+ /*
+ ** If it was requested to store the results in a rowset and that has
+ ** not already been do, then do so now.
+ */
+ if( regRowSet>=0 && !codeRowSetEarly ){
+ int r1 = sqlite3GetTempReg(pParse);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
+ sqlite3VdbeAddOp2(v, OP_VRowid, iCur, r1);
+ }else
+#endif
+ {
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
+ }
+ sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
+ }
+
return notReady;
}
SrcList *pTabList, /* A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
- u8 wctrlFlags /* One of the WHERE_* flags defined in sqliteInt.h */
+ u8 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
+ int regRowSet /* Register hold RowSet if WHERE_FILL_ROWSET is set */
){
int i; /* Loop counter */
WhereInfo *pWInfo; /* Will become the return value of this function */
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
+ pWInfo->regRowSet = (wctrlFlags & WHERE_FILL_ROWSET) ? regRowSet : -1;
pWInfo->pWC = pWC = (WhereClause*)&pWInfo->a[pWInfo->nLevel];
pMaskSet = (WhereMaskSet*)&pWC[1];
--- /dev/null
+# 2008 December 23
+#
+# 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 multi-index OR clause optimizer.
+#
+# $Id: where7.test,v 1.1 2008/12/23 23:56:22 drh Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+ifcapable !or_opt {
+ finish_test
+ return
+}
+
+# Evaluate SQL. Return the result set followed by the
+# and the number of full-scan steps.
+#
+proc count_steps {sql} {
+ set r [db eval $sql]
+ lappend r scan [db status step]
+}
+
+# Build some test data
+#
+do_test where7-1.1 {
+ execsql {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d);
+ INSERT INTO t1 VALUES(1,2,3,4);
+ INSERT INTO t1 VALUES(2,3,4,5);
+ INSERT INTO t1 VALUES(3,4,6,8);
+ INSERT INTO t1 VALUES(4,5,10,15);
+ INSERT INTO t1 VALUES(5,10,100,1000);
+ CREATE INDEX t1b ON t1(b);
+ CREATE INDEX t1c ON t1(c);
+ SELECT * FROM t1;
+ }
+} {1 2 3 4 2 3 4 5 3 4 6 8 4 5 10 15 5 10 100 1000}
+do_test where7-1.2 {
+ count_steps {
+ SELECT a FROM t1 WHERE b=3 OR c=6
+ }
+} {2 3 scan 0}
+do_test where7-1.3 {
+ count_steps {
+ SELECT a FROM t1 WHERE b=3 OR +c=6
+ }
+} {2 3 scan 4}
+do_test where7-1.4 {
+ count_steps {
+ SELECT a FROM t1 WHERE +b=3 OR c=6
+ }
+} {2 3 scan 4}
+do_test where7-1.5 {
+ count_steps {
+ SELECT a FROM t1 WHERE 3=b OR c=6
+ }
+} {2 3 scan 0}
+do_test where7-1.6 {
+ count_steps {
+ SELECT a FROM t1 WHERE (3=b OR c=6) AND +a>0
+ }
+} {2 3 scan 0}
+do_test where7-1.7 {
+ count_steps {
+ SELECT a FROM t1 WHERE (b=3 OR c>10)
+ }
+} {2 5 scan 0}
+do_test where7-1.8 {
+ count_steps {
+ SELECT a FROM t1 WHERE (b=3 OR c>=10)
+ }
+} {2 4 5 scan 0}
+do_test where7-1.9 {
+ count_steps {
+ SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4)
+ }
+} {2 4 5 scan 0}
+do_test where7-1.10 {
+ count_steps {
+ SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4 OR b>10)
+ }
+} {2 4 5 scan 0}
+
+
+finish_test