Back to index

lightning-sunbird  0.9+nobinonly
alter.c
Go to the documentation of this file.
00001 /*
00002 ** 2005 February 15
00003 **
00004 ** The author disclaims copyright to this source code.  In place of
00005 ** a legal notice, here is a blessing:
00006 **
00007 **    May you do good and not evil.
00008 **    May you find forgiveness for yourself and forgive others.
00009 **    May you share freely, never taking more than you give.
00010 **
00011 *************************************************************************
00012 ** This file contains C code routines that used to generate VDBE code
00013 ** that implements the ALTER TABLE command.
00014 **
00015 ** $Id: alter.c,v 1.2.8.4 2006/05/22 19:12:32 brettw%gmail.com Exp $
00016 */
00017 #include "sqliteInt.h"
00018 #include <ctype.h>
00019 
00020 /*
00021 ** The code in this file only exists if we are not omitting the
00022 ** ALTER TABLE logic from the build.
00023 */
00024 #ifndef SQLITE_OMIT_ALTERTABLE
00025 
00026 
00027 /*
00028 ** This function is used by SQL generated to implement the 
00029 ** ALTER TABLE command. The first argument is the text of a CREATE TABLE or
00030 ** CREATE INDEX command. The second is a table name. The table name in 
00031 ** the CREATE TABLE or CREATE INDEX statement is replaced with the second
00032 ** argument and the result returned. Examples:
00033 **
00034 ** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
00035 **     -> 'CREATE TABLE def(a, b, c)'
00036 **
00037 ** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def')
00038 **     -> 'CREATE INDEX i ON def(a, b, c)'
00039 */
00040 static void renameTableFunc(
00041   sqlite3_context *context,
00042   int argc,
00043   sqlite3_value **argv
00044 ){
00045   unsigned char const *zSql = sqlite3_value_text(argv[0]);
00046   unsigned char const *zTableName = sqlite3_value_text(argv[1]);
00047 
00048   int token;
00049   Token tname;
00050   unsigned char const *zCsr = zSql;
00051   int len = 0;
00052   char *zRet;
00053 
00054   /* The principle used to locate the table name in the CREATE TABLE 
00055   ** statement is that the table name is the first token that is immediatedly
00056   ** followed by a left parenthesis - TK_LP.
00057   */
00058   if( zSql ){
00059     do {
00060       /* Store the token that zCsr points to in tname. */
00061       tname.z = zCsr;
00062       tname.n = len;
00063 
00064       /* Advance zCsr to the next token. Store that token type in 'token',
00065       ** and it's length in 'len' (to be used next iteration of this loop).
00066       */
00067       do {
00068         zCsr += len;
00069         len = sqlite3GetToken(zCsr, &token);
00070       } while( token==TK_SPACE );
00071       assert( len>0 );
00072     } while( token!=TK_LP );
00073 
00074     zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql, 
00075        zTableName, tname.z+tname.n);
00076     sqlite3_result_text(context, zRet, -1, sqlite3FreeX);
00077   }
00078 }
00079 
00080 #ifndef SQLITE_OMIT_TRIGGER
00081 /* This function is used by SQL generated to implement the ALTER TABLE
00082 ** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER 
00083 ** statement. The second is a table name. The table name in the CREATE 
00084 ** TRIGGER statement is replaced with the second argument and the result 
00085 ** returned. This is analagous to renameTableFunc() above, except for CREATE
00086 ** TRIGGER, not CREATE INDEX and CREATE TABLE.
00087 */
00088 static void renameTriggerFunc(
00089   sqlite3_context *context,
00090   int argc,
00091   sqlite3_value **argv
00092 ){
00093   unsigned char const *zSql = sqlite3_value_text(argv[0]);
00094   unsigned char const *zTableName = sqlite3_value_text(argv[1]);
00095 
00096   int token;
00097   Token tname;
00098   int dist = 3;
00099   unsigned char const *zCsr = zSql;
00100   int len = 0;
00101   char *zRet;
00102 
00103   /* The principle used to locate the table name in the CREATE TRIGGER 
00104   ** statement is that the table name is the first token that is immediatedly
00105   ** preceded by either TK_ON or TK_DOT and immediatedly followed by one
00106   ** of TK_WHEN, TK_BEGIN or TK_FOR.
00107   */
00108   if( zSql ){
00109     do {
00110       /* Store the token that zCsr points to in tname. */
00111       tname.z = zCsr;
00112       tname.n = len;
00113 
00114       /* Advance zCsr to the next token. Store that token type in 'token',
00115       ** and it's length in 'len' (to be used next iteration of this loop).
00116       */
00117       do {
00118         zCsr += len;
00119         len = sqlite3GetToken(zCsr, &token);
00120       }while( token==TK_SPACE );
00121       assert( len>0 );
00122 
00123       /* Variable 'dist' stores the number of tokens read since the most
00124       ** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN 
00125       ** token is read and 'dist' equals 2, the condition stated above
00126       ** to be met.
00127       **
00128       ** Note that ON cannot be a database, table or column name, so
00129       ** there is no need to worry about syntax like 
00130       ** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc.
00131       */
00132       dist++;
00133       if( token==TK_DOT || token==TK_ON ){
00134         dist = 0;
00135       }
00136     } while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) );
00137 
00138     /* Variable tname now contains the token that is the old table-name
00139     ** in the CREATE TRIGGER statement.
00140     */
00141     zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql, 
00142        zTableName, tname.z+tname.n);
00143     sqlite3_result_text(context, zRet, -1, sqlite3FreeX);
00144   }
00145 }
00146 #endif   /* !SQLITE_OMIT_TRIGGER */
00147 
00148 /*
00149 ** Register built-in functions used to help implement ALTER TABLE
00150 */
00151 void sqlite3AlterFunctions(sqlite3 *db){
00152   static const struct {
00153      char *zName;
00154      signed char nArg;
00155      void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
00156   } aFuncs[] = {
00157     { "sqlite_rename_table",    2, renameTableFunc},
00158 #ifndef SQLITE_OMIT_TRIGGER
00159     { "sqlite_rename_trigger",  2, renameTriggerFunc},
00160 #endif
00161   };
00162   int i;
00163 
00164   for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
00165     sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
00166         SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
00167   }
00168 }
00169 
00170 /*
00171 ** Generate the text of a WHERE expression which can be used to select all
00172 ** temporary triggers on table pTab from the sqlite_temp_master table. If
00173 ** table pTab has no temporary triggers, or is itself stored in the 
00174 ** temporary database, NULL is returned.
00175 */
00176 static char *whereTempTriggers(Parse *pParse, Table *pTab){
00177   Trigger *pTrig;
00178   char *zWhere = 0;
00179   char *tmp = 0;
00180   const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */
00181 
00182   /* If the table is not located in the temp-db (in which case NULL is 
00183   ** returned, loop through the tables list of triggers. For each trigger
00184   ** that is not part of the temp-db schema, add a clause to the WHERE 
00185   ** expression being built up in zWhere.
00186   */
00187   if( pTab->pSchema!=pTempSchema ){
00188     for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
00189       if( pTrig->pSchema==pTempSchema ){
00190         if( !zWhere ){
00191           zWhere = sqlite3MPrintf("name=%Q", pTrig->name);
00192         }else{
00193           tmp = zWhere;
00194           zWhere = sqlite3MPrintf("%s OR name=%Q", zWhere, pTrig->name);
00195           sqliteFree(tmp);
00196         }
00197       }
00198     }
00199   }
00200   return zWhere;
00201 }
00202 
00203 /*
00204 ** Generate code to drop and reload the internal representation of table
00205 ** pTab from the database, including triggers and temporary triggers.
00206 ** Argument zName is the name of the table in the database schema at
00207 ** the time the generated code is executed. This can be different from
00208 ** pTab->zName if this function is being called to code part of an 
00209 ** "ALTER TABLE RENAME TO" statement.
00210 */
00211 static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
00212   Vdbe *v;
00213   char *zWhere;
00214   int iDb;                   /* Index of database containing pTab */
00215 #ifndef SQLITE_OMIT_TRIGGER
00216   Trigger *pTrig;
00217 #endif
00218 
00219   v = sqlite3GetVdbe(pParse);
00220   if( !v ) return;
00221   iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
00222   assert( iDb>=0 );
00223 
00224 #ifndef SQLITE_OMIT_TRIGGER
00225   /* Drop any table triggers from the internal schema. */
00226   for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){
00227     int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
00228     assert( iTrigDb==iDb || iTrigDb==1 );
00229     sqlite3VdbeOp3(v, OP_DropTrigger, iTrigDb, 0, pTrig->name, 0);
00230   }
00231 #endif
00232 
00233   /* Drop the table and index from the internal schema */
00234   sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
00235 
00236   /* Reload the table, index and permanent trigger schemas. */
00237   zWhere = sqlite3MPrintf("tbl_name=%Q", zName);
00238   if( !zWhere ) return;
00239   sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC);
00240 
00241 #ifndef SQLITE_OMIT_TRIGGER
00242   /* Now, if the table is not stored in the temp database, reload any temp 
00243   ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined. 
00244   */
00245   if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
00246     sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zWhere, P3_DYNAMIC);
00247   }
00248 #endif
00249 }
00250 
00251 /*
00252 ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" 
00253 ** command. 
00254 */
00255 void sqlite3AlterRenameTable(
00256   Parse *pParse,            /* Parser context. */
00257   SrcList *pSrc,            /* The table to rename. */
00258   Token *pName              /* The new table name. */
00259 ){
00260   int iDb;                  /* Database that contains the table */
00261   char *zDb;                /* Name of database iDb */
00262   Table *pTab;              /* Table being renamed */
00263   char *zName = 0;          /* NULL-terminated version of pName */ 
00264   sqlite3 *db = pParse->db; /* Database connection */
00265   Vdbe *v;
00266 #ifndef SQLITE_OMIT_TRIGGER
00267   char *zWhere = 0;         /* Where clause to locate temp triggers */
00268 #endif
00269   
00270   if( sqlite3MallocFailed() ) goto exit_rename_table;
00271   assert( pSrc->nSrc==1 );
00272 
00273   pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
00274   if( !pTab ) goto exit_rename_table;
00275   iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
00276   zDb = db->aDb[iDb].zName;
00277 
00278   /* Get a NULL terminated version of the new table name. */
00279   zName = sqlite3NameFromToken(pName);
00280   if( !zName ) goto exit_rename_table;
00281 
00282   /* Check that a table or index named 'zName' does not already exist
00283   ** in database iDb. If so, this is an error.
00284   */
00285   if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
00286     sqlite3ErrorMsg(pParse, 
00287         "there is already another table or index with this name: %s", zName);
00288     goto exit_rename_table;
00289   }
00290 
00291   /* Make sure it is not a system table being altered, or a reserved name
00292   ** that the table is being renamed to.
00293   */
00294   if( strlen(pTab->zName)>6 && 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ){
00295     sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName);
00296     goto exit_rename_table;
00297   }
00298   if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
00299     goto exit_rename_table;
00300   }
00301 
00302 #ifndef SQLITE_OMIT_AUTHORIZATION
00303   /* Invoke the authorization callback. */
00304   if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
00305     goto exit_rename_table;
00306   }
00307 #endif
00308 
00309   /* Begin a transaction and code the VerifyCookie for database iDb. 
00310   ** Then modify the schema cookie (since the ALTER TABLE modifies the
00311   ** schema).
00312   */
00313   v = sqlite3GetVdbe(pParse);
00314   if( v==0 ){
00315     goto exit_rename_table;
00316   }
00317   sqlite3BeginWriteOperation(pParse, 0, iDb);
00318   sqlite3ChangeCookie(db, v, iDb);
00319 
00320   /* Modify the sqlite_master table to use the new table name. */
00321   sqlite3NestedParse(pParse,
00322       "UPDATE %Q.%s SET "
00323 #ifdef SQLITE_OMIT_TRIGGER
00324           "sql = sqlite_rename_table(sql, %Q), "
00325 #else
00326           "sql = CASE "
00327             "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)"
00328             "ELSE sqlite_rename_table(sql, %Q) END, "
00329 #endif
00330           "tbl_name = %Q, "
00331           "name = CASE "
00332             "WHEN type='table' THEN %Q "
00333             "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
00334               "'sqlite_autoindex_' || %Q || substr(name, %d+18,10) "
00335             "ELSE name END "
00336       "WHERE tbl_name=%Q AND "
00337           "(type='table' OR type='index' OR type='trigger');", 
00338       zDb, SCHEMA_TABLE(iDb), zName, zName, zName, 
00339 #ifndef SQLITE_OMIT_TRIGGER
00340       zName,
00341 #endif
00342       zName, strlen(pTab->zName), pTab->zName
00343   );
00344 
00345 #ifndef SQLITE_OMIT_AUTOINCREMENT
00346   /* If the sqlite_sequence table exists in this database, then update 
00347   ** it with the new table name.
00348   */
00349   if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){
00350     sqlite3NestedParse(pParse,
00351         "UPDATE %Q.sqlite_sequence set name = %Q WHERE name = %Q",
00352         zDb, zName, pTab->zName);
00353   }
00354 #endif
00355 
00356 #ifndef SQLITE_OMIT_TRIGGER
00357   /* If there are TEMP triggers on this table, modify the sqlite_temp_master
00358   ** table. Don't do this if the table being ALTERed is itself located in
00359   ** the temp database.
00360   */
00361   if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
00362     sqlite3NestedParse(pParse, 
00363         "UPDATE sqlite_temp_master SET "
00364             "sql = sqlite_rename_trigger(sql, %Q), "
00365             "tbl_name = %Q "
00366             "WHERE %s;", zName, zName, zWhere);
00367     sqliteFree(zWhere);
00368   }
00369 #endif
00370 
00371   /* Drop and reload the internal table schema. */
00372   reloadTableSchema(pParse, pTab, zName);
00373 
00374 exit_rename_table:
00375   sqlite3SrcListDelete(pSrc);
00376   sqliteFree(zName);
00377 }
00378 
00379 
00380 /*
00381 ** This function is called after an "ALTER TABLE ... ADD" statement
00382 ** has been parsed. Argument pColDef contains the text of the new
00383 ** column definition.
00384 **
00385 ** The Table structure pParse->pNewTable was extended to include
00386 ** the new column during parsing.
00387 */
00388 void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
00389   Table *pNew;              /* Copy of pParse->pNewTable */
00390   Table *pTab;              /* Table being altered */
00391   int iDb;                  /* Database number */
00392   const char *zDb;          /* Database name */
00393   const char *zTab;         /* Table name */
00394   char *zCol;               /* Null-terminated column definition */
00395   Column *pCol;             /* The new column */
00396   Expr *pDflt;              /* Default value for the new column */
00397 
00398   if( pParse->nErr ) return;
00399   pNew = pParse->pNewTable;
00400   assert( pNew );
00401 
00402   iDb = sqlite3SchemaToIndex(pParse->db, pNew->pSchema);
00403   zDb = pParse->db->aDb[iDb].zName;
00404   zTab = pNew->zName;
00405   pCol = &pNew->aCol[pNew->nCol-1];
00406   pDflt = pCol->pDflt;
00407   pTab = sqlite3FindTable(pParse->db, zTab, zDb);
00408   assert( pTab );
00409 
00410 #ifndef SQLITE_OMIT_AUTHORIZATION
00411   /* Invoke the authorization callback. */
00412   if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
00413     return;
00414   }
00415 #endif
00416 
00417   /* If the default value for the new column was specified with a 
00418   ** literal NULL, then set pDflt to 0. This simplifies checking
00419   ** for an SQL NULL default below.
00420   */
00421   if( pDflt && pDflt->op==TK_NULL ){
00422     pDflt = 0;
00423   }
00424 
00425   /* Check that the new column is not specified as PRIMARY KEY or UNIQUE.
00426   ** If there is a NOT NULL constraint, then the default value for the
00427   ** column must not be NULL.
00428   */
00429   if( pCol->isPrimKey ){
00430     sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
00431     return;
00432   }
00433   if( pNew->pIndex ){
00434     sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
00435     return;
00436   }
00437   if( pCol->notNull && !pDflt ){
00438     sqlite3ErrorMsg(pParse, 
00439         "Cannot add a NOT NULL column with default value NULL");
00440     return;
00441   }
00442 
00443   /* Ensure the default expression is something that sqlite3ValueFromExpr()
00444   ** can handle (i.e. not CURRENT_TIME etc.)
00445   */
00446   if( pDflt ){
00447     sqlite3_value *pVal;
00448     if( sqlite3ValueFromExpr(pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
00449       /* malloc() has failed */
00450       return;
00451     }
00452     if( !pVal ){
00453       sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
00454       return;
00455     }
00456     sqlite3ValueFree(pVal);
00457   }
00458 
00459   /* Modify the CREATE TABLE statement. */
00460   zCol = sqliteStrNDup((char*)pColDef->z, pColDef->n);
00461   if( zCol ){
00462     char *zEnd = &zCol[pColDef->n-1];
00463     while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){
00464       *zEnd-- = '\0';
00465     }
00466     sqlite3NestedParse(pParse, 
00467         "UPDATE %Q.%s SET "
00468           "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d,length(sql)) "
00469         "WHERE type = 'table' AND name = %Q", 
00470       zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1,
00471       zTab
00472     );
00473     sqliteFree(zCol);
00474   }
00475 
00476   /* If the default value of the new column is NULL, then set the file
00477   ** format to 2. If the default value of the new column is not NULL,
00478   ** the file format becomes 3.
00479   */
00480   sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2);
00481 
00482   /* Reload the schema of the modified table. */
00483   reloadTableSchema(pParse, pTab, pTab->zName);
00484 }
00485 
00486 /*
00487 ** This function is called by the parser after the table-name in
00488 ** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument 
00489 ** pSrc is the full-name of the table being altered.
00490 **
00491 ** This routine makes a (partial) copy of the Table structure
00492 ** for the table being altered and sets Parse.pNewTable to point
00493 ** to it. Routines called by the parser as the column definition
00494 ** is parsed (i.e. sqlite3AddColumn()) add the new Column data to 
00495 ** the copy. The copy of the Table structure is deleted by tokenize.c 
00496 ** after parsing is finished.
00497 **
00498 ** Routine sqlite3AlterFinishAddColumn() will be called to complete
00499 ** coding the "ALTER TABLE ... ADD" statement.
00500 */
00501 void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
00502   Table *pNew;
00503   Table *pTab;
00504   Vdbe *v;
00505   int iDb;
00506   int i;
00507   int nAlloc;
00508 
00509   /* Look up the table being altered. */
00510   assert( pParse->pNewTable==0 );
00511   if( sqlite3MallocFailed() ) goto exit_begin_add_column;
00512   pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
00513   if( !pTab ) goto exit_begin_add_column;
00514 
00515   /* Make sure this is not an attempt to ALTER a view. */
00516   if( pTab->pSelect ){
00517     sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
00518     goto exit_begin_add_column;
00519   }
00520 
00521   assert( pTab->addColOffset>0 );
00522   iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
00523 
00524   /* Put a copy of the Table struct in Parse.pNewTable for the
00525   ** sqlite3AddColumn() function and friends to modify.
00526   */
00527   pNew = (Table *)sqliteMalloc(sizeof(Table));
00528   if( !pNew ) goto exit_begin_add_column;
00529   pParse->pNewTable = pNew;
00530   pNew->nRef = 1;
00531   pNew->nCol = pTab->nCol;
00532   assert( pNew->nCol>0 );
00533   nAlloc = (((pNew->nCol-1)/8)*8)+8;
00534   assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 );
00535   pNew->aCol = (Column *)sqliteMalloc(sizeof(Column)*nAlloc);
00536   pNew->zName = sqliteStrDup(pTab->zName);
00537   if( !pNew->aCol || !pNew->zName ){
00538     goto exit_begin_add_column;
00539   }
00540   memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
00541   for(i=0; i<pNew->nCol; i++){
00542     Column *pCol = &pNew->aCol[i];
00543     pCol->zName = sqliteStrDup(pCol->zName);
00544     pCol->zColl = 0;
00545     pCol->zType = 0;
00546     pCol->pDflt = 0;
00547   }
00548   pNew->pSchema = pParse->db->aDb[iDb].pSchema;
00549   pNew->addColOffset = pTab->addColOffset;
00550   pNew->nRef = 1;
00551 
00552   /* Begin a transaction and increment the schema cookie.  */
00553   sqlite3BeginWriteOperation(pParse, 0, iDb);
00554   v = sqlite3GetVdbe(pParse);
00555   if( !v ) goto exit_begin_add_column;
00556   sqlite3ChangeCookie(pParse->db, v, iDb);
00557 
00558 exit_begin_add_column:
00559   sqlite3SrcListDelete(pSrc);
00560   return;
00561 }
00562 #endif  /* SQLITE_ALTER_TABLE */