-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
-C This\sis\sthe\sbeginning\sof\san\sattempt\sto\sbackport\srecent\squery\splanner\nenhancements\sto\sversion\s3.7.2.\s\sThe\scode\sin\sthis\sversion\sbuilds\sand\sruns\sand\nseems\sto\sgive\scorrect\sanswers,\sbut\sit\sgenerates\ssuboptimal\squery\splans\sand\nhence\smany\sof\sthe\stest\scases\sfail.\s\sThe\stest\sscript\sgives\sup\safter\s1000\serrors.
-D 2011-02-12T01:59:22.979
+C Fix\sproblems\sin\sthe\sbackport,\sreducing\sthe\snumber\sof\serrors\sin\sthe\sTCL\stests\nto\sjust\sa\sfew\sdozen.\s\sMost\sof\sthe\sremaining\serrors\sseem\sto\sbe\sreal\sand\ndesirable\schanges\sof\sbehavior.
+D 2011-02-12T05:34:43.018
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/btree.c 5047fb303cdf6806a42676a6f513c57e15b7d69b
F src/btree.h b4ba2fdf6b64c7c376bdfffa826af6b786b151d9
F src/btreeInt.h 5b034ff54800046cc5870605d683ac1f9134bd99
-F src/build.c 0018d49629fc4807100c988dd191dd95e185bb38
+F src/build.c a3c83d34a7f1e56308175076f65d510ae52dd6dc
F src/callback.c da3c38d0ef5d7f04fae371e519bda61aa9cb1704
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
F src/pcache1.c e921e8a1d52c93abde63cb6dad1fa39770410c52
F src/pragma.c 8b24ce00a93de345b6c3bd1e1e2cfba9f63d2325
-F src/prepare.c ce4c35a2b1d5fe916e4a46b70d24a6e997d7c4c6
+F src/prepare.c c2b318037d626fed27905c9446730b560637217a
F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
-F src/select.c 8add6cab889fc02e1492eda8dba462ccf11f51dd
+F src/select.c 7a673c43b49d5f05f76e9c5a8cafa02862cbb901
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
F src/sqlite.h.in 2d72a6242df41c517e38eec8791abcf5484a36f1
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
-F src/sqliteInt.h f419da0d4ca6f723aca055ef67e440723bc7c6ff
+F src/sqliteInt.h 39a0b4d6bd4f5daf75465a1d35c121f06cf85751
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
F src/vdbeInt.h ffd68c4d4229227a5089bec53a1c635146177abc
F src/vdbeapi.c d0f4407e465f261780ad725c1caece7d66a6aa35
-F src/vdbeaux.c c73bcefcebfd3d2cf91bf6a41ef0fb0d884814c6
+F src/vdbeaux.c 157d62a6a8ca22c3792f5957e887df8bda2d58eb
F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
F src/vdbemem.c e5673f81a2381b35c60e73ef0a8502be2ab1041e
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F test/alter4.test 9386ffd1e9c7245f43eca412b2058d747509cc1f
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
F test/analyze.test bf692e7db414f268a136bade16c03a1bdbb9240c
-F test/analyze2.test 59dac6c399c0c5d1a90a11ee7cc606743fb6db93
+F test/analyze2.test 8f2b1534d43f5547ce9a6b736c021d4192c75be3
F test/analyze3.test 6d4f4b0929545a9d1af803a0608a0c51b92a3537
F test/async.test ad4ba51b77cd118911a3fe1356b0809da9c108c3
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
F test/index.test cbf301cdb2da43e4eac636c3400c2439af1834ad
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
-F test/indexedby.test 5a1180602f2e72c481467bd4cae05dae5dc36f47
+F test/indexedby.test be501e381b82b2f8ab406309ba7aac46e221f4ad
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908
F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
F test/tempdb.test 800c36623d67a2ad1f58784b9c5644e0405af6e6
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
-F test/tester.tcl 6135019fcfac363ea0e11aee670cc97080ab578e
+F test/tester.tcl ba665916dfef8c41769cd225ea374a6b05b75a96
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 42537b60566f288167f1b5864a5435986838e3a3
-R 911182819e6787775a4c401119b6d58c
-T *bgcolor * #d1d3a8
-T *branch * branch-3.7.2
-T *sym-branch-3.7.2 *
-T -sym-trunk *
+P e72cf118cb25e9fed96f8d5cebbc0f637892479a
+R cd223ce61acd48a0fa6d93a74733dd61
U drh
-Z 6673081ac69ed84639c088e8d1e7d477
+Z a73dbb9504f9bb87d458dc1f3711231d
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
-iD8DBQFNVel/oxKgR168RlERAmLzAJwLpY7ATRL1epv2W0jdVpK7vB8cTwCfT/I1
-KFlk2dAE9J/wYPCdpsrAlmY=
-=eWSL
+iD8DBQFNVhv2oxKgR168RlERApFoAJ4s0p8GLfjU21wkHd9FYZ6AXkPMTACeL9gy
+rUEoRNhVYquXJEH4o1up8iU=
+=3IXK
-----END PGP SIGNATURE-----
-e72cf118cb25e9fed96f8d5cebbc0f637892479a
\ No newline at end of file
+9d2b0af266b85f10823e54ca6417e76950c1d531
\ No newline at end of file
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
+ pTable->nRowEst = 1000000;
assert( pParse->pNewTable==0 );
pParse->pNewTable = pTable;
void sqlite3DefaultRowEst(Index *pIdx){
unsigned *a = pIdx->aiRowEst;
int i;
+ unsigned n;
assert( a!=0 );
- a[0] = 1000000;
- for(i=pIdx->nColumn; i>=5; i--){
- a[i] = 5;
- }
- while( i>=1 ){
- a[i] = 11 - i;
- i--;
+ a[0] = pIdx->pTable->nRowEst;
+ if( a[0]<10 ) a[0] = 10;
+ n = 10;
+ for(i=1; i<=pIdx->nColumn; i++){
+ a[i] = n;
+ if( n>5 ) n--;
}
if( pIdx->onError!=OE_None ){
a[pIdx->nColumn] = 1;
if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
static const char * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
- "order", "from", "detail"
+ "selectid", "order", "from", "detail"
};
int iFirst, mx;
if( pParse->explain==2 ){
- sqlite3VdbeSetNumCols(pParse->pVdbe, 3);
+ sqlite3VdbeSetNumCols(pParse->pVdbe, 4);
iFirst = 8;
- mx = 11;
+ mx = 12;
}else{
sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
iFirst = 0;
assert( db->lookaside.bEnabled==0 );
pTab->nRef = 1;
pTab->zName = 0;
+ pTab->nRowEst = 1000000;
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSelect);
pTab->iPKey = -1;
VdbeComment((v, "LIMIT counter"));
if( n==0 ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak);
+ }else{
+ if( p->nSelectRow > (double)n ) p->nSelectRow = (double)n;
}
}else{
sqlite3ExprCode(pParse, p->pLimit, iLimit);
switch( p->op ){
case TK_ALL: {
int addr = 0;
+ int nLimit;
assert( !pPrior->pLimit );
pPrior->pLimit = p->pLimit;
pPrior->pOffset = p->pOffset;
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
p->pPrior = pPrior;
+ p->nSelectRow += pPrior->nSelectRow;
+ if( pPrior->pLimit
+ && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
+ && p->nSelectRow > (double)nLimit
+ ){
+ p->nSelectRow = (double)nLimit;
+ }
if( addr ){
sqlite3VdbeJumpHere(v, addr);
}
pDelete = p->pPrior;
p->pPrior = pPrior;
p->pOrderBy = 0;
+ if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = pLimit;
p->pOffset = pOffset;
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
p->pPrior = pPrior;
+ if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = pLimit;
p->pOffset = pOffset;
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA);
+ p->nSelectRow += pPrior->nSelectRow;
}
/* Generate a subroutine to run when the results from select B
*/
if( op==TK_INTERSECT ){
addrEofB = addrEofA;
+ if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
}else{
VdbeNoopComment((v, "eof-B subroutine"));
addrEofB = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
while( pSel->pPrior ){ pSel = pSel->pPrior; }
selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
pTab->iPKey = -1;
+ pTab->nRowEst = 1000000;
pTab->tabFlags |= TF_Ephemeral;
#endif
}else{
assert( pItem->isPopulated==0 );
sqlite3Select(pParse, pSub, &dest);
pItem->isPopulated = 1;
+ pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
}
if( /*pParse->nErr ||*/ db->mallocFailed ){
goto select_end;
/* Set the limiter.
*/
iEnd = sqlite3VdbeMakeLabel(v);
+ p->nSelectRow = (double)LARGEST_INT64;
computeLimitRegisters(pParse, p, iEnd);
/* Open a virtual index to use for the distinct set.
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0);
if( pWInfo==0 ) goto select_end;
+ if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
/* If sorting index that was created by a prior OP_OpenEphemeral
** instruction ended up not being needed, then change the OP_OpenEphemeral
for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
pItem->iAlias = 0;
}
+ if( p->nSelectRow>(double)100 ) p->nSelectRow = (double)100;
+ }else{
+ p->nSelectRow = (double)1;
}
Expr *pOffset; /* OFFSET expression. NULL means not used. */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
+ double nSelectRow; /* Estimated number of result rows */
};
/*
pMem->type = SQLITE_INTEGER;
pMem++;
- if( p->explain==1 ){
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p3; /* P3 */
- pMem->type = SQLITE_INTEGER;
- pMem++;
- }
+ pMem->flags = MEM_Int;
+ pMem->u.i = pOp->p3; /* P3 */
+ pMem->type = SQLITE_INTEGER;
+ pMem++;
if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
assert( p->db->mallocFailed );
}
}
- p->nResColumn = 8 - 5*(p->explain-1);
+ p->nResColumn = 8 - 4*(p->explain-1);
p->rc = SQLITE_OK;
rc = SQLITE_ROW;
}
return
}
+set testprefix analyze2
+
# Do not use a codec for tests in this file, as the database file is
# manipulated directly using tcl scripts (using the [hexio_write] command).
#
execsql COMMIT
execsql ANALYZE
} {}
-do_test analyze2-2.2 {
- eqp "SELECT * FROM t1 WHERE x>500 AND y>700"
-} {0 0 {TABLE t1 WITH INDEX t1_y}}
-do_test analyze2-2.3 {
- eqp "SELECT * FROM t1 WHERE x>700 AND y>500"
-} {0 0 {TABLE t1 WITH INDEX t1_x}}
-do_test analyze2-2.3 {
- eqp "SELECT * FROM t1 WHERE y>700 AND x>500"
-} {0 0 {TABLE t1 WITH INDEX t1_y}}
-do_test analyze2-2.4 {
- eqp "SELECT * FROM t1 WHERE y>500 AND x>700"
-} {0 0 {TABLE t1 WITH INDEX t1_x}}
-do_test analyze2-2.5 {
- eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 200 AND y BETWEEN 400 AND 700"
-} {0 0 {TABLE t1 WITH INDEX t1_x}}
-do_test analyze2-2.6 {
- eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 400 AND 700"
-} {0 0 {TABLE t1 WITH INDEX t1_y}}
-do_test analyze2-2.7 {
- eqp "SELECT * FROM t1 WHERE x BETWEEN -400 AND -300 AND y BETWEEN 100 AND 300"
-} {0 0 {TABLE t1 WITH INDEX t1_x}}
-do_test analyze2-2.8 {
- eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN -400 AND -300"
-} {0 0 {TABLE t1 WITH INDEX t1_y}}
-do_test analyze2-2.9 {
- eqp "SELECT * FROM t1 WHERE x BETWEEN 500 AND 100 AND y BETWEEN 100 AND 300"
-} {0 0 {TABLE t1 WITH INDEX t1_x}}
-do_test analyze2-2.10 {
- eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN 500 AND 100"
-} {0 0 {TABLE t1 WITH INDEX t1_y}}
+do_eqp_test 2.2 {
+ SELECT * FROM t1 WHERE x>500 AND y>700
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~100 rows)}
+}
+do_eqp_test 2.3 {
+ SELECT * FROM t1 WHERE x>700 AND y>500
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>?) (~100 rows)}
+}
+do_eqp_test 2.3 {
+ SELECT * FROM t1 WHERE y>700 AND x>500
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~100 rows)}
+}
+do_eqp_test 2.4 {
+ SELECT * FROM t1 WHERE y>500 AND x>700
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>?) (~100 rows)}
+}
+do_eqp_test 2.5 {
+ SELECT * FROM t1 WHERE x BETWEEN 100 AND 200 AND y BETWEEN 400 AND 700
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~25 rows)}
+}
+do_eqp_test 2.6 {
+ SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 400 AND 700
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~75 rows)}
+}
+do_eqp_test 2.7 {
+ SELECT * FROM t1 WHERE x BETWEEN -400 AND -300 AND y BETWEEN 100 AND 300
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~12 rows)}
+}
+do_eqp_test 2.8 {
+ SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN -400 AND -300
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~12 rows)}
+}
+do_eqp_test 2.9 {
+ SELECT * FROM t1 WHERE x BETWEEN 500 AND 100 AND y BETWEEN 100 AND 300
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~12 rows)}
+}
+do_eqp_test 2.10 {
+ SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN 500 AND 100
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~12 rows)}
+}
do_test analyze2-3.1 {
set alphabet [list a b c d e f g h i j]
}
} {t1 t1_y {100 299 499 699 899 ajj cjj ejj gjj ijj}}
-do_test analyze2-3.3 {
- eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 'a' AND 'b'"
-} {0 0 {TABLE t1 WITH INDEX t1_y}}
-do_test analyze2-3.4 {
- eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 400 AND y BETWEEN 'a' AND 'h'"
-} {0 0 {TABLE t1 WITH INDEX t1_x}}
-do_test analyze2-3.5 {
- eqp "SELECT * FROM t1 WHERE x<'a' AND y>'h'"
-} {0 0 {TABLE t1 WITH INDEX t1_y}}
-do_test analyze2-3.6 {
- eqp "SELECT * FROM t1 WHERE x<444 AND y>'h'"
-} {0 0 {TABLE t1 WITH INDEX t1_y}}
-do_test analyze2-3.7 {
- eqp "SELECT * FROM t1 WHERE x<221 AND y>'g'"
-} {0 0 {TABLE t1 WITH INDEX t1_x}}
+do_eqp_test 3.3 {
+ SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 'a' AND 'b'
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~50 rows)}
+}
+do_eqp_test 3.4 {
+ SELECT * FROM t1 WHERE x BETWEEN 100 AND 400 AND y BETWEEN 'a' AND 'h'
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~100 rows)}
+}
+do_eqp_test 3.5 {
+ SELECT * FROM t1 WHERE x<'a' AND y>'h'
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~66 rows)}
+}
+do_eqp_test 3.6 {
+ SELECT * FROM t1 WHERE x<444 AND y>'h'
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~66 rows)}
+}
+do_eqp_test 3.7 {
+ SELECT * FROM t1 WHERE x<221 AND y>'g'
+} {
+ 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x<?) (~66 rows)}
+}
do_test analyze2-4.1 {
execsql { CREATE TABLE t3(a COLLATE nocase, b) }
} {}
do_test analyze2-4.2 {
execsql {
+ PRAGMA automatic_index=OFF;
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat2
WHERE idx = 't3a'
- GROUP BY tbl,idx
+ GROUP BY tbl,idx;
+ PRAGMA automatic_index=ON;
}
} {t3 t3a {AfA bEj CEj dEj EEj fEj GEj hEj IEj jEj}}
do_test analyze2-4.3 {
}
} {t3 t3b {AbA CIj EIj GIj IIj bIj dIj fIj hIj jIj}}
-do_test analyze2-4.4 {
- eqp "SELECT * FROM t3 WHERE a > 'A' AND a < 'C' AND b > 'A' AND b < 'C'"
-} {0 0 {TABLE t3 WITH INDEX t3b}}
-do_test analyze2-4.5 {
- eqp "SELECT * FROM t3 WHERE a > 'A' AND a < 'c' AND b > 'A' AND b < 'c'"
-} {0 0 {TABLE t3 WITH INDEX t3a}}
+do_eqp_test 4.4 {
+ SELECT * FROM t3 WHERE a > 'A' AND a < 'C' AND b > 'A' AND b < 'C'
+} {
+ 0 0 0 {SEARCH TABLE t3 USING INDEX t3b (b>? AND b<?) (~11 rows)}
+}
+do_eqp_test 4.5 {
+ SELECT * FROM t3 WHERE a > 'A' AND a < 'c' AND b > 'A' AND b < 'c'
+} {
+ 0 0 0 {SEARCH TABLE t3 USING INDEX t3a (a>? AND a<?) (~22 rows)}
+}
ifcapable utf16 {
proc test_collate {enc lhs rhs} {
GROUP BY tbl,idx
}
} {t4 t4x {afa bej cej dej eej fej gej hej iej jej}}
- do_test analyze2-5.3 {
- eqp "SELECT * FROM t4 WHERE x>'ccc'"
- } {0 0 {TABLE t4 WITH INDEX t4x}}
- do_test analyze2-5.4 {
- eqp "SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ccc' AND t42.x>'ggg'"
- } {0 1 {TABLE t4 AS t42 WITH INDEX t4x} 1 0 {TABLE t4 AS t41 WITH INDEX t4x}}
- do_test analyze2-5.5 {
- eqp "SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc'"
- } {0 0 {TABLE t4 AS t41 WITH INDEX t4x} 1 1 {TABLE t4 AS t42 WITH INDEX t4x}}
+ do_eqp_test 5.3 {
+ SELECT * FROM t4 WHERE x>'ccc'
+ } {0 0 0 {SEARCH TABLE t4 USING COVERING INDEX t4x (x>?) (~800 rows)}}
+ do_eqp_test 5.4 {
+ SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ccc' AND t42.x>'ggg'
+ } {
+ 0 0 1 {SEARCH TABLE t4 AS t42 USING COVERING INDEX t4x (x>?) (~300 rows)}
+ 0 1 0 {SEARCH TABLE t4 AS t41 USING COVERING INDEX t4x (x>?) (~800 rows)}
+ }
+ do_eqp_test 5.5 {
+ SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc'
+ } {
+ 0 0 0 {SEARCH TABLE t4 AS t41 USING COVERING INDEX t4x (x>?) (~700 rows)}
+ 0 1 1 {SEARCH TABLE t4 AS t42 USING COVERING INDEX t4x (x>?) (~800 rows)}
+ }
}
#--------------------------------------------------------------------
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
-} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
+} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a=? AND b=?) (~9 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.1.2 {
db cache flush
execsql ANALYZE
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
-} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
+} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.1.3 {
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
-} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
+} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.1.4 {
execsql {
PRAGMA writable_schema = 1;
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
-} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
+} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.1.5 {
execsql {
PRAGMA writable_schema = 1;
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
-} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
+} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a=? AND b=?) (~9 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.1.6 {
execsql {
PRAGMA writable_schema = 1;
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
-} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
+} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.1 {
execsql {
t5.a>1 AND t5.a<15 AND
t6.a>1
}
-} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
+} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~60000 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.2 {
db cache flush
execsql ANALYZE
t5.a>1 AND t5.a<15 AND
t6.a>1
}
-} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
+} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.3 {
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
-} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
+} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.4 {
execsql {
PRAGMA writable_schema = 1;
t5.a>1 AND t5.a<15 AND
t6.a>1
}
-} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
+} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~60000 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.5 {
execsql {
PRAGMA writable_schema = 1;
t5.a>1 AND t5.a<15 AND
t6.a>1
}
-} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
+} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~60000 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.6 {
execsql {
PRAGMA writable_schema = 1;
t5.a>1 AND t5.a<15 AND
t6.a>1
}
-} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
+} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
#--------------------------------------------------------------------
# These tests, analyze2-7.*, test that the sqlite_stat2 functionality
t5.a>1 AND t5.a<15 AND
t6.a>1
} db1
- } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
+ } {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-7.6 {
incr_schema_cookie test.db
execsql { SELECT * FROM sqlite_master } db2
t5.a>1 AND t5.a<15 AND
t6.a>1
} db2
- } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
+ } {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-7.7 {
incr_schema_cookie test.db
execsql { SELECT * FROM sqlite_master } db1
t5.a>1 AND t5.a<15 AND
t6.a>1
} db1
- } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
+ } {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-7.8 {
execsql { DELETE FROM sqlite_stat2 } db2
t5.a>1 AND t5.a<15 AND
t6.a>1
} db1
- } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
+ } {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-7.9 {
execsql { SELECT * FROM sqlite_master } db2
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
} db2
- } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
+ } {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-7.10 {
incr_schema_cookie test.db
t5.a>1 AND t5.a<15 AND
t6.a>1
} db1
- } {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
+ } {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
db1 close
db2 close
# These tests are to check that "EXPLAIN QUERY PLAN" is working as expected.
#
-do_test indexedby-1.2 {
- EQP { select * from t1 WHERE a = 10; }
-} {0 0 {TABLE t1 WITH INDEX i1}}
-do_test indexedby-1.3 {
- EQP { select * from t1 ; }
-} {0 0 {TABLE t1}}
-do_test indexedby-1.4 {
- EQP { select * from t1, t2 WHERE c = 10; }
-} {0 1 {TABLE t2 WITH INDEX i3} 1 0 {TABLE t1}}
+do_execsql_test indexedby-1.2 {
+ EXPLAIN QUERY PLAN select * from t1 WHERE a = 10;
+} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)}}
+do_execsql_test indexedby-1.3 {
+ EXPLAIN QUERY PLAN select * from t1 ;
+} {0 0 0 {SCAN TABLE t1 (~1000000 rows)}}
+do_execsql_test indexedby-1.4 {
+ EXPLAIN QUERY PLAN select * from t1, t2 WHERE c = 10;
+} {
+ 0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?) (~10 rows)}
+ 0 1 0 {SCAN TABLE t1 (~1000000 rows)}
+}
# Parser tests. Test that an INDEXED BY or NOT INDEX clause can be
# attached to a table in the FROM clause, but not to a sub-select or
# Tests for single table cases.
#
-do_test indexedby-3.1 {
- EQP { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'}
-} {0 0 {TABLE t1}}
-do_test indexedby-3.2 {
- EQP { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'}
-} {0 0 {TABLE t1 WITH INDEX i1}}
-do_test indexedby-3.3 {
- EQP { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'}
-} {0 0 {TABLE t1 WITH INDEX i2}}
+do_execsql_test indexedby-3.1 {
+ EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'
+} {0 0 0 {SCAN TABLE t1 (~10000 rows)}}
+do_execsql_test indexedby-3.2 {
+ EXPLAIN QUERY PLAN
+ SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'
+} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}}
+do_execsql_test indexedby-3.3 {
+ EXPLAIN QUERY PLAN
+ SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'
+} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}}
do_test indexedby-3.4 {
catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' }
} {1 {cannot use index: i2}}
catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a }
} {0 {}}
-do_test indexedby-3.8 {
- EQP { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e }
-} {0 0 {TABLE t3 WITH INDEX sqlite_autoindex_t3_1 ORDER BY}}
-do_test indexedby-3.9 {
- EQP { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 }
-} {0 0 {TABLE t3 WITH INDEX sqlite_autoindex_t3_1}}
+do_execsql_test indexedby-3.8 {
+ EXPLAIN QUERY PLAN
+ SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e
+} {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1 (~1000000 rows)}}
+do_execsql_test indexedby-3.9 {
+ EXPLAIN QUERY PLAN
+ SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10
+} {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?) (~1 rows)}}
do_test indexedby-3.10 {
catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 }
} {1 {cannot use index: sqlite_autoindex_t3_1}}
# Tests for multiple table cases.
#
-do_test indexedby-4.1 {
- EQP { SELECT * FROM t1, t2 WHERE a = c }
-} {0 0 {TABLE t1} 1 1 {TABLE t2 WITH INDEX i3}}
-do_test indexedby-4.2 {
- EQP { SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c }
-} {0 1 {TABLE t2} 1 0 {TABLE t1 WITH INDEX i1}}
+do_execsql_test indexedby-4.1 {
+ EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE a = c
+} {
+ 0 0 0 {SCAN TABLE t1 (~1000000 rows)}
+ 0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?) (~10 rows)}
+}
+do_execsql_test indexedby-4.2 {
+ EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c
+} {
+ 0 0 1 {SCAN TABLE t2 (~1000000 rows)}
+ 0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)}
+}
do_test indexedby-4.3 {
catchsql {
SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c
# also tests that nothing bad happens if an index refered to by
# a CREATE VIEW statement is dropped and recreated.
#
-do_test indexedby-5.1 {
- execsql {
- CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5;
- }
- EQP { SELECT * FROM v2 }
-} {0 0 {TABLE t1 WITH INDEX i1}}
-do_test indexedby-5.2 {
- EQP { SELECT * FROM v2 WHERE b = 10 }
-} {0 0 {TABLE t1 WITH INDEX i1}}
+do_execsql_test indexedby-5.1 {
+ CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5;
+ EXPLAIN QUERY PLAN SELECT * FROM v2
+} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~250000 rows)}}
+do_execsql_test indexedby-5.2 {
+ EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10
+} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~25000 rows)}}
do_test indexedby-5.3 {
execsql { DROP INDEX i1 }
catchsql { SELECT * FROM v2 }
# Test that "NOT INDEXED" may use the rowid index, but not others.
#
-do_test indexedby-6.1 {
- EQP { SELECT * FROM t1 WHERE b = 10 ORDER BY rowid }
-} {0 0 {TABLE t1 WITH INDEX i2 ORDER BY}}
-do_test indexedby-6.2 {
- EQP { SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid }
-} {0 0 {TABLE t1 USING PRIMARY KEY ORDER BY}}
+do_execsql_test indexedby-6.1 {
+ EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 10 ORDER BY rowid
+} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~10 rows)}}
+do_execsql_test indexedby-6.2 {
+ EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid
+} {0 0 0 {SCAN TABLE t1 USING INTEGER PRIMARY KEY (~100000 rows)}}
# Test that "INDEXED BY" can be used in a DELETE statement.
#
-do_test indexedby-7.1 {
- EQP { DELETE FROM t1 WHERE a = 5 }
-} {0 0 {TABLE t1 WITH INDEX i1}}
-do_test indexedby-7.2 {
- EQP { DELETE FROM t1 NOT INDEXED WHERE a = 5 }
-} {0 0 {TABLE t1}}
-do_test indexedby-7.3 {
- EQP { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 }
-} {0 0 {TABLE t1 WITH INDEX i1}}
-do_test indexedby-7.4 {
- EQP { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10}
-} {0 0 {TABLE t1 WITH INDEX i1}}
-do_test indexedby-7.5 {
- EQP { DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10}
-} {0 0 {TABLE t1 WITH INDEX i2}}
+do_execsql_test indexedby-7.1 {
+ EXPLAIN QUERY PLAN DELETE FROM t1 WHERE a = 5
+} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}}
+do_execsql_test indexedby-7.2 {
+ EXPLAIN QUERY PLAN DELETE FROM t1 NOT INDEXED WHERE a = 5
+} {0 0 0 {SCAN TABLE t1 (~100000 rows)}}
+do_execsql_test indexedby-7.3 {
+ EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5
+} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}}
+do_execsql_test indexedby-7.4 {
+ EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10
+} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}}
+do_execsql_test indexedby-7.5 {
+ EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10
+} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}}
do_test indexedby-7.6 {
catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5}
} {1 {cannot use index: i2}}
# Test that "INDEXED BY" can be used in an UPDATE statement.
#
-do_test indexedby-8.1 {
- EQP { UPDATE t1 SET rowid=rowid+1 WHERE a = 5 }
-} {0 0 {TABLE t1 WITH INDEX i1}}
-do_test indexedby-8.2 {
- EQP { UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 }
-} {0 0 {TABLE t1}}
-do_test indexedby-8.3 {
- EQP { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 }
-} {0 0 {TABLE t1 WITH INDEX i1}}
-do_test indexedby-8.4 {
- EQP { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10}
-} {0 0 {TABLE t1 WITH INDEX i1}}
-do_test indexedby-8.5 {
- EQP { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10}
-} {0 0 {TABLE t1 WITH INDEX i2}}
+do_execsql_test indexedby-8.1 {
+ EXPLAIN QUERY PLAN UPDATE t1 SET rowid=rowid+1 WHERE a = 5
+} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}}
+do_execsql_test indexedby-8.2 {
+ EXPLAIN QUERY PLAN UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5
+} {0 0 0 {SCAN TABLE t1 (~100000 rows)}}
+do_execsql_test indexedby-8.3 {
+ EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5
+} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}}
+do_execsql_test indexedby-8.4 {
+ EXPLAIN QUERY PLAN
+ UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10
+} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}}
+do_execsql_test indexedby-8.5 {
+ EXPLAIN QUERY PLAN
+ UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10
+} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}}
do_test indexedby-8.6 {
catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5}
} {1 {cannot use index: i2}}
proc do_catchsql_test {testname sql result} {
uplevel do_test $testname [list "catchsql {$sql}"] [list $result]
}
+proc do_eqp_test {name sql res} {
+ uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] \
+ [list [string trim $res]]
+}
# Run an SQL script.