1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-12-24 14:17:58 +03:00

Split the logic for the ALTER TABLE command off into a separate source

code file. (CVS 2342)

FossilOrigin-Name: 90d6573c2631fac92b9e572e9e21698ae2480c9d
This commit is contained in:
drh
2005-02-15 20:47:57 +00:00
parent 057cd3a0aa
commit d0e4a6c11d
7 changed files with 216 additions and 189 deletions

186
src/alter.c Normal file
View File

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

View File

@@ -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 <ctype.h>
@@ -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

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.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 <ctype.h>
@@ -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