Fix a dangling-else problem that was causing recursive CTEs to malfunction.
Begin fixing test cases to work with the new EQP output. FossilOrigin-Name: 82ca44b82fed6814c84440ba8bfaa019488ab956e84ac165180e2fcece6facb2
This commit is contained in:
parent
c631ded5e8
commit
03c3905f94
26
manifest
26
manifest
@ -1,5 +1,5 @@
|
||||
C Improvements\sto\sthe\sEQP\sdisplay\sfor\scompound\sselect\sstatements.
|
||||
D 2018-05-02T02:22:22.993
|
||||
C Fix\sa\sdangling-else\sproblem\sthat\swas\scausing\srecursive\sCTEs\sto\smalfunction.\nBegin\sfixing\stest\scases\sto\swork\swith\sthe\snew\sEQP\soutput.
|
||||
D 2018-05-02T14:24:34.656
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 5ce9343cba9c189046f1afe6d2bcc1f68079439febc05267b98aec6ecc752439
|
||||
@ -488,17 +488,17 @@ F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||
F src/pragma.c bea56df3ae0637768c0da4fbbb8f2492f780980d95000034a105ff291bf7ca69
|
||||
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
||||
F src/prepare.c 1492a2bed7bc5770c5850404f09bf887a67d4580985b8cee37bdab2ea809f479
|
||||
F src/prepare.c 95a9dba7a5d032039a77775188cb3b6fb17f2fa1a0b7cd915b30b4b823383ffa
|
||||
F src/printf.c d3b7844ddeb11fbbdd38dd84d09c9c1ac171d21fb038473c3aa97981201cc660
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 6415381a0e9d22c0e7cba33ca4a53f81474190862f5d4838190f5eb5b0b47bc9
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 41962df2f21593db4eb5e0d7d8f15848b9ebd3ffed9b7584677033a8db37223b
|
||||
F src/select.c e66bb89e00608e50fa03939d5d86213a302487e8b78e0960b646be9ea0ac2f3e
|
||||
F src/shell.c.in 29309f2ab656c8817fbc3b7910b9af8464557b91cba75277a03669399c8e2730
|
||||
F src/sqlite.h.in d669de545f18f2f01362de02e309cd7f15185958c71bac8f53cd5438b46d2bea
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 83a3c4ce93d650bedfd1aa558cb85a516bd6d094445ee989740827d0d944368d
|
||||
F src/sqliteInt.h 337e4fe0a9e3bef575699bd0063ac2dcc31b73c905206d5425d442fe7fbb2798
|
||||
F src/sqliteInt.h 4095263176d49601f27086b7e66ca541923b72a909187923e3b45e60511cfe2a
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@ -579,7 +579,7 @@ F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
|
||||
F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f
|
||||
F src/where.c 7a1c5555c00bcf49c677472ae83bb49bf24c8d8e9a060d475e86dee39be2fb3a
|
||||
F src/whereInt.h 2610cb87dd95509995b63decc674c60f2757697a206cfe0c085ee53d9c43cfff
|
||||
F src/wherecode.c 13b831d258ab8468cb0469a882f0778632b55d787f329751e50d92b8133ea594
|
||||
F src/wherecode.c 3368f0797a4b166e0773a4137d270d92ddcbce91618b11d1e9f11f7c39f33068
|
||||
F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@ -595,13 +595,13 @@ F test/alter4.test b6d7b86860111864f6cddb54af313f5862dda23b
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test b3a9c67d00e1df7588a5b7be9a0292899f94fe8cac1f94a017277474ca2e59df
|
||||
F test/analyze3.test 8b3ef8ba6d1096b76c40e0925c0fe51e700d2b779cdda40914580de3f9b9d80f
|
||||
F test/analyze3.test ff62d9029e6deb2c914490c6b00caf7fae47cc85cdc046e4a0d0a4d4b87c71d8
|
||||
F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213
|
||||
F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
|
||||
F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f
|
||||
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
|
||||
F test/analyze8.test c05a461d0a6b05991106467d0c47480f2e709c82
|
||||
F test/analyze9.test dac0bdc7eab965b9ad639ca83564d98717aaf13ce5a776f23d9a3680238cecd8
|
||||
F test/analyze9.test 9fbf0e0101eef4f5dc149769aa14e10b76ee06e7c28598264b32173cd1999a54
|
||||
F test/analyzeA.test 3335697f6700c7052295cfd0067fc5b2aacddf9a
|
||||
F test/analyzeB.test a4c1c3048f6d9e090eb76e83eecb18bcf6d31a70
|
||||
F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93
|
||||
@ -791,7 +791,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
|
||||
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
|
||||
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
|
||||
F test/eqp.test 3fe051af50921284189d1970eb653f9fcf5117d2
|
||||
F test/eqp.test 0d06518e010ca5f02bd56b6a45fb70514a29c7eb97d244d72826d164477cfb1e
|
||||
F test/errmsg.test eae9f091eb39ce7e20305de45d8e5d115b68fa856fba4ea6757b6ca3705ff7f9
|
||||
F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c
|
||||
F test/exclusive.test 1206b87e192497d78c7f35552e86a9d05421498da300fb1cce5ca5351ccde3c3
|
||||
@ -1316,7 +1316,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl 94901a4625d9a2229666dd5c44120ddf7f0fb639470710ef74a4cefc7b039e07
|
||||
F test/tester.tcl aa7558f20fcf7dd9151325f849d9103bd450235093bc078073bf0f080991e3c4
|
||||
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@ -1727,7 +1727,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 70b48a7972dfbb44af3ccd8ccd830e984bec88d80a78b3566a5de86a16e7fc14
|
||||
R 21b35e2f4fb3267c4b0452fc48ac12e8
|
||||
P 699a77e479010a331b0423f157a2fbfc373688e3d0d04ae5e64376c00cb3d488
|
||||
R 5835567753900691e5cf824409193ffc
|
||||
U drh
|
||||
Z 26b206c16e8cc64ca80991a86c32cf32
|
||||
Z eb3edd9f2f9ef18dad6eafce24ad9bb2
|
||||
|
@ -1 +1 @@
|
||||
699a77e479010a331b0423f157a2fbfc373688e3d0d04ae5e64376c00cb3d488
|
||||
82ca44b82fed6814c84440ba8bfaa019488ab956e84ac165180e2fcece6facb2
|
@ -616,7 +616,7 @@ static int sqlite3Prepare(
|
||||
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
|
||||
static const char * const azColName[] = {
|
||||
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
|
||||
"selectid", "order", "from", "detail"
|
||||
"id", "parent", "notused", "detail"
|
||||
};
|
||||
int iFirst, mx;
|
||||
if( sParse.explain==2 ){
|
||||
|
412
src/select.c
412
src/select.c
@ -2487,231 +2487,237 @@ static int multiSelect(
|
||||
*/
|
||||
if( p->pOrderBy ){
|
||||
return multiSelectOrderBy(pParse, p, pDest);
|
||||
}else
|
||||
}else{
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( pPrior->pPrior==0 ){
|
||||
ExplainQueryPlan((pParse, 1, "COMPOUND QUERY"));
|
||||
ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY"));
|
||||
ExplainQueryPlanSetId(pParse, pPrior);
|
||||
}
|
||||
if( p->pNext==0 ){
|
||||
ExplainQueryPlan((pParse, 1, "COMPOUND QUERY"));
|
||||
}
|
||||
if( pPrior->pPrior==0 ){
|
||||
ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY"));
|
||||
ExplainQueryPlanSetId(pParse, pPrior);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate code for the left and right SELECT statements.
|
||||
*/
|
||||
switch( p->op ){
|
||||
case TK_ALL: {
|
||||
int addr = 0;
|
||||
int nLimit;
|
||||
assert( !pPrior->pLimit );
|
||||
pPrior->iLimit = p->iLimit;
|
||||
pPrior->iOffset = p->iOffset;
|
||||
pPrior->pLimit = p->pLimit;
|
||||
rc = sqlite3Select(pParse, pPrior, &dest);
|
||||
p->pLimit = 0;
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
p->pPrior = 0;
|
||||
p->iLimit = pPrior->iLimit;
|
||||
p->iOffset = pPrior->iOffset;
|
||||
if( p->iLimit ){
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
|
||||
VdbeComment((v, "Jump ahead if LIMIT reached"));
|
||||
if( p->iOffset ){
|
||||
sqlite3VdbeAddOp3(v, OP_OffsetLimit,
|
||||
p->iLimit, p->iOffset+1, p->iOffset);
|
||||
/* Generate code for the left and right SELECT statements.
|
||||
*/
|
||||
switch( p->op ){
|
||||
case TK_ALL: {
|
||||
int addr = 0;
|
||||
int nLimit;
|
||||
assert( !pPrior->pLimit );
|
||||
pPrior->iLimit = p->iLimit;
|
||||
pPrior->iOffset = p->iOffset;
|
||||
pPrior->pLimit = p->pLimit;
|
||||
rc = sqlite3Select(pParse, pPrior, &dest);
|
||||
p->pLimit = 0;
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
p->pPrior = 0;
|
||||
p->iLimit = pPrior->iLimit;
|
||||
p->iOffset = pPrior->iOffset;
|
||||
if( p->iLimit ){
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
|
||||
VdbeComment((v, "Jump ahead if LIMIT reached"));
|
||||
if( p->iOffset ){
|
||||
sqlite3VdbeAddOp3(v, OP_OffsetLimit,
|
||||
p->iLimit, p->iOffset+1, p->iOffset);
|
||||
}
|
||||
}
|
||||
ExplainQueryPlan((pParse, 1, "UNION ALL"));
|
||||
ExplainQueryPlanSetId(pParse, p);
|
||||
rc = sqlite3Select(pParse, p, &dest);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
pDelete = p->pPrior;
|
||||
p->pPrior = pPrior;
|
||||
p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
|
||||
if( pPrior->pLimit
|
||||
&& sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit)
|
||||
&& nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
|
||||
){
|
||||
p->nSelectRow = sqlite3LogEst((u64)nLimit);
|
||||
}
|
||||
if( addr ){
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
ExplainQueryPlan((pParse, 1, "UNION ALL"));
|
||||
ExplainQueryPlanSetId(pParse, p);
|
||||
rc = sqlite3Select(pParse, p, &dest);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
pDelete = p->pPrior;
|
||||
p->pPrior = pPrior;
|
||||
p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
|
||||
if( pPrior->pLimit
|
||||
&& sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit)
|
||||
&& nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
|
||||
){
|
||||
p->nSelectRow = sqlite3LogEst((u64)nLimit);
|
||||
}
|
||||
if( addr ){
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_EXCEPT:
|
||||
case TK_UNION: {
|
||||
int unionTab; /* Cursor number of the temporary table holding result */
|
||||
u8 op = 0; /* One of the SRT_ operations to apply to self */
|
||||
int priorOp; /* The SRT_ operation to apply to prior selects */
|
||||
Expr *pLimit; /* Saved values of p->nLimit */
|
||||
int addr;
|
||||
SelectDest uniondest;
|
||||
|
||||
testcase( p->op==TK_EXCEPT );
|
||||
testcase( p->op==TK_UNION );
|
||||
priorOp = SRT_Union;
|
||||
if( dest.eDest==priorOp ){
|
||||
/* We can reuse a temporary table generated by a SELECT to our
|
||||
** right.
|
||||
case TK_EXCEPT:
|
||||
case TK_UNION: {
|
||||
int unionTab; /* Cursor number of the temp table holding result */
|
||||
u8 op = 0; /* One of the SRT_ operations to apply to self */
|
||||
int priorOp; /* The SRT_ operation to apply to prior selects */
|
||||
Expr *pLimit; /* Saved values of p->nLimit */
|
||||
int addr;
|
||||
SelectDest uniondest;
|
||||
|
||||
testcase( p->op==TK_EXCEPT );
|
||||
testcase( p->op==TK_UNION );
|
||||
priorOp = SRT_Union;
|
||||
if( dest.eDest==priorOp ){
|
||||
/* We can reuse a temporary table generated by a SELECT to our
|
||||
** right.
|
||||
*/
|
||||
assert( p->pLimit==0 ); /* Not allowed on leftward elements */
|
||||
unionTab = dest.iSDParm;
|
||||
}else{
|
||||
/* We will need to create our own temporary table to hold the
|
||||
** intermediate results.
|
||||
*/
|
||||
unionTab = pParse->nTab++;
|
||||
assert( p->pOrderBy==0 );
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0);
|
||||
assert( p->addrOpenEphm[0] == -1 );
|
||||
p->addrOpenEphm[0] = addr;
|
||||
findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
||||
assert( p->pEList );
|
||||
}
|
||||
|
||||
/* Code the SELECT statements to our left
|
||||
*/
|
||||
assert( p->pLimit==0 ); /* Not allowed on leftward elements */
|
||||
unionTab = dest.iSDParm;
|
||||
}else{
|
||||
/* We will need to create our own temporary table to hold the
|
||||
** intermediate results.
|
||||
assert( !pPrior->pOrderBy );
|
||||
sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
|
||||
rc = sqlite3Select(pParse, pPrior, &uniondest);
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
|
||||
/* Code the current SELECT statement
|
||||
*/
|
||||
unionTab = pParse->nTab++;
|
||||
if( p->op==TK_EXCEPT ){
|
||||
op = SRT_Except;
|
||||
}else{
|
||||
assert( p->op==TK_UNION );
|
||||
op = SRT_Union;
|
||||
}
|
||||
p->pPrior = 0;
|
||||
pLimit = p->pLimit;
|
||||
p->pLimit = 0;
|
||||
uniondest.eDest = op;
|
||||
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
|
||||
selectOpName(p->op)));
|
||||
ExplainQueryPlanSetId(pParse, p);
|
||||
rc = sqlite3Select(pParse, p, &uniondest);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
/* Query flattening in sqlite3Select() might refill p->pOrderBy.
|
||||
** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
|
||||
sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
pDelete = p->pPrior;
|
||||
p->pPrior = pPrior;
|
||||
p->pOrderBy = 0;
|
||||
if( p->op==TK_UNION ){
|
||||
p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
|
||||
}
|
||||
sqlite3ExprDelete(db, p->pLimit);
|
||||
p->pLimit = pLimit;
|
||||
p->iLimit = 0;
|
||||
p->iOffset = 0;
|
||||
|
||||
/* Convert the data in the temporary table into whatever form
|
||||
** it is that we currently need.
|
||||
*/
|
||||
assert( unionTab==dest.iSDParm || dest.eDest!=priorOp );
|
||||
if( dest.eDest!=priorOp ){
|
||||
int iCont, iBreak, iStart;
|
||||
assert( p->pEList );
|
||||
iBreak = sqlite3VdbeMakeLabel(v);
|
||||
iCont = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, iBreak);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
|
||||
iStart = sqlite3VdbeCurrentAddr(v);
|
||||
selectInnerLoop(pParse, p, unionTab,
|
||||
0, 0, &dest, iCont, iBreak);
|
||||
sqlite3VdbeResolveLabel(v, iCont);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v);
|
||||
sqlite3VdbeResolveLabel(v, iBreak);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: assert( p->op==TK_INTERSECT ); {
|
||||
int tab1, tab2;
|
||||
int iCont, iBreak, iStart;
|
||||
Expr *pLimit;
|
||||
int addr;
|
||||
SelectDest intersectdest;
|
||||
int r1;
|
||||
|
||||
/* INTERSECT is different from the others since it requires
|
||||
** two temporary tables. Hence it has its own case. Begin
|
||||
** by allocating the tables we will need.
|
||||
*/
|
||||
tab1 = pParse->nTab++;
|
||||
tab2 = pParse->nTab++;
|
||||
assert( p->pOrderBy==0 );
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0);
|
||||
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0);
|
||||
assert( p->addrOpenEphm[0] == -1 );
|
||||
p->addrOpenEphm[0] = addr;
|
||||
findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
||||
assert( p->pEList );
|
||||
}
|
||||
|
||||
/* Code the SELECT statements to our left
|
||||
*/
|
||||
assert( !pPrior->pOrderBy );
|
||||
sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
|
||||
rc = sqlite3Select(pParse, pPrior, &uniondest);
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
|
||||
/* Code the current SELECT statement
|
||||
*/
|
||||
if( p->op==TK_EXCEPT ){
|
||||
op = SRT_Except;
|
||||
}else{
|
||||
assert( p->op==TK_UNION );
|
||||
op = SRT_Union;
|
||||
}
|
||||
p->pPrior = 0;
|
||||
pLimit = p->pLimit;
|
||||
p->pLimit = 0;
|
||||
uniondest.eDest = op;
|
||||
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
|
||||
selectOpName(p->op)));
|
||||
ExplainQueryPlanSetId(pParse, p);
|
||||
rc = sqlite3Select(pParse, p, &uniondest);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
/* Query flattening in sqlite3Select() might refill p->pOrderBy.
|
||||
** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
|
||||
sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
pDelete = p->pPrior;
|
||||
p->pPrior = pPrior;
|
||||
p->pOrderBy = 0;
|
||||
if( p->op==TK_UNION ){
|
||||
p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
|
||||
}
|
||||
sqlite3ExprDelete(db, p->pLimit);
|
||||
p->pLimit = pLimit;
|
||||
p->iLimit = 0;
|
||||
p->iOffset = 0;
|
||||
|
||||
/* Convert the data in the temporary table into whatever form
|
||||
** it is that we currently need.
|
||||
*/
|
||||
assert( unionTab==dest.iSDParm || dest.eDest!=priorOp );
|
||||
if( dest.eDest!=priorOp ){
|
||||
int iCont, iBreak, iStart;
|
||||
|
||||
/* Code the SELECTs to our left into temporary table "tab1".
|
||||
*/
|
||||
sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
|
||||
rc = sqlite3Select(pParse, pPrior, &intersectdest);
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
|
||||
/* Code the current SELECT into temporary table "tab2"
|
||||
*/
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0);
|
||||
assert( p->addrOpenEphm[1] == -1 );
|
||||
p->addrOpenEphm[1] = addr;
|
||||
p->pPrior = 0;
|
||||
pLimit = p->pLimit;
|
||||
p->pLimit = 0;
|
||||
intersectdest.iSDParm = tab2;
|
||||
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
|
||||
selectOpName(p->op)));
|
||||
ExplainQueryPlanSetId(pParse, p);
|
||||
rc = sqlite3Select(pParse, p, &intersectdest);
|
||||
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;
|
||||
|
||||
/* Generate code to take the intersection of the two temporary
|
||||
** tables.
|
||||
*/
|
||||
assert( p->pEList );
|
||||
iBreak = sqlite3VdbeMakeLabel(v);
|
||||
iCont = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, iBreak);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
|
||||
iStart = sqlite3VdbeCurrentAddr(v);
|
||||
selectInnerLoop(pParse, p, unionTab,
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0);
|
||||
VdbeCoverage(v);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
selectInnerLoop(pParse, p, tab1,
|
||||
0, 0, &dest, iCont, iBreak);
|
||||
sqlite3VdbeResolveLabel(v, iCont);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v);
|
||||
sqlite3VdbeResolveLabel(v, iBreak);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, tab2, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, tab1, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: assert( p->op==TK_INTERSECT ); {
|
||||
int tab1, tab2;
|
||||
int iCont, iBreak, iStart;
|
||||
Expr *pLimit;
|
||||
int addr;
|
||||
SelectDest intersectdest;
|
||||
int r1;
|
||||
|
||||
/* INTERSECT is different from the others since it requires
|
||||
** two temporary tables. Hence it has its own case. Begin
|
||||
** by allocating the tables we will need.
|
||||
*/
|
||||
tab1 = pParse->nTab++;
|
||||
tab2 = pParse->nTab++;
|
||||
assert( p->pOrderBy==0 );
|
||||
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0);
|
||||
assert( p->addrOpenEphm[0] == -1 );
|
||||
p->addrOpenEphm[0] = addr;
|
||||
findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
||||
assert( p->pEList );
|
||||
|
||||
/* Code the SELECTs to our left into temporary table "tab1".
|
||||
*/
|
||||
sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
|
||||
rc = sqlite3Select(pParse, pPrior, &intersectdest);
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
|
||||
/* Code the current SELECT into temporary table "tab2"
|
||||
*/
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0);
|
||||
assert( p->addrOpenEphm[1] == -1 );
|
||||
p->addrOpenEphm[1] = addr;
|
||||
p->pPrior = 0;
|
||||
pLimit = p->pLimit;
|
||||
p->pLimit = 0;
|
||||
intersectdest.iSDParm = tab2;
|
||||
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
|
||||
selectOpName(p->op)));
|
||||
ExplainQueryPlanSetId(pParse, p);
|
||||
rc = sqlite3Select(pParse, p, &intersectdest);
|
||||
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;
|
||||
|
||||
/* Generate code to take the intersection of the two temporary
|
||||
** tables.
|
||||
*/
|
||||
assert( p->pEList );
|
||||
iBreak = sqlite3VdbeMakeLabel(v);
|
||||
iCont = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, iBreak);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
selectInnerLoop(pParse, p, tab1,
|
||||
0, 0, &dest, iCont, iBreak);
|
||||
sqlite3VdbeResolveLabel(v, iCont);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v);
|
||||
sqlite3VdbeResolveLabel(v, iBreak);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, tab2, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, tab1, 0);
|
||||
break;
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( p->pNext==0 ){
|
||||
ExplainQueryPlanPop(pParse);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( p->pNext==0 ){
|
||||
ExplainQueryPlanPop(pParse);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Compute collating sequences used by
|
||||
** temporary tables needed to implement the compound select.
|
||||
** Attach the KeyInfo structure to all temporary tables.
|
||||
@ -5566,7 +5572,7 @@ int sqlite3Select(
|
||||
VdbeComment((v, "%s", pItem->pTab->zName));
|
||||
pItem->addrFillSub = addrTop;
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
||||
ExplainQueryPlan((pParse, 1, "CO-ROUTINE %p", pSub));
|
||||
ExplainQueryPlan((pParse, 1, "CO-ROUTINE 0x%p", pSub));
|
||||
ExplainQueryPlanSetId(pParse, pSub);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||
@ -5606,7 +5612,7 @@ int sqlite3Select(
|
||||
pSub->nSelectRow = pPrior->pSelect->nSelectRow;
|
||||
}else{
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
ExplainQueryPlan((pParse, 1, "MATERIALIZE %p", pSub));
|
||||
ExplainQueryPlan((pParse, 1, "MATERIALIZE 0x%p", pSub));
|
||||
ExplainQueryPlanSetId(pParse,pSub);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
}
|
||||
|
@ -2823,8 +2823,7 @@ struct Select {
|
||||
#define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */
|
||||
#define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */
|
||||
#define SF_IncludeHidden 0x20000 /* Include hidden columns in output */
|
||||
#define SF_ComplexResult 0x40000 /* Result set contains subquery or function */
|
||||
|
||||
#define SF_ComplexResult 0x40000 /* Result contains subquery or function */
|
||||
|
||||
/*
|
||||
** The results of a SELECT can be distributed in several ways, as defined
|
||||
|
@ -152,7 +152,7 @@ int sqlite3WhereExplainOneScan(
|
||||
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
|
||||
sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
|
||||
if( pItem->pSelect ){
|
||||
sqlite3XPrintf(&str, " SUBQUERY %p", pItem->pSelect);
|
||||
sqlite3XPrintf(&str, " SUBQUERY 0x%p", pItem->pSelect);
|
||||
}else{
|
||||
sqlite3XPrintf(&str, " TABLE %s", pItem->zName);
|
||||
}
|
||||
|
@ -118,10 +118,10 @@ do_execsql_test analyze3-1.1.x {
|
||||
#
|
||||
do_eqp_test analyze3-1.1.2 {
|
||||
SELECT sum(y) FROM t1 WHERE x>200 AND x<300
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
|
||||
} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}
|
||||
do_eqp_test analyze3-1.1.3 {
|
||||
SELECT sum(y) FROM t1 WHERE x>0 AND x<1100
|
||||
} {0 0 0 {SCAN TABLE t1}}
|
||||
} {SCAN TABLE t1}
|
||||
|
||||
# 2017-06-26: Verify that the SQLITE_DBCONFIG_ENABLE_QPSG setting disables
|
||||
# the use of bound parameters by STAT4
|
||||
@ -131,27 +131,27 @@ unset -nocomplain l
|
||||
unset -nocomplain u
|
||||
do_eqp_test analyze3-1.1.3.100 {
|
||||
SELECT sum(y) FROM t1 WHERE x>$l AND x<$u
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
|
||||
} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}
|
||||
set l 200
|
||||
set u 300
|
||||
do_eqp_test analyze3-1.1.3.101 {
|
||||
SELECT sum(y) FROM t1 WHERE x>$l AND x<$u
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
|
||||
} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}
|
||||
set l 0
|
||||
set u 1100
|
||||
do_eqp_test analyze3-1.1.3.102 {
|
||||
SELECT sum(y) FROM t1 WHERE x>$l AND x<$u
|
||||
} {0 0 0 {SCAN TABLE t1}}
|
||||
} {SCAN TABLE t1}
|
||||
db cache flush
|
||||
sqlite3_db_config db ENABLE_QPSG 1
|
||||
do_eqp_test analyze3-1.1.3.103 {
|
||||
SELECT sum(y) FROM t1 WHERE x>$l AND x<$u
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
|
||||
} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}
|
||||
db cache flush
|
||||
sqlite3_db_config db ENABLE_QPSG 0
|
||||
do_eqp_test analyze3-1.1.3.104 {
|
||||
SELECT sum(y) FROM t1 WHERE x>$l AND x<$u
|
||||
} {0 0 0 {SCAN TABLE t1}}
|
||||
} {SCAN TABLE t1}
|
||||
|
||||
do_test analyze3-1.1.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 }
|
||||
@ -201,10 +201,10 @@ do_execsql_test analyze3-2.1.x {
|
||||
} {200 990}
|
||||
do_eqp_test analyze3-1.2.2 {
|
||||
SELECT sum(y) FROM t2 WHERE x>1 AND x<2
|
||||
} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}}
|
||||
} {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}
|
||||
do_eqp_test analyze3-1.2.3 {
|
||||
SELECT sum(y) FROM t2 WHERE x>0 AND x<99
|
||||
} {0 0 0 {SCAN TABLE t2}}
|
||||
} {SCAN TABLE t2}
|
||||
|
||||
do_test analyze3-1.2.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 }
|
||||
@ -253,10 +253,10 @@ do_execsql_test analyze3-1.3.x {
|
||||
} {99 1000}
|
||||
do_eqp_test analyze3-1.3.2 {
|
||||
SELECT sum(y) FROM t3 WHERE x>200 AND x<300
|
||||
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}}
|
||||
} {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}
|
||||
do_eqp_test analyze3-1.3.3 {
|
||||
SELECT sum(y) FROM t3 WHERE x>0 AND x<1100
|
||||
} {0 0 0 {SCAN TABLE t3}}
|
||||
} {SCAN TABLE t3}
|
||||
|
||||
do_test analyze3-1.3.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 }
|
||||
@ -308,10 +308,10 @@ do_test analyze3-2.1 {
|
||||
} {}
|
||||
do_eqp_test analyze3-2.2 {
|
||||
SELECT count(a) FROM t1 WHERE b LIKE 'a%'
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?)}}
|
||||
} {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?)}
|
||||
do_eqp_test analyze3-2.3 {
|
||||
SELECT count(a) FROM t1 WHERE b LIKE '%a'
|
||||
} {0 0 0 {SCAN TABLE t1}}
|
||||
} {SCAN TABLE t1}
|
||||
|
||||
# Return the first argument if like_match_blobs is true (the default)
|
||||
# or the second argument if not
|
||||
@ -698,11 +698,11 @@ do_test analyze3-6.1 {
|
||||
|
||||
do_eqp_test analyze3-6-3 {
|
||||
SELECT * FROM t1 WHERE a = 5 AND c = 13;
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}}
|
||||
} {SEARCH TABLE t1 USING INDEX i2 (c=?)}
|
||||
|
||||
do_eqp_test analyze3-6-2 {
|
||||
SELECT * FROM t1 WHERE a = 5 AND b > 'w' AND c = 13;
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}}
|
||||
} {SEARCH TABLE t1 USING INDEX i2 (c=?)}
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# 2015-04-20.
|
||||
|
@ -987,7 +987,8 @@ do_eqp_test 21.3 {
|
||||
reset_db
|
||||
do_execsql_test 22.0 {
|
||||
CREATE TABLE t3(a, b, c, d, PRIMARY KEY(a, b)) WITHOUT ROWID;
|
||||
}
|
||||
SELECT * FROM t3;
|
||||
} {}
|
||||
do_execsql_test 22.1 {
|
||||
WITH r(x) AS (
|
||||
SELECT 1
|
||||
@ -1055,15 +1056,11 @@ do_eqp_test 23.1 {
|
||||
-- Formerly used index i41. But i41 is not a covering index whereas
|
||||
-- the PRIMARY KEY is a covering index, and so as of 2017-10-15, the
|
||||
-- PRIMARY KEY is preferred.
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t4 USING PRIMARY KEY (c=? AND b=? AND a<?)}
|
||||
}
|
||||
} {SEARCH TABLE t4 USING PRIMARY KEY (c=? AND b=? AND a<?)}
|
||||
do_eqp_test 23.2 {
|
||||
SELECT * FROM t4 WHERE
|
||||
(e=1 AND b='xyz' AND c='zyx' AND a<'JJJ') AND f<300
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t4 USING INDEX i42 (f<?)}
|
||||
}
|
||||
} {SEARCH TABLE t4 USING INDEX i42 (f<?)}
|
||||
|
||||
do_execsql_test 24.0 {
|
||||
CREATE TABLE t5(c, d, b, e, a, PRIMARY KEY(a, b, c)) WITHOUT ROWID;
|
||||
@ -1108,33 +1105,26 @@ ifcapable stat4&&cte {
|
||||
|
||||
# Term (b<?) is estimated at 25%. Better than (a<30) but not as
|
||||
# good as (a<20).
|
||||
do_eqp_test 25.2.1 { SELECT * FROM t6 WHERE a<30 AND b<? } {
|
||||
0 0 0 {SEARCH TABLE t6 USING INDEX bb (b<?)}
|
||||
}
|
||||
do_eqp_test 25.2.2 { SELECT * FROM t6 WHERE a<20 AND b<? } {
|
||||
0 0 0 {SEARCH TABLE t6 USING INDEX aa (a<?)}
|
||||
}
|
||||
do_eqp_test 25.2.1 { SELECT * FROM t6 WHERE a<30 AND b<? } \
|
||||
{SEARCH TABLE t6 USING INDEX bb (b<?)}
|
||||
do_eqp_test 25.2.2 { SELECT * FROM t6 WHERE a<20 AND b<? } \
|
||||
{SEARCH TABLE t6 USING INDEX aa (a<?)}
|
||||
|
||||
# Term (b BETWEEN ? AND ?) is estimated at 1/64.
|
||||
do_eqp_test 25.3.1 {
|
||||
SELECT * FROM t6 WHERE a BETWEEN 5 AND 10 AND b BETWEEN ? AND ?
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)}
|
||||
}
|
||||
} {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)}
|
||||
|
||||
# Term (b BETWEEN ? AND 60) is estimated to return roughly 15 rows -
|
||||
# 60 from (b<=60) multiplied by 0.25 for the b>=? term. Better than
|
||||
# (a<20) but not as good as (a<10).
|
||||
do_eqp_test 25.4.1 {
|
||||
SELECT * FROM t6 WHERE a < 10 AND (b BETWEEN ? AND 60)
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t6 USING INDEX aa (a<?)}
|
||||
}
|
||||
} {SEARCH TABLE t6 USING INDEX aa (a<?)}
|
||||
|
||||
do_eqp_test 25.4.2 {
|
||||
SELECT * FROM t6 WHERE a < 20 AND (b BETWEEN ? AND 60)
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)}
|
||||
}
|
||||
} {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@ -1190,9 +1180,7 @@ do_execsql_test 26.1.3 {
|
||||
#
|
||||
do_eqp_test 26.1.4 {
|
||||
SELECT * FROM t1 WHERE x = 10000 AND y < 50 AND z = 444;
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1z (z=?)}
|
||||
}
|
||||
} {SEARCH TABLE t1 USING INDEX t1z (z=?)}
|
||||
|
||||
|
||||
# This test - 26.2.* - tests that another manifestation of the same problem
|
||||
@ -1241,9 +1229,7 @@ do_execsql_test 26.2.1 {
|
||||
|
||||
do_eqp_test 26.2.2 {
|
||||
SELECT * FROM t1 WHERE x='B' AND y>25 AND z=?;
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x=? AND y>?)}
|
||||
}
|
||||
} {SEARCH TABLE t1 USING INDEX i1 (x=? AND y>?)}
|
||||
|
||||
|
||||
finish_test
|
||||
|
428
test/eqp.test
428
test/eqp.test
@ -43,78 +43,102 @@ do_execsql_test 1.1 {
|
||||
do_eqp_test 1.2 {
|
||||
SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2;
|
||||
} {
|
||||
0 0 1 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
|
||||
0 0 1 {SEARCH TABLE t1 USING INDEX i2 (b=?)}
|
||||
0 1 0 {SCAN TABLE t2}
|
||||
QUERY PLAN
|
||||
|--SEARCH TABLE t1 USING INDEX i1 (a=?)
|
||||
|--SEARCH TABLE t1 USING INDEX i2 (b=?)
|
||||
`--SCAN TABLE t2
|
||||
}
|
||||
do_eqp_test 1.3 {
|
||||
SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t2}
|
||||
0 1 1 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
|
||||
0 1 1 {SEARCH TABLE t1 USING INDEX i2 (b=?)}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t2
|
||||
|--SEARCH TABLE t1 USING INDEX i1 (a=?)
|
||||
`--SEARCH TABLE t1 USING INDEX i2 (b=?)
|
||||
}
|
||||
do_eqp_test 1.3 {
|
||||
SELECT a FROM t1 ORDER BY a
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}
|
||||
QUERY PLAN
|
||||
`--SCAN TABLE t1 USING COVERING INDEX i1
|
||||
}
|
||||
do_eqp_test 1.4 {
|
||||
SELECT a FROM t1 ORDER BY +a
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1 USING COVERING INDEX i1
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
do_eqp_test 1.5 {
|
||||
SELECT a FROM t1 WHERE a=4
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}
|
||||
QUERY PLAN
|
||||
`--SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)
|
||||
}
|
||||
do_eqp_test 1.6 {
|
||||
SELECT DISTINCT count(*) FROM t3 GROUP BY a;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t3}
|
||||
0 0 0 {USE TEMP B-TREE FOR GROUP BY}
|
||||
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t3
|
||||
|--USE TEMP B-TREE FOR GROUP BY
|
||||
`--USE TEMP B-TREE FOR DISTINCT
|
||||
}
|
||||
|
||||
do_eqp_test 1.7 {
|
||||
SELECT * FROM t3 JOIN (SELECT 1)
|
||||
} {
|
||||
0 0 1 {SCAN SUBQUERY 1}
|
||||
0 1 0 {SCAN TABLE t3}
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE xxxxxx
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
`--SCAN TABLE t3
|
||||
}
|
||||
do_eqp_test 1.8 {
|
||||
SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2)
|
||||
} {
|
||||
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)}
|
||||
0 0 1 {SCAN SUBQUERY 1}
|
||||
0 1 0 {SCAN TABLE t3}
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE xxxxxx
|
||||
| `--COMPOUND QUERY
|
||||
| |--LEFT-MOST SUBQUERY
|
||||
| `--UNION USING TEMP B-TREE
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
`--SCAN TABLE t3
|
||||
}
|
||||
do_eqp_test 1.9 {
|
||||
SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17)
|
||||
} {
|
||||
3 0 0 {SCAN TABLE t3}
|
||||
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (EXCEPT)}
|
||||
0 0 1 {SCAN SUBQUERY 1}
|
||||
0 1 0 {SCAN TABLE t3}
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE xxxxxx
|
||||
| `--COMPOUND QUERY
|
||||
| |--LEFT-MOST SUBQUERY
|
||||
| `--EXCEPT USING TEMP B-TREE
|
||||
| `--SCAN TABLE t3
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
`--SCAN TABLE t3
|
||||
}
|
||||
do_eqp_test 1.10 {
|
||||
SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17)
|
||||
} {
|
||||
3 0 0 {SCAN TABLE t3}
|
||||
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (INTERSECT)}
|
||||
0 0 1 {SCAN SUBQUERY 1}
|
||||
0 1 0 {SCAN TABLE t3}
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE xxxxxx
|
||||
| `--COMPOUND QUERY
|
||||
| |--LEFT-MOST SUBQUERY
|
||||
| `--INTERSECT USING TEMP B-TREE
|
||||
| `--SCAN TABLE t3
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
`--SCAN TABLE t3
|
||||
}
|
||||
|
||||
do_eqp_test 1.11 {
|
||||
SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17)
|
||||
} {
|
||||
3 0 0 {SCAN TABLE t3}
|
||||
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 (UNION ALL)}
|
||||
0 0 1 {SCAN SUBQUERY 1}
|
||||
0 1 0 {SCAN TABLE t3}
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE xxxxxx
|
||||
| `--COMPOUND QUERY
|
||||
| |--LEFT-MOST SUBQUERY
|
||||
| `--UNION ALL
|
||||
| `--SCAN TABLE t3
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
`--SCAN TABLE t3
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@ -129,48 +153,58 @@ do_execsql_test 2.1 {
|
||||
}
|
||||
|
||||
det 2.2.1 "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 0 0 {USE TEMP B-TREE FOR GROUP BY}
|
||||
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
|--USE TEMP B-TREE FOR GROUP BY
|
||||
|--USE TEMP B-TREE FOR DISTINCT
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
det 2.2.2 "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1" {
|
||||
0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
|
||||
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t2 USING COVERING INDEX t2i1
|
||||
|--USE TEMP B-TREE FOR DISTINCT
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
det 2.2.3 "SELECT DISTINCT * FROM t1" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
`--USE TEMP B-TREE FOR DISTINCT
|
||||
}
|
||||
det 2.2.4 "SELECT DISTINCT * FROM t1, t2" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SCAN TABLE t2}
|
||||
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
|--SCAN TABLE t2
|
||||
`--USE TEMP B-TREE FOR DISTINCT
|
||||
}
|
||||
det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SCAN TABLE t2}
|
||||
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
|--SCAN TABLE t2
|
||||
|--USE TEMP B-TREE FOR DISTINCT
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
det 2.2.6 "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x" {
|
||||
0 0 1 {SCAN TABLE t2 USING COVERING INDEX t2i1}
|
||||
0 1 0 {SCAN TABLE t1}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t2 USING COVERING INDEX t2i1
|
||||
`--SCAN TABLE t1
|
||||
}
|
||||
|
||||
det 2.3.1 "SELECT max(x) FROM t2" {
|
||||
0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1}
|
||||
QUERY PLAN
|
||||
`--SEARCH TABLE t2 USING COVERING INDEX t2i1
|
||||
}
|
||||
det 2.3.2 "SELECT min(x) FROM t2" {
|
||||
0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1}
|
||||
QUERY PLAN
|
||||
`--SEARCH TABLE t2 USING COVERING INDEX t2i1
|
||||
}
|
||||
det 2.3.3 "SELECT min(x), max(x) FROM t2" {
|
||||
0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
|
||||
QUERY PLAN
|
||||
`--SCAN TABLE t2 USING COVERING INDEX t2i1
|
||||
}
|
||||
|
||||
det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" {
|
||||
0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
QUERY PLAN
|
||||
`--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
}
|
||||
|
||||
|
||||
@ -181,40 +215,46 @@ det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" {
|
||||
do_eqp_test 3.1.1 {
|
||||
SELECT (SELECT x FROM t1 AS sub) FROM t1;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
|
||||
1 0 0 {SCAN TABLE t1 AS sub}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
`--SCALAR SUBQUERY
|
||||
`--SCAN TABLE t1 AS sub
|
||||
}
|
||||
do_eqp_test 3.1.2 {
|
||||
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
|
||||
1 0 0 {SCAN TABLE t1 AS sub}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
`--SCALAR SUBQUERY
|
||||
`--SCAN TABLE t1 AS sub
|
||||
}
|
||||
do_eqp_test 3.1.3 {
|
||||
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
|
||||
1 0 0 {SCAN TABLE t1 AS sub}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
`--SCALAR SUBQUERY
|
||||
|--SCAN TABLE t1 AS sub
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
do_eqp_test 3.1.4 {
|
||||
SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
|
||||
1 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
`--SCALAR SUBQUERY
|
||||
`--SCAN TABLE t2 USING COVERING INDEX t2i1
|
||||
}
|
||||
|
||||
det 3.2.1 {
|
||||
SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
0 0 0 {SCAN SUBQUERY 1}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
QUERY PLAN
|
||||
|--CO-ROUTINE xxxxxx
|
||||
| |--SCAN TABLE t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
det 3.2.2 {
|
||||
SELECT * FROM
|
||||
@ -222,34 +262,40 @@ det 3.2.2 {
|
||||
(SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2
|
||||
ORDER BY x2.y LIMIT 5
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
0 0 0 {SCAN SUBQUERY 1 AS x1}
|
||||
0 1 1 {SCAN SUBQUERY 2 AS x2}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE xxxxxx
|
||||
| |--SCAN TABLE t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
|--MATERIALIZE xxxxxx
|
||||
| `--SCAN TABLE t2 USING INDEX t2i1
|
||||
|--SCAN SUBQUERY xxxxxx AS x1
|
||||
|--SCAN SUBQUERY xxxxxx AS x2
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
|
||||
det 3.3.1 {
|
||||
SELECT * FROM t1 WHERE y IN (SELECT y FROM t2)
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 0 0 {EXECUTE LIST SUBQUERY 1}
|
||||
1 0 0 {SCAN TABLE t2}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
`--LIST SUBQUERY
|
||||
`--SCAN TABLE t2
|
||||
}
|
||||
det 3.3.2 {
|
||||
SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x)
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1}
|
||||
1 0 0 {SCAN TABLE t2}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
`--CORRELATED LIST SUBQUERY
|
||||
`--SCAN TABLE t2
|
||||
}
|
||||
det 3.3.3 {
|
||||
SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x)
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 1}
|
||||
1 0 0 {SCAN TABLE t2}
|
||||
QUERY PLAN
|
||||
|--SCAN TABLE t1
|
||||
`--CORRELATED SCALAR SUBQUERY
|
||||
`--SCAN TABLE t2
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@ -258,119 +304,158 @@ det 3.3.3 {
|
||||
do_eqp_test 4.1.1 {
|
||||
SELECT * FROM t1 UNION ALL SELECT * FROM t2
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)}
|
||||
QUERY PLAN
|
||||
`--COMPOUND QUERY
|
||||
|--LEFT-MOST SUBQUERY
|
||||
| `--SCAN TABLE t1
|
||||
`--UNION ALL
|
||||
`--SCAN TABLE t2
|
||||
}
|
||||
do_eqp_test 4.1.2 {
|
||||
SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)}
|
||||
QUERY PLAN
|
||||
`--MERGE (UNION ALL)
|
||||
|--LEFT
|
||||
| |--SCAN TABLE t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
`--RIGHT
|
||||
|--SCAN TABLE t2
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
do_eqp_test 4.1.3 {
|
||||
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)}
|
||||
QUERY PLAN
|
||||
`--MERGE (UNION)
|
||||
|--LEFT
|
||||
| |--SCAN TABLE t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
`--RIGHT
|
||||
|--SCAN TABLE t2
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
do_eqp_test 4.1.4 {
|
||||
SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)}
|
||||
QUERY PLAN
|
||||
`--MERGE (INTERSECT)
|
||||
|--LEFT
|
||||
| |--SCAN TABLE t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
`--RIGHT
|
||||
|--SCAN TABLE t2
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
do_eqp_test 4.1.5 {
|
||||
SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
|
||||
QUERY PLAN
|
||||
`--MERGE (EXCEPT)
|
||||
|--LEFT
|
||||
| |--SCAN TABLE t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
`--RIGHT
|
||||
|--SCAN TABLE t2
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
|
||||
do_eqp_test 4.2.2 {
|
||||
SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 1
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)}
|
||||
QUERY PLAN
|
||||
`--MERGE (UNION ALL)
|
||||
|--LEFT
|
||||
| |--SCAN TABLE t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
`--RIGHT
|
||||
`--SCAN TABLE t2 USING INDEX t2i1
|
||||
}
|
||||
do_eqp_test 4.2.3 {
|
||||
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)}
|
||||
QUERY PLAN
|
||||
`--MERGE (UNION)
|
||||
|--LEFT
|
||||
| |--SCAN TABLE t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
`--RIGHT
|
||||
|--SCAN TABLE t2 USING INDEX t2i1
|
||||
`--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
|
||||
}
|
||||
do_eqp_test 4.2.4 {
|
||||
SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 1
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)}
|
||||
QUERY PLAN
|
||||
`--MERGE (INTERSECT)
|
||||
|--LEFT
|
||||
| |--SCAN TABLE t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
`--RIGHT
|
||||
|--SCAN TABLE t2 USING INDEX t2i1
|
||||
`--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
|
||||
}
|
||||
do_eqp_test 4.2.5 {
|
||||
SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 1
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
|
||||
QUERY PLAN
|
||||
`--MERGE (EXCEPT)
|
||||
|--LEFT
|
||||
| |--SCAN TABLE t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
`--RIGHT
|
||||
|--SCAN TABLE t2 USING INDEX t2i1
|
||||
`--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
|
||||
}
|
||||
|
||||
do_eqp_test 4.3.1 {
|
||||
SELECT x FROM t1 UNION SELECT x FROM t2
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
2 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)}
|
||||
QUERY PLAN
|
||||
`--COMPOUND QUERY
|
||||
|--LEFT-MOST SUBQUERY
|
||||
| `--SCAN TABLE t1
|
||||
`--UNION USING TEMP B-TREE
|
||||
`--SCAN TABLE t2 USING COVERING INDEX t2i1
|
||||
}
|
||||
|
||||
do_eqp_test 4.3.2 {
|
||||
SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1
|
||||
} {
|
||||
2 0 0 {SCAN TABLE t1}
|
||||
3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
|
||||
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)}
|
||||
4 0 0 {SCAN TABLE t1}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 4 USING TEMP B-TREE (UNION)}
|
||||
QUERY PLAN
|
||||
`--COMPOUND QUERY
|
||||
|--LEFT-MOST SUBQUERY
|
||||
| `--SCAN TABLE t1
|
||||
|--UNION USING TEMP B-TREE
|
||||
| `--SCAN TABLE t2 USING COVERING INDEX t2i1
|
||||
`--UNION USING TEMP B-TREE
|
||||
`--SCAN TABLE t1
|
||||
}
|
||||
do_eqp_test 4.3.3 {
|
||||
SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 ORDER BY 1
|
||||
} {
|
||||
2 0 0 {SCAN TABLE t1}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
|
||||
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 (UNION)}
|
||||
4 0 0 {SCAN TABLE t1}
|
||||
4 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 4 (UNION)}
|
||||
QUERY PLAN
|
||||
`--MERGE (UNION)
|
||||
|--LEFT
|
||||
| `--MERGE (UNION)
|
||||
| |--LEFT
|
||||
| | |--SCAN TABLE t1
|
||||
| | `--USE TEMP B-TREE FOR ORDER BY
|
||||
| `--RIGHT
|
||||
| `--SCAN TABLE t2 USING COVERING INDEX t2i1
|
||||
`--RIGHT
|
||||
|--SCAN TABLE t1
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
|
||||
if 0 {
|
||||
#-------------------------------------------------------------------------
|
||||
# This next block of tests verifies that the examples on the
|
||||
# lang_explain.html page are correct.
|
||||
#
|
||||
drop_all_tables
|
||||
|
||||
# EVIDENCE-OF: R-47779-47605 sqlite> EXPLAIN QUERY PLAN SELECT a, b
|
||||
# XVIDENCE-OF: R-47779-47605 sqlite> EXPLAIN QUERY PLAN SELECT a, b
|
||||
# FROM t1 WHERE a=1;
|
||||
# 0|0|0|SCAN TABLE t1
|
||||
#
|
||||
@ -379,7 +464,7 @@ det 5.1.1 "SELECT a, b FROM t1 WHERE a=1" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-55852-17599 sqlite> CREATE INDEX i1 ON t1(a);
|
||||
# XVIDENCE-OF: R-55852-17599 sqlite> CREATE INDEX i1 ON t1(a);
|
||||
# sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1;
|
||||
# 0|0|0|SEARCH TABLE t1 USING INDEX i1
|
||||
#
|
||||
@ -388,7 +473,7 @@ det 5.2.1 "SELECT a, b FROM t1 WHERE a=1" {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-21179-11011 sqlite> CREATE INDEX i2 ON t1(a, b);
|
||||
# XVIDENCE-OF: R-21179-11011 sqlite> CREATE INDEX i2 ON t1(a, b);
|
||||
# sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1;
|
||||
# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)
|
||||
#
|
||||
@ -397,7 +482,7 @@ det 5.3.1 "SELECT a, b FROM t1 WHERE a=1" {
|
||||
0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-09991-48941 sqlite> EXPLAIN QUERY PLAN
|
||||
# XVIDENCE-OF: R-09991-48941 sqlite> EXPLAIN QUERY PLAN
|
||||
# SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2;
|
||||
# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)
|
||||
# 0|1|1|SCAN TABLE t2
|
||||
@ -408,7 +493,7 @@ det 5.4.1 "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2" {
|
||||
0 1 1 {SCAN TABLE t2}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-33626-61085 sqlite> EXPLAIN QUERY PLAN
|
||||
# XVIDENCE-OF: R-33626-61085 sqlite> EXPLAIN QUERY PLAN
|
||||
# SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2;
|
||||
# 0|0|1|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)
|
||||
# 0|1|0|SCAN TABLE t2
|
||||
@ -418,7 +503,7 @@ det 5.5 "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2" {
|
||||
0 1 0 {SCAN TABLE t2}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-04002-25654 sqlite> CREATE INDEX i3 ON t1(b);
|
||||
# XVIDENCE-OF: R-04002-25654 sqlite> CREATE INDEX i3 ON t1(b);
|
||||
# sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2;
|
||||
# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)
|
||||
# 0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?)
|
||||
@ -429,7 +514,7 @@ det 5.6.1 "SELECT a, b FROM t1 WHERE a=1 OR b=2" {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-24577-38891 sqlite> EXPLAIN QUERY PLAN
|
||||
# XVIDENCE-OF: R-24577-38891 sqlite> EXPLAIN QUERY PLAN
|
||||
# SELECT c, d FROM t2 ORDER BY c;
|
||||
# 0|0|0|SCAN TABLE t2
|
||||
# 0|0|0|USE TEMP B-TREE FOR ORDER BY
|
||||
@ -439,7 +524,7 @@ det 5.7 "SELECT c, d FROM t2 ORDER BY c" {
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-58157-12355 sqlite> CREATE INDEX i4 ON t2(c);
|
||||
# XVIDENCE-OF: R-58157-12355 sqlite> CREATE INDEX i4 ON t2(c);
|
||||
# sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c;
|
||||
# 0|0|0|SCAN TABLE t2 USING INDEX i4
|
||||
#
|
||||
@ -448,7 +533,7 @@ det 5.8.1 "SELECT c, d FROM t2 ORDER BY c" {
|
||||
0 0 0 {SCAN TABLE t2 USING INDEX i4}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-13931-10421 sqlite> EXPLAIN QUERY PLAN SELECT
|
||||
# XVIDENCE-OF: R-13931-10421 sqlite> EXPLAIN QUERY PLAN SELECT
|
||||
# (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2;
|
||||
# 0|0|0|SCAN TABLE t2
|
||||
# 0|0|0|EXECUTE SCALAR SUBQUERY 1
|
||||
@ -466,7 +551,7 @@ det 5.9 {
|
||||
2 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-50892-45943 sqlite> EXPLAIN QUERY PLAN
|
||||
# XVIDENCE-OF: R-50892-45943 sqlite> EXPLAIN QUERY PLAN
|
||||
# SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x;
|
||||
# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2
|
||||
# 0|0|0|SCAN SUBQUERY 1
|
||||
@ -480,7 +565,7 @@ det 5.10 {
|
||||
0 0 0 {USE TEMP B-TREE FOR GROUP BY}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-46219-33846 sqlite> EXPLAIN QUERY PLAN
|
||||
# XVIDENCE-OF: R-46219-33846 sqlite> EXPLAIN QUERY PLAN
|
||||
# SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1;
|
||||
# 0|0|0|SEARCH TABLE t2 USING INDEX i4 (c=?)
|
||||
# 0|1|1|SCAN TABLE t1
|
||||
@ -490,7 +575,7 @@ det 5.11 "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1" {
|
||||
0 1 1 {SCAN TABLE t1 USING COVERING INDEX i2}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-37879-39987 sqlite> EXPLAIN QUERY PLAN
|
||||
# XVIDENCE-OF: R-37879-39987 sqlite> EXPLAIN QUERY PLAN
|
||||
# SELECT a FROM t1 UNION SELECT c FROM t2;
|
||||
# 1|0|0|SCAN TABLE t1
|
||||
# 2|0|0|SCAN TABLE t2
|
||||
@ -502,7 +587,7 @@ det 5.12 "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2" {
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-44864-63011 sqlite> EXPLAIN QUERY PLAN
|
||||
# XVIDENCE-OF: R-44864-63011 sqlite> EXPLAIN QUERY PLAN
|
||||
# SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1;
|
||||
# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2
|
||||
# 2|0|0|SCAN TABLE t2 2|0|0|USE TEMP B-TREE FOR ORDER BY
|
||||
@ -515,7 +600,6 @@ det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" {
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
|
||||
}
|
||||
|
||||
|
||||
if {![nonzero_reserved_bytes]} {
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests - eqp-6.* - test that the example C code on
|
||||
@ -557,6 +641,7 @@ if {![nonzero_reserved_bytes]} {
|
||||
0 0 0 COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests - eqp-7.* - test that queries that use the OP_Count
|
||||
@ -571,11 +656,13 @@ do_execsql_test 7.0 {
|
||||
}
|
||||
|
||||
det 7.1 "SELECT count(*) FROM t1" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
QUERY PLAN
|
||||
`--SCAN TABLE t1
|
||||
}
|
||||
|
||||
det 7.2 "SELECT count(*) FROM t2" {
|
||||
0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1}
|
||||
QUERY PLAN
|
||||
`--SCAN TABLE t2 USING COVERING INDEX i1
|
||||
}
|
||||
|
||||
do_execsql_test 7.3 {
|
||||
@ -593,11 +680,13 @@ db close
|
||||
sqlite3 db test.db
|
||||
|
||||
det 7.4 "SELECT count(*) FROM t1" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
QUERY PLAN
|
||||
`--SCAN TABLE t1
|
||||
}
|
||||
|
||||
det 7.5 "SELECT count(*) FROM t2" {
|
||||
0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1}
|
||||
QUERY PLAN
|
||||
`--SCAN TABLE t2 USING COVERING INDEX i1
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@ -612,31 +701,38 @@ do_execsql_test 8.0 {
|
||||
}
|
||||
|
||||
det 8.1.1 "SELECT * FROM t2" {
|
||||
0 0 0 {SCAN TABLE t2}
|
||||
QUERY PLAN
|
||||
`--SCAN TABLE t2
|
||||
}
|
||||
|
||||
det 8.1.2 "SELECT * FROM t2 WHERE rowid=?" {
|
||||
0 0 0 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
QUERY PLAN
|
||||
`--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
}
|
||||
|
||||
det 8.1.3 "SELECT count(*) FROM t2" {
|
||||
0 0 0 {SCAN TABLE t2}
|
||||
QUERY PLAN
|
||||
`--SCAN TABLE t2
|
||||
}
|
||||
|
||||
det 8.2.1 "SELECT * FROM t1" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
QUERY PLAN
|
||||
`--SCAN TABLE t1
|
||||
}
|
||||
|
||||
det 8.2.2 "SELECT * FROM t1 WHERE b=?" {
|
||||
0 0 0 {SEARCH TABLE t1 USING PRIMARY KEY (b=?)}
|
||||
QUERY PLAN
|
||||
`--SEARCH TABLE t1 USING PRIMARY KEY (b=?)
|
||||
}
|
||||
|
||||
det 8.2.3 "SELECT * FROM t1 WHERE b=? AND c=?" {
|
||||
0 0 0 {SEARCH TABLE t1 USING PRIMARY KEY (b=? AND c=?)}
|
||||
QUERY PLAN
|
||||
`--SEARCH TABLE t1 USING PRIMARY KEY (b=? AND c=?)
|
||||
}
|
||||
|
||||
det 8.2.4 "SELECT count(*) FROM t1" {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
QUERY PLAN
|
||||
`--SCAN TABLE t1
|
||||
}
|
||||
|
||||
|
||||
|
@ -959,10 +959,81 @@ proc do_timed_execsql_test {testname sql {result {}}} {
|
||||
uplevel do_test [list $testname] [list "execsql_timed {$sql}"]\
|
||||
[list [list {*}$result]]
|
||||
}
|
||||
proc do_eqp_test {name sql res} {
|
||||
uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res]
|
||||
|
||||
# Run an EXPLAIN QUERY PLAN $sql in database "db". Then rewrite the output
|
||||
# as an ASCII-art graph and return a string that is that graph.
|
||||
#
|
||||
# Hexadecimal literals in the output text are converted into "xxxxxx" since those
|
||||
# literals are pointer values that might very from one run of the test to the
|
||||
# next, yet we want the output to be consistent.
|
||||
#
|
||||
proc query_plan_graph {sql} {
|
||||
db eval "EXPLAIN QUERY PLAN $sql" {
|
||||
set dx($id) $detail
|
||||
lappend cx($parent) $id
|
||||
}
|
||||
set a "\n QUERY PLAN\n"
|
||||
append a [append_graph " " dx cx 0]
|
||||
return [regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx}]
|
||||
}
|
||||
|
||||
# Helper routine for [query_plan_graph SQL]:
|
||||
#
|
||||
# Output rows of the graph that are children of $level.
|
||||
#
|
||||
# prefix: Prepend to every output line
|
||||
#
|
||||
# dxname: Name of an array variable that stores text describe
|
||||
# The description for $id is $dx($id)
|
||||
#
|
||||
# cxname: Name of an array variable holding children of item.
|
||||
# Children of $id are $cx($id)
|
||||
#
|
||||
# level: Render all lines that are children of $level
|
||||
#
|
||||
proc append_graph {prefix dxname cxname level} {
|
||||
upvar $dxname dx $cxname cx
|
||||
set a ""
|
||||
set x $cx($level)
|
||||
set n [llength $x]
|
||||
for {set i 0} {$i<$n} {incr i} {
|
||||
set id [lindex $x $i]
|
||||
if {$i==$n-1} {
|
||||
set p1 "`--"
|
||||
set p2 " "
|
||||
} else {
|
||||
set p1 "|--"
|
||||
set p2 "| "
|
||||
}
|
||||
append a $prefix$p1$dx($id)\n
|
||||
if {[info exists cx($id)]} {
|
||||
append a [append_graph "$prefix$p2" dx cx $id]
|
||||
}
|
||||
}
|
||||
return $a
|
||||
}
|
||||
|
||||
# Do an EXPLAIN QUERY PLAN test on input $sql with expected results $res
|
||||
#
|
||||
# If $res begins with a "\s+QUERY PLAN\n" then it is assumed to be the
|
||||
# complete graph which must match the output of [query_plan_graph $sql]
|
||||
# exactly.
|
||||
#
|
||||
# If $res does not begin with "\s+QUERY PLAN\n" then take it is a string
|
||||
# that must be found somewhere in the query plan output.
|
||||
#
|
||||
proc do_eqp_test {name sql res} {
|
||||
if {[regexp {^\s+QUERY PLAN\n} $res]} {
|
||||
uplevel do_test $name [list [list query_plan_graph $sql]] [list $res]
|
||||
} else {
|
||||
if {[string index $res 0]!="/"} {
|
||||
set res "/*$res*/"
|
||||
}
|
||||
uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Usage: do_select_tests PREFIX ?SWITCHES? TESTLIST
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user