From: drh Date: Sat, 12 Feb 2011 05:34:43 +0000 (+0000) Subject: Fix problems in the backport, reducing the number of errors in the TCL tests X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d694cc590914362605b8cb5be6c7cf35530b643a;p=thirdparty%2Fsqlite.git Fix problems in the backport, reducing the number of errors in the TCL tests to just a few dozen. Most of the remaining errors seem to be real and desirable changes of behavior. FossilOrigin-Name: 9d2b0af266b85f10823e54ca6417e76950c1d531 --- diff --git a/manifest b/manifest index 227ecf3f83..fbee74f8e9 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -----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 @@ -119,7 +119,7 @@ F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff 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 @@ -166,16 +166,16 @@ F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07 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 @@ -225,7 +225,7 @@ F src/vdbe.c 66c262a923915e596379b1d597178e04c5d719e4 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 @@ -243,7 +243,7 @@ F test/alter3.test 25b95a136708f22b87184fa6a4309eea03d65153 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 @@ -450,7 +450,7 @@ F test/incrvacuum_ioerr.test 57d2f5777ab13fa03b87b262a4ea1bad5cfc0291 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 @@ -625,7 +625,7 @@ F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3 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 @@ -849,18 +849,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff 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----- diff --git a/manifest.uuid b/manifest.uuid index aa7409700f..b7ab61dc19 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e72cf118cb25e9fed96f8d5cebbc0f637892479a \ No newline at end of file +9d2b0af266b85f10823e54ca6417e76950c1d531 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 636b8a6942..b6316204b5 100644 --- a/src/build.c +++ b/src/build.c @@ -802,6 +802,7 @@ void sqlite3StartTable( pTable->iPKey = -1; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nRef = 1; + pTable->nRowEst = 1000000; assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; @@ -2832,14 +2833,14 @@ exit_create_index: 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; diff --git a/src/prepare.c b/src/prepare.c index 74accd761f..fa64a00dfd 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -628,13 +628,13 @@ static int sqlite3Prepare( 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; diff --git a/src/select.c b/src/select.c index 17184b675a..e059ea135d 100644 --- a/src/select.c +++ b/src/select.c @@ -1302,6 +1302,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ 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; @@ -1372,6 +1373,8 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ 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); @@ -1528,6 +1531,7 @@ static int multiSelect( switch( p->op ){ case TK_ALL: { int addr = 0; + int nLimit; assert( !pPrior->pLimit ); pPrior->pLimit = p->pLimit; pPrior->pOffset = p->pOffset; @@ -1548,6 +1552,13 @@ static int multiSelect( 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); } @@ -1618,6 +1629,7 @@ static int multiSelect( 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; @@ -1695,6 +1707,7 @@ static int multiSelect( 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; @@ -2274,6 +2287,7 @@ static int multiSelectOrderBy( 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 @@ -2281,6 +2295,7 @@ static int multiSelectOrderBy( */ 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); @@ -3101,6 +3116,7 @@ static int selectExpander(Walker *pWalker, Select *p){ 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{ @@ -3658,6 +3674,7 @@ int sqlite3Select( 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; @@ -3758,6 +3775,7 @@ int sqlite3Select( /* 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. @@ -3780,6 +3798,7 @@ int sqlite3Select( */ 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 @@ -3824,6 +3843,9 @@ int sqlite3Select( 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; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 123868444d..e2880d230b 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1995,6 +1995,7 @@ struct Select { 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 */ }; /* diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 5a4ad84975..2ef841e23b 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1182,12 +1182,10 @@ int sqlite3VdbeList( 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 ); @@ -1232,7 +1230,7 @@ int sqlite3VdbeList( } } - p->nResColumn = 8 - 5*(p->explain-1); + p->nResColumn = 8 - 4*(p->explain-1); p->rc = SQLITE_OK; rc = SQLITE_ROW; } diff --git a/test/analyze2.test b/test/analyze2.test index 7a606bb7f6..de2567bb6f 100644 --- a/test/analyze2.test +++ b/test/analyze2.test @@ -22,6 +22,8 @@ ifcapable !stat2 { 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). # @@ -119,36 +121,56 @@ do_test analyze2-2.1 { 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? AND y? AND x? AND y? AND x? 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? AND x'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 '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 'A' AND a < 'c' AND b > 'A' AND b < 'c' +} { + 0 0 0 {SEARCH TABLE t3 USING INDEX t3a (a>? AND a'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)} + } } #-------------------------------------------------------------------- @@ -306,7 +350,7 @@ do_test analyze2-6.1.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.2 { db cache flush execsql ANALYZE @@ -314,14 +358,14 @@ do_test analyze2-6.1.2 { 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; @@ -332,7 +376,7 @@ do_test analyze2-6.1.4 { 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; @@ -343,7 +387,7 @@ do_test analyze2-6.1.5 { 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; @@ -354,7 +398,7 @@ do_test analyze2-6.1.6 { 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 { @@ -366,7 +410,7 @@ do_test analyze2-6.2.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 a1 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; @@ -392,7 +436,7 @@ do_test analyze2-6.2.4 { 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 a1 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 a1 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 @@ -459,7 +503,7 @@ ifcapable shared_cache { 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 @@ -467,7 +511,7 @@ ifcapable shared_cache { 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 @@ -475,7 +519,7 @@ ifcapable shared_cache { 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 @@ -484,14 +528,14 @@ ifcapable shared_cache { 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 @@ -500,7 +544,7 @@ ifcapable shared_cache { 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 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 } @@ -165,51 +176,53 @@ do_test indexedby-5.5 { # 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}} diff --git a/test/tester.tcl b/test/tester.tcl index fb26561b23..736cc945ff 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -338,6 +338,10 @@ proc do_execsql_test {testname sql result} { 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.