mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Have ALTER TABLE RENAME edit column references in CREATE VIEW statements.
FossilOrigin-Name: db829dc1a2d7afa49798a2fd32d1f070185b23e513416e65d8144fda24f23b50
This commit is contained in:
39
manifest
39
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Edit\sthe\sWHEN\sand\sUPDATE\sOF\sclauses\sof\strigger\sprograms\sas\spart\sof\sALTER\sTABLE\nRENAME\sCOLUMN.
|
C Have\sALTER\sTABLE\sRENAME\sedit\scolumn\sreferences\sin\sCREATE\sVIEW\sstatements.
|
||||||
D 2018-08-13T17:14:26.913
|
D 2018-08-14T20:18:50.875
|
||||||
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 Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
|
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
|
||||||
@@ -432,7 +432,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 9f8231841d00ef09d328ecb39af46e0cd85ce4e39d416319d458f8aff7af10dd
|
F src/alter.c 03a90ab39849f7f7ba3c637cc8fa663e2e0464b7fcb30c689db594b0a0db694e
|
||||||
F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9
|
F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9
|
||||||
F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a
|
F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a
|
||||||
F src/auth.c 32a5bbe3b755169ab6c66311c5225a3cd4f75a46c041f7fb117e0cbb68055114
|
F src/auth.c 32a5bbe3b755169ab6c66311c5225a3cd4f75a46c041f7fb117e0cbb68055114
|
||||||
@@ -442,7 +442,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
|||||||
F src/btree.c 3f5e1a03db871e627bf5da21092bf7434ecfc5c5980bbd7d45eba13341340173
|
F src/btree.c 3f5e1a03db871e627bf5da21092bf7434ecfc5c5980bbd7d45eba13341340173
|
||||||
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
|
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
|
||||||
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
|
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
|
||||||
F src/build.c 49cad074fcc2218f45e126375b4d8f7c3960d2fe2c3398bad862e1bfd640d7c4
|
F src/build.c a2e61e716e7d90e382d71818404472207024ecb94a44431ac9fcf1ac3b8c3066
|
||||||
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
|
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
|
||||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||||
F src/ctime.c b157b01081f92442f8b0218ddb93ddce8ebddad36dbddeecfdd771561dd4f387
|
F src/ctime.c b157b01081f92442f8b0218ddb93ddce8ebddad36dbddeecfdd771561dd4f387
|
||||||
@@ -459,7 +459,7 @@ F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
|
|||||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||||
F src/insert.c 894594952bcda1dc6e1549871e4022517563545ffc7a3f4e9e5f3faa788893fd
|
F src/insert.c c723716f0de7aa0a679300f7d3541c89645f4a9882161cecdb3093fc07f8cc4b
|
||||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||||
F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b
|
F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b
|
||||||
F src/main.c df233667bbb6f05a8492ea93e0995abbeb816eab53e51e638a0dece1de0e83a3
|
F src/main.c df233667bbb6f05a8492ea93e0995abbeb816eab53e51e638a0dece1de0e83a3
|
||||||
@@ -482,7 +482,7 @@ F src/os.c 8aeb0b0f40f8f5b0da03fe49706695adaf42d2f516ab95abc72e86c245e119de
|
|||||||
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
|
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
|
||||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||||
F src/os_unix.c d9cf5ae0c79f31019d8325e8736c83914aeed64d8327a8d91a62b6439b748948
|
F src/os_unix.c e681b2a3ab1085be3eb2e81254449782ca0bd0c38b73c48cb0c2480b8f2f25b9
|
||||||
F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971
|
F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971
|
||||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||||
F src/pager.c 76d29b8a960dcb8b67210f095899d91e4a90673a6674ea58cfd1115b705a7fb9
|
F src/pager.c 76d29b8a960dcb8b67210f095899d91e4a90673a6674ea58cfd1115b705a7fb9
|
||||||
@@ -493,7 +493,7 @@ F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
|||||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||||
F src/pragma.c 873b767f233932e97cbffd094aa61928be90aca03f946a94bb29ce5695e4885b
|
F src/pragma.c 873b767f233932e97cbffd094aa61928be90aca03f946a94bb29ce5695e4885b
|
||||||
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
||||||
F src/prepare.c 540a24af1b579d9c3f9d37c381f84a1a91fbac656d16c88496a0b73c3e064a11
|
F src/prepare.c 117e27c6826a83f461986c0cfbb09c31fe004922ce23a61bf78d82a46b0958d9
|
||||||
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
|
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
|
||||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||||
F src/resolve.c b51a48f33da36e0c2dd1ea5f0d10197c3e938a54086a69efce064ae41e2254e1
|
F src/resolve.c b51a48f33da36e0c2dd1ea5f0d10197c3e938a54086a69efce064ae41e2254e1
|
||||||
@@ -503,7 +503,7 @@ F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1
|
|||||||
F src/sqlite.h.in c6451bb876adced3aba5b1682c6317d215c5eceaba21a6ce979e71a0b8d0bf95
|
F src/sqlite.h.in c6451bb876adced3aba5b1682c6317d215c5eceaba21a6ce979e71a0b8d0bf95
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
|
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
|
||||||
F src/sqliteInt.h 6a5d65117068808e2f37035d97a4cea6d55d679e02f9673b2b71ae6d5a0b1c8d
|
F src/sqliteInt.h c3bca346f053c0d2fe08f0813b0521597bbab11ff8195348372005606c309f84
|
||||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||||
@@ -569,11 +569,11 @@ F src/upsert.c 47edd408cc73f8d3c00a140550d1ad180b407c146285947969dd09874802bf88
|
|||||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||||
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
||||||
F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
|
F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
|
||||||
F src/vdbe.c a8dbb4cea2582818f8e253c904fec13ef1f1b6ff50517f7b8962a2ce9e5aad02
|
F src/vdbe.c 18482b9a1ac73c62487dd034da342d464ab9b59cae2abfb4cb234ba8fa7ba16f
|
||||||
F src/vdbe.h d93abdc8bc9295e0a256e582c19f548c545dc498319d108bbc9dd29de31c48a2
|
F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907
|
||||||
F src/vdbeInt.h 8ea493d994c6697cf7bccc60583a80a0222560490410f60f1113e90d36643ce0
|
F src/vdbeInt.h 8ea493d994c6697cf7bccc60583a80a0222560490410f60f1113e90d36643ce0
|
||||||
F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611
|
F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611
|
||||||
F src/vdbeaux.c b610cef3d8d381c9287d02c2e61590acc0a1b4de1cc0188d560f5ef345527a24
|
F src/vdbeaux.c f03d4a1961ec282abaec5dbf7e5576ddb1eb01e6157335a232d8d9e57fd5eca1
|
||||||
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
|
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
|
||||||
F src/vdbemem.c 720df42ad8e5c7cb883573de40a185afef4a214903098a16f2bb14b62b2399b7
|
F src/vdbemem.c 720df42ad8e5c7cb883573de40a185afef4a214903098a16f2bb14b62b2399b7
|
||||||
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
|
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
|
||||||
@@ -599,7 +599,7 @@ F test/alter.test b820ab9dcf85f8e3a65bc8326accb2f0c7be64ef
|
|||||||
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||||
F test/alter3.test 4d79934d812eaeacc6f22781a080f8cfe012fdc3
|
F test/alter3.test 4d79934d812eaeacc6f22781a080f8cfe012fdc3
|
||||||
F test/alter4.test b6d7b86860111864f6cddb54af313f5862dda23b
|
F test/alter4.test b6d7b86860111864f6cddb54af313f5862dda23b
|
||||||
F test/altercol.test b3263a3d663e57e35fcd888614cb2256df42ac1be07d40282c5c6023a47a431b
|
F test/altercol.test 98f1c88a9012ce2dbb8765f55557cac12473731a3bce31a8016e133407d235f5
|
||||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||||
F test/analyze.test b3a9c67d00e1df7588a5b7be9a0292899f94fe8cac1f94a017277474ca2e59df
|
F test/analyze.test b3a9c67d00e1df7588a5b7be9a0292899f94fe8cac1f94a017277474ca2e59df
|
||||||
@@ -1502,7 +1502,7 @@ F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945
|
|||||||
F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359
|
F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359
|
||||||
F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
|
F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
|
||||||
F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
|
F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
|
||||||
F test/trigger7.test 799c9d2561facef70340cc9e0dee98aee9b5bdfe
|
F test/trigger7.test 93cfa9b48ab9104b2b3d87bc544ac8021405643e36f23ee84635fbfaf9b8fef5
|
||||||
F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
|
F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
|
||||||
F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41
|
F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41
|
||||||
F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332
|
F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332
|
||||||
@@ -1528,7 +1528,7 @@ F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
|
|||||||
F test/unordered.test ffeea7747d5ba962a8009a20b7e53d68cbae05b063604c68702c5998eb50c981
|
F test/unordered.test ffeea7747d5ba962a8009a20b7e53d68cbae05b063604c68702c5998eb50c981
|
||||||
F test/update.test 1148de8d913e9817717990603aadeca07aab9ddbb10a30f167cbfd8d3a3ccb60
|
F test/update.test 1148de8d913e9817717990603aadeca07aab9ddbb10a30f167cbfd8d3a3ccb60
|
||||||
F test/update2.test 5e67667e1c54017d964e626db765cf8bedcf87483c184f4c575bdb8c1dd2313e
|
F test/update2.test 5e67667e1c54017d964e626db765cf8bedcf87483c184f4c575bdb8c1dd2313e
|
||||||
F test/upsert1.test ecd8f69e20183f298464992762fee24750508b3cbefc5badba8a259a3fc887ec
|
F test/upsert1.test 994bde41800bb77dbe32fcd2e1f6c4b49cc9f2c6cd345731c774dff02b51c110
|
||||||
F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
|
F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
|
||||||
F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
|
F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
|
||||||
F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5
|
F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5
|
||||||
@@ -1756,11 +1756,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 32edc8920376aabb84ebe1900eaa9512d23f1b44d6459e4916dc6b07db66e27c
|
P 5fdb6b0aafba727139e1937ef5950e4434a77f95a10fc46f8010ca2de3922326
|
||||||
R 4f99214f849ec616e294c625bebc2173
|
R 9599d9a5f29aa1850ea700a8d90d37c9
|
||||||
T *branch * edit-trigger-wrapper
|
T +closed 4b575b8050cdb703df26d28228a60b88f60e5279453ba71c65e0739575609a0b
|
||||||
T *sym-edit-trigger-wrapper *
|
|
||||||
T +closed 43c3d2d707a7c54dcb75660be9347d6bd79c4844f81f6ed73446570876f5f72b
|
|
||||||
T -sym-alter-table-rename-column *
|
|
||||||
U dan
|
U dan
|
||||||
Z e89da0f8ef0add6d1c95dbb889527ec9
|
Z 1ded9b508d80d9b5a23b7f7d1204945e
|
||||||
|
@@ -1 +1 @@
|
|||||||
5fdb6b0aafba727139e1937ef5950e4434a77f95a10fc46f8010ca2de3922326
|
db829dc1a2d7afa49798a2fd32d1f070185b23e513416e65d8144fda24f23b50
|
183
src/alter.c
183
src/alter.c
@@ -844,11 +844,14 @@ void sqlite3AlterRenameColumn(
|
|||||||
bQuote = sqlite3Isquote(pNew->z[0]);
|
bQuote = sqlite3Isquote(pNew->z[0]);
|
||||||
sqlite3NestedParse(pParse,
|
sqlite3NestedParse(pParse,
|
||||||
"UPDATE \"%w\".%s SET "
|
"UPDATE \"%w\".%s SET "
|
||||||
"sql = sqlite_rename_column(sql, %d, %d, %Q, %Q, %Q) "
|
"sql = sqlite_rename_column(sql, %Q, %Q, %d, %Q, %d) "
|
||||||
"WHERE name NOT LIKE 'sqlite_%%' AND ("
|
"WHERE name NOT LIKE 'sqlite_%%' AND ("
|
||||||
" type = 'table' OR (type IN ('index', 'trigger') AND tbl_name = %Q)"
|
" type IN ('table', 'view') "
|
||||||
|
" OR (type IN ('index', 'trigger') AND tbl_name = %Q)"
|
||||||
")",
|
")",
|
||||||
zDb, MASTER_NAME, iCol, bQuote, zNew, pTab->zName, zOld, pTab->zName
|
zDb, MASTER_NAME,
|
||||||
|
zDb, pTab->zName, iCol, zNew, bQuote,
|
||||||
|
pTab->zName
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Drop and reload the database schema. */
|
/* Drop and reload the database schema. */
|
||||||
@@ -896,6 +899,7 @@ struct RenameCtx {
|
|||||||
RenameToken *pList; /* List of tokens to overwrite */
|
RenameToken *pList; /* List of tokens to overwrite */
|
||||||
int nList; /* Number of tokens in pList */
|
int nList; /* Number of tokens in pList */
|
||||||
int iCol; /* Index of column being renamed */
|
int iCol; /* Index of column being renamed */
|
||||||
|
Table *pTab; /* Table being ALTERed */
|
||||||
const char *zOld; /* Old column name */
|
const char *zOld; /* Old column name */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -942,7 +946,13 @@ static void renameTokenFree(sqlite3 *db, RenameToken *pToken){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void renameTokenFind(Parse *pParse, RenameCtx *pCtx, void *pPtr){
|
/*
|
||||||
|
** Search the Parse object passed as the first argument for a RenameToken
|
||||||
|
** object associated with parse tree element pPtr. If found, remove it
|
||||||
|
** from the Parse object and add it to the list maintained by the
|
||||||
|
** RenameCtx object passed as the second argument.
|
||||||
|
*/
|
||||||
|
static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
|
||||||
RenameToken **pp;
|
RenameToken **pp;
|
||||||
for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
|
for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
|
||||||
if( (*pp)->p==pPtr ){
|
if( (*pp)->p==pPtr ){
|
||||||
@@ -956,6 +966,20 @@ static void renameTokenFind(Parse *pParse, RenameCtx *pCtx, void *pPtr){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int renameColumnSelectCb(Walker *pWalker, Select *p){
|
||||||
|
return WRC_Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This is a Walker expression callback.
|
||||||
|
**
|
||||||
|
** For every TK_COLUMN node in the expression tree, search to see
|
||||||
|
** if the column being references is the column being renamed by an
|
||||||
|
** ALTER TABLE statement. If it is, then attach its associated
|
||||||
|
** RenameToken object to the list of RenameToken objects being
|
||||||
|
** constructed in RenameCtx object at pWalker->u.pRename.
|
||||||
|
*/
|
||||||
static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
|
static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
|
||||||
RenameCtx *p = pWalker->u.pRename;
|
RenameCtx *p = pWalker->u.pRename;
|
||||||
if( p->zOld && pExpr->op==TK_DOT ){
|
if( p->zOld && pExpr->op==TK_DOT ){
|
||||||
@@ -969,12 +993,23 @@ static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
|
|||||||
renameTokenFind(pWalker->pParse, p, (void*)pRight);
|
renameTokenFind(pWalker->pParse, p, (void*)pRight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol ){
|
}else if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol
|
||||||
|
&& (p->pTab==0 || p->pTab==pExpr->pTab)
|
||||||
|
){
|
||||||
renameTokenFind(pWalker->pParse, p, (void*)pExpr);
|
renameTokenFind(pWalker->pParse, p, (void*)pExpr);
|
||||||
}
|
}
|
||||||
return WRC_Continue;
|
return WRC_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The RenameCtx contains a list of tokens that reference a column that
|
||||||
|
** is being renamed by an ALTER TABLE statement. Return the "first"
|
||||||
|
** RenameToken in the RenameCtx and remove that RenameToken from the
|
||||||
|
** RenameContext. "First" means the first RenameToken encountered when
|
||||||
|
** the input SQL from left to right. Repeated calls to this routine
|
||||||
|
** return all column name tokens in the order that they are encountered
|
||||||
|
** in the SQL statement.
|
||||||
|
*/
|
||||||
static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
|
static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
|
||||||
RenameToken *pBest = pCtx->pList;
|
RenameToken *pBest = pCtx->pList;
|
||||||
RenameToken *pToken;
|
RenameToken *pToken;
|
||||||
@@ -990,7 +1025,31 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** sqlite_rename_column(SQL, iCol, bQuote, zNew, zTable, zOld)
|
** SQL function:
|
||||||
|
**
|
||||||
|
** sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld)
|
||||||
|
**
|
||||||
|
** 0. zSql: SQL statement to rewrite
|
||||||
|
** 1. Database: Database name (e.g. "main")
|
||||||
|
** 2. Table: Table name
|
||||||
|
** 3. iCol: Index of column to rename
|
||||||
|
** 4. zNew: New column name
|
||||||
|
** 5. bQuote: True if the new column name should be quoted
|
||||||
|
**
|
||||||
|
** Do a column rename operation on the CREATE statement given in zSql.
|
||||||
|
** The iCol-th column (left-most is 0) of table zTable is renamed from zCol
|
||||||
|
** into zNew. The name should be quoted if bQuote is true.
|
||||||
|
**
|
||||||
|
** This function is used internally by the ALTER TABLE RENAME COLUMN command.
|
||||||
|
** Though accessible to application code, it is not intended for use by
|
||||||
|
** applications. The existance of this function, and the way it works,
|
||||||
|
** is subject to change without notice.
|
||||||
|
**
|
||||||
|
** If any of the parameters are out-of-bounds, then simply return NULL.
|
||||||
|
** An out-of-bounds parameter can only occur when the application calls
|
||||||
|
** this function directly. The parameters will always be well-formed when
|
||||||
|
** this routine is invoked by the bytecode for a legitimate ALTER TABLE
|
||||||
|
** statement.
|
||||||
*/
|
*/
|
||||||
static void renameColumnFunc(
|
static void renameColumnFunc(
|
||||||
sqlite3_context *context,
|
sqlite3_context *context,
|
||||||
@@ -1001,11 +1060,13 @@ static void renameColumnFunc(
|
|||||||
RenameCtx sCtx;
|
RenameCtx sCtx;
|
||||||
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
||||||
int nSql = sqlite3_value_bytes(argv[0]);
|
int nSql = sqlite3_value_bytes(argv[0]);
|
||||||
int bQuote = sqlite3_value_int(argv[2]);
|
const char *zDb = (const char*)sqlite3_value_text(argv[1]);
|
||||||
const char *zNew = (const char*)sqlite3_value_text(argv[3]);
|
const char *zTable = (const char*)sqlite3_value_text(argv[2]);
|
||||||
int nNew = sqlite3_value_bytes(argv[3]);
|
int iCol = sqlite3_value_int(argv[3]);
|
||||||
const char *zTable = (const char*)sqlite3_value_text(argv[4]);
|
const char *zNew = (const char*)sqlite3_value_text(argv[4]);
|
||||||
const char *zOld = (const char*)sqlite3_value_text(argv[5]);
|
int nNew = sqlite3_value_bytes(argv[4]);
|
||||||
|
int bQuote = sqlite3_value_int(argv[5]);
|
||||||
|
const char *zOld;
|
||||||
|
|
||||||
int rc;
|
int rc;
|
||||||
char *zErr = 0;
|
char *zErr = 0;
|
||||||
@@ -1017,9 +1078,17 @@ static void renameColumnFunc(
|
|||||||
char *zQuot = 0; /* Quoted version of zNew */
|
char *zQuot = 0; /* Quoted version of zNew */
|
||||||
int nQuot = 0; /* Length of zQuot in bytes */
|
int nQuot = 0; /* Length of zQuot in bytes */
|
||||||
int i;
|
int i;
|
||||||
|
Table *pTab;
|
||||||
|
|
||||||
|
if( zSql==0 ) return;
|
||||||
|
if( zNew==0 ) return;
|
||||||
|
if( zTable==0 ) return;
|
||||||
|
if( iCol<0 ) return;
|
||||||
|
pTab = sqlite3FindTable(db, zTable, zDb);
|
||||||
|
if( pTab==0 || iCol>=pTab->nCol ) return;
|
||||||
|
zOld = pTab->aCol[iCol].zName;
|
||||||
memset(&sCtx, 0, sizeof(sCtx));
|
memset(&sCtx, 0, sizeof(sCtx));
|
||||||
sCtx.iCol = sqlite3_value_int(argv[1]);
|
sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);
|
||||||
|
|
||||||
memset(&sParse, 0, sizeof(sParse));
|
memset(&sParse, 0, sizeof(sParse));
|
||||||
sParse.eParseMode = PARSE_MODE_RENAME_COLUMN;
|
sParse.eParseMode = PARSE_MODE_RENAME_COLUMN;
|
||||||
@@ -1043,16 +1112,6 @@ static void renameColumnFunc(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
if( zErr ){
|
|
||||||
sqlite3_result_error(context, zErr, -1);
|
|
||||||
}else{
|
|
||||||
sqlite3_result_error_code(context, rc);
|
|
||||||
}
|
|
||||||
sqlite3DbFree(db, zErr);
|
|
||||||
goto renameColumnFunc_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( bQuote ){
|
if( bQuote ){
|
||||||
zNew = zQuot;
|
zNew = zQuot;
|
||||||
nNew = nQuot;
|
nNew = nQuot;
|
||||||
@@ -1060,7 +1119,7 @@ static void renameColumnFunc(
|
|||||||
|
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
assert( sqlite3Strlen30(zSql)==nSql );
|
assert( sqlite3Strlen30(zSql)==nSql );
|
||||||
{
|
if( rc==SQLITE_OK ){
|
||||||
RenameToken *pToken;
|
RenameToken *pToken;
|
||||||
for(pToken=sParse.pRename; pToken; pToken=pToken->pNext){
|
for(pToken=sParse.pRename; pToken; pToken=pToken->pNext){
|
||||||
assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] );
|
assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] );
|
||||||
@@ -1072,34 +1131,55 @@ static void renameColumnFunc(
|
|||||||
memset(&sWalker, 0, sizeof(Walker));
|
memset(&sWalker, 0, sizeof(Walker));
|
||||||
sWalker.pParse = &sParse;
|
sWalker.pParse = &sParse;
|
||||||
sWalker.xExprCallback = renameColumnExprCb;
|
sWalker.xExprCallback = renameColumnExprCb;
|
||||||
|
sWalker.xSelectCallback = renameColumnSelectCb;
|
||||||
sWalker.u.pRename = &sCtx;
|
sWalker.u.pRename = &sCtx;
|
||||||
|
|
||||||
|
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
|
||||||
if( sParse.pNewTable ){
|
if( sParse.pNewTable ){
|
||||||
int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
|
Select *pSelect = sParse.pNewTable->pSelect;
|
||||||
FKey *pFKey;
|
if( pSelect ){
|
||||||
if( bFKOnly==0 ){
|
sCtx.pTab = pTab;
|
||||||
renameTokenFind(
|
sParse.rc = SQLITE_OK;
|
||||||
&sParse, &sCtx, (void*)sParse.pNewTable->aCol[sCtx.iCol].zName
|
sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, 0);
|
||||||
);
|
rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
|
||||||
assert( sCtx.iCol>=0 );
|
if( rc==SQLITE_OK ){
|
||||||
if( sParse.pNewTable->iPKey==sCtx.iCol ){
|
sqlite3WalkSelect(&sWalker, pSelect);
|
||||||
sCtx.iCol = -1;
|
}else if( rc==SQLITE_ERROR ){
|
||||||
|
/* Failed to resolve all symboles in the view. This is not an
|
||||||
|
** error, but it will not be edited. */
|
||||||
|
sqlite3DbFree(db, sParse.zErrMsg);
|
||||||
|
sParse.zErrMsg = 0;
|
||||||
|
rc = SQLITE_OK;
|
||||||
}
|
}
|
||||||
sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck);
|
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
|
||||||
for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
|
}else{
|
||||||
sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
|
/* A regular table */
|
||||||
}
|
int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
|
||||||
}
|
FKey *pFKey;
|
||||||
|
assert( sParse.pNewTable->pSelect==0 );
|
||||||
for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
if( bFKOnly==0 ){
|
||||||
for(i=0; i<pFKey->nCol; i++){
|
renameTokenFind(
|
||||||
if( bFKOnly==0 && pFKey->aCol[i].iFrom==sCtx.iCol ){
|
&sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zName
|
||||||
renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]);
|
);
|
||||||
|
if( sCtx.iCol<0 ){
|
||||||
|
renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey);
|
||||||
}
|
}
|
||||||
if( 0==sqlite3_stricmp(pFKey->zTo, zTable)
|
sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck);
|
||||||
&& 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld)
|
for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||||
){
|
sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
|
||||||
renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
||||||
|
for(i=0; i<pFKey->nCol; i++){
|
||||||
|
if( bFKOnly==0 && pFKey->aCol[i].iFrom==sCtx.iCol ){
|
||||||
|
renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]);
|
||||||
|
}
|
||||||
|
if( 0==sqlite3_stricmp(pFKey->zTo, zTable)
|
||||||
|
&& 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld)
|
||||||
|
){
|
||||||
|
renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1119,6 +1199,7 @@ static void renameColumnFunc(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert( rc==SQLITE_OK );
|
||||||
assert( nQuot>=nNew );
|
assert( nQuot>=nNew );
|
||||||
zOut = sqlite3DbMallocZero(db, nSql + sCtx.nList*nQuot + 1);
|
zOut = sqlite3DbMallocZero(db, nSql + sCtx.nList*nQuot + 1);
|
||||||
if( zOut ){
|
if( zOut ){
|
||||||
@@ -1152,9 +1233,19 @@ static void renameColumnFunc(
|
|||||||
|
|
||||||
sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
|
sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
|
||||||
sqlite3DbFree(db, zOut);
|
sqlite3DbFree(db, zOut);
|
||||||
|
}else{
|
||||||
|
rc = SQLITE_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
renameColumnFunc_done:
|
renameColumnFunc_done:
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
if( zErr ){
|
||||||
|
sqlite3_result_error(context, zErr, -1);
|
||||||
|
}else{
|
||||||
|
sqlite3_result_error_code(context, rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( sParse.pVdbe ){
|
if( sParse.pVdbe ){
|
||||||
sqlite3VdbeFinalize(sParse.pVdbe);
|
sqlite3VdbeFinalize(sParse.pVdbe);
|
||||||
}
|
}
|
||||||
|
10
src/build.c
10
src/build.c
@@ -1370,6 +1370,9 @@ void sqlite3AddPrimaryKey(
|
|||||||
&& sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
|
&& sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
|
||||||
&& sortOrder!=SQLITE_SO_DESC
|
&& sortOrder!=SQLITE_SO_DESC
|
||||||
){
|
){
|
||||||
|
if( IN_RENAME_COLUMN && pList ){
|
||||||
|
sqlite3MoveRenameToken(pParse, &pTab->iPKey, pList->a[0].pExpr);
|
||||||
|
}
|
||||||
pTab->iPKey = iCol;
|
pTab->iPKey = iCol;
|
||||||
pTab->keyConf = (u8)onError;
|
pTab->keyConf = (u8)onError;
|
||||||
assert( autoInc==0 || autoInc==1 );
|
assert( autoInc==0 || autoInc==1 );
|
||||||
@@ -2172,7 +2175,12 @@ void sqlite3CreateView(
|
|||||||
** allocated rather than point to the input string - which means that
|
** allocated rather than point to the input string - which means that
|
||||||
** they will persist after the current sqlite3_exec() call returns.
|
** they will persist after the current sqlite3_exec() call returns.
|
||||||
*/
|
*/
|
||||||
p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
if( IN_RENAME_COLUMN ){
|
||||||
|
p->pSelect = pSelect;
|
||||||
|
pSelect = 0;
|
||||||
|
}else{
|
||||||
|
p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
||||||
|
}
|
||||||
p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
|
p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
|
||||||
if( db->mallocFailed ) goto create_view_fail;
|
if( db->mallocFailed ) goto create_view_fail;
|
||||||
|
|
||||||
|
117
src/insert.c
117
src/insert.c
@@ -1178,44 +1178,6 @@ static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
|
|||||||
return !w.eCode;
|
return !w.eCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** An instance of the ConstraintAddr object remembers the byte-code addresses
|
|
||||||
** for sections of the constraint checks that deal with uniqueness constraints
|
|
||||||
** on the rowid and on the upsert constraint.
|
|
||||||
**
|
|
||||||
** This information is passed into checkReorderConstraintChecks() to insert
|
|
||||||
** some OP_Goto operations so that the rowid and upsert constraints occur
|
|
||||||
** in the correct order relative to other constraints.
|
|
||||||
*/
|
|
||||||
typedef struct ConstraintAddr ConstraintAddr;
|
|
||||||
struct ConstraintAddr {
|
|
||||||
int ipkTop; /* Subroutine for rowid constraint check */
|
|
||||||
int upsertTop; /* Label for upsert constraint check subroutine */
|
|
||||||
int upsertTop2; /* Copy of upsertTop not cleared by the call */
|
|
||||||
int upsertBtm; /* upsert constraint returns to this label */
|
|
||||||
int ipkBtm; /* Return opcode rowid constraint check */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Generate any OP_Goto operations needed to cause constraints to be
|
|
||||||
** run that haven't already been run.
|
|
||||||
*/
|
|
||||||
static void reorderConstraintChecks(Vdbe *v, ConstraintAddr *p){
|
|
||||||
if( p->upsertTop ){
|
|
||||||
testcase( sqlite3VdbeLabelHasBeenResolved(v, p->upsertTop) );
|
|
||||||
sqlite3VdbeGoto(v, p->upsertTop);
|
|
||||||
VdbeComment((v, "call upsert subroutine"));
|
|
||||||
sqlite3VdbeResolveLabel(v, p->upsertBtm);
|
|
||||||
p->upsertTop = 0;
|
|
||||||
}
|
|
||||||
if( p->ipkTop ){
|
|
||||||
sqlite3VdbeGoto(v, p->ipkTop);
|
|
||||||
VdbeComment((v, "call rowid unique-check subroutine"));
|
|
||||||
sqlite3VdbeJumpHere(v, p->ipkBtm);
|
|
||||||
p->ipkTop = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code to do constraint checks prior to an INSERT or an UPDATE
|
** Generate code to do constraint checks prior to an INSERT or an UPDATE
|
||||||
** on table pTab.
|
** on table pTab.
|
||||||
@@ -1325,11 +1287,13 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
int addr1; /* Address of jump instruction */
|
int addr1; /* Address of jump instruction */
|
||||||
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
||||||
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
|
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
|
||||||
ConstraintAddr sAddr;/* Address information for constraint reordering */
|
|
||||||
Index *pUpIdx = 0; /* Index to which to apply the upsert */
|
Index *pUpIdx = 0; /* Index to which to apply the upsert */
|
||||||
u8 isUpdate; /* True if this is an UPDATE operation */
|
u8 isUpdate; /* True if this is an UPDATE operation */
|
||||||
u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
|
u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
|
||||||
int upsertBypass = 0; /* Address of Goto to bypass upsert subroutine */
|
int upsertBypass = 0; /* Address of Goto to bypass upsert subroutine */
|
||||||
|
int upsertJump = 0; /* Address of Goto that jumps into upsert subroutine */
|
||||||
|
int ipkTop = 0; /* Top of the IPK uniqueness check */
|
||||||
|
int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */
|
||||||
|
|
||||||
isUpdate = regOldData!=0;
|
isUpdate = regOldData!=0;
|
||||||
db = pParse->db;
|
db = pParse->db;
|
||||||
@@ -1337,7 +1301,6 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
assert( v!=0 );
|
assert( v!=0 );
|
||||||
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
||||||
nCol = pTab->nCol;
|
nCol = pTab->nCol;
|
||||||
memset(&sAddr, 0, sizeof(sAddr));
|
|
||||||
|
|
||||||
/* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
|
/* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
|
||||||
** normal rowid tables. nPkField is the number of key fields in the
|
** normal rowid tables. nPkField is the number of key fields in the
|
||||||
@@ -1441,8 +1404,8 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
/* UNIQUE and PRIMARY KEY constraints should be handled in the following
|
/* UNIQUE and PRIMARY KEY constraints should be handled in the following
|
||||||
** order:
|
** order:
|
||||||
**
|
**
|
||||||
** (1) OE_Abort, OE_Fail, OE_Rollback, OE_Ignore
|
** (1) OE_Update
|
||||||
** (2) OE_Update
|
** (2) OE_Abort, OE_Fail, OE_Rollback, OE_Ignore
|
||||||
** (3) OE_Replace
|
** (3) OE_Replace
|
||||||
**
|
**
|
||||||
** OE_Fail and OE_Ignore must happen before any changes are made.
|
** OE_Fail and OE_Ignore must happen before any changes are made.
|
||||||
@@ -1451,6 +1414,11 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
** could happen in any order, but they are grouped up front for
|
** could happen in any order, but they are grouped up front for
|
||||||
** convenience.
|
** convenience.
|
||||||
**
|
**
|
||||||
|
** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43
|
||||||
|
** The order of constraints used to have OE_Update as (2) and OE_Abort
|
||||||
|
** and so forth as (1). But apparently PostgreSQL checks the OE_Update
|
||||||
|
** constraint before any others, so it had to be moved.
|
||||||
|
**
|
||||||
** Constraint checking code is generated in this order:
|
** Constraint checking code is generated in this order:
|
||||||
** (A) The rowid constraint
|
** (A) The rowid constraint
|
||||||
** (B) Unique index constraints that do not have OE_Replace as their
|
** (B) Unique index constraints that do not have OE_Replace as their
|
||||||
@@ -1470,11 +1438,10 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
overrideError = OE_Ignore;
|
overrideError = OE_Ignore;
|
||||||
pUpsert = 0;
|
pUpsert = 0;
|
||||||
}else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){
|
}else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){
|
||||||
/* If the constraint-target is on some column other than
|
/* If the constraint-target uniqueness check must be run first.
|
||||||
** then ROWID, then we might need to move the UPSERT around
|
** Jump to that uniqueness check now */
|
||||||
** so that it occurs in the correct order. */
|
upsertJump = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
sAddr.upsertTop = sAddr.upsertTop2 = sqlite3VdbeMakeLabel(v);
|
VdbeComment((v, "UPSERT constraint goes first"));
|
||||||
sAddr.upsertBtm = sqlite3VdbeMakeLabel(v);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1506,16 +1473,12 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
** to defer the running of the rowid conflict checking until after
|
** to defer the running of the rowid conflict checking until after
|
||||||
** the UNIQUE constraints have run.
|
** the UNIQUE constraints have run.
|
||||||
*/
|
*/
|
||||||
assert( OE_Update>OE_Replace );
|
if( onError==OE_Replace /* IPK rule is REPLACE */
|
||||||
assert( OE_Ignore<OE_Replace );
|
&& onError!=overrideError /* Rules for other contraints are different */
|
||||||
assert( OE_Fail<OE_Replace );
|
&& pTab->pIndex /* There exist other constraints */
|
||||||
assert( OE_Abort<OE_Replace );
|
|
||||||
assert( OE_Rollback<OE_Replace );
|
|
||||||
if( onError>=OE_Replace
|
|
||||||
&& (pUpsert || onError!=overrideError)
|
|
||||||
&& pTab->pIndex
|
|
||||||
){
|
){
|
||||||
sAddr.ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
|
ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
|
||||||
|
VdbeComment((v, "defer IPK REPLACE until last"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if( isUpdate ){
|
if( isUpdate ){
|
||||||
@@ -1610,9 +1573,9 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3VdbeResolveLabel(v, addrRowidOk);
|
sqlite3VdbeResolveLabel(v, addrRowidOk);
|
||||||
if( sAddr.ipkTop ){
|
if( ipkTop ){
|
||||||
sAddr.ipkBtm = sqlite3VdbeAddOp0(v, OP_Goto);
|
ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
sqlite3VdbeJumpHere(v, sAddr.ipkTop-1);
|
sqlite3VdbeJumpHere(v, ipkTop-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1630,18 +1593,18 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
|
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
|
||||||
|
|
||||||
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
||||||
if( bAffinityDone==0 ){
|
|
||||||
sqlite3TableAffinity(v, pTab, regNewData+1);
|
|
||||||
bAffinityDone = 1;
|
|
||||||
}
|
|
||||||
if( pUpIdx==pIdx ){
|
if( pUpIdx==pIdx ){
|
||||||
addrUniqueOk = sAddr.upsertBtm;
|
addrUniqueOk = upsertJump+1;
|
||||||
upsertBypass = sqlite3VdbeGoto(v, 0);
|
upsertBypass = sqlite3VdbeGoto(v, 0);
|
||||||
VdbeComment((v, "Skip upsert subroutine"));
|
VdbeComment((v, "Skip upsert subroutine"));
|
||||||
sqlite3VdbeResolveLabel(v, sAddr.upsertTop2);
|
sqlite3VdbeJumpHere(v, upsertJump);
|
||||||
}else{
|
}else{
|
||||||
addrUniqueOk = sqlite3VdbeMakeLabel(v);
|
addrUniqueOk = sqlite3VdbeMakeLabel(v);
|
||||||
}
|
}
|
||||||
|
if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
|
||||||
|
sqlite3TableAffinity(v, pTab, regNewData+1);
|
||||||
|
bAffinityDone = 1;
|
||||||
|
}
|
||||||
VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
|
VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
|
||||||
iThisCur = iIdxCur+ix;
|
iThisCur = iIdxCur+ix;
|
||||||
|
|
||||||
@@ -1713,15 +1676,6 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke subroutines to handle IPK replace and upsert prior to running
|
|
||||||
** the first REPLACE constraint check. */
|
|
||||||
if( onError==OE_Replace ){
|
|
||||||
testcase( sAddr.ipkTop );
|
|
||||||
testcase( sAddr.upsertTop
|
|
||||||
&& sqlite3VdbeLabelHasBeenResolved(v,sAddr.upsertTop) );
|
|
||||||
reorderConstraintChecks(v, &sAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Collision detection may be omitted if all of the following are true:
|
/* Collision detection may be omitted if all of the following are true:
|
||||||
** (1) The conflict resolution algorithm is REPLACE
|
** (1) The conflict resolution algorithm is REPLACE
|
||||||
** (2) The table is a WITHOUT ROWID table
|
** (2) The table is a WITHOUT ROWID table
|
||||||
@@ -1843,18 +1797,21 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( pUpIdx==pIdx ){
|
if( pUpIdx==pIdx ){
|
||||||
|
sqlite3VdbeGoto(v, upsertJump+1);
|
||||||
sqlite3VdbeJumpHere(v, upsertBypass);
|
sqlite3VdbeJumpHere(v, upsertBypass);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||||
}
|
}
|
||||||
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
||||||
|
|
||||||
}
|
}
|
||||||
testcase( sAddr.ipkTop!=0 );
|
|
||||||
testcase( sAddr.upsertTop
|
/* If the IPK constraint is a REPLACE, run it last */
|
||||||
&& sqlite3VdbeLabelHasBeenResolved(v,sAddr.upsertTop) );
|
if( ipkTop ){
|
||||||
reorderConstraintChecks(v, &sAddr);
|
sqlite3VdbeGoto(v, ipkTop+1);
|
||||||
|
VdbeComment((v, "Do IPK REPLACE"));
|
||||||
|
sqlite3VdbeJumpHere(v, ipkBottom);
|
||||||
|
}
|
||||||
|
|
||||||
*pbMayReplace = seenReplace;
|
*pbMayReplace = seenReplace;
|
||||||
VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
|
VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
|
||||||
}
|
}
|
||||||
|
104
src/os_unix.c
104
src/os_unix.c
@@ -702,12 +702,25 @@ static int robust_open(const char *z, int f, mode_t m){
|
|||||||
** unixEnterMutex()
|
** unixEnterMutex()
|
||||||
** assert( unixMutexHeld() );
|
** assert( unixMutexHeld() );
|
||||||
** unixEnterLeave()
|
** unixEnterLeave()
|
||||||
|
**
|
||||||
|
** To prevent deadlock, the global unixBigLock must must be acquired
|
||||||
|
** before the unixInodeInfo.pLockMutex mutex, if both are held. It is
|
||||||
|
** OK to get the pLockMutex without holding unixBigLock first, but if
|
||||||
|
** that happens, the unixBigLock mutex must not be acquired until after
|
||||||
|
** pLockMutex is released.
|
||||||
|
**
|
||||||
|
** OK: enter(unixBigLock), enter(pLockInfo)
|
||||||
|
** OK: enter(unixBigLock)
|
||||||
|
** OK: enter(pLockInfo)
|
||||||
|
** ERROR: enter(pLockInfo), enter(unixBigLock)
|
||||||
*/
|
*/
|
||||||
static sqlite3_mutex *unixBigLock = 0;
|
static sqlite3_mutex *unixBigLock = 0;
|
||||||
static void unixEnterMutex(void){
|
static void unixEnterMutex(void){
|
||||||
|
assert( sqlite3_mutex_notheld(unixBigLock) ); /* Not a recursive mutex */
|
||||||
sqlite3_mutex_enter(unixBigLock);
|
sqlite3_mutex_enter(unixBigLock);
|
||||||
}
|
}
|
||||||
static void unixLeaveMutex(void){
|
static void unixLeaveMutex(void){
|
||||||
|
assert( sqlite3_mutex_held(unixBigLock) );
|
||||||
sqlite3_mutex_leave(unixBigLock);
|
sqlite3_mutex_leave(unixBigLock);
|
||||||
}
|
}
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
@@ -1111,9 +1124,9 @@ struct unixFileId {
|
|||||||
**
|
**
|
||||||
** Mutex rules:
|
** Mutex rules:
|
||||||
**
|
**
|
||||||
** (1) The pLockMutex mutex must be held in order to read or write
|
** (1) Only the pLockMutex mutex must be held in order to read or write
|
||||||
** any of the locking fields:
|
** any of the locking fields:
|
||||||
** nShared, nLock, eFileLock, or bProcessLock
|
** nShared, nLock, eFileLock, bProcessLock, pUnused
|
||||||
**
|
**
|
||||||
** (2) When nRef>0, then the following fields are unchanging and can
|
** (2) When nRef>0, then the following fields are unchanging and can
|
||||||
** be read (but not written) without holding any mutex:
|
** be read (but not written) without holding any mutex:
|
||||||
@@ -1121,6 +1134,10 @@ struct unixFileId {
|
|||||||
**
|
**
|
||||||
** (3) With the exceptions above, all the fields may only be read
|
** (3) With the exceptions above, all the fields may only be read
|
||||||
** or written while holding the global unixBigLock mutex.
|
** or written while holding the global unixBigLock mutex.
|
||||||
|
**
|
||||||
|
** Deadlock prevention: The global unixBigLock mutex may not
|
||||||
|
** be acquired while holding the pLockMutex mutex. If both unixBigLock
|
||||||
|
** and pLockMutex are needed, then unixBigLock must be acquired first.
|
||||||
*/
|
*/
|
||||||
struct unixInodeInfo {
|
struct unixInodeInfo {
|
||||||
struct unixFileId fileId; /* The lookup key */
|
struct unixFileId fileId; /* The lookup key */
|
||||||
@@ -1129,9 +1146,9 @@ struct unixInodeInfo {
|
|||||||
int nLock; /* Number of outstanding file locks */
|
int nLock; /* Number of outstanding file locks */
|
||||||
unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
|
unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
|
||||||
unsigned char bProcessLock; /* An exclusive process lock is held */
|
unsigned char bProcessLock; /* An exclusive process lock is held */
|
||||||
|
UnixUnusedFd *pUnused; /* Unused file descriptors to close */
|
||||||
int nRef; /* Number of pointers to this structure */
|
int nRef; /* Number of pointers to this structure */
|
||||||
unixShmNode *pShmNode; /* Shared memory associated with this inode */
|
unixShmNode *pShmNode; /* Shared memory associated with this inode */
|
||||||
UnixUnusedFd *pUnused; /* Unused file descriptors to close */
|
|
||||||
unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
|
unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
|
||||||
unixInodeInfo *pPrev; /* .... doubly linked */
|
unixInodeInfo *pPrev; /* .... doubly linked */
|
||||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||||
@@ -1147,7 +1164,21 @@ struct unixInodeInfo {
|
|||||||
** A lists of all unixInodeInfo objects.
|
** A lists of all unixInodeInfo objects.
|
||||||
*/
|
*/
|
||||||
static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */
|
static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */
|
||||||
static unsigned int nUnusedFd = 0; /* Total unused file descriptors */
|
|
||||||
|
#ifdef SQLITE_DEBUG
|
||||||
|
/*
|
||||||
|
** True if the inode mutex is held, or not. Used only within assert()
|
||||||
|
** to help verify correct mutex usage.
|
||||||
|
*/
|
||||||
|
int unixFileMutexHeld(unixFile *pFile){
|
||||||
|
assert( pFile->pInode );
|
||||||
|
return sqlite3_mutex_held(pFile->pInode->pLockMutex);
|
||||||
|
}
|
||||||
|
int unixFileMutexNotheld(unixFile *pFile){
|
||||||
|
assert( pFile->pInode );
|
||||||
|
return sqlite3_mutex_notheld(pFile->pInode->pLockMutex);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
**
|
**
|
||||||
@@ -1253,11 +1284,11 @@ static void closePendingFds(unixFile *pFile){
|
|||||||
unixInodeInfo *pInode = pFile->pInode;
|
unixInodeInfo *pInode = pFile->pInode;
|
||||||
UnixUnusedFd *p;
|
UnixUnusedFd *p;
|
||||||
UnixUnusedFd *pNext;
|
UnixUnusedFd *pNext;
|
||||||
|
assert( unixFileMutexHeld(pFile) );
|
||||||
for(p=pInode->pUnused; p; p=pNext){
|
for(p=pInode->pUnused; p; p=pNext){
|
||||||
pNext = p->pNext;
|
pNext = p->pNext;
|
||||||
robust_close(pFile, p->fd, __LINE__);
|
robust_close(pFile, p->fd, __LINE__);
|
||||||
sqlite3_free(p);
|
sqlite3_free(p);
|
||||||
nUnusedFd--;
|
|
||||||
}
|
}
|
||||||
pInode->pUnused = 0;
|
pInode->pUnused = 0;
|
||||||
}
|
}
|
||||||
@@ -1271,11 +1302,14 @@ static void closePendingFds(unixFile *pFile){
|
|||||||
static void releaseInodeInfo(unixFile *pFile){
|
static void releaseInodeInfo(unixFile *pFile){
|
||||||
unixInodeInfo *pInode = pFile->pInode;
|
unixInodeInfo *pInode = pFile->pInode;
|
||||||
assert( unixMutexHeld() );
|
assert( unixMutexHeld() );
|
||||||
|
assert( unixFileMutexNotheld(pFile) );
|
||||||
if( ALWAYS(pInode) ){
|
if( ALWAYS(pInode) ){
|
||||||
pInode->nRef--;
|
pInode->nRef--;
|
||||||
if( pInode->nRef==0 ){
|
if( pInode->nRef==0 ){
|
||||||
assert( pInode->pShmNode==0 );
|
assert( pInode->pShmNode==0 );
|
||||||
|
sqlite3_mutex_enter(pInode->pLockMutex);
|
||||||
closePendingFds(pFile);
|
closePendingFds(pFile);
|
||||||
|
sqlite3_mutex_leave(pInode->pLockMutex);
|
||||||
if( pInode->pPrev ){
|
if( pInode->pPrev ){
|
||||||
assert( pInode->pPrev->pNext==pInode );
|
assert( pInode->pPrev->pNext==pInode );
|
||||||
pInode->pPrev->pNext = pInode->pNext;
|
pInode->pPrev->pNext = pInode->pNext;
|
||||||
@@ -1291,7 +1325,6 @@ static void releaseInodeInfo(unixFile *pFile){
|
|||||||
sqlite3_free(pInode);
|
sqlite3_free(pInode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert( inodeList!=0 || nUnusedFd==0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1361,7 +1394,6 @@ static int findInodeInfo(
|
|||||||
#else
|
#else
|
||||||
fileId.ino = (u64)statbuf.st_ino;
|
fileId.ino = (u64)statbuf.st_ino;
|
||||||
#endif
|
#endif
|
||||||
assert( inodeList!=0 || nUnusedFd==0 );
|
|
||||||
pInode = inodeList;
|
pInode = inodeList;
|
||||||
while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
|
while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
|
||||||
pInode = pInode->pNext;
|
pInode = pInode->pNext;
|
||||||
@@ -1826,11 +1858,11 @@ end_lock:
|
|||||||
static void setPendingFd(unixFile *pFile){
|
static void setPendingFd(unixFile *pFile){
|
||||||
unixInodeInfo *pInode = pFile->pInode;
|
unixInodeInfo *pInode = pFile->pInode;
|
||||||
UnixUnusedFd *p = pFile->pPreallocatedUnused;
|
UnixUnusedFd *p = pFile->pPreallocatedUnused;
|
||||||
|
assert( unixFileMutexHeld(pFile) );
|
||||||
p->pNext = pInode->pUnused;
|
p->pNext = pInode->pUnused;
|
||||||
pInode->pUnused = p;
|
pInode->pUnused = p;
|
||||||
pFile->h = -1;
|
pFile->h = -1;
|
||||||
pFile->pPreallocatedUnused = 0;
|
pFile->pPreallocatedUnused = 0;
|
||||||
nUnusedFd++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1988,14 +2020,14 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
|||||||
*/
|
*/
|
||||||
pInode->nLock--;
|
pInode->nLock--;
|
||||||
assert( pInode->nLock>=0 );
|
assert( pInode->nLock>=0 );
|
||||||
if( pInode->nLock==0 ){
|
if( pInode->nLock==0 ) closePendingFds(pFile);
|
||||||
closePendingFds(pFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
end_unlock:
|
end_unlock:
|
||||||
sqlite3_mutex_leave(pInode->pLockMutex);
|
sqlite3_mutex_leave(pInode->pLockMutex);
|
||||||
if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
|
if( rc==SQLITE_OK ){
|
||||||
|
pFile->eFileLock = eFileLock;
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2066,15 +2098,20 @@ static int closeUnixFile(sqlite3_file *id){
|
|||||||
static int unixClose(sqlite3_file *id){
|
static int unixClose(sqlite3_file *id){
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
unixFile *pFile = (unixFile *)id;
|
unixFile *pFile = (unixFile *)id;
|
||||||
|
unixInodeInfo *pInode = pFile->pInode;
|
||||||
|
|
||||||
|
assert( pInode!=0 );
|
||||||
verifyDbFile(pFile);
|
verifyDbFile(pFile);
|
||||||
unixUnlock(id, NO_LOCK);
|
unixUnlock(id, NO_LOCK);
|
||||||
|
assert( unixFileMutexNotheld(pFile) );
|
||||||
unixEnterMutex();
|
unixEnterMutex();
|
||||||
|
|
||||||
/* unixFile.pInode is always valid here. Otherwise, a different close
|
/* unixFile.pInode is always valid here. Otherwise, a different close
|
||||||
** routine (e.g. nolockClose()) would be called instead.
|
** routine (e.g. nolockClose()) would be called instead.
|
||||||
*/
|
*/
|
||||||
assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
|
assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
|
||||||
if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){
|
sqlite3_mutex_enter(pInode->pLockMutex);
|
||||||
|
if( pFile->pInode->nLock ){
|
||||||
/* If there are outstanding locks, do not actually close the file just
|
/* If there are outstanding locks, do not actually close the file just
|
||||||
** yet because that would clear those locks. Instead, add the file
|
** yet because that would clear those locks. Instead, add the file
|
||||||
** descriptor to pInode->pUnused list. It will be automatically closed
|
** descriptor to pInode->pUnused list. It will be automatically closed
|
||||||
@@ -2082,6 +2119,7 @@ static int unixClose(sqlite3_file *id){
|
|||||||
*/
|
*/
|
||||||
setPendingFd(pFile);
|
setPendingFd(pFile);
|
||||||
}
|
}
|
||||||
|
sqlite3_mutex_leave(pInode->pLockMutex);
|
||||||
releaseInodeInfo(pFile);
|
releaseInodeInfo(pFile);
|
||||||
rc = closeUnixFile(id);
|
rc = closeUnixFile(id);
|
||||||
unixLeaveMutex();
|
unixLeaveMutex();
|
||||||
@@ -2679,6 +2717,7 @@ static int semXClose(sqlite3_file *id) {
|
|||||||
unixFile *pFile = (unixFile*)id;
|
unixFile *pFile = (unixFile*)id;
|
||||||
semXUnlock(id, NO_LOCK);
|
semXUnlock(id, NO_LOCK);
|
||||||
assert( pFile );
|
assert( pFile );
|
||||||
|
assert( unixFileMutexNotheld(pFile) );
|
||||||
unixEnterMutex();
|
unixEnterMutex();
|
||||||
releaseInodeInfo(pFile);
|
releaseInodeInfo(pFile);
|
||||||
unixLeaveMutex();
|
unixLeaveMutex();
|
||||||
@@ -3119,14 +3158,14 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
|
|||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
pInode->nLock--;
|
pInode->nLock--;
|
||||||
assert( pInode->nLock>=0 );
|
assert( pInode->nLock>=0 );
|
||||||
if( pInode->nLock==0 ){
|
if( pInode->nLock==0 ) closePendingFds(pFile);
|
||||||
closePendingFds(pFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_mutex_leave(pInode->pLockMutex);
|
sqlite3_mutex_leave(pInode->pLockMutex);
|
||||||
if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
|
if( rc==SQLITE_OK ){
|
||||||
|
pFile->eFileLock = eFileLock;
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3138,14 +3177,20 @@ static int afpClose(sqlite3_file *id) {
|
|||||||
unixFile *pFile = (unixFile*)id;
|
unixFile *pFile = (unixFile*)id;
|
||||||
assert( id!=0 );
|
assert( id!=0 );
|
||||||
afpUnlock(id, NO_LOCK);
|
afpUnlock(id, NO_LOCK);
|
||||||
|
assert( unixFileMutexNotheld(pFile) );
|
||||||
unixEnterMutex();
|
unixEnterMutex();
|
||||||
if( pFile->pInode && pFile->pInode->nLock ){
|
if( pFile->pInode ){
|
||||||
/* If there are outstanding locks, do not actually close the file just
|
unixInodeInfo *pInode = pFile->pInode;
|
||||||
** yet because that would clear those locks. Instead, add the file
|
sqlite3_mutex_enter(pInode->pLockMutex);
|
||||||
** descriptor to pInode->aPending. It will be automatically closed when
|
if( pFile->pInode->nLock ){
|
||||||
** the last lock is cleared.
|
/* If there are outstanding locks, do not actually close the file just
|
||||||
*/
|
** yet because that would clear those locks. Instead, add the file
|
||||||
setPendingFd(pFile);
|
** descriptor to pInode->aPending. It will be automatically closed when
|
||||||
|
** the last lock is cleared.
|
||||||
|
*/
|
||||||
|
setPendingFd(pFile);
|
||||||
|
}
|
||||||
|
sqlite3_mutex_leave(pInode->pLockMutex);
|
||||||
}
|
}
|
||||||
releaseInodeInfo(pFile);
|
releaseInodeInfo(pFile);
|
||||||
sqlite3_free(pFile->lockingContext);
|
sqlite3_free(pFile->lockingContext);
|
||||||
@@ -4451,6 +4496,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
|||||||
/* Check to see if a unixShmNode object already exists. Reuse an existing
|
/* Check to see if a unixShmNode object already exists. Reuse an existing
|
||||||
** one if present. Create a new one if necessary.
|
** one if present. Create a new one if necessary.
|
||||||
*/
|
*/
|
||||||
|
assert( unixFileMutexNotheld(pDbFd) );
|
||||||
unixEnterMutex();
|
unixEnterMutex();
|
||||||
pInode = pDbFd->pInode;
|
pInode = pDbFd->pInode;
|
||||||
pShmNode = pInode->pShmNode;
|
pShmNode = pInode->pShmNode;
|
||||||
@@ -4833,6 +4879,7 @@ static void unixShmBarrier(
|
|||||||
){
|
){
|
||||||
UNUSED_PARAMETER(fd);
|
UNUSED_PARAMETER(fd);
|
||||||
sqlite3MemoryBarrier(); /* compiler-defined memory barrier */
|
sqlite3MemoryBarrier(); /* compiler-defined memory barrier */
|
||||||
|
assert( unixFileMutexNotheld((unixFile*)fd) );
|
||||||
unixEnterMutex(); /* Also mutex, for redundancy */
|
unixEnterMutex(); /* Also mutex, for redundancy */
|
||||||
unixLeaveMutex();
|
unixLeaveMutex();
|
||||||
}
|
}
|
||||||
@@ -4874,6 +4921,7 @@ static int unixShmUnmap(
|
|||||||
|
|
||||||
/* If pShmNode->nRef has reached 0, then close the underlying
|
/* If pShmNode->nRef has reached 0, then close the underlying
|
||||||
** shared-memory file, too */
|
** shared-memory file, too */
|
||||||
|
assert( unixFileMutexNotheld(pDbFd) );
|
||||||
unixEnterMutex();
|
unixEnterMutex();
|
||||||
assert( pShmNode->nRef>0 );
|
assert( pShmNode->nRef>0 );
|
||||||
pShmNode->nRef--;
|
pShmNode->nRef--;
|
||||||
@@ -5200,7 +5248,7 @@ IOMETHODS(
|
|||||||
IOMETHODS(
|
IOMETHODS(
|
||||||
nolockIoFinder, /* Finder function name */
|
nolockIoFinder, /* Finder function name */
|
||||||
nolockIoMethods, /* sqlite3_io_methods object name */
|
nolockIoMethods, /* sqlite3_io_methods object name */
|
||||||
3, /* shared memory is disabled */
|
3, /* shared memory and mmap are enabled */
|
||||||
nolockClose, /* xClose method */
|
nolockClose, /* xClose method */
|
||||||
nolockLock, /* xLock method */
|
nolockLock, /* xLock method */
|
||||||
nolockUnlock, /* xUnlock method */
|
nolockUnlock, /* xUnlock method */
|
||||||
@@ -5696,7 +5744,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
|
|||||||
**
|
**
|
||||||
** Even if a subsequent open() call does succeed, the consequences of
|
** Even if a subsequent open() call does succeed, the consequences of
|
||||||
** not searching for a reusable file descriptor are not dire. */
|
** not searching for a reusable file descriptor are not dire. */
|
||||||
if( nUnusedFd>0 && 0==osStat(zPath, &sStat) ){
|
if( inodeList!=0 && 0==osStat(zPath, &sStat) ){
|
||||||
unixInodeInfo *pInode;
|
unixInodeInfo *pInode;
|
||||||
|
|
||||||
pInode = inodeList;
|
pInode = inodeList;
|
||||||
@@ -5706,12 +5754,14 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
|
|||||||
}
|
}
|
||||||
if( pInode ){
|
if( pInode ){
|
||||||
UnixUnusedFd **pp;
|
UnixUnusedFd **pp;
|
||||||
|
assert( sqlite3_mutex_notheld(pInode->pLockMutex) );
|
||||||
|
sqlite3_mutex_enter(pInode->pLockMutex);
|
||||||
for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
|
for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
|
||||||
pUnused = *pp;
|
pUnused = *pp;
|
||||||
if( pUnused ){
|
if( pUnused ){
|
||||||
nUnusedFd--;
|
|
||||||
*pp = pUnused->pNext;
|
*pp = pUnused->pNext;
|
||||||
}
|
}
|
||||||
|
sqlite3_mutex_leave(pInode->pLockMutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unixLeaveMutex();
|
unixLeaveMutex();
|
||||||
|
@@ -25,15 +25,23 @@ static void corruptSchema(
|
|||||||
const char *zExtra /* Error information */
|
const char *zExtra /* Error information */
|
||||||
){
|
){
|
||||||
sqlite3 *db = pData->db;
|
sqlite3 *db = pData->db;
|
||||||
if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){
|
if( db->mallocFailed ){
|
||||||
|
pData->rc = SQLITE_NOMEM_BKPT;
|
||||||
|
}else if( pData->pzErrMsg[0]!=0 ){
|
||||||
|
/* A error message has already been generated. Do not overwrite it */
|
||||||
|
}else if( pData->mInitFlags & INITFLAG_AlterTable ){
|
||||||
|
*pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
|
||||||
|
pData->rc = SQLITE_ERROR;
|
||||||
|
}else if( db->flags & SQLITE_WriteSchema ){
|
||||||
|
pData->rc = SQLITE_CORRUPT_BKPT;
|
||||||
|
}else{
|
||||||
char *z;
|
char *z;
|
||||||
if( zObj==0 ) zObj = "?";
|
if( zObj==0 ) zObj = "?";
|
||||||
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);
|
||||||
sqlite3DbFree(db, *pData->pzErrMsg);
|
|
||||||
*pData->pzErrMsg = z;
|
*pData->pzErrMsg = z;
|
||||||
|
pData->rc = SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -132,7 +140,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
|||||||
** auxiliary databases. Return one of the SQLITE_ error codes to
|
** auxiliary databases. Return one of the SQLITE_ error codes to
|
||||||
** indicate success or failure.
|
** indicate success or failure.
|
||||||
*/
|
*/
|
||||||
int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||||
int rc;
|
int rc;
|
||||||
int i;
|
int i;
|
||||||
#ifndef SQLITE_OMIT_DEPRECATED
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
@@ -167,6 +175,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|||||||
initData.iDb = iDb;
|
initData.iDb = iDb;
|
||||||
initData.rc = SQLITE_OK;
|
initData.rc = SQLITE_OK;
|
||||||
initData.pzErrMsg = pzErrMsg;
|
initData.pzErrMsg = pzErrMsg;
|
||||||
|
initData.mInitFlags = mFlags;
|
||||||
sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
|
sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
|
||||||
if( initData.rc ){
|
if( initData.rc ){
|
||||||
rc = initData.rc;
|
rc = initData.rc;
|
||||||
@@ -373,14 +382,14 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
|||||||
assert( db->nDb>0 );
|
assert( db->nDb>0 );
|
||||||
/* Do the main schema first */
|
/* Do the main schema first */
|
||||||
if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
|
if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
|
||||||
rc = sqlite3InitOne(db, 0, pzErrMsg);
|
rc = sqlite3InitOne(db, 0, pzErrMsg, 0);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
}
|
}
|
||||||
/* All other schemas after the main schema. The "temp" schema must be last */
|
/* All other schemas after the main schema. The "temp" schema must be last */
|
||||||
for(i=db->nDb-1; i>0; i--){
|
for(i=db->nDb-1; i>0; i--){
|
||||||
assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) );
|
assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) );
|
||||||
if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
|
if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
|
||||||
rc = sqlite3InitOne(db, i, pzErrMsg);
|
rc = sqlite3InitOne(db, i, pzErrMsg, 0);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3329,8 +3329,14 @@ typedef struct {
|
|||||||
char **pzErrMsg; /* Error message stored here */
|
char **pzErrMsg; /* Error message stored here */
|
||||||
int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
|
int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
|
||||||
int rc; /* Result code stored here */
|
int rc; /* Result code stored here */
|
||||||
|
u32 mInitFlags; /* Flags controlling error messages */
|
||||||
} InitData;
|
} InitData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Allowed values for mInitFlags
|
||||||
|
*/
|
||||||
|
#define INITFLAG_AlterTable 0x0001 /* This is a reparse after ALTER TABLE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Structure containing global configuration data for the SQLite library.
|
** Structure containing global configuration data for the SQLite library.
|
||||||
**
|
**
|
||||||
@@ -3801,7 +3807,7 @@ void sqlite3ExprListDelete(sqlite3*, ExprList*);
|
|||||||
u32 sqlite3ExprListFlags(const ExprList*);
|
u32 sqlite3ExprListFlags(const ExprList*);
|
||||||
int sqlite3Init(sqlite3*, char**);
|
int sqlite3Init(sqlite3*, char**);
|
||||||
int sqlite3InitCallback(void*, int, char**, char**);
|
int sqlite3InitCallback(void*, int, char**, char**);
|
||||||
int sqlite3InitOne(sqlite3*, int, char**);
|
int sqlite3InitOne(sqlite3*, int, char**, u32);
|
||||||
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
|
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
|
Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
|
||||||
|
@@ -5722,7 +5722,8 @@ case OP_SqlExec: {
|
|||||||
/* Opcode: ParseSchema P1 * * P4 *
|
/* Opcode: ParseSchema P1 * * P4 *
|
||||||
**
|
**
|
||||||
** Read and parse all entries from the SQLITE_MASTER table of database P1
|
** Read and parse all entries from the SQLITE_MASTER table of database P1
|
||||||
** that match the WHERE clause P4.
|
** that match the WHERE clause P4. If P4 is a NULL pointer, then the
|
||||||
|
** entire schema for P1 is reparsed.
|
||||||
**
|
**
|
||||||
** This opcode invokes the parser to create a new virtual machine,
|
** This opcode invokes the parser to create a new virtual machine,
|
||||||
** then runs the new virtual machine. It is thus a re-entrant opcode.
|
** then runs the new virtual machine. It is thus a re-entrant opcode.
|
||||||
@@ -5751,11 +5752,11 @@ 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);
|
rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
|
||||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
db->mDbFlags |= DBFLAG_SchemaChange;
|
||||||
}else
|
}else
|
||||||
#endif
|
#endif
|
||||||
/* Used to be a conditional */ {
|
{
|
||||||
zMaster = MASTER_NAME;
|
zMaster = MASTER_NAME;
|
||||||
initData.db = db;
|
initData.db = db;
|
||||||
initData.iDb = pOp->p1;
|
initData.iDb = pOp->p1;
|
||||||
|
@@ -238,9 +238,6 @@ void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
|
|||||||
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
|
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
|
||||||
int sqlite3VdbeFinalize(Vdbe*);
|
int sqlite3VdbeFinalize(Vdbe*);
|
||||||
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||||
#ifdef SQLITE_COVERAGE_TEST
|
|
||||||
int sqlite3VdbeLabelHasBeenResolved(Vdbe*,int);
|
|
||||||
#endif
|
|
||||||
int sqlite3VdbeCurrentAddr(Vdbe*);
|
int sqlite3VdbeCurrentAddr(Vdbe*);
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
int sqlite3VdbeAssertMayAbort(Vdbe *, int);
|
int sqlite3VdbeAssertMayAbort(Vdbe *, int);
|
||||||
|
@@ -437,19 +437,6 @@ void sqlite3VdbeResolveLabel(Vdbe *v, int x){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SQLITE_COVERAGE_TEST
|
|
||||||
/*
|
|
||||||
** Return TRUE if and only if the label x has already been resolved.
|
|
||||||
** Return FALSE (zero) if label x is still unresolved.
|
|
||||||
**
|
|
||||||
** This routine is only used inside of testcase() macros, and so it
|
|
||||||
** only exists when measuring test coverage.
|
|
||||||
*/
|
|
||||||
int sqlite3VdbeLabelHasBeenResolved(Vdbe *v, int x){
|
|
||||||
return v->pParse->aLabel && v->pParse->aLabel[ADDR(x)]>=0;
|
|
||||||
}
|
|
||||||
#endif /* SQLITE_COVERAGE_TEST */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Mark the VDBE as one that can only be run one time.
|
** Mark the VDBE as one that can only be run one time.
|
||||||
*/
|
*/
|
||||||
|
@@ -66,6 +66,21 @@ foreach {tn before after} {
|
|||||||
13 {CREATE TABLE t1(a, b, c, FOREIGN KEY (b) REFERENCES t2)}
|
13 {CREATE TABLE t1(a, b, c, FOREIGN KEY (b) REFERENCES t2)}
|
||||||
{CREATE TABLE t1(a, d, c, FOREIGN KEY (d) REFERENCES t2)}
|
{CREATE TABLE t1(a, d, c, FOREIGN KEY (d) REFERENCES t2)}
|
||||||
|
|
||||||
|
15 {CREATE TABLE t1(a INTEGER, b INTEGER, c BLOB, PRIMARY KEY(b))}
|
||||||
|
{CREATE TABLE t1(a INTEGER, d INTEGER, c BLOB, PRIMARY KEY(d))}
|
||||||
|
|
||||||
|
16 {CREATE TABLE t1(a INTEGER, b INTEGER PRIMARY KEY, c BLOB)}
|
||||||
|
{CREATE TABLE t1(a INTEGER, d INTEGER PRIMARY KEY, c BLOB)}
|
||||||
|
|
||||||
|
14 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, PRIMARY KEY(b))}
|
||||||
|
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, PRIMARY KEY(d))}
|
||||||
|
|
||||||
|
15 {CREATE TABLE t1(a INTEGER, b INTEGER, c BLOB, PRIMARY KEY(b))}
|
||||||
|
{CREATE TABLE t1(a INTEGER, d INTEGER, c BLOB, PRIMARY KEY(d))}
|
||||||
|
|
||||||
|
16 {CREATE TABLE t1(a INTEGER, b INTEGER PRIMARY KEY, c BLOB)}
|
||||||
|
{CREATE TABLE t1(a INTEGER, d INTEGER PRIMARY KEY, c BLOB)}
|
||||||
|
|
||||||
} {
|
} {
|
||||||
reset_db
|
reset_db
|
||||||
do_execsql_test 1.$tn.0 $before
|
do_execsql_test 1.$tn.0 $before
|
||||||
@@ -209,6 +224,7 @@ do_execsql_test 6.3 {
|
|||||||
} {}
|
} {}
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
# Triggers.
|
||||||
#
|
#
|
||||||
reset_db
|
reset_db
|
||||||
do_execsql_test 7.0 {
|
do_execsql_test 7.0 {
|
||||||
@@ -235,5 +251,78 @@ do_execsql_test 7.3 {
|
|||||||
SELECT * FROM c;
|
SELECT * FROM c;
|
||||||
} {2}
|
} {2}
|
||||||
|
|
||||||
finish_test
|
#-------------------------------------------------------------------------
|
||||||
|
# Views.
|
||||||
|
#
|
||||||
|
reset_db
|
||||||
|
do_execsql_test 8.0 {
|
||||||
|
CREATE TABLE a1(x INTEGER, y TEXT, z BLOB, PRIMARY KEY(x));
|
||||||
|
CREATE TABLE a2(a, b, c);
|
||||||
|
CREATE VIEW v1 AS SELECT x, y, z FROM a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 8.1 {
|
||||||
|
ALTER TABLE a1 RENAME y TO yyy;
|
||||||
|
SELECT sql FROM sqlite_master WHERE type='view';
|
||||||
|
} {{CREATE VIEW v1 AS SELECT x, yyy, z FROM a1}}
|
||||||
|
|
||||||
|
do_execsql_test 8.2.1 {
|
||||||
|
DROP VIEW v1;
|
||||||
|
CREATE VIEW v2 AS SELECT x, x+x, a, a+a FROM a1, a2;
|
||||||
|
} {}
|
||||||
|
do_execsql_test 8.2.2 {
|
||||||
|
ALTER TABLE a1 RENAME x TO xxx;
|
||||||
|
}
|
||||||
|
do_execsql_test 8.2.3 {
|
||||||
|
SELECT sql FROM sqlite_master WHERE type='view';
|
||||||
|
} {{CREATE VIEW v2 AS SELECT xxx, xxx+xxx, a, a+a FROM a1, a2}}
|
||||||
|
|
||||||
|
do_execsql_test 8.3.1 {
|
||||||
|
DROP TABLE a2;
|
||||||
|
DROP VIEW v2;
|
||||||
|
CREATE TABLE a2(a INTEGER PRIMARY KEY, b, c);
|
||||||
|
CREATE VIEW v2 AS SELECT xxx, xxx+xxx, a, a+a FROM a1, a2;
|
||||||
|
} {}
|
||||||
|
do_execsql_test 8.3.2 {
|
||||||
|
ALTER TABLE a1 RENAME xxx TO x;
|
||||||
|
}
|
||||||
|
do_execsql_test 8.3.3 {
|
||||||
|
SELECT sql FROM sqlite_master WHERE type='view';
|
||||||
|
} {{CREATE VIEW v2 AS SELECT x, x+x, a, a+a FROM a1, a2}}
|
||||||
|
|
||||||
|
do_execsql_test 8.4.0 {
|
||||||
|
CREATE TABLE b1(a, b, c);
|
||||||
|
CREATE TABLE b2(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 8.4.1 {
|
||||||
|
CREATE VIEW vvv AS SELECT c+c || coalesce(c, c) FROM b1, b2 WHERE x=c GROUP BY c HAVING c>0;
|
||||||
|
ALTER TABLE b1 RENAME c TO "a;b";
|
||||||
|
SELECT sql FROM sqlite_master WHERE name='vvv';
|
||||||
|
} {{CREATE VIEW vvv AS SELECT "a;b"+"a;b" || coalesce("a;b", "a;b") FROM b1, b2 WHERE x="a;b" GROUP BY "a;b" HAVING "a;b">0}}
|
||||||
|
|
||||||
|
do_execsql_test 8.4.2 {
|
||||||
|
CREATE VIEW www AS SELECT b FROM b1 UNION ALL SELECT y FROM b2;
|
||||||
|
ALTER TABLE b1 RENAME b TO bbb;
|
||||||
|
SELECT sql FROM sqlite_master WHERE name='www';
|
||||||
|
} {{CREATE VIEW www AS SELECT bbb FROM b1 UNION ALL SELECT y FROM b2}}
|
||||||
|
|
||||||
|
db collate nocase {string compare}
|
||||||
|
|
||||||
|
do_execsql_test 8.4.3 {
|
||||||
|
CREATE VIEW xxx AS SELECT a FROM b1 UNION SELECT x FROM b2 ORDER BY 1 COLLATE nocase;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 8.4.4 {
|
||||||
|
ALTER TABLE b2 RENAME x TO hello;
|
||||||
|
SELECT sql FROM sqlite_master WHERE name='xxx';
|
||||||
|
} {{CREATE VIEW xxx AS SELECT a FROM b1 UNION SELECT hello FROM b2 ORDER BY 1 COLLATE nocase}}
|
||||||
|
|
||||||
|
do_execsql_test 8.4.5 {
|
||||||
|
CREATE VIEW zzz AS SELECT george, ringo FROM b1;
|
||||||
|
ALTER TABLE b1 RENAME a TO aaa;
|
||||||
|
SELECT sql FROM sqlite_master WHERE name = 'zzz'
|
||||||
|
} {{CREATE VIEW zzz AS SELECT george, ringo FROM b1}}
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
@@ -113,6 +113,6 @@ do_test trigger7-99.1 {
|
|||||||
db close
|
db close
|
||||||
catch { sqlite3 db test.db }
|
catch { sqlite3 db test.db }
|
||||||
catchsql { DROP TRIGGER t2r5 }
|
catchsql { DROP TRIGGER t2r5 }
|
||||||
} {1 {malformed database schema (t2r12)}}
|
} {/1 {malformed database schema .*}/}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
@@ -128,4 +128,87 @@ do_execsql_test upsert1-610 {
|
|||||||
PRAGMA integrity_check;
|
PRAGMA integrity_check;
|
||||||
} {ok}
|
} {ok}
|
||||||
|
|
||||||
|
# 2018-08-14
|
||||||
|
# Ticket https://www.sqlite.org/src/info/908f001483982c43
|
||||||
|
# If there are multiple uniqueness contraints, the UPSERT should fire
|
||||||
|
# if the one constraint it targets fails, regardless of whether or not
|
||||||
|
# the other constraints pass or fail. In other words, the UPSERT constraint
|
||||||
|
# should be tested first.
|
||||||
|
#
|
||||||
|
do_execsql_test upsert1-700 {
|
||||||
|
DROP TABLE t1;
|
||||||
|
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT, c INT, d INT, e INT);
|
||||||
|
CREATE UNIQUE INDEX t1b ON t1(b);
|
||||||
|
CREATE UNIQUE INDEX t1e ON t1(e);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
|
||||||
|
ON CONFLICT(e) DO UPDATE SET c=excluded.c;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
} {1 2 33 4 5}
|
||||||
|
do_execsql_test upsert1-710 {
|
||||||
|
DELETE FROM t1;
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
|
||||||
|
ON CONFLICT(a) DO UPDATE SET c=excluded.c;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
} {1 2 33 4 5}
|
||||||
|
do_execsql_test upsert1-720 {
|
||||||
|
DELETE FROM t1;
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
|
||||||
|
ON CONFLICT(b) DO UPDATE SET c=excluded.c;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
} {1 2 33 4 5}
|
||||||
|
do_execsql_test upsert1-730 {
|
||||||
|
DROP TABLE t1;
|
||||||
|
CREATE TABLE t1(a INT, b INT, c INT, d INT, e INT);
|
||||||
|
CREATE UNIQUE INDEX t1a ON t1(a);
|
||||||
|
CREATE UNIQUE INDEX t1b ON t1(b);
|
||||||
|
CREATE UNIQUE INDEX t1e ON t1(e);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
|
||||||
|
ON CONFLICT(e) DO UPDATE SET c=excluded.c;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
} {1 2 33 4 5}
|
||||||
|
do_execsql_test upsert1-740 {
|
||||||
|
DELETE FROM t1;
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
|
||||||
|
ON CONFLICT(a) DO UPDATE SET c=excluded.c;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
} {1 2 33 4 5}
|
||||||
|
do_execsql_test upsert1-750 {
|
||||||
|
DELETE FROM t1;
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
|
||||||
|
ON CONFLICT(b) DO UPDATE SET c=excluded.c;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
} {1 2 33 4 5}
|
||||||
|
do_execsql_test upsert1-760 {
|
||||||
|
DROP TABLE t1;
|
||||||
|
CREATE TABLE t1(a INT PRIMARY KEY, b INT, c INT, d INT, e INT) WITHOUT ROWID;
|
||||||
|
CREATE UNIQUE INDEX t1a ON t1(a);
|
||||||
|
CREATE UNIQUE INDEX t1b ON t1(b);
|
||||||
|
CREATE UNIQUE INDEX t1e ON t1(e);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
|
||||||
|
ON CONFLICT(e) DO UPDATE SET c=excluded.c;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
} {1 2 33 4 5}
|
||||||
|
do_execsql_test upsert1-770 {
|
||||||
|
DELETE FROM t1;
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
|
||||||
|
ON CONFLICT(a) DO UPDATE SET c=excluded.c;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
} {1 2 33 4 5}
|
||||||
|
do_execsql_test upsert1-780 {
|
||||||
|
DELETE FROM t1;
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||||
|
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
|
||||||
|
ON CONFLICT(b) DO UPDATE SET c=excluded.c;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
} {1 2 33 4 5}
|
||||||
|
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
Reference in New Issue
Block a user