blob: d6ce4208b276703d9769353d954f3430c1851058 [file] [log] [blame]
drhd0e4a6c2005-02-15 20:47:57 +00001/*
2** 2005 February 15
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11*************************************************************************
12** This file contains C code routines that used to generate VDBE code
13** that implements the ALTER TABLE command.
14**
15** $Id: alter.c,v 1.1 2005/02/15 20:47:57 drh Exp $
16*/
17#include "sqliteInt.h"
18
19
20#ifndef SQLITE_OMIT_ALTERTABLE
21/*
22** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
23** command.
24*/
25void sqlite3AlterRenameTable(
26 Parse *pParse, /* Parser context. */
27 SrcList *pSrc, /* The table to rename. */
28 Token *pName /* The new table name. */
29){
30 int iDb; /* Database that contains the table */
31 char *zDb; /* Name of database iDb */
32 Table *pTab; /* Table being renamed */
33 char *zName = 0; /* NULL-terminated version of pName */
34 char *zWhere = 0; /* Where clause of schema elements to reparse */
35 sqlite3 *db = pParse->db; /* Database connection */
36 Vdbe *v;
37#ifndef SQLITE_OMIT_TRIGGER
38 char *zTempTrig = 0; /* Where clause to locate temp triggers */
39#endif
40
41 assert( pSrc->nSrc==1 );
42
43 pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
44 if( !pTab ) goto exit_rename_table;
45 iDb = pTab->iDb;
46 zDb = db->aDb[iDb].zName;
47
48 /* Get a NULL terminated version of the new table name. */
49 zName = sqlite3NameFromToken(pName);
50 if( !zName ) goto exit_rename_table;
51
52 /* Check that a table or index named 'zName' does not already exist
53 ** in database iDb. If so, this is an error.
54 */
55 if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
56 sqlite3ErrorMsg(pParse,
57 "there is already another table or index with this name: %s", zName);
58 goto exit_rename_table;
59 }
60
61 /* Make sure it is not a system table being altered, or a reserved name
62 ** that the table is being renamed to.
63 */
64 if( strlen(pTab->zName)>6 && 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ){
65 sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName);
66 goto exit_rename_table;
67 }
68 if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
69 goto exit_rename_table;
70 }
71
72#ifndef SQLITE_OMIT_AUTHORIZATION
73 /* Invoke the authorization callback. */
74 if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
75 goto exit_rename_table;
76 }
77#endif
78
79 /* Begin a transaction and code the VerifyCookie for database iDb.
80 ** Then modify the schema cookie (since the ALTER TABLE modifies the
81 ** schema).
82 */
83 v = sqlite3GetVdbe(pParse);
84 if( v==0 ){
85 goto exit_rename_table;
86 }
87 sqlite3BeginWriteOperation(pParse, 0, iDb);
88 sqlite3ChangeCookie(db, v, iDb);
89
90 /* Modify the sqlite_master table to use the new table name. */
91 sqlite3NestedParse(pParse,
92 "UPDATE %Q.%s SET "
93#ifdef SQLITE_OMIT_TRIGGER
94 "sql = sqlite_rename_table(sql, %Q), "
95#else
96 "sql = CASE "
97 "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)"
98 "ELSE sqlite_rename_table(sql, %Q) END, "
99#endif
100 "tbl_name = %Q, "
101 "name = CASE "
102 "WHEN type='table' THEN %Q "
103 "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
104 "'sqlite_autoindex_' || %Q || substr(name, %d+18,10) "
105 "ELSE name END "
106 "WHERE tbl_name=%Q AND "
107 "(type='table' OR type='index' OR type='trigger');",
108 zDb, SCHEMA_TABLE(iDb), zName, zName, zName,
109#ifndef SQLITE_OMIT_TRIGGER
110zName,
111#endif
112 zName, strlen(pTab->zName), pTab->zName
113 );
114
115#ifndef SQLITE_OMIT_AUTOINCREMENT
116 /* If the sqlite_sequence table exists in this database, then update
117 ** it with the new table name.
118 */
119 if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){
120 sqlite3NestedParse(pParse,
121 "UPDATE %Q.sqlite_sequence set name = %Q WHERE name = %Q",
122 zDb, zName, pTab->zName);
123 }
124#endif
125
126#ifndef SQLITE_OMIT_TRIGGER
127 /* If there are TEMP triggers on this table, modify the sqlite_temp_master
128 ** table. Don't do this if the table being ALTERed is itself located in
129 ** the temp database.
130 */
131 if( iDb!=1 ){
132 Trigger *pTrig;
133 char *tmp = 0;
134 for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
135 if( pTrig->iDb==1 ){
136 if( !zTempTrig ){
137 zTempTrig =
138 sqlite3MPrintf("type = 'trigger' AND (name=%Q", pTrig->name);
139 }else{
140 tmp = zTempTrig;
141 zTempTrig = sqlite3MPrintf("%s OR name=%Q", zTempTrig, pTrig->name);
142 sqliteFree(tmp);
143 }
144 }
145 }
146 if( zTempTrig ){
147 tmp = zTempTrig;
148 zTempTrig = sqlite3MPrintf("%s)", zTempTrig);
149 sqliteFree(tmp);
150 sqlite3NestedParse(pParse,
151 "UPDATE sqlite_temp_master SET "
152 "sql = sqlite_rename_trigger(sql, %Q), "
153 "tbl_name = %Q "
154 "WHERE %s;", zName, zName, zTempTrig);
155 }
156 }
157#endif
158
159 /* Drop the elements of the in-memory schema that refered to the table
160 ** renamed and load the new versions from the database.
161 */
162 if( pParse->nErr==0 ){
163#ifndef SQLITE_OMIT_TRIGGER
164 Trigger *pTrig;
165 for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
166 assert( pTrig->iDb==iDb || pTrig->iDb==1 );
167 sqlite3VdbeOp3(v, OP_DropTrigger, pTrig->iDb, 0, pTrig->name, 0);
168 }
169#endif
170 sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
171 zWhere = sqlite3MPrintf("tbl_name=%Q", zName);
172 sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC);
173#ifndef SQLITE_OMIT_TRIGGER
174 if( zTempTrig ){
175 sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zTempTrig, P3_DYNAMIC);
176 }
177 }else{
178 sqliteFree(zTempTrig);
179#endif
180 }
181
182exit_rename_table:
183 sqlite3SrcListDelete(pSrc);
184 sqliteFree(zName);
185}
186#endif /* SQLITE_ALTER_TABLE */