1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-12 13:01:09 +03:00

Add support for attaching a FILTER clause to an aggregate function.

FossilOrigin-Name: ee293e5aeac0b05a8b809095610fd8b4fdaf8e68cd368de90ec0d45e3582ffe5
This commit is contained in:
dan
2019-07-13 16:39:38 +00:00
17 changed files with 580 additions and 104 deletions

View File

@@ -1,5 +1,5 @@
C Remove\sunreachable\s"break"\sstatements\sto\ssilence\sharmless\scompiler\swarnings\nfrom\sICC. C Add\ssupport\sfor\sattaching\sa\sFILTER\sclause\sto\san\saggregate\sfunction.
D 2019-07-13T16:15:23.170 D 2019-07-13T16:39:38.075
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -463,7 +463,7 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df
F src/backup.c b1d37f6f7f5913944583733ed0f9e182f3ece0d42c27f46701142141a6e6fd33 F src/backup.c b1d37f6f7f5913944583733ed0f9e182f3ece0d42c27f46701142141a6e6fd33
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c 1dbc191e5c1d9bca84a956fed5d73924c574ae5390855009f067bd0f6422e462 F src/btree.c 0e30c98649796a91a889c2ab1c2f032da9918ac5244a3688ed97e8b5779b61fa
F src/btree.h c11446f07ec0e9dc85af8041cb0855c52f5359c8b2a43e47e02a685282504d89 F src/btree.h c11446f07ec0e9dc85af8041cb0855c52f5359c8b2a43e47e02a685282504d89
F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f
F src/build.c 23a0253ab53e62feadcc0c6f31e7e418ef9d4b92c82a1398e98433776b920a4e F src/build.c 23a0253ab53e62feadcc0c6f31e7e418ef9d4b92c82a1398e98433776b920a4e
@@ -474,7 +474,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041
F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319
F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf
F src/expr.c 2756d2875ac5b7a7efcc54edea3c8a31f4126684ded18da6fb406f4d3780a5f5 F src/expr.c 896c4576cd88a0dc5b5ae0abd236b507b778105b58744bd8974fac98fc432b4c
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 0e14d4bef8eac2d87bbd517e492d9084c65008d117823f8922c5e7b2b599bd33 F src/fkey.c 0e14d4bef8eac2d87bbd517e492d9084c65008d117823f8922c5e7b2b599bd33
F src/func.c 905c0424900979fade3731b4a271592059425c988cb7d5b245032253712dd7c8 F src/func.c 905c0424900979fade3731b4a271592059425c988cb7d5b245032253712dd7c8
@@ -511,23 +511,23 @@ F src/os_win.c 85d9e532d0444ab6c16d7431490c2e279e282aa0917b0e988996b1ae0de5c5a0
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 422fd8cfa59fb9173eff36a95878904a0eeb0dcc62ba49350acc8b1e51c4dc7b F src/pager.c 422fd8cfa59fb9173eff36a95878904a0eeb0dcc62ba49350acc8b1e51c4dc7b
F src/pager.h 217921e81eb5fe455caa5cda96061959706bcdd29ddb57166198645ef7822ac3 F src/pager.h 217921e81eb5fe455caa5cda96061959706bcdd29ddb57166198645ef7822ac3
F src/parse.y 026e3e6fff32432166a4eae0bdb78ad09a53c84eb49acb44dc32e49b4c0b8a48 F src/parse.y ef494825aa4d633b601af10f936fe50a630bd4c4a6ceb4d941ecfb6756e06c56
F src/pcache.c fd2d0553b3222d6b9f7cb251079e5bca1299d1161da3027b525932d8bf46340a F src/pcache.c fd2d0553b3222d6b9f7cb251079e5bca1299d1161da3027b525932d8bf46340a
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c e6373934cdafea272d94feb224344f9fd93ff94318221b64ccabd72d98b4672e F src/pcache1.c e6373934cdafea272d94feb224344f9fd93ff94318221b64ccabd72d98b4672e
F src/pragma.c 925bcac0afd98a0d4255c7524b93239ab4d83893d96f7f8fdccd78d4929a39bb F src/pragma.c 925bcac0afd98a0d4255c7524b93239ab4d83893d96f7f8fdccd78d4929a39bb
F src/pragma.h 4a9fabff14db4487a734dfeeb4be984ce662bfdccfae16145b9c732327735e13 F src/pragma.h 4a9fabff14db4487a734dfeeb4be984ce662bfdccfae16145b9c732327735e13
F src/prepare.c 78027c6231fbb19ca186a5f5f0c0a1375d9c2cec0655273f9bd90d9ff74a34b3 F src/prepare.c d633c3610c23dc98239ea445803c2a6188c2b8ab647e3df4243f369516e6c8d1
F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4 F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 93b7bc7c45efa6322d92293361c51a873690daed50cf77eeff88a448246b0d5a F src/resolve.c 6d96d5c1cfa48e49df160aee6032dbb1f79e1d04163c34f9be5625828ac9a2ec
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
F src/select.c 62f21307b280791c50554c9fa3766758dd695ed66a05d2408d213355c7b0aa89 F src/select.c 1ac359aed1a83239ce3434c0620e488ad9cf25dee829b86c89f7fe4b5cd366c5
F src/shell.c.in 82f8a473c01662f52233c6c75b9bf88d0d2cab276086d5d4ca6f2ff57a3e48eb F src/shell.c.in 82f8a473c01662f52233c6c75b9bf88d0d2cab276086d5d4ca6f2ff57a3e48eb
F src/sqlite.h.in 83ebc8ab1a2e82d92214006ea2c15bf8a0604f3fac2c31dd9ce9021f568c71f2 F src/sqlite.h.in 83ebc8ab1a2e82d92214006ea2c15bf8a0604f3fac2c31dd9ce9021f568c71f2
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5 F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5
F src/sqliteInt.h bf65dfa6565fae2e0d501088fc9c5212244adc1429a543827a16b2f5eaf41982 F src/sqliteInt.h c13c4abe0d245b6b2a4b4a1f9f2b6c4f7347b30b22f61b3fdfd4652b2b328906
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -598,7 +598,7 @@ F src/vdbe.c e9493a767fafd71bb9b10462a39b3af36d029d4e47e8cc4f531f89175dadf7f4
F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237 F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237
F src/vdbeInt.h 889c52272a02cea8af6e21b493b08bc9a043e3372a77fdfe838d25e73a47ac92 F src/vdbeInt.h 889c52272a02cea8af6e21b493b08bc9a043e3372a77fdfe838d25e73a47ac92
F src/vdbeapi.c f9161e5c77f512fbb80091ce8af621d19c9556bda5e734cffaac1198407400da F src/vdbeapi.c f9161e5c77f512fbb80091ce8af621d19c9556bda5e734cffaac1198407400da
F src/vdbeaux.c a2da4e67d337d128ec91b295fbd747bb45b4fd3bed0c658af5d7d3000f202fa5 F src/vdbeaux.c eb2b67dcf65e71fd11d977961220f9d1888fb60bbf3730eb60ff971c68dc7dd5
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbemem.c f6f277d17d50972571d1394535d4c3d156fdea871d8f327f5b9479984054015a F src/vdbemem.c f6f277d17d50972571d1394535d4c3d156fdea871d8f327f5b9479984054015a
F src/vdbesort.c 66592d478dbb46f19aed0b42222325eadb84deb40a90eebe25c6e7c1d8468f47 F src/vdbesort.c 66592d478dbb46f19aed0b42222325eadb84deb40a90eebe25c6e7c1d8468f47
@@ -607,12 +607,12 @@ F src/vtab.c 1fa256c6ddad7a81e2a4dc080d015d4b0a7135767717d311298e47f6fca64bb3
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c b09a2a9cab50efa08451a8c81d47052120ad5da174048c6d0b08d405384abdf2 F src/wal.c b09a2a9cab50efa08451a8c81d47052120ad5da174048c6d0b08d405384abdf2
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c 7607f1a68130c028255d8d56094ea602fc402c79e1e35a46e6282849d90d5fe4 F src/walker.c ccbe57a6eeedce5826510c509cebb547e0c877d53f14b3118698643057d4b597
F src/where.c 2f11eeb14335b7640f886b2fb441f54a94c35ab5cde8b53461a1074bfd587081 F src/where.c 2f11eeb14335b7640f886b2fb441f54a94c35ab5cde8b53461a1074bfd587081
F src/whereInt.h 1b728f71654ebf8421a1715497a587f02d6f538e819af58dc826908f8577e810 F src/whereInt.h 1b728f71654ebf8421a1715497a587f02d6f538e819af58dc826908f8577e810
F src/wherecode.c 37a1004237d630d785c47bba2290eac652a7a8b0047518eba3cb7c808b604c4a F src/wherecode.c 37a1004237d630d785c47bba2290eac652a7a8b0047518eba3cb7c808b604c4a
F src/whereexpr.c 5e559bdd24b06e3bc2e68f258bf751302954dc1e432daf71fdd8098a71462326 F src/whereexpr.c 5e559bdd24b06e3bc2e68f258bf751302954dc1e432daf71fdd8098a71462326
F src/window.c 3408c0f606574d41033d461506bad68790239844b23e70610738a71152873d05 F src/window.c 6cfb1b3c821a4cb2c6f262c6a61cd400a2803b390370e3d45d7e59b9f38e61da
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -856,6 +856,9 @@ F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
F test/fallocate.test 37a62e396a68eeede8f8d2ecf23573a80faceb630788d314d0a073d862616717 F test/fallocate.test 37a62e396a68eeede8f8d2ecf23573a80faceb630788d314d0a073d862616717
F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3 F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3
F test/filefmt.test f393e80c4b8d493b7a7f8f3809a8425bbf4292af1f5140f01cb1427798a2bbd4 F test/filefmt.test f393e80c4b8d493b7a7f8f3809a8425bbf4292af1f5140f01cb1427798a2bbd4
F test/filter1.test 5830d6214399abb874f2c0293d299b8cbd02d56b8e529e509befd322f1bc2003
F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8
F test/filter2.test 485cf95d1f6d6ceee5632201ca52a71868599836f430cdee42e5f7f14666e30a
F test/fkey1.test d11dbb8a93ead9b5c46ae5d02da016d61245d47662fb2d844c99214f6163f768 F test/fkey1.test d11dbb8a93ead9b5c46ae5d02da016d61245d47662fb2d844c99214f6163f768
F test/fkey2.test d35d1c81e7569bdd2b872e91750f7098117d2e8291369f70b7e3d50a0e523dc2 F test/fkey2.test d35d1c81e7569bdd2b872e91750f7098117d2e8291369f70b7e3d50a0e523dc2
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49 F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
@@ -1696,8 +1699,8 @@ F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
F test/window1.test 8d453bfaa3f8f0873ba16ca1270c7368f18445065a0003a1b5954ac4e95797b4 F test/window1.test 8d453bfaa3f8f0873ba16ca1270c7368f18445065a0003a1b5954ac4e95797b4
F test/window2.tcl 0c2918ef2a1640553fd791972d458356808a608418c64c02a0a379cecfc7fb0d F test/window2.tcl a44834af6267be6e14882311ef8790bf5047f1b9bc25685ee1762d48dc24f1e7
F test/window2.test 96ef949f0197c025652f6c6e5812cdbfb948989bd40cf79cbb02104249a89513 F test/window2.test 2f3ae63e171dce7f2ac29a41020f4da413b1d7bdaba48ee124fd336b152e34c5
F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03 F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03
F test/window3.test e9959a993c8a71e96433be8daaa1827d78b8921e4f12debd7bdbeb3c856ef3cb F test/window3.test e9959a993c8a71e96433be8daaa1827d78b8921e4f12debd7bdbeb3c856ef3cb
F test/window4.tcl 5fbaab489677914ee5686b2008426e336daf88a2f58be7df92757f780a5ebf91 F test/window4.tcl 5fbaab489677914ee5686b2008426e336daf88a2f58be7df92757f780a5ebf91
@@ -1831,7 +1834,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 18bfb2179ce2c60cec8f5859a84b737731a5e53b28e35072cbb249f18b94262b P 0d7287e1bfdd5a392bf2fb17699e7cfd0b08bf61fab6cbf4b4bb347b3c4b4610 5dac8c38dfc3f41c5c8fb49ca35de7fd1b21f269d72e8ba6ba59ed0a4030a54d
R f8c803745189eeccce948a3e0c8a7622 R 561c885d15821daa82f4a82578c1b361
U drh U dan
Z 30db5a05339ca75cff828d9d142b8bbe Z 16d98d754e52d40d038f719e1b555d93

View File

@@ -1 +1 @@
0d7287e1bfdd5a392bf2fb17699e7cfd0b08bf61fab6cbf4b4bb347b3c4b4610 ee293e5aeac0b05a8b809095610fd8b4fdaf8e68cd368de90ec0d45e3582ffe5

View File

@@ -8307,11 +8307,13 @@ static int balance(BtCursor *pCur){
VVA_ONLY( int balance_deeper_called = 0 ); VVA_ONLY( int balance_deeper_called = 0 );
do { do {
int iPage = pCur->iPage; int iPage;
MemPage *pPage = pCur->pPage; MemPage *pPage = pCur->pPage;
if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break; if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break;
if( iPage==0 ){ if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
break;
}else if( (iPage = pCur->iPage)==0 ){
if( pPage->nOverflow ){ if( pPage->nOverflow ){
/* The root page of the b-tree is overfull. In this case call the /* The root page of the b-tree is overfull. In this case call the
** balance_deeper() function to create a new child for the root-page ** balance_deeper() function to create a new child for the root-page
@@ -8332,8 +8334,6 @@ static int balance(BtCursor *pCur){
}else{ }else{
break; break;
} }
}else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
break;
}else{ }else{
MemPage * const pParent = pCur->apPage[iPage-1]; MemPage * const pParent = pCur->apPage[iPage-1];
int const iIdx = pCur->aiIdx[iPage-1]; int const iIdx = pCur->aiIdx[iPage-1];

View File

@@ -1040,15 +1040,18 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
assert( p->x.pList==0 || p->pRight==0 ); assert( p->x.pList==0 || p->pRight==0 );
if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft);
if( p->pRight ){ if( p->pRight ){
assert( !ExprHasProperty(p, EP_WinFunc) );
sqlite3ExprDeleteNN(db, p->pRight); sqlite3ExprDeleteNN(db, p->pRight);
}else if( ExprHasProperty(p, EP_xIsSelect) ){ }else if( ExprHasProperty(p, EP_xIsSelect) ){
assert( !ExprHasProperty(p, EP_WinFunc) );
sqlite3SelectDelete(db, p->x.pSelect); sqlite3SelectDelete(db, p->x.pSelect);
}else{ }else{
sqlite3ExprListDelete(db, p->x.pList); sqlite3ExprListDelete(db, p->x.pList);
} #ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(p, EP_WinFunc) ){ if( ExprHasProperty(p, EP_WinFunc) ){
assert( p->op==TK_FUNCTION ); sqlite3WindowDelete(db, p->y.pWin);
sqlite3WindowDelete(db, p->y.pWin); }
#endif
} }
} }
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
@@ -1332,8 +1335,9 @@ static With *withDup(sqlite3 *db, With *p){
** objects found there, assembling them onto the linked list at Select->pWin. ** objects found there, assembling them onto the linked list at Select->pWin.
*/ */
static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){ static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_FUNCTION && pExpr->y.pWin!=0 ){ if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_WinFunc) ){
assert( ExprHasProperty(pExpr, EP_WinFunc) ); assert( pExpr->y.pWin );
assert( IsWindowFunc(pExpr) );
pExpr->y.pWin->pNextWin = pWalker->u.pSelect->pWin; pExpr->y.pWin->pNextWin = pWalker->u.pSelect->pWin;
pWalker->u.pSelect->pWin = pExpr->y.pWin; pWalker->u.pSelect->pWin = pExpr->y.pWin;
} }
@@ -4839,20 +4843,17 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
return 2; return 2;
} }
if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){ if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
if( pA->op==TK_FUNCTION ){ if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
#ifndef SQLITE_OMIT_WINDOWFUNC #ifndef SQLITE_OMIT_WINDOWFUNC
/* Justification for the assert(): assert( pA->op==pB->op );
** window functions have p->op==TK_FUNCTION but aggregate functions if( ExprHasProperty(pA,EP_WinFunc)!=ExprHasProperty(pB,EP_WinFunc) ){
** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate return 2;
** function and a window function should have failed before reaching }
** this point. And, it is not possible to have a window function and
** a scalar function with the same name and number of arguments. So
** if we reach this point, either A and B both window functions or
** neither are a window functions. */
assert( ExprHasProperty(pA,EP_WinFunc)==ExprHasProperty(pB,EP_WinFunc) );
if( ExprHasProperty(pA,EP_WinFunc) ){ if( ExprHasProperty(pA,EP_WinFunc) ){
if( sqlite3WindowCompare(pParse,pA->y.pWin,pB->y.pWin)!=0 ) return 2; if( sqlite3WindowCompare(pParse, pA->y.pWin, pB->y.pWin, 1)!=0 ){
return 2;
}
} }
#endif #endif
}else if( pA->op==TK_NULL ){ }else if( pA->op==TK_NULL ){

View File

@@ -1044,11 +1044,11 @@ expr(A) ::= id(X) LP STAR RP. {
} }
%ifndef SQLITE_OMIT_WINDOWFUNC %ifndef SQLITE_OMIT_WINDOWFUNC
expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP over_clause(Z). { expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP filter_over(Z). {
A = sqlite3ExprFunction(pParse, Y, &X, D); A = sqlite3ExprFunction(pParse, Y, &X, D);
sqlite3WindowAttach(pParse, A, Z); sqlite3WindowAttach(pParse, A, Z);
} }
expr(A) ::= id(X) LP STAR RP over_clause(Z). { expr(A) ::= id(X) LP STAR RP filter_over(Z). {
A = sqlite3ExprFunction(pParse, 0, &X, 0); A = sqlite3ExprFunction(pParse, 0, &X, 0);
sqlite3WindowAttach(pParse, A, Z); sqlite3WindowAttach(pParse, A, Z);
} }
@@ -1657,8 +1657,14 @@ windowdefn(A) ::= nm(X) AS LP window(Y) RP. {
%type part_opt {ExprList*} %type part_opt {ExprList*}
%destructor part_opt {sqlite3ExprListDelete(pParse->db, $$);} %destructor part_opt {sqlite3ExprListDelete(pParse->db, $$);}
%type filter_opt {Expr*} %type filter_clause {Expr*}
%destructor filter_opt {sqlite3ExprDelete(pParse->db, $$);} %destructor filter_clause {sqlite3ExprDelete(pParse->db, $$);}
%type over_clause {Window*}
%destructor over_clause {sqlite3WindowDelete(pParse->db, $$);}
%type filter_over {Window*}
%destructor filter_over {sqlite3WindowDelete(pParse->db, $$);}
%type range_or_rows {int} %type range_or_rows {int}
@@ -1724,25 +1730,33 @@ frame_exclude(A) ::= GROUP|TIES(X). {A = @X; /*A-overwrites-X*/}
%destructor window_clause {sqlite3WindowListDelete(pParse->db, $$);} %destructor window_clause {sqlite3WindowListDelete(pParse->db, $$);}
window_clause(A) ::= WINDOW windowdefn_list(B). { A = B; } window_clause(A) ::= WINDOW windowdefn_list(B). { A = B; }
%type over_clause {Window*} filter_over(A) ::= filter_clause(F) over_clause(O). {
%destructor over_clause {sqlite3WindowDelete(pParse->db, $$);} O->pFilter = F;
over_clause(A) ::= filter_opt(W) OVER LP window(Z) RP. { A = O;
A = Z;
assert( A!=0 );
A->pFilter = W;
} }
over_clause(A) ::= filter_opt(W) OVER nm(Z). { filter_over(A) ::= over_clause(O). {
A = O;
}
filter_over(A) ::= filter_clause(F). {
A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
if( A ){ if( A ){
A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n); A->eFrmType = TK_FILTER;
A->pFilter = W; A->pFilter = F;
}else{
sqlite3ExprDelete(pParse->db, W);
} }
} }
filter_opt(A) ::= . { A = 0; } over_clause(A) ::= OVER LP window(Z) RP. {
filter_opt(A) ::= FILTER LP WHERE expr(X) RP. { A = X; } A = Z;
assert( A!=0 );
}
over_clause(A) ::= OVER nm(Z). {
A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
if( A ){
A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n);
}
}
filter_clause(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
%endif /* SQLITE_OMIT_WINDOWFUNC */ %endif /* SQLITE_OMIT_WINDOWFUNC */
/* /*

View File

@@ -635,7 +635,7 @@ static int sqlite3Prepare(
rc = sParse.rc; rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN #ifndef SQLITE_OMIT_EXPLAIN
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ if( sParse.explain && rc==SQLITE_OK && sParse.pVdbe ){
static const char * const azColName[] = { static const char * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
"id", "parent", "notused", "detail" "id", "parent", "notused", "detail"
@@ -660,8 +660,8 @@ static int sqlite3Prepare(
if( db->init.busy==0 ){ if( db->init.busy==0 ){
sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags); sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags);
} }
if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){ if( rc!=SQLITE_OK || db->mallocFailed ){
sqlite3VdbeFinalize(sParse.pVdbe); if( sParse.pVdbe ) sqlite3VdbeFinalize(sParse.pVdbe);
assert(!(*ppStmt)); assert(!(*ppStmt));
}else{ }else{
*ppStmt = (sqlite3_stmt*)sParse.pVdbe; *ppStmt = (sqlite3_stmt*)sParse.pVdbe;

View File

@@ -749,7 +749,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
FuncDef *pDef; /* Information about the function */ FuncDef *pDef; /* Information about the function */
u8 enc = ENC(pParse->db); /* The database encoding */ u8 enc = ENC(pParse->db); /* The database encoding */
int savedAllowFlags = (pNC->ncFlags & (NC_AllowAgg | NC_AllowWin)); int savedAllowFlags = (pNC->ncFlags & (NC_AllowAgg | NC_AllowWin));
#ifndef SQLITE_OMIT_WINDOWFUNC
Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
#endif
assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
zId = pExpr->u.zToken; zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId); nId = sqlite3Strlen30(zId);
@@ -830,18 +832,18 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|| (pDef->xValue==0 && pDef->xInverse==0) || (pDef->xValue==0 && pDef->xInverse==0)
|| (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize) || (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize)
); );
if( pDef && pDef->xValue==0 && ExprHasProperty(pExpr, EP_WinFunc) ){ if( pDef && pDef->xValue==0 && pWin ){
sqlite3ErrorMsg(pParse, sqlite3ErrorMsg(pParse,
"%.*s() may not be used as a window function", nId, zId "%.*s() may not be used as a window function", nId, zId
); );
pNC->nErr++; pNC->nErr++;
}else if( }else if(
(is_agg && (pNC->ncFlags & NC_AllowAgg)==0) (is_agg && (pNC->ncFlags & NC_AllowAgg)==0)
|| (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pExpr->y.pWin) || (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pWin)
|| (is_agg && pExpr->y.pWin && (pNC->ncFlags & NC_AllowWin)==0) || (is_agg && pWin && (pNC->ncFlags & NC_AllowWin)==0)
){ ){
const char *zType; const char *zType;
if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->y.pWin ){ if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pWin ){
zType = "window"; zType = "window";
}else{ }else{
zType = "aggregate"; zType = "aggregate";
@@ -849,6 +851,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId); sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId);
pNC->nErr++; pNC->nErr++;
is_agg = 0; is_agg = 0;
}else if( is_agg==0 && ExprHasProperty(pExpr, EP_WinFunc) ){
assert( !IsWindowFunc(pExpr) );
sqlite3ErrorMsg(pParse,
"filter clause may not be used with non-aggregate %.*s()",
nId, zId
);
pNC->nErr++;
} }
#else #else
if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){ if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){
@@ -874,7 +883,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
** Or arguments of other window functions. But aggregate functions ** Or arguments of other window functions. But aggregate functions
** may be arguments for window functions. */ ** may be arguments for window functions. */
#ifndef SQLITE_OMIT_WINDOWFUNC #ifndef SQLITE_OMIT_WINDOWFUNC
pNC->ncFlags &= ~(NC_AllowWin | (!pExpr->y.pWin ? NC_AllowAgg : 0)); pNC->ncFlags &= ~(NC_AllowWin | (!pWin ? NC_AllowAgg : 0));
#else #else
pNC->ncFlags &= ~NC_AllowAgg; pNC->ncFlags &= ~NC_AllowAgg;
#endif #endif
@@ -883,16 +892,16 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
sqlite3WalkExprList(pWalker, pList); sqlite3WalkExprList(pWalker, pList);
if( is_agg ){ if( is_agg ){
#ifndef SQLITE_OMIT_WINDOWFUNC #ifndef SQLITE_OMIT_WINDOWFUNC
if( pExpr->y.pWin ){ if( pWin ){
Select *pSel = pNC->pWinSelect; Select *pSel = pNC->pWinSelect;
if( IN_RENAME_OBJECT==0 ){ if( IN_RENAME_OBJECT==0 ){
sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->y.pWin, pDef); sqlite3WindowUpdate(pParse, pSel->pWinDefn, pWin, pDef);
} }
sqlite3WalkExprList(pWalker, pExpr->y.pWin->pPartition); sqlite3WalkExprList(pWalker, pWin->pPartition);
sqlite3WalkExprList(pWalker, pExpr->y.pWin->pOrderBy); sqlite3WalkExprList(pWalker, pWin->pOrderBy);
sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter); sqlite3WalkExpr(pWalker, pWin->pFilter);
if( 0==pSel->pWin if( 0==pSel->pWin
|| 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->y.pWin) || 0==sqlite3WindowCompare(pParse, pSel->pWin, pWin, 0)
){ ){
pExpr->y.pWin->pNextWin = pSel->pWin; pExpr->y.pWin->pNextWin = pSel->pWin;
pSel->pWin = pExpr->y.pWin; pSel->pWin = pExpr->y.pWin;
@@ -904,6 +913,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
NameContext *pNC2 = pNC; NameContext *pNC2 = pNC;
pExpr->op = TK_AGG_FUNCTION; pExpr->op = TK_AGG_FUNCTION;
pExpr->op2 = 0; pExpr->op2 = 0;
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(pExpr, EP_WinFunc) ){
sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter);
}
#endif
while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){ while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
pExpr->op2++; pExpr->op2++;
pNC2 = pNC2->pNext; pNC2 = pNC2->pNext;

View File

@@ -4403,7 +4403,10 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
assert( *ppMinMax==0 ); assert( *ppMinMax==0 );
assert( pFunc->op==TK_AGG_FUNCTION ); assert( pFunc->op==TK_AGG_FUNCTION );
if( pEList==0 || pEList->nExpr!=1 ) return eRet; assert( !IsWindowFunc(pFunc) );
if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_WinFunc) ){
return eRet;
}
zFunc = pFunc->u.zToken; zFunc = pFunc->u.zToken;
if( sqlite3StrICmp(zFunc, "min")==0 ){ if( sqlite3StrICmp(zFunc, "min")==0 ){
eRet = WHERE_ORDERBY_MIN; eRet = WHERE_ORDERBY_MIN;
@@ -4450,7 +4453,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
if( pExpr->op!=TK_AGG_FUNCTION ) return 0; if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
if( NEVER(pAggInfo->nFunc==0) ) return 0; if( NEVER(pAggInfo->nFunc==0) ) return 0;
if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0; if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0;
if( pExpr->flags&EP_Distinct ) return 0; if( ExprHasProperty(pExpr, EP_Distinct|EP_WinFunc) ) return 0;
return pTab; return pTab;
} }
@@ -5330,6 +5333,12 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
int regAgg; int regAgg;
ExprList *pList = pF->pExpr->x.pList; ExprList *pList = pF->pExpr->x.pList;
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
assert( !IsWindowFunc(pF->pExpr) );
if( ExprHasProperty(pF->pExpr, EP_WinFunc) ){
Expr *pFilter = pF->pExpr->y.pWin->pFilter;
addrNext = sqlite3VdbeMakeLabel(pParse);
sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL);
}
if( pList ){ if( pList ){
nArg = pList->nExpr; nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg); regAgg = sqlite3GetTempRange(pParse, nArg);
@@ -5339,7 +5348,9 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
regAgg = 0; regAgg = 0;
} }
if( pF->iDistinct>=0 ){ if( pF->iDistinct>=0 ){
addrNext = sqlite3VdbeMakeLabel(pParse); if( addrNext==0 ){
addrNext = sqlite3VdbeMakeLabel(pParse);
}
testcase( nArg==0 ); /* Error condition */ testcase( nArg==0 ); /* Error condition */
testcase( nArg>1 ); /* Also an error */ testcase( nArg>1 ); /* Also an error */
codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg); codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
@@ -6222,9 +6233,16 @@ int sqlite3Select(
minMaxFlag = WHERE_ORDERBY_NORMAL; minMaxFlag = WHERE_ORDERBY_NORMAL;
} }
for(i=0; i<sAggInfo.nFunc; i++){ for(i=0; i<sAggInfo.nFunc; i++){
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) ); Expr *pExpr = sAggInfo.aFunc[i].pExpr;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
sNC.ncFlags |= NC_InAggFunc; sNC.ncFlags |= NC_InAggFunc;
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList); sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
#ifndef SQLITE_OMIT_WINDOWFUNC
assert( !IsWindowFunc(pExpr) );
if( ExprHasProperty(pExpr, EP_WinFunc) ){
sqlite3ExprAnalyzeAggregates(&sNC, pExpr->y.pWin->pFilter);
}
#endif
sNC.ncFlags &= ~NC_InAggFunc; sNC.ncFlags &= ~NC_InAggFunc;
} }
sAggInfo.mxReg = pParse->nMem; sAggInfo.mxReg = pParse->nMem;

View File

@@ -2491,7 +2491,7 @@ struct Expr {
union { union {
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
** for a column of an index on an expression */ ** for a column of an index on an expression */
Window *pWin; /* TK_FUNCTION: Window definition for the func */ Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */
struct { /* TK_IN, TK_SELECT, and TK_EXISTS */ struct { /* TK_IN, TK_SELECT, and TK_EXISTS */
int iAddr; /* Subroutine entry address */ int iAddr; /* Subroutine entry address */
int regReturn; /* Register used to hold return address */ int regReturn; /* Register used to hold return address */
@@ -2579,6 +2579,14 @@ struct Expr {
*/ */
#define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */ #define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */
/*
** True if the expression passed as an argument was a function with
** an OVER() clause (a window function).
*/
#define IsWindowFunc(p) ( \
ExprHasProperty((p), EP_WinFunc) && p->y.pWin->eFrmType!=TK_FILTER \
)
/* /*
** A list of expressions. Each expression may optionally have a ** A list of expressions. Each expression may optionally have a
** name. An expr/name combination can be used in several ways, such ** name. An expr/name combination can be used in several ways, such
@@ -3552,10 +3560,11 @@ struct TreeView {
#endif /* SQLITE_DEBUG */ #endif /* SQLITE_DEBUG */
/* /*
** This object is used in various ways, all related to window functions ** This object is used in various ways, most (but not all) related to window
** functions.
** **
** (1) A single instance of this structure is attached to the ** (1) A single instance of this structure is attached to the
** the Expr.pWin field for each window function in an expression tree. ** the Expr.y.pWin field for each window function in an expression tree.
** This object holds the information contained in the OVER clause, ** This object holds the information contained in the OVER clause,
** plus additional fields used during code generation. ** plus additional fields used during code generation.
** **
@@ -3566,6 +3575,10 @@ struct TreeView {
** (3) The terms of the WINDOW clause of a SELECT are instances of this ** (3) The terms of the WINDOW clause of a SELECT are instances of this
** object on a linked list attached to Select.pWinDefn. ** object on a linked list attached to Select.pWinDefn.
** **
** (4) For an aggregate function with a FILTER clause, an instance
** of this object is stored in Expr.y.pWin with eFrmType set to
** TK_FILTER. In this case the only field used is Window.pFilter.
**
** The uses (1) and (2) are really the same Window object that just happens ** The uses (1) and (2) are really the same Window object that just happens
** to be accessible in two different ways. Use case (3) are separate objects. ** to be accessible in two different ways. Use case (3) are separate objects.
*/ */
@@ -3603,7 +3616,7 @@ void sqlite3WindowDelete(sqlite3*, Window*);
void sqlite3WindowListDelete(sqlite3 *db, Window *p); void sqlite3WindowListDelete(sqlite3 *db, Window *p);
Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
void sqlite3WindowAttach(Parse*, Expr*, Window*); void sqlite3WindowAttach(Parse*, Expr*, Window*);
int sqlite3WindowCompare(Parse*, Window*, Window*); int sqlite3WindowCompare(Parse*, Window*, Window*, int);
void sqlite3WindowCodeInit(Parse*, Window*); void sqlite3WindowCodeInit(Parse*, Window*);
void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
int sqlite3WindowRewrite(Parse*, Select*); int sqlite3WindowRewrite(Parse*, Select*);

View File

@@ -4607,7 +4607,11 @@ static int vdbeRecordCompareString(
nCmp = MIN( pPKey2->aMem[0].n, nStr ); nCmp = MIN( pPKey2->aMem[0].n, nStr );
res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp); res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
if( res==0 ){ if( res>0 ){
res = pPKey2->r2;
}else if( res<0 ){
res = pPKey2->r1;
}else{
res = nStr - pPKey2->aMem[0].n; res = nStr - pPKey2->aMem[0].n;
if( res==0 ){ if( res==0 ){
if( pPKey2->nField>1 ){ if( pPKey2->nField>1 ){
@@ -4621,10 +4625,6 @@ static int vdbeRecordCompareString(
}else{ }else{
res = pPKey2->r1; res = pPKey2->r1;
} }
}else if( res>0 ){
res = pPKey2->r2;
}else{
res = pPKey2->r1;
} }
} }

View File

@@ -63,18 +63,22 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
assert( pExpr->x.pList==0 || pExpr->pRight==0 ); assert( pExpr->x.pList==0 || pExpr->pRight==0 );
if( pExpr->pRight ){ if( pExpr->pRight ){
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
pExpr = pExpr->pRight; pExpr = pExpr->pRight;
continue; continue;
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
}else if( pExpr->x.pList ){ }else{
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; if( pExpr->x.pList ){
} if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
}
#ifndef SQLITE_OMIT_WINDOWFUNC #ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(pExpr, EP_WinFunc) ){ if( ExprHasProperty(pExpr, EP_WinFunc) ){
if( walkWindowList(pWalker, pExpr->y.pWin) ) return WRC_Abort; if( walkWindowList(pWalker, pExpr->y.pWin) ) return WRC_Abort;
} }
#endif #endif
}
} }
break; break;
} }

View File

@@ -1196,17 +1196,14 @@ void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pList){
void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
if( p ){ if( p ){
assert( p->op==TK_FUNCTION ); assert( p->op==TK_FUNCTION );
/* This routine is only called for the parser. If pWin was not assert( pWin );
** allocated due to an OOM, then the parser would fail before ever p->y.pWin = pWin;
** invoking this routine */ ExprSetProperty(p, EP_WinFunc);
if( ALWAYS(pWin) ){ pWin->pOwner = p;
p->y.pWin = pWin; if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){
ExprSetProperty(p, EP_WinFunc); sqlite3ErrorMsg(pParse,
pWin->pOwner = p; "DISTINCT is not supported for window functions"
if( p->flags & EP_Distinct ){ );
sqlite3ErrorMsg(pParse,
"DISTINCT is not supported for window functions");
}
} }
}else{ }else{
sqlite3WindowDelete(pParse->db, pWin); sqlite3WindowDelete(pParse->db, pWin);
@@ -1217,7 +1214,7 @@ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
** Return 0 if the two window objects are identical, or non-zero otherwise. ** Return 0 if the two window objects are identical, or non-zero otherwise.
** Identical window objects can be processed in a single scan. ** Identical window objects can be processed in a single scan.
*/ */
int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){ int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2, int bFilter){
if( p1->eFrmType!=p2->eFrmType ) return 1; if( p1->eFrmType!=p2->eFrmType ) return 1;
if( p1->eStart!=p2->eStart ) return 1; if( p1->eStart!=p2->eStart ) return 1;
if( p1->eEnd!=p2->eEnd ) return 1; if( p1->eEnd!=p2->eEnd ) return 1;
@@ -1226,6 +1223,9 @@ int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){
if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1; if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1;
if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1; if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1;
if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1; if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1;
if( bFilter ){
if( sqlite3ExprCompare(pParse, p1->pFilter, p2->pFilter, -1) ) return 1;
}
return 0; return 0;
} }

106
test/filter1.test Normal file
View File

@@ -0,0 +1,106 @@
# 2018 May 8
#
# 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.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix filter1
ifcapable !windowfunc {
finish_test
return
}
do_execsql_test 1.0 {
CREATE TABLE t1(a);
CREATE INDEX i1 ON t1(a);
INSERT INTO t1 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9);
}
do_execsql_test 1.1 { SELECT sum(a) FROM t1; } 45
do_execsql_test 1.2 { SELECT sum(a) FILTER( WHERE a<5 ) FROM t1; } 10
do_execsql_test 1.3 {
SELECT sum(a) FILTER( WHERE a>9 ),
sum(a) FILTER( WHERE a>8 ),
sum(a) FILTER( WHERE a>7 ),
sum(a) FILTER( WHERE a>6 ),
sum(a) FILTER( WHERE a>5 ),
sum(a) FILTER( WHERE a>4 ),
sum(a) FILTER( WHERE a>3 ),
sum(a) FILTER( WHERE a>2 ),
sum(a) FILTER( WHERE a>1 ),
sum(a) FILTER( WHERE a>0 )
FROM t1;
} {{} 9 17 24 30 35 39 42 44 45}
do_execsql_test 1.4 {
SELECT max(a) FILTER (WHERE (a % 2)==0) FROM t1
} {8}
do_execsql_test 1.5 {
SELECT min(a) FILTER (WHERE a>4) FROM t1
} {5}
do_execsql_test 1.6 {
SELECT count(*) FILTER (WHERE a!=5) FROM t1
} {8}
do_execsql_test 1.7 {
SELECT min(a) FILTER (WHERE a>3) FROM t1 GROUP BY (a%2) ORDER BY 1;
} {4 5}
do_execsql_test 1.8 {
CREATE VIEW vv AS
SELECT sum(a) FILTER( WHERE a>9 ),
sum(a) FILTER( WHERE a>8 ),
sum(a) FILTER( WHERE a>7 ),
sum(a) FILTER( WHERE a>6 ),
sum(a) FILTER( WHERE a>5 ),
sum(a) FILTER( WHERE a>4 ),
sum(a) FILTER( WHERE a>3 ),
sum(a) FILTER( WHERE a>2 ),
sum(a) FILTER( WHERE a>1 ),
sum(a) FILTER( WHERE a>0 )
FROM t1;
SELECT * FROM vv;
} {{} 9 17 24 30 35 39 42 44 45}
#-------------------------------------------------------------------------
# Test some errors:
#
# .1 FILTER on a non-aggregate function,
# .2 Window function in FILTER clause,
# .3 Aggregate function in FILTER clause,
#
reset_db
do_execsql_test 2.0 {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9);
}
do_catchsql_test 2.1 {
SELECT upper(a) FILTER (WHERE a=1) FROM t1
} {1 {filter clause may not be used with non-aggregate upper()}}
do_catchsql_test 2.2 {
SELECT sum(a) FILTER (WHERE 1 - max(a) OVER () > 0) FROM t1
} {1 {misuse of window function max()}}
do_catchsql_test 2.3 {
SELECT sum(a) FILTER (WHERE 1 - count(a)) FROM t1
} {1 {misuse of aggregate function count()}}
finish_test

132
test/filter2.tcl Normal file
View File

@@ -0,0 +1,132 @@
# 2018 May 19
#
# 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.
#
#***********************************************************************
#
source [file join [file dirname $argv0] pg_common.tcl]
#=========================================================================
start_test filter2 "2019 July 2"
ifcapable !windowfunc
execsql_test 1.0 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER);
INSERT INTO t1 VALUES
(1, 7), (2, 3), (3, 5), (4, 30), (5, 26), (6, 23), (7, 27),
(8, 3), (9, 17), (10, 26), (11, 33), (12, 25), (13, NULL), (14, 47),
(15, 36), (16, 13), (17, 45), (18, 31), (19, 11), (20, 36), (21, 37),
(22, 21), (23, 22), (24, 14), (25, 16), (26, 3), (27, 7), (28, 29),
(29, 50), (30, 38), (31, 3), (32, 36), (33, 12), (34, 4), (35, 46),
(36, 3), (37, 48), (38, 23), (39, NULL), (40, 24), (41, 5), (42, 46),
(43, 11), (44, NULL), (45, 18), (46, 25), (47, 15), (48, 18), (49, 23);
}
execsql_test 1.1 { SELECT sum(b) FROM t1 }
execsql_test 1.2 { SELECT sum(b) FILTER (WHERE a<10) FROM t1 }
execsql_test 1.3 { SELECT count(DISTINCT b) FROM t1 }
execsql_test 1.4 { SELECT count(DISTINCT b) FILTER (WHERE a!=19) FROM t1 }
execsql_test 1.5 {
SELECT min(b) FILTER (WHERE a>19),
min(b) FILTER (WHERE a>0),
max(a+b) FILTER (WHERE a>19),
max(b+a) FILTER (WHERE a BETWEEN 10 AND 40)
FROM t1;
}
execsql_test 1.6 {
SELECT min(b),
min(b),
max(a+b),
max(b+a)
FROM t1
GROUP BY (a%10)
ORDER BY 1, 2, 3, 4;
}
execsql_test 1.7 {
SELECT min(b) FILTER (WHERE a>19),
min(b) FILTER (WHERE a>0),
max(a+b) FILTER (WHERE a>19),
max(b+a) FILTER (WHERE a BETWEEN 10 AND 40)
FROM t1
GROUP BY (a%10)
ORDER BY 1, 2, 3, 4;
}
execsql_test 1.8 {
SELECT sum(a+b) FILTER (WHERE a=NULL) FROM t1
}
execsql_test 1.9 {
SELECT (a%5) FROM t1 GROUP BY (a%5)
HAVING sum(b) FILTER (WHERE b<20) > 34
ORDER BY 1
}
execsql_test 1.10 {
SELECT (a%5), sum(b) FILTER (WHERE b<20) AS bbb
FROM t1
GROUP BY (a%5) HAVING sum(b) FILTER (WHERE b<20) >34
ORDER BY 1
}
execsql_test 1.11 {
SELECT (a%5), sum(b) FILTER (WHERE b<20) AS bbb
FROM t1
GROUP BY (a%5) HAVING sum(b) FILTER (WHERE b<20) >34
ORDER BY 2
}
execsql_test 1.12 {
SELECT (a%5),
sum(b) FILTER (WHERE b<20) AS bbb,
count(distinct b) FILTER (WHERE b<20 OR a=13) AS ccc
FROM t1 GROUP BY (a%5)
ORDER BY 2
}
execsql_test 1.13 {
SELECT
string_agg(CAST(b AS TEXT), '_') FILTER (WHERE b%2!=0),
string_agg(CAST(b AS TEXT), '_') FILTER (WHERE b%2!=1),
count(*) FILTER (WHERE b%2!=0),
count(*) FILTER (WHERE b%2!=1)
FROM t1;
}
execsql_float_test 1.14 {
SELECT
avg(b) FILTER (WHERE b>a),
avg(b) FILTER (WHERE b<a)
FROM t1 GROUP BY (a%2) ORDER BY 1,2;
}
execsql_test 1.15 {
SELECT
a/5,
sum(b) FILTER (WHERE a%5=0),
sum(b) FILTER (WHERE a%5=1),
sum(b) FILTER (WHERE a%5=2),
sum(b) FILTER (WHERE a%5=3),
sum(b) FILTER (WHERE a%5=4)
FROM t1 GROUP BY (a/5) ORDER BY 1;
}
finish_test

156
test/filter2.test Normal file
View File

@@ -0,0 +1,156 @@
# 2019 July 2
#
# 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.
#
####################################################
# DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED!
####################################################
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix filter2
ifcapable !windowfunc { finish_test ; return }
do_execsql_test 1.0 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER);
INSERT INTO t1 VALUES
(1, 7), (2, 3), (3, 5), (4, 30), (5, 26), (6, 23), (7, 27),
(8, 3), (9, 17), (10, 26), (11, 33), (12, 25), (13, NULL), (14, 47),
(15, 36), (16, 13), (17, 45), (18, 31), (19, 11), (20, 36), (21, 37),
(22, 21), (23, 22), (24, 14), (25, 16), (26, 3), (27, 7), (28, 29),
(29, 50), (30, 38), (31, 3), (32, 36), (33, 12), (34, 4), (35, 46),
(36, 3), (37, 48), (38, 23), (39, NULL), (40, 24), (41, 5), (42, 46),
(43, 11), (44, NULL), (45, 18), (46, 25), (47, 15), (48, 18), (49, 23);
} {}
do_execsql_test 1.1 {
SELECT sum(b) FROM t1
} {1041}
do_execsql_test 1.2 {
SELECT sum(b) FILTER (WHERE a<10) FROM t1
} {141}
do_execsql_test 1.3 {
SELECT count(DISTINCT b) FROM t1
} {31}
do_execsql_test 1.4 {
SELECT count(DISTINCT b) FILTER (WHERE a!=19) FROM t1
} {31}
do_execsql_test 1.5 {
SELECT min(b) FILTER (WHERE a>19),
min(b) FILTER (WHERE a>0),
max(a+b) FILTER (WHERE a>19),
max(b+a) FILTER (WHERE a BETWEEN 10 AND 40)
FROM t1;
} {3 3 88 85}
do_execsql_test 1.6 {
SELECT min(b),
min(b),
max(a+b),
max(b+a)
FROM t1
GROUP BY (a%10)
ORDER BY 1, 2, 3, 4;
} {3 3 58 58 3 3 66 66 3 3 71 71 3 3 88 88 4 4 61 61 5 5 54 54
7 7 85 85 11 11 79 79 16 16 81 81 24 24 68 68}
do_execsql_test 1.7 {
SELECT min(b) FILTER (WHERE a>19),
min(b) FILTER (WHERE a>0),
max(a+b) FILTER (WHERE a>19),
max(b+a) FILTER (WHERE a BETWEEN 10 AND 40)
FROM t1
GROUP BY (a%10)
ORDER BY 1, 2, 3, 4;
} {3 3 58 58 3 3 71 39 4 4 38 61 7 7 85 85 11 5 54 45 16 16 81 81
18 3 66 61 21 3 88 68 23 11 79 79 24 24 68 68}
do_execsql_test 1.8 {
SELECT sum(a+b) FILTER (WHERE a=NULL) FROM t1
} {{}}
do_execsql_test 1.9 {
SELECT (a%5) FROM t1 GROUP BY (a%5)
HAVING sum(b) FILTER (WHERE b<20) > 34
ORDER BY 1
} {3 4}
do_execsql_test 1.10 {
SELECT (a%5), sum(b) FILTER (WHERE b<20) AS bbb
FROM t1
GROUP BY (a%5) HAVING sum(b) FILTER (WHERE b<20) >34
ORDER BY 1
} {3 49 4 46}
do_execsql_test 1.11 {
SELECT (a%5), sum(b) FILTER (WHERE b<20) AS bbb
FROM t1
GROUP BY (a%5) HAVING sum(b) FILTER (WHERE b<20) >34
ORDER BY 2
} {4 46 3 49}
do_execsql_test 1.12 {
SELECT (a%5),
sum(b) FILTER (WHERE b<20) AS bbb,
count(distinct b) FILTER (WHERE b<20 OR a=13) AS ccc
FROM t1 GROUP BY (a%5)
ORDER BY 2
} {2 25 3 0 34 2 1 34 4 4 46 4 3 49 5}
do_execsql_test 1.13 {
SELECT
group_concat(CAST(b AS TEXT), '_') FILTER (WHERE b%2!=0),
group_concat(CAST(b AS TEXT), '_') FILTER (WHERE b%2!=1),
count(*) FILTER (WHERE b%2!=0),
count(*) FILTER (WHERE b%2!=1)
FROM t1;
} {7_3_5_23_27_3_17_33_25_47_13_45_31_11_37_21_3_7_29_3_3_23_5_11_25_15_23 30_26_26_36_36_22_14_16_50_38_36_12_4_46_48_24_46_18_18 27 19}
do_test 1.14 {
set myres {}
foreach r [db eval {SELECT
avg(b) FILTER (WHERE b>a),
avg(b) FILTER (WHERE b<a)
FROM t1 GROUP BY (a%2) ORDER BY 1,2;}] {
lappend myres [format %.4f [set r]]
}
set res2 {30.8333 13.7273 31.4167 13.0000}
set i 0
foreach r [set myres] r2 [set res2] {
if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} {
error "list element [set i] does not match: got=[set r] expected=[set r2]"
}
incr i
}
set {} {}
} {}
do_execsql_test 1.15 {
SELECT
a/5,
sum(b) FILTER (WHERE a%5=0),
sum(b) FILTER (WHERE a%5=1),
sum(b) FILTER (WHERE a%5=2),
sum(b) FILTER (WHERE a%5=3),
sum(b) FILTER (WHERE a%5=4)
FROM t1 GROUP BY (a/5) ORDER BY 1;
} {0 {} 7 3 5 30 1 26 23 27 3 17 2 26 33 25 {} 47 3 36 13 45 31 11
4 36 37 21 22 14 5 16 3 7 29 50 6 38 3 36 12 4 7 46 3 48 23 {}
8 24 5 46 11 {} 9 18 25 15 18 23}
finish_test

View File

@@ -424,6 +424,13 @@ execsql_float_test 4.9 {
WINDOW win AS (ORDER BY 1); WINDOW win AS (ORDER BY 1);
} }
execsql_test 4.10 {
SELECT count(*) OVER (ORDER BY b) FROM t1
}
execsql_test 4.11 {
SELECT count(distinct a) FILTER (WHERE b='odd') FROM t1
}
finish_test finish_test

View File

@@ -893,4 +893,12 @@ do_test 4.9 {
set {} {} set {} {}
} {} } {}
do_execsql_test 4.10 {
SELECT count(*) OVER (ORDER BY b) FROM t1
} {3 3 3 6 6 6}
do_execsql_test 4.11 {
SELECT count(distinct a) FILTER (WHERE b='odd') FROM t1
} {3}
finish_test finish_test