Add an "ALTER TABLE RENAME COLUMN" command. Upgrade "ALTER TABLE RENAME TABLE"
so that it modifies references to the renamed table embedded in SQL view and trigger definitions. FossilOrigin-Name: 4da5998314ed2c694b0e242755930f5320af89ac5c148845392f0a2043d44d22
This commit is contained in:
commit
fb05c7ff7d
@ -1278,6 +1278,9 @@ changeset$(TEXE): $(TOP)/ext/session/changeset.c sqlite3.lo
|
||||
rollback-test$(TEXE): $(TOP)/tool/rollback-test.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/tool/rollback-test.c sqlite3.lo $(TLIBS)
|
||||
|
||||
atrc$(TEXX): $(TOP)/test/atrc.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/test/atrc.c sqlite3.lo $(TLIBS)
|
||||
|
||||
LogEst$(TEXE): $(TOP)/tool/logest.c sqlite3.h
|
||||
$(LTLINK) -I. -o $@ $(TOP)/tool/logest.c
|
||||
|
||||
|
@ -2438,6 +2438,10 @@ rollback-test.exe: $(TOP)\tool\rollback-test.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\tool\rollback-test.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
atrc.exe: $(TOP)\test\atrc.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\test\atrc.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
LogEst.exe: $(TOP)\tool\logest.c $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\LogEst.c /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
|
@ -280,7 +280,7 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
|
||||
case FTS5_SAVEPOINT:
|
||||
assert( p->ts.eState==1 );
|
||||
assert( iSavepoint>=0 );
|
||||
assert( iSavepoint>p->ts.iSavepoint );
|
||||
assert( iSavepoint>=p->ts.iSavepoint );
|
||||
p->ts.iSavepoint = iSavepoint;
|
||||
break;
|
||||
|
||||
|
4
main.mk
4
main.mk
@ -1000,6 +1000,10 @@ rollback-test$(EXE): $(TOP)/tool/rollback-test.c sqlite3.o
|
||||
$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o rollback-test$(EXE) \
|
||||
$(TOP)/tool/rollback-test.c sqlite3.o $(THREADLIB)
|
||||
|
||||
atrc$(EXE): $(TOP)/test/atrc.c sqlite3.o
|
||||
$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o atrc$(EXE) \
|
||||
$(TOP)/test/atrc.c sqlite3.o $(THREADLIB)
|
||||
|
||||
LogEst$(EXE): $(TOP)/tool/logest.c sqlite3.h
|
||||
$(TCC) -o LogEst$(EXE) $(TOP)/tool/logest.c
|
||||
|
||||
|
60
manifest
60
manifest
@ -1,10 +1,10 @@
|
||||
C Add\sthe\srandomshape.tcl\stest-case\sgenerator\sscript\sto\sthe\sutil\ssubdirectory\nof\sthe\srtree\sextension.
|
||||
D 2018-09-06T14:01:56.119
|
||||
C Add\san\s"ALTER\sTABLE\sRENAME\sCOLUMN"\scommand.\sUpgrade\s"ALTER\sTABLE\sRENAME\sTABLE"\nso\sthat\sit\smodifies\sreferences\sto\sthe\srenamed\stable\sembedded\sin\sSQL\sview\sand\ntrigger\sdefinitions.
|
||||
D 2018-09-06T16:20:09.413
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f
|
||||
F Makefile.in 6b650013511fd9d8b094203ac268af9220d292cc7d4e1bc9fbca15aacd8c7995
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc ab99b4a0aa33f1c0f39587be9df15c9db536acf7859828ff8c51e13eb5082874
|
||||
F Makefile.msc d37bb24f0910744b555d77bea3d2f31e412caaf0c8ac6ec76a3d312cb3cf52ce
|
||||
F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee
|
||||
F VERSION d3e3afdec1165a5e593dcdfffd8e0f33a2b0186067eb51a073ef6c4aec34923d
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@ -116,7 +116,7 @@ F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
|
||||
F ext/fts5/fts5_expr.c 5aef080ba3c8947e22f38ce1ff9fe548e4a740e72b77241f35ed941ae128d2c7
|
||||
F ext/fts5/fts5_hash.c 32be400cf761868c9db33efe81a06eb19a17c5402ad477ee9efb51301546dd55
|
||||
F ext/fts5/fts5_index.c d1b2d7d92cb2b72b9465da35b7d7c30e4b426c7f208bf6f94ce86b50eed8a1cb
|
||||
F ext/fts5/fts5_main.c 2ee492d773ec8d5d93615603640eeb07746ff0ce8d5ce7329c240b0001bd58ad
|
||||
F ext/fts5/fts5_main.c 7e52868e6b444e5353ff30e1dcd2a9273e8eaa543ddccf0c94b3cd2c235ff104
|
||||
F ext/fts5/fts5_storage.c 4bec8a1b3905978b22a67bca5f4a3cfdb94af234cf51efb36f4f2d733d278634
|
||||
F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95
|
||||
F ext/fts5/fts5_test_mi.c 65864ba1e5c34a61d409c4c587e0bbe0466eb4f8f478d85dc42a92caad1338e6
|
||||
@ -423,7 +423,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 1cce6391d663fc1cb67075a951efaaab5c2852f59f5c356a74d1eed5387d3c8e
|
||||
F main.mk 1db6df4bff24ed6684917e3fe311ce28f5924d6417c698fe4326f7cadf02df31
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@ -435,17 +435,17 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 6beb476095a4cfeb95ebedb2e5e17894d1687b24fddd5b8761a4de120e0392c6
|
||||
F src/alter.c 9088b817d4ca84504dc3b4237be6347cfeb3471aa8b29f57ffc4b102d9f62924
|
||||
F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9
|
||||
F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a
|
||||
F src/auth.c 8272da9ff761bf84f0357298ccc6e5924e3f7fac143c6587f06aa72b202445a2
|
||||
F src/auth.c 32a5bbe3b755169ab6c66311c5225a3cd4f75a46c041f7fb117e0cbb68055114
|
||||
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 3f5e1a03db871e627bf5da21092bf7434ecfc5c5980bbd7d45eba13341340173
|
||||
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
|
||||
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
|
||||
F src/build.c fe407be13d1201bf386d2c629424e5c97a07bcfc6ef21cf6e888e50b792a6191
|
||||
F src/build.c 3565efa51996dc501c3008aa73cad5ffeb983d91a73d7499d8e2bf1a886ff381
|
||||
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c b157b01081f92442f8b0218ddb93ddce8ebddad36dbddeecfdd771561dd4f387
|
||||
@ -453,7 +453,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
|
||||
F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3
|
||||
F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
|
||||
F src/delete.c 107e28d3ef8bd72fd11953374ca9107cd74e8b09c3ded076a6048742d26ce7d2
|
||||
F src/expr.c bf08bfe77ec3d54c230ad91ed62d2cba796f82420b58f43aa8250c9025f4c7f9
|
||||
F src/expr.c 92dc4e104b06d06ffeacbd1a4dc0a520daf37f6156278fb6ece5e90e2ca6b610
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c f59253c0be4b1e9dfcb073b6d6d6ab83090ae50c08b5c113b76013c4b157cd6a
|
||||
F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
|
||||
@ -490,23 +490,23 @@ F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c a0d8f686ef64549ad5b356fd30429bd9ee7a06dd42b4d6faa096352ff26b1c5b
|
||||
F src/pager.h ecc554a55bc55d1c4ba5e17137b72e238e00bd81e72ff2662d8b9c8c10ae3963
|
||||
F src/parse.y 704c94624d41d7d46a5467574130e55aa8029a563f4df538f0121475eae46e34
|
||||
F src/parse.y b3ca0ebaba6abe775e22c380fecfea17776ea150a6fb8e419a2a2274e478bc01
|
||||
F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
|
||||
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||
F src/pragma.c 79abc65c08d2754048efee3ba99fe91863dfeab0ba699a4439fa5053ec87cf36
|
||||
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
||||
F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0
|
||||
F src/prepare.c f8e260d940a0e08494c0f30744521b2f832d7263eca9d02b050cea0ba144b097
|
||||
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea
|
||||
F src/resolve.c 352c6af1a99441206ff62a6f7429dbf537827f42c428639695220b9c8639e33b
|
||||
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
|
||||
F src/select.c ae7396a314cc1bb1d767947cd57094e3a9ffcbb155ebc1b1c391e028c44a9a04
|
||||
F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f
|
||||
F src/sqlite.h.in cdf2a539cd0570322a94bcb97c01c56feb1be0657ec7cfb8273c89d19fff87a9
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
|
||||
F src/sqliteInt.h 26e48f0c823844fcce67bd2a11ad1ad3468aaed32fd8864bc69c4147cb608728
|
||||
F src/sqliteInt.h 8a75462ee70e76754e88daaa32bf7926ee412a3fea95551dcb1687194ff4da3d
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@ -564,15 +564,15 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
|
||||
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 01e96d1b639c3eb0b9ef90616e766d453935c554f1f7aa86b6db937b79554b97
|
||||
F src/tokenize.c 9f55961518f77793edd56eee860ecf035d4370ebbb0726ad2f6cada6637fd16b
|
||||
F src/treeview.c e7a7f90552bb418533cdd0309b5eb71d4effa50165b880fc8c2001e613577e5f
|
||||
F src/trigger.c 4ace6d1d5ba9a89822deb287317f33c810440526eafe185c2d8a48c31df1e995
|
||||
F src/trigger.c d3d78568f37fb2e6cdcc2d1e7b60156f15b0b600adec55b83c5d42f6cad250bd
|
||||
F src/update.c 345ce35eb1332eb4829857aa8b1f65a614b07dae91d0346c0dc2baacafbcc51b
|
||||
F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
||||
F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
|
||||
F src/vdbe.c 74671dff9ba856c5464557a8dbf2ba940fc4fa67efbceb32e262eedac31d86ca
|
||||
F src/vdbe.c dea0115a61f31227a116930c2f16b97f0a0e90abc7b87b09d1dfb8dc525b147b
|
||||
F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907
|
||||
F src/vdbeInt.h f1f35f70460698d8f5a2bdef1001114babf318e2983a067804e2ae077d8e9827
|
||||
F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611
|
||||
@ -581,7 +581,7 @@ F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c9419
|
||||
F src/vdbemem.c 81329ab760e4ec0162119d9cd10193e0303c45c5935bb20c7ae9139d44dd6641
|
||||
F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f
|
||||
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
|
||||
F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14
|
||||
F src/vtab.c 8665561f244c137a2d17b5c3e5910d7303054fe841c5d510e53f23beb0089594
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c df50883d93689d009be5ad9bdc4e53a4ee45fcc291087ec9272569d00b360791
|
||||
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
|
||||
@ -598,11 +598,14 @@ F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 18b00de006597e960a6b27ccec51474ac66cf1070a87c1933e5694dc02190ef1
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test ae17c4412639e16bd797c7617864a16c2badc0035c808ae8246f145e38f8e2f9
|
||||
F test/alter.test b820ab9dcf85f8e3a65bc8326accb2f0c7be64ef
|
||||
F test/alter.test cf28c2f35253d3395cf16334fb9dde1d8c4b035cb7c89204353ee1f47feaec1b
|
||||
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||
F test/alter3.test 4d79934d812eaeacc6f22781a080f8cfe012fdc3
|
||||
F test/alter4.test b6d7b86860111864f6cddb54af313f5862dda23b
|
||||
F test/alter4.test 7e93a21fe131e1dfeb317e90056856f96b10381fc7fe3a05e765569a23400433
|
||||
F test/altercol.test a5e24ad5e71afbf4a604336ee5f5287d3633ef26952b4ee8b5fe154a30ed2993
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/altermalloc2.test 0231398534c494401a70a1d06a63d7849cb5b317fcc14228cbdb53039eba7eae
|
||||
F test/altertab.test bd1fbe88c9e87c5ab9aedc2b1d1d29342d9364297bd6c4548b224188a9a351fb
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test b3a9c67d00e1df7588a5b7be9a0292899f94fe8cac1f94a017277474ca2e59df
|
||||
F test/analyze3.test ff62d9029e6deb2c914490c6b00caf7fae47cc85cdc046e4a0d0a4d4b87c71d8
|
||||
@ -627,12 +630,13 @@ F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
|
||||
F test/atof1.test ff0b0156fd705b67c506e1f2bfe9e26102bea9bd
|
||||
F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061
|
||||
F test/atomic2.test b6863b4aa552543874f80b42fb3063f1c8c2e3d8e56b6562f00a3cc347b5c1da
|
||||
F test/atrc.c ec92d56d8fbed9eb3e11aaf1ab98cf7dd59e69dae31f128013f1d97e54e7dfed
|
||||
F test/attach.test f4b8918ba2f3e88e6883b8452340545f10a1388af808343c37fc5c577be8281c
|
||||
F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3a0ce
|
||||
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
|
||||
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
|
||||
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
|
||||
F test/auth.test 3d6cd8f3978ba55b1202574e6ecd79c6e00914ca44b9bfd6c1fe6fb873fcac88
|
||||
F test/auth.test 4dd570df24d175f6c3a8988358e9ce884d86434edf8af0b396af97c97147ac57
|
||||
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
|
||||
F test/auth3.test db21405b95257c24d29273b6b31d0efc59e1d337e3d5804ba2d1fd4897b1ae49
|
||||
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
|
||||
@ -818,7 +822,7 @@ F test/fallocate.test 07416bd593a116d5893cb244f45a94d5c6fe030561df3bd972e6135f81
|
||||
F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3
|
||||
F test/filefmt.test f393e80c4b8d493b7a7f8f3809a8425bbf4292af1f5140f01cb1427798a2bbd4
|
||||
F test/fkey1.test d11dbb8a93ead9b5c46ae5d02da016d61245d47662fb2d844c99214f6163f768
|
||||
F test/fkey2.test 155809016fad6b2a1491facf2ac53a551bc57c2c
|
||||
F test/fkey2.test 6206484a0eba570902a1a4d86489df24d0265f6994daebf851861d8f0cf4a27b
|
||||
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 24dd28eb3d9f1b5a174f47e9899ace5facb08373a4223593c8c631e6cf9f7d5a
|
||||
@ -1505,7 +1509,7 @@ F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945
|
||||
F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359
|
||||
F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
|
||||
F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
|
||||
F test/trigger7.test 799c9d2561facef70340cc9e0dee98aee9b5bdfe
|
||||
F test/trigger7.test 93cfa9b48ab9104b2b3d87bc544ac8021405643e36f23ee84635fbfaf9b8fef5
|
||||
F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
|
||||
F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41
|
||||
F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332
|
||||
@ -1650,7 +1654,7 @@ F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f1982
|
||||
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
|
||||
F test/without_rowid1.test 533add9100255e4cc430d371b3ecfb79f11f956b86c3a1b9d34413bf8e482d8f
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
F test/without_rowid3.test 2724c787a51a5dce09d078453a758117b4b728f1
|
||||
F test/without_rowid3.test e1bb85362d9b7b63ea2b93c433bb2923fff8badb98e463474365531c1cd5f880
|
||||
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
|
||||
F test/without_rowid5.test 89b1c587bd92a0590e440da33e7666bf4891572a
|
||||
F test/without_rowid6.test 1f99644e6508447fb050f73697350c7ceca3392e
|
||||
@ -1759,7 +1763,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 9057e27e12ded07a9ea0b2868036d3019f7bc5be3a67e3d341f56b762d3de9d9
|
||||
R 3130dca95e718b6cbbaac719dc665d6a
|
||||
U drh
|
||||
Z 0d8f7c300159980e6dfc3b9bdb17b906
|
||||
P 8f48991dcbb01e21d065fbba7782a6d1aebaa8065841a70a76af1e5a21f18ea4 8a28a326d7f72ab94c7d089dbc047e719038b6cd410068dec0d173a7655c87ca
|
||||
R 2f5689c57a4e86b56b7049238d0df17b
|
||||
U dan
|
||||
Z 7b23a2a6c7e81f02ef801f3d49dd8665
|
||||
|
@ -1 +1 @@
|
||||
8f48991dcbb01e21d065fbba7782a6d1aebaa8065841a70a76af1e5a21f18ea4
|
||||
4da5998314ed2c694b0e242755930f5320af89ac5c148845392f0a2043d44d22
|
1605
src/alter.c
1605
src/alter.c
File diff suppressed because it is too large
Load Diff
@ -207,7 +207,7 @@ int sqlite3AuthCheck(
|
||||
/* Don't do any authorization checks if the database is initialising
|
||||
** or if the parser is being invoked from within sqlite3_declare_vtab.
|
||||
*/
|
||||
if( db->init.busy || IN_DECLARE_VTAB ){
|
||||
if( db->init.busy || IN_SPECIAL_PARSE ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
271
src/build.c
271
src/build.c
@ -439,7 +439,7 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
|
||||
/*
|
||||
** Reclaim the memory used by an index
|
||||
*/
|
||||
static void freeIndex(sqlite3 *db, Index *p){
|
||||
void sqlite3FreeIndex(sqlite3 *db, Index *p){
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
sqlite3DeleteIndexSamples(db, p);
|
||||
#endif
|
||||
@ -479,7 +479,7 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
||||
p->pNext = pIndex->pNext;
|
||||
}
|
||||
}
|
||||
freeIndex(db, pIndex);
|
||||
sqlite3FreeIndex(db, pIndex);
|
||||
}
|
||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
||||
}
|
||||
@ -625,7 +625,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
|
||||
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
||||
assert( pOld==pIndex || pOld==0 );
|
||||
}
|
||||
freeIndex(db, pIndex);
|
||||
sqlite3FreeIndex(db, pIndex);
|
||||
}
|
||||
|
||||
/* Delete any foreign keys attached to this table. */
|
||||
@ -783,7 +783,7 @@ int sqlite3TwoPartName(
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
assert( db->init.iDb==0 || db->init.busy
|
||||
assert( db->init.iDb==0 || db->init.busy || IN_RENAME_OBJECT
|
||||
|| (db->mDbFlags & DBFLAG_Vacuum)!=0);
|
||||
iDb = db->init.iDb;
|
||||
*pUnqual = pName1;
|
||||
@ -878,6 +878,9 @@ void sqlite3StartTable(
|
||||
}
|
||||
if( !OMIT_TEMPDB && isTemp ) iDb = 1;
|
||||
zName = sqlite3NameFromToken(db, pName);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenMap(pParse, (void*)zName, pName);
|
||||
}
|
||||
}
|
||||
pParse->sNameToken = *pName;
|
||||
if( zName==0 ) return;
|
||||
@ -913,7 +916,7 @@ void sqlite3StartTable(
|
||||
** and types will be used, so there is no need to test for namespace
|
||||
** collisions.
|
||||
*/
|
||||
if( !IN_DECLARE_VTAB ){
|
||||
if( !IN_SPECIAL_PARSE ){
|
||||
char *zDb = db->aDb[iDb].zDbSName;
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto begin_table_error;
|
||||
@ -1072,6 +1075,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
}
|
||||
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
|
||||
if( z==0 ) return;
|
||||
if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, pName);
|
||||
memcpy(z, pName->z, pName->n);
|
||||
z[pName->n] = 0;
|
||||
sqlite3Dequote(z);
|
||||
@ -1278,6 +1282,9 @@ void sqlite3AddDefaultValue(
|
||||
sqlite3DbFree(db, x.u.zToken);
|
||||
}
|
||||
}
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameExprUnmap(pParse, pExpr);
|
||||
}
|
||||
sqlite3ExprDelete(db, pExpr);
|
||||
}
|
||||
|
||||
@ -1369,6 +1376,9 @@ void sqlite3AddPrimaryKey(
|
||||
&& sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
|
||||
&& sortOrder!=SQLITE_SO_DESC
|
||||
){
|
||||
if( IN_RENAME_OBJECT && pList ){
|
||||
sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pList->a[0].pExpr);
|
||||
}
|
||||
pTab->iPKey = iCol;
|
||||
pTab->keyConf = (u8)onError;
|
||||
assert( autoInc==0 || autoInc==1 );
|
||||
@ -2171,7 +2181,12 @@ void sqlite3CreateView(
|
||||
** allocated rather than point to the input string - which means that
|
||||
** they will persist after the current sqlite3_exec() call returns.
|
||||
*/
|
||||
p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
p->pSelect = pSelect;
|
||||
pSelect = 0;
|
||||
}else{
|
||||
p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
||||
}
|
||||
p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
|
||||
if( db->mallocFailed ) goto create_view_fail;
|
||||
|
||||
@ -2739,6 +2754,9 @@ void sqlite3CreateForeignKey(
|
||||
pFKey->pNextFrom = p->pFKey;
|
||||
z = (char*)&pFKey->aCol[nCol];
|
||||
pFKey->zTo = z;
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenMap(pParse, (void*)z, pTo);
|
||||
}
|
||||
memcpy(z, pTo->z, pTo->n);
|
||||
z[pTo->n] = 0;
|
||||
sqlite3Dequote(z);
|
||||
@ -2761,12 +2779,18 @@ void sqlite3CreateForeignKey(
|
||||
pFromCol->a[i].zName);
|
||||
goto fk_end;
|
||||
}
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pToCol ){
|
||||
for(i=0; i<nCol; i++){
|
||||
int n = sqlite3Strlen30(pToCol->a[i].zName);
|
||||
pFKey->aCol[i].zCol = z;
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zName);
|
||||
}
|
||||
memcpy(z, pToCol->a[i].zName, n);
|
||||
z[n] = 0;
|
||||
z += n+1;
|
||||
@ -3099,21 +3123,23 @@ void sqlite3CreateIndex(
|
||||
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( !db->init.busy ){
|
||||
if( sqlite3FindTable(db, zName, 0)!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
|
||||
if( !IN_RENAME_OBJECT ){
|
||||
if( !db->init.busy ){
|
||||
if( sqlite3FindTable(db, zName, 0)!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
|
||||
goto exit_create_index;
|
||||
}
|
||||
}
|
||||
if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){
|
||||
if( !ifNotExist ){
|
||||
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
||||
}else{
|
||||
assert( !db->init.busy );
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
}
|
||||
goto exit_create_index;
|
||||
}
|
||||
}
|
||||
if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){
|
||||
if( !ifNotExist ){
|
||||
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
||||
}else{
|
||||
assert( !db->init.busy );
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
}
|
||||
goto exit_create_index;
|
||||
}
|
||||
}else{
|
||||
int n;
|
||||
Index *pLoop;
|
||||
@ -3128,13 +3154,13 @@ void sqlite3CreateIndex(
|
||||
** The following statement converts "sqlite3_autoindex..." into
|
||||
** "sqlite3_butoindex..." in order to make the names distinct.
|
||||
** The "vtab_err.test" test demonstrates the need of this statement. */
|
||||
if( IN_DECLARE_VTAB ) zName[7]++;
|
||||
if( IN_SPECIAL_PARSE ) zName[7]++;
|
||||
}
|
||||
|
||||
/* Check for authorization to create an index.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
if( !IN_RENAME_OBJECT ){
|
||||
const char *zDb = pDb->zDbSName;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
|
||||
goto exit_create_index;
|
||||
@ -3221,7 +3247,12 @@ void sqlite3CreateIndex(
|
||||
** TODO: Issue a warning if the table primary key is used as part of the
|
||||
** index key.
|
||||
*/
|
||||
for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
|
||||
pListItem = pList->a;
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pIndex->aColExpr = pList;
|
||||
pList = 0;
|
||||
}
|
||||
for(i=0; i<pIndex->nKeyCol; i++, pListItem++){
|
||||
Expr *pCExpr; /* The i-th index expression */
|
||||
int requestedSortOrder; /* ASC or DESC on the i-th expression */
|
||||
const char *zColl; /* Collation sequence name */
|
||||
@ -3237,12 +3268,8 @@ void sqlite3CreateIndex(
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( pIndex->aColExpr==0 ){
|
||||
ExprList *pCopy = sqlite3ExprListDup(db, pList, 0);
|
||||
pIndex->aColExpr = pCopy;
|
||||
if( !db->mallocFailed ){
|
||||
assert( pCopy!=0 );
|
||||
pListItem = &pCopy->a[i];
|
||||
}
|
||||
pIndex->aColExpr = pList;
|
||||
pList = 0;
|
||||
}
|
||||
j = XN_EXPR;
|
||||
pIndex->aiColumn[i] = XN_EXPR;
|
||||
@ -3381,98 +3408,101 @@ void sqlite3CreateIndex(
|
||||
}
|
||||
}
|
||||
|
||||
/* Link the new Index structure to its table and to the other
|
||||
** in-memory database structures.
|
||||
*/
|
||||
assert( pParse->nErr==0 );
|
||||
if( db->init.busy ){
|
||||
Index *p;
|
||||
assert( !IN_DECLARE_VTAB );
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
||||
p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
|
||||
pIndex->zName, pIndex);
|
||||
if( p ){
|
||||
assert( p==pIndex ); /* Malloc must have failed */
|
||||
sqlite3OomFault(db);
|
||||
goto exit_create_index;
|
||||
}
|
||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
||||
if( pTblName!=0 ){
|
||||
pIndex->tnum = db->init.newTnum;
|
||||
}
|
||||
}
|
||||
if( !IN_RENAME_OBJECT ){
|
||||
|
||||
/* If this is the initial CREATE INDEX statement (or CREATE TABLE if the
|
||||
** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then
|
||||
** emit code to allocate the index rootpage on disk and make an entry for
|
||||
** the index in the sqlite_master table and populate the index with
|
||||
** content. But, do not do this if we are simply reading the sqlite_master
|
||||
** table to parse the schema, or if this index is the PRIMARY KEY index
|
||||
** of a WITHOUT ROWID table.
|
||||
**
|
||||
** If pTblName==0 it means this index is generated as an implied PRIMARY KEY
|
||||
** or UNIQUE index in a CREATE TABLE statement. Since the table
|
||||
** has just been created, it contains no data and the index initialization
|
||||
** step can be skipped.
|
||||
*/
|
||||
else if( HasRowid(pTab) || pTblName!=0 ){
|
||||
Vdbe *v;
|
||||
char *zStmt;
|
||||
int iMem = ++pParse->nMem;
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto exit_create_index;
|
||||
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
|
||||
/* Create the rootpage for the index using CreateIndex. But before
|
||||
** doing so, code a Noop instruction and store its address in
|
||||
** Index.tnum. This is required in case this index is actually a
|
||||
** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
|
||||
** that case the convertToWithoutRowidTable() routine will replace
|
||||
** the Noop with a Goto to jump over the VDBE code generated below. */
|
||||
pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
|
||||
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
|
||||
|
||||
/* Gather the complete text of the CREATE INDEX statement into
|
||||
** the zStmt variable
|
||||
/* Link the new Index structure to its table and to the other
|
||||
** in-memory database structures.
|
||||
*/
|
||||
if( pStart ){
|
||||
int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
|
||||
if( pName->z[n-1]==';' ) n--;
|
||||
/* A named index with an explicit CREATE INDEX statement */
|
||||
zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
|
||||
onError==OE_None ? "" : " UNIQUE", n, pName->z);
|
||||
}else{
|
||||
/* An automatic index created by a PRIMARY KEY or UNIQUE constraint */
|
||||
/* zStmt = sqlite3MPrintf(""); */
|
||||
zStmt = 0;
|
||||
assert( pParse->nErr==0 );
|
||||
if( db->init.busy ){
|
||||
Index *p;
|
||||
assert( !IN_SPECIAL_PARSE );
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
||||
p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
|
||||
pIndex->zName, pIndex);
|
||||
if( p ){
|
||||
assert( p==pIndex ); /* Malloc must have failed */
|
||||
sqlite3OomFault(db);
|
||||
goto exit_create_index;
|
||||
}
|
||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
||||
if( pTblName!=0 ){
|
||||
pIndex->tnum = db->init.newTnum;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add an entry in sqlite_master for this index
|
||||
/* If this is the initial CREATE INDEX statement (or CREATE TABLE if the
|
||||
** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then
|
||||
** emit code to allocate the index rootpage on disk and make an entry for
|
||||
** the index in the sqlite_master table and populate the index with
|
||||
** content. But, do not do this if we are simply reading the sqlite_master
|
||||
** table to parse the schema, or if this index is the PRIMARY KEY index
|
||||
** of a WITHOUT ROWID table.
|
||||
**
|
||||
** If pTblName==0 it means this index is generated as an implied PRIMARY KEY
|
||||
** or UNIQUE index in a CREATE TABLE statement. Since the table
|
||||
** has just been created, it contains no data and the index initialization
|
||||
** step can be skipped.
|
||||
*/
|
||||
sqlite3NestedParse(pParse,
|
||||
"INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
|
||||
db->aDb[iDb].zDbSName, MASTER_NAME,
|
||||
pIndex->zName,
|
||||
pTab->zName,
|
||||
iMem,
|
||||
zStmt
|
||||
);
|
||||
sqlite3DbFree(db, zStmt);
|
||||
else if( HasRowid(pTab) || pTblName!=0 ){
|
||||
Vdbe *v;
|
||||
char *zStmt;
|
||||
int iMem = ++pParse->nMem;
|
||||
|
||||
/* Fill the index with data and reparse the schema. Code an OP_Expire
|
||||
** to invalidate all pre-compiled statements.
|
||||
*/
|
||||
if( pTblName ){
|
||||
sqlite3RefillIndex(pParse, pIndex, iMem);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto exit_create_index;
|
||||
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
|
||||
/* Create the rootpage for the index using CreateIndex. But before
|
||||
** doing so, code a Noop instruction and store its address in
|
||||
** Index.tnum. This is required in case this index is actually a
|
||||
** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
|
||||
** that case the convertToWithoutRowidTable() routine will replace
|
||||
** the Noop with a Goto to jump over the VDBE code generated below. */
|
||||
pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
|
||||
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
|
||||
|
||||
/* Gather the complete text of the CREATE INDEX statement into
|
||||
** the zStmt variable
|
||||
*/
|
||||
if( pStart ){
|
||||
int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
|
||||
if( pName->z[n-1]==';' ) n--;
|
||||
/* A named index with an explicit CREATE INDEX statement */
|
||||
zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
|
||||
onError==OE_None ? "" : " UNIQUE", n, pName->z);
|
||||
}else{
|
||||
/* An automatic index created by a PRIMARY KEY or UNIQUE constraint */
|
||||
/* zStmt = sqlite3MPrintf(""); */
|
||||
zStmt = 0;
|
||||
}
|
||||
|
||||
/* Add an entry in sqlite_master for this index
|
||||
*/
|
||||
sqlite3NestedParse(pParse,
|
||||
"INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
|
||||
db->aDb[iDb].zDbSName, MASTER_NAME,
|
||||
pIndex->zName,
|
||||
pTab->zName,
|
||||
iMem,
|
||||
zStmt
|
||||
);
|
||||
sqlite3DbFree(db, zStmt);
|
||||
|
||||
/* Fill the index with data and reparse the schema. Code an OP_Expire
|
||||
** to invalidate all pre-compiled statements.
|
||||
*/
|
||||
if( pTblName ){
|
||||
sqlite3RefillIndex(pParse, pIndex, iMem);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
|
||||
}
|
||||
|
||||
sqlite3VdbeJumpHere(v, pIndex->tnum);
|
||||
}
|
||||
|
||||
sqlite3VdbeJumpHere(v, pIndex->tnum);
|
||||
}
|
||||
|
||||
/* When adding an index to the list of indices for a table, make
|
||||
@ -3496,10 +3526,15 @@ void sqlite3CreateIndex(
|
||||
}
|
||||
pIndex = 0;
|
||||
}
|
||||
else if( IN_RENAME_OBJECT ){
|
||||
assert( pParse->pNewIndex==0 );
|
||||
pParse->pNewIndex = pIndex;
|
||||
pIndex = 0;
|
||||
}
|
||||
|
||||
/* Clean up before exiting */
|
||||
exit_create_index:
|
||||
if( pIndex ) freeIndex(db, pIndex);
|
||||
if( pIndex ) sqlite3FreeIndex(db, pIndex);
|
||||
sqlite3ExprDelete(db, pPIWhere);
|
||||
sqlite3ExprListDelete(db, pList);
|
||||
sqlite3SrcListDelete(db, pTblName);
|
||||
@ -3668,7 +3703,8 @@ void *sqlite3ArrayAllocate(
|
||||
**
|
||||
** A new IdList is returned, or NULL if malloc() fails.
|
||||
*/
|
||||
IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
|
||||
IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
|
||||
sqlite3 *db = pParse->db;
|
||||
int i;
|
||||
if( pList==0 ){
|
||||
pList = sqlite3DbMallocZero(db, sizeof(IdList) );
|
||||
@ -3686,6 +3722,9 @@ IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
|
||||
return 0;
|
||||
}
|
||||
pList->a[i].zName = sqlite3NameFromToken(db, pToken);
|
||||
if( IN_RENAME_OBJECT && pList->a[i].zName ){
|
||||
sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken);
|
||||
}
|
||||
return pList;
|
||||
}
|
||||
|
||||
@ -3932,6 +3971,10 @@ SrcList *sqlite3SrcListAppendFromTerm(
|
||||
}
|
||||
assert( p->nSrc>0 );
|
||||
pItem = &p->a[p->nSrc-1];
|
||||
if( IN_RENAME_OBJECT && pItem->zName ){
|
||||
Token *pToken = (pDatabase && pDatabase->z) ? pDatabase : pTable;
|
||||
sqlite3RenameTokenMap(pParse, pItem->zName, pToken);
|
||||
}
|
||||
assert( pAlias!=0 );
|
||||
if( pAlias->n ){
|
||||
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
|
||||
|
@ -1666,6 +1666,9 @@ void sqlite3ExprListSetName(
|
||||
assert( pItem->zName==0 );
|
||||
pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
|
||||
if( dequote ) sqlite3Dequote(pItem->zName);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenMap(pParse, (void*)pItem->zName, pName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
57
src/parse.y
57
src/parse.y
@ -325,7 +325,7 @@ ccons ::= DEFAULT scanpt id(X). {
|
||||
sqlite3ExprIdToTrueFalse(p);
|
||||
testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) );
|
||||
}
|
||||
sqlite3AddDefaultValue(pParse,p,X.z,X.z+X.n);
|
||||
sqlite3AddDefaultValue(pParse,p,X.z,X.z+X.n);
|
||||
}
|
||||
|
||||
// In addition to the type name, we also care about the primary key and
|
||||
@ -683,10 +683,14 @@ dbnm(A) ::= DOT nm(X). {A = X;}
|
||||
|
||||
%type fullname {SrcList*}
|
||||
%destructor fullname {sqlite3SrcListDelete(pParse->db, $$);}
|
||||
fullname(A) ::= nm(X).
|
||||
{A = sqlite3SrcListAppend(pParse->db,0,&X,0); /*A-overwrites-X*/}
|
||||
fullname(A) ::= nm(X) DOT nm(Y).
|
||||
{A = sqlite3SrcListAppend(pParse->db,0,&X,&Y); /*A-overwrites-X*/}
|
||||
fullname(A) ::= nm(X). {
|
||||
A = sqlite3SrcListAppend(pParse->db,0,&X,0);
|
||||
if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &X);
|
||||
}
|
||||
fullname(A) ::= nm(X) DOT nm(Y). {
|
||||
A = sqlite3SrcListAppend(pParse->db,0,&X,&Y);
|
||||
if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &Y);
|
||||
}
|
||||
|
||||
%type xfullname {SrcList*}
|
||||
%destructor xfullname {sqlite3SrcListDelete(pParse->db, $$);}
|
||||
@ -908,9 +912,9 @@ insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
|
||||
idlist_opt(A) ::= . {A = 0;}
|
||||
idlist_opt(A) ::= LP idlist(X) RP. {A = X;}
|
||||
idlist(A) ::= idlist(A) COMMA nm(Y).
|
||||
{A = sqlite3IdListAppend(pParse->db,A,&Y);}
|
||||
{A = sqlite3IdListAppend(pParse,A,&Y);}
|
||||
idlist(A) ::= nm(Y).
|
||||
{A = sqlite3IdListAppend(pParse->db,0,&Y); /*A-overwrites-Y*/}
|
||||
{A = sqlite3IdListAppend(pParse,0,&Y); /*A-overwrites-Y*/}
|
||||
|
||||
/////////////////////////// Expression Processing /////////////////////////////
|
||||
//
|
||||
@ -929,10 +933,21 @@ idlist(A) ::= nm(Y).
|
||||
static Expr *tokenExpr(Parse *pParse, int op, Token t){
|
||||
Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
|
||||
if( p ){
|
||||
memset(p, 0, sizeof(Expr));
|
||||
/* memset(p, 0, sizeof(Expr)); */
|
||||
p->op = (u8)op;
|
||||
p->affinity = 0;
|
||||
p->flags = EP_Leaf;
|
||||
p->iAgg = -1;
|
||||
p->pLeft = p->pRight = 0;
|
||||
p->x.pList = 0;
|
||||
p->pAggInfo = 0;
|
||||
p->pTab = 0;
|
||||
p->op2 = 0;
|
||||
p->iTable = 0;
|
||||
p->iColumn = 0;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
p->pWin = 0;
|
||||
#endif
|
||||
p->u.zToken = (char*)&p[1];
|
||||
memcpy(p->u.zToken, t.z, t.n);
|
||||
p->u.zToken[t.n] = 0;
|
||||
@ -943,9 +958,13 @@ idlist(A) ::= nm(Y).
|
||||
#if SQLITE_MAX_EXPR_DEPTH>0
|
||||
p->nHeight = 1;
|
||||
#endif
|
||||
if( IN_RENAME_OBJECT ){
|
||||
return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
expr(A) ::= term(A).
|
||||
@ -955,6 +974,10 @@ expr(A) ::= JOIN_KW(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/}
|
||||
expr(A) ::= nm(X) DOT nm(Y). {
|
||||
Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1);
|
||||
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenMap(pParse, (void*)temp2, &Y);
|
||||
sqlite3RenameTokenMap(pParse, (void*)temp1, &X);
|
||||
}
|
||||
A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
|
||||
}
|
||||
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
|
||||
@ -962,6 +985,10 @@ expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
|
||||
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
|
||||
Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &Z, 1);
|
||||
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenMap(pParse, (void*)temp3, &Z);
|
||||
sqlite3RenameTokenMap(pParse, (void*)temp2, &Y);
|
||||
}
|
||||
A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
|
||||
}
|
||||
term(A) ::= NULL|FLOAT|BLOB(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/}
|
||||
@ -1260,6 +1287,9 @@ cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
|
||||
sqlite3CreateIndex(pParse, &X, &D,
|
||||
sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
|
||||
&S, W, SQLITE_SO_ASC, NE, SQLITE_IDXTYPE_APPDEF);
|
||||
if( IN_RENAME_OBJECT && pParse->pNewIndex ){
|
||||
sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &Y);
|
||||
}
|
||||
}
|
||||
|
||||
%type uniqueflag {int}
|
||||
@ -1445,16 +1475,16 @@ tridxby ::= NOT INDEXED. {
|
||||
// UPDATE
|
||||
trigger_cmd(A) ::=
|
||||
UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z) scanpt(E).
|
||||
{A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R, B.z, E);}
|
||||
{A = sqlite3TriggerUpdateStep(pParse, &X, Y, Z, R, B.z, E);}
|
||||
|
||||
// INSERT
|
||||
trigger_cmd(A) ::= scanpt(B) insert_cmd(R) INTO
|
||||
trnm(X) idlist_opt(F) select(S) upsert(U) scanpt(Z). {
|
||||
A = sqlite3TriggerInsertStep(pParse->db,&X,F,S,R,U,B,Z);/*A-overwrites-R*/
|
||||
A = sqlite3TriggerInsertStep(pParse,&X,F,S,R,U,B,Z);/*A-overwrites-R*/
|
||||
}
|
||||
// DELETE
|
||||
trigger_cmd(A) ::= DELETE(B) FROM trnm(X) tridxby where_opt(Y) scanpt(E).
|
||||
{A = sqlite3TriggerDeleteStep(pParse->db, &X, Y, B.z, E);}
|
||||
{A = sqlite3TriggerDeleteStep(pParse, &X, Y, B.z, E);}
|
||||
|
||||
// SELECT
|
||||
trigger_cmd(A) ::= scanpt(B) select(X) scanpt(E).
|
||||
@ -1532,8 +1562,13 @@ add_column_fullname ::= fullname(X). {
|
||||
disableLookaside(pParse);
|
||||
sqlite3AlterBeginAddColumn(pParse, X);
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X) RENAME kwcolumn_opt nm(Y) TO nm(Z). {
|
||||
sqlite3AlterRenameColumn(pParse, X, &Y, &Z);
|
||||
}
|
||||
|
||||
kwcolumn_opt ::= .
|
||||
kwcolumn_opt ::= COLUMNKW.
|
||||
|
||||
%endif SQLITE_OMIT_ALTERTABLE
|
||||
|
||||
//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
|
||||
|
@ -25,15 +25,23 @@ static void corruptSchema(
|
||||
const char *zExtra /* Error information */
|
||||
){
|
||||
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;
|
||||
if( zObj==0 ) zObj = "?";
|
||||
z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
|
||||
if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
|
||||
sqlite3DbFree(db, *pData->pzErrMsg);
|
||||
*pData->pzErrMsg = z;
|
||||
pData->rc = SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -85,7 +93,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
rc = db->errCode;
|
||||
assert( (rc&0xFF)==(rcp&0xFF) );
|
||||
db->init.iDb = saved_iDb;
|
||||
assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 );
|
||||
/* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */
|
||||
if( SQLITE_OK!=rc ){
|
||||
if( db->init.orphanTrigger ){
|
||||
assert( iDb==1 );
|
||||
@ -132,7 +140,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
** auxiliary databases. Return one of the SQLITE_ error codes to
|
||||
** indicate success or failure.
|
||||
*/
|
||||
static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
int rc;
|
||||
int i;
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
@ -167,6 +175,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
initData.iDb = iDb;
|
||||
initData.rc = SQLITE_OK;
|
||||
initData.pzErrMsg = pzErrMsg;
|
||||
initData.mInitFlags = mFlags;
|
||||
sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
|
||||
if( initData.rc ){
|
||||
rc = initData.rc;
|
||||
@ -373,14 +382,14 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
assert( db->nDb>0 );
|
||||
/* Do the main schema first */
|
||||
if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
|
||||
rc = sqlite3InitOne(db, 0, pzErrMsg);
|
||||
rc = sqlite3InitOne(db, 0, pzErrMsg, 0);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
/* All other schemas after the main schema. The "temp" schema must be last */
|
||||
for(i=db->nDb-1; i>0; i--){
|
||||
assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) );
|
||||
if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
|
||||
rc = sqlite3InitOne(db, i, pzErrMsg);
|
||||
rc = sqlite3InitOne(db, i, pzErrMsg, 0);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
}
|
||||
|
113
src/resolve.c
113
src/resolve.c
@ -264,6 +264,9 @@ static int lookupName(
|
||||
if( sqlite3StrICmp(zTabName, zTab)!=0 ){
|
||||
continue;
|
||||
}
|
||||
if( IN_RENAME_OBJECT && pItem->zAlias ){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->pTab);
|
||||
}
|
||||
}
|
||||
if( 0==(cntTab++) ){
|
||||
pMatch = pItem;
|
||||
@ -349,9 +352,15 @@ static int lookupName(
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
if( pExpr->iTable==2 ){
|
||||
testcase( iCol==(-1) );
|
||||
pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
|
||||
eNewExprOp = TK_REGISTER;
|
||||
ExprSetProperty(pExpr, EP_Alias);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pExpr->iColumn = iCol;
|
||||
pExpr->pTab = pTab;
|
||||
eNewExprOp = TK_COLUMN;
|
||||
}else{
|
||||
pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
|
||||
eNewExprOp = TK_REGISTER;
|
||||
ExprSetProperty(pExpr, EP_Alias);
|
||||
}
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_UPSERT */
|
||||
{
|
||||
@ -436,6 +445,9 @@ static int lookupName(
|
||||
cnt = 1;
|
||||
pMatch = 0;
|
||||
assert( zTab==0 && zDb==0 );
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);
|
||||
}
|
||||
goto lookupname_end;
|
||||
}
|
||||
}
|
||||
@ -663,17 +675,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
zTable = 0;
|
||||
zColumn = pExpr->u.zToken;
|
||||
}else{
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
|
||||
pRight = pExpr->pRight;
|
||||
if( pRight->op==TK_ID ){
|
||||
zDb = 0;
|
||||
zTable = pExpr->pLeft->u.zToken;
|
||||
zColumn = pRight->u.zToken;
|
||||
}else{
|
||||
assert( pRight->op==TK_DOT );
|
||||
zDb = pExpr->pLeft->u.zToken;
|
||||
zTable = pRight->pLeft->u.zToken;
|
||||
zColumn = pRight->pRight->u.zToken;
|
||||
zDb = pLeft->u.zToken;
|
||||
pLeft = pRight->pLeft;
|
||||
pRight = pRight->pRight;
|
||||
}
|
||||
zTable = pLeft->u.zToken;
|
||||
zColumn = pRight->u.zToken;
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight);
|
||||
}
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, (void*)&pExpr->pTab, (void*)pLeft);
|
||||
}
|
||||
}
|
||||
return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
|
||||
@ -757,56 +776,58 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
}
|
||||
|
||||
if( 0==IN_RENAME_OBJECT ){
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX)
|
||||
assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX)
|
||||
|| (pDef->xValue==0 && pDef->xInverse==0)
|
||||
|| (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize)
|
||||
);
|
||||
if( pDef && pDef->xValue==0 && pExpr->pWin ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"%.*s() may not be used as a window function", nId, zId
|
||||
);
|
||||
pNC->nErr++;
|
||||
}else if(
|
||||
(is_agg && (pNC->ncFlags & NC_AllowAgg)==0)
|
||||
|| (is_agg && (pDef->funcFlags & SQLITE_FUNC_WINDOW) && !pExpr->pWin)
|
||||
|| (is_agg && pExpr->pWin && (pNC->ncFlags & NC_AllowWin)==0)
|
||||
){
|
||||
const char *zType;
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->pWin ){
|
||||
zType = "window";
|
||||
}else{
|
||||
zType = "aggregate";
|
||||
if( pDef && pDef->xValue==0 && pExpr->pWin ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"%.*s() may not be used as a window function", nId, zId
|
||||
);
|
||||
pNC->nErr++;
|
||||
}else if(
|
||||
(is_agg && (pNC->ncFlags & NC_AllowAgg)==0)
|
||||
|| (is_agg && (pDef->funcFlags & SQLITE_FUNC_WINDOW) && !pExpr->pWin)
|
||||
|| (is_agg && pExpr->pWin && (pNC->ncFlags & NC_AllowWin)==0)
|
||||
){
|
||||
const char *zType;
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->pWin ){
|
||||
zType = "window";
|
||||
}else{
|
||||
zType = "aggregate";
|
||||
}
|
||||
sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId);
|
||||
pNC->nErr++;
|
||||
is_agg = 0;
|
||||
}
|
||||
sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()", zType, nId,zId);
|
||||
pNC->nErr++;
|
||||
is_agg = 0;
|
||||
}
|
||||
#else
|
||||
if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){
|
||||
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
|
||||
pNC->nErr++;
|
||||
is_agg = 0;
|
||||
}
|
||||
if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){
|
||||
sqlite3ErrorMsg(pParse,"misuse of aggregate function %.*s()",nId,zId);
|
||||
pNC->nErr++;
|
||||
is_agg = 0;
|
||||
}
|
||||
#endif
|
||||
else if( no_such_func && pParse->db->init.busy==0
|
||||
else if( no_such_func && pParse->db->init.busy==0
|
||||
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
&& pParse->explain==0
|
||||
&& pParse->explain==0
|
||||
#endif
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
|
||||
pNC->nErr++;
|
||||
}else if( wrong_num_args ){
|
||||
sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
|
||||
nId, zId);
|
||||
pNC->nErr++;
|
||||
}
|
||||
if( is_agg ){
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
|
||||
pNC->nErr++;
|
||||
}else if( wrong_num_args ){
|
||||
sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
|
||||
nId, zId);
|
||||
pNC->nErr++;
|
||||
}
|
||||
if( is_agg ){
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
pNC->ncFlags &= ~(pExpr->pWin ? NC_AllowWin : NC_AllowAgg);
|
||||
pNC->ncFlags &= ~(pExpr->pWin ? NC_AllowWin : NC_AllowAgg);
|
||||
#else
|
||||
pNC->ncFlags &= ~NC_AllowAgg;
|
||||
pNC->ncFlags &= ~NC_AllowAgg;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
sqlite3WalkExprList(pWalker, pList);
|
||||
if( is_agg ){
|
||||
|
@ -1088,6 +1088,7 @@ typedef struct NameContext NameContext;
|
||||
typedef struct Parse Parse;
|
||||
typedef struct PreUpdate PreUpdate;
|
||||
typedef struct PrintfArguments PrintfArguments;
|
||||
typedef struct RenameToken RenameToken;
|
||||
typedef struct RowSet RowSet;
|
||||
typedef struct Savepoint Savepoint;
|
||||
typedef struct Select Select;
|
||||
@ -2281,9 +2282,11 @@ struct IndexSample {
|
||||
** Each token coming out of the lexer is an instance of
|
||||
** this structure. Tokens are also used as part of an expression.
|
||||
**
|
||||
** Note if Token.z==0 then Token.dyn and Token.n are undefined and
|
||||
** may contain random values. Do not make any assumptions about Token.dyn
|
||||
** and Token.n when Token.z==0.
|
||||
** The memory that "z" points to is owned by other objects. Take care
|
||||
** that the owner of the "z" string does not deallocate the string before
|
||||
** the Token goes out of scope! Very often, the "z" points to some place
|
||||
** in the middle of the Parse.zSql text. But it might also point to a
|
||||
** static string.
|
||||
*/
|
||||
struct Token {
|
||||
const char *z; /* Text of the token. Not NULL-terminated! */
|
||||
@ -3088,8 +3091,10 @@ struct Parse {
|
||||
ynVar nVar; /* Number of '?' variables seen in the SQL so far */
|
||||
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
|
||||
u8 explain; /* True if the EXPLAIN flag is found on the query */
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_ALTERTABLE)
|
||||
u8 eParseMode; /* PARSE_MODE_XXX constant */
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
|
||||
int nVtabLock; /* Number of virtual tables to lock */
|
||||
#endif
|
||||
int nHeight; /* Expression tree height of current sub-select */
|
||||
@ -3100,6 +3105,7 @@ struct Parse {
|
||||
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
|
||||
const char *zTail; /* All SQL text past the last semicolon parsed */
|
||||
Table *pNewTable; /* A table being constructed by CREATE TABLE */
|
||||
Index *pNewIndex; /* An index being constructed by CREATE INDEX */
|
||||
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
|
||||
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
@ -3110,8 +3116,16 @@ struct Parse {
|
||||
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
|
||||
With *pWith; /* Current WITH clause, or NULL */
|
||||
With *pWithToFree; /* Free this WITH object at the end of the parse */
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define PARSE_MODE_NORMAL 0
|
||||
#define PARSE_MODE_DECLARE_VTAB 1
|
||||
#define PARSE_MODE_RENAME_COLUMN 2
|
||||
#define PARSE_MODE_RENAME_TABLE 3
|
||||
|
||||
/*
|
||||
** Sizes and pointers of various parts of the Parse object.
|
||||
*/
|
||||
@ -3126,7 +3140,19 @@ struct Parse {
|
||||
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
||||
#define IN_DECLARE_VTAB 0
|
||||
#else
|
||||
#define IN_DECLARE_VTAB (pParse->declareVtab)
|
||||
#define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB)
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_OMIT_ALTERTABLE)
|
||||
#define IN_RENAME_OBJECT 0
|
||||
#else
|
||||
#define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME_COLUMN)
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE)
|
||||
#define IN_SPECIAL_PARSE 0
|
||||
#else
|
||||
#define IN_SPECIAL_PARSE (pParse->eParseMode!=PARSE_MODE_NORMAL)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -3305,8 +3331,14 @@ typedef struct {
|
||||
char **pzErrMsg; /* Error message stored here */
|
||||
int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
|
||||
int rc; /* Result code stored here */
|
||||
u32 mInitFlags; /* Flags controlling error messages */
|
||||
} 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.
|
||||
**
|
||||
@ -3410,6 +3442,7 @@ struct Walker {
|
||||
Select *pSelect; /* HAVING to WHERE clause ctx */
|
||||
struct WindowRewrite *pRewrite; /* Window rewrite context */
|
||||
struct WhereConst *pConst; /* WHERE clause constants */
|
||||
struct RenameCtx *pRename; /* RENAME COLUMN context */
|
||||
} u;
|
||||
};
|
||||
|
||||
@ -3609,9 +3642,7 @@ int sqlite3CantopenError(int);
|
||||
# define sqlite3Tolower(x) tolower((unsigned char)(x))
|
||||
# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
int sqlite3IsIdChar(u8);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Internal function prototypes
|
||||
@ -3776,6 +3807,7 @@ void sqlite3ExprListDelete(sqlite3*, ExprList*);
|
||||
u32 sqlite3ExprListFlags(const ExprList*);
|
||||
int sqlite3Init(sqlite3*, char**);
|
||||
int sqlite3InitCallback(void*, int, char**, char**);
|
||||
int sqlite3InitOne(sqlite3*, int, char**, u32);
|
||||
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
|
||||
@ -3846,6 +3878,7 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int);
|
||||
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
||||
void sqlite3CodeDropTable(Parse*, Table*, int, int);
|
||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
void sqlite3FreeIndex(sqlite3*, Index*);
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
void sqlite3AutoincrementBegin(Parse *pParse);
|
||||
void sqlite3AutoincrementEnd(Parse *pParse);
|
||||
@ -3855,7 +3888,7 @@ void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
#endif
|
||||
void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*);
|
||||
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
|
||||
IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
|
||||
IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
|
||||
int sqlite3IdListIndex(IdList*,const char*);
|
||||
SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int);
|
||||
SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*);
|
||||
@ -4017,12 +4050,12 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
|
||||
void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
|
||||
TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
|
||||
const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
|
||||
TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*,
|
||||
Select*,u8,Upsert*,
|
||||
const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8,
|
||||
TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,ExprList*, Expr*, u8,
|
||||
const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*,
|
||||
TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*,
|
||||
const char*,const char*);
|
||||
void sqlite3DeleteTrigger(sqlite3*, Trigger*);
|
||||
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
|
||||
@ -4190,6 +4223,7 @@ void sqlite3RootPageMoved(sqlite3*, int, int, int);
|
||||
void sqlite3Reindex(Parse*, Token*, Token*);
|
||||
void sqlite3AlterFunctions(void);
|
||||
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
||||
void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
|
||||
int sqlite3GetToken(const unsigned char *, int *);
|
||||
void sqlite3NestedParse(Parse*, const char*, ...);
|
||||
void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
||||
@ -4205,6 +4239,9 @@ int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
|
||||
void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
|
||||
void sqlite3AlterFinishAddColumn(Parse *, Token *);
|
||||
void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
|
||||
void *sqlite3RenameTokenMap(Parse*, void*, Token*);
|
||||
void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom);
|
||||
void sqlite3RenameExprUnmap(Parse*, Expr*);
|
||||
CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
|
||||
char sqlite3AffinityType(const char*, Column*);
|
||||
void sqlite3Analyze(Parse*, Token*, Token*);
|
||||
|
@ -184,10 +184,8 @@ const char sqlite3IsEbcdicIdChar[] = {
|
||||
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
|
||||
#endif
|
||||
|
||||
/* Make the IdChar function accessible from ctime.c */
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
/* Make the IdChar function accessible from ctime.c and alter.c */
|
||||
int sqlite3IsIdChar(u8 c){ return IdChar(c); }
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/*
|
||||
@ -690,16 +688,18 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
sqlite3_free(pParse->apVtabLock);
|
||||
#endif
|
||||
|
||||
if( !IN_DECLARE_VTAB ){
|
||||
if( !IN_SPECIAL_PARSE ){
|
||||
/* If the pParse->declareVtab flag is set, do not delete any table
|
||||
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
|
||||
** will take responsibility for freeing the Table structure.
|
||||
*/
|
||||
sqlite3DeleteTable(db, pParse->pNewTable);
|
||||
}
|
||||
if( !IN_RENAME_OBJECT ){
|
||||
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
||||
}
|
||||
|
||||
if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
|
||||
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
||||
sqlite3DbFree(db, pParse->pVList);
|
||||
while( pParse->pAinc ){
|
||||
AutoincInfo *p = pParse->pAinc;
|
||||
|
@ -181,14 +181,16 @@ void sqlite3BeginTrigger(
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
|
||||
}else{
|
||||
assert( !db->init.busy );
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
if( !IN_RENAME_OBJECT ){
|
||||
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
|
||||
}else{
|
||||
assert( !db->init.busy );
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
}
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
/* Do not create a trigger on a system table */
|
||||
@ -212,7 +214,7 @@ void sqlite3BeginTrigger(
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
if( !IN_RENAME_OBJECT ){
|
||||
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
int code = SQLITE_CREATE_TRIGGER;
|
||||
const char *zDb = db->aDb[iTabDb].zDbSName;
|
||||
@ -246,8 +248,15 @@ void sqlite3BeginTrigger(
|
||||
pTrigger->pTabSchema = pTab->pSchema;
|
||||
pTrigger->op = (u8)op;
|
||||
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
|
||||
pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
|
||||
pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName);
|
||||
pTrigger->pWhen = pWhen;
|
||||
pWhen = 0;
|
||||
}else{
|
||||
pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
|
||||
}
|
||||
pTrigger->pColumns = pColumns;
|
||||
pColumns = 0;
|
||||
assert( pParse->pNewTrigger==0 );
|
||||
pParse->pNewTrigger = pTrigger;
|
||||
|
||||
@ -296,6 +305,14 @@ void sqlite3FinishTrigger(
|
||||
goto triggerfinish_cleanup;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
if( IN_RENAME_OBJECT ){
|
||||
assert( !db->init.busy );
|
||||
pParse->pNewTrigger = pTrig;
|
||||
pTrig = 0;
|
||||
}else
|
||||
#endif
|
||||
|
||||
/* if we are not initializing,
|
||||
** build the sqlite_master entry
|
||||
*/
|
||||
@ -337,7 +354,7 @@ void sqlite3FinishTrigger(
|
||||
|
||||
triggerfinish_cleanup:
|
||||
sqlite3DeleteTrigger(db, pTrig);
|
||||
assert( !pParse->pNewTrigger );
|
||||
assert( IN_RENAME_OBJECT || !pParse->pNewTrigger );
|
||||
sqlite3DeleteTriggerStep(db, pStepList);
|
||||
}
|
||||
|
||||
@ -384,12 +401,13 @@ TriggerStep *sqlite3TriggerSelectStep(
|
||||
** If an OOM error occurs, NULL is returned and db->mallocFailed is set.
|
||||
*/
|
||||
static TriggerStep *triggerStepAllocate(
|
||||
sqlite3 *db, /* Database connection */
|
||||
Parse *pParse, /* Parser context */
|
||||
u8 op, /* Trigger opcode */
|
||||
Token *pName, /* The target name */
|
||||
const char *zStart, /* Start of SQL text */
|
||||
const char *zEnd /* End of SQL text */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
TriggerStep *pTriggerStep;
|
||||
|
||||
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1);
|
||||
@ -400,6 +418,9 @@ static TriggerStep *triggerStepAllocate(
|
||||
pTriggerStep->zTarget = z;
|
||||
pTriggerStep->op = op;
|
||||
pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName);
|
||||
}
|
||||
}
|
||||
return pTriggerStep;
|
||||
}
|
||||
@ -412,7 +433,7 @@ static TriggerStep *triggerStepAllocate(
|
||||
** body of a trigger.
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerInsertStep(
|
||||
sqlite3 *db, /* The database connection */
|
||||
Parse *pParse, /* Parser */
|
||||
Token *pTableName, /* Name of the table into which we insert */
|
||||
IdList *pColumn, /* List of columns in pTableName to insert into */
|
||||
Select *pSelect, /* A SELECT statement that supplies values */
|
||||
@ -421,13 +442,19 @@ TriggerStep *sqlite3TriggerInsertStep(
|
||||
const char *zStart, /* Start of SQL text */
|
||||
const char *zEnd /* End of SQL text */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
TriggerStep *pTriggerStep;
|
||||
|
||||
assert(pSelect != 0 || db->mallocFailed);
|
||||
|
||||
pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName, zStart, zEnd);
|
||||
pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd);
|
||||
if( pTriggerStep ){
|
||||
pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pTriggerStep->pSelect = pSelect;
|
||||
pSelect = 0;
|
||||
}else{
|
||||
pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
||||
}
|
||||
pTriggerStep->pIdList = pColumn;
|
||||
pTriggerStep->pUpsert = pUpsert;
|
||||
pTriggerStep->orconf = orconf;
|
||||
@ -448,7 +475,7 @@ TriggerStep *sqlite3TriggerInsertStep(
|
||||
** sees an UPDATE statement inside the body of a CREATE TRIGGER.
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerUpdateStep(
|
||||
sqlite3 *db, /* The database connection */
|
||||
Parse *pParse, /* Parser */
|
||||
Token *pTableName, /* Name of the table to be updated */
|
||||
ExprList *pEList, /* The SET clause: list of column and new values */
|
||||
Expr *pWhere, /* The WHERE clause */
|
||||
@ -456,12 +483,20 @@ TriggerStep *sqlite3TriggerUpdateStep(
|
||||
const char *zStart, /* Start of SQL text */
|
||||
const char *zEnd /* End of SQL text */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
TriggerStep *pTriggerStep;
|
||||
|
||||
pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName, zStart, zEnd);
|
||||
pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd);
|
||||
if( pTriggerStep ){
|
||||
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
|
||||
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pTriggerStep->pExprList = pEList;
|
||||
pTriggerStep->pWhere = pWhere;
|
||||
pEList = 0;
|
||||
pWhere = 0;
|
||||
}else{
|
||||
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
|
||||
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
||||
}
|
||||
pTriggerStep->orconf = orconf;
|
||||
}
|
||||
sqlite3ExprListDelete(db, pEList);
|
||||
@ -475,17 +510,23 @@ TriggerStep *sqlite3TriggerUpdateStep(
|
||||
** sees a DELETE statement inside the body of a CREATE TRIGGER.
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerDeleteStep(
|
||||
sqlite3 *db, /* Database connection */
|
||||
Parse *pParse, /* Parser */
|
||||
Token *pTableName, /* The table from which rows are deleted */
|
||||
Expr *pWhere, /* The WHERE clause */
|
||||
const char *zStart, /* Start of SQL text */
|
||||
const char *zEnd /* End of SQL text */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
TriggerStep *pTriggerStep;
|
||||
|
||||
pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName, zStart, zEnd);
|
||||
pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd);
|
||||
if( pTriggerStep ){
|
||||
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pTriggerStep->pWhere = pWhere;
|
||||
pWhere = 0;
|
||||
}else{
|
||||
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
||||
}
|
||||
pTriggerStep->orconf = OE_Default;
|
||||
}
|
||||
sqlite3ExprDelete(db, pWhere);
|
||||
|
15
src/vdbe.c
15
src/vdbe.c
@ -5722,7 +5722,8 @@ case OP_SqlExec: {
|
||||
/* Opcode: ParseSchema P1 * * P4 *
|
||||
**
|
||||
** 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,
|
||||
** then runs the new virtual machine. It is thus a re-entrant opcode.
|
||||
@ -5746,7 +5747,17 @@ case OP_ParseSchema: {
|
||||
iDb = pOp->p1;
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
|
||||
/* Used to be a conditional */ {
|
||||
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
if( pOp->p4.z==0 ){
|
||||
sqlite3SchemaClear(db->aDb[iDb].pSchema);
|
||||
db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
|
||||
rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
|
||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
||||
p->expired = 0;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
zMaster = MASTER_NAME;
|
||||
initData.db = db;
|
||||
initData.iDb = pOp->p1;
|
||||
|
@ -758,7 +758,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
assert( IsVirtual(pTab) );
|
||||
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.declareVtab = 1;
|
||||
sParse.eParseMode = PARSE_MODE_DECLARE_VTAB;
|
||||
sParse.db = db;
|
||||
sParse.nQueryLoop = 1;
|
||||
if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
|
||||
@ -799,7 +799,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
sqlite3DbFree(db, zErr);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
sParse.declareVtab = 0;
|
||||
sParse.eParseMode = PARSE_MODE_NORMAL;
|
||||
|
||||
if( sParse.pVdbe ){
|
||||
sqlite3VdbeFinalize(sParse.pVdbe);
|
||||
|
@ -681,21 +681,21 @@ do_test alter-8.2 {
|
||||
} {1 18 2 9}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# alter-9.X - Special test: Make sure the sqlite_rename_trigger() and
|
||||
# alter-9.X - Special test: Make sure the sqlite_rename_column() and
|
||||
# rename_table() functions do not crash when handed bad input.
|
||||
#
|
||||
ifcapable trigger {
|
||||
do_test alter-9.1 {
|
||||
execsql {SELECT SQLITE_RENAME_TRIGGER(0,0)}
|
||||
} {{}}
|
||||
do_test alter-9.1 {
|
||||
execsql {SELECT SQLITE_RENAME_COLUMN(0,0,0,0,0,0,0,0,0)}
|
||||
} {{}}
|
||||
foreach {tn sql} {
|
||||
1 { SELECT SQLITE_RENAME_TABLE(0,0,0,0,0,0,0) }
|
||||
2 { SELECT SQLITE_RENAME_TABLE(10,20,30,40,50,60,70) }
|
||||
3 { SELECT SQLITE_RENAME_TABLE('foo','foo','foo','foo','foo','foo','foo') }
|
||||
} {
|
||||
do_test alter-9.2.$tn {
|
||||
catch { execsql $sql }
|
||||
} 1
|
||||
}
|
||||
do_test alter-9.2 {
|
||||
execsql {
|
||||
SELECT SQLITE_RENAME_TABLE(0,0);
|
||||
SELECT SQLITE_RENAME_TABLE(10,20);
|
||||
SELECT SQLITE_RENAME_TABLE('foo', 'foo');
|
||||
}
|
||||
} {{} {} {}}
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# alter-10.X - Make sure ALTER TABLE works with multi-byte UTF-8 characters
|
||||
@ -875,51 +875,5 @@ do_execsql_test alter-16.2 {
|
||||
SELECT * FROM t16a_rn ORDER BY a;
|
||||
} {abc 1.25 99 xyzzy cba 5.5 98 fizzle}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Verify that NULL values into the internal-use-only sqlite_rename_*()
|
||||
# functions do not cause problems.
|
||||
#
|
||||
do_execsql_test alter-17.1 {
|
||||
SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)','abc');
|
||||
} {{CREATE TABLE "abc"(a,b,c)}}
|
||||
do_execsql_test alter-17.2 {
|
||||
SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)',NULL);
|
||||
} {{CREATE TABLE "(NULL)"(a,b,c)}}
|
||||
do_execsql_test alter-17.3 {
|
||||
SELECT sqlite_rename_table(NULL,'abc');
|
||||
} {{}}
|
||||
do_execsql_test alter-17.4 {
|
||||
SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN','abc');
|
||||
} {{CREATE TRIGGER r1 ON "abc" WHEN}}
|
||||
do_execsql_test alter-17.5 {
|
||||
SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN',NULL);
|
||||
} {{CREATE TRIGGER r1 ON "(NULL)" WHEN}}
|
||||
do_execsql_test alter-17.6 {
|
||||
SELECT sqlite_rename_trigger(NULL,'abc');
|
||||
} {{}}
|
||||
do_execsql_test alter-17.7 {
|
||||
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
|
||||
'xyzzy','lmnop');
|
||||
} {{CREATE TABLE t1(a REFERENCES "lmnop")}}
|
||||
do_execsql_test alter-17.8 {
|
||||
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
|
||||
'xyzzy',NULL);
|
||||
} {{CREATE TABLE t1(a REFERENCES "(NULL)")}}
|
||||
do_execsql_test alter-17.9 {
|
||||
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
|
||||
NULL, 'lmnop');
|
||||
} {{}}
|
||||
do_execsql_test alter-17.10 {
|
||||
SELECT sqlite_rename_parent(NULL,'abc','xyz');
|
||||
} {{}}
|
||||
do_execsql_test alter-17.11 {
|
||||
SELECT sqlite_rename_parent('create references ''','abc','xyz');
|
||||
} {{create references '}}
|
||||
do_execsql_test alter-17.12 {
|
||||
SELECT sqlite_rename_parent('create references "abc"123" ','abc','xyz');
|
||||
} {{create references "xyz"123" }}
|
||||
do_execsql_test alter-17.13 {
|
||||
SELECT sqlite_rename_parent("references '''",'abc','xyz');
|
||||
} {{references '''}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
@ -394,4 +394,32 @@ do_test alter4-10.1 {
|
||||
}
|
||||
} {ok}
|
||||
|
||||
reset_db
|
||||
do_execsql_test alter4-11.0 {
|
||||
CREATE TABLE t1(c INTEGER PRIMARY KEY, d);
|
||||
PRAGMA foreign_keys = on;
|
||||
ALTER TABLE t1 ADD COLUMN e;
|
||||
}
|
||||
|
||||
do_execsql_test alter4-11.1 {
|
||||
ALTER TABLE t1 ADD COLUMN f REFERENCES t1;
|
||||
}
|
||||
|
||||
do_catchsql_test alter4-11.2 {
|
||||
ALTER TABLE t1 ADD COLUMN g REFERENCES t1 DEFAULT 4;
|
||||
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
|
||||
|
||||
do_catchsql_test alter4-11.3 {
|
||||
ALTER TABLE t2 ADD COLUMN g;
|
||||
} {1 {no such table: t2}}
|
||||
|
||||
ifcapable fts5 {
|
||||
do_execsql_test alter4-11.4 {
|
||||
CREATE VIRTUAL TABLE fff USING fts5(f);
|
||||
}
|
||||
do_catchsql_test alter4-11.2 {
|
||||
ALTER TABLE fff ADD COLUMN g;
|
||||
} {1 {virtual tables may not be altered}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
755
test/altercol.test
Normal file
755
test/altercol.test
Normal file
@ -0,0 +1,755 @@
|
||||
# 2009 February 2
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing that SQLite can handle a subtle
|
||||
# file format change that may be used in the future to implement
|
||||
# "ALTER TABLE ... RENAME COLUMN ... TO".
|
||||
#
|
||||
# $Id: alter4.test,v 1.1 2009/02/02 18:03:22 drh Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix altercol
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Drop all the tables and views in the 'main' database of database connect
|
||||
# [db]. Sort the objects by name before dropping them.
|
||||
#
|
||||
proc drop_all_tables_and_views {db} {
|
||||
set SQL {
|
||||
SELECT name, type FROM sqlite_master
|
||||
WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
|
||||
ORDER BY 1
|
||||
}
|
||||
foreach {z t} [db eval $SQL] {
|
||||
db eval "DROP $t $z"
|
||||
}
|
||||
}
|
||||
|
||||
foreach {tn before after} {
|
||||
1 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB)}
|
||||
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB)}
|
||||
|
||||
2 {CREATE TABLE t1(a INTEGER, x TEXT, "b" BLOB)}
|
||||
{CREATE TABLE t1(a INTEGER, x TEXT, "d" BLOB)}
|
||||
|
||||
3 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, CHECK(b!=''))}
|
||||
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, CHECK(d!=''))}
|
||||
|
||||
4 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, CHECK(t1.b!=''))}
|
||||
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, CHECK(t1.d!=''))}
|
||||
|
||||
5 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, CHECK( coalesce(b,c) ))}
|
||||
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, CHECK( coalesce(d,c) ))}
|
||||
|
||||
6 {CREATE TABLE t1(a INTEGER, "b"TEXT, c BLOB, CHECK( coalesce(b,c) ))}
|
||||
{CREATE TABLE t1(a INTEGER, "d"TEXT, c BLOB, CHECK( coalesce(d,c) ))}
|
||||
|
||||
7 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, PRIMARY KEY(b, c))}
|
||||
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, PRIMARY KEY(d, c))}
|
||||
|
||||
8 {CREATE TABLE t1(a INTEGER, b TEXT PRIMARY KEY, c BLOB)}
|
||||
{CREATE TABLE t1(a INTEGER, d TEXT PRIMARY KEY, c BLOB)}
|
||||
|
||||
9 {CREATE TABLE t1(a, b TEXT, c, PRIMARY KEY(a, b), UNIQUE("B"))}
|
||||
{CREATE TABLE t1(a, d TEXT, c, PRIMARY KEY(a, d), UNIQUE("d"))}
|
||||
|
||||
10 {CREATE TABLE t1(a, b, c); CREATE INDEX t1i ON t1(a, c)}
|
||||
{{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(a, c)}}
|
||||
|
||||
11 {CREATE TABLE t1(a, b, c); CREATE INDEX t1i ON t1(b, c)}
|
||||
{{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(d, c)}}
|
||||
|
||||
12 {CREATE TABLE t1(a, b, c); CREATE INDEX t1i ON t1(b+b+b+b, c) WHERE b>0}
|
||||
{{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(d+d+d+d, c) WHERE d>0}}
|
||||
|
||||
13 {CREATE TABLE t1(a, b, c, FOREIGN KEY (b) REFERENCES t2)}
|
||||
{CREATE TABLE t1(a, d, c, FOREIGN KEY (d) REFERENCES t2)}
|
||||
|
||||
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)}
|
||||
|
||||
17 {CREATE TABLE t1(a INTEGER, b INTEGER PRIMARY KEY, c BLOB, FOREIGN KEY (b) REFERENCES t2)}
|
||||
{CREATE TABLE t1(a INTEGER, d INTEGER PRIMARY KEY, c BLOB, FOREIGN KEY (d) REFERENCES t2)}
|
||||
|
||||
} {
|
||||
reset_db
|
||||
do_execsql_test 1.$tn.0 $before
|
||||
|
||||
do_execsql_test 1.$tn.1 {
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
}
|
||||
|
||||
do_execsql_test 1.$tn.2 {
|
||||
ALTER TABLE t1 RENAME COLUMN b TO d;
|
||||
}
|
||||
|
||||
do_execsql_test 1.$tn.3 {
|
||||
SELECT * FROM t1;
|
||||
} {1 2 3}
|
||||
|
||||
if {[string first INDEX $before]>0} {
|
||||
set res $after
|
||||
} else {
|
||||
set res [list $after]
|
||||
}
|
||||
do_execsql_test 1.$tn.4 {
|
||||
SELECT sql FROM sqlite_master WHERE tbl_name='t1' AND sql!=''
|
||||
} $res
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t3(a, b, c, d, e, f, g, h, i, j, k, l, m, FOREIGN KEY (b, c, d, e, f, g, h, i, j, k, l, m) REFERENCES t4);
|
||||
}
|
||||
|
||||
sqlite3 db2 test.db
|
||||
do_execsql_test -db db2 2.1 { SELECT b FROM t3 }
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
ALTER TABLE t3 RENAME b TO biglongname;
|
||||
SELECT sql FROM sqlite_master WHERE name='t3';
|
||||
} {{CREATE TABLE t3(a, biglongname, c, d, e, f, g, h, i, j, k, l, m, FOREIGN KEY (biglongname, c, d, e, f, g, h, i, j, k, l, m) REFERENCES t4)}}
|
||||
|
||||
do_execsql_test -db db2 2.3 { SELECT biglongname FROM t3 }
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t4(x, y, z);
|
||||
CREATE TRIGGER ttt AFTER INSERT ON t4 WHEN new.y<0 BEGIN
|
||||
SELECT x, y, z FROM t4;
|
||||
DELETE FROM t4 WHERE y=32;
|
||||
UPDATE t4 SET x=y+1, y=0 WHERE y=32;
|
||||
INSERT INTO t4(x, y, z) SELECT 4, 5, 6 WHERE 0;
|
||||
END;
|
||||
INSERT INTO t4 VALUES(3, 2, 1);
|
||||
}
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
ALTER TABLE t4 RENAME y TO abc;
|
||||
SELECT sql FROM sqlite_master WHERE name='t4';
|
||||
} {{CREATE TABLE t4(x, abc, z)}}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
SELECT * FROM t4;
|
||||
} {3 2 1}
|
||||
|
||||
do_execsql_test 3.3 { INSERT INTO t4 VALUES(6, 5, 4); } {}
|
||||
|
||||
do_execsql_test 3.4 { SELECT sql FROM sqlite_master WHERE type='trigger' } {
|
||||
{CREATE TRIGGER ttt AFTER INSERT ON t4 WHEN new.abc<0 BEGIN
|
||||
SELECT x, abc, z FROM t4;
|
||||
DELETE FROM t4 WHERE abc=32;
|
||||
UPDATE t4 SET x=abc+1, abc=0 WHERE abc=32;
|
||||
INSERT INTO t4(x, abc, z) SELECT 4, 5, 6 WHERE 0;
|
||||
END}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE c1(a, b, FOREIGN KEY (a, b) REFERENCES p1(c, d));
|
||||
CREATE TABLE p1(c, d, PRIMARY KEY(c, d));
|
||||
PRAGMA foreign_keys = 1;
|
||||
INSERT INTO p1 VALUES(1, 2);
|
||||
INSERT INTO p1 VALUES(3, 4);
|
||||
}
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
ALTER TABLE p1 RENAME d TO "silly name";
|
||||
SELECT sql FROM sqlite_master WHERE name IN ('c1', 'p1');
|
||||
} {
|
||||
{CREATE TABLE c1(a, b, FOREIGN KEY (a, b) REFERENCES p1(c, "silly name"))}
|
||||
{CREATE TABLE p1(c, "silly name", PRIMARY KEY(c, "silly name"))}
|
||||
}
|
||||
|
||||
do_execsql_test 4.2 { INSERT INTO c1 VALUES(1, 2); }
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
CREATE TABLE c2(a, b, FOREIGN KEY (a, b) REFERENCES p1);
|
||||
}
|
||||
|
||||
do_execsql_test 4.4 {
|
||||
ALTER TABLE p1 RENAME "silly name" TO reasonable;
|
||||
SELECT sql FROM sqlite_master WHERE name IN ('c1', 'c2', 'p1');
|
||||
} {
|
||||
{CREATE TABLE c1(a, b, FOREIGN KEY (a, b) REFERENCES p1(c, "reasonable"))}
|
||||
{CREATE TABLE p1(c, "reasonable", PRIMARY KEY(c, "reasonable"))}
|
||||
{CREATE TABLE c2(a, b, FOREIGN KEY (a, b) REFERENCES p1)}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE t5(a, b, c);
|
||||
CREATE INDEX t5a ON t5(a);
|
||||
INSERT INTO t5 VALUES(1, 2, 3), (4, 5, 6);
|
||||
ANALYZE;
|
||||
}
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
ALTER TABLE t5 RENAME b TO big;
|
||||
SELECT big FROM t5;
|
||||
} {2 5}
|
||||
|
||||
do_catchsql_test 6.1 {
|
||||
ALTER TABLE sqlite_stat1 RENAME tbl TO thetable;
|
||||
} {1 {table sqlite_stat1 may not be altered}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 6.0 {
|
||||
CREATE TABLE blob(
|
||||
rid INTEGER PRIMARY KEY,
|
||||
rcvid INTEGER,
|
||||
size INTEGER,
|
||||
uuid TEXT UNIQUE NOT NULL,
|
||||
content BLOB,
|
||||
CHECK( length(uuid)>=40 AND rid>0 )
|
||||
);
|
||||
}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
ALTER TABLE "blob" RENAME COLUMN "rid" TO "a1";
|
||||
}
|
||||
|
||||
do_catchsql_test 6.2 {
|
||||
ALTER TABLE "blob" RENAME COLUMN "a1" TO [where];
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 6.3 {
|
||||
SELECT "where" FROM blob;
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Triggers.
|
||||
#
|
||||
db close
|
||||
db2 close
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE c(x);
|
||||
INSERT INTO c VALUES(0);
|
||||
CREATE TABLE t6("col a", "col b", "col c");
|
||||
CREATE TRIGGER zzz AFTER UPDATE OF "col a", "col c" ON t6 BEGIN
|
||||
UPDATE c SET x=x+1;
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 7.1.1 {
|
||||
INSERT INTO t6 VALUES(0, 0, 0);
|
||||
UPDATE t6 SET "col c" = 1;
|
||||
SELECT * FROM c;
|
||||
} {1}
|
||||
|
||||
do_execsql_test 7.1.2 {
|
||||
ALTER TABLE t6 RENAME "col c" TO "col 3";
|
||||
}
|
||||
|
||||
do_execsql_test 7.1.3 {
|
||||
UPDATE t6 SET "col 3" = 0;
|
||||
SELECT * FROM c;
|
||||
} {2}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# 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_catchsql_test 8.4.5 {
|
||||
CREATE VIEW zzz AS SELECT george, ringo FROM b1;
|
||||
ALTER TABLE b1 RENAME a TO aaa;
|
||||
} {1 {error in view zzz: no such column: george}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# More triggers.
|
||||
#
|
||||
proc do_rename_column_test {tn old new lSchema} {
|
||||
for {set i 0} {$i < 2} {incr i} {
|
||||
drop_all_tables_and_views db
|
||||
|
||||
set lSorted [list]
|
||||
foreach sql $lSchema {
|
||||
execsql $sql
|
||||
lappend lSorted [string trim $sql]
|
||||
}
|
||||
set lSorted [lsort $lSorted]
|
||||
|
||||
do_execsql_test $tn.$i.1 {
|
||||
SELECT sql FROM sqlite_master WHERE sql!='' ORDER BY 1
|
||||
} $lSorted
|
||||
|
||||
if {$i==1} {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
}
|
||||
|
||||
do_execsql_test $tn.$i.2 "ALTER TABLE t1 RENAME $old TO $new"
|
||||
|
||||
do_execsql_test $tn.$i.3 {
|
||||
SELECT sql FROM sqlite_master ORDER BY 1
|
||||
} [string map [list $old $new] $lSorted]
|
||||
}
|
||||
}
|
||||
|
||||
foreach {tn old new lSchema} {
|
||||
1 _x_ _xxx_ {
|
||||
{ CREATE TABLE t1(a, b, _x_) }
|
||||
{ CREATE TRIGGER AFTER INSERT ON t1 BEGIN
|
||||
SELECT _x_ FROM t1;
|
||||
END }
|
||||
}
|
||||
|
||||
2 _x_ _xxx_ {
|
||||
{ CREATE TABLE t1(a, b, _x_) }
|
||||
{ CREATE TABLE t2(c, d, e) }
|
||||
{ CREATE TRIGGER ttt AFTER INSERT ON t2 BEGIN
|
||||
SELECT _x_ FROM t1;
|
||||
END }
|
||||
}
|
||||
|
||||
3 _x_ _xxx_ {
|
||||
{ CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) }
|
||||
{ CREATE TABLE t2(c, d, e) }
|
||||
{ CREATE TRIGGER ttt AFTER UPDATE ON t1 BEGIN
|
||||
INSERT INTO t2 VALUES(new.a, new.b, new._x_);
|
||||
END }
|
||||
}
|
||||
|
||||
4 _x_ _xxx_ {
|
||||
{ CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) }
|
||||
{ CREATE TRIGGER ttt AFTER UPDATE ON t1 BEGIN
|
||||
INSERT INTO t1 VALUES(new.a, new.b, new._x_)
|
||||
ON CONFLICT (_x_) WHERE _x_>10 DO UPDATE SET _x_ = _x_+1;
|
||||
END }
|
||||
}
|
||||
|
||||
4 _x_ _xxx_ {
|
||||
{ CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) }
|
||||
{ CREATE TRIGGER ttt AFTER UPDATE ON t1 BEGIN
|
||||
INSERT INTO t1 VALUES(new.a, new.b, new._x_)
|
||||
ON CONFLICT (_x_) WHERE _x_>10 DO NOTHING;
|
||||
END }
|
||||
}
|
||||
} {
|
||||
do_rename_column_test 9.$tn $old $new $lSchema
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that views can be edited even if there are missing collation
|
||||
# sequences or user defined functions.
|
||||
#
|
||||
reset_db
|
||||
|
||||
foreach {tn old new lSchema} {
|
||||
1 _x_ _xxx_ {
|
||||
{ CREATE TABLE t1(a, b, _x_) }
|
||||
{ CREATE VIEW s1 AS SELECT a, b, _x_ FROM t1 WHERE _x_='abc' COLLATE xyz }
|
||||
}
|
||||
|
||||
2 _x_ _xxx_ {
|
||||
{ CREATE TABLE t1(a, b, _x_) }
|
||||
{ CREATE VIEW v1 AS SELECT a, b, _x_ FROM t1 WHERE scalar(_x_) }
|
||||
}
|
||||
|
||||
3 _x_ _xxx_ {
|
||||
{ CREATE TABLE t1(a, b, _x_) }
|
||||
{ CREATE VIEW v1 AS SELECT a, b, _x_ FROM t1 WHERE _x_ = unicode(1, 2, 3) }
|
||||
}
|
||||
|
||||
4 _x_ _xxx_ {
|
||||
{ CREATE TABLE t1(a, b, _x_) }
|
||||
{ CREATE VIRTUAL TABLE e1 USING echo(t1) }
|
||||
}
|
||||
} {
|
||||
register_echo_module db
|
||||
do_rename_column_test 10.$tn $old $new $lSchema
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Test that if a view or trigger refers to a virtual table for which the
|
||||
# module is not available, RENAME COLUMN cannot proceed.
|
||||
#
|
||||
reset_db
|
||||
register_echo_module db
|
||||
do_execsql_test 11.0 {
|
||||
CREATE TABLE x1(a, b, c);
|
||||
CREATE VIRTUAL TABLE e1 USING echo(x1);
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_execsql_test 11.1 {
|
||||
ALTER TABLE x1 RENAME b TO bbb;
|
||||
SELECT sql FROM sqlite_master;
|
||||
} { {CREATE TABLE x1(a, bbb, c)} {CREATE VIRTUAL TABLE e1 USING echo(x1)} }
|
||||
|
||||
do_execsql_test 11.2 {
|
||||
CREATE VIEW v1 AS SELECT e1.*, x1.c FROM e1, x1;
|
||||
}
|
||||
|
||||
do_catchsql_test 11.3 {
|
||||
ALTER TABLE x1 RENAME c TO ccc;
|
||||
} {1 {error in view v1: no such module: echo}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test some error conditions:
|
||||
#
|
||||
# 1. Renaming a column of a system table,
|
||||
# 2. Renaming a column of a VIEW,
|
||||
# 3. Renaming a column of a virtual table.
|
||||
# 4. Renaming a column that does not exist.
|
||||
# 5. Renaming a column of a table that does not exist.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 12.1.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
INSERT INTO t1 VALUES(1, 1), (2, 2), (3, 4);
|
||||
ANALYZE;
|
||||
}
|
||||
do_catchsql_test 12.1.2 {
|
||||
ALTER TABLE sqlite_stat1 RENAME idx TO theindex;
|
||||
} {1 {table sqlite_stat1 may not be altered}}
|
||||
do_execsql_test 12.1.3 {
|
||||
SELECT sql FROM sqlite_master WHERE tbl_name = 'sqlite_stat1'
|
||||
} {{CREATE TABLE sqlite_stat1(tbl,idx,stat)}}
|
||||
|
||||
do_execsql_test 12.2.1 {
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
CREATE VIEW v2(c, d) AS SELECT * FROM t1;
|
||||
}
|
||||
do_catchsql_test 12.2.2 {
|
||||
ALTER TABLE v1 RENAME a TO z;
|
||||
} {1 {cannot rename columns of view "v1"}}
|
||||
do_catchsql_test 12.2.3 {
|
||||
ALTER TABLE v2 RENAME c TO y;
|
||||
} {1 {cannot rename columns of view "v2"}}
|
||||
|
||||
ifcapable fts5 {
|
||||
do_execsql_test 12.3.1 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(a, b, c);
|
||||
}
|
||||
do_catchsql_test 12.3.2 {
|
||||
ALTER TABLE ft RENAME a TO z;
|
||||
} {1 {cannot rename columns of virtual table "ft"}}
|
||||
}
|
||||
|
||||
do_execsql_test 12.4.1 {
|
||||
CREATE TABLE t2(x, y, z);
|
||||
}
|
||||
do_catchsql_test 12.4.2 {
|
||||
ALTER TABLE t2 RENAME COLUMN a TO b;
|
||||
} {1 {no such column: "a"}}
|
||||
|
||||
do_catchsql_test 12.5.1 {
|
||||
ALTER TABLE t3 RENAME COLUMN a TO b;
|
||||
} {1 {no such table: t3}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the effect of some parse/resolve errors.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 13.1.1 {
|
||||
CREATE TABLE x1(i INTEGER, t TEXT UNIQUE);
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
|
||||
SELECT * FROM nosuchtable;
|
||||
END;
|
||||
}
|
||||
|
||||
do_catchsql_test 13.1.2 {
|
||||
ALTER TABLE x1 RENAME COLUMN t TO ttt;
|
||||
} {1 {error in trigger tr1: no such table: main.nosuchtable}}
|
||||
|
||||
do_execsql_test 13.1.3 {
|
||||
DROP TRIGGER tr1;
|
||||
CREATE INDEX x1i ON x1(i);
|
||||
SELECT sql FROM sqlite_master WHERE name='x1i';
|
||||
} {{CREATE INDEX x1i ON x1(i)}}
|
||||
|
||||
do_execsql_test 13.1.4 {
|
||||
PRAGMA writable_schema = 1;
|
||||
UPDATE sqlite_master SET sql = 'CREATE INDEX x1i ON x1(j)' WHERE name='x1i';
|
||||
} {}
|
||||
|
||||
do_catchsql_test 13.1.5 {
|
||||
ALTER TABLE x1 RENAME COLUMN t TO ttt;
|
||||
} {1 {error in index x1i: no such column: j}}
|
||||
|
||||
do_execsql_test 13.1.6 {
|
||||
UPDATE sqlite_master SET sql = '' WHERE name='x1i';
|
||||
} {}
|
||||
|
||||
do_catchsql_test 13.1.7 {
|
||||
ALTER TABLE x1 RENAME COLUMN t TO ttt;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
do_execsql_test 13.1.8 {
|
||||
DELETE FROM sqlite_master WHERE name = 'x1i';
|
||||
}
|
||||
|
||||
do_execsql_test 13.2.0 {
|
||||
CREATE TABLE data(x UNIQUE, y, z);
|
||||
}
|
||||
foreach {tn trigger error} {
|
||||
1 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
|
||||
UPDATE data SET x=x+1 WHERE zzz=new.i;
|
||||
END;
|
||||
} {no such column: zzz}
|
||||
|
||||
2 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
|
||||
INSERT INTO data(x, y) VALUES(new.i, new.t, 1)
|
||||
ON CONFLICT (x) DO UPDATE SET z=zz+1;
|
||||
END;
|
||||
} {no such column: zz}
|
||||
|
||||
3 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
|
||||
INSERT INTO x1(i, t) VALUES(new.i+1, new.t||'1')
|
||||
ON CONFLICT (tttttt) DO UPDATE SET t=i+1;
|
||||
END;
|
||||
} {no such column: tttttt}
|
||||
|
||||
4 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
|
||||
INSERT INTO nosuchtable VALUES(new.i, new.t);
|
||||
END;
|
||||
} {no such table: main.nosuchtable}
|
||||
} {
|
||||
do_execsql_test 13.2.$tn.1 "
|
||||
DROP TRIGGER IF EXISTS tr1;
|
||||
$trigger
|
||||
"
|
||||
|
||||
do_catchsql_test 13.2.$tn.2 {
|
||||
ALTER TABLE x1 RENAME COLUMN t TO ttt;
|
||||
} "1 {error in trigger tr1: $error}"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Passing invalid parameters directly to sqlite_rename_column().
|
||||
#
|
||||
do_execsql_test 14.1 {
|
||||
CREATE TABLE ddd(sql, type, object, db, tbl, icol, znew, bquote);
|
||||
INSERT INTO ddd VALUES(
|
||||
'CREATE TABLE x1(i INTEGER, t TEXT)',
|
||||
'table', 'x1', 'main', 'x1', -1, 'zzz', 0
|
||||
), (
|
||||
'CREATE TABLE x1(i INTEGER, t TEXT)',
|
||||
'table', 'x1', 'main', 'x1', 2, 'zzz', 0
|
||||
), (
|
||||
'CREATE TABLE x1(i INTEGER, t TEXT)',
|
||||
'table', 'x1', 'main', 'notable', 0, 'zzz', 0
|
||||
), (
|
||||
'CREATE TABLE x1(i INTEGER, t TEXT)',
|
||||
'table', 'x1', 'main', 'ddd', -1, 'zzz', 0
|
||||
);
|
||||
} {}
|
||||
|
||||
do_execsql_test 14.2 {
|
||||
SELECT
|
||||
sqlite_rename_column(sql, type, object, db, tbl, icol, znew, bquote, 0)
|
||||
FROM ddd;
|
||||
} {{} {} {} {}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 15.0 {
|
||||
CREATE TABLE xxx(a, b, c);
|
||||
SELECT a AS d FROM xxx WHERE d=0;
|
||||
}
|
||||
|
||||
do_execsql_test 15.1 {
|
||||
CREATE VIEW vvv AS SELECT a AS d FROM xxx WHERE d=0;
|
||||
ALTER TABLE xxx RENAME a TO xyz;
|
||||
}
|
||||
|
||||
do_execsql_test 15.2 {
|
||||
SELECT sql FROM sqlite_master WHERE type='view';
|
||||
} {{CREATE VIEW vvv AS SELECT xyz AS d FROM xxx WHERE d=0}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 16.1.0 {
|
||||
CREATE TABLE t1(a,b,c);
|
||||
CREATE TABLE t2(d,e,f);
|
||||
INSERT INTO t1 VALUES(1,2,3);
|
||||
INSERT INTO t2 VALUES(4,5,6);
|
||||
CREATE VIEW v4 AS SELECT a, d FROM t1, t2;
|
||||
SELECT * FROM v4;
|
||||
} {1 4}
|
||||
|
||||
do_catchsql_test 16.1.1 {
|
||||
ALTER TABLE t2 RENAME d TO a;
|
||||
} {1 {error in view v4 after rename: ambiguous column name: a}}
|
||||
|
||||
do_execsql_test 16.1.2 {
|
||||
SELECT * FROM v4;
|
||||
} {1 4}
|
||||
|
||||
do_execsql_test 16.1.3 {
|
||||
CREATE UNIQUE INDEX t2d ON t2(d);
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
|
||||
INSERT INTO t2 VALUES(new.a, new.b, new.c)
|
||||
ON CONFLICT(d) DO UPDATE SET f = excluded.f;
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 16.1.4 {
|
||||
INSERT INTO t1 VALUES(4, 8, 456);
|
||||
SELECT * FROM t2;
|
||||
} {4 5 456}
|
||||
|
||||
do_execsql_test 16.1.5 {
|
||||
ALTER TABLE t2 RENAME COLUMN f TO "big f";
|
||||
INSERT INTO t1 VALUES(4, 0, 20456);
|
||||
SELECT * FROM t2;
|
||||
} {4 5 20456}
|
||||
|
||||
do_execsql_test 16.1.6 {
|
||||
ALTER TABLE t1 RENAME COLUMN c TO "big c";
|
||||
INSERT INTO t1 VALUES(4, 0, 0);
|
||||
SELECT * FROM t2;
|
||||
} {4 5 0}
|
||||
|
||||
do_execsql_test 16.2.1 {
|
||||
CREATE VIEW temp.v5 AS SELECT "big c" FROM t1;
|
||||
SELECT * FROM v5;
|
||||
} {3 456 20456 0}
|
||||
|
||||
do_execsql_test 16.2.2 {
|
||||
ALTER TABLE t1 RENAME COLUMN "big c" TO reallybigc;
|
||||
} {}
|
||||
|
||||
do_execsql_test 16.2.3 {
|
||||
SELECT * FROM v5;
|
||||
} {3 456 20456 0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 17.0 {
|
||||
CREATE TABLE u7(x, y, z);
|
||||
CREATE TRIGGER u7t AFTER INSERT ON u7 BEGIN
|
||||
INSERT INTO u8 VALUES(new.x, new.y, new.z);
|
||||
END;
|
||||
} {}
|
||||
do_catchsql_test 17.1 {
|
||||
ALTER TABLE u7 RENAME x TO xxx;
|
||||
} {1 {error in trigger u7t: no such table: main.u8}}
|
||||
|
||||
do_execsql_test 17.2 {
|
||||
CREATE TEMP TABLE uu7(x, y, z);
|
||||
CREATE TRIGGER uu7t AFTER INSERT ON uu7 BEGIN
|
||||
INSERT INTO u8 VALUES(new.x, new.y, new.z);
|
||||
END;
|
||||
} {}
|
||||
do_catchsql_test 17.3 {
|
||||
ALTER TABLE uu7 RENAME x TO xxx;
|
||||
} {1 {error in trigger uu7t: no such table: u8}}
|
||||
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
do_execsql_test 18.0 {
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE t1(a);
|
||||
CREATE TABLE aux.log(v);
|
||||
CREATE TEMP TRIGGER tr1 AFTER INSERT ON t1 BEGIN
|
||||
INSERT INTO log VALUES(new.a);
|
||||
END;
|
||||
INSERT INTO t1 VALUES(111);
|
||||
SELECT v FROM log;
|
||||
} {111}
|
||||
|
||||
do_execsql_test 18.1 {
|
||||
ALTER TABLE t1 RENAME a TO b;
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
75
test/altermalloc2.test
Normal file
75
test/altermalloc2.test
Normal file
@ -0,0 +1,75 @@
|
||||
# 2018 August 20
|
||||
#
|
||||
# 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 altermalloc2
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(abcd, efgh);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 1 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
ALTER TABLE t1 RENAME abcd TO dcba
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
catch {db close}
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 2.0 {
|
||||
PRAGMA encoding = 'utf-16';
|
||||
CREATE TABLE t1(abcd, efgh);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 2 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
ALTER TABLE t1 RENAME abcd TO dcba
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t1(abcd, efgh);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1 WHERE abcd>efgh;
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 3 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
ALTER TABLE t1 RENAME abcd TO dcba
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
finish_test
|
371
test/altertab.test
Normal file
371
test/altertab.test
Normal file
@ -0,0 +1,371 @@
|
||||
# 2018 August 24
|
||||
#
|
||||
# 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 altertab
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, CHECK(t1.a != t1.b));
|
||||
|
||||
CREATE TABLE t2(a, b);
|
||||
CREATE INDEX t2expr ON t2(a) WHERE t2.b>0;
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT sql FROM sqlite_master
|
||||
} {
|
||||
{CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))}
|
||||
{CREATE TABLE t2(a, b)}
|
||||
{CREATE INDEX t2expr ON t2(a) WHERE t2.b>0}
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
ALTER TABLE t1 RENAME TO t1new;
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
CREATE TABLE t3(c, d);
|
||||
ALTER TABLE t3 RENAME TO t3new;
|
||||
DROP TABLE t3new;
|
||||
}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
SELECT sql FROM sqlite_master
|
||||
} {
|
||||
{CREATE TABLE "t1new"(a, b, CHECK("t1new".a != "t1new".b))}
|
||||
{CREATE TABLE t2(a, b)}
|
||||
{CREATE INDEX t2expr ON t2(a) WHERE t2.b>0}
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
ALTER TABLE t2 RENAME TO t2new;
|
||||
}
|
||||
do_execsql_test 1.4 {
|
||||
SELECT sql FROM sqlite_master
|
||||
} {
|
||||
{CREATE TABLE "t1new"(a, b, CHECK("t1new".a != "t1new".b))}
|
||||
{CREATE TABLE "t2new"(a, b)}
|
||||
{CREATE INDEX t2expr ON "t2new"(a) WHERE "t2new".b>0}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
register_echo_module db
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE abc(a, b, c);
|
||||
INSERT INTO abc VALUES(1, 2, 3);
|
||||
CREATE VIRTUAL TABLE eee USING echo('abc');
|
||||
SELECT * FROM eee;
|
||||
} {1 2 3}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
ALTER TABLE eee RENAME TO fff;
|
||||
SELECT * FROM fff;
|
||||
} {1 2 3}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_catchsql_test 2.2 {
|
||||
ALTER TABLE fff RENAME TO ggg;
|
||||
} {1 {no such module: echo}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE txx(a, b, c);
|
||||
INSERT INTO txx VALUES(1, 2, 3);
|
||||
CREATE VIEW vvv AS SELECT main.txx.a, txx.b, c FROM txx;
|
||||
CREATE VIEW uuu AS SELECT main.one.a, one.b, c FROM txx AS one;
|
||||
CREATE VIEW temp.ttt AS SELECT main.txx.a, txx.b, one.b, main.one.a FROM txx AS one, txx;
|
||||
}
|
||||
|
||||
do_execsql_test 3.1.1 {
|
||||
SELECT * FROM vvv;
|
||||
} {1 2 3}
|
||||
do_execsql_test 3.1.2 {
|
||||
ALTER TABLE txx RENAME TO "t xx";
|
||||
SELECT * FROM vvv;
|
||||
} {1 2 3}
|
||||
do_execsql_test 3.1.3 {
|
||||
SELECT sql FROM sqlite_master WHERE name='vvv';
|
||||
} {{CREATE VIEW vvv AS SELECT main."t xx".a, "t xx".b, c FROM "t xx"}}
|
||||
|
||||
|
||||
do_execsql_test 3.2.1 {
|
||||
SELECT * FROM uuu;
|
||||
} {1 2 3}
|
||||
do_execsql_test 3.2.2 {
|
||||
SELECT sql FROM sqlite_master WHERE name='uuu';;
|
||||
} {{CREATE VIEW uuu AS SELECT main.one.a, one.b, c FROM "t xx" AS one}}
|
||||
|
||||
do_execsql_test 3.3.1 {
|
||||
SELECT * FROM ttt;
|
||||
} {1 2 2 1}
|
||||
do_execsql_test 3.3.2 {
|
||||
SELECT sql FROM sqlite_temp_master WHERE name='ttt';
|
||||
} {{CREATE VIEW ttt AS SELECT main."t xx".a, "t xx".b, one.b, main.one.a FROM "t xx" AS one, "t xx"}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE table t1(x, y);
|
||||
CREATE table t2(a, b);
|
||||
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
|
||||
SELECT t1.x, * FROM t1, t2;
|
||||
INSERT INTO t2 VALUES(new.x, new.y);
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
ALTER TABLE t1 RENAME TO t11;
|
||||
INSERT INTO t11 VALUES(2, 2);
|
||||
ALTER TABLE t2 RENAME TO t22;
|
||||
INSERT INTO t11 VALUES(3, 3);
|
||||
}
|
||||
|
||||
proc squish {a} {
|
||||
string trim [regsub -all {[[:space:]][[:space:]]*} $a { }]
|
||||
}
|
||||
db func squish squish
|
||||
do_test 4.2 {
|
||||
execsql { SELECT squish(sql) FROM sqlite_master WHERE name = 'tr1' }
|
||||
} [list [squish {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON "t11" BEGIN
|
||||
SELECT "t11".x, * FROM "t11", "t22";
|
||||
INSERT INTO "t22" VALUES(new.x, new.y);
|
||||
END
|
||||
}]]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE t9(a, b, c);
|
||||
CREATE TABLE t10(a, b, c);
|
||||
CREATE TEMP TABLE t9(a, b, c);
|
||||
|
||||
CREATE TRIGGER temp.t9t AFTER INSERT ON temp.t9 BEGIN
|
||||
INSERT INTO t10 VALUES(new.a, new.b, new.c);
|
||||
END;
|
||||
|
||||
INSERT INTO temp.t9 VALUES(1, 2, 3);
|
||||
SELECT * FROM t10;
|
||||
} {1 2 3}
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
ALTER TABLE temp.t9 RENAME TO 't1234567890'
|
||||
}
|
||||
|
||||
do_execsql_test 5.2 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t2 VALUES(3, 4);
|
||||
CREATE VIEW v AS SELECT one.a, one.b, t2.a, t2.b FROM t1 AS one, t2;
|
||||
SELECT * FROM v;
|
||||
} {1 2 3 4}
|
||||
|
||||
do_catchsql_test 5.3 {
|
||||
ALTER TABLE t2 RENAME TO one;
|
||||
} {1 {error in view v after rename: ambiguous column name: one.a}}
|
||||
|
||||
do_execsql_test 5.4 {
|
||||
SELECT * FROM v
|
||||
} {1 2 3 4}
|
||||
|
||||
do_execsql_test 5.5 {
|
||||
DROP VIEW v;
|
||||
CREATE VIEW temp.vv AS SELECT one.a, one.b, t2.a, t2.b FROM t1 AS one, t2;
|
||||
SELECT * FROM vv;
|
||||
} {1 2 3 4}
|
||||
|
||||
do_catchsql_test 5.6 {
|
||||
ALTER TABLE t2 RENAME TO one;
|
||||
} {1 {error in view vv after rename: ambiguous column name: one.a}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
register_tcl_module db
|
||||
proc tcl_command {method args} {
|
||||
switch -- $method {
|
||||
xConnect {
|
||||
return "CREATE TABLE t1(a, b, c)"
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING tcl(tcl_command);
|
||||
}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
ALTER TABLE x1 RENAME TO x2;
|
||||
SELECT sql FROM sqlite_master WHERE name = 'x2'
|
||||
} {{CREATE VIRTUAL TABLE "x2" USING tcl(tcl_command)}}
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
CREATE TABLE ddd(db, sql, zOld, zNew, bTemp);
|
||||
INSERT INTO ddd VALUES(
|
||||
'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', 'ddd', NULL, 0
|
||||
), (
|
||||
'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', NULL, 'eee', 0
|
||||
), (
|
||||
'main', NULL, 'ddd', 'eee', 0
|
||||
);
|
||||
} {}
|
||||
|
||||
do_execsql_test 7.2 {
|
||||
SELECT
|
||||
sqlite_rename_table(db, 0, 0, sql, zOld, zNew, bTemp)
|
||||
FROM ddd;
|
||||
} {{} {} {}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
do_execsql_test 8.1 {
|
||||
ATTACH 'test.db2' AS aux;
|
||||
PRAGMA foreign_keys = on;
|
||||
CREATE TABLE aux.p1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE aux.c1(x INTEGER PRIMARY KEY, y REFERENCES p1(a));
|
||||
INSERT INTO aux.p1 VALUES(1, 1);
|
||||
INSERT INTO aux.p1 VALUES(2, 2);
|
||||
INSERT INTO aux.c1 VALUES(NULL, 2);
|
||||
CREATE TABLE aux.c2(x INTEGER PRIMARY KEY, y REFERENCES c1(a));
|
||||
}
|
||||
|
||||
do_execsql_test 8.2 {
|
||||
ALTER TABLE aux.p1 RENAME TO ppp;
|
||||
}
|
||||
|
||||
do_execsql_test 8.2 {
|
||||
INSERT INTO aux.c1 VALUES(NULL, 1);
|
||||
SELECT sql FROM aux.sqlite_master WHERE name = 'c1';
|
||||
} {{CREATE TABLE c1(x INTEGER PRIMARY KEY, y REFERENCES "ppp"(a))}}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 9.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE VIEW v1 AS SELECT * FROM t2;
|
||||
}
|
||||
do_catchsql_test 9.1 {
|
||||
ALTER TABLE t1 RENAME TO t3;
|
||||
} {1 {error in view v1: no such table: main.t2}}
|
||||
do_execsql_test 9.2 {
|
||||
DROP VIEW v1;
|
||||
CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN
|
||||
INSERT INTO t2 VALUES(new.a);
|
||||
END;
|
||||
}
|
||||
do_catchsql_test 9.3 {
|
||||
ALTER TABLE t1 RENAME TO t3;
|
||||
} {1 {error in trigger tr: no such table: main.t2}}
|
||||
|
||||
forcedelete test.db2
|
||||
do_execsql_test 9.4 {
|
||||
DROP TRIGGER tr;
|
||||
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN SELECT 1, 2, 3; END;
|
||||
|
||||
CREATE TABLE aux.t1(x);
|
||||
CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END;
|
||||
}
|
||||
do_execsql_test 9.5 {
|
||||
ALTER TABLE main.t1 RENAME TO t3;
|
||||
}
|
||||
do_execsql_test 9.6 {
|
||||
SELECT sql FROM sqlite_temp_master;
|
||||
SELECT sql FROM sqlite_master WHERE type='trigger';
|
||||
} {
|
||||
{CREATE TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END}
|
||||
{CREATE TRIGGER tr AFTER INSERT ON "t3" BEGIN SELECT 1, 2, 3; END}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
ifcapable fts5 {
|
||||
do_execsql_test 10.0 {
|
||||
CREATE VIRTUAL TABLE fff USING fts5(x, y, z);
|
||||
}
|
||||
|
||||
do_execsql_test 10.1 {
|
||||
BEGIN;
|
||||
INSERT INTO fff VALUES('a', 'b', 'c');
|
||||
ALTER TABLE fff RENAME TO ggg;
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 10.2 {
|
||||
SELECT * FROM ggg;
|
||||
} {a b c}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
db func trigger trigger
|
||||
set ::trigger [list]
|
||||
proc trigger {args} {
|
||||
lappend ::trigger $args
|
||||
}
|
||||
do_execsql_test 11.0 {
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.t1(a, b, c);
|
||||
CREATE TABLE main.t1(a, b, c);
|
||||
CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN
|
||||
SELECT trigger(new.a, new.b, new.c);
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 11.1 {
|
||||
INSERT INTO main.t1 VALUES(1, 2, 3);
|
||||
INSERT INTO aux.t1 VALUES(4, 5, 6);
|
||||
}
|
||||
do_test 11.2 { set ::trigger } {{4 5 6}}
|
||||
|
||||
do_execsql_test 11.3 {
|
||||
SELECT name, tbl_name FROM sqlite_temp_master;
|
||||
} {tr t1}
|
||||
|
||||
do_execsql_test 11.4 {
|
||||
ALTER TABLE main.t1 RENAME TO t2;
|
||||
SELECT name, tbl_name FROM sqlite_temp_master;
|
||||
} {tr t1}
|
||||
|
||||
do_execsql_test 11.5 {
|
||||
ALTER TABLE aux.t1 RENAME TO t2;
|
||||
SELECT name, tbl_name FROM sqlite_temp_master;
|
||||
} {tr t2}
|
||||
|
||||
do_execsql_test 11.6 {
|
||||
INSERT INTO aux.t2 VALUES(7, 8, 9);
|
||||
}
|
||||
do_test 11.7 { set ::trigger } {{4 5 6} {7 8 9}}
|
||||
|
||||
finish_test
|
||||
|
150
test/atrc.c
Normal file
150
test/atrc.c
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
** This program generates a script that stresses the ALTER TABLE statement.
|
||||
** Compile like this:
|
||||
**
|
||||
** gcc -g -c sqlite3.c
|
||||
** gcc -g -o atrc atrc.c sqlite3.o -ldl -lpthread
|
||||
**
|
||||
** Run the program this way:
|
||||
**
|
||||
** ./atrc DATABASE | ./sqlite3 DATABASE
|
||||
**
|
||||
** This program "atrc" generates a script that can be fed into an ordinary
|
||||
** command-line shell. The script performs many ALTER TABLE statements,
|
||||
** runs ".schema --indent" and "PRAGMA integrity_check;", does more
|
||||
** ALTER TABLE statements to restore the original schema, and then
|
||||
** runs "PRAGMA integrity_check" again. Every table and column has its
|
||||
** name changed. The entire script is contained within BEGIN...ROLLBACK
|
||||
** so that no changes are ever actually made to the database.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
** Generate the text of ALTER TABLE statements that will rename
|
||||
** every column in table zTable to a generic name composed from
|
||||
** zColPrefix and a sequential number. The generated text is
|
||||
** appended pConvert. If pUndo is not NULL, then SQL text that
|
||||
** will undo the change is appended to pUndo.
|
||||
**
|
||||
** The table to be converted must be in the "main" schema.
|
||||
*/
|
||||
int rename_all_columns_of_table(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zTab, /* Table whose columns should all be renamed */
|
||||
const char *zColPrefix, /* Prefix for new column names */
|
||||
sqlite3_str *pConvert, /* Append ALTER TABLE statements here */
|
||||
sqlite3_str *pUndo /* SQL to undo the change, if not NULL */
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
int cnt = 0;
|
||||
|
||||
rc = sqlite3_prepare_v2(db,
|
||||
"SELECT name FROM pragma_table_info(?1);",
|
||||
-1, &pStmt, 0);
|
||||
if( rc ) return rc;
|
||||
sqlite3_bind_text(pStmt, 1, zTab, -1, SQLITE_STATIC);
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
const char *zCol = (const char*)sqlite3_column_text(pStmt, 0);
|
||||
cnt++;
|
||||
sqlite3_str_appendf(pConvert,
|
||||
"ALTER TABLE \"%w\" RENAME COLUMN \"%w\" TO \"%w%d\";\n",
|
||||
zTab, zCol, zColPrefix, cnt
|
||||
);
|
||||
if( pUndo ){
|
||||
sqlite3_str_appendf(pUndo,
|
||||
"ALTER TABLE \"%w\" RENAME COLUMN \"%w%d\" TO \"%w\";\n",
|
||||
zTab, zColPrefix, cnt, zCol
|
||||
);
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Rename all tables and their columns in the main database
|
||||
*/
|
||||
int rename_all_tables(
|
||||
sqlite3 *db, /* Database connection */
|
||||
sqlite3_str *pConvert, /* Append SQL to do the rename here */
|
||||
sqlite3_str *pUndo /* Append SQL to undo the rename here */
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
int cnt = 0;
|
||||
|
||||
rc = sqlite3_prepare_v2(db,
|
||||
"SELECT name FROM sqlite_master WHERE type='table'"
|
||||
" AND name NOT LIKE 'sqlite_%';",
|
||||
-1, &pStmt, 0);
|
||||
if( rc ) return rc;
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
const char *zTab = (const char*)sqlite3_column_text(pStmt, 0);
|
||||
char *zNewTab;
|
||||
char zPrefix[2];
|
||||
|
||||
zPrefix[0] = (cnt%26) + 'a';
|
||||
zPrefix[1] = 0;
|
||||
zNewTab = sqlite3_mprintf("tx%d", ++cnt);
|
||||
if( pUndo ){
|
||||
sqlite3_str_appendf(pUndo,
|
||||
"ALTER TABLE \"%s\" RENAME TO \"%w\";\n",
|
||||
zNewTab, zTab
|
||||
);
|
||||
}
|
||||
rename_all_columns_of_table(db, zTab, zPrefix, pConvert, pUndo);
|
||||
sqlite3_str_appendf(pConvert,
|
||||
"ALTER TABLE \"%w\" RENAME TO \"%s\";\n",
|
||||
zTab, zNewTab
|
||||
);
|
||||
sqlite3_free(zNewTab);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a script that does this:
|
||||
**
|
||||
** (1) Start a transaction
|
||||
** (2) Rename all tables and columns to use generic names.
|
||||
** (3) Print the schema after this rename
|
||||
** (4) Run pragma integrity_check
|
||||
** (5) Do more ALTER TABLE statements to change the names back
|
||||
** (6) Run pragma integrity_check again
|
||||
** (7) Rollback the transaction
|
||||
*/
|
||||
int main(int argc, char **argv){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
sqlite3_str *pConvert;
|
||||
sqlite3_str *pUndo;
|
||||
char *zDbName;
|
||||
char *zSql1, *zSql2;
|
||||
if( argc!=2 ){
|
||||
fprintf(stderr, "Usage: %s DATABASE\n", argv[0]);
|
||||
}
|
||||
zDbName = argv[1];
|
||||
rc = sqlite3_open(zDbName, &db);
|
||||
if( rc ){
|
||||
fprintf(stderr, "sqlite3_open() returns %d\n", rc);
|
||||
return 1;
|
||||
}
|
||||
pConvert = sqlite3_str_new(db);
|
||||
pUndo = sqlite3_str_new(db);
|
||||
rename_all_tables(db, pConvert, pUndo);
|
||||
zSql1 = sqlite3_str_finish(pConvert);
|
||||
zSql2 = sqlite3_str_finish(pUndo);
|
||||
sqlite3_close(db);
|
||||
printf("BEGIN;\n");
|
||||
printf("%s", zSql1);
|
||||
sqlite3_free(zSql1);
|
||||
printf(".schema --indent\n");
|
||||
printf("PRAGMA integrity_check;\n");
|
||||
printf("%s", zSql2);
|
||||
sqlite3_free(zSql2);
|
||||
printf("PRAGMA integrity_check;\n");
|
||||
printf("ROLLBACK;\n");
|
||||
return 0;
|
||||
}
|
@ -2133,6 +2133,75 @@ ifcapable {cte} {
|
||||
} {1 {not authorized}}
|
||||
} ;# ifcapable cte
|
||||
|
||||
#
|
||||
# db eval {SELECT sql FROM temp.sqlite_master} {puts "TEMP: $sql;"}
|
||||
# db eval {SELECT sql FROM main.sqlite_master} {puts "MAIN: $sql;"}
|
||||
#
|
||||
# MAIN: CREATE TABLE "t2"(a,b,c);
|
||||
# MAIN: CREATE TABLE t4(a,b,c);
|
||||
# MAIN: CREATE INDEX t4i1 ON t4(a);
|
||||
# MAIN: CREATE INDEX t4i2 ON t4(b,a,c);
|
||||
# MAIN: CREATE TABLE sqlite_stat1(tbl,idx,stat);
|
||||
# MAIN: CREATE TABLE t1(a,b);
|
||||
#
|
||||
ifcapable altertable {
|
||||
do_test 1.350 {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_ALTER_TABLE"} {
|
||||
set ::authargs [list $arg1 $arg2 $arg3 $arg4]
|
||||
return SQLITE_OK
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {
|
||||
ALTER TABLE t1 RENAME COLUMN b TO bcdefg;
|
||||
}
|
||||
} {0 {}}
|
||||
do_execsql_test auth-1.351 {
|
||||
SELECT name FROM pragma_table_info('t1') ORDER BY cid;
|
||||
} {a bcdefg}
|
||||
do_test auth-1.352 {
|
||||
set authargs
|
||||
} {main t1 {} {}}
|
||||
do_test 1.353 {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_ALTER_TABLE"} {
|
||||
set ::authargs [list $arg1 $arg2 $arg3 $arg4]
|
||||
return SQLITE_IGNORE
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {
|
||||
ALTER TABLE t1 RENAME COLUMN bcdefg TO b;
|
||||
}
|
||||
} {0 {}}
|
||||
do_execsql_test auth-1.354 {
|
||||
SELECT name FROM pragma_table_info('t1') ORDER BY cid;
|
||||
} {a bcdefg}
|
||||
do_test auth-1.355 {
|
||||
set authargs
|
||||
} {main t1 {} {}}
|
||||
do_test 1.356 {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_ALTER_TABLE"} {
|
||||
set ::authargs [list $arg1 $arg2 $arg3 $arg4]
|
||||
return SQLITE_DENY
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {
|
||||
ALTER TABLE t1 RENAME COLUMN bcdefg TO b;
|
||||
}
|
||||
} {1 {not authorized}}
|
||||
do_execsql_test auth-1.356 {
|
||||
SELECT name FROM pragma_table_info('t1') ORDER BY cid;
|
||||
} {a bcdefg}
|
||||
do_test auth-1.357 {
|
||||
set authargs
|
||||
} {main t1 {} {}}
|
||||
}
|
||||
|
||||
|
||||
do_test auth-2.1 {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} {
|
||||
|
@ -983,7 +983,9 @@ ifcapable altertable {
|
||||
# Test the sqlite_rename_parent() function directly.
|
||||
#
|
||||
proc test_rename_parent {zCreate zOld zNew} {
|
||||
db eval {SELECT sqlite_rename_parent($zCreate, $zOld, $zNew)}
|
||||
db eval {SELECT sqlite_rename_table(
|
||||
'main', 'table', 't1', $zCreate, $zOld, $zNew, 0
|
||||
)}
|
||||
}
|
||||
do_test fkey2-14.2.1.1 {
|
||||
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
|
||||
|
@ -113,6 +113,6 @@ do_test trigger7-99.1 {
|
||||
db close
|
||||
catch { sqlite3 db test.db }
|
||||
catchsql { DROP TRIGGER t2r5 }
|
||||
} {1 {malformed database schema (t2r12)}}
|
||||
} {/1 {malformed database schema .*}/}
|
||||
|
||||
finish_test
|
||||
|
@ -949,7 +949,9 @@ ifcapable altertable {
|
||||
# Test the sqlite_rename_parent() function directly.
|
||||
#
|
||||
proc test_rename_parent {zCreate zOld zNew} {
|
||||
db eval {SELECT sqlite_rename_parent($zCreate, $zOld, $zNew)}
|
||||
db eval {SELECT sqlite_rename_table(
|
||||
'main', 'table', 't1', $zCreate, $zOld, $zNew, 0
|
||||
)}
|
||||
}
|
||||
do_test without_rowid3-14.2.1.1 {
|
||||
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
|
||||
|
Loading…
x
Reference in New Issue
Block a user