Add support for "ALTER TABLE ... DROP COLUMN ..." commands.

FossilOrigin-Name: c844a331e78949850fde8ed95058cb34f863566944bc9e92e3ae042768f130e1
This commit is contained in:
dan 2021-02-19 14:32:58 +00:00
commit be2ee38283
19 changed files with 726 additions and 84 deletions

View File

@ -1,5 +1,5 @@
C Avoid\sinvoking\sthe\supdate\sor\spre-update\shooks\sduring\sVACUUM\soperations. C Add\ssupport\sfor\s"ALTER\sTABLE\s...\sDROP\sCOLUMN\s..."\scommands.
D 2021-02-18T15:59:37.490 D 2021-02-19T14:32:58.535
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -475,7 +475,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c c4a973d7fc68f81fbc5d1d028a88ddb2cb212faef8c6f63433175b8d5ecd83dc F src/alter.c 1addd06a7aae343497ebede71ec355c2011f175075943007341693ebf7daa47d
F src/analyze.c 01c6c6765cb4d40b473b71d85535093730770bb186f2f473abac25f07fcdee5c F src/analyze.c 01c6c6765cb4d40b473b71d85535093730770bb186f2f473abac25f07fcdee5c
F src/attach.c e80162a47411f296bea550ed8fafd730481f4aa71e89ece23ba9c957eed15d4a F src/attach.c e80162a47411f296bea550ed8fafd730481f4aa71e89ece23ba9c957eed15d4a
F src/auth.c 08954fdc4cc2da5264ba5b75cfd90b67a6fc7d1710a02ccf917c38eadec77853 F src/auth.c 08954fdc4cc2da5264ba5b75cfd90b67a6fc7d1710a02ccf917c38eadec77853
@ -485,7 +485,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c 694020ad8a3af3d79b09f74c8f1421272a419cdea42a13401e3b0f7dea6e9c3e F src/btree.c 694020ad8a3af3d79b09f74c8f1421272a419cdea42a13401e3b0f7dea6e9c3e
F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e
F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331
F src/build.c e50a6d7132b051b7d00c59a896e4889128a55c0f55f81c664da1906fbad51d1c F src/build.c 72b868d9c8a0d56aef4237825b0fad38898a2d9310669940383accf20429c5ca
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410 F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410
@ -530,23 +530,23 @@ F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c c49952ac5e9cc536778eff528091d79d38b3e45cbeeed4695dc05e207dc6547d F src/pager.c c49952ac5e9cc536778eff528091d79d38b3e45cbeeed4695dc05e207dc6547d
F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f
F src/parse.y 67ba503780de64b967ae195b7e14c33531329228e1bc0b83d63324beb733680b F src/parse.y cdc4e5efaf1618d82f6b241a30f1a586188bf37e9c55f967258ed15fe24c51a2
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
F src/pragma.c 6daaaecc26a4b09481d21722525b079ce756751a43a79cc1d8f122d686806193 F src/pragma.c 6daaaecc26a4b09481d21722525b079ce756751a43a79cc1d8f122d686806193
F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf
F src/prepare.c a25c7df3a71be19c31231d59d0694e950183837fc54b1828549c5a766538fcf7 F src/prepare.c 7a534d100c556f45f10aee131f2e4244cb52547b7cf17e1c393f55d8abb62e97
F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 52f81603cc40f78449f5b6aed96dbea9484b194771ecb1937e8c0f6547c186a0 F src/resolve.c 52f81603cc40f78449f5b6aed96dbea9484b194771ecb1937e8c0f6547c186a0
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c aa04743edeac1142f0a698ca4a3188795b826bd5ef46ea61f06897a4f71ad6b2 F src/select.c 371a5c95d47d4e969337548ed9bd344788f15518a1c75921507355bd93815205
F src/shell.c.in 844417f84df1f6c4fce1c815629a888cfdcf219e86513e9c332bbcc38832f477 F src/shell.c.in 844417f84df1f6c4fce1c815629a888cfdcf219e86513e9c332bbcc38832f477
F src/sqlite.h.in 8855a19f37ade8dad189a9e48233a2ebe1b46faf469c7eb0906a654e252dcc57 F src/sqlite.h.in 8855a19f37ade8dad189a9e48233a2ebe1b46faf469c7eb0906a654e252dcc57
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
F src/sqliteInt.h 4d57a17d4697a6e7f992008f36a35852c2a6c3064992fbedf3f56b7bad9df027 F src/sqliteInt.h 4bd449478df0444ccb9f6a8e6f210b2ceacdd59562f52630edb0bb2d8cc25094
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@ -607,23 +607,23 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9
F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
F src/trigger.c 983c7c8464c46840dac1ffe0461a6c447ac12c965746975c108eb5f4283e8801 F src/trigger.c 861c3ec2c5b0fc830bdf82470454a9324fad70cbaa96d2e208fb54577c9e8d28
F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723 F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723
F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048 F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048
F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286
F src/vdbe.c b3c9a3f9d546d4848a2a8c88a3c40875cd6ba3d248d9b99d01b1eeb38b29c171 F src/vdbe.c 9766281c0febf25f30a043d98b2417011acc7b04f287d3c671c3e59f656fc208
F src/vdbe.h 83603854bfa5851af601fc0947671eb260f4363e62e960e8a994fb9bbcd2aaa1 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
F src/vdbeInt.h 3df118924e1711f1bbc8e30c46260d0ab6c3b029b32dd411f789111f76434f3c F src/vdbeInt.h 3df118924e1711f1bbc8e30c46260d0ab6c3b029b32dd411f789111f76434f3c
F src/vdbeapi.c 4a43e303ec3354c785f453e881521969378e85628278ab74ba4a9df790c0d93b F src/vdbeapi.c 4a43e303ec3354c785f453e881521969378e85628278ab74ba4a9df790c0d93b
F src/vdbeaux.c c8e96fb57ee6f7150845325ffb8d7fd4e340ff4f73aa527a6f26a485db8b9955 F src/vdbeaux.c fb51483c2bcaf45c5de63c26cce8649ef37f1332e8e035867033d21ef5e7fc2c
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1 F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f
F src/vdbesort.c f5b5e473a7cee44e47a94817b042fd7172cf3aa2c0a7928a8339d612bcfdec5a F src/vdbesort.c f5b5e473a7cee44e47a94817b042fd7172cf3aa2c0a7928a8339d612bcfdec5a
F src/vdbetrace.c 666c6fd9f1b62be6999e072a45b913e3c2c3518bc60dfd4d54fe304130acb724 F src/vdbetrace.c 666c6fd9f1b62be6999e072a45b913e3c2c3518bc60dfd4d54fe304130acb724
F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
F src/vtab.c b7773ffbde8d2b134fde8f7349c8d0a0503b308f77561acda7db975d3114d6a1 F src/vtab.c 032a0165c147fda16927e6a3230e90c068d4af93f887ce94e26f678fe48e5e4c
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 69e770e96fd56cc21608992bf2c6f1f3dc5cf2572d0495c6a643b06c3a679f14 F src/wal.c 69e770e96fd56cc21608992bf2c6f1f3dc5cf2572d0495c6a643b06c3a679f14
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
@ -645,11 +645,14 @@ F test/alter2.test a966ccfcddf9ce0a4e0e6ff1aca9e6e7948e0e242cd7e43fc091948521807
F test/alter3.test e487958dec7932453e0b83baf21d6b1e71d5e7d9a55bc20eadfa62a51ddffc29 F test/alter3.test e487958dec7932453e0b83baf21d6b1e71d5e7d9a55bc20eadfa62a51ddffc29
F test/alter4.test dfd6086faf461b27ca2d2999848dcd207edf23352fc1592d0005c0844f3f08cf F test/alter4.test dfd6086faf461b27ca2d2999848dcd207edf23352fc1592d0005c0844f3f08cf
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959 F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
F test/alterauth2.test c0a1ddf5b93d93cb0d15ba7acaf0c5c6fb515bbe861ede75b2d3fabad33b6499 F test/alterauth2.test 794ac5cef251819fe364b4fe20f12f86e9c5d68070513c7fd26c17cb244c89af
F test/altercol.test 1d6a6fe698b81e626baea4881f5717f9bc53d7d07f1cd23ee7ad1b931f117ddf F test/altercol.test 1d6a6fe698b81e626baea4881f5717f9bc53d7d07f1cd23ee7ad1b931f117ddf
F test/alterlegacy.test 82022721ce0de29cedc9a7af63bc9fcc078b0ee000f8283b4b6ea9c3eab2f44b F test/altercorrupt.test cb17a81f655a0d71bc1e48e44741a5e0905a3b3efbbe485b0b6c7648f2af3eed
F test/alterdropcol.test baad37ff9b07078ea02dcc33dbfb82bde655f3eee5c453e218f69501c36f02ba
F test/alterlegacy.test f38c6d06cda39e1f7b955bbce57f2e3ef5b7cb566d3d1234502093e228c15811
F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9 F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b
F test/altermalloc3.test 2c7bbd8cf3e9c4a91e28675bb62bcc2ef70f227967fa74349f03d9f4642f0615
F test/altertab.test 6d7bbac2c4a6ef71b775094a3298fa3a92274d95034ee23157ffba92768e47e6 F test/altertab.test 6d7bbac2c4a6ef71b775094a3298fa3a92274d95034ee23157ffba92768e47e6
F test/altertab2.test b0d62f323ca5dab42b0bc028c52e310ebdd13e655e8fac070fe622bad7852c2b F test/altertab2.test b0d62f323ca5dab42b0bc028c52e310ebdd13e655e8fac070fe622bad7852c2b
F test/altertab3.test 2b82fa2236a3a91553d53ae5555d8e723c7eec174c41f1fa62ff497355398479 F test/altertab3.test 2b82fa2236a3a91553d53ae5555d8e723c7eec174c41f1fa62ff497355398479
@ -1020,7 +1023,7 @@ F test/fts4noti.test 5553d7bb2e20bf4a06b23e849352efc022ce6309
F test/fts4onepass.test d69ddc4ee3415e40b0c5d1d0408488a87614d4f63ba9c44f3e52db541d6b7cc7 F test/fts4onepass.test d69ddc4ee3415e40b0c5d1d0408488a87614d4f63ba9c44f3e52db541d6b7cc7
F test/fts4opt.test 0fd0cc84000743ff2a883b9b84b4a5be07249f0ba790c8848a757164cdd46b2a F test/fts4opt.test 0fd0cc84000743ff2a883b9b84b4a5be07249f0ba790c8848a757164cdd46b2a
F test/fts4record.test a48508f69a84c9287c8019d3a1ae712f5730d8335ffaf8e2101e691d078950bb F test/fts4record.test a48508f69a84c9287c8019d3a1ae712f5730d8335ffaf8e2101e691d078950bb
F test/fts4rename.test 15fd9985c2bce6dea20da2245b22029ec89bd4710ed317c4c53abbe3cfd0c880 F test/fts4rename.test 2e0565ffd92b2c51f1a757df0b8f2ca30537197106fec09e943919801d173692
F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f757380429 F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f757380429
F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9 F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9
F test/fts4upfrom.test 8df5acb6e10ad73f393d1add082b042ab1db72567888847d098152121e507b34 F test/fts4upfrom.test 8df5acb6e10ad73f393d1add082b042ab1db72567888847d098152121e507b34
@ -1900,7 +1903,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P f985a78ecc0c6d9ff671c730a109d97dc781b06e47a0ab03f441cea5d021a4c3 P 3c25cb4ab8885a50e2a485fe76f5ffd5dd8ebe1306aca8c0989e0b7fd7dd18d2 126ee1ec4f3565c0cccca98885fa3665a641ea3df251511de16eed2a1c396124
R 887c3ab5f5432ba4ea084453147dc94e R a9f6b9c36a39e6908ea00fd7298f0619
T +closed 126ee1ec4f3565c0cccca98885fa3665a641ea3df251511de16eed2a1c396124
U dan U dan
Z 858d0f25e386aba1accc2e325cd1540d Z c1e3973235fcf41f620261cabeb4df13

View File

@ -1 +1 @@
3c25cb4ab8885a50e2a485fe76f5ffd5dd8ebe1306aca8c0989e0b7fd7dd18d2 c844a331e78949850fde8ed95058cb34f863566944bc9e92e3ae042768f130e1

View File

@ -49,16 +49,21 @@ static int isAlterableTable(Parse *pParse, Table *pTab){
** statement to ensure that the operation has not rendered any schema ** statement to ensure that the operation has not rendered any schema
** objects unusable. ** objects unusable.
*/ */
static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ static void renameTestSchema(
Parse *pParse, /* Parse context */
const char *zDb, /* Name of db to verify schema of */
int bTemp, /* True if this is the temp db */
const char *zWhen /* "when" part of error message */
){
pParse->colNamesSet = 1; pParse->colNamesSet = 1;
sqlite3NestedParse(pParse, sqlite3NestedParse(pParse,
"SELECT 1 " "SELECT 1 "
"FROM \"%w\"." DFLT_SCHEMA_TABLE " " "FROM \"%w\"." DFLT_SCHEMA_TABLE " "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
" AND sql NOT LIKE 'create virtual%%'" " AND sql NOT LIKE 'create virtual%%'"
" AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ", " AND sqlite_rename_test(%Q, sql, type, name, %d, %Q)=NULL ",
zDb, zDb,
zDb, bTemp zDb, bTemp, zWhen
); );
if( bTemp==0 ){ if( bTemp==0 ){
@ -67,8 +72,8 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
"FROM temp." DFLT_SCHEMA_TABLE " " "FROM temp." DFLT_SCHEMA_TABLE " "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
" AND sql NOT LIKE 'create virtual%%'" " AND sql NOT LIKE 'create virtual%%'"
" AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ", " AND sqlite_rename_test(%Q, sql, type, name, 1, %Q)=NULL ",
zDb zDb, zWhen
); );
} }
} }
@ -77,12 +82,12 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
** Generate code to reload the schema for database iDb. And, if iDb!=1, for ** Generate code to reload the schema for database iDb. And, if iDb!=1, for
** the temp database as well. ** the temp database as well.
*/ */
static void renameReloadSchema(Parse *pParse, int iDb){ static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
if( v ){ if( v ){
sqlite3ChangeCookie(pParse, iDb); sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0); sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0, p5);
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0); if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0, p5);
} }
} }
@ -231,7 +236,7 @@ void sqlite3AlterRenameTable(
"sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), " "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
"tbl_name = " "tbl_name = "
"CASE WHEN tbl_name=%Q COLLATE nocase AND " "CASE WHEN tbl_name=%Q COLLATE nocase AND "
" sqlite_rename_test(%Q, sql, type, name, 1) " " sqlite_rename_test(%Q, sql, type, name, 1, 'after rename') "
"THEN %Q ELSE tbl_name END " "THEN %Q ELSE tbl_name END "
"WHERE type IN ('view', 'trigger')" "WHERE type IN ('view', 'trigger')"
, zDb, zTabName, zName, zTabName, zDb, zName); , zDb, zTabName, zName, zTabName, zDb, zName);
@ -250,8 +255,8 @@ void sqlite3AlterRenameTable(
} }
#endif #endif
renameReloadSchema(pParse, iDb); renameReloadSchema(pParse, iDb, INITFLAG_AlterRename);
renameTestSchema(pParse, zDb, iDb==1); renameTestSchema(pParse, zDb, iDb==1, "after rename");
exit_rename_table: exit_rename_table:
sqlite3SrcListDelete(db, pSrc); sqlite3SrcListDelete(db, pSrc);
@ -413,7 +418,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
} }
/* Reload the table definition */ /* Reload the table definition */
renameReloadSchema(pParse, iDb); renameReloadSchema(pParse, iDb, INITFLAG_AlterRename);
} }
/* /*
@ -513,7 +518,7 @@ exit_begin_add_column:
** Or, if pTab is not a view or virtual table, zero is returned. ** Or, if pTab is not a view or virtual table, zero is returned.
*/ */
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
static int isRealTable(Parse *pParse, Table *pTab){ static int isRealTable(Parse *pParse, Table *pTab, int bDrop){
const char *zType = 0; const char *zType = 0;
#ifndef SQLITE_OMIT_VIEW #ifndef SQLITE_OMIT_VIEW
if( pTab->pSelect ){ if( pTab->pSelect ){
@ -526,15 +531,16 @@ static int isRealTable(Parse *pParse, Table *pTab){
} }
#endif #endif
if( zType ){ if( zType ){
sqlite3ErrorMsg( sqlite3ErrorMsg(pParse, "cannot %s %s \"%s\"",
pParse, "cannot rename columns of %s \"%s\"", zType, pTab->zName (bDrop ? "drop column from" : "rename columns of"),
zType, pTab->zName
); );
return 1; return 1;
} }
return 0; return 0;
} }
#else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ #else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
# define isRealTable(x,y) (0) # define isRealTable(x,y,z) (0)
#endif #endif
/* /*
@ -563,7 +569,7 @@ void sqlite3AlterRenameColumn(
/* Cannot alter a system table */ /* Cannot alter a system table */
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column; if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column;
if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column; if( SQLITE_OK!=isRealTable(pParse, pTab, 0) ) goto exit_rename_column;
/* Which schema holds the table to be altered */ /* Which schema holds the table to be altered */
iSchema = sqlite3SchemaToIndex(db, pTab->pSchema); iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
@ -617,8 +623,8 @@ void sqlite3AlterRenameColumn(
); );
/* Drop and reload the database schema. */ /* Drop and reload the database schema. */
renameReloadSchema(pParse, iSchema); renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename);
renameTestSchema(pParse, zDb, iSchema==1); renameTestSchema(pParse, zDb, iSchema==1, "after rename");
exit_rename_column: exit_rename_column:
sqlite3SrcListDelete(db, pSrc); sqlite3SrcListDelete(db, pSrc);
@ -870,23 +876,33 @@ static void renameTokenFree(sqlite3 *db, RenameToken *pToken){
/* /*
** Search the Parse object passed as the first argument for a RenameToken ** Search the Parse object passed as the first argument for a RenameToken
** object associated with parse tree element pPtr. If found, remove it ** object associated with parse tree element pPtr. If found, return a pointer
** from the Parse object and add it to the list maintained by the ** to it. Otherwise, return NULL.
** RenameCtx object passed as the second argument. **
** If the second argument passed to this function is not NULL and a matching
** RenameToken object is found, remove it from the Parse object and add it to
** the list maintained by the RenameCtx object.
*/ */
static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){ static RenameToken *renameTokenFind(
Parse *pParse,
struct RenameCtx *pCtx,
void *pPtr
){
RenameToken **pp; RenameToken **pp;
assert( pPtr!=0 ); assert( pPtr!=0 );
for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){ for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
if( (*pp)->p==pPtr ){ if( (*pp)->p==pPtr ){
RenameToken *pToken = *pp; RenameToken *pToken = *pp;
if( pCtx ){
*pp = pToken->pNext; *pp = pToken->pNext;
pToken->pNext = pCtx->pList; pToken->pNext = pCtx->pList;
pCtx->pList = pToken; pCtx->pList = pToken;
pCtx->nList++; pCtx->nList++;
break; }
return pToken;
} }
} }
return 0;
} }
/* /*
@ -957,7 +973,7 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
*/ */
static void renameColumnParseError( static void renameColumnParseError(
sqlite3_context *pCtx, sqlite3_context *pCtx,
int bPost, const char *zWhen,
sqlite3_value *pType, sqlite3_value *pType,
sqlite3_value *pObject, sqlite3_value *pObject,
Parse *pParse Parse *pParse
@ -966,8 +982,8 @@ static void renameColumnParseError(
const char *zN = (const char*)sqlite3_value_text(pObject); const char *zN = (const char*)sqlite3_value_text(pObject);
char *zErr; char *zErr;
zErr = sqlite3_mprintf("error in %s %s%s: %s", zErr = sqlite3_mprintf("error in %s %s%s%s: %s",
zT, zN, (bPost ? " after rename" : ""), zT, zN, (zWhen[0] ? " " : ""), zWhen,
pParse->zErrMsg pParse->zErrMsg
); );
sqlite3_result_error(pCtx, zErr, -1); sqlite3_result_error(pCtx, zErr, -1);
@ -1046,7 +1062,7 @@ static int renameParseSql(
p->eParseMode = PARSE_MODE_RENAME; p->eParseMode = PARSE_MODE_RENAME;
p->db = db; p->db = db;
p->nQueryLoop = 1; p->nQueryLoop = 1;
rc = sqlite3RunParser(p, zSql, &zErr); rc = zSql ? sqlite3RunParser(p, zSql, &zErr) : SQLITE_NOMEM;
assert( p->zErrMsg==0 ); assert( p->zErrMsg==0 );
assert( rc!=SQLITE_OK || zErr==0 ); assert( rc!=SQLITE_OK || zErr==0 );
p->zErrMsg = zErr; p->zErrMsg = zErr;
@ -1473,7 +1489,7 @@ static void renameColumnFunc(
renameColumnFunc_done: renameColumnFunc_done:
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
if( sParse.zErrMsg ){ if( sParse.zErrMsg ){
renameColumnParseError(context, 0, argv[1], argv[2], &sParse); renameColumnParseError(context, "", argv[1], argv[2], &sParse);
}else{ }else{
sqlite3_result_error_code(context, rc); sqlite3_result_error_code(context, rc);
} }
@ -1662,7 +1678,7 @@ static void renameTableFunc(
} }
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
if( sParse.zErrMsg ){ if( sParse.zErrMsg ){
renameColumnParseError(context, 0, argv[1], argv[2], &sParse); renameColumnParseError(context, "", argv[1], argv[2], &sParse);
}else{ }else{
sqlite3_result_error_code(context, rc); sqlite3_result_error_code(context, rc);
} }
@ -1691,6 +1707,7 @@ static void renameTableFunc(
** 2: Object type ("view", "table", "trigger" or "index"). ** 2: Object type ("view", "table", "trigger" or "index").
** 3: Object name. ** 3: Object name.
** 4: True if object is from temp schema. ** 4: True if object is from temp schema.
** 5: "when" part of error message.
** **
** Unless it finds an error, this function normally returns NULL. However, it ** Unless it finds an error, this function normally returns NULL. However, it
** returns integer value 1 if: ** returns integer value 1 if:
@ -1708,6 +1725,7 @@ static void renameTableTest(
char const *zInput = (const char*)sqlite3_value_text(argv[1]); char const *zInput = (const char*)sqlite3_value_text(argv[1]);
int bTemp = sqlite3_value_int(argv[4]); int bTemp = sqlite3_value_int(argv[4]);
int isLegacy = (db->flags & SQLITE_LegacyAlter); int isLegacy = (db->flags & SQLITE_LegacyAlter);
char const *zWhen = (const char*)sqlite3_value_text(argv[5]);
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
sqlite3_xauth xAuth = db->xAuth; sqlite3_xauth xAuth = db->xAuth;
@ -1740,8 +1758,8 @@ static void renameTableTest(
} }
} }
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK && zWhen ){
renameColumnParseError(context, 1, argv[2], argv[3], &sParse); renameColumnParseError(context, zWhen, argv[2], argv[3],&sParse);
} }
renameParseCleanup(&sParse); renameParseCleanup(&sParse);
} }
@ -1751,6 +1769,198 @@ static void renameTableTest(
#endif #endif
} }
/*
** The implementation of internal UDF sqlite_drop_column().
**
** Arguments:
**
** argv[0]: An integer - the index of the schema containing the table
** argv[1]: CREATE TABLE statement to modify.
** argv[2]: An integer - the index of the column to remove.
** argv[3]: Byte offset of first byte after last column definition in argv[1]
**
** The value returned is a string containing the CREATE TABLE statement
** with column argv[2] removed.
*/
static void dropColumnFunc(
sqlite3_context *context,
int NotUsed,
sqlite3_value **argv
){
sqlite3 *db = sqlite3_context_db_handle(context);
int iSchema = sqlite3_value_int(argv[0]);
const char *zSql = (const char*)sqlite3_value_text(argv[1]);
int iCol = sqlite3_value_int(argv[2]);
int iAddColOffset = sqlite3_value_int(argv[3]);
const char *zDb = db->aDb[iSchema].zDbSName;
int rc;
Parse sParse;
RenameToken *pCol;
Table *pTab;
const char *zEnd;
char *zNew = 0;
#ifndef SQLITE_OMIT_AUTHORIZATION
sqlite3_xauth xAuth = db->xAuth;
db->xAuth = 0;
#endif
rc = renameParseSql(&sParse, zDb, db, zSql, iSchema==1);
if( rc!=SQLITE_OK ) goto drop_column_done;
pTab = sParse.pNewTable;
if( iCol>=pTab->nCol ){
/* This can happen if the sqlite_schema table is corrupt */
rc = SQLITE_CORRUPT_BKPT;
goto drop_column_done;
}
pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zName);
if( iCol<pTab->nCol-1 ){
RenameToken *pEnd;
pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zName);
zEnd = (const char*)pEnd->t.z;
}else{
zEnd = (const char*)&zSql[iAddColOffset];
while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--;
}
zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd);
sqlite3_result_text(context, zNew, -1, SQLITE_TRANSIENT);
sqlite3_free(zNew);
drop_column_done:
renameParseCleanup(&sParse);
#ifndef SQLITE_OMIT_AUTHORIZATION
db->xAuth = xAuth;
#endif
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(context, rc);
}
}
/*
** This function is called by the parser upon parsing an
**
** ALTER TABLE pSrc DROP COLUMN pName
**
** statement. Argument pSrc contains the possibly qualified name of the
** table being edited, and token pName the name of the column to drop.
*/
void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){
sqlite3 *db = pParse->db; /* Database handle */
Table *pTab; /* Table to modify */
int iDb; /* Index of db containing pTab in aDb[] */
const char *zDb; /* Database containing pTab ("main" etc.) */
char *zCol = 0; /* Name of column to drop */
int iCol; /* Index of column zCol in pTab->aCol[] */
/* Look up the table being altered. */
assert( pParse->pNewTable==0 );
assert( sqlite3BtreeHoldsAllMutexes(db) );
if( NEVER(db->mallocFailed) ) goto exit_drop_column;
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
if( !pTab ) goto exit_drop_column;
/* Make sure this is not an attempt to ALTER a view, virtual table or
** system table. */
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_drop_column;
if( SQLITE_OK!=isRealTable(pParse, pTab, 1) ) goto exit_drop_column;
/* Find the index of the column being dropped. */
zCol = sqlite3NameFromToken(db, pName);
if( zCol==0 ){
assert( db->mallocFailed );
goto exit_drop_column;
}
iCol = sqlite3ColumnIndex(pTab, zCol);
if( iCol<0 ){
sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zCol);
goto exit_drop_column;
}
/* Do not allow the user to drop a PRIMARY KEY column or a column
** constrained by a UNIQUE constraint. */
if( pTab->aCol[iCol].colFlags & (COLFLAG_PRIMKEY|COLFLAG_UNIQUE) ){
sqlite3ErrorMsg(pParse, "cannot drop %s column: \"%s\"",
(pTab->aCol[iCol].colFlags&COLFLAG_PRIMKEY) ? "PRIMARY KEY" : "UNIQUE",
zCol
);
goto exit_drop_column;
}
/* Do not allow the number of columns to go to zero */
if( pTab->nCol<=1 ){
sqlite3ErrorMsg(pParse, "cannot drop column \"%s\": no other columns exist",zCol);
goto exit_drop_column;
}
/* Edit the sqlite_schema table */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb>=0 );
zDb = db->aDb[iDb].zDbSName;
renameTestSchema(pParse, zDb, iDb==1, "");
sqlite3NestedParse(pParse,
"UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = sqlite_drop_column(%d, sql, %d, %d) "
"WHERE (type=='table' AND tbl_name=%Q COLLATE nocase)"
, zDb, iDb, iCol, pTab->addColOffset, pTab->zName
);
/* Drop and reload the database schema. */
renameReloadSchema(pParse, iDb, INITFLAG_AlterDrop);
renameTestSchema(pParse, zDb, iDb==1, "after drop column");
/* Edit rows of table on disk */
if( pParse->nErr==0 && (pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL)==0 ){
int i;
int addr;
int reg;
int regRec;
Index *pPk = 0;
int nField = 0; /* Number of non-virtual columns after drop */
int iCur;
Vdbe *v = sqlite3GetVdbe(pParse);
iCur = pParse->nTab++;
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
reg = ++pParse->nMem;
pParse->nMem += pTab->nCol;
if( HasRowid(pTab) ){
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg);
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
}
for(i=0; i<pTab->nCol; i++){
if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
int regOut;
if( pPk ){
int iPos = sqlite3TableColumnToIndex(pPk, i);
int iColPos = sqlite3TableColumnToIndex(pPk, iCol);
regOut = reg+1+iPos-(iPos>iColPos);
}else{
regOut = reg+1+nField;
}
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
nField++;
}
}
regRec = reg + pTab->nCol;
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec);
if( pPk ){
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol);
}else{
sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg);
}
sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr);
}
exit_drop_column:
sqlite3DbFree(db, zCol);
sqlite3SrcListDelete(db, pSrc);
}
/* /*
** Register built-in functions used to help implement ALTER TABLE ** Register built-in functions used to help implement ALTER TABLE
*/ */
@ -1758,7 +1968,8 @@ void sqlite3AlterFunctions(void){
static FuncDef aAlterTableFuncs[] = { static FuncDef aAlterTableFuncs[] = {
INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc), INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc),
INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc), INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc),
INTERNAL_FUNCTION(sqlite_rename_test, 5, renameTableTest), INTERNAL_FUNCTION(sqlite_rename_test, 6, renameTableTest),
INTERNAL_FUNCTION(sqlite_drop_column, 4, dropColumnFunc),
}; };
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
} }

View File

@ -2641,7 +2641,7 @@ void sqlite3EndTable(
/* Reparse everything to update our internal data structures */ /* Reparse everything to update our internal data structures */
sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName)); sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
} }
/* Add the table to the in-memory representation of the database. /* Add the table to the in-memory representation of the database.
@ -4129,7 +4129,7 @@ void sqlite3CreateIndex(
sqlite3RefillIndex(pParse, pIndex, iMem); sqlite3RefillIndex(pParse, pIndex, iMem);
sqlite3ChangeCookie(pParse, iDb); sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0);
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1); sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
} }

View File

@ -1621,6 +1621,10 @@ cmd ::= ALTER TABLE add_column_fullname
Y.n = (int)(pParse->sLastToken.z-Y.z) + pParse->sLastToken.n; Y.n = (int)(pParse->sLastToken.z-Y.z) + pParse->sLastToken.n;
sqlite3AlterFinishAddColumn(pParse, &Y); sqlite3AlterFinishAddColumn(pParse, &Y);
} }
cmd ::= ALTER TABLE fullname(X) DROP kwcolumn_opt nm(Y). {
sqlite3AlterDropColumn(pParse, X, &Y);
}
add_column_fullname ::= fullname(X). { add_column_fullname ::= fullname(X). {
disableLookaside(pParse); disableLookaside(pParse);
sqlite3AlterBeginAddColumn(pParse, X); sqlite3AlterBeginAddColumn(pParse, X);

View File

@ -21,7 +21,7 @@
*/ */
static void corruptSchema( static void corruptSchema(
InitData *pData, /* Initialization context */ InitData *pData, /* Initialization context */
const char *zObj, /* Object being parsed at the point of error */ char **azObj, /* Type and name of object being parsed */
const char *zExtra /* Error information */ const char *zExtra /* Error information */
){ ){
sqlite3 *db = pData->db; sqlite3 *db = pData->db;
@ -29,14 +29,18 @@ static void corruptSchema(
pData->rc = SQLITE_NOMEM_BKPT; pData->rc = SQLITE_NOMEM_BKPT;
}else if( pData->pzErrMsg[0]!=0 ){ }else if( pData->pzErrMsg[0]!=0 ){
/* A error message has already been generated. Do not overwrite it */ /* A error message has already been generated. Do not overwrite it */
}else if( pData->mInitFlags & INITFLAG_AlterTable ){ }else if( pData->mInitFlags & (INITFLAG_AlterRename|INITFLAG_AlterDrop) ){
*pData->pzErrMsg = sqlite3DbStrDup(db, zExtra); *pData->pzErrMsg = sqlite3MPrintf(db,
"error in %s %s after %s: %s", azObj[0], azObj[1],
(pData->mInitFlags & INITFLAG_AlterRename) ? "rename" : "drop column",
zExtra
);
pData->rc = SQLITE_ERROR; pData->rc = SQLITE_ERROR;
}else if( db->flags & SQLITE_WriteSchema ){ }else if( db->flags & SQLITE_WriteSchema ){
pData->rc = SQLITE_CORRUPT_BKPT; pData->rc = SQLITE_CORRUPT_BKPT;
}else{ }else{
char *z; char *z;
if( zObj==0 ) zObj = "?"; const char *zObj = azObj[1] ? azObj[1] : "?";
z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
*pData->pzErrMsg = z; *pData->pzErrMsg = z;
@ -94,14 +98,14 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
db->mDbFlags |= DBFLAG_EncodingFixed; db->mDbFlags |= DBFLAG_EncodingFixed;
pData->nInitRow++; pData->nInitRow++;
if( db->mallocFailed ){ if( db->mallocFailed ){
corruptSchema(pData, argv[1], 0); corruptSchema(pData, argv, 0);
return 1; return 1;
} }
assert( iDb>=0 && iDb<db->nDb ); assert( iDb>=0 && iDb<db->nDb );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[3]==0 ){ if( argv[3]==0 ){
corruptSchema(pData, argv[1], 0); corruptSchema(pData, argv, 0);
}else if( argv[4] }else if( argv[4]
&& 'c'==sqlite3UpperToLower[(unsigned char)argv[4][0]] && 'c'==sqlite3UpperToLower[(unsigned char)argv[4][0]]
&& 'r'==sqlite3UpperToLower[(unsigned char)argv[4][1]] ){ && 'r'==sqlite3UpperToLower[(unsigned char)argv[4][1]] ){
@ -126,7 +130,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|| (db->init.newTnum>pData->mxPage && pData->mxPage>0) || (db->init.newTnum>pData->mxPage && pData->mxPage>0)
){ ){
if( sqlite3Config.bExtraSchemaChecks ){ if( sqlite3Config.bExtraSchemaChecks ){
corruptSchema(pData, argv[1], "invalid rootpage"); corruptSchema(pData, argv, "invalid rootpage");
} }
} }
db->init.orphanTrigger = 0; db->init.orphanTrigger = 0;
@ -145,13 +149,13 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
if( rc==SQLITE_NOMEM ){ if( rc==SQLITE_NOMEM ){
sqlite3OomFault(db); sqlite3OomFault(db);
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){ }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
corruptSchema(pData, argv[1], sqlite3_errmsg(db)); corruptSchema(pData, argv, sqlite3_errmsg(db));
} }
} }
} }
sqlite3_finalize(pStmt); sqlite3_finalize(pStmt);
}else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){ }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
corruptSchema(pData, argv[1], 0); corruptSchema(pData, argv, 0);
}else{ }else{
/* If the SQL column is blank it means this is an index that /* If the SQL column is blank it means this is an index that
** was created to be the PRIMARY KEY or to fulfill a UNIQUE ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
@ -162,7 +166,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
Index *pIndex; Index *pIndex;
pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName); pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
if( pIndex==0 ){ if( pIndex==0 ){
corruptSchema(pData, argv[1], "orphan index"); corruptSchema(pData, argv, "orphan index");
}else }else
if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0 if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0
|| pIndex->tnum<2 || pIndex->tnum<2
@ -170,7 +174,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|| sqlite3IndexHasDuplicateRootPage(pIndex) || sqlite3IndexHasDuplicateRootPage(pIndex)
){ ){
if( sqlite3Config.bExtraSchemaChecks ){ if( sqlite3Config.bExtraSchemaChecks ){
corruptSchema(pData, argv[1], "invalid rootpage"); corruptSchema(pData, argv, "invalid rootpage");
} }
} }
} }

View File

@ -262,7 +262,7 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
** Return the index of a column in a table. Return -1 if the column ** Return the index of a column in a table. Return -1 if the column
** is not contained in the table. ** is not contained in the table.
*/ */
static int columnIndex(Table *pTab, const char *zCol){ int sqlite3ColumnIndex(Table *pTab, const char *zCol){
int i; int i;
u8 h = sqlite3StrIHash(zCol); u8 h = sqlite3StrIHash(zCol);
Column *pCol; Column *pCol;
@ -294,7 +294,7 @@ static int tableAndColumnIndex(
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */ assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
for(i=0; i<N; i++){ for(i=0; i<N; i++){
iCol = columnIndex(pSrc->a[i].pTab, zCol); iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol);
if( iCol>=0 if( iCol>=0
&& (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0) && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
){ ){
@ -504,7 +504,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
int iRightCol; /* Column number of matching column on the right */ int iRightCol; /* Column number of matching column on the right */
zName = pList->a[j].zName; zName = pList->a[j].zName;
iRightCol = columnIndex(pRightTab, zName); iRightCol = sqlite3ColumnIndex(pRightTab, zName);
if( iRightCol<0 if( iRightCol<0
|| !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 0) || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 0)
){ ){

View File

@ -3716,7 +3716,8 @@ typedef struct {
/* /*
** Allowed values for mInitFlags ** Allowed values for mInitFlags
*/ */
#define INITFLAG_AlterTable 0x0001 /* This is a reparse after ALTER TABLE */ #define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */
#define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */
/* /*
** Structure containing global configuration data for the SQLite library. ** Structure containing global configuration data for the SQLite library.
@ -4536,6 +4537,7 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
#endif #endif
int sqlite3JoinType(Parse*, Token*, Token*, Token*); int sqlite3JoinType(Parse*, Token*, Token*, Token*);
int sqlite3ColumnIndex(Table *pTab, const char *zCol);
void sqlite3SetJoinExpr(Expr*,int); void sqlite3SetJoinExpr(Expr*,int);
void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
void sqlite3DeferForeignKey(Parse*, int); void sqlite3DeferForeignKey(Parse*, int);
@ -4720,6 +4722,7 @@ int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
void sqlite3ColumnDefault(Vdbe *, Table *, int, int); void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
void sqlite3AlterFinishAddColumn(Parse *, Token *); void sqlite3AlterFinishAddColumn(Parse *, Token *);
void sqlite3AlterBeginAddColumn(Parse *, SrcList *); void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
void sqlite3AlterDropColumn(Parse*, SrcList*, Token*);
void *sqlite3RenameTokenMap(Parse*, void*, Token*); void *sqlite3RenameTokenMap(Parse*, void*, Token*);
void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom); void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom);
void sqlite3RenameExprUnmap(Parse*, Expr*); void sqlite3RenameExprUnmap(Parse*, Expr*);

View File

@ -356,7 +356,7 @@ void sqlite3FinishTrigger(
sqlite3DbFree(db, z); sqlite3DbFree(db, z);
sqlite3ChangeCookie(pParse, iDb); sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName)); sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0);
} }
if( db->init.busy ){ if( db->init.busy ){

View File

@ -6330,7 +6330,7 @@ case OP_ParseSchema: {
if( pOp->p4.z==0 ){ if( pOp->p4.z==0 ){
sqlite3SchemaClear(db->aDb[iDb].pSchema); sqlite3SchemaClear(db->aDb[iDb].pSchema);
db->mDbFlags &= ~DBFLAG_SchemaKnownOk; db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable); rc = sqlite3InitOne(db, iDb, &p->zErrMsg, pOp->p5);
db->mDbFlags |= DBFLAG_SchemaChange; db->mDbFlags |= DBFLAG_SchemaChange;
p->expired = 0; p->expired = 0;
}else }else

View File

@ -223,7 +223,7 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
#else #else
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/ # define sqlite3ExplainBreakpoint(A,B) /*no-op*/
#endif #endif
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16);
void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8); void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);

View File

@ -471,9 +471,10 @@ void sqlite3VdbeExplainPop(Parse *pParse){
** The zWhere string must have been obtained from sqlite3_malloc(). ** The zWhere string must have been obtained from sqlite3_malloc().
** This routine will take ownership of the allocated memory. ** This routine will take ownership of the allocated memory.
*/ */
void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){ void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){
int j; int j;
sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
sqlite3VdbeChangeP5(p, p5);
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j); for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
sqlite3MayAbort(p->pParse); sqlite3MayAbort(p->pParse);
} }

View File

@ -489,7 +489,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddOp0(v, OP_Expire); sqlite3VdbeAddOp0(v, OP_Expire);
zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt); zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere, 0);
sqlite3DbFree(db, zStmt); sqlite3DbFree(db, zStmt);
iReg = ++pParse->nMem; iReg = ++pParse->nMem;

View File

@ -95,4 +95,21 @@ do_auth_test 1.2 {
{SQLITE_UPDATE sqlite_temp_master sql temp {}} {SQLITE_UPDATE sqlite_temp_master sql temp {}}
} }
do_auth_test 1.3 {
ALTER TABLE t2 DROP COLUMN c;
} {
{SQLITE_FUNCTION {} like {} {}}
{SQLITE_FUNCTION {} sqlite_drop_column {} {}}
{SQLITE_FUNCTION {} sqlite_rename_test {} {}}
{SQLITE_READ sqlite_master name main {}}
{SQLITE_READ sqlite_master sql main {}}
{SQLITE_READ sqlite_master tbl_name main {}}
{SQLITE_READ sqlite_master type main {}}
{SQLITE_READ sqlite_temp_master name temp {}}
{SQLITE_READ sqlite_temp_master sql temp {}}
{SQLITE_READ sqlite_temp_master type temp {}}
{SQLITE_SELECT {} {} {} {}}
{SQLITE_UPDATE sqlite_master sql main {}}
}
finish_test finish_test

100
test/altercorrupt.test Normal file
View File

@ -0,0 +1,100 @@
# 2019-01-11
#
# 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix altercorrupt
database_may_be_corrupt
#--------------------------------------------------------------------------
reset_db
do_test 1.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 24576 pagesize 4096 filename crash-685346d89b5e5f.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
| 32: 00 00 63 00 00 05 f0 00 00 00 00 04 10 00 00 04 ..c.............
| 48: 00 00 00 00 00 00 0f f0 00 00 00 01 00 00 00 00 ................
| 64: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 96: 00 00 00 00 0d 0f f8 00 05 0e cf 00 0f 79 0f d3 .............y..
| 112: 0f 2e 0e f3 0e cf 00 00 00 00 00 00 00 00 00 00 ................
| 3776: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................
| 3792: 05 06 17 11 11 01 31 74 61 62 6c 65 74 34 74 34 ......1tablet4t4
| 3808: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 34 .CREATE TABLE t4
| 3824: 28 7a 29 39 04 06 17 11 11 01 5f 74 61 62 6c 65 (z)9......_table
| 3840: 74 33 74 33 05 43 52 45 41 54 45 20 54 41 42 4c t3t3.CREATE TABL
| 3856: 45 20 74 33 28 78 20 49 4e 54 45 47 45 52 20 50 E t3(x INTEGER P
| 3872: 52 49 4d 41 52 59 20 4b 45 59 2c 20 79 29 49 03 RIMARY KEY, y)I.
| 3888: 06 17 11 11 01 7f 74 61 62 6c 65 74 32 74 32 04 ......tablet2t2.
| 3904: 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 32 28 CREATE TABLE t2(
| 3920: 61 2c 62 2c 63 20 50 52 49 4d 41 52 59 20 4b 45 a,b,c PRIMARY KE
| 3936: 59 2c 20 64 2c 20 65 2c 20 66 29 20 57 49 54 48 Y, d, e, f) WITH
| 3952: 4f 55 54 20 52 4f 57 49 44 58 03 07 17 11 11 01 OUT ROWIDX......
| 3968: 81 1b 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 ..tablet1t1.CREA
| 3984: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 2c TE TABLE t1(a,b,
| 4000: 63 20 41 53 20 28 2d 62 29 20 56 49 52 54 55 41 c AS (-b) VIRTUA
| 4016: 4c 2c 64 20 43 48 45 43 4b 28 64 3e 35 29 2c 65 L,d CHECK(d>5),e
| 4032: 20 55 4e 49 51 55 45 2c 20 66 20 41 53 20 28 2b UNIQUE, f AS (+
| 4048: 62 29 29 23 02 06 17 37 11 01 00 69 6e 64 65 78 b))#...7...index
| 4064: 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e 64 65 78 sqlite_autoindex
| 4080: 5f 74 31 5f 31 74 31 03 00 00 00 08 00 00 00 00 _t1_1t1.........
| page 2 offset 4096
| 0: 0d 00 00 00 0a 0f 93 00 0f f6 0f eb 0f e0 0f d5 ................
| 16: 0f ca 0f 8f 0f b4 0f a9 0f 9e 0f 93 00 00 00 00 ................
| 3984: 00 00 00 09 0a 05 01 01 01 01 0a 64 6e 14 09 09 ...........dn...
| 4000: 05 01 01 01 01 09 5a 6d 12 09 08 05 01 01 01 01 ......Zm........
| 4016: 08 50 6c 10 09 07 05 01 01 01 01 07 46 6b 0e 09 .Pl.........Fk..
| 4032: 06 05 01 01 01 01 06 3c 6a 0c 09 05 05 01 01 01 .......<j.......
| 4048: 01 05 32 69 0a 09 04 05 01 01 01 01 04 28 68 08 ..2i.........(h.
| 4064: 09 03 05 01 01 01 01 03 1e 67 06 09 02 05 01 01 .........g......
| 4080: 01 01 02 14 66 04 08 01 05 09 01 01 01 0a 65 02 ....f.........e.
| page 3 offset 8192
| 0: 0a 00 00 00 0a 0f c5 00 0f fb 0f f5 0f ef 0f e9 ................
| 16: 0f e3 0f dd 0f d7 0f d1 0f cb 0f c5 00 00 00 00 ................
| 4032: 00 00 00 00 00 05 03 01 01 14 0a 05 03 01 01 12 ................
| 4048: 09 05 03 01 01 10 08 05 03 01 01 0e 07 05 03 01 ................
| 4064: 01 0c 06 05 03 01 01 0a 05 05 03 01 01 08 04 05 ................
| 4080: 03 01 01 06 03 05 03 01 01 04 02 04 03 01 09 02 ................
| page 4 offset 12288
| 0: 0a 00 00 00 0a 0f 75 00 0f 75 0f 83 0f 91 0f 9f ......u..u......
| 16: 0f ad 0f bb 0f 00 00 00 00 00 00 00 00 00 00 00 ................
| 3952: 00 00 00 00 00 0d 07 01 01 01 01 01 01 9c 0a 64 ...............d
| 3968: 6e 14 64 0d 07 02 01 01 01 01 01 a6 09 5a 6d 12 n.d..........Zm.
| 3984: 5a 0d 07 01 01 01 01 01 01 b0 08 50 6c 10 50 0d Z..........Pl.P.
| 4000: 07 01 01 01 01 01 01 ba 07 46 6b 0e 46 0d 07 01 .........Fk.F...
| 4016: 01 01 01 01 01 c4 06 3c 6a 0c 3c 0d 07 01 01 01 .......<j.<.....
| 4032: 01 01 01 ce 05 32 69 0a 32 0d 07 01 01 01 01 01 .....2i.2.......
| 4048: 01 d8 04 28 68 08 28 0d 07 01 01 01 01 01 01 e2 ...(h.(.........
| 4064: 03 1e 67 06 1e 0d 07 01 01 01 01 01 01 ec 02 14 ..g.............
| 4080: 66 04 14 0c 07 01 09 01 01 01 01 f6 0a 65 02 0a f............e..
| page 5 offset 16384
| 0: 0d 00 00 00 03 0f e9 00 0f e9 0f fb 0f f6 00 00 ................
| 16: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 00 03 ff ff ff ff ff ff ................
| 4080: ff ff 9c 03 00 00 03 64 03 00 00 03 01 03 00 00 .......d........
| page 6 offset 20480
| 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................
| end crash-685346d89b5e5f.db
}]} {}
do_execsql_test 1.1 {
ALTER TABLE t2 DROP COLUMN e;
}
do_catchsql_test 1.2 {
ALTER TABLE t1 DROP COLUMN f;
} {1 {database disk image is malformed}}
finish_test

258
test/alterdropcol.test Normal file
View File

@ -0,0 +1,258 @@
# 2021 February 16
#
# 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.
#
#*************************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix alterdropcol
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
finish_test
return
}
do_execsql_test 1.0 {
CREATE TABLE t1(a, b, c);
CREATE VIEW v1 AS SELECT * FROM t1;
CREATE TABLE t2(x INTEGER PRIMARY KEY, y, z UNIQUE);
CREATE INDEX t2y ON t2(y);
CREATE TABLE t3(q, r, s);
CREATE INDEX t3rs ON t3(r+s);
}
do_catchsql_test 1.1 {
ALTER TABLE nosuch DROP COLUMN z;
} {1 {no such table: nosuch}}
do_catchsql_test 1.2 {
ALTER TABLE v1 DROP COLUMN c;
} {1 {cannot drop column from view "v1"}}
ifcapable fts5 {
do_execsql_test 1.3.1 {
CREATE VIRTUAL TABLE ft1 USING fts5(one, two);
}
do_catchsql_test 1.3.2 {
ALTER TABLE ft1 DROP COLUMN two;
} {1 {cannot drop column from virtual table "ft1"}}
}
do_catchsql_test 1.4 {
ALTER TABLE sqlite_schema DROP COLUMN sql;
} {1 {table sqlite_master may not be altered}}
do_catchsql_test 1.5 {
ALTER TABLE t1 DROP COLUMN d;
} {1 {no such column: "d"}}
do_execsql_test 1.6.1 {
ALTER TABLE t1 DROP COLUMN b;
}
do_execsql_test 1.6.2 {
SELECT sql FROM sqlite_schema WHERE name = 't1'
} {{CREATE TABLE t1(a, c)}}
do_execsql_test 1.7.1 {
ALTER TABLE t1 DROP COLUMN c;
}
do_execsql_test 1.7.2 {
SELECT sql FROM sqlite_schema WHERE name = 't1'
} {{CREATE TABLE t1(a)}}
do_catchsql_test 1.7.3 {
ALTER TABLE t1 DROP COLUMN a;
} {1 {cannot drop column "a": no other columns exist}}
do_catchsql_test 1.8 {
ALTER TABLE t2 DROP COLUMN z
} {1 {cannot drop UNIQUE column: "z"}}
do_catchsql_test 1.9 {
ALTER TABLE t2 DROP COLUMN x
} {1 {cannot drop PRIMARY KEY column: "x"}}
do_catchsql_test 1.10 {
ALTER TABLE t2 DROP COLUMN y
} {1 {error in index t2y after drop column: no such column: y}}
do_catchsql_test 1.11 {
ALTER TABLE t3 DROP COLUMN s
} {1 {error in index t3rs after drop column: no such column: s}}
#-------------------------------------------------------------------------
foreach {tn wo} {
1 {}
2 {WITHOUT ROWID}
} { eval [string map [list %TN% $tn %WO% $wo] {
reset_db
do_execsql_test 2.%TN%.0 {
CREATE TABLE t1(x, y INTEGER PRIMARY KEY, z) %WO% ;
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES(4, 5, 6);
INSERT INTO t1 VALUES(7, 8, 9);
}
do_execsql_test 2.%TN%.1 {
ALTER TABLE t1 DROP COLUMN x;
SELECT * FROM t1;
} {
2 3 5 6 8 9
}
do_execsql_test 2.%TN%.2 {
ALTER TABLE t1 DROP COLUMN z;
SELECT * FROM t1;
} {
2 5 8
}
}]}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE TABLE t12(a, b, c, CHECK(c>10));
CREATE TABLE t13(a, b, c CHECK(c>10));
}
do_catchsql_test 3.1 {
ALTER TABLE t12 DROP COLUMN c;
} {1 {error in table t12 after drop column: no such column: c}}
do_catchsql_test 3.2 {
ALTER TABLE t13 DROP COLUMN c;
} {0 {}}
#-------------------------------------------------------------------------
# Test that generated columns can be dropped. And that other columns from
# tables that contain generated columns can be dropped.
#
foreach {tn wo vs} {
1 "" ""
2 "" VIRTUAL
3 "" STORED
4 "WITHOUT ROWID" STORED
5 "WITHOUT ROWID" VIRTUAL
} {
reset_db
do_execsql_test 4.$tn.0 "
CREATE TABLE 'my table'(a, b PRIMARY KEY, c AS (a+b) $vs, d) $wo
"
do_execsql_test 4.$tn.1 {
INSERT INTO "my table"(a, b, d) VALUES(1, 2, 'hello');
INSERT INTO "my table"(a, b, d) VALUES(3, 4, 'world');
SELECT * FROM "my table"
} {
1 2 3 hello
3 4 7 world
}
do_execsql_test 4.$tn.2 {
ALTER TABLE "my table" DROP COLUMN c;
}
do_execsql_test 4.$tn.3 {
SELECT * FROM "my table"
} {
1 2 hello
3 4 world
}
do_execsql_test 4.$tn.4 "
CREATE TABLE x1(a, b, c PRIMARY KEY, d AS (b+c) $vs, e) $wo
"
do_execsql_test 4.$tn.5 {
INSERT INTO x1(a, b, c, e) VALUES(1, 2, 3, 4);
INSERT INTO x1(a, b, c, e) VALUES(5, 6, 7, 8);
INSERT INTO x1(a, b, c, e) VALUES(9, 10, 11, 12);
SELECT * FROM x1;
} {
1 2 3 5 4
5 6 7 13 8
9 10 11 21 12
}
do_execsql_test 4.$tn.6 {
ALTER TABLE x1 DROP COLUMN a
}
do_execsql_test 4.$tn.7 {
SELECT * FROM x1
} {
2 3 5 4
6 7 13 8
10 11 21 12
}
do_execsql_test 4.$tn.8 {
ALTER TABLE x1 DROP COLUMN e
}
do_execsql_test 4.$tn.9 {
SELECT * FROM x1
} {
2 3 5
6 7 13
10 11 21
}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
CREATE TABLE p1(a PRIMARY KEY, b UNIQUE);
CREATE TABLE c1(x, y, z REFERENCES p1(c));
CREATE TABLE c2(x, y, z, w REFERENCES p1(b));
}
do_execsql_test 5.1 {
ALTER TABLE c1 DROP COLUMN z;
ALTER TABLE c2 DROP COLUMN z;
SELECT sql FROM sqlite_schema WHERE name IN ('c1', 'c2');
} {
{CREATE TABLE c1(x, y)}
{CREATE TABLE c2(x, y, w REFERENCES p1(b))}
}
do_execsql_test 5.2.1 {
CREATE VIEW v1 AS SELECT d, e FROM p1
}
do_catchsql_test 5.2.2 {
ALTER TABLE c1 DROP COLUMN x
} {1 {error in view v1: no such column: d}}
do_execsql_test 5.3.1 {
DROP VIEW v1;
CREATE VIEW v1 AS SELECT x, y FROM c1;
}
do_catchsql_test 5.3.2 {
ALTER TABLE c1 DROP COLUMN x
} {1 {error in view v1 after drop column: no such column: x}}
do_execsql_test 5.4.1 {
CREATE TRIGGER tr AFTER INSERT ON c1 BEGIN
INSERT INTO p1 VALUES(new.y, new.xyz);
END;
}
do_catchsql_test 5.4.2 {
ALTER TABLE c1 DROP COLUMN y
} {1 {error in trigger tr: no such column: new.xyz}}
do_execsql_test 5.5.1 {
DROP TRIGGER tr;
CREATE TRIGGER tr AFTER INSERT ON c1 BEGIN
INSERT INTO p1 VALUES(new.y, new.z);
END;
}
do_catchsql_test 5.5.2 {
ALTER TABLE c1 DROP COLUMN y
} {1 {error in trigger tr: no such column: new.z}}
finish_test

View File

@ -40,7 +40,7 @@ do_execsql_test 1.1 {
# slightly different - it rejects the change and rolls back the transaction. # slightly different - it rejects the change and rolls back the transaction.
do_catchsql_test 1.2 { do_catchsql_test 1.2 {
ALTER TABLE t1 RENAME TO t1new; ALTER TABLE t1 RENAME TO t1new;
} {1 {no such column: t1.a}} } {1 {error in table t1new after rename: no such column: t1.a}}
do_execsql_test 1.3 { do_execsql_test 1.3 {
CREATE TABLE t3(c, d); CREATE TABLE t3(c, d);
@ -59,7 +59,7 @@ do_execsql_test 1.4 {
do_catchsql_test 1.3 { do_catchsql_test 1.3 {
ALTER TABLE t2 RENAME TO t2new; ALTER TABLE t2 RENAME TO t2new;
} {1 {no such column: t2.b}} } {1 {error in index t2expr after rename: no such column: t2.b}}
do_execsql_test 1.4 { do_execsql_test 1.4 {
SELECT sql FROM sqlite_master SELECT sql FROM sqlite_master
} { } {

40
test/altermalloc3.test Normal file
View File

@ -0,0 +1,40 @@
# 2021 February 18
#
# 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.
#
#*************************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix altermalloc3
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
finish_test
return
}
do_execsql_test 1.0 {
CREATE TABLE t1(a, b, c, d, PRIMARY KEY(d, b)) WITHOUT ROWID;
INSERT INTO t1 VALUES(1, 2, 3, 4);
}
faultsim_save_and_close
do_faultsim_test 1 -prep {
faultsim_restore_and_reopen
} -body {
execsql { ALTER TABLE t1 DROP COLUMN c }
} -test {
faultsim_test_result {0 {}}
}
finish_test

View File

@ -29,7 +29,7 @@ do_execsql_test 1.0 {
do_catchsql_test 1.1 { do_catchsql_test 1.1 {
ALTER TABLE t1_content RENAME c0a TO docid; ALTER TABLE t1_content RENAME c0a TO docid;
} {1 {duplicate column name: docid}} } {1 {error in table t1_content after rename: duplicate column name: docid}}
do_catchsql_test 1.2 { do_catchsql_test 1.2 {
UPDATE t1 SET Col0 = 1 ; UPDATE t1 SET Col0 = 1 ;