1
0
mirror of https://github.com/sqlite/sqlite.git synced 2026-01-06 08:01:16 +03:00

Add the "ALTER TABLE xxx RENAME TO yyy" command. (CVS 2092)

FossilOrigin-Name: a1b2cc63e604785bd51e358ff72c485d858752e3
This commit is contained in:
danielk1977
2004-11-12 13:42:30 +00:00
parent 2958a4e6a5
commit 9fd2a9a028
9 changed files with 326 additions and 21 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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: