mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-15 11:41:13 +03:00
Add the ability to use indices for the first few terms of an ORDER BY clause,
then sort in batches to handle the later terms. FossilOrigin-Name: fa06a6fed9f48322d9b89721799ba12c46efa898
This commit is contained in:
41
manifest
41
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Change\sthe\snames\sof\sSRT_DistTable\sand\sSRT_Table\sused\sby\sCTE\sto\smore\nmeaningful\sSRT_DistFifo\sand\sSRT_Fifo,\srespectively.\s\sSimplify\sthe\nIgnorableOrderby()\smacro\sin\sthe\sprocess.
|
C Add\sthe\sability\sto\suse\sindices\sfor\sthe\sfirst\sfew\sterms\sof\san\sORDER\sBY\sclause,\nthen\ssort\sin\sbatches\sto\shandle\sthe\slater\sterms.
|
||||||
D 2014-03-21T19:56:09.443
|
D 2014-03-21T20:58:42.176
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@@ -164,8 +164,8 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
|||||||
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
|
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
|
||||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||||
F src/btree.c 2a0e73f26c329f49e426237e71a879ffd205d778
|
F src/btree.c 029cec7b98fe0a985922c03f101630391044c4ad
|
||||||
F src/btree.h da1b69b441ecee21f8b34ba73f0ae339540c4025
|
F src/btree.h 232836cb51753f2e96aa8ce0f052c6df850f76ba
|
||||||
F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4
|
F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4
|
||||||
F src/build.c 0d50ef95aad63f4c4fc47f3fa2670d4557c45db0
|
F src/build.c 0d50ef95aad63f4c4fc47f3fa2670d4557c45db0
|
||||||
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
|
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
|
||||||
@@ -173,7 +173,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
|||||||
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
|
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
|
||||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||||
F src/delete.c cdd57149543bb28304d8f717c243f2a86b1fc280
|
F src/delete.c cdd57149543bb28304d8f717c243f2a86b1fc280
|
||||||
F src/expr.c 6e1e8bca468753f06758db7835a85e5408351e7a
|
F src/expr.c da2b3cb41081af6b56e95e7c9e95949564ce2e21
|
||||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||||
F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf
|
F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf
|
||||||
F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811
|
F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811
|
||||||
@@ -211,18 +211,18 @@ F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
|
|||||||
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
|
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
|
||||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||||
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
|
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
|
||||||
F src/pragma.c e78b4bf2a267de2c17ee09f90b6807cf8d40e6a3
|
F src/pragma.c 10f169b9650f0930a7a6df67e1387a4c2c449f38
|
||||||
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
|
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
|
||||||
F src/printf.c e5a0005f8b3de21f85da6a709d2fbee76775bf4b
|
F src/printf.c e5a0005f8b3de21f85da6a709d2fbee76775bf4b
|
||||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||||
F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66
|
F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66
|
||||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||||
F src/select.c cbee644f795a5fa14fa79bd760c3c9c883a6b4d8
|
F src/select.c 633c56adeb382173d01016bea9e04e4dac54dfbc
|
||||||
F src/shell.c cee9f46f2688a261601b1fd3d7f4b3cddf9b5cdf
|
F src/shell.c cee9f46f2688a261601b1fd3d7f4b3cddf9b5cdf
|
||||||
F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80
|
F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80
|
||||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||||
F src/sqliteInt.h 76b1cf0836f0d022aec5045474f5c6c90f7b9730
|
F src/sqliteInt.h 1e16bac177ce6396e59af867afb90c92949895de
|
||||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||||
@@ -278,21 +278,21 @@ F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115
|
|||||||
F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c
|
F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c
|
||||||
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
|
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
|
||||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||||
F src/vdbe.c 5f0fffa9bf49a90c05dc3d46d8217603fd0ee00e
|
F src/vdbe.c 37cfae03a0c40515304fb0a8a1a97ac3aa965e87
|
||||||
F src/vdbe.h fb2c48c198300a7c632f09fc940011d2ad2fc2ae
|
F src/vdbe.h fb2c48c198300a7c632f09fc940011d2ad2fc2ae
|
||||||
F src/vdbeInt.h e54fc4f289fce48e81b3371128446033d097733b
|
F src/vdbeInt.h 2b9a6849166d0014c843ae3fd83a062be4efa325
|
||||||
F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4
|
F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4
|
||||||
F src/vdbeaux.c e45e3f9daf38c5be3fd39e9aacc1c9066af57a06
|
F src/vdbeaux.c 5078ca7de4fd5ba4535bd17fe44d5b56c2d3294c
|
||||||
F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa
|
F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa
|
||||||
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
|
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
|
||||||
F src/vdbesort.c 0fef5fa890fda760f92f293a5b0f2ccfe5d2dc55
|
F src/vdbesort.c 4abb7c0f8f19b7d7d82f4558d5da1a30fdf9ea38
|
||||||
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
|
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
|
||||||
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||||
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
|
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
|
||||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||||
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
||||||
F src/where.c eed0b83bd7ffef4ac2f7a2fcc9dcfa66b18b8b9e
|
F src/where.c f394453e4960462e62671158199f060ac956f8bc
|
||||||
F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138
|
F src/whereInt.h 2564055b440e44ebec8b47f237bbccae6719b7af
|
||||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||||
@@ -431,7 +431,7 @@ F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
|
|||||||
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||||
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||||
F test/distinct.test c7b194ef95dbddb32d77acbbab2e023c6eed0cb2
|
F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77
|
||||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||||
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
|
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
|
||||||
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
||||||
@@ -722,7 +722,8 @@ F test/orderby1.test 9b524aff9147288da43a6d7ddfdcff47fa2303c6
|
|||||||
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
|
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
|
||||||
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
|
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
|
||||||
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
|
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
|
||||||
F test/orderby5.test 0eb82d5890c3f3d0563966560cfdc984ea69e30c
|
F test/orderby5.test 2490183fef54417209d1df253633a605d46bd350
|
||||||
|
F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859
|
||||||
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
|
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
|
||||||
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
|
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
|
||||||
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
|
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
|
||||||
@@ -1089,7 +1090,7 @@ F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
|
|||||||
F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62
|
F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62
|
||||||
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
|
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
|
||||||
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||||
F test/whereG.test 2a3d5181decc801b36600fa1c40b0dad2ccc267f
|
F test/whereG.test eb3a46b3eaf38e25e3013433b2db8a25a866c215
|
||||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||||
@@ -1156,7 +1157,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||||
P 1f413aca00015100224273480e1ce39a76bf93ab
|
P 45d8cc678d128f1dda6469864215a8ed9de4366a 71e9ae72c272dc86720b2bfe719f57de437c400b
|
||||||
R 26118dcbaf585402aab527afe8f97345
|
R 3371108f475a5908c384cc490e83cfb1
|
||||||
U drh
|
U drh
|
||||||
Z d7e9ffdc5a42e976a5961e8287a0561b
|
Z 76333cbbd5592a854905d3a7e7bd7626
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
45d8cc678d128f1dda6469864215a8ed9de4366a
|
fa06a6fed9f48322d9b89721799ba12c46efa898
|
||||||
@@ -7425,6 +7425,15 @@ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Delete all information from the single table that pCur is open on.
|
||||||
|
**
|
||||||
|
** This routine only work for pCur on an ephemeral table.
|
||||||
|
*/
|
||||||
|
int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){
|
||||||
|
return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Erase all information in a table and add the root of the table to
|
** Erase all information in a table and add the root of the table to
|
||||||
** the freelist. Except, the root of the principle table (the one on
|
** the freelist. Except, the root of the principle table (the one on
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ int sqlite3BtreeIncrVacuum(Btree *);
|
|||||||
|
|
||||||
int sqlite3BtreeDropTable(Btree*, int, int*);
|
int sqlite3BtreeDropTable(Btree*, int, int*);
|
||||||
int sqlite3BtreeClearTable(Btree*, int, int*);
|
int sqlite3BtreeClearTable(Btree*, int, int*);
|
||||||
|
int sqlite3BtreeClearTableOfCursor(BtCursor*);
|
||||||
void sqlite3BtreeTripAllCursors(Btree*, int);
|
void sqlite3BtreeTripAllCursors(Btree*, int);
|
||||||
|
|
||||||
void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
|
void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
|
||||||
|
|||||||
@@ -955,7 +955,6 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
|||||||
if( p==0 ) return 0;
|
if( p==0 ) return 0;
|
||||||
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
|
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
|
||||||
if( pNew==0 ) return 0;
|
if( pNew==0 ) return 0;
|
||||||
pNew->iECursor = 0;
|
|
||||||
pNew->nExpr = i = p->nExpr;
|
pNew->nExpr = i = p->nExpr;
|
||||||
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
|
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
|
||||||
pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
|
pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
|
||||||
@@ -1068,7 +1067,6 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
|||||||
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
||||||
pNew->addrOpenEphm[0] = -1;
|
pNew->addrOpenEphm[0] = -1;
|
||||||
pNew->addrOpenEphm[1] = -1;
|
pNew->addrOpenEphm[1] = -1;
|
||||||
pNew->addrOpenEphm[2] = -1;
|
|
||||||
pNew->nSelectRow = p->nSelectRow;
|
pNew->nSelectRow = p->nSelectRow;
|
||||||
pNew->pWith = withDup(db, p->pWith);
|
pNew->pWith = withDup(db, p->pWith);
|
||||||
return pNew;
|
return pNew;
|
||||||
@@ -2340,7 +2338,7 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
|
|||||||
int i;
|
int i;
|
||||||
struct yColCache *p;
|
struct yColCache *p;
|
||||||
assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
|
assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
|
||||||
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1);
|
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
|
||||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
int x = p->iReg;
|
int x = p->iReg;
|
||||||
if( x>=iFrom && x<iFrom+nReg ){
|
if( x>=iFrom && x<iFrom+nReg ){
|
||||||
|
|||||||
@@ -1875,7 +1875,7 @@ void sqlite3Pragma(
|
|||||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
||||||
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
|
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
|
||||||
P4_DYNAMIC);
|
P4_DYNAMIC);
|
||||||
sqlite3VdbeAddOp2(v, OP_Move, 2, 4);
|
sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
|
||||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
|
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
|
||||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
|
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
|
||||||
sqlite3VdbeJumpHere(v, addr);
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
|
|||||||
248
src/select.c
248
src/select.c
@@ -14,6 +14,34 @@
|
|||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of the following object is used to record information about
|
||||||
|
** how to process the DISTINCT keyword, to simplify passing that information
|
||||||
|
** into the selectInnerLoop() routine.
|
||||||
|
*/
|
||||||
|
typedef struct DistinctCtx DistinctCtx;
|
||||||
|
struct DistinctCtx {
|
||||||
|
u8 isTnct; /* True if the DISTINCT keyword is present */
|
||||||
|
u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
|
||||||
|
int tabTnct; /* Ephemeral table used for DISTINCT processing */
|
||||||
|
int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of the following object is used to record information about
|
||||||
|
** the ORDER BY (or GROUP BY) clause of query is being coded.
|
||||||
|
*/
|
||||||
|
typedef struct SortCtx SortCtx;
|
||||||
|
struct SortCtx {
|
||||||
|
ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */
|
||||||
|
int nOBSat; /* Number of ORDER BY terms satisfied by indices */
|
||||||
|
int iECursor; /* Cursor number for the sorter */
|
||||||
|
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 */
|
||||||
|
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
|
||||||
|
};
|
||||||
|
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Delete all the content of a Select structure but do not deallocate
|
** Delete all the content of a Select structure but do not deallocate
|
||||||
@@ -87,7 +115,6 @@ Select *sqlite3SelectNew(
|
|||||||
assert( pOffset==0 || pLimit!=0 );
|
assert( pOffset==0 || pLimit!=0 );
|
||||||
pNew->addrOpenEphm[0] = -1;
|
pNew->addrOpenEphm[0] = -1;
|
||||||
pNew->addrOpenEphm[1] = -1;
|
pNew->addrOpenEphm[1] = -1;
|
||||||
pNew->addrOpenEphm[2] = -1;
|
|
||||||
if( db->mallocFailed ) {
|
if( db->mallocFailed ) {
|
||||||
clearSelect(db, pNew);
|
clearSelect(db, pNew);
|
||||||
if( pNew!=&standin ) sqlite3DbFree(db, pNew);
|
if( pNew!=&standin ) sqlite3DbFree(db, pNew);
|
||||||
@@ -419,34 +446,71 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Forward reference */
|
||||||
|
static KeyInfo *keyInfoFromExprList(
|
||||||
|
Parse *pParse, /* Parsing context */
|
||||||
|
ExprList *pList, /* Form the KeyInfo object from this ExprList */
|
||||||
|
int iStart, /* Begin with this column of pList */
|
||||||
|
int nExtra /* Add this many extra columns to the end */
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Insert code into "v" that will push the record on the top of the
|
** Insert code into "v" that will push the record in register regData
|
||||||
** stack into the sorter.
|
** into the sorter.
|
||||||
*/
|
*/
|
||||||
static void pushOntoSorter(
|
static void pushOntoSorter(
|
||||||
Parse *pParse, /* Parser context */
|
Parse *pParse, /* Parser context */
|
||||||
ExprList *pOrderBy, /* The ORDER BY clause */
|
SortCtx *pSort, /* Information about the ORDER BY clause */
|
||||||
Select *pSelect, /* The whole SELECT statement */
|
Select *pSelect, /* The whole SELECT statement */
|
||||||
int regData /* Register holding data to be sorted */
|
int regData /* Register holding data to be sorted */
|
||||||
){
|
){
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe;
|
||||||
int nExpr = pOrderBy->nExpr;
|
int nExpr = pSort->pOrderBy->nExpr;
|
||||||
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
|
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
|
||||||
int regRecord = sqlite3GetTempReg(pParse);
|
int regRecord = sqlite3GetTempReg(pParse);
|
||||||
|
int nOBSat = pSort->nOBSat;
|
||||||
int op;
|
int op;
|
||||||
sqlite3ExprCacheClear(pParse);
|
sqlite3ExprCacheClear(pParse);
|
||||||
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
|
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
|
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
|
||||||
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
|
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
|
||||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord);
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat, regRecord);
|
||||||
if( pSelect->selFlags & SF_UseSorter ){
|
if( nOBSat>0 ){
|
||||||
|
int regPrevKey; /* The first nOBSat columns of the previous row */
|
||||||
|
int addrFirst; /* Address of the OP_IfNot opcode */
|
||||||
|
int addrJmp; /* Address of the OP_Jump opcode */
|
||||||
|
VdbeOp *pOp; /* Opcode that opens the sorter */
|
||||||
|
int nKey; /* Number of sorting key columns, including OP_Sequence */
|
||||||
|
|
||||||
|
regPrevKey = pParse->nMem+1;
|
||||||
|
pParse->nMem += pSort->nOBSat;
|
||||||
|
nKey = nExpr - pSort->nOBSat + 1;
|
||||||
|
addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v);
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat);
|
||||||
|
pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex);
|
||||||
|
pOp->p2 = nKey + 1;
|
||||||
|
sqlite3VdbeChangeP4(v, -1, (char*)pOp->p4.pKeyInfo, P4_KEYINFO);
|
||||||
|
pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1);
|
||||||
|
addrJmp = sqlite3VdbeCurrentAddr(v);
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
|
||||||
|
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
|
||||||
|
pSort->regReturn = ++pParse->nMem;
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
||||||
|
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
|
||||||
|
sqlite3VdbeJumpHere(v, addrFirst);
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat);
|
||||||
|
sqlite3VdbeJumpHere(v, addrJmp);
|
||||||
|
}
|
||||||
|
if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
||||||
op = OP_SorterInsert;
|
op = OP_SorterInsert;
|
||||||
}else{
|
}else{
|
||||||
op = OP_IdxInsert;
|
op = OP_IdxInsert;
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp2(v, op, pOrderBy->iECursor, regRecord);
|
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
|
||||||
|
if( nOBSat==0 ){
|
||||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||||
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
|
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
|
||||||
|
}
|
||||||
if( pSelect->iLimit ){
|
if( pSelect->iLimit ){
|
||||||
int addr1, addr2;
|
int addr1, addr2;
|
||||||
int iLimit;
|
int iLimit;
|
||||||
@@ -459,8 +523,8 @@ static void pushOntoSorter(
|
|||||||
sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
|
sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
|
||||||
addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
|
addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
sqlite3VdbeJumpHere(v, addr1);
|
sqlite3VdbeJumpHere(v, addr1);
|
||||||
sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
|
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
|
||||||
sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
|
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
|
||||||
sqlite3VdbeJumpHere(v, addr2);
|
sqlite3VdbeJumpHere(v, addr2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -534,19 +598,6 @@ static int checkForMultiColumnSelectError(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
** An instance of the following object is used to record information about
|
|
||||||
** how to process the DISTINCT keyword, to simplify passing that information
|
|
||||||
** into the selectInnerLoop() routine.
|
|
||||||
*/
|
|
||||||
typedef struct DistinctCtx DistinctCtx;
|
|
||||||
struct DistinctCtx {
|
|
||||||
u8 isTnct; /* True if the DISTINCT keyword is present */
|
|
||||||
u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
|
|
||||||
int tabTnct; /* Ephemeral table used for DISTINCT processing */
|
|
||||||
int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine generates the code for the inside of the inner loop
|
** This routine generates the code for the inside of the inner loop
|
||||||
** of a SELECT.
|
** of a SELECT.
|
||||||
@@ -561,7 +612,7 @@ static void selectInnerLoop(
|
|||||||
Select *p, /* The complete select statement being coded */
|
Select *p, /* The complete select statement being coded */
|
||||||
ExprList *pEList, /* List of values being extracted */
|
ExprList *pEList, /* List of values being extracted */
|
||||||
int srcTab, /* Pull data from this table */
|
int srcTab, /* Pull data from this table */
|
||||||
ExprList *pOrderBy, /* If not NULL, sort results using this key */
|
SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */
|
||||||
DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
|
DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
|
||||||
SelectDest *pDest, /* How to dispose of the results */
|
SelectDest *pDest, /* How to dispose of the results */
|
||||||
int iContinue, /* Jump here to continue with next row */
|
int iContinue, /* Jump here to continue with next row */
|
||||||
@@ -578,7 +629,8 @@ static void selectInnerLoop(
|
|||||||
assert( v );
|
assert( v );
|
||||||
assert( pEList!=0 );
|
assert( pEList!=0 );
|
||||||
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
|
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
|
||||||
if( pOrderBy==0 && !hasDistinct ){
|
if( pSort && pSort->pOrderBy==0 ) pSort = 0;
|
||||||
|
if( pSort==0 && !hasDistinct ){
|
||||||
assert( iContinue!=0 );
|
assert( iContinue!=0 );
|
||||||
codeOffset(v, p->iOffset, iContinue);
|
codeOffset(v, p->iOffset, iContinue);
|
||||||
}
|
}
|
||||||
@@ -669,7 +721,7 @@ static void selectInnerLoop(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( pOrderBy==0 ){
|
if( pSort==0 ){
|
||||||
codeOffset(v, p->iOffset, iContinue);
|
codeOffset(v, p->iOffset, iContinue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -718,11 +770,11 @@ static void selectInnerLoop(
|
|||||||
int addr = sqlite3VdbeCurrentAddr(v) + 4;
|
int addr = sqlite3VdbeCurrentAddr(v) + 4;
|
||||||
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v);
|
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v);
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
|
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
|
||||||
assert( pOrderBy==0 );
|
assert( pSort==0 );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if( pOrderBy ){
|
if( pSort ){
|
||||||
pushOntoSorter(pParse, pOrderBy, p, r1);
|
pushOntoSorter(pParse, pSort, p, r1);
|
||||||
}else{
|
}else{
|
||||||
int r2 = sqlite3GetTempReg(pParse);
|
int r2 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
|
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
|
||||||
@@ -743,12 +795,12 @@ static void selectInnerLoop(
|
|||||||
assert( nResultCol==1 );
|
assert( nResultCol==1 );
|
||||||
pDest->affSdst =
|
pDest->affSdst =
|
||||||
sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
|
sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
|
||||||
if( pOrderBy ){
|
if( pSort ){
|
||||||
/* At first glance you would think we could optimize out the
|
/* At first glance you would think we could optimize out the
|
||||||
** ORDER BY in this case since the order of entries in the set
|
** ORDER BY in this case since the order of entries in the set
|
||||||
** does not matter. But there might be a LIMIT clause, in which
|
** does not matter. But there might be a LIMIT clause, in which
|
||||||
** case the order does matter */
|
** case the order does matter */
|
||||||
pushOntoSorter(pParse, pOrderBy, p, regResult);
|
pushOntoSorter(pParse, pSort, p, regResult);
|
||||||
}else{
|
}else{
|
||||||
int r1 = sqlite3GetTempReg(pParse);
|
int r1 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
|
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
|
||||||
@@ -773,8 +825,8 @@ static void selectInnerLoop(
|
|||||||
*/
|
*/
|
||||||
case SRT_Mem: {
|
case SRT_Mem: {
|
||||||
assert( nResultCol==1 );
|
assert( nResultCol==1 );
|
||||||
if( pOrderBy ){
|
if( pSort ){
|
||||||
pushOntoSorter(pParse, pOrderBy, p, regResult);
|
pushOntoSorter(pParse, pSort, p, regResult);
|
||||||
}else{
|
}else{
|
||||||
sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
|
sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
|
||||||
/* The LIMIT clause will jump out of the loop for us */
|
/* The LIMIT clause will jump out of the loop for us */
|
||||||
@@ -787,10 +839,10 @@ static void selectInnerLoop(
|
|||||||
case SRT_Output: { /* Return the results */
|
case SRT_Output: { /* Return the results */
|
||||||
testcase( eDest==SRT_Coroutine );
|
testcase( eDest==SRT_Coroutine );
|
||||||
testcase( eDest==SRT_Output );
|
testcase( eDest==SRT_Output );
|
||||||
if( pOrderBy ){
|
if( pSort ){
|
||||||
int r1 = sqlite3GetTempReg(pParse);
|
int r1 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
|
||||||
pushOntoSorter(pParse, pOrderBy, p, r1);
|
pushOntoSorter(pParse, pSort, p, r1);
|
||||||
sqlite3ReleaseTempReg(pParse, r1);
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
}else if( eDest==SRT_Coroutine ){
|
}else if( eDest==SRT_Coroutine ){
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
|
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
|
||||||
@@ -867,7 +919,7 @@ static void selectInnerLoop(
|
|||||||
** there is a sorter, in which case the sorter has already limited
|
** there is a sorter, in which case the sorter has already limited
|
||||||
** the output for us.
|
** the output for us.
|
||||||
*/
|
*/
|
||||||
if( pOrderBy==0 && p->iLimit ){
|
if( pSort==0 && p->iLimit ){
|
||||||
sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
|
sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -938,7 +990,12 @@ int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; }
|
|||||||
** function is responsible for seeing that this structure is eventually
|
** function is responsible for seeing that this structure is eventually
|
||||||
** freed.
|
** freed.
|
||||||
*/
|
*/
|
||||||
static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){
|
static KeyInfo *keyInfoFromExprList(
|
||||||
|
Parse *pParse, /* Parsing context */
|
||||||
|
ExprList *pList, /* Form the KeyInfo object from this ExprList */
|
||||||
|
int iStart, /* Begin with this column of pList */
|
||||||
|
int nExtra /* Add this many extra columns to the end */
|
||||||
|
){
|
||||||
int nExpr;
|
int nExpr;
|
||||||
KeyInfo *pInfo;
|
KeyInfo *pInfo;
|
||||||
struct ExprList_item *pItem;
|
struct ExprList_item *pItem;
|
||||||
@@ -946,15 +1003,15 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
nExpr = pList->nExpr;
|
nExpr = pList->nExpr;
|
||||||
pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra, 1);
|
pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1);
|
||||||
if( pInfo ){
|
if( pInfo ){
|
||||||
assert( sqlite3KeyInfoIsWriteable(pInfo) );
|
assert( sqlite3KeyInfoIsWriteable(pInfo) );
|
||||||
for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
|
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
|
||||||
CollSeq *pColl;
|
CollSeq *pColl;
|
||||||
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
|
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
|
||||||
if( !pColl ) pColl = db->pDfltColl;
|
if( !pColl ) pColl = db->pDfltColl;
|
||||||
pInfo->aColl[i] = pColl;
|
pInfo->aColl[i-iStart] = pColl;
|
||||||
pInfo->aSortOrder[i] = pItem->sortOrder;
|
pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pInfo;
|
return pInfo;
|
||||||
@@ -1056,24 +1113,31 @@ static void explainComposite(
|
|||||||
static void generateSortTail(
|
static void generateSortTail(
|
||||||
Parse *pParse, /* Parsing context */
|
Parse *pParse, /* Parsing context */
|
||||||
Select *p, /* The SELECT statement */
|
Select *p, /* The SELECT statement */
|
||||||
Vdbe *v, /* Generate code into this VDBE */
|
SortCtx *pSort, /* Information on the ORDER BY clause */
|
||||||
int nColumn, /* Number of columns of data */
|
int nColumn, /* Number of columns of data */
|
||||||
SelectDest *pDest /* Write the sorted results here */
|
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 = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
|
||||||
int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
|
int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
|
||||||
int addr;
|
int addr;
|
||||||
|
int addrOnce = 0;
|
||||||
int iTab;
|
int iTab;
|
||||||
int pseudoTab = 0;
|
int pseudoTab = 0;
|
||||||
ExprList *pOrderBy = p->pOrderBy;
|
ExprList *pOrderBy = pSort->pOrderBy;
|
||||||
|
|
||||||
int eDest = pDest->eDest;
|
int eDest = pDest->eDest;
|
||||||
int iParm = pDest->iSDParm;
|
int iParm = pDest->iSDParm;
|
||||||
|
|
||||||
int regRow;
|
int regRow;
|
||||||
int regRowid;
|
int regRowid;
|
||||||
|
int nKey;
|
||||||
|
|
||||||
iTab = pOrderBy->iECursor;
|
if( pSort->labelBkOut ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
|
||||||
|
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
|
||||||
|
addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||||
|
}
|
||||||
|
iTab = pSort->iECursor;
|
||||||
regRow = sqlite3GetTempReg(pParse);
|
regRow = sqlite3GetTempReg(pParse);
|
||||||
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
|
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
|
||||||
pseudoTab = pParse->nTab++;
|
pseudoTab = pParse->nTab++;
|
||||||
@@ -1082,20 +1146,23 @@ static void generateSortTail(
|
|||||||
}else{
|
}else{
|
||||||
regRowid = sqlite3GetTempReg(pParse);
|
regRowid = sqlite3GetTempReg(pParse);
|
||||||
}
|
}
|
||||||
if( p->selFlags & SF_UseSorter ){
|
nKey = pOrderBy->nExpr - pSort->nOBSat;
|
||||||
|
if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
||||||
int regSortOut = ++pParse->nMem;
|
int regSortOut = ++pParse->nMem;
|
||||||
int ptab2 = pParse->nTab++;
|
int ptab2 = pParse->nTab++;
|
||||||
sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, pOrderBy->nExpr+2);
|
sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2);
|
||||||
|
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
|
||||||
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
|
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
|
||||||
VdbeCoverage(v);
|
VdbeCoverage(v);
|
||||||
codeOffset(v, p->iOffset, addrContinue);
|
codeOffset(v, p->iOffset, addrContinue);
|
||||||
sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
|
sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, ptab2, pOrderBy->nExpr+1, regRow);
|
sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow);
|
||||||
sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
|
sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
|
||||||
}else{
|
}else{
|
||||||
|
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
|
||||||
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
|
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
|
||||||
codeOffset(v, p->iOffset, addrContinue);
|
codeOffset(v, p->iOffset, addrContinue);
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr+1, regRow);
|
sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow);
|
||||||
}
|
}
|
||||||
switch( eDest ){
|
switch( eDest ){
|
||||||
case SRT_Table:
|
case SRT_Table:
|
||||||
@@ -1150,11 +1217,12 @@ static void generateSortTail(
|
|||||||
/* The bottom of the loop
|
/* The bottom of the loop
|
||||||
*/
|
*/
|
||||||
sqlite3VdbeResolveLabel(v, addrContinue);
|
sqlite3VdbeResolveLabel(v, addrContinue);
|
||||||
if( p->selFlags & SF_UseSorter ){
|
if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
||||||
sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v);
|
sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
|
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
|
||||||
}
|
}
|
||||||
|
if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn);
|
||||||
sqlite3VdbeResolveLabel(v, addrBreak);
|
sqlite3VdbeResolveLabel(v, addrBreak);
|
||||||
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
|
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
|
sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
|
||||||
@@ -4312,7 +4380,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
|||||||
"argument");
|
"argument");
|
||||||
pFunc->iDistinct = -1;
|
pFunc->iDistinct = -1;
|
||||||
}else{
|
}else{
|
||||||
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0);
|
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0);
|
||||||
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
|
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
|
||||||
(char*)pKeyInfo, P4_KEYINFO);
|
(char*)pKeyInfo, P4_KEYINFO);
|
||||||
}
|
}
|
||||||
@@ -4467,12 +4535,11 @@ int sqlite3Select(
|
|||||||
ExprList *pEList; /* List of columns to extract. */
|
ExprList *pEList; /* List of columns to extract. */
|
||||||
SrcList *pTabList; /* List of tables to select from */
|
SrcList *pTabList; /* List of tables to select from */
|
||||||
Expr *pWhere; /* The WHERE clause. May be NULL */
|
Expr *pWhere; /* The WHERE clause. May be NULL */
|
||||||
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
|
|
||||||
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
|
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
|
||||||
Expr *pHaving; /* The HAVING clause. May be NULL */
|
Expr *pHaving; /* The HAVING clause. May be NULL */
|
||||||
int rc = 1; /* Value to return from this function */
|
int rc = 1; /* Value to return from this function */
|
||||||
int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
|
|
||||||
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
|
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
|
||||||
|
SortCtx sSort; /* Info on how to code the ORDER BY clause */
|
||||||
AggInfo sAggInfo; /* Information used by aggregate queries */
|
AggInfo sAggInfo; /* Information used by aggregate queries */
|
||||||
int iEnd; /* Address of the end of the query */
|
int iEnd; /* Address of the end of the query */
|
||||||
sqlite3 *db; /* The database connection */
|
sqlite3 *db; /* The database connection */
|
||||||
@@ -4505,7 +4572,8 @@ int sqlite3Select(
|
|||||||
p->selFlags &= ~SF_Distinct;
|
p->selFlags &= ~SF_Distinct;
|
||||||
}
|
}
|
||||||
sqlite3SelectPrep(pParse, p, 0);
|
sqlite3SelectPrep(pParse, p, 0);
|
||||||
pOrderBy = p->pOrderBy;
|
memset(&sSort, 0, sizeof(sSort));
|
||||||
|
sSort.pOrderBy = p->pOrderBy;
|
||||||
pTabList = p->pSrc;
|
pTabList = p->pSrc;
|
||||||
pEList = p->pEList;
|
pEList = p->pEList;
|
||||||
if( pParse->nErr || db->mallocFailed ){
|
if( pParse->nErr || db->mallocFailed ){
|
||||||
@@ -4627,7 +4695,7 @@ int sqlite3Select(
|
|||||||
pParse->nHeight -= sqlite3SelectExprHeight(p);
|
pParse->nHeight -= sqlite3SelectExprHeight(p);
|
||||||
pTabList = p->pSrc;
|
pTabList = p->pSrc;
|
||||||
if( !IgnorableOrderby(pDest) ){
|
if( !IgnorableOrderby(pDest) ){
|
||||||
pOrderBy = p->pOrderBy;
|
sSort.pOrderBy = p->pOrderBy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pEList = p->pEList;
|
pEList = p->pEList;
|
||||||
@@ -4654,9 +4722,9 @@ int sqlite3Select(
|
|||||||
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
|
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
|
||||||
** to disable this optimization for testing purposes.
|
** to disable this optimization for testing purposes.
|
||||||
*/
|
*/
|
||||||
if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy, -1)==0
|
if( sqlite3ExprListCompare(p->pGroupBy, sSort.pOrderBy, -1)==0
|
||||||
&& OptimizationEnabled(db, SQLITE_GroupByOrder) ){
|
&& OptimizationEnabled(db, SQLITE_GroupByOrder) ){
|
||||||
pOrderBy = 0;
|
sSort.pOrderBy = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
|
/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
|
||||||
@@ -4675,12 +4743,12 @@ int sqlite3Select(
|
|||||||
** BY and DISTINCT, and an index or separate temp-table for the other.
|
** BY and DISTINCT, and an index or separate temp-table for the other.
|
||||||
*/
|
*/
|
||||||
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
|
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
|
||||||
&& sqlite3ExprListCompare(pOrderBy, p->pEList, -1)==0
|
&& sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0
|
||||||
){
|
){
|
||||||
p->selFlags &= ~SF_Distinct;
|
p->selFlags &= ~SF_Distinct;
|
||||||
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
|
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
|
||||||
pGroupBy = p->pGroupBy;
|
pGroupBy = p->pGroupBy;
|
||||||
pOrderBy = 0;
|
sSort.pOrderBy = 0;
|
||||||
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
|
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
|
||||||
** the sDistinct.isTnct is still set. Hence, isTnct represents the
|
** the sDistinct.isTnct is still set. Hence, isTnct represents the
|
||||||
** original setting of the SF_Distinct flag, not the current setting */
|
** original setting of the SF_Distinct flag, not the current setting */
|
||||||
@@ -4694,16 +4762,16 @@ int sqlite3Select(
|
|||||||
** we figure out that the sorting index is not needed. The addrSortIndex
|
** we figure out that the sorting index is not needed. The addrSortIndex
|
||||||
** variable is used to facilitate that change.
|
** variable is used to facilitate that change.
|
||||||
*/
|
*/
|
||||||
if( pOrderBy ){
|
if( sSort.pOrderBy ){
|
||||||
KeyInfo *pKeyInfo;
|
KeyInfo *pKeyInfo;
|
||||||
pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 0);
|
pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0);
|
||||||
pOrderBy->iECursor = pParse->nTab++;
|
sSort.iECursor = pParse->nTab++;
|
||||||
p->addrOpenEphm[2] = addrSortIndex =
|
sSort.addrSortIndex =
|
||||||
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
||||||
pOrderBy->iECursor, pOrderBy->nExpr+2, 0,
|
sSort.iECursor, sSort.pOrderBy->nExpr+2, 0,
|
||||||
(char*)pKeyInfo, P4_KEYINFO);
|
(char*)pKeyInfo, P4_KEYINFO);
|
||||||
}else{
|
}else{
|
||||||
addrSortIndex = -1;
|
sSort.addrSortIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the output is destined for a temporary table, open that table.
|
/* If the output is destined for a temporary table, open that table.
|
||||||
@@ -4717,9 +4785,9 @@ int sqlite3Select(
|
|||||||
iEnd = sqlite3VdbeMakeLabel(v);
|
iEnd = sqlite3VdbeMakeLabel(v);
|
||||||
p->nSelectRow = LARGEST_INT64;
|
p->nSelectRow = LARGEST_INT64;
|
||||||
computeLimitRegisters(pParse, p, iEnd);
|
computeLimitRegisters(pParse, p, iEnd);
|
||||||
if( p->iLimit==0 && addrSortIndex>=0 ){
|
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
|
||||||
sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen;
|
sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen;
|
||||||
p->selFlags |= SF_UseSorter;
|
sSort.sortFlags |= SORTFLAG_UseSorter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open a virtual index to use for the distinct set.
|
/* Open a virtual index to use for the distinct set.
|
||||||
@@ -4728,7 +4796,7 @@ int sqlite3Select(
|
|||||||
sDistinct.tabTnct = pParse->nTab++;
|
sDistinct.tabTnct = pParse->nTab++;
|
||||||
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
||||||
sDistinct.tabTnct, 0, 0,
|
sDistinct.tabTnct, 0, 0,
|
||||||
(char*)keyInfoFromExprList(pParse, p->pEList, 0),
|
(char*)keyInfoFromExprList(pParse, p->pEList,0,0),
|
||||||
P4_KEYINFO);
|
P4_KEYINFO);
|
||||||
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||||
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
|
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
|
||||||
@@ -4741,8 +4809,8 @@ int sqlite3Select(
|
|||||||
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
|
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
|
||||||
|
|
||||||
/* Begin the database scan. */
|
/* Begin the database scan. */
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, p->pEList,
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
|
||||||
wctrlFlags, 0);
|
p->pEList, wctrlFlags, 0);
|
||||||
if( pWInfo==0 ) goto select_end;
|
if( pWInfo==0 ) goto select_end;
|
||||||
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
|
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
|
||||||
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
|
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
|
||||||
@@ -4750,19 +4818,23 @@ int sqlite3Select(
|
|||||||
if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
|
if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
|
||||||
sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
|
sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
|
||||||
}
|
}
|
||||||
if( pOrderBy && sqlite3WhereIsOrdered(pWInfo) ) pOrderBy = 0;
|
if( sSort.pOrderBy ){
|
||||||
|
sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
|
||||||
|
if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
|
||||||
|
sSort.pOrderBy = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If sorting index that was created by a prior OP_OpenEphemeral
|
/* If sorting index that was created by a prior OP_OpenEphemeral
|
||||||
** instruction ended up not being needed, then change the OP_OpenEphemeral
|
** instruction ended up not being needed, then change the OP_OpenEphemeral
|
||||||
** into an OP_Noop.
|
** into an OP_Noop.
|
||||||
*/
|
*/
|
||||||
if( addrSortIndex>=0 && pOrderBy==0 ){
|
if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){
|
||||||
sqlite3VdbeChangeToNoop(v, addrSortIndex);
|
sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
|
||||||
p->addrOpenEphm[2] = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the standard inner loop. */
|
/* Use the standard inner loop. */
|
||||||
selectInnerLoop(pParse, p, pEList, -1, pOrderBy, &sDistinct, pDest,
|
selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
|
||||||
sqlite3WhereContinueLabel(pWInfo),
|
sqlite3WhereContinueLabel(pWInfo),
|
||||||
sqlite3WhereBreakLabel(pWInfo));
|
sqlite3WhereBreakLabel(pWInfo));
|
||||||
|
|
||||||
@@ -4818,7 +4890,7 @@ int sqlite3Select(
|
|||||||
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
|
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
|
||||||
sAggInfo.pGroupBy = pGroupBy;
|
sAggInfo.pGroupBy = pGroupBy;
|
||||||
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
||||||
sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
|
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
||||||
if( pHaving ){
|
if( pHaving ){
|
||||||
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
||||||
}
|
}
|
||||||
@@ -4852,7 +4924,7 @@ int sqlite3Select(
|
|||||||
** will be converted into a Noop.
|
** will be converted into a Noop.
|
||||||
*/
|
*/
|
||||||
sAggInfo.sortingIdx = pParse->nTab++;
|
sAggInfo.sortingIdx = pParse->nTab++;
|
||||||
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0);
|
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0);
|
||||||
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
||||||
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
|
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
|
||||||
0, (char*)pKeyInfo, P4_KEYINFO);
|
0, (char*)pKeyInfo, P4_KEYINFO);
|
||||||
@@ -4884,7 +4956,7 @@ int sqlite3Select(
|
|||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
|
||||||
WHERE_GROUPBY, 0);
|
WHERE_GROUPBY, 0);
|
||||||
if( pWInfo==0 ) goto select_end;
|
if( pWInfo==0 ) goto select_end;
|
||||||
if( sqlite3WhereIsOrdered(pWInfo) ){
|
if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
|
||||||
/* The optimizer is able to deliver rows in group by order so
|
/* The optimizer is able to deliver rows in group by order so
|
||||||
** we do not have to sort. The OP_OpenEphemeral table will be
|
** we do not have to sort. The OP_OpenEphemeral table will be
|
||||||
** cancelled later because we still need to use the pKeyInfo
|
** cancelled later because we still need to use the pKeyInfo
|
||||||
@@ -5035,7 +5107,7 @@ int sqlite3Select(
|
|||||||
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
||||||
finalizeAggFunctions(pParse, &sAggInfo);
|
finalizeAggFunctions(pParse, &sAggInfo);
|
||||||
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
|
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
|
||||||
selectInnerLoop(pParse, p, p->pEList, -1, pOrderBy,
|
selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
|
||||||
&sDistinct, pDest,
|
&sDistinct, pDest,
|
||||||
addrOutputRow+1, addrSetAbort);
|
addrOutputRow+1, addrSetAbort);
|
||||||
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
||||||
@@ -5167,7 +5239,7 @@ int sqlite3Select(
|
|||||||
}
|
}
|
||||||
updateAccumulator(pParse, &sAggInfo);
|
updateAccumulator(pParse, &sAggInfo);
|
||||||
assert( pMinMax==0 || pMinMax->nExpr==1 );
|
assert( pMinMax==0 || pMinMax->nExpr==1 );
|
||||||
if( sqlite3WhereIsOrdered(pWInfo) ){
|
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo));
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo));
|
||||||
VdbeComment((v, "%s() by index",
|
VdbeComment((v, "%s() by index",
|
||||||
(flag==WHERE_ORDERBY_MIN?"min":"max")));
|
(flag==WHERE_ORDERBY_MIN?"min":"max")));
|
||||||
@@ -5176,7 +5248,7 @@ int sqlite3Select(
|
|||||||
finalizeAggFunctions(pParse, &sAggInfo);
|
finalizeAggFunctions(pParse, &sAggInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
pOrderBy = 0;
|
sSort.pOrderBy = 0;
|
||||||
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
|
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
|
||||||
selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
|
selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
|
||||||
pDest, addrEnd, addrEnd);
|
pDest, addrEnd, addrEnd);
|
||||||
@@ -5193,9 +5265,9 @@ int sqlite3Select(
|
|||||||
/* If there is an ORDER BY clause, then we need to sort the results
|
/* If there is an ORDER BY clause, then we need to sort the results
|
||||||
** and send them to the callback one by one.
|
** and send them to the callback one by one.
|
||||||
*/
|
*/
|
||||||
if( pOrderBy ){
|
if( sSort.pOrderBy ){
|
||||||
explainTempTable(pParse, "ORDER BY");
|
explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
|
||||||
generateSortTail(pParse, p, v, pEList->nExpr, pDest);
|
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Jump here to skip this query
|
/* Jump here to skip this query
|
||||||
|
|||||||
@@ -1958,7 +1958,6 @@ struct Expr {
|
|||||||
*/
|
*/
|
||||||
struct ExprList {
|
struct ExprList {
|
||||||
int nExpr; /* Number of expressions on the list */
|
int nExpr; /* Number of expressions on the list */
|
||||||
int iECursor; /* VDBE Cursor associated with this ExprList */
|
|
||||||
struct ExprList_item { /* For each expression in the list */
|
struct ExprList_item { /* For each expression in the list */
|
||||||
Expr *pExpr; /* The list of expressions */
|
Expr *pExpr; /* The list of expressions */
|
||||||
char *zName; /* Token associated with this expression */
|
char *zName; /* Token associated with this expression */
|
||||||
@@ -2182,7 +2181,7 @@ struct Select {
|
|||||||
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
||||||
u16 selFlags; /* Various SF_* values */
|
u16 selFlags; /* Various SF_* values */
|
||||||
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
||||||
int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
|
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
|
||||||
u64 nSelectRow; /* Estimated number of result rows */
|
u64 nSelectRow; /* Estimated number of result rows */
|
||||||
SrcList *pSrc; /* The FROM clause */
|
SrcList *pSrc; /* The FROM clause */
|
||||||
Expr *pWhere; /* The WHERE clause */
|
Expr *pWhere; /* The WHERE clause */
|
||||||
@@ -2206,9 +2205,9 @@ struct Select {
|
|||||||
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
|
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
|
||||||
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
|
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
|
||||||
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
|
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
|
||||||
#define SF_UseSorter 0x0040 /* Sort using a sorter */
|
/* 0x0040 NOT USED */
|
||||||
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
|
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
|
||||||
#define SF_Materialize 0x0100 /* NOT USED */
|
/* 0x0100 NOT USED */
|
||||||
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
||||||
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
|
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
|
||||||
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
|
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
|
||||||
|
|||||||
38
src/vdbe.c
38
src/vdbe.c
@@ -1080,10 +1080,11 @@ case OP_Variable: { /* out2-prerelease */
|
|||||||
/* Opcode: Move P1 P2 P3 * *
|
/* Opcode: Move P1 P2 P3 * *
|
||||||
** Synopsis: r[P2@P3]=r[P1@P3]
|
** Synopsis: r[P2@P3]=r[P1@P3]
|
||||||
**
|
**
|
||||||
** Move the values in register P1..P1+P3 over into
|
** Move the P3 values in register P1..P1+P3-1 over into
|
||||||
** registers P2..P2+P3. Registers P1..P1+P3 are
|
** registers P2..P2+P3-1. Registers P1..P1+P3-1 are
|
||||||
** left holding a NULL. It is an error for register ranges
|
** left holding a NULL. It is an error for register ranges
|
||||||
** P1..P1+P3 and P2..P2+P3 to overlap.
|
** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error
|
||||||
|
** for P3 to be less than 1.
|
||||||
*/
|
*/
|
||||||
case OP_Move: {
|
case OP_Move: {
|
||||||
char *zMalloc; /* Holding variable for allocated memory */
|
char *zMalloc; /* Holding variable for allocated memory */
|
||||||
@@ -1094,7 +1095,7 @@ case OP_Move: {
|
|||||||
n = pOp->p3;
|
n = pOp->p3;
|
||||||
p1 = pOp->p1;
|
p1 = pOp->p1;
|
||||||
p2 = pOp->p2;
|
p2 = pOp->p2;
|
||||||
assert( n>=0 && p1>0 && p2>0 );
|
assert( n>0 && p1>0 && p2>0 );
|
||||||
assert( p1+n<=p2 || p2+n<=p1 );
|
assert( p1+n<=p2 || p2+n<=p1 );
|
||||||
|
|
||||||
pIn1 = &aMem[p1];
|
pIn1 = &aMem[p1];
|
||||||
@@ -1118,7 +1119,7 @@ case OP_Move: {
|
|||||||
REGISTER_TRACE(p2++, pOut);
|
REGISTER_TRACE(p2++, pOut);
|
||||||
pIn1++;
|
pIn1++;
|
||||||
pOut++;
|
pOut++;
|
||||||
}while( n-- );
|
}while( --n );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1995,6 +1996,7 @@ case OP_Permutation: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: Compare P1 P2 P3 P4 P5
|
/* Opcode: Compare P1 P2 P3 P4 P5
|
||||||
|
** Synopsis: r[P1@P3] <-> r[P2@P3]
|
||||||
**
|
**
|
||||||
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
|
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
|
||||||
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
|
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
|
||||||
@@ -3330,6 +3332,7 @@ case OP_OpenEphemeral: {
|
|||||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||||
if( pCx==0 ) goto no_mem;
|
if( pCx==0 ) goto no_mem;
|
||||||
pCx->nullRow = 1;
|
pCx->nullRow = 1;
|
||||||
|
pCx->isEphemeral = 1;
|
||||||
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
|
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
|
||||||
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
|
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
@@ -3820,7 +3823,7 @@ case OP_NotExists: { /* jump, in3 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: Sequence P1 P2 * * *
|
/* Opcode: Sequence P1 P2 * * *
|
||||||
** Synopsis: r[P2]=rowid
|
** Synopsis: r[P2]=cursor[P1].ctr++
|
||||||
**
|
**
|
||||||
** Find the next available sequence number for cursor P1.
|
** Find the next available sequence number for cursor P1.
|
||||||
** Write the sequence number into register P2.
|
** Write the sequence number into register P2.
|
||||||
@@ -4869,6 +4872,29 @@ case OP_Clear: {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Opcode: ResetSorter P1 * * * *
|
||||||
|
**
|
||||||
|
** Delete all contents from the ephemeral table or sorter
|
||||||
|
** that is open on cursor P1.
|
||||||
|
**
|
||||||
|
** This opcode only works for cursors used for sorting and
|
||||||
|
** opened with OP_OpenEphemeral or OP_SorterOpen.
|
||||||
|
*/
|
||||||
|
case OP_ResetSorter: {
|
||||||
|
VdbeCursor *pC;
|
||||||
|
|
||||||
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||||
|
pC = p->apCsr[pOp->p1];
|
||||||
|
assert( pC!=0 );
|
||||||
|
if( pC->pSorter ){
|
||||||
|
sqlite3VdbeSorterReset(db, pC->pSorter);
|
||||||
|
}else{
|
||||||
|
assert( pC->isEphemeral );
|
||||||
|
rc = sqlite3BtreeClearTableOfCursor(pC->pCursor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Opcode: CreateTable P1 P2 * * *
|
/* Opcode: CreateTable P1 P2 * * *
|
||||||
** Synopsis: r[P2]=root iDb=P1
|
** Synopsis: r[P2]=root iDb=P1
|
||||||
**
|
**
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ struct VdbeCursor {
|
|||||||
u8 nullRow; /* True if pointing to a row with no data */
|
u8 nullRow; /* True if pointing to a row with no data */
|
||||||
u8 rowidIsValid; /* True if lastRowid is valid */
|
u8 rowidIsValid; /* True if lastRowid is valid */
|
||||||
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||||
|
Bool isEphemeral:1; /* True for an ephemeral table */
|
||||||
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
|
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
|
||||||
Bool isTable:1; /* True if a table requiring integer keys */
|
Bool isTable:1; /* True if a table requiring integer keys */
|
||||||
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
|
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
|
||||||
@@ -437,6 +438,7 @@ int sqlite3VdbeFrameRestore(VdbeFrame *);
|
|||||||
int sqlite3VdbeTransferError(Vdbe *p);
|
int sqlite3VdbeTransferError(Vdbe *p);
|
||||||
|
|
||||||
int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
|
int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
|
||||||
|
void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
|
||||||
void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
|
void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
|
||||||
int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
|
int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
|
||||||
int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
|
int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
|
||||||
|
|||||||
@@ -783,7 +783,9 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
|||||||
addr = p->nOp - 1;
|
addr = p->nOp - 1;
|
||||||
}
|
}
|
||||||
pOp = &p->aOp[addr];
|
pOp = &p->aOp[addr];
|
||||||
assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 );
|
assert( pOp->p4type==P4_NOTUSED
|
||||||
|
|| pOp->p4type==P4_INT32
|
||||||
|
|| pOp->p4type==P4_KEYINFO );
|
||||||
freeP4(db, pOp->p4type, pOp->p4.p);
|
freeP4(db, pOp->p4type, pOp->p4.p);
|
||||||
pOp->p4.p = 0;
|
pOp->p4.p = 0;
|
||||||
if( n==P4_INT32 ){
|
if( n==P4_INT32 ){
|
||||||
|
|||||||
@@ -505,22 +505,39 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
|
** Reset a sorting cursor back to its original empty state.
|
||||||
*/
|
*/
|
||||||
void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
|
void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
|
||||||
VdbeSorter *pSorter = pCsr->pSorter;
|
|
||||||
if( pSorter ){
|
|
||||||
if( pSorter->aIter ){
|
if( pSorter->aIter ){
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<pSorter->nTree; i++){
|
for(i=0; i<pSorter->nTree; i++){
|
||||||
vdbeSorterIterZero(db, &pSorter->aIter[i]);
|
vdbeSorterIterZero(db, &pSorter->aIter[i]);
|
||||||
}
|
}
|
||||||
sqlite3DbFree(db, pSorter->aIter);
|
sqlite3DbFree(db, pSorter->aIter);
|
||||||
|
pSorter->aIter = 0;
|
||||||
}
|
}
|
||||||
if( pSorter->pTemp1 ){
|
if( pSorter->pTemp1 ){
|
||||||
sqlite3OsCloseFree(pSorter->pTemp1);
|
sqlite3OsCloseFree(pSorter->pTemp1);
|
||||||
|
pSorter->pTemp1 = 0;
|
||||||
}
|
}
|
||||||
vdbeSorterRecordFree(db, pSorter->pRecord);
|
vdbeSorterRecordFree(db, pSorter->pRecord);
|
||||||
|
pSorter->pRecord = 0;
|
||||||
|
pSorter->iWriteOff = 0;
|
||||||
|
pSorter->iReadOff = 0;
|
||||||
|
pSorter->nInMemory = 0;
|
||||||
|
pSorter->nTree = 0;
|
||||||
|
pSorter->nPMA = 0;
|
||||||
|
pSorter->aTree = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
|
||||||
|
*/
|
||||||
|
void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
|
||||||
|
VdbeSorter *pSorter = pCsr->pSorter;
|
||||||
|
if( pSorter ){
|
||||||
|
sqlite3VdbeSorterReset(db, pSorter);
|
||||||
sqlite3DbFree(db, pSorter->pUnpacked);
|
sqlite3DbFree(db, pSorter->pUnpacked);
|
||||||
sqlite3DbFree(db, pSorter);
|
sqlite3DbFree(db, pSorter);
|
||||||
pCsr->pSorter = 0;
|
pCsr->pSorter = 0;
|
||||||
|
|||||||
128
src/where.c
128
src/where.c
@@ -39,7 +39,7 @@ int sqlite3WhereIsDistinct(WhereInfo *pWInfo){
|
|||||||
** Return FALSE if the output needs to be sorted.
|
** Return FALSE if the output needs to be sorted.
|
||||||
*/
|
*/
|
||||||
int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
|
int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
|
||||||
return pWInfo->bOBSat!=0;
|
return pWInfo->nOBSat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3037,8 +3037,11 @@ static Bitmask codeOneLoopStart(
|
|||||||
** the first one after the nEq equality constraints in the index,
|
** the first one after the nEq equality constraints in the index,
|
||||||
** this requires some special handling.
|
** this requires some special handling.
|
||||||
*/
|
*/
|
||||||
|
assert( pWInfo->pOrderBy==0
|
||||||
|
|| pWInfo->pOrderBy->nExpr==1
|
||||||
|
|| (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 );
|
||||||
if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
|
if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
|
||||||
&& (pWInfo->bOBSat!=0)
|
&& pWInfo->nOBSat>0
|
||||||
&& (pIdx->nKeyCol>nEq)
|
&& (pIdx->nKeyCol>nEq)
|
||||||
){
|
){
|
||||||
assert( pLoop->u.btree.nSkip==0 );
|
assert( pLoop->u.btree.nSkip==0 );
|
||||||
@@ -4508,8 +4511,8 @@ static int whereLoopAddVirtual(
|
|||||||
pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
|
pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
|
||||||
pIdxInfo->needToFreeIdxStr = 0;
|
pIdxInfo->needToFreeIdxStr = 0;
|
||||||
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
|
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
|
||||||
pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0)
|
pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
|
||||||
&& pIdxInfo->orderByConsumed);
|
pIdxInfo->nOrderBy : 0);
|
||||||
pNew->rSetup = 0;
|
pNew->rSetup = 0;
|
||||||
pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
|
pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
|
||||||
pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
|
pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
|
||||||
@@ -4670,11 +4673,11 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
|||||||
/*
|
/*
|
||||||
** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
|
** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
|
||||||
** parameters) to see if it outputs rows in the requested ORDER BY
|
** parameters) to see if it outputs rows in the requested ORDER BY
|
||||||
** (or GROUP BY) without requiring a separate sort operation. Return:
|
** (or GROUP BY) without requiring a separate sort operation. Return N:
|
||||||
**
|
**
|
||||||
** 0: ORDER BY is not satisfied. Sorting required
|
** N>0: N terms of the ORDER BY clause are satisfied
|
||||||
** 1: ORDER BY is satisfied. Omit sorting
|
** N==0: No terms of the ORDER BY clause are satisfied
|
||||||
** -1: Unknown at this time
|
** N<0: Unknown yet how many terms of ORDER BY might be satisfied.
|
||||||
**
|
**
|
||||||
** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as
|
** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as
|
||||||
** strict. With GROUP BY and DISTINCT the only requirement is that
|
** strict. With GROUP BY and DISTINCT the only requirement is that
|
||||||
@@ -4684,7 +4687,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
|||||||
** the pOrderBy terms can be matched in any order. With ORDER BY, the
|
** the pOrderBy terms can be matched in any order. With ORDER BY, the
|
||||||
** pOrderBy terms must be matched in strict left-to-right order.
|
** pOrderBy terms must be matched in strict left-to-right order.
|
||||||
*/
|
*/
|
||||||
static int wherePathSatisfiesOrderBy(
|
static i8 wherePathSatisfiesOrderBy(
|
||||||
WhereInfo *pWInfo, /* The WHERE clause */
|
WhereInfo *pWInfo, /* The WHERE clause */
|
||||||
ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */
|
ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */
|
||||||
WherePath *pPath, /* The WherePath to check */
|
WherePath *pPath, /* The WherePath to check */
|
||||||
@@ -4917,8 +4920,14 @@ static int wherePathSatisfiesOrderBy(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} /* End the loop over all WhereLoops from outer-most down to inner-most */
|
} /* End the loop over all WhereLoops from outer-most down to inner-most */
|
||||||
if( obSat==obDone ) return 1;
|
if( obSat==obDone ) return nOrderBy;
|
||||||
if( !isOrderDistinct ) return 0;
|
if( !isOrderDistinct ){
|
||||||
|
for(i=nOrderBy-1; i>0; i--){
|
||||||
|
Bitmask m = MASKBIT(i) - 1;
|
||||||
|
if( (obSat&m)==m ) return i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4955,11 +4964,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
int iLoop; /* Loop counter over the terms of the join */
|
int iLoop; /* Loop counter over the terms of the join */
|
||||||
int ii, jj; /* Loop counters */
|
int ii, jj; /* Loop counters */
|
||||||
int mxI = 0; /* Index of next entry to replace */
|
int mxI = 0; /* Index of next entry to replace */
|
||||||
|
int nOrderBy; /* Number of ORDER BY clause terms */
|
||||||
LogEst rCost; /* Cost of a path */
|
LogEst rCost; /* Cost of a path */
|
||||||
LogEst nOut; /* Number of outputs */
|
LogEst nOut; /* Number of outputs */
|
||||||
LogEst mxCost = 0; /* Maximum cost of a set of paths */
|
LogEst mxCost = 0; /* Maximum cost of a set of paths */
|
||||||
LogEst mxOut = 0; /* Maximum nOut value on the set of paths */
|
LogEst mxOut = 0; /* Maximum nOut value on the set of paths */
|
||||||
LogEst rSortCost; /* Cost to do a sort */
|
|
||||||
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
|
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
|
||||||
WherePath *aFrom; /* All nFrom paths at the previous level */
|
WherePath *aFrom; /* All nFrom paths at the previous level */
|
||||||
WherePath *aTo; /* The nTo best paths at the current level */
|
WherePath *aTo; /* The nTo best paths at the current level */
|
||||||
@@ -5001,16 +5010,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
|
|
||||||
/* Precompute the cost of sorting the final result set, if the caller
|
/* Precompute the cost of sorting the final result set, if the caller
|
||||||
** to sqlite3WhereBegin() was concerned about sorting */
|
** to sqlite3WhereBegin() was concerned about sorting */
|
||||||
rSortCost = 0;
|
|
||||||
if( pWInfo->pOrderBy==0 || nRowEst==0 ){
|
if( pWInfo->pOrderBy==0 || nRowEst==0 ){
|
||||||
aFrom[0].isOrderedValid = 1;
|
aFrom[0].isOrdered = 0;
|
||||||
|
nOrderBy = 0;
|
||||||
}else{
|
}else{
|
||||||
/* TUNING: Estimated cost of sorting is 48*N*log2(N) where N is the
|
aFrom[0].isOrdered = -1;
|
||||||
** number of output rows. The 48 is the expected size of a row to sort.
|
nOrderBy = pWInfo->pOrderBy->nExpr;
|
||||||
** FIXME: compute a better estimate of the 48 multiplier based on the
|
|
||||||
** result set expressions. */
|
|
||||||
rSortCost = nRowEst + estLog(nRowEst);
|
|
||||||
WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute successively longer WherePaths using the previous generation
|
/* Compute successively longer WherePaths using the previous generation
|
||||||
@@ -5022,8 +5027,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
|
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
|
||||||
Bitmask maskNew;
|
Bitmask maskNew;
|
||||||
Bitmask revMask = 0;
|
Bitmask revMask = 0;
|
||||||
u8 isOrderedValid = pFrom->isOrderedValid;
|
i8 isOrdered = pFrom->isOrdered;
|
||||||
u8 isOrdered = pFrom->isOrdered;
|
|
||||||
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
|
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
|
||||||
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
|
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
|
||||||
/* At this point, pWLoop is a candidate to be the next loop.
|
/* At this point, pWLoop is a candidate to be the next loop.
|
||||||
@@ -5032,21 +5036,27 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
|
rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
|
||||||
nOut = pFrom->nRow + pWLoop->nOut;
|
nOut = pFrom->nRow + pWLoop->nOut;
|
||||||
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
|
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
|
||||||
if( !isOrderedValid ){
|
if( isOrdered<0 ){
|
||||||
switch( wherePathSatisfiesOrderBy(pWInfo,
|
isOrdered = wherePathSatisfiesOrderBy(pWInfo,
|
||||||
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
|
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
|
||||||
iLoop, pWLoop, &revMask) ){
|
iLoop, pWLoop, &revMask);
|
||||||
case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */
|
if( isOrdered>=0 && isOrdered<nOrderBy ){
|
||||||
isOrdered = 1;
|
/* TUNING: Estimated cost of sorting cost as roughly N*log(N).
|
||||||
isOrderedValid = 1;
|
** If some but not all of the columns are in sorted order, then
|
||||||
break;
|
** scale down the log(N) term. */
|
||||||
case 0: /* No. pFrom+pWLoop will require a separate sort */
|
LogEst rScale = sqlite3LogEst((nOrderBy-isOrdered)*100/nOrderBy);
|
||||||
isOrdered = 0;
|
LogEst rSortCost = nRowEst + estLog(nRowEst) + rScale - 66;
|
||||||
isOrderedValid = 1;
|
/* TUNING: The cost of implementing DISTINCT using a B-TREE is
|
||||||
|
** also N*log(N) but it has a larger constant of proportionality.
|
||||||
|
** Multiply by 3.0. */
|
||||||
|
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
|
||||||
|
rSortCost += 16;
|
||||||
|
}
|
||||||
|
WHERETRACE(0x002,
|
||||||
|
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
|
||||||
|
rSortCost, (nOrderBy-isOrdered), nOrderBy, rCost,
|
||||||
|
sqlite3LogEstAdd(rCost,rSortCost)));
|
||||||
rCost = sqlite3LogEstAdd(rCost, rSortCost);
|
rCost = sqlite3LogEstAdd(rCost, rSortCost);
|
||||||
break;
|
|
||||||
default: /* Cannot tell yet. Try again on the next iteration */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
revMask = pFrom->revLoop;
|
revMask = pFrom->revLoop;
|
||||||
@@ -5054,7 +5064,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
/* Check to see if pWLoop should be added to the mxChoice best so far */
|
/* Check to see if pWLoop should be added to the mxChoice best so far */
|
||||||
for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
|
for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
|
||||||
if( pTo->maskLoop==maskNew
|
if( pTo->maskLoop==maskNew
|
||||||
&& pTo->isOrderedValid==isOrderedValid
|
&& ((pTo->isOrdered^isOrdered)&80)==0
|
||||||
&& ((pTo->rCost<=rCost && pTo->nRow<=nOut) ||
|
&& ((pTo->rCost<=rCost && pTo->nRow<=nOut) ||
|
||||||
(pTo->rCost>=rCost && pTo->nRow>=nOut))
|
(pTo->rCost>=rCost && pTo->nRow>=nOut))
|
||||||
){
|
){
|
||||||
@@ -5068,7 +5078,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
if( sqlite3WhereTrace&0x4 ){
|
if( sqlite3WhereTrace&0x4 ){
|
||||||
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
|
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
|
||||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
||||||
isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
|
isOrdered>=0 ? isOrdered+'0' : '?');
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
@@ -5086,7 +5096,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
if( sqlite3WhereTrace&0x4 ){
|
if( sqlite3WhereTrace&0x4 ){
|
||||||
sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
|
sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
|
||||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
||||||
isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
|
isOrdered>=0 ? isOrdered+'0' : '?');
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}else{
|
}else{
|
||||||
@@ -5096,10 +5106,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
sqlite3DebugPrintf(
|
sqlite3DebugPrintf(
|
||||||
"Skip %s cost=%-3d,%3d order=%c",
|
"Skip %s cost=%-3d,%3d order=%c",
|
||||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
||||||
isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
|
isOrdered>=0 ? isOrdered+'0' : '?');
|
||||||
sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
|
sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
|
||||||
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
|
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
|
||||||
pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
|
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
testcase( pTo->rCost==rCost );
|
testcase( pTo->rCost==rCost );
|
||||||
@@ -5112,10 +5122,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
sqlite3DebugPrintf(
|
sqlite3DebugPrintf(
|
||||||
"Update %s cost=%-3d,%3d order=%c",
|
"Update %s cost=%-3d,%3d order=%c",
|
||||||
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
|
||||||
isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
|
isOrdered>=0 ? isOrdered+'0' : '?');
|
||||||
sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
|
sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
|
||||||
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
|
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
|
||||||
pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
|
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -5124,7 +5134,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
pTo->revLoop = revMask;
|
pTo->revLoop = revMask;
|
||||||
pTo->nRow = nOut;
|
pTo->nRow = nOut;
|
||||||
pTo->rCost = rCost;
|
pTo->rCost = rCost;
|
||||||
pTo->isOrderedValid = isOrderedValid;
|
|
||||||
pTo->isOrdered = isOrdered;
|
pTo->isOrdered = isOrdered;
|
||||||
memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
|
memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
|
||||||
pTo->aLoop[iLoop] = pWLoop;
|
pTo->aLoop[iLoop] = pWLoop;
|
||||||
@@ -5149,8 +5158,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
|
for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
|
||||||
sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
|
sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
|
||||||
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
|
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
|
||||||
pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
|
pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?');
|
||||||
if( pTo->isOrderedValid && pTo->isOrdered ){
|
if( pTo->isOrdered>0 ){
|
||||||
sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
|
sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
|
||||||
}else{
|
}else{
|
||||||
sqlite3DebugPrintf("\n");
|
sqlite3DebugPrintf("\n");
|
||||||
@@ -5193,13 +5202,18 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|||||||
Bitmask notUsed;
|
Bitmask notUsed;
|
||||||
int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
|
int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
|
||||||
WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used);
|
WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used);
|
||||||
if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
|
if( rc==pWInfo->pResultSet->nExpr ){
|
||||||
}
|
|
||||||
if( pFrom->isOrdered ){
|
|
||||||
if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
|
|
||||||
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
|
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( pWInfo->pOrderBy ){
|
||||||
|
if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
|
||||||
|
if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
|
||||||
|
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
pWInfo->bOBSat = 1;
|
pWInfo->nOBSat = pFrom->isOrdered;
|
||||||
|
if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
|
||||||
pWInfo->revMask = pFrom->revLoop;
|
pWInfo->revMask = pFrom->revLoop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5284,7 +5298,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
|||||||
pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
|
pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
|
||||||
pWInfo->a[0].iTabCur = iCur;
|
pWInfo->a[0].iTabCur = iCur;
|
||||||
pWInfo->nRowOut = 1;
|
pWInfo->nRowOut = 1;
|
||||||
if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1;
|
if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr;
|
||||||
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
|
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
|
||||||
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
|
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
|
||||||
}
|
}
|
||||||
@@ -5388,7 +5402,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
|
SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
|
||||||
Expr *pWhere, /* The WHERE clause */
|
Expr *pWhere, /* The WHERE clause */
|
||||||
ExprList *pOrderBy, /* An ORDER BY clause, or NULL */
|
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
|
||||||
ExprList *pResultSet, /* Result set of the query */
|
ExprList *pResultSet, /* Result set of the query */
|
||||||
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
|
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
|
||||||
int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
|
int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
|
||||||
@@ -5410,6 +5424,10 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
/* Variable initialization */
|
/* Variable initialization */
|
||||||
db = pParse->db;
|
db = pParse->db;
|
||||||
memset(&sWLB, 0, sizeof(sWLB));
|
memset(&sWLB, 0, sizeof(sWLB));
|
||||||
|
|
||||||
|
/* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
|
||||||
|
testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
|
||||||
|
if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
|
||||||
sWLB.pOrderBy = pOrderBy;
|
sWLB.pOrderBy = pOrderBy;
|
||||||
|
|
||||||
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
|
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
|
||||||
@@ -5488,7 +5506,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
/* Special case: No FROM clause
|
/* Special case: No FROM clause
|
||||||
*/
|
*/
|
||||||
if( nTabList==0 ){
|
if( nTabList==0 ){
|
||||||
if( pOrderBy ) pWInfo->bOBSat = 1;
|
if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
|
||||||
if( wctrlFlags & WHERE_WANT_DISTINCT ){
|
if( wctrlFlags & WHERE_WANT_DISTINCT ){
|
||||||
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
|
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
|
||||||
}
|
}
|
||||||
@@ -5599,8 +5617,8 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
if( sqlite3WhereTrace ){
|
if( sqlite3WhereTrace ){
|
||||||
int ii;
|
int ii;
|
||||||
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
|
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
|
||||||
if( pWInfo->bOBSat ){
|
if( pWInfo->nOBSat>0 ){
|
||||||
sqlite3DebugPrintf(" ORDERBY=0x%llx", pWInfo->revMask);
|
sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask);
|
||||||
}
|
}
|
||||||
switch( pWInfo->eDistinct ){
|
switch( pWInfo->eDistinct ){
|
||||||
case WHERE_DISTINCT_UNIQUE: {
|
case WHERE_DISTINCT_UNIQUE: {
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ struct WhereLoop {
|
|||||||
struct { /* Information for virtual tables */
|
struct { /* Information for virtual tables */
|
||||||
int idxNum; /* Index number */
|
int idxNum; /* Index number */
|
||||||
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
|
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
|
||||||
u8 isOrdered; /* True if satisfies ORDER BY */
|
i8 isOrdered; /* True if satisfies ORDER BY */
|
||||||
u16 omitMask; /* Terms that may be omitted */
|
u16 omitMask; /* Terms that may be omitted */
|
||||||
char *idxStr; /* Index identifier string */
|
char *idxStr; /* Index identifier string */
|
||||||
} vtab;
|
} vtab;
|
||||||
@@ -183,8 +183,7 @@ struct WherePath {
|
|||||||
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
|
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
|
||||||
LogEst nRow; /* Estimated number of rows generated by this path */
|
LogEst nRow; /* Estimated number of rows generated by this path */
|
||||||
LogEst rCost; /* Total cost of this path */
|
LogEst rCost; /* Total cost of this path */
|
||||||
u8 isOrdered; /* True if this path satisfies ORDER BY */
|
i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
|
||||||
u8 isOrderedValid; /* True if the isOrdered field is valid */
|
|
||||||
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
|
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -398,7 +397,7 @@ struct WhereInfo {
|
|||||||
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
|
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
|
||||||
LogEst nRowOut; /* Estimated number of output rows */
|
LogEst nRowOut; /* Estimated number of output rows */
|
||||||
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
|
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
|
||||||
u8 bOBSat; /* ORDER BY satisfied by indices */
|
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
|
||||||
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
|
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
|
||||||
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
|
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
|
||||||
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
|
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ do_execsql_test 2.0 {
|
|||||||
foreach {tn sql temptables res} {
|
foreach {tn sql temptables res} {
|
||||||
1 "a, b FROM t1" {} {A B a b}
|
1 "a, b FROM t1" {} {A B a b}
|
||||||
2 "b, a FROM t1" {} {B A b a}
|
2 "b, a FROM t1" {} {B A b a}
|
||||||
3 "a, b, c FROM t1" {hash} {a b c A B C}
|
3 "a, b, c FROM t1" {hash} {A B C a b c}
|
||||||
4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c}
|
4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c}
|
||||||
5 "b FROM t1 WHERE a = 'a'" {} {b}
|
5 "b FROM t1 WHERE a = 'a'" {} {b}
|
||||||
6 "b FROM t1 ORDER BY +b COLLATE binary" {btree hash} {B b}
|
6 "b FROM t1 ORDER BY +b COLLATE binary" {btree hash} {B b}
|
||||||
|
|||||||
@@ -64,10 +64,28 @@ do_execsql_test 1.7 {
|
|||||||
EXPLAIN QUERY PLAN
|
EXPLAIN QUERY PLAN
|
||||||
SELECT DISTINCT c, b, a FROM t1 WHERE +a=0;
|
SELECT DISTINCT c, b, a FROM t1 WHERE +a=0;
|
||||||
} {/B-TREE/}
|
} {/B-TREE/}
|
||||||
do_execsql_test 2.1 {
|
|
||||||
|
# In some cases, it is faster to do repeated index lookups than it is to
|
||||||
|
# sort. But in other cases, it is faster to sort than to do repeated index
|
||||||
|
# lookups.
|
||||||
|
#
|
||||||
|
do_execsql_test 2.1a {
|
||||||
|
CREATE TABLE t2(a,b,c);
|
||||||
|
CREATE INDEX t2bc ON t2(b,c);
|
||||||
|
ANALYZE;
|
||||||
|
INSERT INTO sqlite_stat1 VALUES('t1','t1bc','1000000 10 9');
|
||||||
|
INSERT INTO sqlite_stat1 VALUES('t2','t2bc','100 10 5');
|
||||||
|
ANALYZE sqlite_master;
|
||||||
|
|
||||||
|
EXPLAIN QUERY PLAN
|
||||||
|
SELECT * FROM t2 WHERE a=0 ORDER BY a, b, c;
|
||||||
|
} {~/B-TREE/}
|
||||||
|
do_execsql_test 2.1b {
|
||||||
EXPLAIN QUERY PLAN
|
EXPLAIN QUERY PLAN
|
||||||
SELECT * FROM t1 WHERE a=0 ORDER BY a, b, c;
|
SELECT * FROM t1 WHERE a=0 ORDER BY a, b, c;
|
||||||
} {~/B-TREE/}
|
} {/B-TREE/}
|
||||||
|
|
||||||
|
|
||||||
do_execsql_test 2.2 {
|
do_execsql_test 2.2 {
|
||||||
EXPLAIN QUERY PLAN
|
EXPLAIN QUERY PLAN
|
||||||
SELECT * FROM t1 WHERE +a=0 ORDER BY a, b, c;
|
SELECT * FROM t1 WHERE +a=0 ORDER BY a, b, c;
|
||||||
|
|||||||
183
test/orderby6.test
Normal file
183
test/orderby6.test
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# 2014-03-21
|
||||||
|
#
|
||||||
|
# The author disclaims copyright to this source code. In place of
|
||||||
|
# a legal notice, here is a blessing:
|
||||||
|
#
|
||||||
|
# May you do good and not evil.
|
||||||
|
# May you find forgiveness for yourself and forgive others.
|
||||||
|
# May you share freely, never taking more than you give.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this file is testing that the block-sort optimization.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
set ::testprefix orderby6
|
||||||
|
|
||||||
|
# Run all tests twice. Once with a normal table and a second time
|
||||||
|
# with a WITHOUT ROWID table
|
||||||
|
#
|
||||||
|
foreach {tn rowidclause} {1 {} 2 {WITHOUT ROWID}} {
|
||||||
|
|
||||||
|
# Construct a table with 1000 rows and a split primary key
|
||||||
|
#
|
||||||
|
reset_db
|
||||||
|
do_test $tn.1 {
|
||||||
|
db eval "CREATE TABLE t1(a,b,c,PRIMARY KEY(b,c)) $rowidclause;"
|
||||||
|
db eval {
|
||||||
|
WITH RECURSIVE
|
||||||
|
cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<1000)
|
||||||
|
INSERT INTO t1 SELECT x, x%40, x/40 FROM cnt;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
# Run various ORDER BY queries that can benefit from block-sort.
|
||||||
|
# Compare the output to the same output using a full-sort enforced
|
||||||
|
# by adding + to each term of the ORDER BY clause.
|
||||||
|
#
|
||||||
|
do_execsql_test $tn.2 {
|
||||||
|
SELECT b,a,c FROM t1 ORDER BY b,a,c;
|
||||||
|
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b,+a,+c}]
|
||||||
|
do_execsql_test $tn.3 {
|
||||||
|
SELECT b,a,c FROM t1 ORDER BY b,c DESC,a;
|
||||||
|
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b,+c DESC,+a}]
|
||||||
|
do_execsql_test $tn.4 {
|
||||||
|
SELECT b,a,c FROM t1 ORDER BY b DESC,c,a;
|
||||||
|
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b DESC,+c,+a}]
|
||||||
|
do_execsql_test $tn.5 {
|
||||||
|
SELECT b,a,c FROM t1 ORDER BY b DESC,a,c;
|
||||||
|
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b DESC,+a,+c}]
|
||||||
|
|
||||||
|
# LIMIT and OFFSET clauses on block-sort queries.
|
||||||
|
#
|
||||||
|
do_execsql_test $tn.11 {
|
||||||
|
SELECT a FROM t1 ORDER BY b, a LIMIT 10 OFFSET 20;
|
||||||
|
} {840 880 920 960 1000 1 41 81 121 161}
|
||||||
|
do_execsql_test $tn.11x {
|
||||||
|
SELECT a FROM t1 ORDER BY +b, a LIMIT 10 OFFSET 20;
|
||||||
|
} {840 880 920 960 1000 1 41 81 121 161}
|
||||||
|
|
||||||
|
do_execsql_test $tn.12 {
|
||||||
|
SELECT a FROM t1 ORDER BY b DESC, a LIMIT 10 OFFSET 20;
|
||||||
|
} {839 879 919 959 999 38 78 118 158 198}
|
||||||
|
do_execsql_test $tn.12 {
|
||||||
|
SELECT a FROM t1 ORDER BY +b DESC, a LIMIT 10 OFFSET 20;
|
||||||
|
} {839 879 919 959 999 38 78 118 158 198}
|
||||||
|
|
||||||
|
do_execsql_test $tn.13 {
|
||||||
|
SELECT a FROM t1 ORDER BY b, a DESC LIMIT 10 OFFSET 45;
|
||||||
|
} {161 121 81 41 1 962 922 882 842 802}
|
||||||
|
do_execsql_test $tn.13x {
|
||||||
|
SELECT a FROM t1 ORDER BY +b, a DESC LIMIT 10 OFFSET 45;
|
||||||
|
} {161 121 81 41 1 962 922 882 842 802}
|
||||||
|
|
||||||
|
do_execsql_test $tn.14 {
|
||||||
|
SELECT a FROM t1 ORDER BY b DESC, a LIMIT 10 OFFSET 45;
|
||||||
|
} {838 878 918 958 998 37 77 117 157 197}
|
||||||
|
do_execsql_test $tn.14x {
|
||||||
|
SELECT a FROM t1 ORDER BY +b DESC, a LIMIT 10 OFFSET 45;
|
||||||
|
} {838 878 918 958 998 37 77 117 157 197}
|
||||||
|
|
||||||
|
# Many test cases where the LIMIT+OFFSET window is in various
|
||||||
|
# alignments with block-sort boundaries.
|
||||||
|
#
|
||||||
|
foreach {tx limit offset orderby} {
|
||||||
|
1 10 24 {+b,+a}
|
||||||
|
2 10 25 {+b,+a}
|
||||||
|
3 10 26 {+b,+a}
|
||||||
|
4 10 39 {+b,+a}
|
||||||
|
5 10 40 {+b,+a}
|
||||||
|
6 10 41 {+b,+a}
|
||||||
|
7 27 24 {+b,+a}
|
||||||
|
8 27 49 {+b,+a}
|
||||||
|
11 10 24 {+b DESC,+a}
|
||||||
|
12 10 25 {+b DESC,+a}
|
||||||
|
13 10 26 {+b DESC,+a}
|
||||||
|
14 10 39 {+b DESC,+a}
|
||||||
|
15 10 40 {+b DESC,+a}
|
||||||
|
16 10 41 {+b DESC,+a}
|
||||||
|
17 27 24 {+b DESC,+a}
|
||||||
|
18 27 49 {+b DESC,+a}
|
||||||
|
21 10 24 {+b,+a DESC}
|
||||||
|
22 10 25 {+b,+a DESC}
|
||||||
|
23 10 26 {+b,+a DESC}
|
||||||
|
24 10 39 {+b,+a DESC}
|
||||||
|
25 10 40 {+b,+a DESC}
|
||||||
|
26 10 41 {+b,+a DESC}
|
||||||
|
27 27 24 {+b,+a DESC}
|
||||||
|
28 27 49 {+b,+a DESC}
|
||||||
|
31 10 24 {+b DESC,+a DESC}
|
||||||
|
32 10 25 {+b DESC,+a DESC}
|
||||||
|
33 10 26 {+b DESC,+a DESC}
|
||||||
|
34 10 39 {+b DESC,+a DESC}
|
||||||
|
35 10 40 {+b DESC,+a DESC}
|
||||||
|
36 10 41 {+b DESC,+a DESC}
|
||||||
|
37 27 24 {+b DESC,+a DESC}
|
||||||
|
38 27 49 {+b DESC,+a DESC}
|
||||||
|
} {
|
||||||
|
set sql1 "SELECT a FROM t1 ORDER BY $orderby LIMIT $limit OFFSET $offset;"
|
||||||
|
set sql2 [string map {+ {}} $sql1]
|
||||||
|
# puts $sql2\n$sql1\n[db eval $sql2]
|
||||||
|
do_test $tn.21.$tx {db eval $::sql2} [db eval $sql1]
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# A second test table, t2, has many columns open to sorting.
|
||||||
|
do_test $tn.31 {
|
||||||
|
db eval "CREATE TABLE t2(a,b,c,d,e,f,PRIMARY KEY(b,c,d,e,f)) $rowidclause;"
|
||||||
|
db eval {
|
||||||
|
WITH RECURSIVE
|
||||||
|
cnt(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM cnt WHERE x<242)
|
||||||
|
INSERT INTO t2 SELECT x, x%3, (x/3)%3, (x/9)%3, (x/27)%3, (x/81)%3
|
||||||
|
FROM cnt;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_execsql_test $tn.32 {
|
||||||
|
SELECT a FROM t2 ORDER BY b,c,d,e,f;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||||
|
do_execsql_test $tn.33 {
|
||||||
|
SELECT a FROM t2 ORDER BY b,c,d,e,+f;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||||
|
do_execsql_test $tn.34 {
|
||||||
|
SELECT a FROM t2 ORDER BY b,c,d,+e,+f;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||||
|
do_execsql_test $tn.35 {
|
||||||
|
SELECT a FROM t2 ORDER BY b,c,+d,+e,+f;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||||
|
do_execsql_test $tn.36 {
|
||||||
|
SELECT a FROM t2 ORDER BY b,+c,+d,+e,+f;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||||
|
|
||||||
|
do_execsql_test $tn.37 {
|
||||||
|
SELECT a FROM t2 ORDER BY b,c,d,e,f DESC;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f DESC;}]
|
||||||
|
do_execsql_test $tn.38 {
|
||||||
|
SELECT a FROM t2 ORDER BY b,c,d,e DESC,f;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e DESC,+f;}]
|
||||||
|
do_execsql_test $tn.39 {
|
||||||
|
SELECT a FROM t2 ORDER BY b,c,d DESC,e,f;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d DESC,+e,+f;}]
|
||||||
|
do_execsql_test $tn.40 {
|
||||||
|
SELECT a FROM t2 ORDER BY b,c DESC,d,e,f;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b,+c DESC,+d,+e,+f;}]
|
||||||
|
do_execsql_test $tn.41 {
|
||||||
|
SELECT a FROM t2 ORDER BY b DESC,c,d,e,f;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b DESC,+c,+d,+e,+f;}]
|
||||||
|
|
||||||
|
do_execsql_test $tn.42 {
|
||||||
|
SELECT a FROM t2 ORDER BY b DESC,c DESC,d,e,f LIMIT 31;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b DESC,+c DESC,+d,+e,+f LIMIT 31}]
|
||||||
|
do_execsql_test $tn.43 {
|
||||||
|
SELECT a FROM t2 ORDER BY b,c,d,e,f DESC LIMIT 8 OFFSET 7;
|
||||||
|
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f DESC LIMIT 8 OFFSET 7}]
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
||||||
@@ -95,7 +95,7 @@ do_eqp_test whereG-1.5 {
|
|||||||
WHERE cname LIKE '%bach%'
|
WHERE cname LIKE '%bach%'
|
||||||
AND composer.cid=track.cid
|
AND composer.cid=track.cid
|
||||||
AND album.aid=track.aid;
|
AND album.aid=track.aid;
|
||||||
} {/.*track.*composer.*album.*/}
|
} {/.*track.*(composer.*album|album.*composer).*/}
|
||||||
do_execsql_test whereG-1.6 {
|
do_execsql_test whereG-1.6 {
|
||||||
SELECT DISTINCT aname
|
SELECT DISTINCT aname
|
||||||
FROM album, composer, track
|
FROM album, composer, track
|
||||||
@@ -110,7 +110,7 @@ do_eqp_test whereG-1.7 {
|
|||||||
WHERE cname LIKE '%bach%'
|
WHERE cname LIKE '%bach%'
|
||||||
AND unlikely(composer.cid=track.cid)
|
AND unlikely(composer.cid=track.cid)
|
||||||
AND unlikely(album.aid=track.aid);
|
AND unlikely(album.aid=track.aid);
|
||||||
} {/.*track.*composer.*album.*/}
|
} {/.*track.*(composer.*album|album.*composer).*/}
|
||||||
do_execsql_test whereG-1.8 {
|
do_execsql_test whereG-1.8 {
|
||||||
SELECT DISTINCT aname
|
SELECT DISTINCT aname
|
||||||
FROM album, composer, track
|
FROM album, composer, track
|
||||||
|
|||||||
Reference in New Issue
Block a user