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:
59
manifest
59
manifest
@@ -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
|
||||||
|
@@ -1 +1 @@
|
|||||||
9515c8344a6743bbb0c6a6e49fb79fb3139090df
|
95e77efe076ab421bd246119c47dba5dacf9d087
|
@@ -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 ){
|
||||||
|
188
src/btree.c
188
src/btree.c
@@ -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
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
@@ -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.
|
||||||
**
|
**
|
||||||
|
@@ -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);
|
||||||
|
18
src/delete.c
18
src/delete.c
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
31
src/expr.c
31
src/expr.c
@@ -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: {
|
||||||
|
16
src/main.c
16
src/main.c
@@ -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
|
||||||
|
@@ -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 */
|
||||||
|
@@ -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);
|
||||||
|
@@ -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() */
|
||||||
|
@@ -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);
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
@@ -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],
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
233
src/where.c
233
src/where.c
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
139
test/whereH.test
Normal 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
|
Reference in New Issue
Block a user