diff options
author | danielk1977 <danielk1977@noemail.net> | 2004-11-12 13:42:30 +0000 |
---|---|---|
committer | danielk1977 <danielk1977@noemail.net> | 2004-11-12 13:42:30 +0000 |
commit | 9fd2a9a02854aa0cce1c57491d0935d14172cb36 (patch) | |
tree | 110c52475d179b88f8fdf7944c8d720facb9069d /src | |
parent | 2958a4e6a550b306c3958cbe0e7a8aa5f011718d (diff) | |
download | sqlite-9fd2a9a02854aa0cce1c57491d0935d14172cb36.tar.gz sqlite-9fd2a9a02854aa0cce1c57491d0935d14172cb36.zip |
Add the "ALTER TABLE xxx RENAME TO yyy" command. (CVS 2092)
FossilOrigin-Name: a1b2cc63e604785bd51e358ff72c485d858752e3
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 80 | ||||
-rw-r--r-- | src/func.c | 48 | ||||
-rw-r--r-- | src/parse.y | 9 | ||||
-rw-r--r-- | src/sqliteInt.h | 5 | ||||
-rw-r--r-- | src/tokenize.c | 6 |
5 files changed, 140 insertions, 8 deletions
diff --git a/src/build.c b/src/build.c index ead40ec42..ab3877dab 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.276 2004/11/12 03:56:15 drh Exp $ +** $Id: build.c,v 1.277 2004/11/12 13:42:31 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -2359,7 +2359,7 @@ void sqlite3CreateIndex( */ if( pStart && pEnd ){ /* A named index with an explicit CREATE INDEX statement */ - zStmt = sqlite3MPrintf("CREATE%s INDEX %.*q", + zStmt = sqlite3MPrintf("CREATE%s INDEX %.*s", onError==OE_None ? "" : " UNIQUE", Addr(pEnd->z) - Addr(pName->z) + 1, pName->z); @@ -2919,3 +2919,79 @@ 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 */ + Table *pTab; /* Table being renamed */ + sqlite3 *db = pParse->db; /* Database connection */ + char *zName = 0; /* NULL-terminated version of pName */ + char *zWhere = 0; /* Where clause of schema elements to reparse */ + Vdbe *v; + + assert( pSrc->nSrc==1 ); + + pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); + if( !pTab ) return; + iDb = pTab->iDb; + + /* Get a NULL terminated version of the new table name. */ + zName = sqlite3NameFromToken(pName); + if( !zName ) return; + + /* 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, db->aDb[iDb].zName) || + sqlite3FindIndex(db, zName, db->aDb[iDb].zName) ){ + sqlite3ErrorMsg(pParse, + "there is already another table or index with this name: %s", zName); + sqliteFree(zName); + return; + } + + /* 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 ) return; + 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 " + "sql = sqlite_alter_table(sql, %Q), " + "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 IN ('table', 'index');", + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName, zName, zName, + zName, strlen(pTab->zName), pTab->zName + ); + + /* 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 ){ + sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); + zWhere = sqlite3MPrintf("tbl_name=%Q", zName); + sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC); + } + + sqliteFree(zName); +} +#endif + diff --git a/src/func.c b/src/func.c index 46952284e..2d760b7f8 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.85 2004/10/06 15:41:17 drh Exp $ +** $Id: func.c,v 1.86 2004/11/12 13:42:31 danielk1977 Exp $ */ #include <ctype.h> #include <math.h> @@ -507,6 +507,49 @@ static void versionFunc( sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC); } +#ifndef SQLITE_OMIT_ALTERTABLE +/* +** This function is used by SQL generated to implement the +** ALTER TABLE command. The first argument is the text of a CREATE TABLE or +** CREATE INDEX command. The second is a table name. The table name in +** 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') +** -> 'CREATE TABLE def(a, b, c)' +** +** sqlite_alter_table('CREATE INDEX i ON abc(a)', 'def') +** -> 'CREATE INDEX i ON def(a, b, c)' +*/ +static void altertableFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + char const *zSql = sqlite3_value_text(argv[0]); + char const *zTableName = sqlite3_value_text(argv[1]); + + char const *zCsr = zSql; + char const *zPrev; + char *zRet = 0; + int tokenType = 0; + int len; + + assert( argc==2 ); + if( zSql ){ + while( tokenType!=TK_LP ){ + zPrev = zCsr-len; + len = sqlite3GetToken(zCsr, &tokenType); + zCsr += len; + } + + zRet = sqlite3MPrintf("%.*s%Q(%s", zPrev-zSql, zSql, zTableName, zCsr); + sqlite3_result_text(context, zRet, -1, SQLITE_TRANSIENT); + sqliteFree(zRet); + } +} +#endif + /* ** EXPERIMENTAL - This is not an official function. The interface may ** change. This function may disappear. Do not write code that depends @@ -952,6 +995,9 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ { "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid }, { "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}, +#endif #ifdef SQLITE_SOUNDEX { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc}, #endif diff --git a/src/parse.y b/src/parse.y index c8ebc76e1..1ff1b0dcc 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.153 2004/11/12 03:56:15 drh Exp $ +** @(#) $Id: parse.y,v 1.154 2004/11/12 13:42:31 danielk1977 Exp $ */ %token_prefix TK_ %token_type {Token} @@ -953,3 +953,10 @@ cmd ::= DETACH database_kw_opt nm(D). { cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);} cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);} %endif + +//////////////////////// ALTER TABLE table ... //////////////////////////////// +%ifndef SQLITE_OMIT_ALTERTABLE +cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). { + sqlite3AlterRenameTable(pParse,X,&Z); +} +%endif diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 50f7f61a4..4f4e1b294 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.338 2004/11/12 03:56:15 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.339 2004/11/12 13:42:31 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -107,6 +107,7 @@ /* #define SQLITE_OMIT_DATETIME_FUNCS 1 */ /* #define SQLITE_OMIT_PROGRESS_CALLBACK 1 */ /* #define SQLITE_OMIT_AUTOVACUUM */ +/* #define SQLITE_OMIT_ALTERTABLE */ /* ** GCC does not define the offsetof() macro so we'll have to do it @@ -1457,6 +1458,8 @@ sqlite3_value *sqlite3GetTransientValue(sqlite3*db); extern const unsigned char sqlite3UpperToLower[]; void sqlite3RootPageMoved(Db*, int, int); void sqlite3Reindex(Parse*, Token*, Token*); +void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); +int sqlite3GetToken(const unsigned char *, int *); void sqlite3NestedParse(Parse*, const char*, ...); #endif diff --git a/src/tokenize.c b/src/tokenize.c index 9cda93948..5ae661379 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.96 2004/11/12 03:56:15 drh Exp $ +** $Id: tokenize.c,v 1.97 2004/11/12 13:42:31 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -65,7 +65,7 @@ static const char isIdChar[] = { ** Return the length of the token that begins at z[0]. ** Store the token type in *tokenType before returning. */ -static int sqliteGetToken(const unsigned char *z, int *tokenType){ +int sqlite3GetToken(const unsigned char *z, int *tokenType){ int i, c; switch( *z ){ case ' ': case '\t': case '\n': case '\f': case '\r': { @@ -349,7 +349,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ assert( i>=0 ); pParse->sLastToken.z = &zSql[i]; assert( pParse->sLastToken.dyn==0 ); - pParse->sLastToken.n = sqliteGetToken((unsigned char*)&zSql[i], &tokenType); + pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType); i += pParse->sLastToken.n; switch( tokenType ){ case TK_SPACE: |