Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb4e3f8348 | |||
| 3aeec23c29 | |||
| 9da8bf9ae7 | |||
| 3a907ce696 | |||
| b792d9ef4c | |||
| 23a09adc0b | |||
| 1adf686f0c | |||
| 607e10998d | |||
| b3785b8322 | |||
| 80354c6630 | |||
| 66d89de8b4 | |||
| 4427e597b2 | |||
| b5c7f2f235 |
@@ -1,5 +1,5 @@
|
||||
C Version\s3.8.9
|
||||
D 2015-04-08T12:16:33.323
|
||||
C When\schecking\sfor\sthe\sWHERE-clause\spush-down\soptimization,\sverify\sthat\nall\sterms\sof\sthe\scompound\sinner\sSELECT\sare\snon-aggregate,\snot\sjust\sthe\nlast\sterm.\s\sFix\sfor\sticket\s[f7f8c97e97597].
|
||||
D 2017-07-17T19:25:10.921
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 00d12636df7a5b08af09116bcd6c7bfd49b8b3b4
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -167,7 +167,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c d23d6b6991f66b383934f137fd4384d93fb98c81
|
||||
F src/analyze.c 91540f835163d5369ccbae78e2e6c74d0dd53c1d
|
||||
F src/analyze.c 92d7ab85ded7d16f424ee388d250bd99c64302de
|
||||
F src/attach.c 880f9b8641a829c563e52dd13c452ce457ae4dd8
|
||||
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3
|
||||
@@ -176,7 +176,7 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
|
||||
F src/btree.c 2caf598165f3608fde8abac2b243826616ce54b7
|
||||
F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1
|
||||
F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4
|
||||
F src/build.c 0419bba592c22f6d00e6d57a2ca7136720d02c1a
|
||||
F src/build.c 3d1abf90ecf488d49eb0c0a673a9b1f22b3ef4e81b1bffa6cf3dfdb832125d3c
|
||||
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
|
||||
F src/complete.c 198a0066ba60ab06fc00fba1998d870a4d575463
|
||||
F src/ctime.c 98f89724adc891a1a4c655bee04e33e716e05887
|
||||
@@ -230,12 +230,12 @@ F src/printf.c 8ae1fa9d30c1200a9268a390ba9e9cea9197b27a
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c 41aa91af56d960e9414ce1d7c17cfb68e0d1c6cb
|
||||
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
|
||||
F src/select.c c28c52e353287434fac8473e56ee4be848d12c9d
|
||||
F src/select.c 7922b1e1aaceb8eea4b921d0e6d062e32cfef8d897c6b30015fdd546c9b9f57f
|
||||
F src/shell.c 84a1593bd86aaa14f4da8a8f9b16fbc239d262aa
|
||||
F src/sqlite.h.in 278602140d49575e8708e643161f4263e428a02a
|
||||
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
|
||||
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
|
||||
F src/sqliteInt.h 107b02ed6c64162b653acc2368e982de529e14f6
|
||||
F src/sqliteInt.h 3b055fff776a257d0b2473edec5e121db8724c51c1034452c1be3b0faaf02f45
|
||||
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
|
||||
F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
|
||||
F src/table.c e7a09215315a978057fb42c640f890160dbcc45e
|
||||
@@ -293,11 +293,11 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13
|
||||
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
|
||||
F src/util.c 98a7627ca48ad3265b6940915a1d08355eb3fc7e
|
||||
F src/vacuum.c 9460b9de7b2d4e34b0d374894aa6c8a0632be8ec
|
||||
F src/vdbe.c 86ae6f4774410868af41bd839b72b7081ff03e78
|
||||
F src/vdbe.c 1e2abdaedcbd3697994c4f244ae388b2afbe1e1023537a78abdf0bbf70ef23a7
|
||||
F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3
|
||||
F src/vdbeInt.h 9cbaa84f53ddd2d09a0cf61a94337a3a035d08a0
|
||||
F src/vdbeInt.h d96370101d9109cc476b42951272bd660336a638a6b8ef0d72c0911d6cdffbfd
|
||||
F src/vdbeapi.c 583d56b129dd27f12bed518270de9ebe521e6a75
|
||||
F src/vdbeaux.c 413dc496248ac18eb0c19e35e86bb1ffd47b8907
|
||||
F src/vdbeaux.c c562ac4e1d5803287f5ad2718460eb7e1f22b8356b22603f67f6b849056465e1
|
||||
F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90
|
||||
F src/vdbemem.c c0dc81285b7571b0a31c40f17846fe2397ec1cd9
|
||||
F src/vdbesort.c 919717d7599fa31d343ec28bffd0f9e91a4ff5f6
|
||||
@@ -307,8 +307,8 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
|
||||
F src/wal.c 878c8e1a51cb2ec45c395d26b7d5cd9e1a098e4a
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
||||
F src/where.c 85d832efa5ef57de542db7f430b72fecd3af8b38
|
||||
F src/whereInt.h cbe4aa57326998d89e7698ca65bb7c28541d483c
|
||||
F src/where.c 5e7cf96bd85f5e7cee1cce001031bc0ca1af68b8cfd07c781d1d8da7796eab34
|
||||
F src/whereInt.h 1d1fd0b3b9b56e08f5d3583c70a2c785a3c43941
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
|
||||
@@ -683,7 +683,7 @@ F test/join.test 52d4d49f86d0cf46926672878c4eaf0da399104a
|
||||
F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/join5.test 5df23eba184f159ed9705a954957e765a10c141d
|
||||
F test/join5.test 8a5c0be6f0c260a5c7177c3b8f07c7856141038a
|
||||
F test/join6.test cfe6503791ceb0cbb509966740286ec423cbf10b
|
||||
F test/journal1.test 69abc726c51b4a0409189f9a85191205297c0577
|
||||
F test/journal2.test ae06f566c28552c313ded3fee79a6c69e6d049b1
|
||||
@@ -698,6 +698,7 @@ F test/like.test 4f2a71d36a536233727f71995fef900756705e56
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
F test/like3.test 7b0525a39e4f25c4fd113de7e2e28eb712dcdedf
|
||||
F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e
|
||||
F test/limit2.test 7e7744cc548d7e4c92e1dd3edc30dd0f86adafd5
|
||||
F test/loadext.test 648cb95f324d1775c54a55c12271b2d1156b633b
|
||||
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
|
||||
F test/lock.test b984ab9034e7389be0d863fe4e64cbbc4d2028f5
|
||||
@@ -771,7 +772,7 @@ F test/notnull.test f8fcf58669ddba79274daa2770d61dfad8274f62
|
||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||
F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
|
||||
F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
|
||||
F test/orderby1.test eb246e377612b21a418fbea57047ba8ea88aaa6b
|
||||
F test/orderby1.test 66ca14d7860a2da02411106968afee910ab1e657
|
||||
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
|
||||
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
|
||||
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
|
||||
@@ -839,7 +840,7 @@ F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/select1.test fc2a61f226a649393664ad54bc5376631801517c
|
||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||
F test/select4.test e20e8ce47b558de80616102ef273704cf0d48a3b
|
||||
F test/select4.test ddcaffe16252e84b85550d775b7a03bcf0d390b688122ca653d7199e469e3d5e
|
||||
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
|
||||
F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0
|
||||
F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d
|
||||
@@ -1171,7 +1172,7 @@ F test/where9.test 729c3ba9b47e8f9f1aab96bae7dad2a524f1d1a2
|
||||
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
|
||||
F test/whereD.test fd9120e262f9da3c45940f52aefeef4d15b904e5
|
||||
F test/whereD.test ac6926e3f518d5b75b61e81c2b7c327565e07a4bd919b6c5c3a003ca0cf19021
|
||||
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
|
||||
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||
F test/whereG.test 69f5ec4b15760a8c860f80e2d55525669390aab3
|
||||
@@ -1249,10 +1250,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 8e4ac2ce24415926247961b00a62425ae85d6ffb
|
||||
R 5875861747bb686954783d9ce4259b86
|
||||
T +bgcolor * #d0c0ff
|
||||
T +sym-release *
|
||||
T +sym-version-3.8.9 *
|
||||
P 52674f948c3e74e5cc32874d4885f2302ad1d5dd0bc45ff6bfda18cf4bea904a
|
||||
Q +ec215f94ac9748c0acd82af0cc9e7a92249462f9
|
||||
R a908a996bcff610704d1aca2821ce465
|
||||
U drh
|
||||
Z 05045ab8d5dbbaefca88cc23b8dca09c
|
||||
Z 30ce9b14a61bc1a1adc0dcec2dba7a8c
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
8a8ffc862e96f57aa698f93de10dee28e69f6e09
|
||||
adc082c1461e0237cd42653b529fbc136f5899baeff6ee32ee943d76184080c1
|
||||
+1
-1
@@ -1619,7 +1619,7 @@ static void initAvgEq(Index *pIdx){
|
||||
}
|
||||
}
|
||||
|
||||
if( nDist100>nSum100 ){
|
||||
if( nDist100>nSum100 && sumEq<nRow ){
|
||||
avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100);
|
||||
}
|
||||
if( avgEq==0 ) avgEq = 1;
|
||||
|
||||
@@ -949,7 +949,11 @@ void sqlite3StartTable(
|
||||
pTable->iPKey = -1;
|
||||
pTable->pSchema = db->aDb[iDb].pSchema;
|
||||
pTable->nRef = 1;
|
||||
#ifdef SQLITE_DEFAULT_ROWEST
|
||||
pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST);
|
||||
#else
|
||||
pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
#endif
|
||||
assert( pParse->pNewTable==0 );
|
||||
pParse->pNewTable = pTable;
|
||||
|
||||
|
||||
+275
-61
@@ -53,7 +53,9 @@ struct SortCtx {
|
||||
int regReturn; /* Register holding block-output return address */
|
||||
int labelBkOut; /* Start label for the block-output subroutine */
|
||||
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
|
||||
int labelDone; /* Jump here when done, ex: LIMIT reached */
|
||||
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
|
||||
u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */
|
||||
};
|
||||
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
|
||||
|
||||
@@ -501,6 +503,7 @@ static void pushOntoSorter(
|
||||
int regRecord = ++pParse->nMem; /* Assembled sorter record */
|
||||
int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
|
||||
int op; /* Opcode to add sorter record to sorter */
|
||||
int iLimit; /* LIMIT counter */
|
||||
|
||||
assert( bSeq==0 || bSeq==1 );
|
||||
if( nPrefixReg ){
|
||||
@@ -510,6 +513,9 @@ static void pushOntoSorter(
|
||||
regBase = pParse->nMem + 1;
|
||||
pParse->nMem += nBase;
|
||||
}
|
||||
assert( pSelect->iOffset==0 || pSelect->iLimit!=0 );
|
||||
iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
|
||||
pSort->labelDone = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, SQLITE_ECEL_DUP);
|
||||
if( bSeq ){
|
||||
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
|
||||
@@ -517,7 +523,6 @@ static void pushOntoSorter(
|
||||
if( nPrefixReg==0 ){
|
||||
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
|
||||
}
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
|
||||
if( nOBSat>0 ){
|
||||
int regPrevKey; /* The first nOBSat columns of the previous row */
|
||||
@@ -552,6 +557,10 @@ static void pushOntoSorter(
|
||||
pSort->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
|
||||
if( iLimit ){
|
||||
sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addrFirst);
|
||||
sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
|
||||
sqlite3VdbeJumpHere(v, addrJmp);
|
||||
@@ -562,17 +571,32 @@ static void pushOntoSorter(
|
||||
op = OP_IdxInsert;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
|
||||
if( pSelect->iLimit ){
|
||||
if( iLimit ){
|
||||
int addr;
|
||||
int iLimit;
|
||||
if( pSelect->iOffset ){
|
||||
iLimit = pSelect->iOffset+1;
|
||||
}else{
|
||||
iLimit = pSelect->iLimit;
|
||||
}
|
||||
int r1 = 0;
|
||||
/* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit
|
||||
** register is initialized with value of LIMIT+OFFSET.) After the sorter
|
||||
** fills up, delete the least entry in the sorter after each insert.
|
||||
** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */
|
||||
addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
|
||||
if( pSort->bOrderedInnerLoop ){
|
||||
r1 = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1);
|
||||
VdbeComment((v, "seq"));
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
|
||||
if( pSort->bOrderedInnerLoop ){
|
||||
/* If the inner loop is driven by an index such that values from
|
||||
** the same iteration of the inner loop are in sorted order, then
|
||||
** immediately jump to the next iteration of an inner loop if the
|
||||
** entry from the current iteration does not fit into the top
|
||||
** LIMIT+OFFSET entries of the sorter. */
|
||||
int iBrk = sqlite3VdbeCurrentAddr(v) + 2;
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
@@ -1168,7 +1192,7 @@ static void generateSortTail(
|
||||
SelectDest *pDest /* Write the sorted results here */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe; /* The prepared statement */
|
||||
int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
|
||||
int addrBreak = pSort->labelDone; /* Jump here to exit loop */
|
||||
int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
|
||||
int addr;
|
||||
int addrOnce = 0;
|
||||
@@ -1187,6 +1211,7 @@ static void generateSortTail(
|
||||
struct ExprList_item *aOutEx = p->pEList->a;
|
||||
#endif
|
||||
|
||||
assert( addrBreak<0 );
|
||||
if( pSort->labelBkOut ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
|
||||
@@ -2856,10 +2881,11 @@ static int multiSelectOrderBy(
|
||||
** to the right and the left are evaluated, they use the correct
|
||||
** collation.
|
||||
*/
|
||||
aPermute = sqlite3DbMallocRaw(db, sizeof(int)*nOrderBy);
|
||||
aPermute = sqlite3DbMallocRaw(db, sizeof(int)*(nOrderBy + 1));
|
||||
if( aPermute ){
|
||||
struct ExprList_item *pItem;
|
||||
for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
|
||||
aPermute[0] = nOrderBy;
|
||||
for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
|
||||
assert( pItem->u.x.iOrderByCol>0
|
||||
&& pItem->u.x.iOrderByCol<=p->pEList->nExpr );
|
||||
aPermute[i] = pItem->u.x.iOrderByCol - 1;
|
||||
@@ -3723,6 +3749,83 @@ static int flattenSubquery(
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
/*
|
||||
** Make copies of relevant WHERE clause terms of the outer query into
|
||||
** the WHERE clause of subquery. Example:
|
||||
**
|
||||
** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10;
|
||||
**
|
||||
** Transformed into:
|
||||
**
|
||||
** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1 WHERE a=5 AND c-d=10)
|
||||
** WHERE x=5 AND y=10;
|
||||
**
|
||||
** The hope is that the terms added to the inner query will make it more
|
||||
** efficient.
|
||||
**
|
||||
** Do not attempt this optimization if:
|
||||
**
|
||||
** (1) The inner query is an aggregate. (In that case, we'd really want
|
||||
** to copy the outer WHERE-clause terms onto the HAVING clause of the
|
||||
** inner query. But they probably won't help there so do not bother.)
|
||||
**
|
||||
** (2) The inner query is the recursive part of a common table expression.
|
||||
**
|
||||
** (3) The inner query has a LIMIT clause (since the changes to the WHERE
|
||||
** close would change the meaning of the LIMIT).
|
||||
**
|
||||
** (4) The inner query is the right operand of a LEFT JOIN. (The caller
|
||||
** enforces this restriction since this routine does not have enough
|
||||
** information to know.)
|
||||
**
|
||||
** (5) The WHERE clause expression originates in the ON or USING clause
|
||||
** of a LEFT JOIN.
|
||||
**
|
||||
** Return 0 if no changes are made and non-zero if one or more WHERE clause
|
||||
** terms are duplicated into the subquery.
|
||||
*/
|
||||
static int pushDownWhereTerms(
|
||||
sqlite3 *db, /* The database connection (for malloc()) */
|
||||
Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
|
||||
Expr *pWhere, /* The WHERE clause of the outer query */
|
||||
int iCursor /* Cursor number of the subquery */
|
||||
){
|
||||
Expr *pNew;
|
||||
int nChng = 0;
|
||||
Select *pX; /* For looping over compound SELECTs in pSubq */
|
||||
if( pWhere==0 ) return 0;
|
||||
for(pX=pSubq; pX; pX=pX->pPrior){
|
||||
if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
|
||||
testcase( pX->selFlags & SF_Aggregate );
|
||||
testcase( pX->selFlags & SF_Recursive );
|
||||
testcase( pX!=pSubq );
|
||||
return 0; /* restrictions (1) and (2) */
|
||||
}
|
||||
}
|
||||
if( pSubq->pLimit!=0 ){
|
||||
return 0; /* restriction (3) */
|
||||
}
|
||||
while( pWhere->op==TK_AND ){
|
||||
nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
|
||||
pWhere = pWhere->pLeft;
|
||||
}
|
||||
if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
|
||||
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
|
||||
nChng++;
|
||||
while( pSubq ){
|
||||
pNew = sqlite3ExprDup(db, pWhere, 0);
|
||||
pNew = substExpr(db, pNew, iCursor, pSubq->pEList);
|
||||
pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew);
|
||||
pSubq = pSubq->pPrior;
|
||||
}
|
||||
}
|
||||
return nChng;
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
/*
|
||||
** Based on the contents of the AggInfo structure indicated by the first
|
||||
** argument, this function checks if the following are true:
|
||||
@@ -4685,6 +4788,94 @@ static void explainSimpleCount(
|
||||
# define explainSimpleCount(a,b,c)
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
|
||||
/*
|
||||
** Attempt to transform a query of the form
|
||||
**
|
||||
** SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2)
|
||||
**
|
||||
** Into this:
|
||||
**
|
||||
** SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2)
|
||||
**
|
||||
** The transformation only works if all of the following are true:
|
||||
**
|
||||
** * The subquery is a UNION ALL of two or more terms
|
||||
** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries
|
||||
** * The outer query is a simple count(*)
|
||||
**
|
||||
** Return TRUE if the optimization is undertaken.
|
||||
*/
|
||||
static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
Select *pSub, *pPrior;
|
||||
Expr *pExpr;
|
||||
Expr *pCount;
|
||||
sqlite3 *db;
|
||||
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate query */
|
||||
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
|
||||
pExpr = p->pEList->a[0].pExpr;
|
||||
if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */
|
||||
if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Must be count() */
|
||||
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
|
||||
if( p->pSrc->nSrc!=1 ) return 0; /* One table in the FROM clause */
|
||||
pSub = p->pSrc->a[0].pSelect;
|
||||
if( pSub==0 ) return 0; /* The FROM is a subquery */
|
||||
if( pSub->pPrior==0 ) return 0; /* Must be a compound subquery */
|
||||
do{
|
||||
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
|
||||
if( pSub->pWhere ) return 0; /* No WHERE clause */
|
||||
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
|
||||
pSub = pSub->pPrior; /* Repeat over compound terms */
|
||||
}while( pSub );
|
||||
|
||||
/* If we reach this point, that means it is OK to perform the transformation */
|
||||
|
||||
db = pParse->db;
|
||||
pCount = pExpr;
|
||||
pExpr = 0;
|
||||
pSub = p->pSrc->a[0].pSelect;
|
||||
p->pSrc->a[0].pSelect = 0;
|
||||
sqlite3SrcListDelete(db, p->pSrc);
|
||||
p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
|
||||
while( pSub ){
|
||||
Expr *pTerm;
|
||||
pPrior = pSub->pPrior;
|
||||
pSub->pPrior = 0;
|
||||
pSub->pNext = 0;
|
||||
pSub->selFlags |= SF_Aggregate;
|
||||
pSub->selFlags &= ~SF_Compound;
|
||||
pSub->nSelectRow = 0;
|
||||
sqlite3ExprListDelete(db, pSub->pEList);
|
||||
pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
|
||||
pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm);
|
||||
pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
|
||||
if( pTerm ){
|
||||
pTerm->x.pSelect = pSub;
|
||||
ExprSetProperty(pTerm, EP_xIsSelect|EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, pTerm);
|
||||
if( pExpr==0 ){
|
||||
pExpr = pTerm;
|
||||
}else{
|
||||
pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr, 0);
|
||||
}
|
||||
}else{
|
||||
sqlite3SelectDelete(db, pSub);
|
||||
}
|
||||
pSub = pPrior;
|
||||
}
|
||||
p->pEList->a[0].pExpr = pExpr;
|
||||
p->selFlags &= ~SF_Aggregate;
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x400 ){
|
||||
SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
|
||||
|
||||
/*
|
||||
** Generate code for the SELECT statement given in the p argument.
|
||||
**
|
||||
@@ -4826,59 +5017,71 @@ int sqlite3Select(
|
||||
p->selFlags |= SF_Aggregate;
|
||||
}
|
||||
i = -1;
|
||||
}else if( pTabList->nSrc==1
|
||||
&& OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
||||
){
|
||||
/* Implement a co-routine that will return a single row of the result
|
||||
** set on each invocation.
|
||||
*/
|
||||
int addrTop = sqlite3VdbeCurrentAddr(v)+1;
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
|
||||
VdbeComment((v, "%s", pItem->pTab->zName));
|
||||
pItem->addrFillSub = addrTop;
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
||||
pItem->viaCoroutine = 1;
|
||||
pItem->regResult = dest.iSdst;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
|
||||
sqlite3VdbeJumpHere(v, addrTop-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}else{
|
||||
/* Generate a subroutine that will fill an ephemeral table with
|
||||
** the content of this subquery. pItem->addrFillSub will point
|
||||
** to the address of the generated subroutine. pItem->regReturn
|
||||
** is a register allocated to hold the subroutine return address
|
||||
*/
|
||||
int topAddr;
|
||||
int onceAddr = 0;
|
||||
int retAddr;
|
||||
assert( pItem->addrFillSub==0 );
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||
pItem->addrFillSub = topAddr+1;
|
||||
if( pItem->isCorrelated==0 ){
|
||||
/* If the subquery is not correlated and if we are not inside of
|
||||
** a trigger, then we only need to compute the value of the subquery
|
||||
** once. */
|
||||
onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||
VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}else{
|
||||
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
if( (pItem->jointype & JT_OUTER)==0
|
||||
&& pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
|
||||
){
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
sqlite3DebugPrintf("After WHERE-clause push-down:\n");
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if( pTabList->nSrc==1
|
||||
&& OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
||||
){
|
||||
/* Implement a co-routine that will return a single row of the result
|
||||
** set on each invocation.
|
||||
*/
|
||||
int addrTop = sqlite3VdbeCurrentAddr(v)+1;
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
|
||||
VdbeComment((v, "%s", pItem->pTab->zName));
|
||||
pItem->addrFillSub = addrTop;
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
||||
pItem->viaCoroutine = 1;
|
||||
pItem->regResult = dest.iSdst;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
|
||||
sqlite3VdbeJumpHere(v, addrTop-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}else{
|
||||
/* Generate a subroutine that will fill an ephemeral table with
|
||||
** the content of this subquery. pItem->addrFillSub will point
|
||||
** to the address of the generated subroutine. pItem->regReturn
|
||||
** is a register allocated to hold the subroutine return address
|
||||
*/
|
||||
int topAddr;
|
||||
int onceAddr = 0;
|
||||
int retAddr;
|
||||
assert( pItem->addrFillSub==0 );
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||
pItem->addrFillSub = topAddr+1;
|
||||
if( pItem->isCorrelated==0 ){
|
||||
/* If the subquery is not correlated and if we are not inside of
|
||||
** a trigger, then we only need to compute the value of the subquery
|
||||
** once. */
|
||||
onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||
VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}else{
|
||||
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
||||
VdbeComment((v, "end %s", pItem->pTab->zName));
|
||||
sqlite3VdbeChangeP1(v, topAddr, retAddr);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
||||
VdbeComment((v, "end %s", pItem->pTab->zName));
|
||||
sqlite3VdbeChangeP1(v, topAddr, retAddr);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}
|
||||
if( /*pParse->nErr ||*/ db->mallocFailed ){
|
||||
if( db->mallocFailed ){
|
||||
goto select_end;
|
||||
}
|
||||
pParse->nHeight -= sqlite3SelectExprHeight(p);
|
||||
@@ -4908,6 +5111,16 @@ int sqlite3Select(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
|
||||
if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
|
||||
&& countOfViewOptimization(pParse, p)
|
||||
){
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
pEList = p->pEList;
|
||||
pTabList = p->pSrc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
|
||||
** if the select-list is the same as the ORDER BY list, then this query
|
||||
** can be rewritten as a GROUP BY. In other words, this:
|
||||
@@ -5001,6 +5214,7 @@ int sqlite3Select(
|
||||
}
|
||||
if( sSort.pOrderBy ){
|
||||
sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
|
||||
sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo);
|
||||
if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
|
||||
sSort.pOrderBy = 0;
|
||||
}
|
||||
|
||||
@@ -1245,6 +1245,7 @@ struct sqlite3 {
|
||||
#define SQLITE_Transitive 0x0200 /* Transitive constraints */
|
||||
#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
|
||||
#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */
|
||||
#define SQLITE_CountOfView 0x1000 /* The count-of-view optimization */
|
||||
#define SQLITE_AllOpts 0xffff /* All optimizations */
|
||||
|
||||
/*
|
||||
@@ -2276,6 +2277,7 @@ struct SrcList {
|
||||
#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */
|
||||
#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */
|
||||
#define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */
|
||||
#define WHERE_ORDERBY_LIMIT 0x2000 /* ORDERBY+LIMIT on the inner loop */
|
||||
|
||||
/* Allowed return values from sqlite3WhereIsDistinct()
|
||||
*/
|
||||
@@ -3289,6 +3291,7 @@ void sqlite3WhereEnd(WhereInfo*);
|
||||
u64 sqlite3WhereOutputRowCount(WhereInfo*);
|
||||
int sqlite3WhereIsDistinct(WhereInfo*);
|
||||
int sqlite3WhereIsOrdered(WhereInfo*);
|
||||
int sqlite3WhereOrderedInnerLoop(WhereInfo*);
|
||||
int sqlite3WhereIsSorted(WhereInfo*);
|
||||
int sqlite3WhereContinueLabel(WhereInfo*);
|
||||
int sqlite3WhereBreakLabel(WhereInfo*);
|
||||
|
||||
+20
-5
@@ -1980,11 +1980,14 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
** The permutation is only valid until the next OP_Compare that has
|
||||
** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
|
||||
** occur immediately prior to the OP_Compare.
|
||||
**
|
||||
** The first integer in the P4 integer array is the length of the array
|
||||
** and does not become part of the permutation.
|
||||
*/
|
||||
case OP_Permutation: {
|
||||
assert( pOp->p4type==P4_INTARRAY );
|
||||
assert( pOp->p4.ai );
|
||||
aPermute = pOp->p4.ai;
|
||||
aPermute = pOp->p4.ai + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2290,12 +2293,16 @@ case OP_Column: {
|
||||
u16 fx; /* pDest->flags value */
|
||||
Mem *pReg; /* PseudoTable input register */
|
||||
|
||||
pC = p->apCsr[pOp->p1];
|
||||
p2 = pOp->p2;
|
||||
|
||||
/* If the cursor cache is stale, bring it up-to-date */
|
||||
rc = sqlite3VdbeCursorMoveto(&pC, &p2);
|
||||
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( p2<pC->nField );
|
||||
aOffset = pC->aOffset;
|
||||
@@ -2306,8 +2313,6 @@ case OP_Column: {
|
||||
assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
|
||||
assert( pCrsr!=0 || pC->nullRow ); /* pC->nullRow on PseudoTables */
|
||||
|
||||
/* If the cursor cache is stale, bring it up-to-date */
|
||||
rc = sqlite3VdbeCursorMoveto(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( pC->cacheStatus!=p->cacheCtr ){
|
||||
if( pC->nullRow ){
|
||||
@@ -3725,7 +3730,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Seek P1 P2 * * *
|
||||
/* Opcode: Seek P1 P2 P3 P4 *
|
||||
** Synopsis: intkey=r[P2]
|
||||
**
|
||||
** P1 is an open table cursor and P2 is a rowid integer. Arrange
|
||||
@@ -3734,6 +3739,13 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
** This is actually a deferred seek. Nothing actually happens until
|
||||
** the cursor is used to read a record. That way, if no reads
|
||||
** occur, no unnecessary I/O happens.
|
||||
**
|
||||
** P4 may contain an array of integers (type P4_INTARRAY) containing
|
||||
** one entry for each column in the table P1 is open on. If so, then
|
||||
** parameter P3 is a cursor open on a database index. If array entry
|
||||
** a[i] is non-zero, then reading column (a[i]-1) from cursor P3 is
|
||||
** equivalent to performing the deferred seek and then reading column i
|
||||
** from P1.
|
||||
*/
|
||||
case OP_Seek: { /* in2 */
|
||||
VdbeCursor *pC;
|
||||
@@ -3747,6 +3759,9 @@ case OP_Seek: { /* in2 */
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
|
||||
pC->deferredMoveto = 1;
|
||||
assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
|
||||
pC->aAltMap = pOp->p4.ai;
|
||||
pC->pAltCursor = p->apCsr[pOp->p3];
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -60,6 +60,7 @@ typedef struct AuxData AuxData;
|
||||
** Every cursor that the virtual machine has open is represented by an
|
||||
** instance of the following structure.
|
||||
*/
|
||||
typedef struct VdbeCursor VdbeCursor;
|
||||
struct VdbeCursor {
|
||||
BtCursor *pCursor; /* The cursor structure of the backend */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
@@ -83,6 +84,11 @@ struct VdbeCursor {
|
||||
i64 seqCount; /* Sequence counter */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
|
||||
VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
|
||||
int *aAltMap; /* Mapping from table to index column numbers */
|
||||
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
||||
u64 maskUsed; /* Mask of columns used by this cursor */
|
||||
#endif
|
||||
|
||||
/* Cached information about the header for the data record that the
|
||||
** cursor is currently pointing to. Only valid if cacheStatus matches
|
||||
@@ -104,7 +110,6 @@ struct VdbeCursor {
|
||||
** static element declared in the structure. nField total array slots for
|
||||
** aType[] and nField+1 array slots for aOffset[] */
|
||||
};
|
||||
typedef struct VdbeCursor VdbeCursor;
|
||||
|
||||
/*
|
||||
** When a sub-program is executed (OP_Program), a structure of this type
|
||||
@@ -393,7 +398,7 @@ struct Vdbe {
|
||||
*/
|
||||
void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
|
||||
void sqliteVdbePopStack(Vdbe*,int);
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor*);
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
|
||||
int sqlite3VdbeCursorRestore(VdbeCursor*);
|
||||
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
||||
void sqlite3VdbePrintOp(FILE*, int, Op*);
|
||||
|
||||
+23
-2
@@ -1123,7 +1123,21 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
}
|
||||
#endif
|
||||
case P4_INTARRAY: {
|
||||
sqlite3_snprintf(nTemp, zTemp, "intarray");
|
||||
int i, j;
|
||||
int *ai = pOp->p4.ai;
|
||||
int n = ai[0]; /* The first element of an INTARRAY is always the
|
||||
** count of the number of elements to follow */
|
||||
zTemp[0] = '[';
|
||||
for(i=j=1; i<n && j<nTemp-7; i++){
|
||||
if( j>1 ) zTemp[j++] = ',';
|
||||
sqlite3_snprintf(nTemp-j, zTemp+j, "%d", ai[i]);
|
||||
j += sqlite3Strlen30(zTemp+j);
|
||||
}
|
||||
if( i<n ){
|
||||
memcpy(zTemp+j, ",...]", 6);
|
||||
}else{
|
||||
memcpy(zTemp+j, "]", 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case P4_SUBPROGRAM: {
|
||||
@@ -2818,8 +2832,15 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
||||
** If the cursor is already pointing to the correct row and that row has
|
||||
** not been deleted out from under the cursor, then this routine is a no-op.
|
||||
*/
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
|
||||
VdbeCursor *p = *pp;
|
||||
if( p->deferredMoveto ){
|
||||
int iMap;
|
||||
if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){
|
||||
*pp = p->pAltCursor;
|
||||
*piCol = iMap - 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return handleDeferredMoveto(p);
|
||||
}
|
||||
if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){
|
||||
|
||||
+123
-22
@@ -42,6 +42,18 @@ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
|
||||
return pWInfo->nOBSat;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the innermost loop of the WHERE clause implementation
|
||||
** returns rows in ORDER BY order for complete run of the inner loop.
|
||||
**
|
||||
** Across multiple iterations of outer loops, the output rows need not be
|
||||
** sorted. As long as rows are sorted for just the innermost loop, this
|
||||
** routine can return TRUE.
|
||||
*/
|
||||
int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){
|
||||
return pWInfo->bOrderedInnerLoop;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the VDBE address or label to jump to in order to continue
|
||||
** immediately with the next row of a WHERE clause.
|
||||
@@ -2209,7 +2221,7 @@ static int whereKeyStats(
|
||||
iGap = iGap/3;
|
||||
}
|
||||
aStat[0] = iLower + iGap;
|
||||
aStat[1] = pIdx->aAvgEq[iCol];
|
||||
aStat[1] = pIdx->aAvgEq[nField-1];
|
||||
}
|
||||
|
||||
/* Restore the pRec->nField value before returning. */
|
||||
@@ -3236,6 +3248,55 @@ static void whereLikeOptimizationStringFixup(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains
|
||||
** a rowid value just read from cursor iIdxCur, open on index pIdx. This
|
||||
** function generates code to do a deferred seek of cursor iCur to the
|
||||
** rowid stored in register iRowid.
|
||||
**
|
||||
** Normally, this is just:
|
||||
**
|
||||
** OP_Seek $iCur $iRowid
|
||||
**
|
||||
** However, if the scan currently being coded is a branch of an OR-loop and
|
||||
** the statement currently being coded is a SELECT, then P3 of the OP_Seek
|
||||
** is set to iIdxCur and P4 is set to point to an array of integers
|
||||
** containing one entry for each column of the table cursor iCur is open
|
||||
** on. For each table column, if the column is the i'th column of the
|
||||
** index, then the corresponding array entry is set to (i+1). If the column
|
||||
** does not appear in the index at all, the array entry is set to 0.
|
||||
*/
|
||||
static void codeDeferredSeek(
|
||||
WhereInfo *pWInfo, /* Where clause context */
|
||||
Index *pIdx, /* Index scan is using */
|
||||
int iCur, /* Cursor for IPK b-tree */
|
||||
int iRowid, /* Register containing rowid to seek to */
|
||||
int iIdxCur /* Index cursor */
|
||||
){
|
||||
Parse *pParse = pWInfo->pParse; /* Parse context */
|
||||
Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */
|
||||
|
||||
assert( iIdxCur>0 );
|
||||
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_Seek, iCur, iRowid, iIdxCur);
|
||||
if( (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)
|
||||
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
|
||||
){
|
||||
int i;
|
||||
Table *pTab = pIdx->pTable;
|
||||
int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
|
||||
if( ai ){
|
||||
ai[0] = pTab->nCol;
|
||||
for(i=0; i<pIdx->nColumn-1; i++){
|
||||
assert( pIdx->aiColumn[i]<pTab->nCol );
|
||||
if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1;
|
||||
}
|
||||
sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for the start of the iLevel-th loop in the WHERE clause
|
||||
** implementation described by pWInfo.
|
||||
@@ -3714,7 +3775,7 @@ static Bitmask codeOneLoopStart(
|
||||
iRowidReg = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
|
||||
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
|
||||
sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */
|
||||
codeDeferredSeek(pWInfo, pIdx, iCur, iRowidReg, iIdxCur);
|
||||
}else if( iCur!=iIdxCur ){
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
||||
iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
||||
@@ -5602,7 +5663,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
WhereInfo *pWInfo, /* The WHERE clause */
|
||||
ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */
|
||||
WherePath *pPath, /* The WherePath to check */
|
||||
u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */
|
||||
u16 wctrlFlags, /* WHERE_GROUPBY, _DISTINCTBY or _ORDERBY_LIMIT */
|
||||
u16 nLoop, /* Number of entries in pPath->aLoop[] */
|
||||
WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */
|
||||
Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */
|
||||
@@ -5613,6 +5674,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
u8 isOrderDistinct; /* All prior WhereLoops are order-distinct */
|
||||
u8 distinctColumns; /* True if the loop has UNIQUE NOT NULL columns */
|
||||
u8 isMatch; /* iColumn matches a term of the ORDER BY clause */
|
||||
u16 eqOpMask; /* Allowed equality operators */
|
||||
u16 nKeyCol; /* Number of key columns in pIndex */
|
||||
u16 nColumn; /* Total number of ordered columns in the index */
|
||||
u16 nOrderBy; /* Number terms in the ORDER BY clause */
|
||||
@@ -5663,8 +5725,16 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
obDone = MASKBIT(nOrderBy)-1;
|
||||
orderDistinctMask = 0;
|
||||
ready = 0;
|
||||
eqOpMask = WO_EQ | WO_ISNULL;
|
||||
if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN;
|
||||
for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){
|
||||
if( iLoop>0 ) ready |= pLoop->maskSelf;
|
||||
if( iLoop<nLoop ){
|
||||
pLoop = pPath->aLoop[iLoop];
|
||||
if( wctrlFlags & WHERE_ORDERBY_LIMIT ) continue;
|
||||
}else{
|
||||
pLoop = pLast;
|
||||
}
|
||||
pLoop = iLoop<nLoop ? pPath->aLoop[iLoop] : pLast;
|
||||
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
|
||||
if( pLoop->u.vtab.isOrdered ) obSat = obDone;
|
||||
@@ -5683,8 +5753,16 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
if( pOBExpr->op!=TK_COLUMN ) continue;
|
||||
if( pOBExpr->iTable!=iCur ) continue;
|
||||
pTerm = findTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
|
||||
~ready, WO_EQ|WO_ISNULL, 0);
|
||||
~ready, eqOpMask, 0);
|
||||
if( pTerm==0 ) continue;
|
||||
if( pTerm->eOperator==WO_IN ){
|
||||
/* IN terms are only valid for sorting in the ORDER BY LIMIT
|
||||
** optimization, and then only if they are actually used
|
||||
** by the query plan */
|
||||
assert( wctrlFlags & WHERE_ORDERBY_LIMIT );
|
||||
for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){}
|
||||
if( j>=pLoop->nLTerm ) continue;
|
||||
}
|
||||
if( (pTerm->eOperator&WO_EQ)!=0 && pOBExpr->iColumn>=0 ){
|
||||
const char *z1, *z2;
|
||||
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
|
||||
@@ -5721,10 +5799,12 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
for(j=0; j<nColumn; j++){
|
||||
u8 bOnce; /* True to run the ORDER BY search loop */
|
||||
|
||||
/* Skip over == and IS NULL terms */
|
||||
/* Skip over == and IS NULL terms
|
||||
** (Also skip IN terms when doing WHERE_ORDERBY_LIMIT processing)
|
||||
*/
|
||||
if( j<pLoop->u.btree.nEq
|
||||
&& pLoop->nSkip==0
|
||||
&& ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
|
||||
&& ((i = pLoop->aLTerm[j]->eOperator) & eqOpMask)!=0
|
||||
){
|
||||
if( i & WO_ISNULL ){
|
||||
testcase( isOrderDistinct );
|
||||
@@ -6090,8 +6170,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
** this candidate as not viable. */
|
||||
#ifdef WHERETRACE_ENABLED /* 0x4 */
|
||||
if( sqlite3WhereTrace&0x4 ){
|
||||
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
|
||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
||||
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n",
|
||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
|
||||
isOrdered>=0 ? isOrdered+'0' : '?');
|
||||
}
|
||||
#endif
|
||||
@@ -6109,26 +6189,36 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
pTo = &aTo[jj];
|
||||
#ifdef WHERETRACE_ENABLED /* 0x4 */
|
||||
if( sqlite3WhereTrace&0x4 ){
|
||||
sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
|
||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
||||
sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n",
|
||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
|
||||
isOrdered>=0 ? isOrdered+'0' : '?');
|
||||
}
|
||||
#endif
|
||||
}else{
|
||||
/* Control reaches here if best-so-far path pTo=aTo[jj] covers the
|
||||
** same set of loops and has the sam isOrdered setting as the
|
||||
** same set of loops and has the same isOrdered setting as the
|
||||
** candidate path. Check to see if the candidate should replace
|
||||
** pTo or if the candidate should be skipped */
|
||||
if( pTo->rCost<rCost || (pTo->rCost==rCost && pTo->nRow<=nOut) ){
|
||||
** pTo or if the candidate should be skipped.
|
||||
**
|
||||
** The conditional is an expanded vector comparison equivalent to:
|
||||
** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted)
|
||||
*/
|
||||
if( pTo->rCost<rCost
|
||||
|| (pTo->rCost==rCost
|
||||
&& (pTo->nRow<nOut
|
||||
|| (pTo->nRow==nOut && pTo->rUnsorted<=rUnsorted)
|
||||
)
|
||||
)
|
||||
){
|
||||
#ifdef WHERETRACE_ENABLED /* 0x4 */
|
||||
if( sqlite3WhereTrace&0x4 ){
|
||||
sqlite3DebugPrintf(
|
||||
"Skip %s cost=%-3d,%3d order=%c",
|
||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
||||
"Skip %s cost=%-3d,%3d,%3d order=%c",
|
||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
|
||||
isOrdered>=0 ? isOrdered+'0' : '?');
|
||||
sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
|
||||
sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n",
|
||||
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
|
||||
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
|
||||
pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
|
||||
}
|
||||
#endif
|
||||
/* Discard the candidate path from further consideration */
|
||||
@@ -6141,12 +6231,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
#ifdef WHERETRACE_ENABLED /* 0x4 */
|
||||
if( sqlite3WhereTrace&0x4 ){
|
||||
sqlite3DebugPrintf(
|
||||
"Update %s cost=%-3d,%3d order=%c",
|
||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
||||
"Update %s cost=%-3d,%3d,%3d order=%c",
|
||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
|
||||
isOrdered>=0 ? isOrdered+'0' : '?');
|
||||
sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
|
||||
sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n",
|
||||
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
|
||||
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
|
||||
pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -6237,8 +6327,19 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
}
|
||||
}else{
|
||||
pWInfo->nOBSat = pFrom->isOrdered;
|
||||
if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
|
||||
pWInfo->revMask = pFrom->revLoop;
|
||||
if( pWInfo->nOBSat<=0 ){
|
||||
pWInfo->nOBSat = 0;
|
||||
if( nLoop>0 && (pFrom->aLoop[nLoop-1]->wsFlags & WHERE_ONEROW)==0 ){
|
||||
Bitmask m = 0;
|
||||
int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom,
|
||||
WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m);
|
||||
if( rc==pWInfo->pOrderBy->nExpr ){
|
||||
pWInfo->bOrderedInnerLoop = 1;
|
||||
pWInfo->revMask = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
|
||||
&& pWInfo->nOBSat==pWInfo->pOrderBy->nExpr
|
||||
|
||||
@@ -412,6 +412,7 @@ struct WhereInfo {
|
||||
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
|
||||
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
|
||||
u8 nLevel; /* Number of nested loop */
|
||||
u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */
|
||||
int iTop; /* The very beginning of the WHERE loop */
|
||||
int iContinue; /* Jump here to continue with next record */
|
||||
int iBreak; /* Jump here to break out of the loop */
|
||||
|
||||
@@ -161,4 +161,27 @@ do_execsql_test join5-3.3 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 JOIN x3 WHERE x3.d = x2.b;
|
||||
} {}
|
||||
|
||||
# Ticket https://www.sqlite.org/src/tktview/c2a19d81652f40568c770c43 on
|
||||
# 2015-08-20. LEFT JOIN and the push-down optimization.
|
||||
#
|
||||
do_execsql_test join6-4.1 {
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT 'apple' fruit
|
||||
UNION ALL SELECT 'banana'
|
||||
) a
|
||||
JOIN (
|
||||
SELECT 'apple' fruit
|
||||
UNION ALL SELECT 'banana'
|
||||
) b ON a.fruit=b.fruit
|
||||
LEFT JOIN (
|
||||
SELECT 1 isyellow
|
||||
) c ON b.fruit='banana';
|
||||
} {apple apple {} banana banana 1}
|
||||
do_execsql_test join6-4.2 {
|
||||
SELECT *
|
||||
FROM (SELECT 'apple' fruit UNION ALL SELECT 'banana')
|
||||
LEFT JOIN (SELECT 1) ON fruit='banana';
|
||||
} {apple {} banana 1}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# 2016-05-20
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the LIMIT in combination with ORDER BY
|
||||
# and in particular, the optimizations in the inner loop that cause an
|
||||
# early exit of the inner loop when the LIMIT is reached and the inner
|
||||
# loop is emitting rows in ORDER BY order.
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_execsql_test limit2-100 {
|
||||
CREATE TABLE t1(a,b);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000)
|
||||
INSERT INTO t1(a,b) SELECT 1, (x*17)%1000 + 1000 FROM c;
|
||||
INSERT INTO t1(a,b) VALUES(2,2),(3,1006),(4,4),(5,9999);
|
||||
CREATE INDEX t1ab ON t1(a,b);
|
||||
}
|
||||
set sqlite_search_count 0
|
||||
do_execsql_test limit2-100.1 {
|
||||
SELECT a, b, '|' FROM t1 WHERE a IN (2,4,5,3,1) ORDER BY b LIMIT 5;
|
||||
} {2 2 | 4 4 | 1 1000 | 1 1001 | 1 1002 |}
|
||||
set fast_count $sqlite_search_count
|
||||
set sqlite_search_count 0
|
||||
do_execsql_test limit2-100.2 {
|
||||
SELECT a, b, '|' FROM t1 WHERE a IN (2,4,5,3,1) ORDER BY +b LIMIT 5;
|
||||
} {2 2 | 4 4 | 1 1000 | 1 1001 | 1 1002 |}
|
||||
do_test limit2-100.3 {
|
||||
set slow_count $sqlite_search_count
|
||||
expr {$fast_count < 0.02*$slow_count}
|
||||
} {1}
|
||||
|
||||
do_execsql_test limit2-110 {
|
||||
CREATE TABLE t2(x,y);
|
||||
INSERT INTO t2(x,y) VALUES('a',1),('a',2),('a',3),('a',4);
|
||||
INSERT INTO t2(x,y) VALUES('b',1),('c',2),('d',3),('e',4);
|
||||
CREATE INDEX t2xy ON t2(x,y);
|
||||
}
|
||||
set sqlite_search_count 0
|
||||
do_execsql_test limit2-110.1 {
|
||||
SELECT a, b, '|' FROM t2, t1 WHERE t2.x='a' AND t1.a=t2.y ORDER BY t1.b LIMIT 5;
|
||||
} {2 2 | 4 4 | 1 1000 | 1 1001 | 1 1002 |}
|
||||
set fast_count $sqlite_search_count
|
||||
set sqlite_search_count 0
|
||||
do_execsql_test limit2-110.2 {
|
||||
SELECT a, b, '|' FROM t2, t1 WHERE t2.x='a' AND t1.a=t2.y ORDER BY +t1.b LIMIT 5;
|
||||
} {2 2 | 4 4 | 1 1000 | 1 1001 | 1 1002 |}
|
||||
set slow_count $sqlite_search_count
|
||||
do_test limit2-110.3 {
|
||||
expr {$fast_count < 0.02*$slow_count}
|
||||
} {1}
|
||||
|
||||
do_execsql_test limit2-120 {
|
||||
DROP INDEX t1ab;
|
||||
CREATE INDEX t1ab ON t1(a,b DESC);
|
||||
}
|
||||
set sqlite_search_count 0
|
||||
do_execsql_test limit2-120.1 {
|
||||
SELECT a, b, '|' FROM t1 WHERE a IN (2,4,5,3,1) ORDER BY b DESC LIMIT 5;
|
||||
} {5 9999 | 1 1999 | 1 1998 | 1 1997 | 1 1996 |}
|
||||
set fast_count $sqlite_search_count
|
||||
set sqlite_search_count 0
|
||||
do_execsql_test limit2-120.2 {
|
||||
SELECT a, b, '|' FROM t1 WHERE a IN (2,4,5,3,1) ORDER BY +b DESC LIMIT 5;
|
||||
} {5 9999 | 1 1999 | 1 1998 | 1 1997 | 1 1996 |}
|
||||
do_test limit2-120.3 {
|
||||
set slow_count $sqlite_search_count
|
||||
expr {$fast_count < 0.02*$slow_count}
|
||||
} {1}
|
||||
|
||||
# Bug report against the new ORDER BY LIMIT optimization just prior to
|
||||
# release. (Unreleased so there is no ticket).
|
||||
#
|
||||
# Make sure the optimization is not applied if the inner loop can only
|
||||
# provide a single row of output.
|
||||
#
|
||||
do_execsql_test limit2-200 {
|
||||
CREATE TABLE t200(a, b);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000)
|
||||
INSERT INTO t200(a,b) SELECT x, x FROM c;
|
||||
CREATE TABLE t201(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t201(x,y) VALUES(2,12345);
|
||||
|
||||
SELECT *, '|' FROM t200, t201 WHERE x=b ORDER BY y LIMIT 3;
|
||||
} {2 2 2 12345 |}
|
||||
do_execsql_test limit2-210 {
|
||||
SELECT *, '|' FROM t200 LEFT JOIN t201 ON x=b ORDER BY y LIMIT 3;
|
||||
} {1 1 {} {} | 3 3 {} {} | 4 4 {} {} |}
|
||||
|
||||
# Bug in the ORDER BY LIMIT optimization reported on 2016-09-06.
|
||||
# Ticket https://www.sqlite.org/src/info/559733b09e96
|
||||
#
|
||||
do_execsql_test limit2-300 {
|
||||
CREATE TABLE t300(a,b,c);
|
||||
CREATE INDEX t300x ON t300(a,b,c);
|
||||
INSERT INTO t300 VALUES(0,1,99),(0,1,0),(0,0,0);
|
||||
SELECT *,'.' FROM t300 WHERE a=0 AND (c=0 OR c=99) ORDER BY c DESC;
|
||||
} {0 1 99 . 0 0 0 . 0 1 0 .}
|
||||
do_execsql_test limit2-310 {
|
||||
SELECT *,'.' FROM t300 WHERE a=0 AND (c=0 OR c=99) ORDER BY c DESC LIMIT 1;
|
||||
} {0 1 99 .}
|
||||
|
||||
# Make sure the SELECT loop is ordered correctly for the direction of
|
||||
# the ORDER BY
|
||||
#
|
||||
do_execsql_test limit2-400 {
|
||||
CREATE TABLE t400(a,b);
|
||||
CREATE INDEX t400_ab ON t400(a,b);
|
||||
INSERT INTO t400(a,b) VALUES(1,90),(1,40),(2,80),(2,30),(3,70),(3,20);
|
||||
SELECT *,'x' FROM t400 WHERE a IN (1,2,3) ORDER BY b DESC LIMIT 3;
|
||||
SELECT *,'y' FROM t400 WHERE a IN (1,2,3) ORDER BY +b DESC LIMIT 3;
|
||||
} {1 90 x 2 80 x 3 70 x 1 90 y 2 80 y 3 70 y}
|
||||
|
||||
finish_test
|
||||
@@ -496,4 +496,21 @@ do_execsql_test 7.0 {
|
||||
} {~/ORDER BY/}
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# https://www.sqlite.org/src/tktview/cb3aa0641d9a413841c004293a4fc06cdc122029
|
||||
#
|
||||
# Adverse interaction between scalar subqueries and the partial-sorting
|
||||
# logic.
|
||||
#
|
||||
do_execsql_test 9.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY);
|
||||
INSERT INTO t1 VALUES(1),(2);
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t2(y);
|
||||
INSERT INTO t2 VALUES(9),(8),(3),(4);
|
||||
SELECT (SELECT x||y FROM t2, t1 ORDER BY x, y);
|
||||
} {13}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -864,4 +864,41 @@ do_execsql_test select4-14.9 {
|
||||
SELECT * FROM t14 UNION ALL VALUES(3,2,1),(2,3,1),(1,2,3),(2,1,3);
|
||||
} {1 2 3 4 5 6 3 2 1 2 3 1 1 2 3 2 1 3}
|
||||
|
||||
# Ticket https://www.sqlite.org/src/tktview/f7f8c97e975978d45 on 2016-04-25
|
||||
#
|
||||
# The where push-down optimization from 2015-06-02 is suppose to disable
|
||||
# on aggregate subqueries. But if the subquery is a compound where the
|
||||
# last SELECT is non-aggregate but some other SELECT is an aggregate, the
|
||||
# test is incomplete and the optimization is not properly disabled.
|
||||
#
|
||||
# The following test cases verify that the fix works.
|
||||
#
|
||||
do_execsql_test select4-17.1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a int, b int);
|
||||
INSERT INTO t1 VALUES(1,2),(1,18),(2,19);
|
||||
SELECT x, y FROM (
|
||||
SELECT 98 AS x, 99 AS y
|
||||
UNION
|
||||
SELECT a AS x, sum(b) AS y FROM t1 GROUP BY a
|
||||
) AS w WHERE y>=20
|
||||
ORDER BY +x;
|
||||
} {1 20 98 99}
|
||||
do_execsql_test select4-17.2 {
|
||||
SELECT x, y FROM (
|
||||
SELECT a AS x, sum(b) AS y FROM t1 GROUP BY a
|
||||
UNION
|
||||
SELECT 98 AS x, 99 AS y
|
||||
) AS w WHERE y>=20
|
||||
ORDER BY +x;
|
||||
} {1 20 98 99}
|
||||
do_catchsql_test select4-17.3 {
|
||||
SELECT x, y FROM (
|
||||
SELECT a AS x, sum(b) AS y FROM t1 GROUP BY a LIMIT 3
|
||||
UNION
|
||||
SELECT 98 AS x, 99 AS y
|
||||
) AS w WHERE y>=20
|
||||
ORDER BY +x;
|
||||
} {1 {LIMIT clause should come after UNION not before}}
|
||||
|
||||
finish_test
|
||||
|
||||
+72
-1
@@ -156,7 +156,7 @@ do_searchcount_test 3.4.4 {
|
||||
|
||||
do_searchcount_test 3.5.1 {
|
||||
SELECT a, b FROM t3 WHERE (a=1 AND b='one') OR rowid=4
|
||||
} {1 one 2 two search 2}
|
||||
} {1 one 2 two search 1}
|
||||
do_searchcount_test 3.5.2 {
|
||||
SELECT a, c FROM t3 WHERE (a=1 AND b='one') OR rowid=4
|
||||
} {1 i 2 ii search 2}
|
||||
@@ -271,5 +271,76 @@ do_execsql_test 5.3 {
|
||||
c16=1 or c17=1;
|
||||
} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1 {} {}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE x1(a, b, c, d, e);
|
||||
CREATE INDEX x1a ON x1(a);
|
||||
CREATE INDEX x1bc ON x1(b, c);
|
||||
CREATE INDEX x1cd ON x1(c, d);
|
||||
|
||||
INSERT INTO x1 VALUES(1, 2, 3, 4, 'A');
|
||||
INSERT INTO x1 VALUES(5, 6, 7, 8, 'B');
|
||||
INSERT INTO x1 VALUES(9, 10, 11, 12, 'C');
|
||||
INSERT INTO x1 VALUES(13, 14, 15, 16, 'D');
|
||||
}
|
||||
|
||||
do_searchcount_test 6.2.1 {
|
||||
SELECT e FROM x1 WHERE b=2 OR c=7;
|
||||
} {A B search 6}
|
||||
do_searchcount_test 6.2.2 {
|
||||
SELECT c FROM x1 WHERE b=2 OR c=7;
|
||||
} {3 7 search 4}
|
||||
|
||||
do_searchcount_test 6.3.1 {
|
||||
SELECT e FROM x1 WHERE a=1 OR b=10;
|
||||
} {A C search 6}
|
||||
do_searchcount_test 6.3.2 {
|
||||
SELECT c FROM x1 WHERE a=1 OR b=10;
|
||||
} {3 11 search 5}
|
||||
do_searchcount_test 6.3.3 {
|
||||
SELECT rowid FROM x1 WHERE a=1 OR b=10;
|
||||
} {1 3 search 4}
|
||||
|
||||
do_searchcount_test 6.4.1 {
|
||||
SELECT a FROM x1 WHERE b BETWEEN 1 AND 4 OR c BETWEEN 8 AND 12
|
||||
} {1 9 search 6}
|
||||
do_searchcount_test 6.4.2 {
|
||||
SELECT b, c FROM x1 WHERE b BETWEEN 1 AND 4 OR c BETWEEN 8 AND 12
|
||||
} {2 3 10 11 search 5}
|
||||
do_searchcount_test 6.4.3 {
|
||||
SELECT rowid, c FROM x1 WHERE b BETWEEN 1 AND 4 OR c BETWEEN 8 AND 12
|
||||
} {1 3 3 11 search 4}
|
||||
|
||||
db eval {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1000) UNION ALL SELECT x+1 FROM c WHERE x<2000)
|
||||
INSERT INTO x1(rowid,a,b,c,d,e) SELECT x,x,x,x,x,x FROM c;
|
||||
}
|
||||
|
||||
do_searchcount_test 6.5.1 {
|
||||
SELECT a FROM x1 WHERE rowid = 2 OR c=11
|
||||
} {5 9 search 3}
|
||||
do_searchcount_test 6.5.2 {
|
||||
SELECT d FROM x1 WHERE rowid = 2 OR c=11
|
||||
} {8 12 search 2}
|
||||
do_searchcount_test 6.5.3 {
|
||||
SELECT d FROM x1 WHERE c=11 OR rowid = 2
|
||||
} {12 8 search 2}
|
||||
do_searchcount_test 6.5.4 {
|
||||
SELECT a FROM x1 WHERE c=11 OR rowid = 2
|
||||
} {9 5 search 3}
|
||||
|
||||
do_searchcount_test 6.6.1 {
|
||||
SELECT rowid FROM x1 WHERE a=1 OR b=6 OR c=11
|
||||
} {1 2 3 search 6}
|
||||
do_searchcount_test 6.6.2 {
|
||||
SELECT c FROM x1 WHERE a=1 OR b=6 OR c=11
|
||||
} {3 7 11 search 7}
|
||||
do_searchcount_test 6.6.3 {
|
||||
SELECT c FROM x1 WHERE c=11 OR a=1 OR b=6
|
||||
} {11 3 7 search 7}
|
||||
do_searchcount_test 6.6.4 {
|
||||
SELECT c FROM x1 WHERE b=6 OR c=11 OR a=1
|
||||
} {7 11 3 search 7}
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user