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:
80
src/build.c
80
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
|
||||
|
||||
|
||||
48
src/func.c
48
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user