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

Merge recent trunk changes into sessions.

FossilOrigin-Name: 95e77efe076ab421bd246119c47dba5dacf9d087
This commit is contained in:
drh
2014-04-18 01:10:05 +00:00
27 changed files with 665 additions and 254 deletions

View File

@@ -1,5 +1,5 @@
C Merge\sall\srecent\schanges\sfrom\strunk,\nincluding\sthe\sfix\sfor\sthe\sOP_SCopy-vs-OP_Copy\sproblem. C Merge\srecent\strunk\schanges\sinto\ssessions.
D 2014-04-03T16:35:33.203 D 2014-04-18T01:10:05.240
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in e4ee6d36cdf6136aee0158675a3b24dd3bf31a5a F Makefile.in e4ee6d36cdf6136aee0158675a3b24dd3bf31a5a
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -171,23 +171,23 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494 F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 5d99edbac5bc416032772b723ee30182ee6e5de0 F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1
F src/analyze.c 663e0b291d27eb03c9fd6b421e2d61ba348a2389 F src/analyze.c 663e0b291d27eb03c9fd6b421e2d61ba348a2389
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52 F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c a59a199f21338ae1847d69f5db87c3e8ef1b1578 F src/btree.c 6c9b51abd404ce5b78b173b6f2248e8cb824758c
F src/btree.h 232836cb51753f2e96aa8ce0f052c6df850f76ba F src/btree.h d79306df4ed9181b48916737fe8871a4392c4594
F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4 F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3
F src/build.c 0d50ef95aad63f4c4fc47f3fa2670d4557c45db0 F src/build.c 5bfeea8f302ec2926c9eea321a61daea92a29fa4
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98 F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
F src/delete.c 19df05f1ab55f021605e1c7a3c0a3851876fb3c7 F src/delete.c 50b74c1dde25d1ebcb4fa5c870762e6470ee46f1
F src/expr.c da2b3cb41081af6b56e95e7c9e95949564ce2e21 F src/expr.c 4f9e497c66e2f25a4d139357a778c84d5713207c
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf
F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811 F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811
@@ -200,7 +200,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303 F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
F src/main.c 81453a961f9096bf0eb76a48d82c0f0509d62bf0 F src/main.c a71db3a3c95e4b435644511cea305f28be73673f
F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
@@ -219,24 +219,24 @@ F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c ae4b5240af4619d711301d7992396e182585269f F src/os_unix.c ae4b5240af4619d711301d7992396e182585269f
F src/os_win.c e71678ac927d0a0fb11d993db20a9748eabf808e F src/os_win.c e71678ac927d0a0fb11d993db20a9748eabf808e
F src/pager.c 97a8908bf4e6e7c3adea09d3597cfa48ae33ab4e F src/pager.c ab62a24218d87dda1be641f6c5ad291bff78fd94
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0 F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2 F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
F src/pragma.c 10f169b9650f0930a7a6df67e1387a4c2c449f38 F src/pragma.c 21ece94d4f3e76e8e150deecafb9c7abd398ec67
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337 F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
F src/printf.c e5a0005f8b3de21f85da6a709d2fbee76775bf4b F src/printf.c e5a0005f8b3de21f85da6a709d2fbee76775bf4b
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66 F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be
F src/select.c 269c3e31a450fce642a10569221a49180348c88e F src/select.c 269c3e31a450fce642a10569221a49180348c88e
F src/shell.c 5260f2ada8dd06e9f5ae0a448c8c01e7a75dd881 F src/shell.c 2afe7a7154e97be0c74c5feacf09626bda8493be
F src/sqlite.h.in a31c8b7782a0388b4bd823ed3a3a3e4b93b0cf42 F src/sqlite.h.in 6e6d3e092ca968abb3e65fbe22ec9220a3b616b6
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h 2ce2e12bc5a4cf8e5511ee11ee4778a1911be7e9 F src/sqliteInt.h 8697c8e82d4d2ccbfe7fd2f582081e600c9dc7fc
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -253,7 +253,7 @@ F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8 F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12 F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16 F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
F src/test_config.c b131030783f4328beb7008dbfe7392c7f086abc7 F src/test_config.c b131030783f4328beb7008dbfe7392c7f086abc7
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9 F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
@@ -292,12 +292,12 @@ F src/update.c 7bb549d61efc6853f5cc708c1de6931179f8a12d
F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
F src/vdbe.c 47bdf5f82fa23548bc0ee720c54e3b2b8802babe F src/vdbe.c 9d883d5c91c5e7636cd56e952a0ff567e2d5c119
F src/vdbe.h d03fcf47890ae1c79a335ca994cb878b302697ca F src/vdbe.h d03fcf47890ae1c79a335ca994cb878b302697ca
F src/vdbeInt.h c05d4572211384c560b7579e7a299248cf31d6bd F src/vdbeInt.h c05d4572211384c560b7579e7a299248cf31d6bd
F src/vdbeapi.c d3c662762b62e330a03f29de8e2ac7098ef78030 F src/vdbeapi.c d3c662762b62e330a03f29de8e2ac7098ef78030
F src/vdbeaux.c f9c225c26b4cab6239a7790b4bd14a6cd96ba19e F src/vdbeaux.c e0c2e24ee12c94b6d7cb1c521a0b26cd2e3231d9
F src/vdbeblob.c 2d1f0fdb0f5b72118520980360a594b1c30cbdd8 F src/vdbeblob.c d7c232d1c6afc7ee1176c38b7d81b2e17af15ceb
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447 F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
F src/vdbesort.c 4abb7c0f8f19b7d7d82f4558d5da1a30fdf9ea38 F src/vdbesort.c 4abb7c0f8f19b7d7d82f4558d5da1a30fdf9ea38
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
@@ -305,14 +305,14 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8 F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45 F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
F src/where.c ebad891b7494d0c5f925cf7ab135380bd958cba3 F src/where.c 7614c4383d8b6143558dc349da286d0325704d35
F src/whereInt.h 2564055b440e44ebec8b47f237bbccae6719b7af F src/whereInt.h 2564055b440e44ebec8b47f237bbccae6719b7af
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783 F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
F test/alter.test e88dfa77e020c2b48e52a8020c70171ab828e079 F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060 F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
F test/alter4.test d6c011fa0d6227abba762498cafbb607c9609e93 F test/alter4.test d6c011fa0d6227abba762498cafbb607c9609e93
@@ -588,7 +588,7 @@ F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584
F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057 F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057
F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36 F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test a21814945d32137412b553d98ad2107f9b2173a9 F test/func.test c2cbfc23d554c5bf8678d0fb271aa4f8ef94839c
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test dbccee9133cfef1473c59ec07b5f0262b9d72f9a F test/func3.test dbccee9133cfef1473c59ec07b5f0262b9d72f9a
F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f
@@ -624,7 +624,7 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
F test/index3.test 55a90cff99834305e8141df7afaef39674b57062 F test/index3.test 55a90cff99834305e8141df7afaef39674b57062
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33 F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
F test/index6.test 936979c3a1e87b81feaed2d00505665bf142d764 F test/index6.test a0a2d286ffa6d35813f5003fdb7be124825b4422
F test/index7.test a3baf9a625bda7fd49471e99aeae04095fbfeecf F test/index7.test a3baf9a625bda7fd49471e99aeae04095fbfeecf
F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
@@ -1065,7 +1065,7 @@ F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5 F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test ea8778d5b0df200adef2ca7c00c3c37d4375f772 F test/vtab_shared.test ea8778d5b0df200adef2ca7c00c3c37d4375f772
F test/wal.test 40073e54359d43354925b2b700b7eebd5e207285 F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc
F test/wal2.test a8e3963abf6b232cf0b852b09b53665ef34007af F test/wal2.test a8e3963abf6b232cf0b852b09b53665ef34007af
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0 F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
@@ -1104,10 +1104,11 @@ F test/where9.test 4f3eab951353a3ae164befc521c777dfa903e46c
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62 F test/whereD.test fd9120e262f9da3c45940f52aefeef4d15b904e5
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7 F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
F test/whereG.test 2533b72ed4a31fd1687230a499b557b911525344 F test/whereG.test 2533b72ed4a31fd1687230a499b557b911525344
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
@@ -1174,7 +1175,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P fc8ca1a87e7127bd28f32fd809aec3e24355fbfa d5513dfa23baa0b0a095aaf17d19aacd30dcef61 P 9515c8344a6743bbb0c6a6e49fb79fb3139090df 2c5363873a6f990a0abaacac6303acd46b48befc
R 507e4fb477cf51261d2563e52f7cfa77 R 6f10c61594cf9e1d36bddcd9a9abd40d
U drh U drh
Z a91c37323943563a6d3bfb60a104e003 Z cbe658a5d5d955eb999ebf57e51622f9

View File

@@ -1 +1 @@
9515c8344a6743bbb0c6a6e49fb79fb3139090df 95e77efe076ab421bd246119c47dba5dacf9d087

View File

@@ -116,6 +116,7 @@ static void renameParentFunc(
int token; /* Type of token */ int token; /* Type of token */
UNUSED_PARAMETER(NotUsed); UNUSED_PARAMETER(NotUsed);
if( zInput==0 || zOld==0 ) return;
for(z=zInput; *z; z=z+n){ for(z=zInput; *z; z=z+n){
n = sqlite3GetToken(z, &token); n = sqlite3GetToken(z, &token);
if( token==TK_REFERENCES ){ if( token==TK_REFERENCES ){

View File

@@ -446,16 +446,11 @@ static int cursorHoldsMutex(BtCursor *p){
} }
#endif #endif
#ifndef SQLITE_OMIT_INCRBLOB
/* /*
** Invalidate the overflow page-list cache for cursor pCur, if any. ** Invalidate the overflow cache of the cursor passed as the first argument.
** on the shared btree structure pBt.
*/ */
static void invalidateOverflowCache(BtCursor *pCur){ #define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl)
assert( cursorHoldsMutex(pCur) );
sqlite3_free(pCur->aOverflow);
pCur->aOverflow = 0;
}
/* /*
** Invalidate the overflow page-list cache for all cursors opened ** Invalidate the overflow page-list cache for all cursors opened
@@ -469,6 +464,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
} }
} }
#ifndef SQLITE_OMIT_INCRBLOB
/* /*
** This function is called before modifying the contents of a table ** This function is called before modifying the contents of a table
** to invalidate any incrblob cursors that are open on the ** to invalidate any incrblob cursors that are open on the
@@ -491,16 +487,14 @@ static void invalidateIncrblobCursors(
BtShared *pBt = pBtree->pBt; BtShared *pBt = pBtree->pBt;
assert( sqlite3BtreeHoldsMutex(pBtree) ); assert( sqlite3BtreeHoldsMutex(pBtree) );
for(p=pBt->pCursor; p; p=p->pNext){ for(p=pBt->pCursor; p; p=p->pNext){
if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){ if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){
p->eState = CURSOR_INVALID; p->eState = CURSOR_INVALID;
} }
} }
} }
#else #else
/* Stub functions when INCRBLOB is omitted */ /* Stub function when INCRBLOB is omitted */
#define invalidateOverflowCache(x)
#define invalidateAllOverflowCache(x)
#define invalidateIncrblobCursors(x,y,z) #define invalidateIncrblobCursors(x,y,z)
#endif /* SQLITE_OMIT_INCRBLOB */ #endif /* SQLITE_OMIT_INCRBLOB */
@@ -2563,7 +2557,8 @@ static int countValidCursors(BtShared *pBt, int wrOnly){
BtCursor *pCur; BtCursor *pCur;
int r = 0; int r = 0;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++; if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0)
&& pCur->eState!=CURSOR_FAULT ) r++;
} }
return r; return r;
} }
@@ -3638,7 +3633,8 @@ static int btreeCursor(
pCur->pKeyInfo = pKeyInfo; pCur->pKeyInfo = pKeyInfo;
pCur->pBtree = p; pCur->pBtree = p;
pCur->pBt = pBt; pCur->pBt = pBt;
pCur->wrFlag = (u8)wrFlag; assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
pCur->curFlags = wrFlag;
pCur->pNext = pBt->pCursor; pCur->pNext = pBt->pCursor;
if( pCur->pNext ){ if( pCur->pNext ){
pCur->pNext->pPrev = pCur; pCur->pNext->pPrev = pCur;
@@ -3708,7 +3704,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
releasePage(pCur->apPage[i]); releasePage(pCur->apPage[i]);
} }
unlockBtreeIfUnused(pBt); unlockBtreeIfUnused(pBt);
invalidateOverflowCache(pCur); sqlite3DbFree(pBtree->db, pCur->aOverflow);
/* sqlite3_free(pCur); */ /* sqlite3_free(pCur); */
sqlite3BtreeLeave(pBtree); sqlite3BtreeLeave(pBtree);
} }
@@ -3747,7 +3743,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
if( pCur->info.nSize==0 ){ if( pCur->info.nSize==0 ){
int iPage = pCur->iPage; int iPage = pCur->iPage;
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
pCur->validNKey = 1; pCur->curFlags |= BTCF_ValidNKey;
}else{ }else{
assertCellInfo(pCur); assertCellInfo(pCur);
} }
@@ -3758,7 +3754,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
if( pCur->info.nSize==0 ){ \ if( pCur->info.nSize==0 ){ \
int iPage = pCur->iPage; \ int iPage = pCur->iPage; \
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \ btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
pCur->validNKey = 1; \ pCur->curFlags |= BTCF_ValidNKey; \
}else{ \ }else{ \
assertCellInfo(pCur); \ assertCellInfo(pCur); \
} }
@@ -3929,10 +3925,12 @@ static int copyPayload(
/* /*
** This function is used to read or overwrite payload information ** This function is used to read or overwrite payload information
** for the entry that the pCur cursor is pointing to. If the eOp ** for the entry that the pCur cursor is pointing to. The eOp
** parameter is 0, this is a read operation (data copied into ** argument is interpreted as follows:
** buffer pBuf). If it is non-zero, a write (data copied from **
** buffer pBuf). ** 0: The operation is a read. Populate the overflow cache.
** 1: The operation is a write. Populate the overflow cache.
** 2: The operation is a read. Do not populate the overflow cache.
** **
** A total of "amt" bytes are read or written beginning at "offset". ** A total of "amt" bytes are read or written beginning at "offset".
** Data is read to or from the buffer pBuf. ** Data is read to or from the buffer pBuf.
@@ -3940,11 +3938,11 @@ static int copyPayload(
** The content being read or written might appear on the main page ** The content being read or written might appear on the main page
** or be scattered out on multiple overflow pages. ** or be scattered out on multiple overflow pages.
** **
** If the BtCursor.isIncrblobHandle flag is set, and the current ** If the current cursor entry uses one or more overflow pages and the
** cursor entry uses one or more overflow pages, this function ** eOp argument is not 2, this function may allocate space for and lazily
** allocates space for and lazily popluates the overflow page-list ** popluates the overflow page-list cache array (BtCursor.aOverflow).
** cache array (BtCursor.aOverflow). Subsequent calls use this ** Subsequent calls use this cache to make seeking to the supplied offset
** cache to make seeking to the supplied offset more efficient. ** more efficient.
** **
** Once an overflow page-list cache has been allocated, it may be ** Once an overflow page-list cache has been allocated, it may be
** invalidated if some other cursor writes to the same table, or if ** invalidated if some other cursor writes to the same table, or if
@@ -3968,15 +3966,22 @@ static int accessPayload(
int iIdx = 0; int iIdx = 0;
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
#ifdef SQLITE_DIRECT_OVERFLOW_READ
int bEnd; /* True if reading to end of data */
#endif
assert( pPage ); assert( pPage );
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell ); assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
assert( cursorHoldsMutex(pCur) ); assert( cursorHoldsMutex(pCur) );
assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
getCellInfo(pCur); getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader; aPayload = pCur->info.pCell + pCur->info.nHeader;
nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey); nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
#ifdef SQLITE_DIRECT_OVERFLOW_READ
bEnd = (offset+amt==nKey+pCur->info.nData);
#endif
if( NEVER(offset+amt > nKey+pCur->info.nData) if( NEVER(offset+amt > nKey+pCur->info.nData)
|| &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
@@ -3991,7 +3996,7 @@ static int accessPayload(
if( a+offset>pCur->info.nLocal ){ if( a+offset>pCur->info.nLocal ){
a = pCur->info.nLocal - offset; a = pCur->info.nLocal - offset;
} }
rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage); rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
offset = 0; offset = 0;
pBuf += a; pBuf += a;
amt -= a; amt -= a;
@@ -4005,21 +4010,30 @@ static int accessPayload(
nextPage = get4byte(&aPayload[pCur->info.nLocal]); nextPage = get4byte(&aPayload[pCur->info.nLocal]);
#ifndef SQLITE_OMIT_INCRBLOB /* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
/* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[] ** Except, do not allocate aOverflow[] for eOp==2.
** has not been allocated, allocate it now. The array is sized at **
** one entry for each overflow page in the overflow chain. The ** The aOverflow[] array is sized at one entry for each overflow page
** page number of the first overflow page is stored in aOverflow[0], ** in the overflow chain. The page number of the first overflow page is
** etc. A value of 0 in the aOverflow[] array means "not yet known" ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array
** (the cache is lazily populated). ** means "not yet known" (the cache is lazily populated).
*/ */
if( pCur->isIncrblobHandle && !pCur->aOverflow ){ if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl); if( nOvfl>pCur->nOvflAlloc ){
/* nOvfl is always positive. If it were zero, fetchPayload would have Pgno *aNew = (Pgno*)sqlite3DbRealloc(
** been used instead of this routine. */ pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
if( ALWAYS(nOvfl) && !pCur->aOverflow ){ );
if( aNew==0 ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
}else{
pCur->nOvflAlloc = nOvfl*2;
pCur->aOverflow = aNew;
}
}
if( rc==SQLITE_OK ){
memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
pCur->curFlags |= BTCF_ValidOvfl;
} }
} }
@@ -4027,22 +4041,19 @@ static int accessPayload(
** entry for the first required overflow page is valid, skip ** entry for the first required overflow page is valid, skip
** directly to it. ** directly to it.
*/ */
if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){ if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){
iIdx = (offset/ovflSize); iIdx = (offset/ovflSize);
nextPage = pCur->aOverflow[iIdx]; nextPage = pCur->aOverflow[iIdx];
offset = (offset%ovflSize); offset = (offset%ovflSize);
} }
#endif
for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){ for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
#ifndef SQLITE_OMIT_INCRBLOB
/* If required, populate the overflow page-list cache. */ /* If required, populate the overflow page-list cache. */
if( pCur->aOverflow ){ if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage); assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
pCur->aOverflow[iIdx] = nextPage; pCur->aOverflow[iIdx] = nextPage;
} }
#endif
if( offset>=ovflSize ){ if( offset>=ovflSize ){
/* The only reason to read this page is to obtain the page /* The only reason to read this page is to obtain the page
@@ -4050,13 +4061,17 @@ static int accessPayload(
** data is not required. So first try to lookup the overflow ** data is not required. So first try to lookup the overflow
** page-list cache, if any, then fall back to the getOverflowPage() ** page-list cache, if any, then fall back to the getOverflowPage()
** function. ** function.
**
** Note that the aOverflow[] array must be allocated because eOp!=2
** here. If eOp==2, then offset==0 and this branch is never taken.
*/ */
#ifndef SQLITE_OMIT_INCRBLOB assert( eOp!=2 );
if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){ assert( pCur->curFlags & BTCF_ValidOvfl );
if( pCur->aOverflow[iIdx+1] ){
nextPage = pCur->aOverflow[iIdx+1]; nextPage = pCur->aOverflow[iIdx+1];
} else }else{
#endif
rc = getOverflowPage(pBt, nextPage, 0, &nextPage); rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
}
offset -= ovflSize; offset -= ovflSize;
}else{ }else{
/* Need to read this page properly. It contains some of the /* Need to read this page properly. It contains some of the
@@ -4078,13 +4093,15 @@ static int accessPayload(
** 3) the database is file-backed, and ** 3) the database is file-backed, and
** 4) there is no open write-transaction, and ** 4) there is no open write-transaction, and
** 5) the database is not a WAL database, ** 5) the database is not a WAL database,
** 6) all data from the page is being read.
** **
** then data can be read directly from the database file into the ** then data can be read directly from the database file into the
** output buffer, bypassing the page-cache altogether. This speeds ** output buffer, bypassing the page-cache altogether. This speeds
** up loading large records that span many overflow pages. ** up loading large records that span many overflow pages.
*/ */
if( eOp==0 /* (1) */ if( (eOp&0x01)==0 /* (1) */
&& offset==0 /* (2) */ && offset==0 /* (2) */
&& (bEnd || a==ovflSize) /* (6) */
&& pBt->inTransaction==TRANS_READ /* (4) */ && pBt->inTransaction==TRANS_READ /* (4) */
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */ && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
&& pBt->pPage1->aData[19]==0x01 /* (5) */ && pBt->pPage1->aData[19]==0x01 /* (5) */
@@ -4101,12 +4118,12 @@ static int accessPayload(
{ {
DbPage *pDbPage; DbPage *pDbPage;
rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage, rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
(eOp==0 ? PAGER_GET_READONLY : 0) ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
); );
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
aPayload = sqlite3PagerGetData(pDbPage); aPayload = sqlite3PagerGetData(pDbPage);
nextPage = get4byte(aPayload); nextPage = get4byte(aPayload);
rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
sqlite3PagerUnref(pDbPage); sqlite3PagerUnref(pDbPage);
offset = 0; offset = 0;
} }
@@ -4257,14 +4274,14 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
rc = getAndInitPage(pBt, newPgno, &pNewPage, rc = getAndInitPage(pBt, newPgno, &pNewPage,
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0); (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
if( rc ) return rc; if( rc ) return rc;
pCur->apPage[i+1] = pNewPage; pCur->apPage[i+1] = pNewPage;
pCur->aiIdx[i+1] = 0; pCur->aiIdx[i+1] = 0;
pCur->iPage++; pCur->iPage++;
pCur->info.nSize = 0; pCur->info.nSize = 0;
pCur->validNKey = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){ if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
@@ -4322,7 +4339,7 @@ static void moveToParent(BtCursor *pCur){
releasePage(pCur->apPage[pCur->iPage]); releasePage(pCur->apPage[pCur->iPage]);
pCur->iPage--; pCur->iPage--;
pCur->info.nSize = 0; pCur->info.nSize = 0;
pCur->validNKey = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
} }
/* /*
@@ -4369,7 +4386,7 @@ static int moveToRoot(BtCursor *pCur){
return SQLITE_OK; return SQLITE_OK;
}else{ }else{
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0], rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0); (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID; pCur->eState = CURSOR_INVALID;
return rc; return rc;
@@ -4396,8 +4413,7 @@ static int moveToRoot(BtCursor *pCur){
pCur->aiIdx[0] = 0; pCur->aiIdx[0] = 0;
pCur->info.nSize = 0; pCur->info.nSize = 0;
pCur->atLast = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
pCur->validNKey = 0;
if( pRoot->nCell>0 ){ if( pRoot->nCell>0 ){
pCur->eState = CURSOR_VALID; pCur->eState = CURSOR_VALID;
@@ -4460,7 +4476,7 @@ static int moveToRightmost(BtCursor *pCur){
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pCur->aiIdx[pCur->iPage] = pPage->nCell-1; pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
pCur->info.nSize = 0; pCur->info.nSize = 0;
pCur->validNKey = 0; pCur->curFlags &= ~BTCF_ValidNKey;
} }
return rc; return rc;
} }
@@ -4499,7 +4515,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
/* If the cursor already points to the last entry, this is a no-op. */ /* If the cursor already points to the last entry, this is a no-op. */
if( CURSOR_VALID==pCur->eState && pCur->atLast ){ if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
/* This block serves to assert() that the cursor really does point /* This block serves to assert() that the cursor really does point
** to the last entry in the b-tree. */ ** to the last entry in the b-tree. */
@@ -4522,7 +4538,12 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
*pRes = 0; *pRes = 0;
rc = moveToRightmost(pCur); rc = moveToRightmost(pCur);
pCur->atLast = rc==SQLITE_OK ?1:0; if( rc==SQLITE_OK ){
pCur->curFlags |= BTCF_AtLast;
}else{
pCur->curFlags &= ~BTCF_AtLast;
}
} }
} }
return rc; return rc;
@@ -4573,14 +4594,14 @@ int sqlite3BtreeMovetoUnpacked(
/* If the cursor is already positioned at the point we are trying /* If the cursor is already positioned at the point we are trying
** to move to, then just return without doing any work */ ** to move to, then just return without doing any work */
if( pCur->eState==CURSOR_VALID && pCur->validNKey if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
&& pCur->apPage[0]->intKey && pCur->apPage[0]->intKey
){ ){
if( pCur->info.nKey==intKey ){ if( pCur->info.nKey==intKey ){
*pRes = 0; *pRes = 0;
return SQLITE_OK; return SQLITE_OK;
} }
if( pCur->atLast && pCur->info.nKey<intKey ){ if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
*pRes = -1; *pRes = -1;
return SQLITE_OK; return SQLITE_OK;
} }
@@ -4647,7 +4668,7 @@ int sqlite3BtreeMovetoUnpacked(
if( lwr>upr ){ c = +1; break; } if( lwr>upr ){ c = +1; break; }
}else{ }else{
assert( nCellKey==intKey ); assert( nCellKey==intKey );
pCur->validNKey = 1; pCur->curFlags |= BTCF_ValidNKey;
pCur->info.nKey = nCellKey; pCur->info.nKey = nCellKey;
pCur->aiIdx[pCur->iPage] = (u16)idx; pCur->aiIdx[pCur->iPage] = (u16)idx;
if( !pPage->leaf ){ if( !pPage->leaf ){
@@ -4704,7 +4725,7 @@ int sqlite3BtreeMovetoUnpacked(
goto moveto_finish; goto moveto_finish;
} }
pCur->aiIdx[pCur->iPage] = (u16)idx; pCur->aiIdx[pCur->iPage] = (u16)idx;
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
if( rc ){ if( rc ){
sqlite3_free(pCellKey); sqlite3_free(pCellKey);
goto moveto_finish; goto moveto_finish;
@@ -4751,7 +4772,7 @@ moveto_next_layer:
} }
moveto_finish: moveto_finish:
pCur->info.nSize = 0; pCur->info.nSize = 0;
pCur->validNKey = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
return rc; return rc;
} }
@@ -4796,6 +4817,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
assert( *pRes==0 || *pRes==1 ); assert( *pRes==0 || *pRes==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
if( pCur->eState!=CURSOR_VALID ){ if( pCur->eState!=CURSOR_VALID ){
invalidateOverflowCache(pCur);
rc = restoreCursorPosition(pCur); rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
*pRes = 0; *pRes = 0;
@@ -4829,7 +4851,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
testcase( idx>pPage->nCell ); testcase( idx>pPage->nCell );
pCur->info.nSize = 0; pCur->info.nSize = 0;
pCur->validNKey = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
if( idx>=pPage->nCell ){ if( idx>=pPage->nCell ){
if( !pPage->leaf ){ if( !pPage->leaf ){
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
@@ -4890,7 +4912,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
assert( pRes!=0 ); assert( pRes!=0 );
assert( *pRes==0 || *pRes==1 ); assert( *pRes==0 || *pRes==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
pCur->atLast = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl);
if( pCur->eState!=CURSOR_VALID ){ if( pCur->eState!=CURSOR_VALID ){
if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){ if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
rc = btreeRestoreCursorPosition(pCur); rc = btreeRestoreCursorPosition(pCur);
@@ -4935,7 +4957,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
moveToParent(pCur); moveToParent(pCur);
} }
pCur->info.nSize = 0; pCur->info.nSize = 0;
pCur->validNKey = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
pCur->aiIdx[pCur->iPage]--; pCur->aiIdx[pCur->iPage]--;
pPage = pCur->apPage[pCur->iPage]; pPage = pCur->apPage[pCur->iPage];
@@ -6960,7 +6982,7 @@ int sqlite3BtreeInsert(
} }
assert( cursorHoldsMutex(pCur) ); assert( cursorHoldsMutex(pCur) );
assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE
&& (pBt->btsFlags & BTS_READ_ONLY)==0 ); && (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
@@ -6993,7 +7015,7 @@ int sqlite3BtreeInsert(
/* If the cursor is currently on the last row and we are appending a /* If the cursor is currently on the last row and we are appending a
** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto() ** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
** call */ ** call */
if( pCur->validNKey && nKey>0 && pCur->info.nKey==nKey-1 ){ if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){
loc = -1; loc = -1;
} }
} }
@@ -7046,7 +7068,7 @@ int sqlite3BtreeInsert(
/* If no error has occurred and pPage has an overflow cell, call balance() /* If no error has occurred and pPage has an overflow cell, call balance()
** to redistribute the cells within the tree. Since balance() may move ** to redistribute the cells within the tree. Since balance() may move
** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
** variables. ** variables.
** **
** Previous versions of SQLite called moveToRoot() to move the cursor ** Previous versions of SQLite called moveToRoot() to move the cursor
@@ -7066,7 +7088,7 @@ int sqlite3BtreeInsert(
*/ */
pCur->info.nSize = 0; pCur->info.nSize = 0;
if( rc==SQLITE_OK && pPage->nOverflow ){ if( rc==SQLITE_OK && pPage->nOverflow ){
pCur->validNKey = 0; pCur->curFlags &= ~(BTCF_ValidNKey);
rc = balance(pCur); rc = balance(pCur);
/* Must make sure nOverflow is reset to zero even if the balance() /* Must make sure nOverflow is reset to zero even if the balance()
@@ -7098,7 +7120,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) ); assert( cursorHoldsMutex(pCur) );
assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->inTransaction==TRANS_WRITE );
assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( pCur->wrFlag ); assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) );
@@ -8411,7 +8433,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
int rc; int rc;
assert( cursorHoldsMutex(pCsr) ); assert( cursorHoldsMutex(pCsr) );
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
assert( pCsr->isIncrblobHandle ); assert( pCsr->curFlags & BTCF_Incrblob );
rc = restoreCursorPosition(pCsr); rc = restoreCursorPosition(pCsr);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@@ -8440,7 +8462,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
** (d) there are no conflicting read-locks, and ** (d) there are no conflicting read-locks, and
** (e) the cursor points at a valid row of an intKey table. ** (e) the cursor points at a valid row of an intKey table.
*/ */
if( !pCsr->wrFlag ){ if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){
return SQLITE_READONLY; return SQLITE_READONLY;
} }
assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0 assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
@@ -8453,20 +8475,10 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
} }
/* /*
** Set a flag on this cursor to cache the locations of pages from the ** Mark this cursor as an incremental blob cursor.
** overflow list for the current row. This is used by cursors opened
** for incremental blob IO only.
**
** This function sets a flag only. The actual page location cache
** (stored in BtCursor.aOverflow[]) is allocated and used by function
** accessPayload() (the worker function for sqlite3BtreeData() and
** sqlite3BtreePutData()).
*/ */
void sqlite3BtreeCacheOverflow(BtCursor *pCur){ void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) ); pCur->curFlags |= BTCF_Incrblob;
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
invalidateOverflowCache(pCur);
pCur->isIncrblobHandle = 1;
} }
#endif #endif

View File

@@ -190,7 +190,7 @@ char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*); struct Pager *sqlite3BtreePager(Btree*);
int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeCacheOverflow(BtCursor *); void sqlite3BtreeIncrblobCursor(BtCursor *);
void sqlite3BtreeClearCursor(BtCursor *); void sqlite3BtreeClearCursor(BtCursor *);
int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask); void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);

View File

@@ -496,27 +496,30 @@ struct BtCursor {
BtShared *pBt; /* The BtShared this cursor points to */ BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */ struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
#ifndef SQLITE_OMIT_INCRBLOB
Pgno *aOverflow; /* Cache of overflow page locations */ Pgno *aOverflow; /* Cache of overflow page locations */
#endif
Pgno pgnoRoot; /* The root page of this tree */
CellInfo info; /* A parse of the cell we are pointing at */ CellInfo info; /* A parse of the cell we are pointing at */
i64 nKey; /* Size of pKey, or last integer key */ i64 nKey; /* Size of pKey, or last integer key */
void *pKey; /* Saved key that was cursor's last known position */ void *pKey; /* Saved key that was cursor last known position */
Pgno pgnoRoot; /* The root page of this tree */
int nOvflAlloc; /* Allocated size of aOverflow[] array */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */ int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
u8 wrFlag; /* True if writable */ u8 curFlags; /* zero or more BTCF_* flags defined below */
u8 atLast; /* Cursor pointing to the last entry */
u8 validNKey; /* True if info.nKey is valid */
u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 eState; /* One of the CURSOR_XXX constants (see below) */
#ifndef SQLITE_OMIT_INCRBLOB
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
#endif
u8 hints; /* As configured by CursorSetHints() */ u8 hints; /* As configured by CursorSetHints() */
i16 iPage; /* Index of current page in apPage */ i16 iPage; /* Index of current page in apPage */
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */ u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
}; };
/*
** Legal values for BtCursor.curFlags
*/
#define BTCF_WriteFlag 0x01 /* True if a write cursor */
#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
/* /*
** Potential values for BtCursor.eState. ** Potential values for BtCursor.eState.
** **

View File

@@ -2680,7 +2680,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
sqlite3VdbeResolveLabel(v, iPartIdxLabel); sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeJumpHere(v, addr1);
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);

View File

@@ -751,7 +751,7 @@ void sqlite3GenerateRowIndexDelete(
&iPartIdxLabel, pPrior, r1); &iPartIdxLabel, pPrior, r1);
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
sqlite3VdbeResolveLabel(v, iPartIdxLabel); sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
pPrior = pIdx; pPrior = pIdx;
} }
} }
@@ -770,10 +770,11 @@ void sqlite3GenerateRowIndexDelete(
** **
** If *piPartIdxLabel is not NULL, fill it in with a label and jump ** If *piPartIdxLabel is not NULL, fill it in with a label and jump
** to that label if pIdx is a partial index that should be skipped. ** to that label if pIdx is a partial index that should be skipped.
** The label should be resolved using sqlite3ResolvePartIdxLabel().
** A partial index should be skipped if its WHERE clause evaluates ** A partial index should be skipped if its WHERE clause evaluates
** to false or null. If pIdx is not a partial index, *piPartIdxLabel ** to false or null. If pIdx is not a partial index, *piPartIdxLabel
** will be set to zero which is an empty label that is ignored by ** will be set to zero which is an empty label that is ignored by
** sqlite3VdbeResolveLabel(). ** sqlite3ResolvePartIdxLabel().
** **
** The pPrior and regPrior parameters are used to implement a cache to ** The pPrior and regPrior parameters are used to implement a cache to
** avoid unnecessary register loads. If pPrior is not NULL, then it is ** avoid unnecessary register loads. If pPrior is not NULL, then it is
@@ -806,6 +807,7 @@ int sqlite3GenerateIndexKey(
if( pIdx->pPartIdxWhere ){ if( pIdx->pPartIdxWhere ){
*piPartIdxLabel = sqlite3VdbeMakeLabel(v); *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
pParse->iPartIdxTab = iDataCur; pParse->iPartIdxTab = iDataCur;
sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL); SQLITE_JUMPIFNULL);
}else{ }else{
@@ -833,3 +835,15 @@ int sqlite3GenerateIndexKey(
sqlite3ReleaseTempRange(pParse, regBase, nCol); sqlite3ReleaseTempRange(pParse, regBase, nCol);
return regBase; return regBase;
} }
/*
** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label
** because it was a partial index, then this routine should be called to
** resolve that label.
*/
void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
if( iLabel ){
sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel);
sqlite3ExprCachePop(pParse);
}
}

View File

@@ -1883,7 +1883,7 @@ int sqlite3CodeSubselect(
if( testAddr>=0 ){ if( testAddr>=0 ){
sqlite3VdbeJumpHere(v, testAddr); sqlite3VdbeJumpHere(v, testAddr);
} }
sqlite3ExprCachePop(pParse, 1); sqlite3ExprCachePop(pParse);
return rReg; return rReg;
} }
@@ -2018,7 +2018,7 @@ static void sqlite3ExprCodeIN(
} }
} }
sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r1);
sqlite3ExprCachePop(pParse, 1); sqlite3ExprCachePop(pParse);
VdbeComment((v, "end IN expr")); VdbeComment((v, "end IN expr"));
} }
#endif /* SQLITE_OMIT_SUBQUERY */ #endif /* SQLITE_OMIT_SUBQUERY */
@@ -2201,15 +2201,14 @@ void sqlite3ExprCachePush(Parse *pParse){
/* /*
** Remove from the column cache any entries that were added since the ** Remove from the column cache any entries that were added since the
** the previous N Push operations. In other words, restore the cache ** the previous sqlite3ExprCachePush operation. In other words, restore
** to the state it was in N Pushes ago. ** the cache to the state it was in prior the most recent Push.
*/ */
void sqlite3ExprCachePop(Parse *pParse, int N){ void sqlite3ExprCachePop(Parse *pParse){
int i; int i;
struct yColCache *p; struct yColCache *p;
assert( N>0 ); assert( pParse->iCacheLevel>=1 );
assert( pParse->iCacheLevel>=N ); pParse->iCacheLevel--;
pParse->iCacheLevel -= N;
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
printf("POP to %d\n", pParse->iCacheLevel); printf("POP to %d\n", pParse->iCacheLevel);
@@ -2687,7 +2686,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
sqlite3ExprCacheRemove(pParse, target, 1); sqlite3ExprCacheRemove(pParse, target, 1);
sqlite3ExprCachePush(pParse); sqlite3ExprCachePush(pParse);
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target); sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
sqlite3ExprCachePop(pParse, 1); sqlite3ExprCachePop(pParse);
} }
sqlite3VdbeResolveLabel(v, endCoalesce); sqlite3VdbeResolveLabel(v, endCoalesce);
break; break;
@@ -2741,7 +2740,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */ sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
sqlite3ExprCodeExprList(pParse, pFarg, r1, sqlite3ExprCodeExprList(pParse, pFarg, r1,
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR); SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */ sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */
}else{ }else{
r1 = 0; r1 = 0;
} }
@@ -2961,13 +2960,13 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel); sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
sqlite3ExprCachePop(pParse, 1); sqlite3ExprCachePop(pParse);
sqlite3VdbeResolveLabel(v, nextCase); sqlite3VdbeResolveLabel(v, nextCase);
} }
if( (nExpr&1)!=0 ){ if( (nExpr&1)!=0 ){
sqlite3ExprCachePush(pParse); sqlite3ExprCachePush(pParse);
sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
sqlite3ExprCachePop(pParse, 1); sqlite3ExprCachePop(pParse);
}else{ }else{
sqlite3VdbeAddOp2(v, OP_Null, 0, target); sqlite3VdbeAddOp2(v, OP_Null, 0, target);
} }
@@ -3546,7 +3545,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
sqlite3ExprCachePush(pParse); sqlite3ExprCachePush(pParse);
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3VdbeResolveLabel(v, d2); sqlite3VdbeResolveLabel(v, d2);
sqlite3ExprCachePop(pParse, 1); sqlite3ExprCachePop(pParse);
break; break;
} }
case TK_OR: { case TK_OR: {
@@ -3554,7 +3553,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
sqlite3ExprCachePush(pParse); sqlite3ExprCachePush(pParse);
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3ExprCachePop(pParse, 1); sqlite3ExprCachePop(pParse);
break; break;
} }
case TK_NOT: { case TK_NOT: {
@@ -3700,7 +3699,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
sqlite3ExprCachePush(pParse); sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3ExprCachePop(pParse, 1); sqlite3ExprCachePop(pParse);
break; break;
} }
case TK_OR: { case TK_OR: {
@@ -3710,7 +3709,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
sqlite3ExprCachePush(pParse); sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3VdbeResolveLabel(v, d2); sqlite3VdbeResolveLabel(v, d2);
sqlite3ExprCachePop(pParse, 1); sqlite3ExprCachePop(pParse);
break; break;
} }
case TK_NOT: { case TK_NOT: {

View File

@@ -3226,6 +3226,22 @@ int sqlite3_test_control(int op, ...){
break; break;
} }
/*
** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER);
**
** The integer returned reveals the byte-order of the computer on which
** SQLite is running:
**
** 1 big-endian, determined at run-time
** 10 little-endian, determined at run-time
** 432101 big-endian, determined at compile-time
** 123410 little-endian, determined at compile-time
*/
case SQLITE_TESTCTRL_BYTEORDER: {
rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN;
break;
}
/* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N) /* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
** **
** Set the nReserve size to N for the main database on the database ** Set the nReserve size to N for the main database on the database

View File

@@ -1624,12 +1624,11 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
if( !zMaster if( !zMaster
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| pPager->journalMode==PAGER_JOURNALMODE_OFF || !isOpen(pPager->jfd)
){ ){
return SQLITE_OK; return SQLITE_OK;
} }
pPager->setMaster = 1; pPager->setMaster = 1;
assert( isOpen(pPager->jfd) );
assert( pPager->journalHdr <= pPager->journalOff ); assert( pPager->journalHdr <= pPager->journalOff );
/* Calculate the length in bytes and the checksum of zMaster */ /* Calculate the length in bytes and the checksum of zMaster */

View File

@@ -1928,7 +1928,7 @@ void sqlite3Pragma(
sqlite3VdbeAddOp0(v, OP_Halt); sqlite3VdbeAddOp0(v, OP_Halt);
sqlite3VdbeJumpHere(v, jmp4); sqlite3VdbeJumpHere(v, jmp4);
sqlite3VdbeJumpHere(v, jmp2); sqlite3VdbeJumpHere(v, jmp2);
sqlite3VdbeResolveLabel(v, jmp3); sqlite3ResolvePartIdxLabel(pParse, jmp3);
} }
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1); sqlite3VdbeJumpHere(v, loopTop-1);

View File

@@ -112,8 +112,8 @@ struct RowSet {
struct RowSetEntry *pFresh; /* Source of new entry objects */ struct RowSetEntry *pFresh; /* Source of new entry objects */
struct RowSetEntry *pForest; /* List of binary trees of entries */ struct RowSetEntry *pForest; /* List of binary trees of entries */
u16 nFresh; /* Number of objects on pFresh */ u16 nFresh; /* Number of objects on pFresh */
u8 rsFlags; /* Various flags */ u16 rsFlags; /* Various flags */
u8 iBatch; /* Current insert batch */ int iBatch; /* Current insert batch */
}; };
/* /*
@@ -447,7 +447,7 @@ int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
** on pRowSet->pEntry, then sort those entires into the forest at ** on pRowSet->pEntry, then sort those entires into the forest at
** pRowSet->pForest so that they can be tested. ** pRowSet->pForest so that they can be tested.
*/ */
int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){ int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
struct RowSetEntry *p, *pTree; struct RowSetEntry *p, *pTree;
/* This routine is never called after sqlite3RowSetNext() */ /* This routine is never called after sqlite3RowSetNext() */

View File

@@ -3027,6 +3027,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS }, { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD }, { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC }, { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
}; };
int testctrl = -1; int testctrl = -1;
int rc = 0; int rc = 0;
@@ -3070,6 +3071,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
case SQLITE_TESTCTRL_PRNG_SAVE: case SQLITE_TESTCTRL_PRNG_SAVE:
case SQLITE_TESTCTRL_PRNG_RESTORE: case SQLITE_TESTCTRL_PRNG_RESTORE:
case SQLITE_TESTCTRL_PRNG_RESET: case SQLITE_TESTCTRL_PRNG_RESET:
case SQLITE_TESTCTRL_BYTEORDER:
if( nArg==2 ){ if( nArg==2 ){
rc = sqlite3_test_control(testctrl); rc = sqlite3_test_control(testctrl);
fprintf(p->out, "%d (0x%08x)\n", rc, rc); fprintf(p->out, "%d (0x%08x)\n", rc, rc);

View File

@@ -6118,7 +6118,8 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_LAST 21 #define SQLITE_TESTCTRL_BYTEORDER 22
#define SQLITE_TESTCTRL_LAST 22
/* /*
** CAPI3REF: SQLite Runtime Status ** CAPI3REF: SQLite Runtime Status

View File

@@ -546,19 +546,36 @@ typedef INT16_TYPE LogEst;
/* /*
** Macros to determine whether the machine is big or little endian, ** Macros to determine whether the machine is big or little endian,
** evaluated at runtime. ** and whether or not that determination is run-time or compile-time.
**
** For best performance, an attempt is made to guess at the byte-order
** using C-preprocessor macros. If that is unsuccessful, or if
** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
** at run-time.
*/ */
#ifdef SQLITE_AMALGAMATION #ifdef SQLITE_AMALGAMATION
const int sqlite3one = 1; const int sqlite3one = 1;
#else #else
extern const int sqlite3one; extern const int sqlite3one;
#endif #endif
#if defined(i386) || defined(__i386__) || defined(_M_IX86)\ #if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \
|| defined(__x86_64) || defined(__x86_64__) defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER)
# define SQLITE_BYTEORDER 1234
# define SQLITE_BIGENDIAN 0 # define SQLITE_BIGENDIAN 0
# define SQLITE_LITTLEENDIAN 1 # define SQLITE_LITTLEENDIAN 1
# define SQLITE_UTF16NATIVE SQLITE_UTF16LE # define SQLITE_UTF16NATIVE SQLITE_UTF16LE
#else #endif
#if (defined(sparc) || defined(__ppc__)) \
&& !defined(SQLITE_RUNTIME_BYTEORDER)
# define SQLITE_BYTEORDER 4321
# define SQLITE_BIGENDIAN 1
# define SQLITE_LITTLEENDIAN 0
# define SQLITE_UTF16NATIVE SQLITE_UTF16BE
#endif
#if !defined(SQLITE_BYTEORDER)
# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0) # define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1) # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) # define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
@@ -3031,7 +3048,7 @@ int sqlite3BitvecBuiltinTest(int,int*);
RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
void sqlite3RowSetClear(RowSet*); void sqlite3RowSetClear(RowSet*);
void sqlite3RowSetInsert(RowSet*, i64); void sqlite3RowSetInsert(RowSet*, i64);
int sqlite3RowSetTest(RowSet*, u8 iBatch, i64); int sqlite3RowSetTest(RowSet*, int iBatch, i64);
int sqlite3RowSetNext(RowSet*, i64*); int sqlite3RowSetNext(RowSet*, i64*);
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
@@ -3095,7 +3112,7 @@ void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int);
void sqlite3ExprCacheStore(Parse*, int, int, int); void sqlite3ExprCacheStore(Parse*, int, int, int);
void sqlite3ExprCachePush(Parse*); void sqlite3ExprCachePush(Parse*);
void sqlite3ExprCachePop(Parse*, int); void sqlite3ExprCachePop(Parse*);
void sqlite3ExprCacheRemove(Parse*, int, int); void sqlite3ExprCacheRemove(Parse*, int, int);
void sqlite3ExprCacheClear(Parse*); void sqlite3ExprCacheClear(Parse*);
void sqlite3ExprCacheAffinityChange(Parse*, int, int); void sqlite3ExprCacheAffinityChange(Parse*, int, int);
@@ -3147,6 +3164,7 @@ int sqlite3IsRowid(const char*);
void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8); void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
void sqlite3ResolvePartIdxLabel(Parse*,int);
void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
u8,u8,int,int*); u8,u8,int,int*);
void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);

View File

@@ -51,7 +51,7 @@ void sqlite3BtreeCursorList(Btree *p){
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
MemPage *pPage = pCur->apPage[pCur->iPage]; MemPage *pPage = pCur->apPage[pCur->iPage];
char *zMode = pCur->wrFlag ? "rw" : "ro"; char *zMode = (pCur->curFlags & BTCF_WriteFlag) ? "rw" : "ro";
sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n", sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n",
pCur, pCur->pgnoRoot, zMode, pCur, pCur->pgnoRoot, zMode,
pPage ? pPage->pgno : 0, pCur->aiIdx[pCur->iPage], pPage ? pPage->pgno : 0, pCur->aiIdx[pCur->iPage],

View File

@@ -5288,9 +5288,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
assert( pOp->p4type==P4_INT32 ); assert( pOp->p4type==P4_INT32 );
assert( iSet==-1 || iSet>=0 ); assert( iSet==-1 || iSet>=0 );
if( iSet ){ if( iSet ){
exists = sqlite3RowSetTest(pIn1->u.pRowSet, exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i);
(u8)(iSet>=0 ? iSet & 0xf : 0xff),
pIn3->u.i);
VdbeBranchTaken(exists!=0,2); VdbeBranchTaken(exists!=0,2);
if( exists ){ if( exists ){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;

View File

@@ -277,7 +277,7 @@ void sqlite3VdbeResolveLabel(Vdbe *v, int x){
int j = -1-x; int j = -1-x;
assert( v->magic==VDBE_MAGIC_INIT ); assert( v->magic==VDBE_MAGIC_INIT );
assert( j<p->nLabel ); assert( j<p->nLabel );
if( j>=0 && p->aLabel ){ if( ALWAYS(j>=0) && p->aLabel ){
p->aLabel[j] = v->nOp; p->aLabel[j] = v->nOp;
} }
p->iFixedOp = v->nOp - 1; p->iFixedOp = v->nOp - 1;

View File

@@ -79,9 +79,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
p->iOffset = pC->aType[p->iCol + pC->nField]; p->iOffset = pC->aType[p->iCol + pC->nField];
p->nByte = sqlite3VdbeSerialTypeLen(type); p->nByte = sqlite3VdbeSerialTypeLen(type);
p->pCsr = pC->pCursor; p->pCsr = pC->pCursor;
sqlite3BtreeEnterCursor(p->pCsr); sqlite3BtreeIncrblobCursor(p->pCsr);
sqlite3BtreeCacheOverflow(p->pCsr);
sqlite3BtreeLeaveCursor(p->pCsr);
} }
} }

View File

@@ -2841,7 +2841,7 @@ static Bitmask codeOneLoopStart(
pLevel->p1 = iCur; pLevel->p1 = iCur;
pLevel->p2 = sqlite3VdbeCurrentAddr(v); pLevel->p2 = sqlite3VdbeCurrentAddr(v);
sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
sqlite3ExprCachePop(pParse, 1); sqlite3ExprCachePop(pParse);
}else }else
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -3711,6 +3711,124 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
} }
} }
/*
** Return TRUE if the set of WHERE clause terms used by pA is a proper
** subset of the WHERE clause terms used by pB.
*/
static int whereLoopProperSubset(const WhereLoop *pA, const WhereLoop *pB){
int i, j;
assert( pA->nLTerm<pB->nLTerm ); /* Checked by calling function */
for(j=0, i=pA->nLTerm-1; i>=0 && j>=0; i--){
for(j=pB->nLTerm-1; j>=0; j--){
if( pB->aLTerm[j]==pA->aLTerm[i] ) break;
}
}
return j>=0;
}
/*
** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so
** that:
**
** (1) pTemplate costs less than any other WhereLoops that are a proper
** subset of pTemplate
**
** (2) pTemplate costs more than any other WhereLoops for which pTemplate
** is a proper subset.
**
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
** WHERE clause terms than Y and that every WHERE clause term used by X is
** also used by Y.
*/
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
for(; p; p=p->pNextLoop){
if( p->iTab!=pTemplate->iTab ) continue;
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
if( p->nLTerm<pTemplate->nLTerm
&& (p->rRun<pTemplate->rRun || (p->rRun==pTemplate->rRun &&
p->nOut<=pTemplate->nOut))
&& whereLoopProperSubset(p, pTemplate)
){
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut - 1;
}else
if( p->nLTerm>pTemplate->nLTerm
&& (p->rRun>pTemplate->rRun || (p->rRun==pTemplate->rRun &&
p->nOut>=pTemplate->nOut))
&& whereLoopProperSubset(pTemplate, p)
){
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut + 1;
}
}
}
/*
** Search the list of WhereLoops in *ppPrev looking for one that can be
** supplanted by pTemplate.
**
** Return NULL if the WhereLoop list contains an entry that can supplant
** pTemplate, in other words if pTemplate does not belong on the list.
**
** If pX is a WhereLoop that pTemplate can supplant, then return the
** link that points to pX.
**
** If pTemplate cannot supplant any existing element of the list but needs
** to be added to the list, then return a pointer to the tail of the list.
*/
static WhereLoop **whereLoopFindLesser(
WhereLoop **ppPrev,
const WhereLoop *pTemplate
){
WhereLoop *p;
for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){
if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){
/* If either the iTab or iSortIdx values for two WhereLoop are different
** then those WhereLoops need to be considered separately. Neither is
** a candidate to replace the other. */
continue;
}
/* In the current implementation, the rSetup value is either zero
** or the cost of building an automatic index (NlogN) and the NlogN
** is the same for compatible WhereLoops. */
assert( p->rSetup==0 || pTemplate->rSetup==0
|| p->rSetup==pTemplate->rSetup );
/* whereLoopAddBtree() always generates and inserts the automatic index
** case first. Hence compatible candidate WhereLoops never have a larger
** rSetup. Call this SETUP-INVARIANT */
assert( p->rSetup>=pTemplate->rSetup );
/* If existing WhereLoop p is better than pTemplate, pTemplate can be
** discarded. WhereLoop p is better if:
** (1) p has no more dependencies than pTemplate, and
** (2) p has an equal or lower cost than pTemplate
*/
if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */
&& p->rSetup<=pTemplate->rSetup /* (2a) */
&& p->rRun<=pTemplate->rRun /* (2b) */
&& p->nOut<=pTemplate->nOut /* (2c) */
){
return 0; /* Discard pTemplate */
}
/* If pTemplate is always better than p, then cause p to be overwritten
** with pTemplate. pTemplate is better than p if:
** (1) pTemplate has no more dependences than p, and
** (2) pTemplate has an equal or lower cost than p.
*/
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */
&& p->rRun>=pTemplate->rRun /* (2a) */
&& p->nOut>=pTemplate->nOut /* (2b) */
){
assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
break; /* Cause p to be overwritten by pTemplate */
}
}
return ppPrev;
}
/* /*
** Insert or replace a WhereLoop entry using the template supplied. ** Insert or replace a WhereLoop entry using the template supplied.
** **
@@ -3720,25 +3838,23 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
** fewer dependencies than the template. Otherwise a new WhereLoop is ** fewer dependencies than the template. Otherwise a new WhereLoop is
** added based on the template. ** added based on the template.
** **
** If pBuilder->pOrSet is not NULL then we only care about only the ** If pBuilder->pOrSet is not NULL then we care about only the
** prerequisites and rRun and nOut costs of the N best loops. That ** prerequisites and rRun and nOut costs of the N best loops. That
** information is gathered in the pBuilder->pOrSet object. This special ** information is gathered in the pBuilder->pOrSet object. This special
** processing mode is used only for OR clause processing. ** processing mode is used only for OR clause processing.
** **
** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we ** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
** still might overwrite similar loops with the new template if the ** still might overwrite similar loops with the new template if the
** template is better. Loops may be overwritten if the following ** new template is better. Loops may be overwritten if the following
** conditions are met: ** conditions are met:
** **
** (1) They have the same iTab. ** (1) They have the same iTab.
** (2) They have the same iSortIdx. ** (2) They have the same iSortIdx.
** (3) The template has same or fewer dependencies than the current loop ** (3) The template has same or fewer dependencies than the current loop
** (4) The template has the same or lower cost than the current loop ** (4) The template has the same or lower cost than the current loop
** (5) The template uses more terms of the same index but has no additional
** dependencies
*/ */
static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
WhereLoop **ppPrev, *p, *pNext = 0; WhereLoop **ppPrev, *p;
WhereInfo *pWInfo = pBuilder->pWInfo; WhereInfo *pWInfo = pBuilder->pWInfo;
sqlite3 *db = pWInfo->pParse->db; sqlite3 *db = pWInfo->pParse->db;
@@ -3761,64 +3877,23 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
return SQLITE_OK; return SQLITE_OK;
} }
/* Search for an existing WhereLoop to overwrite, or which takes /* Look for an existing WhereLoop to replace with pTemplate
** priority over pTemplate.
*/ */
for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){ whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){ ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);
/* If either the iTab or iSortIdx values for two WhereLoop are different
** then those WhereLoops need to be considered separately. Neither is if( ppPrev==0 ){
** a candidate to replace the other. */ /* There already exists a WhereLoop on the list that is better
continue; ** than pTemplate, so just ignore pTemplate */
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf("ins-noop: ");
whereLoopPrint(pTemplate, pBuilder->pWC);
} }
/* In the current implementation, the rSetup value is either zero #endif
** or the cost of building an automatic index (NlogN) and the NlogN return SQLITE_OK;
** is the same for compatible WhereLoops. */
assert( p->rSetup==0 || pTemplate->rSetup==0
|| p->rSetup==pTemplate->rSetup );
/* whereLoopAddBtree() always generates and inserts the automatic index
** case first. Hence compatible candidate WhereLoops never have a larger
** rSetup. Call this SETUP-INVARIANT */
assert( p->rSetup>=pTemplate->rSetup );
if( (p->prereq & pTemplate->prereq)==p->prereq
&& p->rSetup<=pTemplate->rSetup
&& p->rRun<=pTemplate->rRun
&& p->nOut<=pTemplate->nOut
){
/* This branch taken when p is equal or better than pTemplate in
** all of (1) dependencies (2) setup-cost, (3) run-cost, and
** (4) number of output rows. */
assert( p->rSetup==pTemplate->rSetup );
if( p->prereq==pTemplate->prereq
&& p->nLTerm<pTemplate->nLTerm
&& (p->wsFlags & pTemplate->wsFlags & WHERE_INDEXED)!=0
&& (p->u.btree.pIndex==pTemplate->u.btree.pIndex
|| pTemplate->rRun+p->nLTerm<=p->rRun+pTemplate->nLTerm)
){
/* Overwrite an existing WhereLoop with an similar one that uses
** more terms of the index */
pNext = p->pNextLoop;
break;
}else{ }else{
/* pTemplate is not helpful. p = *ppPrev;
** Return without changing or adding anything */
goto whereLoopInsert_noop;
}
}
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq
&& p->rRun>=pTemplate->rRun
&& p->nOut>=pTemplate->nOut
){
/* Overwrite an existing WhereLoop with a better one: one that is
** better at one of (1) dependencies, (2) setup-cost, (3) run-cost
** or (4) number of output rows, and is no worse in any of those
** categories. */
assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
pNext = p->pNextLoop;
break;
}
} }
/* If we reach this point it means that either p[] should be overwritten /* If we reach this point it means that either p[] should be overwritten
@@ -3836,13 +3911,33 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
} }
#endif #endif
if( p==0 ){ if( p==0 ){
p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); /* Allocate a new WhereLoop to add to the end of the list */
*ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
if( p==0 ) return SQLITE_NOMEM; if( p==0 ) return SQLITE_NOMEM;
whereLoopInit(p); whereLoopInit(p);
p->pNextLoop = 0;
}else{
/* We will be overwriting WhereLoop p[]. But before we do, first
** go through the rest of the list and delete any other entries besides
** p[] that are also supplated by pTemplate */
WhereLoop **ppTail = &p->pNextLoop;
WhereLoop *pToDel;
while( *ppTail ){
ppTail = whereLoopFindLesser(ppTail, pTemplate);
if( NEVER(ppTail==0) ) break;
pToDel = *ppTail;
if( pToDel==0 ) break;
*ppTail = pToDel->pNextLoop;
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf("ins-del: ");
whereLoopPrint(pToDel, pBuilder->pWC);
}
#endif
whereLoopDelete(db, pToDel);
}
} }
whereLoopXfer(db, p, pTemplate); whereLoopXfer(db, p, pTemplate);
p->pNextLoop = pNext;
*ppPrev = p;
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
Index *pIndex = p->u.btree.pIndex; Index *pIndex = p->u.btree.pIndex;
if( pIndex && pIndex->tnum==0 ){ if( pIndex && pIndex->tnum==0 ){
@@ -3850,16 +3945,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
} }
} }
return SQLITE_OK; return SQLITE_OK;
/* Jump here if the insert is a no-op */
whereLoopInsert_noop:
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf("ins-noop: ");
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
return SQLITE_OK;
} }
/* /*

View File

@@ -875,4 +875,42 @@ do_execsql_test alter-16.2 {
SELECT * FROM t16a_rn ORDER BY a; SELECT * FROM t16a_rn ORDER BY a;
} {abc 1.25 99 xyzzy cba 5.5 98 fizzle} } {abc 1.25 99 xyzzy cba 5.5 98 fizzle}
#-------------------------------------------------------------------------
# Verify that NULL values into the internal-use-only sqlite_rename_*()
# functions do not cause problems.
#
do_execsql_test alter-17.1 {
SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)','abc');
} {{CREATE TABLE "abc"(a,b,c)}}
do_execsql_test alter-17.2 {
SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)',NULL);
} {{CREATE TABLE "(NULL)"(a,b,c)}}
do_execsql_test alter-17.3 {
SELECT sqlite_rename_table(NULL,'abc');
} {{}}
do_execsql_test alter-17.4 {
SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN','abc');
} {{CREATE TRIGGER r1 ON "abc" WHEN}}
do_execsql_test alter-17.5 {
SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN',NULL);
} {{CREATE TRIGGER r1 ON "(NULL)" WHEN}}
do_execsql_test alter-17.6 {
SELECT sqlite_rename_trigger(NULL,'abc');
} {{}}
do_execsql_test alter-17.7 {
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
'xyzzy','lmnop');
} {{CREATE TABLE t1(a REFERENCES "lmnop")}}
do_execsql_test alter-17.8 {
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
'xyzzy',NULL);
} {{CREATE TABLE t1(a REFERENCES "(NULL)")}}
do_execsql_test alter-17.9 {
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
NULL, 'lmnop');
} {{}}
do_execsql_test alter-17.10 {
SELECT sqlite_rename_parent(NULL,'abc','xyz');
} {{}}
finish_test finish_test

View File

@@ -1301,11 +1301,13 @@ do_test func-29.3 {
db eval {SELECT typeof(+x) FROM t29 ORDER BY id} db eval {SELECT typeof(+x) FROM t29 ORDER BY id}
} {integer null real blob text} } {integer null real blob text}
if {[permutation] != "mmap"} { if {[permutation] != "mmap"} {
ifcapable !direct_read {
do_test func-29.4 { do_test func-29.4 {
set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1] set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1]
if {$x>100} {set x many} if {$x>100} {set x many}
set x set x
} {many} } {many}
}
} }
do_test func-29.5 { do_test func-29.5 {
db close db close

View File

@@ -248,4 +248,23 @@ do_execsql_test index6-5.0 {
SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b'; SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b';
} {6 6} } {6 6}
# Test case for ticket [2ea3e9fe6379fc3f6ce7e090ce483c1a3a80d6c9] from
# 2014-04-13: Partial index causes assertion fault on UPDATE OR REPLACE.
#
do_execsql_test index6-6.0 {
CREATE TABLE t6(a,b);
CREATE UNIQUE INDEX t6ab ON t1(a,b);
CREATE INDEX t6b ON t6(b) WHERE b=1;
INSERT INTO t6(a,b) VALUES(123,456);
SELECT * FROM t6;
} {123 456}
do_execsql_test index6-6.1 {
UPDATE OR REPLACE t6 SET b=789;
SELECT * FROM t6;
} {123 789}
do_execsql_test index6-6.2 {
PRAGMA integrity_check;
} {ok}
finish_test finish_test

View File

@@ -1574,4 +1574,17 @@ sqlite3_shutdown
test_sqlite3_log test_sqlite3_log
sqlite3_initialize sqlite3_initialize
# Make sure PRAGMA journal_mode=WAL works with ATTACHED databases in
# all journal modes.
#
foreach mode {OFF MEMORY PERSIST DELETE TRUNCATE WAL} {
delete_file test.db test2.db
sqlite3 db test.db
do_test wal-25.$mode {
db eval "PRAGMA journal_mode=$mode"
db eval {ATTACH 'test2.db' AS t2; PRAGMA journal_mode=WAL;}
} {wal}
db close
}
finish_test finish_test

View File

@@ -217,6 +217,59 @@ do_execsql_test 4.7 {
ORDER BY a; ORDER BY a;
} {3 4 3 4} } {3 4 3 4}
# Verify fix of a bug reported on the mailing list by Peter Reid
#
do_execsql_test 5.1 {
DROP TABLE IF EXISTS t;
CREATE TABLE t(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17);
CREATE INDEX tc0 ON t(c0);
CREATE INDEX tc1 ON t(c1);
CREATE INDEX tc2 ON t(c2);
CREATE INDEX tc3 ON t(c3);
CREATE INDEX tc4 ON t(c4);
CREATE INDEX tc5 ON t(c5);
CREATE INDEX tc6 ON t(c6);
CREATE INDEX tc7 ON t(c7);
CREATE INDEX tc8 ON t(c8);
CREATE INDEX tc9 ON t(c9);
CREATE INDEX tc10 ON t(c10);
CREATE INDEX tc11 ON t(c11);
CREATE INDEX tc12 ON t(c12);
CREATE INDEX tc13 ON t(c13);
CREATE INDEX tc14 ON t(c14);
CREATE INDEX tc15 ON t(c15);
CREATE INDEX tc16 ON t(c16);
CREATE INDEX tc17 ON t(c17);
INSERT INTO t(c0, c16) VALUES (1,1);
SELECT * FROM t WHERE
c0=1 or c1=1 or c2=1 or c3=1 or
c4=1 or c5=1 or c6=1 or c7=1 or
c8=1 or c9=1 or c10=1 or c11=1 or
c12=1 or c13=1 or c14=1 or c15=1 or
c16=1 or c17=1;
} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1 {}}
do_execsql_test 5.2 {
DELETE FROM t;
INSERT INTO t(c0,c17) VALUES(1,1);
SELECT * FROM t WHERE
c0=1 or c1=1 or c2=1 or c3=1 or
c4=1 or c5=1 or c6=1 or c7=1 or
c8=1 or c9=1 or c10=1 or c11=1 or
c12=1 or c13=1 or c14=1 or c15=1 or
c16=1 or c17=1;
} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1}
do_execsql_test 5.3 {
DELETE FROM t;
INSERT INTO t(c0,c15) VALUES(1,1);
SELECT * FROM t WHERE
c0=1 or c1=1 or c2=1 or c3=1 or
c4=1 or c5=1 or c6=1 or c7=1 or
c8=1 or c9=1 or c10=1 or c11=1 or
c12=1 or c13=1 or c14=1 or c15=1 or
c16=1 or c17=1;
} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1 {} {}}
finish_test finish_test

139
test/whereH.test Normal file
View File

@@ -0,0 +1,139 @@
# 2014-03-31
#
# 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.
#
#***********************************************************************
#
# Test cases for query planning decisions where one candidate index
# covers a proper superset of the WHERE clause terms of another
# candidate index.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_execsql_test whereH-1.1 {
CREATE TABLE t1(a,b,c,d);
CREATE INDEX t1abc ON t1(a,b,c);
CREATE INDEX t1bc ON t1(b,c);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c;
} {/INDEX t1abc /}
do_execsql_test whereH-1.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-2.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d);
CREATE INDEX t1bc ON t1(b,c);
CREATE INDEX t1abc ON t1(a,b,c);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c;
} {/INDEX t1abc /}
do_execsql_test whereH-2.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-3.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1cd ON t1(c,d);
CREATE INDEX t1bcd ON t1(b,c,d);
CREATE INDEX t1abcd ON t1(a,b,c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-3.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-4.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1cd ON t1(c,d);
CREATE INDEX t1abcd ON t1(a,b,c,d);
CREATE INDEX t1bcd ON t1(b,c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-4.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-5.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1bcd ON t1(b,c,d);
CREATE INDEX t1cd ON t1(c,d);
CREATE INDEX t1abcd ON t1(a,b,c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-5.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-6.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1bcd ON t1(b,c,d);
CREATE INDEX t1abcd ON t1(a,b,c,d);
CREATE INDEX t1cd ON t1(c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-6.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-7.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1abcd ON t1(a,b,c,d);
CREATE INDEX t1bcd ON t1(b,c,d);
CREATE INDEX t1cd ON t1(c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-7.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-8.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1abcd ON t1(a,b,c,d);
CREATE INDEX t1cd ON t1(c,d);
CREATE INDEX t1bcd ON t1(b,c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-8.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
finish_test