1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Add support for "ORDER BY ... NULLS FIRST" and "ORDER BY ... NULLS LAST". Use this to fix ticket [f8a7060e].

FossilOrigin-Name: 94085fb3e756bc984237b74b6e29c68462ad860870c64dcb5124feaeec387660
This commit is contained in:
dan
2019-08-27 19:59:21 +00:00
24 changed files with 2129 additions and 245 deletions

View File

@@ -134,6 +134,7 @@ do_setup_rec_test $tn.5 {
SEARCH TABLE t1 USING COVERING INDEX t1_idx_000123a7 (a=?) SEARCH TABLE t1 USING COVERING INDEX t1_idx_000123a7 (a=?)
} }
if 0 {
do_setup_rec_test $tn.6 { do_setup_rec_test $tn.6 {
CREATE TABLE t1(a, b, c); CREATE TABLE t1(a, b, c);
} { } {
@@ -142,6 +143,7 @@ do_setup_rec_test $tn.6 {
CREATE INDEX t1_idx_00000061 ON t1(a); CREATE INDEX t1_idx_00000061 ON t1(a);
SEARCH TABLE t1 USING COVERING INDEX t1_idx_00000061 SEARCH TABLE t1 USING COVERING INDEX t1_idx_00000061
} }
}
do_setup_rec_test $tn.7 { do_setup_rec_test $tn.7 {
CREATE TABLE t1(a, b, c); CREATE TABLE t1(a, b, c);

View File

@@ -1,5 +1,5 @@
C The\sALWAYS()\sadded\sby\sthe\sprevious\scheck-in\swas\sincorrect.\s\sTake\sit\sback\sout. C Add\ssupport\sfor\s"ORDER\sBY\s...\sNULLS\sFIRST"\sand\s"ORDER\sBY\s...\sNULLS\sLAST".\sUse\sthis\sto\sfix\sticket\s[f8a7060e].
D 2019-08-27T17:59:01.529 D 2019-08-27T19:59:21.714
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
@@ -47,7 +47,7 @@ F ext/async/sqlite3async.c 0f3070cc3f5ede78f2b9361fb3b629ce200d7d74
F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3 F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4 F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
F ext/expert/expert1.test 358e416877a5693fb99d5514f5d88452b5239dc2196b74e0e926718502faef6d F ext/expert/expert1.test e2afc53a27610e8251e44c7f961806607a5490ff204b3db342740d558e052662
F ext/expert/sqlite3expert.c 3da865f2286433588260f41e796422c611bceaca3a0bbf9139a619cf7d062c19 F ext/expert/sqlite3expert.c 3da865f2286433588260f41e796422c611bceaca3a0bbf9139a619cf7d062c19
F ext/expert/sqlite3expert.h af6354f8ee5c9e025024e63fec3bd640a802afcc3099a44d804752cf0791d811 F ext/expert/sqlite3expert.h af6354f8ee5c9e025024e63fec3bd640a802afcc3099a44d804752cf0791d811
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
@@ -467,7 +467,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c fdc4389b271bca30138db27dc2dfb9f52c2a7baaa44845aaf31a3c54663d837f F src/btree.c fdc4389b271bca30138db27dc2dfb9f52c2a7baaa44845aaf31a3c54663d837f
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 da5d5d82eb53cb004e9120277cfe93a9c3dd294871eae3d728ebd0faee84d969
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 18b6d8b5fea8151fae6d67fb12f2fff1f3abe8d5fe70365ecb3671a0aaf51c27 F src/expr.c 0f3aaaac5c1bd6a34fece3308ad572ef846c1601c58957902dc2a36f75373364
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
@@ -484,7 +484,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c c2194dd2886337b870226fcb31c13e7df8c4b5e0ea85140e510a6f1daf1ad65b F src/insert.c 81eec6acf4fbf0942bbab6804fe50df3e109acba40b8bbfb00fec9a14d0715a6
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c a045bb3425a9a633cc0f78e93d9beda6866f4c0f15bfdee735aba7c6b39f5cc4 F src/loadext.c a045bb3425a9a633cc0f78e93d9beda6866f4c0f15bfdee735aba7c6b39f5cc4
F src/main.c 51c55eb579eac4180bfcc6242741084710911350d2cd0c3fdd0f9fde55442128 F src/main.c 51c55eb579eac4180bfcc6242741084710911350d2cd0c3fdd0f9fde55442128
@@ -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 152a72755398be8f36e097bbab9fd3eeebc638b31ed1ec134e49284f9d7f013a F src/parse.y 6f284f7488ad9db9ae2762161e52bec2e9609462b98a3354fcc6e0ce7aa7be8d
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 9891cf5fd155bb199f8b1ff5d1429b9f70484487f4c455bba94348d4cb6f829f F src/resolve.c 9891cf5fd155bb199f8b1ff5d1429b9f70484487f4c455bba94348d4cb6f829f
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
F src/select.c c1dfbd699a6dce14c2e6f30370a57753294d6b725cc75551b26146e0c1d25076 F src/select.c e4fe08c3da81a38061454fb7de2c1b31c36ed76cd1a4bbefd2b5fc4ebb472a5b
F src/shell.c.in e5fb91505f29ae9458cabf1a63bbd1faf6b4b34eabca33d0f75a06aacecca21b F src/shell.c.in e5fb91505f29ae9458cabf1a63bbd1faf6b4b34eabca33d0f75a06aacecca21b
F src/sqlite.h.in 50fc0914ccd347437db9a0278a47d7541df3a45eb6e641e9680750c6f98dad27 F src/sqlite.h.in 50fc0914ccd347437db9a0278a47d7541df3a45eb6e641e9680750c6f98dad27
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31
F src/sqliteInt.h ce52cf59718f4affee3057381f5cf7acefe42d2ab6b43c6da93f4b1f6a3c704b F src/sqliteInt.h b1fca535f01f02ae6927dd44e760c6ab54c7a181e88f813d16b55a1bc95d13c0
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
@@ -589,31 +589,31 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e F src/tokenize.c d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e
F src/treeview.c fc8c6c0a8a26afb3a97e3f844d65403dd27cf1450baf4415034fa4ccf00c4d7e F src/treeview.c fc8c6c0a8a26afb3a97e3f844d65403dd27cf1450baf4415034fa4ccf00c4d7e
F src/trigger.c f964d85935d0b9675b4aa2f74999cabee3ac1ac705f71b38a8b7e8ccd4ad474b F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e
F src/update.c 3cb9150d2cf661d938e2f1b1749945f3faa767f88febdb739ab1793bbf895ff2 F src/update.c 3cb9150d2cf661d938e2f1b1749945f3faa767f88febdb739ab1793bbf895ff2
F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4 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 cdd90f4c4773a08504c66815faa505570257619a0bafcc9b486a24844be51357 F src/vdbe.c fca0f3762bc5cb7698a0bf754886503e703f66bf28013479c2177345053cab17
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 7ccf418141df1c7f87b0d69510523ae522abbe47c769d1b2c15120e88fac3eb9
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 5a0b7193d586991b3db30e343d6b59959906bfe8658a6a0a85709b20ca50bb49 F src/vtab.c 5a0b7193d586991b3db30e343d6b59959906bfe8658a6a0a85709b20ca50bb49
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 6cc2708ab9a386c0aef3fa50ed0f5bdfed22848e492960a4504eb25bdb79c8d1 F src/where.c 6f8bd0b4ade152571e960504a3042a31fd80e8adcef834db0717af3fbac4acb5
F src/whereInt.h 2082fc2bd1eb66cb236a1a3c4b250e33d2bad9e43a0486a2cf9e4e211c58f3eb F src/whereInt.h 4a296fd4fa79fdcbc2b5e8c1b898901617655811223e1082b899c23ecb092217
F src/wherecode.c e1131fe94c8728cbecc707f6455afbda9418896497bdca2d49a04ce6c57999f6 F src/wherecode.c 535c8e228478fd971b9a5b6cb6773995b0fbf7020d5989508a5094ce5b8cd95b
F src/whereexpr.c 2757afbd5cfdbb420f9d0392e1bd5f5c0e33dee50a8c692befc7e502308e449f F src/whereexpr.c 2757afbd5cfdbb420f9d0392e1bd5f5c0e33dee50a8c692befc7e502308e449f
F src/window.c 07e1c15081a735750218185c6b17053c87ecb764d06ab2c0a1ce568a2b4688e5 F src/window.c 3ea716bb0dd5ffc8cdbaa48baffc525958b51bc61b2afd73a56baccfcd7ceb2f
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test b03930d288e38b07f55023a58538ad174605695e98934bdab1facf6bd9ecc436 F test/affinity2.test b03930d288e38b07f55023a58538ad174605695e98934bdab1facf6bd9ecc436
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -1150,7 +1150,7 @@ F test/memsubsys2.test 3e4a8d0c05fd3e5fa92017c64666730a520c7e08
F test/minmax.test 6751e87b409fe11b02e70a306d846fa544e25a41 F test/minmax.test 6751e87b409fe11b02e70a306d846fa544e25a41
F test/minmax2.test dae92964ac87c1d2ef978c582e81a95e11c00f1cbef68980bfb2abaf10315063 F test/minmax2.test dae92964ac87c1d2ef978c582e81a95e11c00f1cbef68980bfb2abaf10315063
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
F test/minmax4.test 838fe32b812dc50778be3799767cefb5ff59bb04cff81d4f12c0708642f65151 F test/minmax4.test 272ca395257f05937dc96441c9dde4bc9fbf116a8d4fa02baeb0d13d50e36c87
F test/misc1.test 7ce84b25df9872e7d7878613a96815d2ba5bc974ac4e15a50118dde8f3917599 F test/misc1.test 7ce84b25df9872e7d7878613a96815d2ba5bc974ac4e15a50118dde8f3917599
F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
@@ -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 5b978fbae9c73b497608c16f2636a2f71de6e2c914e4c78955cf022e39b7a0d5
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
@@ -1216,7 +1217,7 @@ F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442 F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/permutations.test 4282fb00e5ac0f8c2cd1be62652f6da4ac03ce3c58b7d785fa17f4684492a0e0 F test/permutations.test 4282fb00e5ac0f8c2cd1be62652f6da4ac03ce3c58b7d785fa17f4684492a0e0
F test/pg_common.tcl 4740dc35190d6acdab14c097783331361301ab504a94d948f6afbb56ce0a51e8 F test/pg_common.tcl 222a1bad1c41c308fa366313cd7b51b3be7e9b21c8736a421b974ac941693b54
F test/pragma.test cf066fe0f7f5d49f4758de4986407b8676c61aaa7871599340d64f42a8edc352 F test/pragma.test cf066fe0f7f5d49f4758de4986407b8676c61aaa7871599340d64f42a8edc352
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c0df9 F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c0df9
@@ -1709,9 +1710,9 @@ F test/window4.test 807f3e6b15f9338e5b9742b87c5c7ca825b42b9657fde6096e8901193708
F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652821e F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652821e
F test/window6.test f8d674254b23289cc17c84d79dec7eda7caa1dfb7836c43122cfdf3640d1df32 F test/window6.test f8d674254b23289cc17c84d79dec7eda7caa1dfb7836c43122cfdf3640d1df32
F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f
F test/window7.test ce7f865241fdd1c5c4db869cd7bb2986c3be836bc2e73649a6846dd920f63e0f F test/window7.test 1d31276961ae7801edc72173edaf7593e3cbc79c06d1f1f09e20d8418af403cd
F test/window8.tcl 9e9a82ae9eea90a4a83481d641a812b974980c38f9247f3b89a6e3c8bed45518 F test/window8.tcl 5884cc884f9605bf88c0d18a534894bf9342f72687bf1bc43ed0cab4c8af7973
F test/window8.test df187dc19921f7be0ab709d531d681bd80ccaac96a913a89ecee8b272b91d43f F test/window8.test 48590f3737d17eec503d77769c13ead15d12e8819820b1dc68afe8a3c5bc3250
F test/window9.test 20a6b590be718b6bc98a5356d4396d6cdf19329c547da084fa225b92d68e1693 F test/window9.test 20a6b590be718b6bc98a5356d4396d6cdf19329c547da084fa225b92d68e1693
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0 F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b
@@ -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,8 @@ 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 aff209804722ac902c7abfde80ad2677e0f51beb2c7f28f65d51105d984a1640 P 336235db2b1167cdb2feb64b47eb6368c97c43ee9641b7bfccc5775a41dd0d0e ad816d01d4bd3908ff2c574d79d1a29b6d732df308f2f1b1cdf7c0bc7c1bd7cf
R ab1237ad66e99f2406a94be2d43ffa7b R 5139358becb963924affc3638fcd0d5e
U drh T +closed ad816d01d4bd3908ff2c574d79d1a29b6d732df308f2f1b1cdf7c0bc7c1bd7cf
Z 919069f1dca2ee3915ff3c6a1bd5e156 U dan
Z 534b1b1d3945585b80108a8c2d91a394

View File

@@ -1 +1 @@
336235db2b1167cdb2feb64b47eb6368c97c43ee9641b7bfccc5775a41dd0d0e 94085fb3e756bc984237b74b6e29c68462ad860870c64dcb5124feaeec387660

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,
@@ -3153,6 +3153,27 @@ Index *sqlite3AllocateIndexObject(
return p; return p;
} }
/*
** If expression list pList contains an expression that was parsed with
** an explicit "NULLS FIRST" or "NULLS LAST" clause, leave an error in
** pParse and return non-zero. Otherwise, return zero.
*/
int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){
if( pList ){
int i;
for(i=0; i<pList->nExpr; i++){
if( pList->a[i].bNulls ){
u8 sf = pList->a[i].sortFlags;
sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s",
(sf==0 || sf==3) ? "FIRST" : "LAST"
);
return 1;
}
}
}
return 0;
}
/* /*
** Create a new index for an SQL table. pName1.pName2 is the name of the index ** Create a new index for an SQL table. pName1.pName2 is the name of the index
** and pTblList is the name of the table that is to be indexed. Both will ** and pTblList is the name of the table that is to be indexed. Both will
@@ -3204,6 +3225,9 @@ void sqlite3CreateIndex(
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto exit_create_index; goto exit_create_index;
} }
if( sqlite3HasExplicitNulls(pParse, pList) ){
goto exit_create_index;
}
/* /*
** Find the table that is to be indexed. Return early if not found. ** Find the table that is to be indexed. Return early if not found.
@@ -3368,7 +3392,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, SQLITE_SO_UNDEFINED);
}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 +3510,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 +4728,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

@@ -1409,8 +1409,9 @@ 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->bNulls = pOldItem->bNulls;
pItem->bSpanIsTab = pOldItem->bSpanIsTab; pItem->bSpanIsTab = pOldItem->bSpanIsTab;
pItem->bSorterRef = pOldItem->bSorterRef; pItem->bSorterRef = pOldItem->bSorterRef;
pItem->u = pOldItem->u; pItem->u = pOldItem->u;
@@ -1666,15 +1667,34 @@ 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){
struct ExprList_item *pItem;
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
);
pItem = &p->a[p->nExpr-1];
assert( pItem->bNulls==0 );
if( iSortOrder==SQLITE_SO_UNDEFINED ){
iSortOrder = SQLITE_SO_ASC;
}
pItem->sortFlags = (u8)iSortOrder;
if( eNulls!=SQLITE_SO_UNDEFINED ){
pItem->bNulls = 1;
if( iSortOrder!=eNulls ){
pItem->sortFlags |= KEYINFO_ORDER_BIGNULL;
}
} }
p->a[p->nExpr-1].sortOrder = (u8)iSortOrder;
} }
/* /*
@@ -4935,7 +4955,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

@@ -833,6 +833,9 @@ void sqlite3Insert(
pTab->zName); pTab->zName);
goto insert_cleanup; goto insert_cleanup;
} }
if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){
goto insert_cleanup;
}
pTabList->a[0].iCursor = iDataCur; pTabList->a[0].iCursor = iDataCur;
pUpsert->pUpsertSrc = pTabList; pUpsert->pUpsertSrc = pTabList;
pUpsert->regData = regData; pUpsert->regData = regData;

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;}
@@ -1740,12 +1746,12 @@ filter_clause(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
** are synthesized and do not actually appear in the grammar: ** are synthesized and do not actually appear in the grammar:
*/ */
%token %token
TRUEFALSE /* True or false keyword */
ISNOT /* Combination of IS and NOT */
FUNCTION /* A function invocation */
COLUMN /* Reference to a table column */ COLUMN /* Reference to a table column */
AGG_FUNCTION /* An aggregate function */ AGG_FUNCTION /* An aggregate function */
AGG_COLUMN /* An aggregated column */ AGG_COLUMN /* An aggregated column */
TRUEFALSE /* True or false keyword */
ISNOT /* Combination of IS and NOT */
FUNCTION /* A function invocation */
UMINUS /* Unary minus */ UMINUS /* Unary minus */
UPLUS /* Unary plus */ UPLUS /* Unary plus */
TRUTH /* IS TRUE or IS FALSE or IS NOT TRUE or IS NOT FALSE */ TRUTH /* IS TRUE or IS FALSE or IS NOT TRUE or IS NOT FALSE */

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;
} }
} }
} }
@@ -4402,7 +4402,7 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
ExprList *pEList = pFunc->x.pList; /* Arguments to agg function */ ExprList *pEList = pFunc->x.pList; /* Arguments to agg function */
const char *zFunc; /* Name of aggregate function pFunc */ const char *zFunc; /* Name of aggregate function pFunc */
ExprList *pOrderBy; ExprList *pOrderBy;
u8 sortOrder; u8 sortFlags;
assert( *ppMinMax==0 ); assert( *ppMinMax==0 );
assert( pFunc->op==TK_AGG_FUNCTION ); assert( pFunc->op==TK_AGG_FUNCTION );
@@ -4413,16 +4413,16 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
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;
sortOrder = SQLITE_SO_ASC; sortFlags = KEYINFO_ORDER_BIGNULL;
}else if( sqlite3StrICmp(zFunc, "max")==0 ){ }else if( sqlite3StrICmp(zFunc, "max")==0 ){
eRet = WHERE_ORDERBY_MAX; eRet = WHERE_ORDERBY_MAX;
sortOrder = SQLITE_SO_DESC; sortFlags = KEYINFO_ORDER_DESC;
}else{ }else{
return eRet; return eRet;
} }
*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 = sortFlags;
return eRet; return eRet;
} }

View File

@@ -2138,10 +2138,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.
@@ -2603,11 +2606,12 @@ 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; /* Mask of KEYINFO_ORDER_* flags */
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 */
unsigned bSorterRef :1; /* Defer evaluation until after sorting */ unsigned bSorterRef :1; /* Defer evaluation until after sorting */
unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */
union { union {
struct { struct {
u16 iOrderByCol; /* For ORDER BY, column number in result set */ u16 iOrderByCol; /* For ORDER BY, column number in result set */
@@ -3888,7 +3892,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*);
@@ -4365,6 +4369,7 @@ void sqlite3KeyInfoUnref(KeyInfo*);
KeyInfo *sqlite3KeyInfoRef(KeyInfo*); KeyInfo *sqlite3KeyInfoRef(KeyInfo*);
KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int); KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int);
int sqlite3HasExplicitNulls(Parse*, ExprList*);
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
int sqlite3KeyInfoIsWriteable(KeyInfo*); int sqlite3KeyInfoIsWriteable(KeyInfo*);

View File

@@ -463,6 +463,9 @@ TriggerStep *sqlite3TriggerInsertStep(
pTriggerStep->pIdList = pColumn; pTriggerStep->pIdList = pColumn;
pTriggerStep->pUpsert = pUpsert; pTriggerStep->pUpsert = pUpsert;
pTriggerStep->orconf = orconf; pTriggerStep->orconf = orconf;
if( pUpsert ){
sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget);
}
}else{ }else{
testcase( pColumn ); testcase( pColumn );
sqlite3IdListDelete(db, pColumn); sqlite3IdListDelete(db, pColumn);

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{
@@ -5006,7 +5022,7 @@ void sqlite3VdbePreUpdateHook(
preupdate.keyinfo.db = db; preupdate.keyinfo.db = db;
preupdate.keyinfo.enc = ENC(db); preupdate.keyinfo.enc = ENC(db);
preupdate.keyinfo.nKeyField = pTab->nCol; preupdate.keyinfo.nKeyField = pTab->nCol;
preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder; preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder;
preupdate.iKey1 = iKey1; preupdate.iKey1 = iKey1;
preupdate.iKey2 = iKey2; preupdate.iKey2 = iKey2;
preupdate.pTab = pTab; preupdate.pTab = pTab;

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

@@ -934,6 +934,7 @@ static sqlite3_index_info *allocateIndexInfo(
for(i=0; i<n; i++){ for(i=0; i<n; i++){
Expr *pExpr = pOrderBy->a[i].pExpr; Expr *pExpr = pOrderBy->a[i].pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break; if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
if( pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL ) break;
} }
if( i==n){ if( i==n){
nOrderBy = n; nOrderBy = n;
@@ -1032,7 +1033,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;
@@ -3804,7 +3805,7 @@ static i8 wherePathSatisfiesOrderBy(
*/ */
if( pIndex ){ if( pIndex ){
iColumn = pIndex->aiColumn[j]; iColumn = pIndex->aiColumn[j];
revIdx = pIndex->aSortOrder[j]; revIdx = pIndex->aSortOrder[j] & KEYINFO_ORDER_DESC;
if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID; if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID;
}else{ }else{
iColumn = XN_ROWID; iColumn = XN_ROWID;
@@ -3856,22 +3857,28 @@ static i8 wherePathSatisfiesOrderBy(
/* 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. */
if( revSet ){ if( revSet ){
if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0; if( (rev ^ revIdx)!=(pOrderBy->a[i].sortFlags&KEYINFO_ORDER_DESC) ){
isMatch = 0;
}
}else{ }else{
rev = revIdx ^ pOrderBy->a[i].sortOrder; rev = revIdx ^ (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC);
if( rev ) *pRevMask |= MASKBIT(iLoop); if( rev ) *pRevMask |= MASKBIT(iLoop);
revSet = 1; revSet = 1;
} }
} }
if( isMatch && (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL) ){
if( j==pLoop->u.btree.nEq ){
pLoop->wsFlags |= WHERE_BIGNULL_SORT;
}else{
isMatch = 0;
}
}
if( isMatch ){ if( isMatch ){
if( iColumn==XN_ROWID ){ if( iColumn==XN_ROWID ){
testcase( distinctColumns==0 ); testcase( distinctColumns==0 );
distinctColumns = 1; distinctColumns = 1;
} }
obSat |= MASKBIT(i); obSat |= MASKBIT(i);
if( (wctrlFlags & WHERE_ORDERBY_MIN) && j==pLoop->u.btree.nEq ){
pLoop->wsFlags |= WHERE_MIN_ORDERED;
}
}else{ }else{
/* No match found */ /* No match found */
if( j==0 || j<nKeyCol ){ if( j==0 || j<nKeyCol ){
@@ -5065,6 +5072,7 @@ WhereInfo *sqlite3WhereBegin(
sqlite3VdbeSetP4KeyInfo(pParse, pIx); sqlite3VdbeSetP4KeyInfo(pParse, pIx);
if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0 if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
&& (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0 && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
&& (pLoop->wsFlags & WHERE_BIGNULL_SORT)==0
&& (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
&& pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
){ ){
@@ -5206,6 +5214,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
VdbeCoverageIf(v, pLevel->op==OP_Next); VdbeCoverageIf(v, pLevel->op==OP_Next);
VdbeCoverageIf(v, pLevel->op==OP_Prev); VdbeCoverageIf(v, pLevel->op==OP_Prev);
VdbeCoverageIf(v, pLevel->op==OP_VNext); VdbeCoverageIf(v, pLevel->op==OP_VNext);
if( pLevel->regBignull ){
sqlite3VdbeResolveLabel(v, pLevel->addrBignull);
sqlite3VdbeAddOp2(v, OP_IfNotZero, pLevel->regBignull, pLevel->p2-1);
}
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek); if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
#endif #endif

View File

@@ -71,13 +71,15 @@ struct WhereLevel {
int addrCont; /* Jump here to continue with the next loop cycle */ int addrCont; /* Jump here to continue with the next loop cycle */
int addrFirst; /* First instruction of interior of the loop */ int addrFirst; /* First instruction of interior of the loop */
int addrBody; /* Beginning of the body of this loop */ int addrBody; /* Beginning of the body of this loop */
int regBignull; /* big-null flag reg. True if a NULL-scan is needed */
int addrBignull; /* Jump here for next part of big-null scan */
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */ u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */
int addrLikeRep; /* LIKE range processing address */ int addrLikeRep; /* LIKE range processing address */
#endif #endif
u8 iFrom; /* Which entry in the FROM clause */ u8 iFrom; /* Which entry in the FROM clause */
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
int p1, p2; /* Operands of the opcode used to ends the loop */ int p1, p2; /* Operands of the opcode used to end the loop */
union { /* Information that depends on pWLoop->wsFlags */ union { /* Information that depends on pWLoop->wsFlags */
struct { struct {
int nIn; /* Number of entries in aInLoop[] */ int nIn; /* Number of entries in aInLoop[] */
@@ -586,6 +588,6 @@ void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/ #define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */ #define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */
#define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ #define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */
#define WHERE_MIN_ORDERED 0x00080000 /* Column nEq of index is min() expr */ #define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */
#endif /* !defined(SQLITE_WHEREINT_H) */ #endif /* !defined(SQLITE_WHEREINT_H) */

View File

@@ -1550,31 +1550,12 @@ Bitmask sqlite3WhereCodeOneLoopStart(
u8 bSeekPastNull = 0; /* True to seek past initial nulls */ u8 bSeekPastNull = 0; /* True to seek past initial nulls */
u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */
int omitTable; /* True if we use the index only */ int omitTable; /* True if we use the index only */
int regBignull = 0; /* big-null flag register */
pIdx = pLoop->u.btree.pIndex; pIdx = pLoop->u.btree.pIndex;
iIdxCur = pLevel->iIdxCur; iIdxCur = pLevel->iIdxCur;
assert( nEq>=pLoop->nSkip ); assert( nEq>=pLoop->nSkip );
/* If this loop satisfies a sort order (pOrderBy) request that
** was passed to this function to implement a "SELECT min(x) ..."
** query, then the caller will only allow the loop to run for
** a single iteration. This means that the first row returned
** should not have a NULL value stored in 'x'. If column 'x' is
** the first one after the nEq equality constraints in the index,
** this requires some special handling.
*/
assert( (pWInfo->pOrderBy!=0 && pWInfo->pOrderBy->nExpr==1)
|| (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 );
if( pLoop->wsFlags & WHERE_MIN_ORDERED ){
assert( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN) );
assert( pWInfo->nOBSat );
assert( pIdx->nColumn>nEq );
assert( pLoop->nSkip==0 );
bSeekPastNull = 1;
nExtraReg = 1;
}
/* Find any inequality constraint terms for the start and end /* Find any inequality constraint terms for the start and end
** of the range. ** of the range.
*/ */
@@ -1615,6 +1596,25 @@ Bitmask sqlite3WhereCodeOneLoopStart(
} }
assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
/* If the WHERE_BIGNULL_SORT flag is set, then index column nEq uses
** a non-default "big-null" sort (either ASC NULLS LAST or DESC NULLS
** FIRST). In both cases separate ordered scans are made of those
** index entries for which the column is null and for those for which
** it is not. For an ASC sort, the non-NULL entries are scanned first.
** For DESC, NULL entries are scanned first.
*/
if( (pLoop->wsFlags & (WHERE_TOP_LIMIT|WHERE_BTM_LIMIT))==0
&& (pLoop->wsFlags & WHERE_BIGNULL_SORT)!=0
){
assert( bSeekPastNull==0 && nExtraReg==0 && nBtm==0 && nTop==0 );
assert( pRangeEnd==0 && pRangeStart==0 );
assert( pLoop->nSkip==0 );
nExtraReg = 1;
bSeekPastNull = 1;
pLevel->regBignull = regBignull = ++pParse->nMem;
pLevel->addrBignull = sqlite3VdbeMakeLabel(pParse);
}
/* If we are doing a reverse order scan on an ascending index, or /* If we are doing a reverse order scan on an ascending index, or
** a forward order scan on a descending index, interchange the ** a forward order scan on a descending index, interchange the
** start and end terms (pRangeStart and pRangeEnd). ** start and end terms (pRangeStart and pRangeEnd).
@@ -1637,7 +1637,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( zStartAff && nTop ){ if( zStartAff && nTop ){
zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]); zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]);
} }
addrNxt = pLevel->addrNxt; addrNxt = (regBignull ? pLevel->addrBignull : pLevel->addrNxt);
testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 );
@@ -1671,10 +1671,14 @@ Bitmask sqlite3WhereCodeOneLoopStart(
} }
bSeekPastNull = 0; bSeekPastNull = 0;
}else if( bSeekPastNull ){ }else if( bSeekPastNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
nConstraint++;
startEq = 0; startEq = 0;
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
start_constraints = 1; start_constraints = 1;
nConstraint++;
}else if( regBignull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
start_constraints = 1;
nConstraint++;
} }
codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff);
if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){ if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){
@@ -1685,6 +1689,11 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){ if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur); sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur);
} }
if( regBignull ){
sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull);
VdbeComment((v, "NULL-scan pass ctr"));
}
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
assert( op!=0 ); assert( op!=0 );
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
@@ -1696,23 +1705,21 @@ Bitmask sqlite3WhereCodeOneLoopStart(
VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT );
if( bSeekPastNull && (pLoop->wsFlags & WHERE_TOP_LIMIT)==0 ){ assert( bSeekPastNull==0 || bStopAtNull==0 );
/* If bSeekPastNull is set only to skip past the NULL values for if( regBignull ){
** a query like "SELECT min(a), b FROM t1", then add code so that assert( bSeekPastNull==1 || bStopAtNull==1 );
** if there are no rows with (a IS NOT NULL), then do the seek assert( bSeekPastNull==!bStopAtNull );
** without jumping past NULLs instead. This allows the code in assert( bStopAtNull==startEq );
** select.c to pick a value for "b" in the above query. */
assert( startEq==0 && (op==OP_SeekGT || op==OP_SeekLT) );
assert( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0 && pWInfo->nOBSat>0 );
sqlite3VdbeChangeP2(v, -1, sqlite3VdbeCurrentAddr(v)+1);
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2); sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2);
op = aStartOp[(nConstraint>1)*4 + 2 + bRev];
op = aStartOp[(start_constraints<<2) + (1<<1) + bRev]; sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
assert( op==OP_SeekGE || op==OP_SeekLE ); nConstraint-startEq);
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
VdbeCoverage(v); VdbeCoverage(v);
VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
assert( op==OP_Rewind || op==OP_Last || op==OP_SeekGE || op==OP_SeekLE);
} }
} }
@@ -1745,8 +1752,10 @@ Bitmask sqlite3WhereCodeOneLoopStart(
endEq = 1; endEq = 1;
} }
}else if( bStopAtNull ){ }else if( bStopAtNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); if( regBignull==0 ){
endEq = 0; sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
endEq = 0;
}
nConstraint++; nConstraint++;
} }
sqlite3DbFree(db, zStartAff); sqlite3DbFree(db, zStartAff);
@@ -1757,6 +1766,12 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* Check if the index cursor is past the end of the range. */ /* Check if the index cursor is past the end of the range. */
if( nConstraint ){ if( nConstraint ){
if( regBignull ){
/* Except, skip the end-of-range check while doing the NULL-scan */
sqlite3VdbeAddOp2(v, OP_IfNot, regBignull, sqlite3VdbeCurrentAddr(v)+3);
VdbeComment((v, "If NULL-scan 2nd pass"));
VdbeCoverage(v);
}
op = aEndOp[bRev*2 + endEq]; op = aEndOp[bRev*2 + endEq];
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
@@ -1764,6 +1779,23 @@ Bitmask sqlite3WhereCodeOneLoopStart(
testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
} }
if( regBignull ){
/* During a NULL-scan, check to see if we have reached the end of
** the NULLs */
assert( bSeekPastNull==!bStopAtNull );
assert( bSeekPastNull+bStopAtNull==1 );
assert( nConstraint+bSeekPastNull>0 );
sqlite3VdbeAddOp2(v, OP_If, regBignull, sqlite3VdbeCurrentAddr(v)+2);
VdbeComment((v, "If NULL-scan 1st pass"));
VdbeCoverage(v);
op = aEndOp[bRev*2 + bSeekPastNull];
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
nConstraint+bSeekPastNull);
testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE );
testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
}
if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){ if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 1); sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 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;
@@ -1315,8 +1315,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);
@@ -1876,12 +1876,13 @@ static void windowCodeRangeTest(
int reg2 = sqlite3GetTempReg(pParse); int reg2 = sqlite3GetTempReg(pParse);
int arith = OP_Add; int arith = OP_Add;
int addrGe; int addrGe;
ExprList *pOrderBy = p->pMWin->pOrderBy;
int regString = ++pParse->nMem; int regString = ++pParse->nMem;
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( pOrderBy && pOrderBy->nExpr==1 );
if( p->pMWin->pOrderBy->a[0].sortOrder ){ if( 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;
@@ -1901,6 +1902,28 @@ static void windowCodeRangeTest(
VdbeCoverage(v); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1); sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1);
sqlite3VdbeJumpHere(v, addrGe); sqlite3VdbeJumpHere(v, addrGe);
if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_BIGNULL ){
int addr;
addr = sqlite3VdbeAddOp1(v, OP_NotNull, reg1); VdbeCoverage(v);
switch( op ){
case OP_Ge: sqlite3VdbeAddOp2(v, OP_Goto, 0, lbl); break;
case OP_Gt:
sqlite3VdbeAddOp2(v, OP_NotNull, reg2, lbl);
VdbeCoverage(v);
break;
case OP_Le:
sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl);
VdbeCoverage(v);
break;
default: assert( op==OP_Lt ); /* no-op */
}
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v);
if( op==OP_Gt || op==OP_Ge ){
sqlite3VdbeChangeP2(v, -1, sqlite3VdbeCurrentAddr(v)+1);
}
}
sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le ); assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le );

View File

@@ -200,4 +200,37 @@ do_execsql_test 5.1 {
SELECT MIN(a) FROM t1 WHERE a=123; SELECT MIN(a) FROM t1 WHERE a=123;
} {123} } {123}
#-------------------------------------------------------------------------
# Tests for ticket f8a7060ece.
#
reset_db
do_execsql_test 6.1.0 {
CREATE TABLE t1(a, b, c);
INSERT INTO t1 VALUES(NULL, 1, 'x');
CREATE INDEX i1 ON t1(a);
}
do_execsql_test 6.1.1 {
SELECT min(a), b, c FROM t1 WHERE c='x';
} {{} 1 x}
do_execsql_test 6.1.2 {
INSERT INTO t1 VALUES(1, 2, 'y');
} {}
do_execsql_test 6.1.3 {
SELECT min(a), b, c FROM t1 WHERE c='x';
} {{} 1 x}
do_execsql_test 6.2.0 {
CREATE TABLE t0(c0 UNIQUE, c1);
INSERT INTO t0(c1) VALUES (0);
INSERT INTO t0(c0) VALUES (0);
CREATE VIEW v0(c0, c1) AS
SELECT t0.c1, t0.c0 FROM t0 WHERE CAST(t0.rowid AS INT) = 1;
}
do_execsql_test 6.2.1 {
SELECT c0, c1 FROM v0;
} {0 {}}
do_execsql_test 6.2.2 {
SELECT v0.c0, MIN(v0.c1) FROM v0;
} {0 {}}
finish_test finish_test

242
test/nulls1.test Normal file
View File

@@ -0,0 +1,242 @@
# 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.
#
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 < 3} {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 {} {}}
}
switch $a {
0 {
execsql { CREATE INDEX i1 ON t3(a) }
}
1 {
execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t3(a DESC) }
}
}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE TABLE t2(a, b, c);
CREATE INDEX i2 ON t2(a, b);
INSERT INTO t2 VALUES(1, 1, 1);
INSERT INTO t2 VALUES(1, NULL, 2);
INSERT INTO t2 VALUES(1, NULL, 3);
INSERT INTO t2 VALUES(1, 4, 4);
}
do_execsql_test 2.1 {
SELECT * FROM t2 WHERE a=1 ORDER BY b NULLS LAST
} {
1 1 1 1 4 4 1 {} 2 1 {} 3
}
do_execsql_test 2.2 {
SELECT * FROM t2 WHERE a=1 ORDER BY b DESC NULLS FIRST
} {
1 {} 3
1 {} 2
1 4 4
1 1 1
}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 3.0 {
CREATE TABLE t1(a, b, c, d, UNIQUE (b));
}
foreach {tn sql err} {
1 { CREATE INDEX i1 ON t1(a ASC NULLS LAST) } LAST
2 { CREATE INDEX i1 ON t1(a ASC NULLS FIRST) } FIRST
3 { CREATE INDEX i1 ON t1(a, b ASC NULLS LAST) } LAST
4 { CREATE INDEX i1 ON t1(a, b ASC NULLS FIRST) } FIRST
5 { CREATE INDEX i1 ON t1(a DESC NULLS LAST) } LAST
6 { CREATE INDEX i1 ON t1(a DESC NULLS FIRST) } FIRST
7 { CREATE INDEX i1 ON t1(a, b DESC NULLS LAST) } LAST
8 { CREATE INDEX i1 ON t1(a, b DESC NULLS FIRST) } FIRST
9 { CREATE TABLE t2(a, b, PRIMARY KEY(a DESC, b NULLS FIRST)) } FIRST
10 { CREATE TABLE t2(a, b, UNIQUE(a DESC NULLS FIRST, b)) } FIRST
11 { INSERT INTO t1 VALUES(1, 2, 3, 4)
ON CONFLICT (b DESC NULLS LAST) DO UPDATE SET a = a+1 } LAST
12 {
CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
INSERT INTO t1 VALUES(1, 2, 3, 4)
ON CONFLICT (b DESC NULLS FIRST) DO UPDATE SET a = a+1;
END
} FIRST
} {
do_catchsql_test 3.1.$tn $sql "1 {unsupported use of NULLS $err}"
}
do_execsql_test 3.2 {
CREATE TABLE first(nulls, last);
INSERT INTO first(last, nulls) VALUES(100,200), (300,400), (200,300);
SELECT * FROM first ORDER BY nulls;
} {
200 100
300 200
400 300
}
#-------------------------------------------------------------------------
#
ifcapable vtab {
register_echo_module db
do_execsql_test 4.0 {
CREATE TABLE tx(a INTEGER PRIMARY KEY, b, c);
CREATE INDEX i1 ON tx(b);
INSERT INTO tx VALUES(1, 1, 1);
INSERT INTO tx VALUES(2, NULL, 2);
INSERT INTO tx VALUES(3, 3, 3);
INSERT INTO tx VALUES(4, NULL, 4);
INSERT INTO tx VALUES(5, 5, 5);
CREATE VIRTUAL TABLE te USING echo(tx);
}
do_execsql_test 4.1 {
SELECT * FROM tx ORDER BY b NULLS FIRST;
} {2 {} 2 4 {} 4 1 1 1 3 3 3 5 5 5}
do_execsql_test 4.2 {
SELECT * FROM te ORDER BY b NULLS FIRST;
} {2 {} 2 4 {} 4 1 1 1 3 3 3 5 5 5}
do_execsql_test 4.3 {
SELECT * FROM tx ORDER BY b NULLS LAST;
} {1 1 1 3 3 3 5 5 5 2 {} 2 4 {} 4}
do_execsql_test 4.4 {
SELECT * FROM te ORDER BY b NULLS LAST;
} {1 1 1 3 3 3 5 5 5 2 {} 2 4 {} 4}
}
#-------------------------------------------------------------------------
#
do_execsql_test 5.0 {
CREATE TABLE t4(a, b, c);
INSERT INTO t4 VALUES(1, 1, 11);
INSERT INTO t4 VALUES(1, 2, 12);
INSERT INTO t4 VALUES(1, NULL, 1);
INSERT INTO t4 VALUES(2, NULL, 1);
INSERT INTO t4 VALUES(2, 2, 12);
INSERT INTO t4 VALUES(2, 1, 11);
INSERT INTO t4 VALUES(3, NULL, 1);
INSERT INTO t4 VALUES(3, 2, 12);
INSERT INTO t4 VALUES(3, NULL, 3);
}
do_execsql_test 5.1 {
SELECT * FROM t4 WHERE a IN (1, 2, 3) ORDER BY a, b NULLS LAST
} {
1 1 11 1 2 12 1 {} 1
2 1 11 2 2 12 2 {} 1
3 2 12 3 {} 1 3 {} 3
}
do_execsql_test 5.2 {
CREATE INDEX t4ab ON t4(a, b);
SELECT * FROM t4 WHERE a IN (1, 2, 3) ORDER BY a, b NULLS LAST
} {
1 1 11 1 2 12 1 {} 1
2 1 11 2 2 12 2 {} 1
3 2 12 3 {} 1 3 {} 3
}
do_eqp_test 5.3 {
SELECT * FROM t4 WHERE a IN (1, 2, 3) ORDER BY a, b NULLS LAST
} {
QUERY PLAN
`--SEARCH TABLE t4 USING INDEX t4ab (a=?)
}
do_execsql_test 5.4 {
SELECT * FROM t4 WHERE a IN (1, 2, 3) ORDER BY a DESC, b DESC NULLS FIRST
} {
3 {} 3 3 {} 1 3 2 12
2 {} 1 2 2 12 2 1 11
1 {} 1 1 2 12 1 1 11
}
do_eqp_test 5.5 {
SELECT * FROM t4 WHERE a IN (1, 2, 3) ORDER BY a DESC, b DESC NULLS FIRST
} {
QUERY PLAN
`--SEARCH TABLE t4 USING INDEX t4ab (a=?)
}
#-------------------------------------------------------------------------
#
do_execsql_test 6.0 {
CREATE TABLE t5(a, b, c);
WITH s(i) AS (
VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<200
)
INSERT INTO t5 SELECT i%2, CASE WHEN (i%10)==0 THEN NULL ELSE i END, i FROM s;
}
set res1 [db eval { SELECT a,b FROM t5 WHERE a=1 ORDER BY b NULLS LAST, c }]
set res2 [db eval {
SELECT a,b FROM t5 WHERE a=1 ORDER BY b DESC NULLS FIRST, c DESC
}]
do_execsql_test 6.1.1 {
CREATE INDEX t5ab ON t5(a, b, c);
SELECT a,b FROM t5 WHERE a=1 ORDER BY b NULLS LAST, c;
} $res1
do_eqp_test 6.1.2 {
SELECT a,b FROM t5 WHERE a=1 ORDER BY b NULLS LAST, c;
} {
QUERY PLAN
`--SEARCH TABLE t5 USING COVERING INDEX t5ab (a=?)
}
do_execsql_test 6.2.1 {
SELECT a,b FROM t5 WHERE a=1 ORDER BY b DESC NULLS FIRST, c DESC
} $res2
do_eqp_test 6.2.2 {
SELECT a,b FROM t5 WHERE a=1 ORDER BY b DESC NULLS FIRST, c DESC
} {
QUERY PLAN
`--SEARCH TABLE t5 USING COVERING INDEX t5ab (a=?)
}
finish_test

View File

@@ -70,8 +70,8 @@ proc execsql {sql} {
proc execsql_test {tn sql} { proc execsql_test {tn sql} {
set res [execsql $sql] set res [execsql $sql]
set sql [string map {string_agg group_concat} $sql] set sql [string map {string_agg group_concat} $sql]
set sql [string map [list {NULLS FIRST} {}] $sql] # set sql [string map [list {NULLS FIRST} {}] $sql]
set sql [string map [list {NULLS LAST} {}] $sql] # set sql [string map [list {NULLS LAST} {}] $sql]
puts $::fd "do_execsql_test $tn {" puts $::fd "do_execsql_test $tn {"
puts $::fd " [string trim $sql]" puts $::fd " [string trim $sql]"
puts $::fd "} {$res}" puts $::fd "} {$res}"

View File

@@ -41,54 +41,146 @@ do_execsql_test 1.0 {
do_execsql_test 1.1 { do_execsql_test 1.1 {
SELECT a, sum(b) FROM t3 GROUP BY a ORDER BY 1; SELECT a, sum(b) FROM t3 GROUP BY a ORDER BY 1;
} {0 550 1 460 2 470 3 480 4 490 5 500 6 510 7 520 8 530 9 540} } {0 550 1 460 2 470 3 480 4 490 5 500 6 510 7 520 8 530
9 540}
do_execsql_test 1.2 { do_execsql_test 1.2 {
SELECT a, sum(b) OVER ( SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN CURRENT ROW AND CURRENT ROW ORDER BY a GROUPS BETWEEN CURRENT ROW AND CURRENT ROW
) FROM t3 ORDER BY 1; ) FROM t3 ORDER BY 1;
} {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540} } {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550
0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460
1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470
2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480
3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490
4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500
5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510
6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520
7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530
8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530
9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540
9 540}
do_execsql_test 1.3 { do_execsql_test 1.3 {
SELECT a, sum(b) OVER ( SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN 0 PRECEDING AND 0 FOLLOWING ORDER BY a GROUPS BETWEEN 0 PRECEDING AND 0 FOLLOWING
) FROM t3 ORDER BY 1; ) FROM t3 ORDER BY 1;
} {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540} } {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550
0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460
1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470
2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480
3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490
4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500
5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510
6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520
7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530
8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530
9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540
9 540}
do_execsql_test 1.4 { do_execsql_test 1.4 {
SELECT a, sum(b) OVER ( SELECT a, sum(b) OVER (
ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING
) FROM t3 ORDER BY 1; ) FROM t3 ORDER BY 1;
} {0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590} } {0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480
0 1480 0 1480 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960
1 1960 1 1960 1 1960 1 1960 2 2450 2 2450 2 2450 2 2450
2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 3 2400 3 2400
3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400
4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450
4 2450 4 2450 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500
5 2500 5 2500 5 2500 5 2500 6 2550 6 2550 6 2550 6 2550
6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 7 2600 7 2600
7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600
8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100
8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590
9 1590 9 1590 9 1590 9 1590}
do_execsql_test 1.5 { do_execsql_test 1.5 {
SELECT a, sum(b) OVER ( SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING ORDER BY a RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING
) FROM t3 ORDER BY 1; ) FROM t3 ORDER BY 1;
} {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540} } {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550
0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460
1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470
2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480
3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490
4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500
5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510
6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520
7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530
8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530
9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540
9 540}
do_execsql_test 1.6 { do_execsql_test 1.6 {
SELECT a, sum(b) OVER ( SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 2 PRECEDING AND 2 FOLLOWING ORDER BY a RANGE BETWEEN 2 PRECEDING AND 2 FOLLOWING
) FROM t3 ORDER BY 1; ) FROM t3 ORDER BY 1;
} {0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590} } {0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480
0 1480 0 1480 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960
1 1960 1 1960 1 1960 1 1960 2 2450 2 2450 2 2450 2 2450
2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 3 2400 3 2400
3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400
4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450
4 2450 4 2450 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500
5 2500 5 2500 5 2500 5 2500 6 2550 6 2550 6 2550 6 2550
6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 7 2600 7 2600
7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600
8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100
8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590
9 1590 9 1590 9 1590 9 1590}
do_execsql_test 1.7 { do_execsql_test 1.7 {
SELECT a, sum(b) OVER ( SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 2 PRECEDING AND 1 FOLLOWING ORDER BY a RANGE BETWEEN 2 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1; ) FROM t3 ORDER BY 1;
} {0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590} } {0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010
0 1010 0 1010 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480
1 1480 1 1480 1 1480 1 1480 2 1960 2 1960 2 1960 2 1960
2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 3 1900 3 1900
3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900
4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940
4 1940 4 1940 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980
5 1980 5 1980 5 1980 5 1980 6 2020 6 2020 6 2020 6 2020
6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 7 2060 7 2060
7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060
8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100
8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590
9 1590 9 1590 9 1590 9 1590}
do_execsql_test 1.8.1 { do_execsql_test 1.8.1 {
SELECT a, sum(b) OVER ( SELECT a, sum(b) OVER (
ORDER BY a RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING ORDER BY a RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1; ) FROM t3 ORDER BY 1;
} {0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 1 930 1 930 1 930 1 930 1 930 1 930 1 930 1 930 1 930 1 930 2 950 2 950 2 950 2 950 2 950 2 950 2 950 2 950 2 950 2 950 3 970 3 970 3 970 3 970 3 970 3 970 3 970 3 970 3 970 3 970 4 990 4 990 4 990 4 990 4 990 4 990 4 990 4 990 4 990 4 990 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540} } {0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010
0 1010 0 1010 1 930 1 930 1 930 1 930 1 930 1 930 1 930
1 930 1 930 1 930 2 950 2 950 2 950 2 950 2 950 2 950
2 950 2 950 2 950 2 950 3 970 3 970 3 970 3 970 3 970
3 970 3 970 3 970 3 970 3 970 4 990 4 990 4 990 4 990
4 990 4 990 4 990 4 990 4 990 4 990 5 1010 5 1010 5 1010
5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 6 1030
6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030
6 1030 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050
7 1050 7 1050 7 1050 8 1070 8 1070 8 1070 8 1070 8 1070
8 1070 8 1070 8 1070 8 1070 8 1070 9 540 9 540 9 540 9 540
9 540 9 540 9 540 9 540 9 540 9 540}
do_execsql_test 1.8.2 { do_execsql_test 1.8.2 {
SELECT a, sum(b) OVER ( SELECT a, sum(b) OVER (
ORDER BY a DESC RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING ORDER BY a DESC RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING
) FROM t3 ORDER BY 1; ) FROM t3 ORDER BY 1;
} {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 2 930 2 930 2 930 2 930 2 930 2 930 2 930 2 930 2 930 2 930 3 950 3 950 3 950 3 950 3 950 3 950 3 950 3 950 3 950 3 950 4 970 4 970 4 970 4 970 4 970 4 970 4 970 4 970 4 970 4 970 5 990 5 990 5 990 5 990 5 990 5 990 5 990 5 990 5 990 5 990 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070} } {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550
0 550 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010
1 1010 1 1010 1 1010 2 930 2 930 2 930 2 930 2 930 2 930
2 930 2 930 2 930 2 930 3 950 3 950 3 950 3 950 3 950
3 950 3 950 3 950 3 950 3 950 4 970 4 970 4 970 4 970
4 970 4 970 4 970 4 970 4 970 4 970 5 990 5 990 5 990
5 990 5 990 5 990 5 990 5 990 5 990 5 990 6 1010 6 1010
6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010
7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030
7 1030 7 1030 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050
8 1050 8 1050 8 1050 8 1050 9 1070 9 1070 9 1070 9 1070
9 1070 9 1070 9 1070 9 1070 9 1070 9 1070}
finish_test finish_test

View File

@@ -197,30 +197,55 @@ execsql_test 4.2.1 {
ORDER BY a RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ORDER BY a RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING
) FROM t1 ORDER BY 1 NULLS FIRST; ) FROM t1 ORDER BY 1 NULLS FIRST;
} }
execsql_test 4.2.2 { execsql_test 4.2.2 {
SELECT sum(b) OVER (
ORDER BY a RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING
) FROM t1 ORDER BY 1 NULLS LAST;
}
execsql_test 4.2.3 {
SELECT sum(b) OVER ( SELECT sum(b) OVER (
ORDER BY a DESC RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ORDER BY a DESC RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING
) FROM t1 ORDER BY 1 NULLS FIRST; ) FROM t1 ORDER BY 1 NULLS FIRST;
} }
execsql_test 4.2.4 {
SELECT sum(b) OVER (
ORDER BY a DESC RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING
) FROM t1 ORDER BY 1 NULLS LAST;
}
execsql_test 4.3.1 { execsql_test 4.3.1 {
SELECT sum(b) OVER ( SELECT sum(b) OVER (
ORDER BY a NULLS FIRST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING ORDER BY a NULLS FIRST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING
) FROM t1 ORDER BY 1 NULLS FIRST; ) FROM t1 ORDER BY 1 NULLS FIRST;
} }
execsql_test 4.3.2 {
SELECT sum(b) OVER (
ORDER BY a NULLS LAST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING
) FROM t1 ORDER BY 1 NULLS LAST;
}
execsql_test 4.4.1 { execsql_test 4.4.1 {
SELECT sum(b) OVER ( SELECT sum(b) OVER (
ORDER BY a NULLS FIRST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ORDER BY a NULLS FIRST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) FROM t1 ORDER BY 1 NULLS FIRST; ) FROM t1 ORDER BY 1 NULLS FIRST;
} }
execsql_test 4.4.2 { execsql_test 4.4.2 {
SELECT sum(b) OVER (
ORDER BY a NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) FROM t1 ORDER BY 1 NULLS LAST;
}
execsql_test 4.4.3 {
SELECT sum(b) OVER ( SELECT sum(b) OVER (
ORDER BY a DESC NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ORDER BY a DESC NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) FROM t1 ORDER BY 1 NULLS FIRST; ) FROM t1 ORDER BY 1 NULLS FIRST;
} }
execsql_test 4.4.4 {
SELECT sum(b) OVER (
ORDER BY a DESC NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) FROM t1 ORDER BY 1 NULLS LAST;
}
========== ==========
@@ -248,6 +273,17 @@ foreach {tn ex} {
6 { ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING } 6 { ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING }
7 { ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST 7 { ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING } ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING }
8 { RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING }
9 { ORDER BY a NULLS LAST
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING }
10 { PARTITION BY coalesce(a, '')
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING }
11 { ORDER BY a NULLS LAST GROUPS 6 PRECEDING }
12 { ORDER BY c NULLS LAST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING }
13 { ORDER BY c NULLS LAST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING }
14 { ORDER BY c NULLS LAST, b NULLS LAST, a NULLS LAST
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING }
} { } {
execsql_test 5.$tn.$tn2.1 " execsql_test 5.$tn.$tn2.1 "
SELECT max(c) OVER win, SELECT max(c) OVER win,
@@ -294,6 +330,7 @@ execsql_test 6.2 {
} }
finish_test finish_test

File diff suppressed because it is too large Load Diff

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 },