When the same index is used for all OR-terms in a WHERE clause, then try to
use that index as a covering index. FossilOrigin-Name: 62678be3df35cdcb09172ba8c860f7b73517f1ea
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
C Merge\sthe\snested\saggregate\squery\senhancements\sinto\strunk.
|
||||
D 2012-08-24T01:07:52.214
|
||||
C When\sthe\ssame\sindex\sis\sused\sfor\sall\sOR-terms\sin\sa\sWHERE\sclause,\sthen\stry\sto\nuse\sthat\sindex\sas\sa\scovering\sindex.
|
||||
D 2012-08-24T23:56:19.679
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in abd5c10d21d1395f140d9e50ea999df8fa4d6376
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -131,10 +131,10 @@ F src/callback.c 0cb4228cdcd827dcc5def98fb099edcc9142dbcd
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 500d019da966631ad957c37705642be87524463b
|
||||
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
||||
F src/delete.c 4c20ea4f6213b3bc1c6a510586864b679946e05e
|
||||
F src/delete.c 335f36750dc6ac88d580aa36a6487459be9889de
|
||||
F src/expr.c 217840a107dcc1e5dbb57cea311daad04bedbb9a
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
|
||||
F src/fkey.c 9c77d842dc9961d92a06a65abb80c64ef1750296
|
||||
F src/func.c 18dfedfb857e100b05755a1b12e88b389f957879
|
||||
F src/global.c 4cfdca5cb0edd33c4d021baec4ede958cb2c793b
|
||||
F src/hash.c a4031441741932da9e7a65bee2b36b5d0e81c073
|
||||
@@ -176,11 +176,11 @@ F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 9e28280ec98035f31900fdd1db01f86f68ca6c32
|
||||
F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1
|
||||
F src/select.c 2c0291db072924cace54aadbff1996297e9b8de0
|
||||
F src/select.c a9d68e04f07348038ac279f3316ee8f8e146f59a
|
||||
F src/shell.c 076e1c90d594644f36027c8ecff9a392cf2d3a06
|
||||
F src/sqlite.h.in f664797c68ced43c2ea2c541d4ec8e1e04ec68ac
|
||||
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
|
||||
F src/sqliteInt.h f4748d18114510f61e6de8bac0d513dc76e8f21c
|
||||
F src/sqliteInt.h 497e89baddee92a4769cbc2c169b654a223f75d6
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@@ -233,7 +233,7 @@ F src/test_wholenumber.c 3d2b9ed1505c40ad5c5ca2ad16ae7a289d6cc251
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12
|
||||
F src/trigger.c ee7e178fb9188f44b532cebd449a7c1df90fb684
|
||||
F src/update.c d3076782c887c10e882996550345da9c4c9f9dea
|
||||
F src/update.c 28d2d098b43a2c70dae399896ea8a02f622410ef
|
||||
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
|
||||
F src/util.c 0af2e515dc0dabacec931bca39525f6c3f1c5455
|
||||
F src/vacuum.c 587a52bb8833d7ac15af8916f25437e2575028bd
|
||||
@@ -250,7 +250,7 @@ F src/vtab.c bb8ea3a26608bb1357538a5d2fc72beba6638998
|
||||
F src/wal.c 9294df6f96aae5909ae1a9b733fd1e1b4736978b
|
||||
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
|
||||
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
|
||||
F src/where.c 24c7494d8875ead994b4dfe5461340c27fd424ca
|
||||
F src/where.c 9a28820fb0ead5674d5b45dfdb32aef913fe40c3
|
||||
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00
|
||||
@@ -965,6 +965,7 @@ F test/where9.test ae98dc22ef9b6f2bc81e9f164e41b38faa9bda06
|
||||
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5
|
||||
F test/whereD.test 304ccbe3c77e0d0764f37c91d43b8c4792a5e02f
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
@@ -1012,7 +1013,7 @@ F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
|
||||
P 20f184f2d5908badd9d44d4fe2ad7c9e182c8803 00b1dc71be4c3420730b5f7840af824ea86165e7
|
||||
R c1fab8e17aa8935c76d7626b4d7fe139
|
||||
P d4cd6017c9875947a05b1dc36538d4272fb18739 b722143d075979ba3d92b7b29e576ce2307187d1
|
||||
R d51bc6dccf316fa29f046fa529eea646
|
||||
U drh
|
||||
Z 3e9a3890be18a0a197379668b716e1a3
|
||||
Z 88e4cd6b2ce7efc36bc2db59aa6b0ac5
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
d4cd6017c9875947a05b1dc36538d4272fb18739
|
||||
62678be3df35cdcb09172ba8c860f7b73517f1ea
|
||||
+1
-1
@@ -371,7 +371,7 @@ void sqlite3DeleteFrom(
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
|
||||
pWInfo = sqlite3WhereBegin(
|
||||
pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK
|
||||
pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK, 0
|
||||
);
|
||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0);
|
||||
|
||||
+1
-1
@@ -560,7 +560,7 @@ static void fkScanChildren(
|
||||
** clause. If the constraint is not deferred, throw an exception for
|
||||
** each row found. Otherwise, for deferred constraints, increment the
|
||||
** deferred constraint counter by nIncr for each row selected. */
|
||||
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
|
||||
if( nIncr>0 && pFKey->isDeferred==0 ){
|
||||
sqlite3ParseToplevel(pParse)->mayAbort = 1;
|
||||
}
|
||||
|
||||
+3
-3
@@ -4024,7 +4024,7 @@ int sqlite3Select(
|
||||
ExprList *pDist = (isDistinct ? p->pEList : 0);
|
||||
|
||||
/* Begin the database scan. */
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0,0);
|
||||
if( pWInfo==0 ) goto select_end;
|
||||
if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
|
||||
|
||||
@@ -4197,7 +4197,7 @@ int sqlite3Select(
|
||||
** in the right order to begin with.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0, 0);
|
||||
if( pWInfo==0 ) goto select_end;
|
||||
if( pGroupBy==0 ){
|
||||
/* The optimizer is able to deliver rows in group by order so
|
||||
@@ -4466,7 +4466,7 @@ int sqlite3Select(
|
||||
** of output.
|
||||
*/
|
||||
resetAccumulator(pParse, &sAggInfo);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, 0, flag);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax,0,flag,0);
|
||||
if( pWInfo==0 ){
|
||||
sqlite3ExprListDelete(db, pDel);
|
||||
goto select_end;
|
||||
|
||||
+3
-1
@@ -1947,6 +1947,7 @@ struct WhereLevel {
|
||||
int addrInTop; /* Top of the IN loop */
|
||||
} *aInLoop; /* Information about each nested IN operator */
|
||||
} in; /* Used when plan.wsFlags&WHERE_IN_ABLE */
|
||||
Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
|
||||
} u;
|
||||
|
||||
/* The following field is really not part of the current level. But
|
||||
@@ -2806,7 +2807,8 @@ Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *,
|
||||
#endif
|
||||
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
|
||||
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
||||
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**,ExprList*,u16);
|
||||
WhereInfo *sqlite3WhereBegin(
|
||||
Parse*,SrcList*,Expr*,ExprList**,ExprList*,u16,int);
|
||||
void sqlite3WhereEnd(WhereInfo*);
|
||||
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
|
||||
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
|
||||
|
||||
+1
-1
@@ -313,7 +313,7 @@ void sqlite3Update(
|
||||
*/
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
|
||||
pWInfo = sqlite3WhereBegin(
|
||||
pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED
|
||||
pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, 0
|
||||
);
|
||||
if( pWInfo==0 ) goto update_cleanup;
|
||||
okOnePass = pWInfo->okOnePass;
|
||||
|
||||
+48
-8
@@ -3622,7 +3622,7 @@ static int codeAllEqualityTerms(
|
||||
int r1;
|
||||
int k = pIdx->aiColumn[j];
|
||||
pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx);
|
||||
if( NEVER(pTerm==0) ) break;
|
||||
if( pTerm==0 ) break;
|
||||
/* The following true for indices with redundant columns.
|
||||
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
|
||||
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
|
||||
@@ -4297,6 +4297,8 @@ static Bitmask codeOneLoopStart(
|
||||
*/
|
||||
WhereClause *pOrWc; /* The OR-clause broken out into subterms */
|
||||
SrcList *pOrTab; /* Shortened table list or OR-clause generation */
|
||||
Index *pCov = 0; /* Potential covering index (or NULL) */
|
||||
int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */
|
||||
|
||||
int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
|
||||
int regRowset = 0; /* Register for RowSet object */
|
||||
@@ -4315,7 +4317,7 @@ static Bitmask codeOneLoopStart(
|
||||
pLevel->op = OP_Return;
|
||||
pLevel->p1 = regReturn;
|
||||
|
||||
/* Set up a new SrcList ni pOrTab containing the table being scanned
|
||||
/* Set up a new SrcList in pOrTab containing the table being scanned
|
||||
** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
|
||||
** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
|
||||
*/
|
||||
@@ -4392,8 +4394,10 @@ static Bitmask codeOneLoopStart(
|
||||
/* Loop through table entries that match term pOrTerm. */
|
||||
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
|
||||
WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
|
||||
WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY);
|
||||
WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur);
|
||||
assert( pSubWInfo || pParse->nErr || pParse->db->mallocFailed );
|
||||
if( pSubWInfo ){
|
||||
WhereLevel *pLvl;
|
||||
explainOneScan(
|
||||
pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
|
||||
);
|
||||
@@ -4414,11 +4418,36 @@ static Bitmask codeOneLoopStart(
|
||||
*/
|
||||
if( pSubWInfo->untestedTerms ) untestedTerms = 1;
|
||||
|
||||
/* If all of the OR-connected terms are optimized using the same
|
||||
** index, and the index is opened using the same cursor number
|
||||
** by each call to sqlite3WhereBegin() made by this loop, it may
|
||||
** be possible to use that index as a covering index.
|
||||
**
|
||||
** If the call to sqlite3WhereBegin() above resulted in a scan that
|
||||
** uses an index, and this is either the first OR-connected term
|
||||
** processed or the index is the same as that used by all previous
|
||||
** terms, set pCov to the candidate covering index. Otherwise, set
|
||||
** pCov to NULL to indicate that no candidate covering index will
|
||||
** be available.
|
||||
*/
|
||||
pLvl = &pSubWInfo->a[0];
|
||||
if( (pLvl->plan.wsFlags & WHERE_INDEXED)!=0
|
||||
&& (pLvl->plan.wsFlags & WHERE_TEMP_INDEX)==0
|
||||
&& (ii==0 || pLvl->plan.u.pIdx==pCov)
|
||||
){
|
||||
assert( pLvl->iIdxCur==iCovCur );
|
||||
pCov = pLvl->plan.u.pIdx;
|
||||
}else{
|
||||
pCov = 0;
|
||||
}
|
||||
|
||||
/* Finish the loop through table entries that match term pOrTerm. */
|
||||
sqlite3WhereEnd(pSubWInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
pLevel->u.pCovidx = pCov;
|
||||
pLevel->iIdxCur = iCovCur;
|
||||
if( pAndExpr ){
|
||||
pAndExpr->pLeft = 0;
|
||||
sqlite3ExprDelete(pParse->db, pAndExpr);
|
||||
@@ -4636,7 +4665,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
Expr *pWhere, /* The WHERE clause */
|
||||
ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
|
||||
ExprList *pDistinct, /* The select-list for DISTINCT queries - or NULL */
|
||||
u16 wctrlFlags /* One of the WHERE_* flags defined in sqliteInt.h */
|
||||
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
|
||||
int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
|
||||
){
|
||||
int i; /* Loop counter */
|
||||
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
|
||||
@@ -4956,7 +4986,13 @@ WhereInfo *sqlite3WhereBegin(
|
||||
testcase( bestPlan.plan.wsFlags & WHERE_INDEXED );
|
||||
testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX );
|
||||
if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){
|
||||
pLevel->iIdxCur = pParse->nTab++;
|
||||
if( (wctrlFlags & WHERE_ONETABLE_ONLY)
|
||||
&& (bestPlan.plan.wsFlags & WHERE_TEMP_INDEX)==0
|
||||
){
|
||||
pLevel->iIdxCur = iIdxCur;
|
||||
}else{
|
||||
pLevel->iIdxCur = pParse->nTab++;
|
||||
}
|
||||
}else{
|
||||
pLevel->iIdxCur = -1;
|
||||
}
|
||||
@@ -5208,6 +5244,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
*/
|
||||
assert( pWInfo->nLevel==1 || pWInfo->nLevel==pTabList->nSrc );
|
||||
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
|
||||
Index *pIdx = 0;
|
||||
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
Table *pTab = pTabItem->pTab;
|
||||
assert( pTab!=0 );
|
||||
@@ -5237,12 +5274,15 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
** that reference the table and converts them into opcodes that
|
||||
** reference the index.
|
||||
*/
|
||||
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 && !db->mallocFailed){
|
||||
if( pLevel->plan.wsFlags & WHERE_INDEXED ){
|
||||
pIdx = pLevel->plan.u.pIdx;
|
||||
}else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
|
||||
pIdx = pLevel->u.pCovidx;
|
||||
}
|
||||
if( pIdx && !db->mallocFailed){
|
||||
int k, j, last;
|
||||
VdbeOp *pOp;
|
||||
Index *pIdx = pLevel->plan.u.pIdx;
|
||||
|
||||
assert( pIdx!=0 );
|
||||
pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);
|
||||
last = sqlite3VdbeCurrentAddr(v);
|
||||
for(k=pWInfo->iTop; k<last; k++, pOp++){
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
# 2012 August 24
|
||||
#
|
||||
# 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 that an index may be used as a covering
|
||||
# index when there are OR expressions in the WHERE clause.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix whereD
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t(i,j,k,m,n);
|
||||
CREATE INDEX ijk ON t(i,j,k);
|
||||
CREATE INDEX jmn ON t(j,m,n);
|
||||
|
||||
INSERT INTO t VALUES(3, 3, 'three', 3, 'tres');
|
||||
INSERT INTO t VALUES(2, 2, 'two', 2, 'dos');
|
||||
INSERT INTO t VALUES(1, 1, 'one', 1, 'uno');
|
||||
INSERT INTO t VALUES(4, 4, 'four', 4, 'cuatro');
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2);
|
||||
} {one two}
|
||||
do_execsql_test 1.3 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (+i=2 AND j=2);
|
||||
} {one two}
|
||||
do_execsql_test 1.4 {
|
||||
SELECT n FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2);
|
||||
} {uno dos}
|
||||
do_execsql_test 1.5 {
|
||||
SELECT k, n FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2);
|
||||
} {one uno two dos}
|
||||
do_execsql_test 1.6 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2) OR (i=3 AND j=3);
|
||||
} {one two three}
|
||||
do_execsql_test 1.7 {
|
||||
SELECT n FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2) OR (i=3 AND j=3);
|
||||
} {uno dos tres}
|
||||
do_execsql_test 1.8 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (j=2 AND m=2);
|
||||
} {one two}
|
||||
do_execsql_test 1.9 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2) OR (j=3 AND m=3);
|
||||
} {one two three}
|
||||
do_execsql_test 1.10 {
|
||||
SELECT n FROM t WHERE (i=1 AND j=1) OR (i=2 AND j=2) OR (j=3 AND m=3);
|
||||
} {uno dos tres}
|
||||
do_execsql_test 1.11 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (j=2 AND m=2) OR (i=3 AND j=3);
|
||||
} {one two three}
|
||||
do_execsql_test 1.12 {
|
||||
SELECT n FROM t WHERE (i=1 AND j=1) OR (j=2 AND m=2) OR (i=3 AND j=3);
|
||||
} {uno dos tres}
|
||||
do_execsql_test 1.13 {
|
||||
SELECT k FROM t WHERE (j=1 AND m=1) OR (i=2 AND j=2) OR (i=3 AND j=3);
|
||||
} {one two three}
|
||||
do_execsql_test 1.14 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=1) OR (j=2 AND i=2) OR (i=3 AND j=3);
|
||||
} {one two three}
|
||||
do_execsql_test 1.15 {
|
||||
SELECT k FROM t WHERE (i=1 AND j=2) OR (i=2 AND j=1) OR (i=3 AND j=4);
|
||||
} {}
|
||||
do_execsql_test 1.16 {
|
||||
SELECT k FROM t WHERE (i=1 AND (j=1 or j=2)) OR (i=3 AND j=3);
|
||||
} {one three}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t1(a,b,c,d);
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
CREATE INDEX t1c ON t1(c);
|
||||
CREATE INDEX t1d ON t1(d);
|
||||
CREATE TABLE t2(x,y);
|
||||
CREATE INDEX t2y ON t2(y);
|
||||
|
||||
INSERT INTO t1 VALUES(1,2,3,4);
|
||||
INSERT INTO t1 VALUES(5,6,7,8);
|
||||
INSERT INTO t2 VALUES(1,2);
|
||||
INSERT INTO t2 VALUES(2,7);
|
||||
INSERT INTO t2 VALUES(3,4);
|
||||
} {}
|
||||
do_execsql_test 2.1 {
|
||||
SELECT a, x FROM t1 JOIN t2 ON +y=d OR x=7 ORDER BY a, x;
|
||||
} {1 3}
|
||||
do_execsql_test 2.2 {
|
||||
SELECT a, x FROM t1 JOIN t2 ON y=d OR x=7 ORDER BY a, x;
|
||||
} {1 3}
|
||||
|
||||
|
||||
# Similar to [do_execsql_test], except that two elements are appended
|
||||
# to the result - the string "search" and the number of times test variable
|
||||
# sqlite3_search_count is incremented by running the supplied SQL. e.g.
|
||||
#
|
||||
# do_searchcount_test 1.0 { SELECT * FROM t1 } {x y search 2}
|
||||
#
|
||||
proc do_searchcount_test {tn sql res} {
|
||||
uplevel [subst -nocommands {
|
||||
do_test $tn {
|
||||
set ::sqlite_search_count 0
|
||||
concat [db eval {$sql}] search [set ::sqlite_search_count]
|
||||
} [list $res]
|
||||
}]
|
||||
}
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t3(a, b, c);
|
||||
CREATE UNIQUE INDEX i3 ON t3(a, b);
|
||||
INSERT INTO t3 VALUES(1, 'one', 'i');
|
||||
INSERT INTO t3 VALUES(3, 'three', 'iii');
|
||||
INSERT INTO t3 VALUES(6, 'six', 'vi');
|
||||
INSERT INTO t3 VALUES(2, 'two', 'ii');
|
||||
INSERT INTO t3 VALUES(4, 'four', 'iv');
|
||||
INSERT INTO t3 VALUES(5, 'five', 'v');
|
||||
|
||||
CREATE TABLE t4(x PRIMARY KEY, y);
|
||||
INSERT INTO t4 VALUES('a', 'one');
|
||||
INSERT INTO t4 VALUES('b', 'two');
|
||||
}
|
||||
|
||||
do_searchcount_test 3.1 {
|
||||
SELECT a, b FROM t3 WHERE (a=1 AND b='one') OR (a=2 AND b='two')
|
||||
} {1 one 2 two search 2}
|
||||
|
||||
do_searchcount_test 3.2 {
|
||||
SELECT a, c FROM t3 WHERE (a=1 AND b='one') OR (a=2 AND b='two')
|
||||
} {1 i 2 ii search 4}
|
||||
|
||||
do_searchcount_test 3.4.1 {
|
||||
SELECT y FROM t4 WHERE x='a'
|
||||
} {one search 2}
|
||||
do_searchcount_test 3.4.2 {
|
||||
SELECT a, b FROM t3 WHERE
|
||||
(a=1 AND b=(SELECT y FROM t4 WHERE x='a'))
|
||||
OR (a=2 AND b='two')
|
||||
} {1 one 2 two search 4}
|
||||
do_searchcount_test 3.4.3 {
|
||||
SELECT a, b FROM t3 WHERE
|
||||
(a=2 AND b='two')
|
||||
OR (a=1 AND b=(SELECT y FROM t4 WHERE x='a'))
|
||||
} {2 two 1 one search 4}
|
||||
do_searchcount_test 3.4.4 {
|
||||
SELECT a, b FROM t3 WHERE
|
||||
(a=2 AND b=(SELECT y FROM t4 WHERE x='b'))
|
||||
OR (a=1 AND b=(SELECT y FROM t4 WHERE x='a'))
|
||||
} {2 two 1 one search 6}
|
||||
|
||||
do_searchcount_test 3.5.1 {
|
||||
SELECT a, b FROM t3 WHERE (a=1 AND b='one') OR rowid=4
|
||||
} {1 one 2 two search 2}
|
||||
do_searchcount_test 3.5.2 {
|
||||
SELECT a, c FROM t3 WHERE (a=1 AND b='one') OR rowid=4
|
||||
} {1 i 2 ii search 2}
|
||||
|
||||
finish_test
|
||||
Reference in New Issue
Block a user