1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Experimental implementation of NULLS FIRST/LAST. This branch still has problems - the most significant of which is that ORDER BY clauses with a non-default NULLS FIRST/LAST qualifier can never use an index.

FossilOrigin-Name: 07babb0f897fc8c9cb5b30481899c32fdd743f3f3ca508d8d957826252107dd5
This commit is contained in:
dan
2019-08-12 16:36:38 +00:00
parent 41428a97b8
commit 6e11892db8
14 changed files with 171 additions and 64 deletions

View File

@ -1,5 +1,5 @@
C For\sthe\s".testctrl\sprng_seed"\scommand\sin\sthe\sCLI,\sif\sthe\sargument\sis\s"random"\nthen\sselect\sa\srandom\sinteger\sseed\sand\sprint\sthe\sseed\svalue\son\sstdout. C Experimental\simplementation\sof\sNULLS\sFIRST/LAST.\sThis\sbranch\sstill\shas\sproblems\s-\sthe\smost\ssignificant\sof\swhich\sis\sthat\sORDER\sBY\sclauses\swith\sa\snon-default\sNULLS\sFIRST/LAST\squalifier\scan\snever\suse\san\sindex.
D 2019-08-12T16:25:11.731 D 2019-08-12T16:36:38.041
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
@ -467,7 +467,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c 781e4594098dca97db672e52ed17c7f063b5b65db144c0c1bf1e9818e7be1ad4 F src/btree.c 781e4594098dca97db672e52ed17c7f063b5b65db144c0c1bf1e9818e7be1ad4
F src/btree.h c11446f07ec0e9dc85af8041cb0855c52f5359c8b2a43e47e02a685282504d89 F src/btree.h c11446f07ec0e9dc85af8041cb0855c52f5359c8b2a43e47e02a685282504d89
F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f
F src/build.c 7fb6ad35d162517d6bfa196f4fb2a1d7c3a362531e84c59f3a0479e0de511556 F src/build.c 3584e598dd232b182bb657576a4b7ee0c2bd20afa59ad2fe0c4e65ed74e57b64
F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251
@ -475,7 +475,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 85239130e25f54279b1dfb3641984a335ce5a38709af29f9b62b555ed1459d07 F src/expr.c 7cc60cb97c0ddda825cc8bd2de4d3f51f183e894316c74225729ecfa8823aa05
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 6b79f4c2447691aa9ac86e2a6a774b65f3b3dd053d4220a4893051a0de20f82e F src/fkey.c 6b79f4c2447691aa9ac86e2a6a774b65f3b3dd053d4220a4893051a0de20f82e
F src/func.c 4ee36219698d50d672a28eca4adb0fd6b92e607a1883d318315e0d2fd5044467 F src/func.c 4ee36219698d50d672a28eca4adb0fd6b92e607a1883d318315e0d2fd5044467
@ -512,7 +512,7 @@ F src/os_win.c 035a813cbd17f355bdcad7ab894af214a9c13a1db8aeac902365350b98cd45a7
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 6d03a24bc0dcd15b93c480ea8a87f7ccd25313fe826485726d9ef13b82f2378d F src/parse.y 61e979ce7f860df902b21b16ed40504ddd58fe4546fb15908a51538b3062e8e0
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848 F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848
@ -523,12 +523,12 @@ F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c d49679d55d3cf529bbdff8734c4ac02cedfb2fc785545b89815ddb79680b9198 F src/resolve.c d49679d55d3cf529bbdff8734c4ac02cedfb2fc785545b89815ddb79680b9198
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
F src/select.c 11087458ec2af5c4b377559ea0462c2ab842e02badd35b21a8d67257c4e0b117 F src/select.c a8f5a4993c4ca59c68c55717f7f41e89cff6084b368f33cfd284dcf78262b9ad
F src/shell.c.in 66cd8289adbcd159ca67872c242990ca6bed29fe80be7ebf9c6a1c068249a41e F src/shell.c.in 66cd8289adbcd159ca67872c242990ca6bed29fe80be7ebf9c6a1c068249a41e
F src/sqlite.h.in 1fe019ae55182040e6ea10c89ddbb8d24c1b1015c423da53e55205398a65a906 F src/sqlite.h.in 1fe019ae55182040e6ea10c89ddbb8d24c1b1015c423da53e55205398a65a906
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5 F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5
F src/sqliteInt.h 0598c87a995d63b09bcc408552bf38205cd902b577e74b7c3237bde71093c28b F src/sqliteInt.h f1ee0017108d34ecccd30301415be7861816877e3e9a01088df081fbcfbf908c
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
@ -595,25 +595,25 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507
F src/util.c fffdfa627be74d69ef425f92db124e7148af449bb8a3286e79577c42bca84061 F src/util.c fffdfa627be74d69ef425f92db124e7148af449bb8a3286e79577c42bca84061
F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf
F src/vdbe.c 1041610254502572bcc79ce6f61d9364fb93c154a4935fbaeaa7fd2e158e5205 F src/vdbe.c bc43c994a18290b4022eb3751d510df1e070d92fa669e51de515fdd529ef105e
F src/vdbe.h 3f2b571e702e77e6bf031f0236e554aedfae643e991f69000320f481408455cf F src/vdbe.h 3f2b571e702e77e6bf031f0236e554aedfae643e991f69000320f481408455cf
F src/vdbeInt.h e95de5129124d77f01439e6635012adfaf23c0017bff47296126143cf18bd0c6 F src/vdbeInt.h e95de5129124d77f01439e6635012adfaf23c0017bff47296126143cf18bd0c6
F src/vdbeapi.c 95001d0f84ee3cda344fed98ca0d7961deb4fc836b83495630d0af1f7cc4789e F src/vdbeapi.c 95001d0f84ee3cda344fed98ca0d7961deb4fc836b83495630d0af1f7cc4789e
F src/vdbeaux.c 8eeb9799d80bc6b37f2bcb23b3519234b596c530046c2cd0261f9ef1a1ba6c37 F src/vdbeaux.c 68fd90976d0550bd9ab9ba03befba1f182aadce8bfca7d4b4eb33a2587c925bd
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1 F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
F src/vdbemem.c 920285c3b7f5c64369e02da437dab71e9e91862df9c486541c14633739f91d75 F src/vdbemem.c 920285c3b7f5c64369e02da437dab71e9e91862df9c486541c14633739f91d75
F src/vdbesort.c 3531ae3a431ad6b98b67bd891fb42ec9d66867157188a2b1a9e58c55da6151b2 F src/vdbesort.c da75f505aba230060ce6472605a4aa6494f73eeb1071e1cc2643c3d4035e671b
F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0 F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
F src/vtab.c 1fa256c6ddad7a81e2a4dc080d015d4b0a7135767717d311298e47f6fca64bb3 F src/vtab.c 1fa256c6ddad7a81e2a4dc080d015d4b0a7135767717d311298e47f6fca64bb3
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c bbd6838bd79c0a32144d482fb0b6a9d2d1a252fb3b16d5005ec30f2f80413b0d F src/wal.c bbd6838bd79c0a32144d482fb0b6a9d2d1a252fb3b16d5005ec30f2f80413b0d
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd
F src/where.c 90cb93dc8eb9383e72f661b2074551d47ff21e5379f7167f7e078bed436989e9 F src/where.c 83fc2acadfbb1c86501fc0847fd068040ecd9a250a2fc0b81bab5698aa4bc72d
F src/whereInt.h 2082fc2bd1eb66cb236a1a3c4b250e33d2bad9e43a0486a2cf9e4e211c58f3eb F src/whereInt.h 2082fc2bd1eb66cb236a1a3c4b250e33d2bad9e43a0486a2cf9e4e211c58f3eb
F src/wherecode.c cf885ea2d439af9827c5cbab7d4c12be5c079439b7bd12e97151ccfe088c13c0 F src/wherecode.c cf885ea2d439af9827c5cbab7d4c12be5c079439b7bd12e97151ccfe088c13c0
F src/whereexpr.c 5cce1fd11876086890a27c05e0cb75ca97ba64ba6984f72154039f1cfd2e69cc F src/whereexpr.c 5cce1fd11876086890a27c05e0cb75ca97ba64ba6984f72154039f1cfd2e69cc
F src/window.c 98b2571c66246bddadf42e76da45ed970fe7518a4c9c1ccc8cdace0711bfabba F src/window.c 4d56fc1e3dbd3a4fa0653b3f48a3ad7066d0da91d0273cff8bab13c3412ddaf5
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
@ -1182,6 +1182,7 @@ F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161
F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934 F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
F test/notnull.test a37b663d5bb728d66fc182016613fb8e4a0a4bbf3d75b8876a7527f7d4ed3f18 F test/notnull.test a37b663d5bb728d66fc182016613fb8e4a0a4bbf3d75b8876a7527f7d4ed3f18
F test/null.test 0dcce4f04284ec66108c503327ad6d224c0752b3 F test/null.test 0dcce4f04284ec66108c503327ad6d224c0752b3
F test/nulls1.test eac9f46d9bf7a3883700bbc063e8a64fa2f4677ea64f12e173d3052d635f6b23
F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1 F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
F test/numindex1.test 20a5450d4b056e48cd5db30e659f13347a099823 F test/numindex1.test 20a5450d4b056e48cd5db30e659f13347a099823
F test/offset1.test f06b83657bcf26f9ce805e67450e189e282143b2 F test/offset1.test f06b83657bcf26f9ce805e67450e189e282143b2
@ -1764,7 +1765,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3 F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
F tool/mkkeywordhash.c 537b1a11ec1829b51b633da3ba2cc889b4a3f7356b06a07423b6d4cce92c2350 F tool/mkkeywordhash.c bc5bcc92ebcaf15345346be7cf2204b83ed649b5208234adb5e543c061209bbf
F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6a13ea F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6a13ea
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21 F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
@ -1836,7 +1837,11 @@ 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 48d9b48ab4ace234eb1a055cf33cb533a1c3aa82d0a6e086d96226bd9474ceca P 636ca4472c9f41eb3989f28854d4968867837399a2092f389d1b814d98cccbae
R 5a141faa1c39cc955778f126f1aabd0f R 6d8a33d8edc53ea630705f876c1c3795
U drh T *branch * nulls-last
Z 779c2cf81842090ecdd5432af318ddb5 T *sym-nulls-last *
T +closed 8174b2ca587e87083950ab21a47b4b4fe4bf309a8e16a82d4dc26d2c471e28cc
T -sym-trunk *
U dan
Z 02a41ef53191d3d08ca3291791a40934

View File

@ -1 +1 @@
636ca4472c9f41eb3989f28854d4968867837399a2092f389d1b814d98cccbae 07babb0f897fc8c9cb5b30481899c32fdd743f3f3ca508d8d957826252107dd5

View File

@ -1443,7 +1443,7 @@ void sqlite3AddPrimaryKey(
pTab->keyConf = (u8)onError; pTab->keyConf = (u8)onError;
assert( autoInc==0 || autoInc==1 ); assert( autoInc==0 || autoInc==1 );
pTab->tabFlags |= autoInc*TF_Autoincrement; pTab->tabFlags |= autoInc*TF_Autoincrement;
if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder; if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags;
}else if( autoInc ){ }else if( autoInc ){
#ifndef SQLITE_OMIT_AUTOINCREMENT #ifndef SQLITE_OMIT_AUTOINCREMENT
sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
@ -1894,7 +1894,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
if( IN_RENAME_OBJECT ){ if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey); sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey);
} }
pList->a[0].sortOrder = pParse->iPkSortOrder; pList->a[0].sortFlags = pParse->iPkSortOrder;
assert( pParse->pNewTable==pTab ); assert( pParse->pNewTable==pTab );
pTab->iPKey = -1; pTab->iPKey = -1;
sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
@ -3368,7 +3368,7 @@ void sqlite3CreateIndex(
sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
if( pList==0 ) goto exit_create_index; if( pList==0 ) goto exit_create_index;
assert( pList->nExpr==1 ); assert( pList->nExpr==1 );
sqlite3ExprListSetSortOrder(pList, sortOrder); sqlite3ExprListSetSortOrder(pList, sortOrder, 0);
}else{ }else{
sqlite3ExprListCheckLength(pParse, pList, "index"); sqlite3ExprListCheckLength(pParse, pList, "index");
if( pParse->nErr ) goto exit_create_index; if( pParse->nErr ) goto exit_create_index;
@ -3486,7 +3486,7 @@ void sqlite3CreateIndex(
goto exit_create_index; goto exit_create_index;
} }
pIndex->azColl[i] = zColl; pIndex->azColl[i] = zColl;
requestedSortOrder = pListItem->sortOrder & sortOrderMask; requestedSortOrder = pListItem->sortFlags & sortOrderMask;
pIndex->aSortOrder[i] = (u8)requestedSortOrder; pIndex->aSortOrder[i] = (u8)requestedSortOrder;
} }
@ -4704,7 +4704,8 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
const char *zColl = pIdx->azColl[i]; const char *zColl = pIdx->azColl[i];
pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 : pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 :
sqlite3LocateCollSeq(pParse, zColl); sqlite3LocateCollSeq(pParse, zColl);
pKey->aSortOrder[i] = pIdx->aSortOrder[i]; pKey->aSortFlags[i] = pIdx->aSortOrder[i];
assert( 0==(pKey->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) );
} }
if( pParse->nErr ){ if( pParse->nErr ){
assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ ); assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ );

View File

@ -1404,7 +1404,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
} }
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan); pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
pItem->sortOrder = pOldItem->sortOrder; pItem->sortFlags = pOldItem->sortFlags;
pItem->done = 0; pItem->done = 0;
pItem->bSpanIsTab = pOldItem->bSpanIsTab; pItem->bSpanIsTab = pOldItem->bSpanIsTab;
pItem->bSorterRef = pOldItem->bSorterRef; pItem->bSorterRef = pOldItem->bSorterRef;
@ -1657,15 +1657,25 @@ vector_append_error:
/* /*
** Set the sort order for the last element on the given ExprList. ** Set the sort order for the last element on the given ExprList.
*/ */
void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){ void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){
if( p==0 ) return; if( p==0 ) return;
assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 );
assert( p->nExpr>0 ); assert( p->nExpr>0 );
if( iSortOrder<0 ){
assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC ); assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC==0 && SQLITE_SO_DESC>0 );
return; assert( iSortOrder==SQLITE_SO_UNDEFINED
|| iSortOrder==SQLITE_SO_ASC
|| iSortOrder==SQLITE_SO_DESC
);
assert( eNulls==SQLITE_SO_UNDEFINED
|| eNulls==SQLITE_SO_ASC
|| eNulls==SQLITE_SO_DESC
);
if( iSortOrder==SQLITE_SO_UNDEFINED ) iSortOrder = SQLITE_SO_ASC;
p->a[p->nExpr-1].sortFlags = (u8)iSortOrder;
if( eNulls!=SQLITE_SO_UNDEFINED && iSortOrder!=eNulls ){
p->a[p->nExpr-1].sortFlags |= KEYINFO_ORDER_BIGNULL;
} }
p->a[p->nExpr-1].sortOrder = (u8)iSortOrder;
} }
/* /*
@ -4909,7 +4919,7 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
for(i=0; i<pA->nExpr; i++){ for(i=0; i<pA->nExpr; i++){
Expr *pExprA = pA->a[i].pExpr; Expr *pExprA = pA->a[i].pExpr;
Expr *pExprB = pB->a[i].pExpr; Expr *pExprB = pB->a[i].pExpr;
if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1; if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1; if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1;
} }
return 0; return 0;

View File

@ -211,6 +211,7 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN
QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW ROWS QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW ROWS
ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
NULLS FIRST LAST
%ifdef SQLITE_OMIT_COMPOUND_SELECT %ifdef SQLITE_OMIT_COMPOUND_SELECT
EXCEPT INTERSECT UNION EXCEPT INTERSECT UNION
%endif SQLITE_OMIT_COMPOUND_SELECT %endif SQLITE_OMIT_COMPOUND_SELECT
@ -781,13 +782,13 @@ using_opt(U) ::= . {U = 0;}
orderby_opt(A) ::= . {A = 0;} orderby_opt(A) ::= . {A = 0;}
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
sortlist(A) ::= sortlist(A) COMMA expr(Y) sortorder(Z). { sortlist(A) ::= sortlist(A) COMMA expr(Y) sortorder(Z) nulls(X). {
A = sqlite3ExprListAppend(pParse,A,Y); A = sqlite3ExprListAppend(pParse,A,Y);
sqlite3ExprListSetSortOrder(A,Z); sqlite3ExprListSetSortOrder(A,Z,X);
} }
sortlist(A) ::= expr(Y) sortorder(Z). { sortlist(A) ::= expr(Y) sortorder(Z) nulls(X). {
A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/ A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/
sqlite3ExprListSetSortOrder(A,Z); sqlite3ExprListSetSortOrder(A,Z,X);
} }
%type sortorder {int} %type sortorder {int}
@ -796,6 +797,11 @@ sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;}
sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;} sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;}
sortorder(A) ::= . {A = SQLITE_SO_UNDEFINED;} sortorder(A) ::= . {A = SQLITE_SO_UNDEFINED;}
%type nulls {int}
nulls(A) ::= NULLS FIRST. {A = SQLITE_SO_ASC;}
nulls(A) ::= NULLS LAST. {A = SQLITE_SO_DESC;}
nulls(A) ::= . {A = SQLITE_SO_UNDEFINED;}
%type groupby_opt {ExprList*} %type groupby_opt {ExprList*}
%destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);} %destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);}
groupby_opt(A) ::= . {A = 0;} groupby_opt(A) ::= . {A = 0;}

View File

@ -664,7 +664,7 @@ static void pushOntoSorter(
if( pParse->db->mallocFailed ) return; if( pParse->db->mallocFailed ) return;
pOp->p2 = nKey + nData; pOp->p2 = nKey + nData;
pKI = pOp->p4.pKeyInfo; pKI = pOp->p4.pKeyInfo;
memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */ memset(pKI->aSortFlags, 0, pKI->nKeyField); /* Makes OP_Jump testable */
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
testcase( pKI->nAllField > pKI->nKeyField+2 ); testcase( pKI->nAllField > pKI->nKeyField+2 );
pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat, pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat,
@ -1275,7 +1275,7 @@ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*); int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*);
KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra); KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
if( p ){ if( p ){
p->aSortOrder = (u8*)&p->aColl[N+X]; p->aSortFlags = (u8*)&p->aColl[N+X];
p->nKeyField = (u16)N; p->nKeyField = (u16)N;
p->nAllField = (u16)(N+X); p->nAllField = (u16)(N+X);
p->enc = ENC(db); p->enc = ENC(db);
@ -1352,7 +1352,7 @@ KeyInfo *sqlite3KeyInfoFromExprList(
assert( sqlite3KeyInfoIsWriteable(pInfo) ); assert( sqlite3KeyInfoIsWriteable(pInfo) );
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){ for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr); pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr);
pInfo->aSortOrder[i-iStart] = pItem->sortOrder; pInfo->aSortFlags[i-iStart] = pItem->sortFlags;
} }
} }
return pInfo; return pInfo;
@ -2253,7 +2253,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
} }
assert( sqlite3KeyInfoIsWriteable(pRet) ); assert( sqlite3KeyInfoIsWriteable(pRet) );
pRet->aColl[i] = pColl; pRet->aColl[i] = pColl;
pRet->aSortOrder[i] = pOrderBy->a[i].sortOrder; pRet->aSortFlags[i] = pOrderBy->a[i].sortFlags;
} }
} }
@ -3228,7 +3228,7 @@ static int multiSelectOrderBy(
assert( sqlite3KeyInfoIsWriteable(pKeyDup) ); assert( sqlite3KeyInfoIsWriteable(pKeyDup) );
for(i=0; i<nExpr; i++){ for(i=0; i<nExpr; i++){
pKeyDup->aColl[i] = multiSelectCollSeq(pParse, p, i); pKeyDup->aColl[i] = multiSelectCollSeq(pParse, p, i);
pKeyDup->aSortOrder[i] = 0; pKeyDup->aSortFlags[i] = 0;
} }
} }
} }
@ -4425,7 +4425,7 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
} }
*ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0); *ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0);
assert( pOrderBy!=0 || db->mallocFailed ); assert( pOrderBy!=0 || db->mallocFailed );
if( pOrderBy ) pOrderBy->a[0].sortOrder = sortOrder; if( pOrderBy ) pOrderBy->a[0].sortFlags = sortOrder;
return eRet; return eRet;
} }

View File

@ -2134,10 +2134,13 @@ struct KeyInfo {
u16 nKeyField; /* Number of key columns in the index */ u16 nKeyField; /* Number of key columns in the index */
u16 nAllField; /* Total columns, including key plus others */ u16 nAllField; /* Total columns, including key plus others */
sqlite3 *db; /* The database connection */ sqlite3 *db; /* The database connection */
u8 *aSortOrder; /* Sort order for each column. */ u8 *aSortFlags; /* Sort order for each column. */
CollSeq *aColl[1]; /* Collating sequence for each term of the key */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */
}; };
#define KEYINFO_ORDER_DESC 0x01
#define KEYINFO_ORDER_BIGNULL 0x02
/* /*
** This object holds a record which has been parsed out into individual ** This object holds a record which has been parsed out into individual
** fields, for the purposes of doing a comparison. ** fields, for the purposes of doing a comparison.
@ -2597,7 +2600,7 @@ struct ExprList {
Expr *pExpr; /* The parse tree for this expression */ Expr *pExpr; /* The parse tree for this expression */
char *zName; /* Token associated with this expression */ char *zName; /* Token associated with this expression */
char *zSpan; /* Original text of the expression */ char *zSpan; /* Original text of the expression */
u8 sortOrder; /* 1 for DESC or 0 for ASC */ u8 sortFlags; /* 1 for DESC or 0 for ASC */
unsigned done :1; /* A flag to indicate when processing is finished */ unsigned done :1; /* A flag to indicate when processing is finished */
unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */ unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
unsigned reusable :1; /* Constant expression is reusable */ unsigned reusable :1; /* Constant expression is reusable */
@ -3881,7 +3884,7 @@ void sqlite3ExprDelete(sqlite3*, Expr*);
void sqlite3ExprUnmapAndDelete(Parse*, Expr*); void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
void sqlite3ExprListSetSortOrder(ExprList*,int); void sqlite3ExprListSetSortOrder(ExprList*,int,int);
void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
void sqlite3ExprListDelete(sqlite3*, ExprList*); void sqlite3ExprListDelete(sqlite3*, ExprList*);

View File

@ -2227,9 +2227,14 @@ case OP_Compare: {
REGISTER_TRACE(p2+idx, &aMem[p2+idx]); REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
assert( i<pKeyInfo->nKeyField ); assert( i<pKeyInfo->nKeyField );
pColl = pKeyInfo->aColl[i]; pColl = pKeyInfo->aColl[i];
bRev = pKeyInfo->aSortOrder[i]; bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC);
iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl); iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
if( iCompare ){ if( iCompare ){
if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
&& ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null))
){
iCompare = -iCompare;
}
if( bRev ) iCompare = -iCompare; if( bRev ) iCompare = -iCompare;
break; break;
} }

View File

@ -1493,14 +1493,16 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
case P4_KEYINFO: { case P4_KEYINFO: {
int j; int j;
KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
assert( pKeyInfo->aSortOrder!=0 ); assert( pKeyInfo->aSortFlags!=0 );
sqlite3_str_appendf(&x, "k(%d", pKeyInfo->nKeyField); sqlite3_str_appendf(&x, "k(%d", pKeyInfo->nKeyField);
for(j=0; j<pKeyInfo->nKeyField; j++){ for(j=0; j<pKeyInfo->nKeyField; j++){
CollSeq *pColl = pKeyInfo->aColl[j]; CollSeq *pColl = pKeyInfo->aColl[j];
const char *zColl = pColl ? pColl->zName : ""; const char *zColl = pColl ? pColl->zName : "";
if( strcmp(zColl, "BINARY")==0 ) zColl = "B"; if( strcmp(zColl, "BINARY")==0 ) zColl = "B";
sqlite3_str_appendf(&x, ",%s%s", sqlite3_str_appendf(&x, ",%s%s%s",
pKeyInfo->aSortOrder[j] ? "-" : "", zColl); (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_DESC) ? "-" : "",
(pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_BIGNULL)? "N." : "",
zColl);
} }
sqlite3_str_append(&x, ")", 1); sqlite3_str_append(&x, ")", 1);
break; break;
@ -3813,7 +3815,7 @@ UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
if( !p ) return 0; if( !p ) return 0;
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
assert( pKeyInfo->aSortOrder!=0 ); assert( pKeyInfo->aSortFlags!=0 );
p->pKeyInfo = pKeyInfo; p->pKeyInfo = pKeyInfo;
p->nField = pKeyInfo->nKeyField + 1; p->nField = pKeyInfo->nKeyField + 1;
return p; return p;
@ -3912,7 +3914,7 @@ static int vdbeRecordCompareDebug(
if( szHdr1>98307 ) return SQLITE_CORRUPT; if( szHdr1>98307 ) return SQLITE_CORRUPT;
d1 = szHdr1; d1 = szHdr1;
assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB );
assert( pKeyInfo->aSortOrder!=0 ); assert( pKeyInfo->aSortFlags!=0 );
assert( pKeyInfo->nKeyField>0 ); assert( pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB ); assert( idx1<=szHdr1 || CORRUPT_DB );
do{ do{
@ -3943,7 +3945,12 @@ static int vdbeRecordCompareDebug(
pKeyInfo->nAllField>i ? pKeyInfo->aColl[i] : 0); pKeyInfo->nAllField>i ? pKeyInfo->aColl[i] : 0);
if( rc!=0 ){ if( rc!=0 ){
assert( mem1.szMalloc==0 ); /* See comment below */ assert( mem1.szMalloc==0 ); /* See comment below */
if( pKeyInfo->aSortOrder[i] ){ if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
&& ((mem1.flags & MEM_Null) || (pPKey2->aMem[i].flags & MEM_Null))
){
rc = -rc;
}
if( pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC ){
rc = -rc; /* Invert the result for DESC sort order. */ rc = -rc; /* Invert the result for DESC sort order. */
} }
goto debugCompareEnd; goto debugCompareEnd;
@ -4319,7 +4326,7 @@ int sqlite3VdbeRecordCompareWithSkip(
VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField
|| CORRUPT_DB ); || CORRUPT_DB );
assert( pPKey2->pKeyInfo->aSortOrder!=0 ); assert( pPKey2->pKeyInfo->aSortFlags!=0 );
assert( pPKey2->pKeyInfo->nKeyField>0 ); assert( pPKey2->pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB ); assert( idx1<=szHdr1 || CORRUPT_DB );
do{ do{
@ -4442,8 +4449,14 @@ int sqlite3VdbeRecordCompareWithSkip(
} }
if( rc!=0 ){ if( rc!=0 ){
if( pPKey2->pKeyInfo->aSortOrder[i] ){ int sortFlags = pPKey2->pKeyInfo->aSortFlags[i];
rc = -rc; if( sortFlags ){
if( (sortFlags & KEYINFO_ORDER_BIGNULL)==0
|| ((sortFlags & KEYINFO_ORDER_DESC)
!=(serial_type==0 || (pRhs->flags&MEM_Null)))
){
rc = -rc;
}
} }
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) ); assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) );
assert( mem1.szMalloc==0 ); /* See comment below */ assert( mem1.szMalloc==0 ); /* See comment below */
@ -4660,7 +4673,10 @@ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
** header size is (12*5 + 1 + 1) bytes. */ ** header size is (12*5 + 1 + 1) bytes. */
if( p->pKeyInfo->nAllField<=13 ){ if( p->pKeyInfo->nAllField<=13 ){
int flags = p->aMem[0].flags; int flags = p->aMem[0].flags;
if( p->pKeyInfo->aSortOrder[0] ){ if( p->pKeyInfo->aSortFlags[0] ){
if( p->pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL ){
return sqlite3VdbeRecordCompare;
}
p->r1 = 1; p->r1 = 1;
p->r2 = -1; p->r2 = -1;
}else{ }else{

View File

@ -829,7 +829,8 @@ static int vdbeSorterCompareText(
); );
} }
}else{ }else{
if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) );
if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){
res = res * -1; res = res * -1;
} }
} }
@ -897,7 +898,8 @@ static int vdbeSorterCompareInt(
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
); );
} }
}else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ }else if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){
assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) );
res = res * -1; res = res * -1;
} }
@ -1012,6 +1014,7 @@ int sqlite3VdbeSorterInit(
if( pKeyInfo->nAllField<13 if( pKeyInfo->nAllField<13
&& (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
&& (pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL)==0
){ ){
pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
} }

View File

@ -1031,7 +1031,7 @@ static sqlite3_index_info *allocateIndexInfo(
for(i=0; i<nOrderBy; i++){ for(i=0; i<nOrderBy; i++){
Expr *pExpr = pOrderBy->a[i].pExpr; Expr *pExpr = pOrderBy->a[i].pExpr;
pIdxOrderBy[i].iColumn = pExpr->iColumn; pIdxOrderBy[i].iColumn = pExpr->iColumn;
pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder; pIdxOrderBy[i].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC;
} }
*pmNoOmit = mNoOmit; *pmNoOmit = mNoOmit;
@ -3836,6 +3836,7 @@ static i8 wherePathSatisfiesOrderBy(
continue; continue;
} }
} }
if( pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL ) continue;
if( iColumn!=XN_ROWID ){ if( iColumn!=XN_ROWID ){
pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
@ -3849,10 +3850,11 @@ static i8 wherePathSatisfiesOrderBy(
if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){ if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){
/* Make sure the sort order is compatible in an ORDER BY clause. /* Make sure the sort order is compatible in an ORDER BY clause.
** Sort order is irrelevant for a GROUP BY clause. */ ** Sort order is irrelevant for a GROUP BY clause. */
assert( (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL)==0 );
if( revSet ){ if( revSet ){
if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0; if( (rev ^ revIdx)!=pOrderBy->a[i].sortFlags ) isMatch = 0;
}else{ }else{
rev = revIdx ^ pOrderBy->a[i].sortOrder; rev = revIdx ^ pOrderBy->a[i].sortFlags;
if( rev ) *pRevMask |= MASKBIT(iLoop); if( rev ) *pRevMask |= MASKBIT(iLoop);
revSet = 1; revSet = 1;
} }

View File

@ -888,7 +888,7 @@ static ExprList *exprListAppendList(
pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse); pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
} }
pList = sqlite3ExprListAppend(pParse, pList, pDup); pList = sqlite3ExprListAppend(pParse, pList, pDup);
if( pList ) pList->a[nInit+i].sortOrder = pAppend->a[i].sortOrder; if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
} }
} }
return pList; return pList;
@ -1296,8 +1296,8 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
pWin->regApp = pParse->nMem+1; pWin->regApp = pParse->nMem+1;
pParse->nMem += 3; pParse->nMem += 3;
if( pKeyInfo && pWin->pFunc->zName[1]=='i' ){ if( pKeyInfo && pWin->pFunc->zName[1]=='i' ){
assert( pKeyInfo->aSortOrder[0]==0 ); assert( pKeyInfo->aSortFlags[0]==0 );
pKeyInfo->aSortOrder[0] = 1; pKeyInfo->aSortFlags[0] = KEYINFO_ORDER_DESC;
} }
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->csrApp, 2); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->csrApp, 2);
sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
@ -1860,7 +1860,7 @@ static void windowCodeRangeTest(
assert( op==OP_Ge || op==OP_Gt || op==OP_Le ); assert( op==OP_Ge || op==OP_Gt || op==OP_Le );
assert( p->pMWin->pOrderBy && p->pMWin->pOrderBy->nExpr==1 ); assert( p->pMWin->pOrderBy && p->pMWin->pOrderBy->nExpr==1 );
if( p->pMWin->pOrderBy->a[0].sortOrder ){ if( p->pMWin->pOrderBy->a[0].sortFlags & KEYINFO_ORDER_DESC ){
switch( op ){ switch( op ){
case OP_Ge: op = OP_Le; break; case OP_Ge: op = OP_Le; break;
case OP_Gt: op = OP_Lt; break; case OP_Gt: op = OP_Lt; break;

53
test/nulls1.test Normal file
View File

@ -0,0 +1,53 @@
# 2019 August 10
#
# 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 nulls1
do_execsql_test 1.0 {
DROP TABLE IF EXISTS t3;
CREATE TABLE t3(a INTEGER);
INSERT INTO t3 VALUES(NULL), (10), (30), (20), (NULL);
} {}
for {set a 0} {$a < 2} {incr a} {
foreach {tn limit} {
1 ""
2 "LIMIT 10"
} {
do_execsql_test 1.$a.$tn.1 "
SELECT a FROM t3 ORDER BY a nULLS FIRST $limit
" {{} {} 10 20 30}
do_execsql_test 1.$a.$tn.2 "
SELECT a FROM t3 ORDER BY a nULLS LAST $limit
" {10 20 30 {} {}}
do_execsql_test 1.$a.$tn.3 "
SELECT a FROM t3 ORDER BY a DESC nULLS FIRST $limit
" {{} {} 30 20 10}
do_execsql_test 1.$a.$tn.4 "
SELECT a FROM t3 ORDER BY a DESC nULLS LAST $limit
" {30 20 10 {} {}}
}
catchsql { CREATE INDEX i1 ON t3(a) }
}
finish_test

View File

@ -210,6 +210,7 @@ static Keyword aKeywordTable[] = {
{ "EXPLAIN", "TK_EXPLAIN", EXPLAIN }, { "EXPLAIN", "TK_EXPLAIN", EXPLAIN },
{ "FAIL", "TK_FAIL", CONFLICT|TRIGGER }, { "FAIL", "TK_FAIL", CONFLICT|TRIGGER },
{ "FILTER", "TK_FILTER", WINDOWFUNC }, { "FILTER", "TK_FILTER", WINDOWFUNC },
{ "FIRST", "TK_FIRST", ALWAYS },
{ "FOLLOWING", "TK_FOLLOWING", WINDOWFUNC }, { "FOLLOWING", "TK_FOLLOWING", WINDOWFUNC },
{ "FOR", "TK_FOR", TRIGGER }, { "FOR", "TK_FOR", TRIGGER },
{ "FOREIGN", "TK_FOREIGN", FKEY }, { "FOREIGN", "TK_FOREIGN", FKEY },
@ -235,6 +236,7 @@ static Keyword aKeywordTable[] = {
{ "ISNULL", "TK_ISNULL", ALWAYS }, { "ISNULL", "TK_ISNULL", ALWAYS },
{ "JOIN", "TK_JOIN", ALWAYS }, { "JOIN", "TK_JOIN", ALWAYS },
{ "KEY", "TK_KEY", ALWAYS }, { "KEY", "TK_KEY", ALWAYS },
{ "LAST", "TK_LAST", ALWAYS },
{ "LEFT", "TK_JOIN_KW", ALWAYS }, { "LEFT", "TK_JOIN_KW", ALWAYS },
{ "LIKE", "TK_LIKE_KW", ALWAYS }, { "LIKE", "TK_LIKE_KW", ALWAYS },
{ "LIMIT", "TK_LIMIT", ALWAYS }, { "LIMIT", "TK_LIMIT", ALWAYS },
@ -245,6 +247,7 @@ static Keyword aKeywordTable[] = {
{ "NOTHING", "TK_NOTHING", UPSERT }, { "NOTHING", "TK_NOTHING", UPSERT },
{ "NOTNULL", "TK_NOTNULL", ALWAYS }, { "NOTNULL", "TK_NOTNULL", ALWAYS },
{ "NULL", "TK_NULL", ALWAYS }, { "NULL", "TK_NULL", ALWAYS },
{ "NULLS", "TK_NULLS", ALWAYS },
{ "OF", "TK_OF", ALWAYS }, { "OF", "TK_OF", ALWAYS },
{ "OFFSET", "TK_OFFSET", ALWAYS }, { "OFFSET", "TK_OFFSET", ALWAYS },
{ "ON", "TK_ON", ALWAYS }, { "ON", "TK_ON", ALWAYS },