diff --git a/Makefile.in b/Makefile.in index d8f84d2216..198a7877c1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -112,7 +112,7 @@ TCC += -DSQLITE_OMIT_CURSOR # Object files for the SQLite library. # -LIBOBJ = attach.lo auth.lo btree.lo build.lo date.lo \ +LIBOBJ = alter.lo attach.lo auth.lo btree.lo build.lo date.lo \ delete.lo expr.lo func.lo hash.lo insert.lo \ main.lo opcodes.lo os_unix.lo os_win.lo \ pager.lo parse.lo pragma.lo printf.lo random.lo \ @@ -123,6 +123,7 @@ LIBOBJ = attach.lo auth.lo btree.lo build.lo date.lo \ # All of the source code files. # SRC = \ + $(TOP)/src/alter.c \ $(TOP)/src/attach.c \ $(TOP)/src/auth.c \ $(TOP)/src/btree.c \ @@ -260,6 +261,9 @@ lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c # Rules to build individual files # +alter.lo: $(TOP)/src/alter.c $(HDR) + $(LTCOMPILE) -c $(TOP)/src/alter.c + attach.lo: $(TOP)/src/attach.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/attach.c diff --git a/main.mk b/main.mk index 6f0fcac2d2..f6fc40c136 100644 --- a/main.mk +++ b/main.mk @@ -54,7 +54,7 @@ TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src # Object files for the SQLite library. # -LIBOBJ+= attach.o auth.o btree.o build.o date.o delete.o \ +LIBOBJ+= alter.o attach.o auth.o btree.o build.o date.o delete.o \ expr.o func.o hash.o insert.o \ main.o opcodes.o os_unix.o os_win.o \ pager.o parse.o pragma.o printf.o random.o \ @@ -66,6 +66,7 @@ LIBOBJ+= attach.o auth.o btree.o build.o date.o delete.o \ # All of the source code files. # SRC = \ + $(TOP)/src/alter.c \ $(TOP)/src/attach.c \ $(TOP)/src/auth.c \ $(TOP)/src/btree.c \ @@ -195,6 +196,9 @@ lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c # Rules to build individual files # +alter.o: $(TOP)/src/alter.c $(HDR) + $(TCCX) -c $(TOP)/src/alter.c + attach.o: $(TOP)/src/attach.c $(HDR) $(TCCX) -c $(TOP)/src/attach.c diff --git a/manifest b/manifest index a824ec6609..366569aa89 100644 --- a/manifest +++ b/manifest @@ -1,6 +1,6 @@ -C Btree\schecks\sthe\sautovacuum\sflag\safter\slocking\sthe\sdatabase\sfile.\s(CVS\s2341) -D 2005-02-15T16:23:02 -F Makefile.in d928187101fa3d78426cf48ca30e39d0fb714e57 +C Split\sthe\slogic\sfor\sthe\sALTER\sTABLE\scommand\soff\sinto\sa\sseparate\ssource\ncode\sfile.\s(CVS\s2342) +D 2005-02-15T20:47:57 +F Makefile.in 76443a83549d1539105e12d13bd0054a05ab2214 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 F VERSION 9e556d0985199b130268c3b8e5615b90dda7e829 @@ -16,7 +16,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826 -F main.mk 834d5f2feb8d0f79fb3d2bb9db5afac2b3da7349 +F main.mk 632150f494ae1a96c8ac3cda0229a77cd18cb843 F mkdll.sh 468d4f41d3ea98221371df4825cfbffbaac4d7e4 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodeh.awk e4d010870a3e98fd4323635c31565a3ca8584741 @@ -27,16 +27,17 @@ F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F sqlite3.1 01fdb467ce387a83248857c92f9e801df9e4611c F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a +F src/alter.c 4e38440d4491a52b55c0c42d5c9b1b1890f0a13d F src/attach.c f78f76bc6a8e5e487ca53636e21ccba2484a9a61 F src/auth.c 18c5a0befe20f3a58a41e3ddd78f372faeeefe1f F src/btree.c 5c6e81855deec3d1eac5ae03e4c8db6c2595421f F src/btree.h 2e2cc923224649337d7217df0dd32b06673ca180 -F src/build.c 09333b6006d26d411dbaa918601be1054c09fff3 +F src/build.c 7db7f593093caeb223c849a0fd7ca428dcda631e F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f F src/delete.c 4b94395b52a8f7785acd71135c2ce54f3f5550b3 F src/experimental.c 8cc66b2be6a011055d75ef19ed2584bcfbb585ad F src/expr.c e160aabb59ff3c02e8e00ca4b30d00b94664c519 -F src/func.c 4538f82c8ae5f753012f15c4f22cffd578280c56 +F src/func.c deba954e40c9bcfaafa899f382176f2c1eb8b1d6 F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/insert.c 0456649d4d48396f918e7ea1fecbf3d66ed90816 @@ -271,7 +272,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl 3e522a06ad41992023c80ca29a048ae2331ca5bd -P 138577d0a5c41f3de4f9adc9ab6e312a65ff8888 -R f81718102e4042ffed922f8685264bda +P 6610188f09d08c65c46a140685b403aa74f71a19 +R d76aba4c3459eff26416d9c4987a204d U drh -Z ba532001e1e18d6f4d6553ba708c367b +Z ecefb64241ae1525534fd4f0e437a46d diff --git a/manifest.uuid b/manifest.uuid index f365ab42d7..171d52bf1e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6610188f09d08c65c46a140685b403aa74f71a19 \ No newline at end of file +90d6573c2631fac92b9e572e9e21698ae2480c9d \ No newline at end of file diff --git a/src/alter.c b/src/alter.c new file mode 100644 index 0000000000..d6ce4208b2 --- /dev/null +++ b/src/alter.c @@ -0,0 +1,186 @@ +/* +** 2005 February 15 +** +** 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 contains C code routines that used to generate VDBE code +** that implements the ALTER TABLE command. +** +** $Id: alter.c,v 1.1 2005/02/15 20:47:57 drh Exp $ +*/ +#include "sqliteInt.h" + + +#ifndef SQLITE_OMIT_ALTERTABLE +/* +** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" +** command. +*/ +void sqlite3AlterRenameTable( + Parse *pParse, /* Parser context. */ + SrcList *pSrc, /* The table to rename. */ + Token *pName /* The new table name. */ +){ + int iDb; /* Database that contains the table */ + char *zDb; /* Name of database iDb */ + Table *pTab; /* Table being renamed */ + char *zName = 0; /* NULL-terminated version of pName */ + char *zWhere = 0; /* Where clause of schema elements to reparse */ + sqlite3 *db = pParse->db; /* Database connection */ + Vdbe *v; +#ifndef SQLITE_OMIT_TRIGGER + char *zTempTrig = 0; /* Where clause to locate temp triggers */ +#endif + + assert( pSrc->nSrc==1 ); + + pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); + if( !pTab ) goto exit_rename_table; + iDb = pTab->iDb; + zDb = db->aDb[iDb].zName; + + /* Get a NULL terminated version of the new table name. */ + zName = sqlite3NameFromToken(pName); + if( !zName ) goto exit_rename_table; + + /* Check that a table or index named 'zName' does not already exist + ** in database iDb. If so, this is an error. + */ + if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){ + sqlite3ErrorMsg(pParse, + "there is already another table or index with this name: %s", zName); + goto exit_rename_table; + } + + /* Make sure it is not a system table being altered, or a reserved name + ** that the table is being renamed to. + */ + if( strlen(pTab->zName)>6 && 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ){ + sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName); + goto exit_rename_table; + } + if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + goto exit_rename_table; + } + +#ifndef SQLITE_OMIT_AUTHORIZATION + /* Invoke the authorization callback. */ + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ + goto exit_rename_table; + } +#endif + + /* Begin a transaction and code the VerifyCookie for database iDb. + ** Then modify the schema cookie (since the ALTER TABLE modifies the + ** schema). + */ + v = sqlite3GetVdbe(pParse); + if( v==0 ){ + goto exit_rename_table; + } + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3ChangeCookie(db, v, iDb); + + /* Modify the sqlite_master table to use the new table name. */ + sqlite3NestedParse(pParse, + "UPDATE %Q.%s SET " +#ifdef SQLITE_OMIT_TRIGGER + "sql = sqlite_rename_table(sql, %Q), " +#else + "sql = CASE " + "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)" + "ELSE sqlite_rename_table(sql, %Q) END, " +#endif + "tbl_name = %Q, " + "name = CASE " + "WHEN type='table' THEN %Q " + "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " + "'sqlite_autoindex_' || %Q || substr(name, %d+18,10) " + "ELSE name END " + "WHERE tbl_name=%Q AND " + "(type='table' OR type='index' OR type='trigger');", + zDb, SCHEMA_TABLE(iDb), zName, zName, zName, +#ifndef SQLITE_OMIT_TRIGGER +zName, +#endif + zName, strlen(pTab->zName), pTab->zName + ); + +#ifndef SQLITE_OMIT_AUTOINCREMENT + /* If the sqlite_sequence table exists in this database, then update + ** it with the new table name. + */ + if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ + sqlite3NestedParse(pParse, + "UPDATE %Q.sqlite_sequence set name = %Q WHERE name = %Q", + zDb, zName, pTab->zName); + } +#endif + +#ifndef SQLITE_OMIT_TRIGGER + /* If there are TEMP triggers on this table, modify the sqlite_temp_master + ** table. Don't do this if the table being ALTERed is itself located in + ** the temp database. + */ + if( iDb!=1 ){ + Trigger *pTrig; + char *tmp = 0; + for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ + if( pTrig->iDb==1 ){ + if( !zTempTrig ){ + zTempTrig = + sqlite3MPrintf("type = 'trigger' AND (name=%Q", pTrig->name); + }else{ + tmp = zTempTrig; + zTempTrig = sqlite3MPrintf("%s OR name=%Q", zTempTrig, pTrig->name); + sqliteFree(tmp); + } + } + } + if( zTempTrig ){ + tmp = zTempTrig; + zTempTrig = sqlite3MPrintf("%s)", zTempTrig); + sqliteFree(tmp); + sqlite3NestedParse(pParse, + "UPDATE sqlite_temp_master SET " + "sql = sqlite_rename_trigger(sql, %Q), " + "tbl_name = %Q " + "WHERE %s;", zName, zName, zTempTrig); + } + } +#endif + + /* Drop the elements of the in-memory schema that refered to the table + ** renamed and load the new versions from the database. + */ + if( pParse->nErr==0 ){ +#ifndef SQLITE_OMIT_TRIGGER + Trigger *pTrig; + for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ + assert( pTrig->iDb==iDb || pTrig->iDb==1 ); + sqlite3VdbeOp3(v, OP_DropTrigger, pTrig->iDb, 0, pTrig->name, 0); + } +#endif + sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); + zWhere = sqlite3MPrintf("tbl_name=%Q", zName); + sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC); +#ifndef SQLITE_OMIT_TRIGGER + if( zTempTrig ){ + sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zTempTrig, P3_DYNAMIC); + } + }else{ + sqliteFree(zTempTrig); +#endif + } + +exit_rename_table: + sqlite3SrcListDelete(pSrc); + sqliteFree(zName); +} +#endif /* SQLITE_ALTER_TABLE */ diff --git a/src/build.c b/src/build.c index d9328d98a8..e8412d1a21 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.310 2005/02/14 20:48:20 drh Exp $ +** $Id: build.c,v 1.311 2005/02/15 20:47:57 drh Exp $ */ #include "sqliteInt.h" #include @@ -3003,171 +3003,3 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); } #endif - -#ifndef SQLITE_OMIT_ALTERTABLE -/* -** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" -** command. -*/ -void sqlite3AlterRenameTable( - Parse *pParse, /* Parser context. */ - SrcList *pSrc, /* The table to rename. */ - Token *pName /* The new table name. */ -){ - int iDb; /* Database that contains the table */ - char *zDb; /* Name of database iDb */ - Table *pTab; /* Table being renamed */ - char *zName = 0; /* NULL-terminated version of pName */ - char *zWhere = 0; /* Where clause of schema elements to reparse */ - sqlite3 *db = pParse->db; /* Database connection */ - Vdbe *v; -#ifndef SQLITE_OMIT_TRIGGER - char *zTempTrig = 0; /* Where clause to locate temp triggers */ -#endif - - assert( pSrc->nSrc==1 ); - - pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); - if( !pTab ) goto exit_alter_table; - iDb = pTab->iDb; - zDb = db->aDb[iDb].zName; - - /* Get a NULL terminated version of the new table name. */ - zName = sqlite3NameFromToken(pName); - if( !zName ) goto exit_alter_table; - - /* Check that a table or index named 'zName' does not already exist - ** in database iDb. If so, this is an error. - */ - if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){ - sqlite3ErrorMsg(pParse, - "there is already another table or index with this name: %s", zName); - goto exit_alter_table; - } - - /* Make sure it is not a system table being altered, or a reserved name - ** that the table is being renamed to. - */ - if( strlen(pTab->zName)>6 && 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ){ - sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName); - goto exit_alter_table; - } - if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ - goto exit_alter_table; - } - -#ifndef SQLITE_OMIT_AUTHORIZATION - /* Invoke the authorization callback. */ - if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ - goto exit_alter_table; - } -#endif - - /* Begin a transaction and code the VerifyCookie for database iDb. - ** Then modify the schema cookie (since the ALTER TABLE modifies the - ** schema). - */ - v = sqlite3GetVdbe(pParse); - if( v==0 ){ - goto exit_alter_table; - } - sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3ChangeCookie(db, v, iDb); - - /* Modify the sqlite_master table to use the new table name. */ - sqlite3NestedParse(pParse, - "UPDATE %Q.%s SET " -#ifdef SQLITE_OMIT_TRIGGER - "sql = sqlite_alter_table(sql, %Q), " -#else - "sql = CASE " - "WHEN type = 'trigger' THEN sqlite_alter_trigger(sql, %Q)" - "ELSE sqlite_alter_table(sql, %Q) END, " -#endif - "tbl_name = %Q, " - "name = CASE " - "WHEN type='table' THEN %Q " - "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " - "'sqlite_autoindex_' || %Q || substr(name, %d+18,10) " - "ELSE name END " - "WHERE tbl_name=%Q AND " - "(type='table' OR type='index' OR type='trigger');", - zDb, SCHEMA_TABLE(iDb), zName, zName, zName, -#ifndef SQLITE_OMIT_TRIGGER -zName, -#endif - zName, strlen(pTab->zName), pTab->zName - ); - -#ifndef SQLITE_OMIT_AUTOINCREMENT - /* If the sqlite_sequence table exists in this database, then update - ** it with the new table name. - */ - if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ - sqlite3NestedParse(pParse, - "UPDATE %Q.sqlite_sequence set name = %Q WHERE name = %Q", - zDb, zName, pTab->zName); - } -#endif - -#ifndef SQLITE_OMIT_TRIGGER - /* If there are TEMP triggers on this table, modify the sqlite_temp_master - ** table. Don't do this if the table being ALTERed is itself located in - ** the temp database. - */ - if( iDb!=1 ){ - Trigger *pTrig; - char *tmp = 0; - for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ - if( pTrig->iDb==1 ){ - if( !zTempTrig ){ - zTempTrig = - sqlite3MPrintf("type = 'trigger' AND (name=%Q", pTrig->name); - }else{ - tmp = zTempTrig; - zTempTrig = sqlite3MPrintf("%s OR name=%Q", zTempTrig, pTrig->name); - sqliteFree(tmp); - } - } - } - if( zTempTrig ){ - tmp = zTempTrig; - zTempTrig = sqlite3MPrintf("%s)", zTempTrig); - sqliteFree(tmp); - sqlite3NestedParse(pParse, - "UPDATE sqlite_temp_master SET " - "sql = sqlite_alter_trigger(sql, %Q), " - "tbl_name = %Q " - "WHERE %s;", zName, zName, zTempTrig); - } - } -#endif - - /* Drop the elements of the in-memory schema that refered to the table - ** renamed and load the new versions from the database. - */ - if( pParse->nErr==0 ){ -#ifndef SQLITE_OMIT_TRIGGER - Trigger *pTrig; - for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ - assert( pTrig->iDb==iDb || pTrig->iDb==1 ); - sqlite3VdbeOp3(v, OP_DropTrigger, pTrig->iDb, 0, pTrig->name, 0); - } -#endif - sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); - zWhere = sqlite3MPrintf("tbl_name=%Q", zName); - sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC); -#ifndef SQLITE_OMIT_TRIGGER - if( zTempTrig ){ - sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zTempTrig, P3_DYNAMIC); - } - }else{ - sqliteFree(zTempTrig); -#endif - } - -exit_alter_table: - sqlite3SrcListDelete(pSrc); - sqliteFree(zName); -} -#endif diff --git a/src/func.c b/src/func.c index f5e633c57b..afc3de0394 100644 --- a/src/func.c +++ b/src/func.c @@ -16,7 +16,7 @@ ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.94 2005/02/09 01:40:25 danielk1977 Exp $ +** $Id: func.c,v 1.95 2005/02/15 20:47:57 drh Exp $ */ #include "sqliteInt.h" #include @@ -541,13 +541,13 @@ static void versionFunc( ** the CREATE TABLE or CREATE INDEX statement is replaced with the second ** argument and the result returned. Examples: ** -** sqlite_alter_table('CREATE TABLE abc(a, b, c)', 'def') +** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def') ** -> 'CREATE TABLE def(a, b, c)' ** -** sqlite_alter_table('CREATE INDEX i ON abc(a)', 'def') +** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def') ** -> 'CREATE INDEX i ON def(a, b, c)' */ -static void altertableFunc( +static void renameTableFunc( sqlite3_context *context, int argc, sqlite3_value **argv @@ -594,10 +594,10 @@ static void altertableFunc( ** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER ** statement. The second is a table name. The table name in the CREATE ** TRIGGER statement is replaced with the second argument and the result -** returned. This is analagous to altertableFunc() above, except for CREATE +** returned. This is analagous to renameTableFunc() above, except for CREATE ** TRIGGER, not CREATE INDEX and CREATE TABLE. */ -static void altertriggerFunc( +static void renameTriggerFunc( sqlite3_context *context, int argc, sqlite3_value **argv @@ -1123,9 +1123,9 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ { "changes", 0, 1, SQLITE_UTF8, 0, changes }, { "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes }, #ifndef SQLITE_OMIT_ALTERTABLE - { "sqlite_alter_table", 2, 0, SQLITE_UTF8, 0, altertableFunc}, + { "sqlite_rename_table", 2, 0, SQLITE_UTF8, 0, renameTableFunc}, #ifndef SQLITE_OMIT_TRIGGER - { "sqlite_alter_trigger", 2, 0, SQLITE_UTF8, 0, altertriggerFunc}, + { "sqlite_rename_trigger",2, 0, SQLITE_UTF8, 0, renameTriggerFunc}, #endif #endif #ifdef SQLITE_SOUNDEX