Experimental implementation of ALTER TABLE ... RENAME COLUMN. Still buggy.
FossilOrigin-Name: fa0fc01eb48a864f0a3d43f9b805d5ed2e530846ee0c34fcbc2eabd9e5696277
This commit is contained in:
parent
d98f53249c
commit
cf8f289542
33
manifest
33
manifest
@ -1,5 +1,5 @@
|
|||||||
C When\sa\scolumn\smust\sbe\sa\sconstant\sdue\sto\sWHERE\sclause\sand\sthe\svalue\sof\sthat\ncolumn\sis\sbeing\scoded\sas\sa\sconstant,\smake\ssure\sthe\saffinity\sis\scorrect.
|
C Experimental\simplementation\sof\sALTER\sTABLE\s...\sRENAME\sCOLUMN.\sStill\sbuggy.
|
||||||
D 2018-08-09T18:36:54.837
|
D 2018-08-09T20:47:01.074
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
|
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
|
||||||
@ -432,17 +432,17 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
|||||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||||
F src/alter.c 6beb476095a4cfeb95ebedb2e5e17894d1687b24fddd5b8761a4de120e0392c6
|
F src/alter.c 94baeaee1206dfed286b2a69c5e771519c9cf12253bfc3895ffa2198ce437bf0
|
||||||
F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9
|
F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9
|
||||||
F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a
|
F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a
|
||||||
F src/auth.c 8272da9ff761bf84f0357298ccc6e5924e3f7fac143c6587f06aa72b202445a2
|
F src/auth.c 32a5bbe3b755169ab6c66311c5225a3cd4f75a46c041f7fb117e0cbb68055114
|
||||||
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
|
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
|
||||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||||
F src/btree.c 3f5e1a03db871e627bf5da21092bf7434ecfc5c5980bbd7d45eba13341340173
|
F src/btree.c 3f5e1a03db871e627bf5da21092bf7434ecfc5c5980bbd7d45eba13341340173
|
||||||
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
|
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
|
||||||
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
|
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
|
||||||
F src/build.c fe407be13d1201bf386d2c629424e5c97a07bcfc6ef21cf6e888e50b792a6191
|
F src/build.c 1cdcd12f5df74f4545d9677d7beebe0281a648d0302fca6109e82ac12e13cfa2
|
||||||
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
|
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
|
||||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||||
F src/ctime.c b157b01081f92442f8b0218ddb93ddce8ebddad36dbddeecfdd771561dd4f387
|
F src/ctime.c b157b01081f92442f8b0218ddb93ddce8ebddad36dbddeecfdd771561dd4f387
|
||||||
@ -487,7 +487,7 @@ F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971
|
|||||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||||
F src/pager.c 76d29b8a960dcb8b67210f095899d91e4a90673a6674ea58cfd1115b705a7fb9
|
F src/pager.c 76d29b8a960dcb8b67210f095899d91e4a90673a6674ea58cfd1115b705a7fb9
|
||||||
F src/pager.h c571b064df842ec8f2e90855dead9acf4cbe0d1b2c05afe0ef0d0145f7fd0388
|
F src/pager.h c571b064df842ec8f2e90855dead9acf4cbe0d1b2c05afe0ef0d0145f7fd0388
|
||||||
F src/parse.y 704c94624d41d7d46a5467574130e55aa8029a563f4df538f0121475eae46e34
|
F src/parse.y b981ac4656a9289bd61d78705f238dc8d156a7feee4bf064d054de4e8f10ff53
|
||||||
F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
|
F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
|
||||||
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
||||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||||
@ -496,14 +496,14 @@ F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
|||||||
F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0
|
F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0
|
||||||
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
|
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
|
||||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||||
F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea
|
F src/resolve.c b51a48f33da36e0c2dd1ea5f0d10197c3e938a54086a69efce064ae41e2254e1
|
||||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||||
F src/select.c ae7396a314cc1bb1d767947cd57094e3a9ffcbb155ebc1b1c391e028c44a9a04
|
F src/select.c ae7396a314cc1bb1d767947cd57094e3a9ffcbb155ebc1b1c391e028c44a9a04
|
||||||
F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f
|
F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f
|
||||||
F src/sqlite.h.in c6451bb876adced3aba5b1682c6317d215c5eceaba21a6ce979e71a0b8d0bf95
|
F src/sqlite.h.in c6451bb876adced3aba5b1682c6317d215c5eceaba21a6ce979e71a0b8d0bf95
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
|
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
|
||||||
F src/sqliteInt.h a5d212bb7ae5cfc0540af6fb09eee2092a45fe083fac4191ee64ff70e7d4d78a
|
F src/sqliteInt.h 4c9dc8cf5a231803c295558696077263c6f0c6f5aa505343f5a1e30b19dc59cf
|
||||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||||
@ -561,7 +561,7 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
|
|||||||
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
|
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
|
||||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||||
F src/tokenize.c 01e96d1b639c3eb0b9ef90616e766d453935c554f1f7aa86b6db937b79554b97
|
F src/tokenize.c 3177575b587f3d0491ca5c3e937663ca3e91bf86adf4f2e8e9f7d0ab98bc66d3
|
||||||
F src/treeview.c e7a7f90552bb418533cdd0309b5eb71d4effa50165b880fc8c2001e613577e5f
|
F src/treeview.c e7a7f90552bb418533cdd0309b5eb71d4effa50165b880fc8c2001e613577e5f
|
||||||
F src/trigger.c 4ace6d1d5ba9a89822deb287317f33c810440526eafe185c2d8a48c31df1e995
|
F src/trigger.c 4ace6d1d5ba9a89822deb287317f33c810440526eafe185c2d8a48c31df1e995
|
||||||
F src/update.c 345ce35eb1332eb4829857aa8b1f65a614b07dae91d0346c0dc2baacafbcc51b
|
F src/update.c 345ce35eb1332eb4829857aa8b1f65a614b07dae91d0346c0dc2baacafbcc51b
|
||||||
@ -578,7 +578,7 @@ F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c9419
|
|||||||
F src/vdbemem.c 720df42ad8e5c7cb883573de40a185afef4a214903098a16f2bb14b62b2399b7
|
F src/vdbemem.c 720df42ad8e5c7cb883573de40a185afef4a214903098a16f2bb14b62b2399b7
|
||||||
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
|
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
|
||||||
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
|
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
|
||||||
F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14
|
F src/vtab.c 8665561f244c137a2d17b5c3e5910d7303054fe841c5d510e53f23beb0089594
|
||||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||||
F src/wal.c c617d78715e85d81fe5719b276d32186a37eb47a49d07a3d55ddbc541de043c9
|
F src/wal.c c617d78715e85d81fe5719b276d32186a37eb47a49d07a3d55ddbc541de043c9
|
||||||
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
|
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
|
||||||
@ -599,6 +599,7 @@ F test/alter.test b820ab9dcf85f8e3a65bc8326accb2f0c7be64ef
|
|||||||
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||||
F test/alter3.test 4d79934d812eaeacc6f22781a080f8cfe012fdc3
|
F test/alter3.test 4d79934d812eaeacc6f22781a080f8cfe012fdc3
|
||||||
F test/alter4.test b6d7b86860111864f6cddb54af313f5862dda23b
|
F test/alter4.test b6d7b86860111864f6cddb54af313f5862dda23b
|
||||||
|
F test/altercol.test 44fedc517b92f321418c0918a359456a1657614c6bcd22570c0368c2417a3a29
|
||||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||||
F test/analyze.test b3a9c67d00e1df7588a5b7be9a0292899f94fe8cac1f94a017277474ca2e59df
|
F test/analyze.test b3a9c67d00e1df7588a5b7be9a0292899f94fe8cac1f94a017277474ca2e59df
|
||||||
@ -1754,7 +1755,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 60bbca2b9a591800cd8e7b374e62d75b1df0e8fd2d2f71f9b4d5fd044da78be0
|
P 7404ea83168e6c739ebe8fc5d65bbf0265432ccb35b3418bb0381d74362f7527
|
||||||
R ef663a1df8c5f6cbefbb7dcd86b83b66
|
R 0f3d0199e04ab490bfdcf0cb2303572a
|
||||||
U drh
|
T *branch * alter-table-rename-column
|
||||||
Z 68dbd529c4e95246b96ffd22fa0b508e
|
T *sym-alter-table-rename-column *
|
||||||
|
T +closed 4889866915b8b8fc28ca20cfc3f2ed4890eb1f0712b0537298fbdd498ce41510
|
||||||
|
T -sym-trunk *
|
||||||
|
U dan
|
||||||
|
Z 92426cbf3686886dee1eff1497f8d0cc
|
||||||
|
@ -1 +1 @@
|
|||||||
7404ea83168e6c739ebe8fc5d65bbf0265432ccb35b3418bb0381d74362f7527
|
fa0fc01eb48a864f0a3d43f9b805d5ed2e530846ee0c34fcbc2eabd9e5696277
|
318
src/alter.c
318
src/alter.c
@ -225,22 +225,6 @@ static void renameTriggerFunc(
|
|||||||
}
|
}
|
||||||
#endif /* !SQLITE_OMIT_TRIGGER */
|
#endif /* !SQLITE_OMIT_TRIGGER */
|
||||||
|
|
||||||
/*
|
|
||||||
** Register built-in functions used to help implement ALTER TABLE
|
|
||||||
*/
|
|
||||||
void sqlite3AlterFunctions(void){
|
|
||||||
static FuncDef aAlterTableFuncs[] = {
|
|
||||||
FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
|
|
||||||
#ifndef SQLITE_OMIT_TRIGGER
|
|
||||||
FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
|
|
||||||
#endif
|
|
||||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
|
||||||
FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This function is used to create the text of expressions of the form:
|
** This function is used to create the text of expressions of the form:
|
||||||
**
|
**
|
||||||
@ -805,4 +789,306 @@ exit_begin_add_column:
|
|||||||
sqlite3SrcListDelete(db, pSrc);
|
sqlite3SrcListDelete(db, pSrc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sqlite3AlterRenameColumn(
|
||||||
|
Parse *pParse,
|
||||||
|
SrcList *pSrc,
|
||||||
|
Token *pOld,
|
||||||
|
Token *pNew
|
||||||
|
){
|
||||||
|
sqlite3 *db = pParse->db;
|
||||||
|
Table *pTab; /* Table being updated */
|
||||||
|
int iCol; /* Index of column being renamed */
|
||||||
|
char *zOld = 0;
|
||||||
|
char *zNew = 0;
|
||||||
|
const char *zDb;
|
||||||
|
int iSchema;
|
||||||
|
|
||||||
|
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
|
||||||
|
if( !pTab ) goto exit_rename_column;
|
||||||
|
iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||||
|
assert( iSchema>=0 );
|
||||||
|
zDb = db->aDb[iSchema].zDbSName;
|
||||||
|
|
||||||
|
zOld = sqlite3NameFromToken(db, pOld);
|
||||||
|
if( !zOld ) goto exit_rename_column;
|
||||||
|
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||||
|
if( 0==sqlite3StrICmp(pTab->aCol[iCol].zName, zOld) ) break;
|
||||||
|
}
|
||||||
|
if( iCol==pTab->nCol ){
|
||||||
|
sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld);
|
||||||
|
goto exit_rename_column;
|
||||||
|
}
|
||||||
|
|
||||||
|
zNew = sqlite3NameFromToken(db, pNew);
|
||||||
|
if( !zNew ) goto exit_rename_column;
|
||||||
|
|
||||||
|
sqlite3NestedParse(pParse,
|
||||||
|
"UPDATE \"%w\".%s SET "
|
||||||
|
"sql = sqlite_rename_column(sql, %d, %Q) "
|
||||||
|
"WHERE type IN ('table', 'index') AND tbl_name = %Q AND sql!=''",
|
||||||
|
zDb, MASTER_NAME, iCol, zNew, pTab->zName
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Drop and reload the internal table schema. */
|
||||||
|
reloadTableSchema(pParse, pTab, pTab->zName);
|
||||||
|
|
||||||
|
exit_rename_column:
|
||||||
|
sqlite3SrcListDelete(db, pSrc);
|
||||||
|
sqlite3DbFree(db, zOld);
|
||||||
|
sqlite3DbFree(db, zNew);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RenameToken {
|
||||||
|
void *p;
|
||||||
|
Token t;
|
||||||
|
RenameToken *pNext;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenameCtx {
|
||||||
|
RenameToken *pList; /* List of tokens to overwrite */
|
||||||
|
int nList; /* Number of tokens in pList */
|
||||||
|
int iCol; /* Index of column being renamed */
|
||||||
|
};
|
||||||
|
|
||||||
|
void sqlite3RenameToken(Parse *pParse, void *pPtr, Token *pToken){
|
||||||
|
RenameToken *pNew;
|
||||||
|
pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
|
||||||
|
if( pNew ){
|
||||||
|
pNew->p = pPtr;
|
||||||
|
pNew->t = *pToken;
|
||||||
|
pNew->pNext = pParse->pRename;
|
||||||
|
pParse->pRename = pNew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sqlite3MoveRenameToken(Parse *pParse, void *pTo, void *pFrom){
|
||||||
|
RenameToken *p;
|
||||||
|
for(p=pParse->pRename; p; p=p->pNext){
|
||||||
|
if( p->p==pFrom ){
|
||||||
|
p->p = pTo;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renameTokenFree(sqlite3 *db, RenameToken *pToken){
|
||||||
|
RenameToken *pNext;
|
||||||
|
RenameToken *p;
|
||||||
|
for(p=pToken; p; p=pNext){
|
||||||
|
pNext = p->pNext;
|
||||||
|
sqlite3DbFree(db, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static RenameToken *renameTokenFind(Parse *pParse, void *pPtr){
|
||||||
|
RenameToken **pp;
|
||||||
|
for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
|
||||||
|
if( (*pp)->p==pPtr ){
|
||||||
|
RenameToken *pToken = *pp;
|
||||||
|
*pp = pToken->pNext;
|
||||||
|
pToken->pNext = 0;
|
||||||
|
return pToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
|
||||||
|
struct RenameCtx *p = pWalker->u.pRename;
|
||||||
|
if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol ){
|
||||||
|
RenameToken *pTok = renameTokenFind(pWalker->pParse, (void*)pExpr);
|
||||||
|
if( pTok ){
|
||||||
|
pTok->pNext = p->pList;
|
||||||
|
p->pList = pTok;
|
||||||
|
p->nList++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return WRC_Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RenameToken *renameColumnTokenNext(struct RenameCtx *pCtx){
|
||||||
|
RenameToken *pBest = pCtx->pList;
|
||||||
|
RenameToken *pToken;
|
||||||
|
RenameToken **pp;
|
||||||
|
|
||||||
|
for(pToken=pBest->pNext; pToken; pToken=pToken->pNext){
|
||||||
|
if( pToken->t.z>pBest->t.z ) pBest = pToken;
|
||||||
|
}
|
||||||
|
for(pp=&pCtx->pList; *pp!=pBest; pp=&(*pp)->pNext);
|
||||||
|
*pp = pBest->pNext;
|
||||||
|
|
||||||
|
return pBest;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renameColumnFunc(
|
||||||
|
sqlite3_context *context,
|
||||||
|
int NotUsed,
|
||||||
|
sqlite3_value **argv
|
||||||
|
){
|
||||||
|
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||||
|
struct RenameCtx sCtx;
|
||||||
|
const char *zSql = sqlite3_value_text(argv[0]);
|
||||||
|
int nSql = sqlite3_value_bytes(argv[0]);
|
||||||
|
const char *zNew = sqlite3_value_text(argv[2]);
|
||||||
|
int nNew = sqlite3_value_bytes(argv[2]);
|
||||||
|
int rc;
|
||||||
|
char *zErr = 0;
|
||||||
|
Parse sParse;
|
||||||
|
Walker sWalker;
|
||||||
|
Table *pTab;
|
||||||
|
Index *pIdx;
|
||||||
|
char *zOut = 0;
|
||||||
|
|
||||||
|
char *zQuot = 0; /* Quoted version of zNew */
|
||||||
|
int nQuot = 0; /* Length of zQuot in bytes */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(&sCtx, 0, sizeof(sCtx));
|
||||||
|
sCtx.iCol = sqlite3_value_int(argv[1]);
|
||||||
|
|
||||||
|
memset(&sParse, 0, sizeof(sParse));
|
||||||
|
sParse.eParseMode = PARSE_MODE_RENAME_COLUMN;
|
||||||
|
sParse.db = db;
|
||||||
|
sParse.nQueryLoop = 1;
|
||||||
|
rc = sqlite3RunParser(&sParse, zSql, &zErr);
|
||||||
|
assert( sParse.pNewTable==0 || sParse.pNewIndex==0 );
|
||||||
|
if( rc==SQLITE_OK && sParse.pNewTable==0 && sParse.pNewIndex==0 ){
|
||||||
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
zQuot = sqlite3_mprintf("\"%w\"", zNew);
|
||||||
|
if( zQuot==0 ){
|
||||||
|
rc = SQLITE_NOMEM;
|
||||||
|
}else{
|
||||||
|
nQuot = sqlite3Strlen30(zQuot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
if( zErr ){
|
||||||
|
sqlite3_result_error(context, zErr, -1);
|
||||||
|
}else{
|
||||||
|
sqlite3_result_error_code(context, rc);
|
||||||
|
}
|
||||||
|
sqlite3DbFree(db, zErr);
|
||||||
|
sqlite3_free(zQuot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; i<nNew; i++){
|
||||||
|
if( sqlite3IsIdChar(zNew[i])==0 ){
|
||||||
|
zNew = zQuot;
|
||||||
|
nNew = nQuot;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SQLITE_DEBUG
|
||||||
|
assert( sqlite3Strlen30(zSql)==nSql );
|
||||||
|
{
|
||||||
|
RenameToken *pToken;
|
||||||
|
for(pToken=sParse.pRename; pToken; pToken=pToken->pNext){
|
||||||
|
assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Find tokens that need to be replaced. */
|
||||||
|
memset(&sWalker, 0, sizeof(Walker));
|
||||||
|
sWalker.pParse = &sParse;
|
||||||
|
sWalker.xExprCallback = renameColumnExprCb;
|
||||||
|
sWalker.u.pRename = &sCtx;
|
||||||
|
|
||||||
|
if( sParse.pNewTable ){
|
||||||
|
FKey *pFKey;
|
||||||
|
sCtx.pList = renameTokenFind(
|
||||||
|
&sParse, (void*)sParse.pNewTable->aCol[sCtx.iCol].zName
|
||||||
|
);
|
||||||
|
sCtx.nList = 1;
|
||||||
|
sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck);
|
||||||
|
for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||||
|
sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
||||||
|
for(i=0; i<pFKey->nCol; i++){
|
||||||
|
if( pFKey->aCol[i].iFrom==sCtx.iCol ){
|
||||||
|
RenameToken *pTok = renameTokenFind(&sParse, (void*)&pFKey->aCol[i]);
|
||||||
|
if( pTok ){
|
||||||
|
pTok->pNext = sCtx.pList;
|
||||||
|
sCtx.pList = pTok;
|
||||||
|
sCtx.nList++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr);
|
||||||
|
sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
|
||||||
|
}
|
||||||
|
|
||||||
|
zOut = sqlite3DbMallocZero(db, nSql + sCtx.nList*nNew + 1);
|
||||||
|
if( zOut ){
|
||||||
|
int nOut = nSql;
|
||||||
|
memcpy(zOut, zSql, nSql);
|
||||||
|
while( sCtx.pList ){
|
||||||
|
int iOff; /* Offset of token to replace in zOut */
|
||||||
|
RenameToken *pBest = renameColumnTokenNext(&sCtx);
|
||||||
|
|
||||||
|
int nReplace;
|
||||||
|
const char *zReplace;
|
||||||
|
if( sqlite3IsIdChar(*pBest->t.z) ){
|
||||||
|
nReplace = nNew;
|
||||||
|
zReplace = zNew;
|
||||||
|
}else{
|
||||||
|
nReplace = nQuot;
|
||||||
|
zReplace = zQuot;
|
||||||
|
}
|
||||||
|
|
||||||
|
iOff = pBest->t.z - zSql;
|
||||||
|
if( pBest->t.n!=nReplace ){
|
||||||
|
memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n],
|
||||||
|
nOut - (iOff + pBest->t.n)
|
||||||
|
);
|
||||||
|
nOut += nReplace - pBest->t.n;
|
||||||
|
zOut[nOut] = '\0';
|
||||||
|
}
|
||||||
|
memcpy(&zOut[iOff], zReplace, nReplace);
|
||||||
|
sqlite3DbFree(db, pBest);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3DbFree(db, zOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( sParse.pVdbe ){
|
||||||
|
sqlite3VdbeFinalize(sParse.pVdbe);
|
||||||
|
}
|
||||||
|
sqlite3DeleteTable(db, sParse.pNewTable);
|
||||||
|
if( sParse.pNewIndex ) sqlite3FreeIndex(db, sParse.pNewIndex);
|
||||||
|
renameTokenFree(db, sParse.pRename);
|
||||||
|
sqlite3ParserReset(&sParse);
|
||||||
|
sqlite3_free(zQuot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Register built-in functions used to help implement ALTER TABLE
|
||||||
|
*/
|
||||||
|
void sqlite3AlterFunctions(void){
|
||||||
|
static FuncDef aAlterTableFuncs[] = {
|
||||||
|
FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
|
||||||
|
FUNCTION(sqlite_rename_column, 3, 0, 0, renameColumnFunc),
|
||||||
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
|
FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
|
||||||
|
#endif
|
||||||
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||||
|
FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
|
||||||
|
}
|
||||||
#endif /* SQLITE_ALTER_TABLE */
|
#endif /* SQLITE_ALTER_TABLE */
|
||||||
|
@ -207,7 +207,7 @@ int sqlite3AuthCheck(
|
|||||||
/* Don't do any authorization checks if the database is initialising
|
/* Don't do any authorization checks if the database is initialising
|
||||||
** or if the parser is being invoked from within sqlite3_declare_vtab.
|
** 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;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
237
src/build.c
237
src/build.c
@ -439,7 +439,7 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
|
|||||||
/*
|
/*
|
||||||
** Reclaim the memory used by an index
|
** Reclaim the memory used by an index
|
||||||
*/
|
*/
|
||||||
static void freeIndex(sqlite3 *db, Index *p){
|
void sqlite3FreeIndex(sqlite3 *db, Index *p){
|
||||||
#ifndef SQLITE_OMIT_ANALYZE
|
#ifndef SQLITE_OMIT_ANALYZE
|
||||||
sqlite3DeleteIndexSamples(db, p);
|
sqlite3DeleteIndexSamples(db, p);
|
||||||
#endif
|
#endif
|
||||||
@ -479,7 +479,7 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
|||||||
p->pNext = pIndex->pNext;
|
p->pNext = pIndex->pNext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeIndex(db, pIndex);
|
sqlite3FreeIndex(db, pIndex);
|
||||||
}
|
}
|
||||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
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( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
||||||
assert( pOld==pIndex || pOld==0 );
|
assert( pOld==pIndex || pOld==0 );
|
||||||
}
|
}
|
||||||
freeIndex(db, pIndex);
|
sqlite3FreeIndex(db, pIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete any foreign keys attached to this table. */
|
/* Delete any foreign keys attached to this table. */
|
||||||
@ -913,7 +913,7 @@ void sqlite3StartTable(
|
|||||||
** and types will be used, so there is no need to test for namespace
|
** and types will be used, so there is no need to test for namespace
|
||||||
** collisions.
|
** collisions.
|
||||||
*/
|
*/
|
||||||
if( !IN_DECLARE_VTAB ){
|
if( !IN_SPECIAL_PARSE ){
|
||||||
char *zDb = db->aDb[iDb].zDbSName;
|
char *zDb = db->aDb[iDb].zDbSName;
|
||||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||||
goto begin_table_error;
|
goto begin_table_error;
|
||||||
@ -1072,6 +1072,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
|||||||
}
|
}
|
||||||
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
|
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
|
||||||
if( z==0 ) return;
|
if( z==0 ) return;
|
||||||
|
if( IN_RENAME_COLUMN ) sqlite3RenameToken(pParse, (void*)z, pName);
|
||||||
memcpy(z, pName->z, pName->n);
|
memcpy(z, pName->z, pName->n);
|
||||||
z[pName->n] = 0;
|
z[pName->n] = 0;
|
||||||
sqlite3Dequote(z);
|
sqlite3Dequote(z);
|
||||||
@ -2761,6 +2762,9 @@ void sqlite3CreateForeignKey(
|
|||||||
pFromCol->a[i].zName);
|
pFromCol->a[i].zName);
|
||||||
goto fk_end;
|
goto fk_end;
|
||||||
}
|
}
|
||||||
|
if( IN_RENAME_COLUMN ){
|
||||||
|
sqlite3MoveRenameToken(pParse, &pFKey->aCol[i], &pFromCol->a[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( pToCol ){
|
if( pToCol ){
|
||||||
@ -3099,21 +3103,23 @@ void sqlite3CreateIndex(
|
|||||||
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||||
goto exit_create_index;
|
goto exit_create_index;
|
||||||
}
|
}
|
||||||
if( !db->init.busy ){
|
if( !IN_RENAME_COLUMN ){
|
||||||
if( sqlite3FindTable(db, zName, 0)!=0 ){
|
if( !db->init.busy ){
|
||||||
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
|
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;
|
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{
|
}else{
|
||||||
int n;
|
int n;
|
||||||
Index *pLoop;
|
Index *pLoop;
|
||||||
@ -3128,13 +3134,13 @@ void sqlite3CreateIndex(
|
|||||||
** The following statement converts "sqlite3_autoindex..." into
|
** The following statement converts "sqlite3_autoindex..." into
|
||||||
** "sqlite3_butoindex..." in order to make the names distinct.
|
** "sqlite3_butoindex..." in order to make the names distinct.
|
||||||
** The "vtab_err.test" test demonstrates the need of this statement. */
|
** 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.
|
/* Check for authorization to create an index.
|
||||||
*/
|
*/
|
||||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||||
{
|
if( !IN_RENAME_COLUMN ){
|
||||||
const char *zDb = pDb->zDbSName;
|
const char *zDb = pDb->zDbSName;
|
||||||
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
|
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
|
||||||
goto exit_create_index;
|
goto exit_create_index;
|
||||||
@ -3221,7 +3227,12 @@ void sqlite3CreateIndex(
|
|||||||
** TODO: Issue a warning if the table primary key is used as part of the
|
** TODO: Issue a warning if the table primary key is used as part of the
|
||||||
** index key.
|
** index key.
|
||||||
*/
|
*/
|
||||||
for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
|
pListItem = pList->a;
|
||||||
|
if( IN_RENAME_COLUMN ){
|
||||||
|
pIndex->aColExpr = pList;
|
||||||
|
pList = 0;
|
||||||
|
}
|
||||||
|
for(i=0; i<pIndex->nKeyCol; i++, pListItem++){
|
||||||
Expr *pCExpr; /* The i-th index expression */
|
Expr *pCExpr; /* The i-th index expression */
|
||||||
int requestedSortOrder; /* ASC or DESC on the i-th expression */
|
int requestedSortOrder; /* ASC or DESC on the i-th expression */
|
||||||
const char *zColl; /* Collation sequence name */
|
const char *zColl; /* Collation sequence name */
|
||||||
@ -3237,12 +3248,8 @@ void sqlite3CreateIndex(
|
|||||||
goto exit_create_index;
|
goto exit_create_index;
|
||||||
}
|
}
|
||||||
if( pIndex->aColExpr==0 ){
|
if( pIndex->aColExpr==0 ){
|
||||||
ExprList *pCopy = sqlite3ExprListDup(db, pList, 0);
|
pIndex->aColExpr = pList;
|
||||||
pIndex->aColExpr = pCopy;
|
pList = 0;
|
||||||
if( !db->mallocFailed ){
|
|
||||||
assert( pCopy!=0 );
|
|
||||||
pListItem = &pCopy->a[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
j = XN_EXPR;
|
j = XN_EXPR;
|
||||||
pIndex->aiColumn[i] = XN_EXPR;
|
pIndex->aiColumn[i] = XN_EXPR;
|
||||||
@ -3381,98 +3388,101 @@ void sqlite3CreateIndex(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Link the new Index structure to its table and to the other
|
if( !IN_RENAME_COLUMN ){
|
||||||
** 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 this is the initial CREATE INDEX statement (or CREATE TABLE if the
|
/* Link the new Index structure to its table and to the other
|
||||||
** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then
|
** in-memory database structures.
|
||||||
** 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
|
|
||||||
*/
|
*/
|
||||||
if( pStart ){
|
assert( pParse->nErr==0 );
|
||||||
int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
|
if( db->init.busy ){
|
||||||
if( pName->z[n-1]==';' ) n--;
|
Index *p;
|
||||||
/* A named index with an explicit CREATE INDEX statement */
|
assert( !IN_SPECIAL_PARSE );
|
||||||
zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
|
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
||||||
onError==OE_None ? "" : " UNIQUE", n, pName->z);
|
p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
|
||||||
}else{
|
pIndex->zName, pIndex);
|
||||||
/* An automatic index created by a PRIMARY KEY or UNIQUE constraint */
|
if( p ){
|
||||||
/* zStmt = sqlite3MPrintf(""); */
|
assert( p==pIndex ); /* Malloc must have failed */
|
||||||
zStmt = 0;
|
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,
|
else if( HasRowid(pTab) || pTblName!=0 ){
|
||||||
"INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
|
Vdbe *v;
|
||||||
db->aDb[iDb].zDbSName, MASTER_NAME,
|
char *zStmt;
|
||||||
pIndex->zName,
|
int iMem = ++pParse->nMem;
|
||||||
pTab->zName,
|
|
||||||
iMem,
|
|
||||||
zStmt
|
|
||||||
);
|
|
||||||
sqlite3DbFree(db, zStmt);
|
|
||||||
|
|
||||||
/* Fill the index with data and reparse the schema. Code an OP_Expire
|
v = sqlite3GetVdbe(pParse);
|
||||||
** to invalidate all pre-compiled statements.
|
if( v==0 ) goto exit_create_index;
|
||||||
*/
|
|
||||||
if( pTblName ){
|
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||||
sqlite3RefillIndex(pParse, pIndex, iMem);
|
|
||||||
sqlite3ChangeCookie(pParse, iDb);
|
/* Create the rootpage for the index using CreateIndex. But before
|
||||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
** doing so, code a Noop instruction and store its address in
|
||||||
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
|
** Index.tnum. This is required in case this index is actually a
|
||||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
|
** 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
|
/* When adding an index to the list of indices for a table, make
|
||||||
@ -3496,10 +3506,15 @@ void sqlite3CreateIndex(
|
|||||||
}
|
}
|
||||||
pIndex = 0;
|
pIndex = 0;
|
||||||
}
|
}
|
||||||
|
else if( IN_RENAME_COLUMN ){
|
||||||
|
assert( pParse->pNewIndex==0 );
|
||||||
|
pParse->pNewIndex = pIndex;
|
||||||
|
pIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Clean up before exiting */
|
/* Clean up before exiting */
|
||||||
exit_create_index:
|
exit_create_index:
|
||||||
if( pIndex ) freeIndex(db, pIndex);
|
if( pIndex ) sqlite3FreeIndex(db, pIndex);
|
||||||
sqlite3ExprDelete(db, pPIWhere);
|
sqlite3ExprDelete(db, pPIWhere);
|
||||||
sqlite3ExprListDelete(db, pList);
|
sqlite3ExprListDelete(db, pList);
|
||||||
sqlite3SrcListDelete(db, pTblName);
|
sqlite3SrcListDelete(db, pTblName);
|
||||||
|
11
src/parse.y
11
src/parse.y
@ -940,6 +940,7 @@ idlist(A) ::= nm(Y).
|
|||||||
if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted;
|
if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted;
|
||||||
sqlite3Dequote(p->u.zToken);
|
sqlite3Dequote(p->u.zToken);
|
||||||
}
|
}
|
||||||
|
if( IN_RENAME_COLUMN ) sqlite3RenameToken(pParse, (void*)p, &t);
|
||||||
#if SQLITE_MAX_EXPR_DEPTH>0
|
#if SQLITE_MAX_EXPR_DEPTH>0
|
||||||
p->nHeight = 1;
|
p->nHeight = 1;
|
||||||
#endif
|
#endif
|
||||||
@ -955,6 +956,7 @@ expr(A) ::= JOIN_KW(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/}
|
|||||||
expr(A) ::= nm(X) DOT nm(Y). {
|
expr(A) ::= nm(X) DOT nm(Y). {
|
||||||
Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1);
|
Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1);
|
||||||
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
|
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
|
||||||
|
if( IN_RENAME_COLUMN ) sqlite3RenameToken(pParse, (void*)temp2, &Y);
|
||||||
A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
|
A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
|
||||||
}
|
}
|
||||||
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
|
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
|
||||||
@ -962,6 +964,7 @@ expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
|
|||||||
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
|
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
|
||||||
Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &Z, 1);
|
Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &Z, 1);
|
||||||
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
|
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
|
||||||
|
if( IN_RENAME_COLUMN ) sqlite3RenameToken(pParse, (void*)temp3, &Z);
|
||||||
A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
|
A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
|
||||||
}
|
}
|
||||||
term(A) ::= NULL|FLOAT|BLOB(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/}
|
term(A) ::= NULL|FLOAT|BLOB(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/}
|
||||||
@ -1308,6 +1311,9 @@ uniqueflag(A) ::= . {A = OE_None;}
|
|||||||
pIdToken->n, pIdToken->z);
|
pIdToken->n, pIdToken->z);
|
||||||
}
|
}
|
||||||
sqlite3ExprListSetName(pParse, p, pIdToken, 1);
|
sqlite3ExprListSetName(pParse, p, pIdToken, 1);
|
||||||
|
if( IN_RENAME_COLUMN ){
|
||||||
|
sqlite3RenameToken(pParse, (void*)&(p->a[p->nExpr-1]), pIdToken);
|
||||||
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
} // end %include
|
} // end %include
|
||||||
@ -1532,8 +1538,13 @@ add_column_fullname ::= fullname(X). {
|
|||||||
disableLookaside(pParse);
|
disableLookaside(pParse);
|
||||||
sqlite3AlterBeginAddColumn(pParse, X);
|
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 ::= .
|
||||||
kwcolumn_opt ::= COLUMNKW.
|
kwcolumn_opt ::= COLUMNKW.
|
||||||
|
|
||||||
%endif SQLITE_OMIT_ALTERTABLE
|
%endif SQLITE_OMIT_ALTERTABLE
|
||||||
|
|
||||||
//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
|
//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
|
||||||
|
@ -668,12 +668,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||||||
if( pRight->op==TK_ID ){
|
if( pRight->op==TK_ID ){
|
||||||
zDb = 0;
|
zDb = 0;
|
||||||
zTable = pExpr->pLeft->u.zToken;
|
zTable = pExpr->pLeft->u.zToken;
|
||||||
zColumn = pRight->u.zToken;
|
|
||||||
}else{
|
}else{
|
||||||
assert( pRight->op==TK_DOT );
|
assert( pRight->op==TK_DOT );
|
||||||
zDb = pExpr->pLeft->u.zToken;
|
zDb = pExpr->pLeft->u.zToken;
|
||||||
zTable = pRight->pLeft->u.zToken;
|
zTable = pRight->pLeft->u.zToken;
|
||||||
zColumn = pRight->pRight->u.zToken;
|
pRight = pRight->pRight;
|
||||||
|
}
|
||||||
|
zColumn = pRight->u.zToken;
|
||||||
|
if( IN_RENAME_COLUMN ){
|
||||||
|
sqlite3MoveRenameToken(pParse, (void*)pExpr, (void*)pRight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
|
return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
|
||||||
|
@ -1087,6 +1087,7 @@ typedef struct NameContext NameContext;
|
|||||||
typedef struct Parse Parse;
|
typedef struct Parse Parse;
|
||||||
typedef struct PreUpdate PreUpdate;
|
typedef struct PreUpdate PreUpdate;
|
||||||
typedef struct PrintfArguments PrintfArguments;
|
typedef struct PrintfArguments PrintfArguments;
|
||||||
|
typedef struct RenameToken RenameToken;
|
||||||
typedef struct RowSet RowSet;
|
typedef struct RowSet RowSet;
|
||||||
typedef struct Savepoint Savepoint;
|
typedef struct Savepoint Savepoint;
|
||||||
typedef struct Select Select;
|
typedef struct Select Select;
|
||||||
@ -3087,8 +3088,10 @@ struct Parse {
|
|||||||
ynVar nVar; /* Number of '?' variables seen in the SQL so far */
|
ynVar nVar; /* Number of '?' variables seen in the SQL so far */
|
||||||
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
|
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
|
||||||
u8 explain; /* True if the EXPLAIN flag is found on the query */
|
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
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
|
|
||||||
int nVtabLock; /* Number of virtual tables to lock */
|
int nVtabLock; /* Number of virtual tables to lock */
|
||||||
#endif
|
#endif
|
||||||
int nHeight; /* Expression tree height of current sub-select */
|
int nHeight; /* Expression tree height of current sub-select */
|
||||||
@ -3099,6 +3102,7 @@ struct Parse {
|
|||||||
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
|
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
|
||||||
const char *zTail; /* All SQL text past the last semicolon parsed */
|
const char *zTail; /* All SQL text past the last semicolon parsed */
|
||||||
Table *pNewTable; /* A table being constructed by CREATE TABLE */
|
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 */
|
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
|
||||||
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
|
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
@ -3109,8 +3113,15 @@ struct Parse {
|
|||||||
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
|
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
|
||||||
With *pWith; /* Current WITH clause, or NULL */
|
With *pWith; /* Current WITH clause, or NULL */
|
||||||
With *pWithToFree; /* Free this WITH object at the end of the parse */
|
With *pWithToFree; /* Free this WITH object at the end of the parse */
|
||||||
|
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||||
|
RenameToken *pRename;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PARSE_MODE_NORMAL 0
|
||||||
|
#define PARSE_MODE_DECLARE_VTAB 1
|
||||||
|
#define PARSE_MODE_RENAME_COLUMN 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Sizes and pointers of various parts of the Parse object.
|
** Sizes and pointers of various parts of the Parse object.
|
||||||
*/
|
*/
|
||||||
@ -3125,7 +3136,19 @@ struct Parse {
|
|||||||
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
||||||
#define IN_DECLARE_VTAB 0
|
#define IN_DECLARE_VTAB 0
|
||||||
#else
|
#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_COLUMN 0
|
||||||
|
#else
|
||||||
|
#define IN_RENAME_COLUMN (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
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3409,6 +3432,7 @@ struct Walker {
|
|||||||
Select *pSelect; /* HAVING to WHERE clause ctx */
|
Select *pSelect; /* HAVING to WHERE clause ctx */
|
||||||
struct WindowRewrite *pRewrite; /* Window rewrite context */
|
struct WindowRewrite *pRewrite; /* Window rewrite context */
|
||||||
struct WhereConst *pConst; /* WHERE clause constants */
|
struct WhereConst *pConst; /* WHERE clause constants */
|
||||||
|
struct RenameCtx *pRename; /* RENAME COLUMN context */
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3844,6 +3868,7 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int);
|
|||||||
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
||||||
void sqlite3CodeDropTable(Parse*, Table*, int, int);
|
void sqlite3CodeDropTable(Parse*, Table*, int, int);
|
||||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||||
|
void sqlite3FreeIndex(sqlite3*, Index*);
|
||||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||||
void sqlite3AutoincrementBegin(Parse *pParse);
|
void sqlite3AutoincrementBegin(Parse *pParse);
|
||||||
void sqlite3AutoincrementEnd(Parse *pParse);
|
void sqlite3AutoincrementEnd(Parse *pParse);
|
||||||
@ -4188,6 +4213,7 @@ void sqlite3RootPageMoved(sqlite3*, int, int, int);
|
|||||||
void sqlite3Reindex(Parse*, Token*, Token*);
|
void sqlite3Reindex(Parse*, Token*, Token*);
|
||||||
void sqlite3AlterFunctions(void);
|
void sqlite3AlterFunctions(void);
|
||||||
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
||||||
|
void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
|
||||||
int sqlite3GetToken(const unsigned char *, int *);
|
int sqlite3GetToken(const unsigned char *, int *);
|
||||||
void sqlite3NestedParse(Parse*, const char*, ...);
|
void sqlite3NestedParse(Parse*, const char*, ...);
|
||||||
void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
||||||
@ -4203,6 +4229,8 @@ int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
|
|||||||
void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
|
void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
|
||||||
void sqlite3AlterFinishAddColumn(Parse *, Token *);
|
void sqlite3AlterFinishAddColumn(Parse *, Token *);
|
||||||
void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
|
void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
|
||||||
|
void sqlite3RenameToken(Parse*, void*, Token*);
|
||||||
|
void sqlite3MoveRenameToken(Parse*, void *pTo, void *pFrom);
|
||||||
CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
|
CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
|
||||||
char sqlite3AffinityType(const char*, Column*);
|
char sqlite3AffinityType(const char*, Column*);
|
||||||
void sqlite3Analyze(Parse*, Token*, Token*);
|
void sqlite3Analyze(Parse*, Token*, Token*);
|
||||||
|
@ -690,7 +690,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
|||||||
sqlite3_free(pParse->apVtabLock);
|
sqlite3_free(pParse->apVtabLock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( !IN_DECLARE_VTAB ){
|
if( !IN_SPECIAL_PARSE ){
|
||||||
/* If the pParse->declareVtab flag is set, do not delete any table
|
/* If the pParse->declareVtab flag is set, do not delete any table
|
||||||
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
|
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
|
||||||
** will take responsibility for freeing the Table structure.
|
** will take responsibility for freeing the Table structure.
|
||||||
|
@ -758,7 +758,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
|||||||
assert( IsVirtual(pTab) );
|
assert( IsVirtual(pTab) );
|
||||||
|
|
||||||
memset(&sParse, 0, sizeof(sParse));
|
memset(&sParse, 0, sizeof(sParse));
|
||||||
sParse.declareVtab = 1;
|
sParse.eParseMode = PARSE_MODE_DECLARE_VTAB;
|
||||||
sParse.db = db;
|
sParse.db = db;
|
||||||
sParse.nQueryLoop = 1;
|
sParse.nQueryLoop = 1;
|
||||||
if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
|
if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
|
||||||
@ -799,7 +799,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
|||||||
sqlite3DbFree(db, zErr);
|
sqlite3DbFree(db, zErr);
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
sParse.declareVtab = 0;
|
sParse.eParseMode = PARSE_MODE_NORMAL;
|
||||||
|
|
||||||
if( sParse.pVdbe ){
|
if( sParse.pVdbe ){
|
||||||
sqlite3VdbeFinalize(sParse.pVdbe);
|
sqlite3VdbeFinalize(sParse.pVdbe);
|
||||||
|
97
test/altercol.test
Normal file
97
test/altercol.test
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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)}
|
||||||
|
|
||||||
|
} {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user