/* ** This routine generates code that opens the sqlite_stat1 table on cursor ** iStatCur. ** ** If the sqlite_stat1 tables does not previously exist, it is created. ** If it does previously exist, all entires associated with table zWhere ** are removed. If zWhere==0 then all entries are removed. */ static void openStatTable( Parse *pParse, /* Parsing context */ int iDb, /* The database we are looking in */ int iStatCur, /* Open the sqlite_stat1 table on this cursor */ const char *zWhere /* Delete entries associated with this table */ ){ sqlite3 *db = pParse->db; Db *pDb; int iRootPage; Table *pStat; Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3VdbeDb(v)==db ); pDb = &db->aDb[iDb]; if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){ /* The sqlite_stat1 tables does not exist. Create it. ** Note that a side-effect of the CREATE TABLE statement is to leave ** the rootpage of the new table on the top of the stack. This is ** important because the OpenWrite opcode below will be needing it. */ sqlite3NestedParse(pParse, "CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)", pDb->zName ); iRootPage = 0; /* Cause rootpage to be taken from top of stack */ }else if( zWhere ){ /* The sqlite_stat1 table exists. Delete all entries associated with ** the table zWhere. */ sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_stat1 WHERE tbl=%Q", pDb->zName, zWhere ); iRootPage = pStat->tnum; }else{ /* The sqlite_stat1 table already exists. Delete all rows. */ iRootPage = pStat->tnum; sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb); } /* Open the sqlite_stat1 table for writing. Unless it was created ** by this vdbe program, lock it for writing at the shared-cache level. ** If this vdbe did create the sqlite_stat1 table, then it must have ** already obtained a schema-lock, making the write-lock redundant. */ if( iRootPage>0 ){ sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1"); } sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage); sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3); }
/* ** This routine generates code that opens the sqlite_stat1 table on cursor ** iStatCur. ** ** If the sqlite_stat1 tables does not previously exist, it is created. ** If it does previously exist, all entires associated with table zWhere ** are removed. If zWhere==0 then all entries are removed. */ static void openStatTable( Parse *pParse, /* Parsing context */ int iDb, /* The database we are looking in */ int iStatCur, /* Open the sqlite_stat1 table on this cursor */ const char *zWhere /* Delete entries associated with this table */ ){ sqlite3 *db = pParse->db; Db *pDb; int iRootPage; Table *pStat; Vdbe *v = sqlite3GetVdbe(pParse); pDb = &db->aDb[iDb]; if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){ /* The sqlite_stat1 tables does not exist. Create it. ** Note that a side-effect of the CREATE TABLE statement is to leave ** the rootpage of the new table on the top of the stack. This is ** important because the OpenWrite opcode below will be needing it. */ sqlite3NestedParse(pParse, "CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)", pDb->zName ); iRootPage = 0; /* Cause rootpage to be taken from top of stack */ }else if( zWhere ){ /* The sqlite_stat1 table exists. Delete all entries associated with ** the table zWhere. */ sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_stat1 WHERE tbl=%Q", pDb->zName, zWhere ); iRootPage = pStat->tnum; }else{ /* The sqlite_stat1 table already exists. Delete all rows. */ iRootPage = pStat->tnum; sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb); } /* Open the sqlite_stat1 table for writing. */ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage); sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3); }
/* ** Drop a trigger given a pointer to that trigger. */ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ Table *pTable; Vdbe *v; sqlite3 *db = pParse->db; int iDb; iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); assert( iDb>=0 && iDb<db->nDb ); pTable = tableOfTrigger(pTrigger); assert( pTable ); assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_TRIGGER; const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) || sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ return; } } #endif /* Generate code to destroy the database record of the trigger. */ assert( pTable!=0 ); if( (v = sqlite3GetVdbe(pParse))!=0 ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'", db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName ); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); } }
/* ** The parser calls this routine after the CREATE VIRTUAL TABLE statement ** has been completely parsed. */ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ Table *pTab = pParse->pNewTable; /* The table being constructed */ sqlite3 *db = pParse->db; /* The database connection */ if( pTab==0 ) return; addArgumentToVtab(pParse); pParse->sArg.z = 0; if( pTab->nModuleArg<1 ) return; /* If the CREATE VIRTUAL TABLE statement is being entered for the ** first time (in other words if the virtual table is actually being ** created now instead of just being read out of sqlite_master) then ** do additional initialization work and store the statement text ** in the sqlite_master table. */ if( !db->init.busy ){ char *zStmt; char *zWhere; int iDb; int iReg; Vdbe *v; /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ if( pEnd ){ pParse->sNameToken.n = (int)(pEnd->z - pParse->sNameToken.z) + pEnd->n; } zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken); /* A slot for the record has already been allocated in the ** SQLITE_MASTER table. We just need to update that slot with all ** the information we've collected. ** ** The VM register number pParse->regRowid holds the rowid of an ** entry in the sqlite_master table tht was created for this vtab ** by sqlite3StartTable(). */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "WHERE rowid=#%d", db->aDb[iDb].zDbSName, MASTER_NAME, pTab->zName, pTab->zName, zStmt, pParse->regRowid ); sqlite3DbFree(db, zStmt); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp0(v, OP_Expire); zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName); sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); iReg = ++pParse->nMem; sqlite3VdbeLoadString(v, iReg, pTab->zName); sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg); } /* If we are rereading the sqlite_master table create the in-memory ** record of the table. The xConnect() method is not called until ** the first time the virtual table is used in an SQL statement. This ** allows a schema that contains virtual tables to be loaded before ** the required virtual table implementations are registered. */ else { Table *pOld; Schema *pSchema = pTab->pSchema; const char *zName = pTab->zName; assert( sqlite3SchemaMutexHeld(db, 0, pSchema) ); pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); if( pOld ){ sqlite3OomFault(db); assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ return; } pParse->pNewTable = 0; } }
/* ** This function is called after an "ALTER TABLE ... ADD" statement ** has been parsed. Argument pColDef contains the text of the new ** column definition. ** ** The Table structure pParse->pNewTable was extended to include ** the new column during parsing. */ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ Table *pNew; /* Copy of pParse->pNewTable */ Table *pTab; /* Table being altered */ int iDb; /* Database number */ const char *zDb; /* Database name */ const char *zTab; /* Table name */ char *zCol; /* Null-terminated column definition */ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ if( pParse->nErr ) return; pNew = pParse->pNewTable; assert( pNew ); iDb = sqlite3SchemaToIndex(pParse->db, pNew->pSchema); zDb = pParse->db->aDb[iDb].zName; zTab = pNew->zName; pCol = &pNew->aCol[pNew->nCol-1]; pDflt = pCol->pDflt; pTab = sqlite3FindTable(pParse->db, zTab, zDb); assert( pTab ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ return; } #endif /* If the default value for the new column was specified with a ** literal NULL, then set pDflt to 0. This simplifies checking ** for an SQL NULL default below. */ if( pDflt && pDflt->op==TK_NULL ){ pDflt = 0; } /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. ** If there is a NOT NULL constraint, then the default value for the ** column must not be NULL. */ if( pCol->isPrimKey ){ sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column"); return; } if( pNew->pIndex ){ sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); return; } if( pCol->notNull && !pDflt ){ sqlite3ErrorMsg(pParse, "Cannot add a NOT NULL column with default value NULL"); return; } /* Ensure the default expression is something that sqlite3ValueFromExpr() ** can handle (i.e. not CURRENT_TIME etc.) */ if( pDflt ){ sqlite3_value *pVal; if( sqlite3ValueFromExpr(pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){ /* malloc() has failed */ return; } if( !pVal ){ sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default"); return; } sqlite3ValueFree(pVal); } /* Modify the CREATE TABLE statement. */ zCol = sqliteStrNDup((char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){ *zEnd-- = '\0'; } sqlite3NestedParse(pParse, "UPDATE %Q.%s SET " "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d,length(sql)) " "WHERE type = 'table' AND name = %Q", zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1, zTab ); sqliteFree(zCol); } /* If the default value of the new column is NULL, then set the file ** format to 2. If the default value of the new column is not NULL, ** the file format becomes 3. */ sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2); /* Reload the schema of the modified table. */ reloadTableSchema(pParse, pTab, pTab->zName); }
/* ** 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 */ sqlite3 *db = pParse->db; /* Database connection */ int nTabName; /* Number of UTF-8 characters in zTabName */ const char *zTabName; /* Original name of the table */ Vdbe *v; #ifndef SQLITE_OMIT_TRIGGER char *zWhere = 0; /* Where clause to locate temp triggers */ #endif int isVirtualRename = 0; /* True if this is a v-table with an xRename() */ if( sqlite3MallocFailed() ) goto exit_rename_table; assert( pSrc->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); 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 #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto exit_rename_table; } if( IsVirtual(pTab) && pTab->pMod->pModule->xRename ){ isVirtualRename = 1; } #endif /* Begin a transaction and code the VerifyCookie for database iDb. ** Then modify the schema cookie (since the ALTER TABLE modifies the ** schema). Open a statement transaction if the table is a virtual ** table. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } sqlite3BeginWriteOperation(pParse, isVirtualRename, iDb); sqlite3ChangeCookie(db, v, iDb); /* If this is a virtual table, invoke the xRename() function if ** one is defined. The xRename() callback will modify the names ** of any resources used by the v-table implementation (including other ** SQLite tables) that are identified by the name of the virtual table. */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( isVirtualRename ){ sqlite3VdbeOp3(v, OP_String8, 0, 0, zName, 0); sqlite3VdbeOp3(v, OP_VRename, 0, 0, (const char*)pTab->pVtab, P3_VTAB); } #endif /* figure out how many UTF-8 characters are in zName */ zTabName = pTab->zName; nTabName = sqlite3Utf8CharLen(zTabName, -1); /* 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, nTabName, zTabName ); #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( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ sqlite3NestedParse(pParse, "UPDATE sqlite_temp_master SET " "sql = sqlite_rename_trigger(sql, %Q), " "tbl_name = %Q " "WHERE %s;", zName, zName, zWhere); sqliteFree(zWhere); } #endif /* Drop and reload the internal table schema. */ reloadTableSchema(pParse, pTab, zName); exit_rename_table: sqlite3SrcListDelete(pSrc); sqliteFree(zName); }
/* ** This function is called after an "ALTER TABLE ... ADD" statement ** has been parsed. Argument pColDef contains the text of the new ** column definition. ** ** The Table structure pParse->pNewTable was extended to include ** the new column during parsing. */ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ Table *pNew; /* Copy of pParse->pNewTable */ Table *pTab; /* Table being altered */ int iDb; /* Database number */ const char *zDb; /* Database name */ const char *zTab; /* Table name */ char *zCol; /* Null-terminated column definition */ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ sqlite3 *db; /* The database connection; */ Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ db = pParse->db; if( pParse->nErr || db->mallocFailed ) return; assert( v!=0 ); pNew = pParse->pNewTable; assert( pNew ); assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pNew->pSchema); zDb = db->aDb[iDb].zName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ pCol = &pNew->aCol[pNew->nCol-1]; pDflt = pCol->pDflt; pTab = sqlite3FindTable(db, zTab, zDb); assert( pTab ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ return; } #endif /* If the default value for the new column was specified with a ** literal NULL, then set pDflt to 0. This simplifies checking ** for an SQL NULL default below. */ if( pDflt && pDflt->op==TK_NULL ){ pDflt = 0; } /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. ** If there is a NOT NULL constraint, then the default value for the ** column must not be NULL. */ if( pCol->colFlags & COLFLAG_PRIMKEY ){ sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column"); return; } if( pNew->pIndex ){ sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); return; } if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){ sqlite3ErrorMsg(pParse, "Cannot add a REFERENCES column with non-NULL default value"); return; } if( pCol->notNull && !pDflt ){ sqlite3ErrorMsg(pParse, "Cannot add a NOT NULL column with default value NULL"); return; } /* Ensure the default expression is something that sqlite3ValueFromExpr() ** can handle (i.e. not CURRENT_TIME etc.) */ if( pDflt ){ sqlite3_value *pVal = 0; int rc; rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); if( rc!=SQLITE_OK ){ assert( db->mallocFailed == 1 ); return; } if( !pVal ){ sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default"); return; } sqlite3ValueFree(pVal); } /* Modify the CREATE TABLE statement. */ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; int savedDbFlags = db->flags; while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){ *zEnd-- = '\0'; } db->flags |= SQLITE_PreferBuiltin; sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) " "WHERE type = 'table' AND name = %Q", zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1, zTab ); sqlite3DbFree(db, zCol); db->flags = savedDbFlags; } /* If the default value of the new column is NULL, then the file ** format to 2. If the default value of the new column is not NULL, ** the file format be 3. Back when this feature was first added ** in 2006, we went to the trouble to upgrade the file format to the ** minimum support values. But 10-years on, we can assume that all ** extent versions of SQLite support file-format 4, so we always and ** unconditionally upgrade to 4. */ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, SQLITE_MAX_FILE_FORMAT); /* Reload the schema of the modified table. */ reloadTableSchema(pParse, pTab, pTab->zName); }
/* ** 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 */ sqlite3 *db = pParse->db; /* Database connection */ int nTabName; /* Number of UTF-8 characters in zTabName */ const char *zTabName; /* Original name of the table */ Vdbe *v; #ifndef SQLITE_OMIT_TRIGGER char *zWhere = 0; /* Where clause to locate temp triggers */ #endif VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */ int savedDbFlags; /* Saved value of db->flags */ savedDbFlags = db->flags; if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); zDb = db->aDb[iDb].zName; db->flags |= SQLITE_PreferBuiltin; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(db, 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( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){ goto exit_rename_table; } if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_rename_table; } #ifndef SQLITE_OMIT_VIEW if( pTab->pSelect ){ sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName); goto exit_rename_table; } #endif #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ goto exit_rename_table; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto exit_rename_table; } if( IsVirtual(pTab) ){ pVTab = sqlite3GetVTable(db, pTab); if( pVTab->pVtab->pModule->xRename==0 ){ pVTab = 0; } } #endif /* Begin a transaction for database iDb. ** Then modify the schema cookie (since the ALTER TABLE modifies the ** schema). Open a statement transaction if the table is a virtual ** table. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } sqlite3BeginWriteOperation(pParse, pVTab!=0, iDb); sqlite3ChangeCookie(pParse, iDb); /* If this is a virtual table, invoke the xRename() function if ** one is defined. The xRename() callback will modify the names ** of any resources used by the v-table implementation (including other ** SQLite tables) that are identified by the name of the virtual table. */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( pVTab ){ int i = ++pParse->nMem; sqlite3VdbeLoadString(v, i, zName); sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); sqlite3MayAbort(pParse); } #endif /* figure out how many UTF-8 characters are in zName */ zTabName = pTab->zName; nTabName = sqlite3Utf8CharLen(zTabName, -1); #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) if( db->flags&SQLITE_ForeignKeys ){ /* If foreign-key support is enabled, rewrite the CREATE TABLE ** statements corresponding to all child tables of foreign key constraints ** for which the renamed table is the parent table. */ if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){ sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = sqlite_rename_parent(sql, %Q, %Q) " "WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere); sqlite3DbFree(db, zWhere); } } #endif /* 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) " "ELSE name END " "WHERE tbl_name=%Q COLLATE nocase AND " "(type='table' OR type='index' OR type='trigger');", zDb, SCHEMA_TABLE(iDb), zName, zName, zName, #ifndef SQLITE_OMIT_TRIGGER zName, #endif zName, nTabName, zTabName ); #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 \"%w\".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( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ sqlite3NestedParse(pParse, "UPDATE sqlite_temp_master SET " "sql = sqlite_rename_trigger(sql, %Q), " "tbl_name = %Q " "WHERE %s;", zName, zName, zWhere); sqlite3DbFree(db, zWhere); } #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) if( db->flags&SQLITE_ForeignKeys ){ FKey *p; for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Table *pFrom = p->pFrom; if( pFrom!=pTab ){ reloadTableSchema(pParse, p->pFrom, pFrom->zName); } } } #endif /* Drop and reload the internal table schema. */ reloadTableSchema(pParse, pTab, zName); exit_rename_table: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zName); db->flags = savedDbFlags; }
/* ** The parser calls this routine after the CREATE VIRTUAL TABLE statement ** has been completely parsed. */ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ Table *pTab; /* The table being constructed */ sqlite3 *db; /* The database connection */ char *zModule; /* The module name of the table: USING modulename */ Module *pMod = 0; addArgumentToVtab(pParse); pParse->sArg.z = 0; /* Lookup the module name. */ pTab = pParse->pNewTable; if( pTab==0 ) return; db = pParse->db; if( pTab->nModuleArg<1 ) return; zModule = pTab->azModuleArg[0]; pMod = (Module *)sqlite3HashFind(&db->aModule, zModule, strlen(zModule)); pTab->pMod = pMod; /* If the CREATE VIRTUAL TABLE statement is being entered for the ** first time (in other words if the virtual table is actually being ** created now instead of just being read out of sqlite_master) then ** do additional initialization work and store the statement text ** in the sqlite_master table. */ if( !db->init.busy ){ char *zStmt; char *zWhere; int iDb; Vdbe *v; /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ if( pEnd ){ pParse->sNameToken.n = pEnd->z - pParse->sNameToken.z + pEnd->n; } zStmt = sqlite3MPrintf("CREATE VIRTUAL TABLE %T", &pParse->sNameToken); /* A slot for the record has already been allocated in the ** SQLITE_MASTER table. We just need to update that slot with all ** the information we've collected. ** ** The top of the stack is the rootpage allocated by sqlite3StartTable(). ** This value is always 0 and is ignored, a virtual table does not have a ** rootpage. The next entry on the stack is the rowid of the record ** in the sqlite_master table. */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "WHERE rowid=#1", db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTab->zName, pTab->zName, zStmt ); sqliteFree(zStmt); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(db, v, iDb); sqlite3VdbeAddOp(v, OP_Expire, 0, 0); zWhere = sqlite3MPrintf("name='%q'", pTab->zName); sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 1, zWhere, P3_DYNAMIC); sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1); } /* If we are rereading the sqlite_master table create the in-memory ** record of the table. If the module has already been registered, ** also call the xConnect method here. */ else { Table *pOld; Schema *pSchema = pTab->pSchema; const char *zName = pTab->zName; int nName = strlen(zName) + 1; pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); if( pOld ){ assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ return; } pSchema->db = pParse->db; pParse->pNewTable = 0; } }
/* ** This routine is called after all of the trigger actions have been parsed ** in order to complete the process of building the trigger. */ SQLITE_PRIVATE void sqlite3FinishTrigger( Parse *pParse, /* Parser context */ TriggerStep *pStepList, /* The triggered program */ Token *pAll /* Token that describes the complete CREATE TRIGGER */ ){ Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */ char *zName; /* Name of trigger */ sqlite3 *db = pParse->db; /* The database */ DbFixer sFix; /* Fixer object */ int iDb; /* Database containing the trigger */ Token nameToken; /* Trigger name for error reporting */ pParse->pNewTrigger = 0; if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; zName = pTrig->zName; iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); pTrig->step_list = pStepList; while( pStepList ){ pStepList->pTrig = pTrig; pStepList = pStepList->pNext; } nameToken.z = pTrig->zName; nameToken.n = sqlite3Strlen30(nameToken.z); sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken); if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) || sqlite3FixExpr(&sFix, pTrig->pWhen) ){ goto triggerfinish_cleanup; } /* if we are not initializing, ** build the sqlite_master entry */ if( !db->init.busy ){ Vdbe *v; char *z; /* Make an entry in the sqlite_master table */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName)); } if( db->init.busy ){ Trigger *pLink = pTrig; Hash *pHash = &db->aDb[iDb].pSchema->trigHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pTrig = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), pTrig); if( pTrig ){ db->mallocFailed = 1; }else if( pLink->pSchema==pLink->pTabSchema ){ Table *pTab; int n = sqlite3Strlen30(pLink->table); pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table, n); assert( pTab!=0 ); pLink->pNext = pTab->pTrigger; pTab->pTrigger = pLink; } } triggerfinish_cleanup: sqlite3DeleteTrigger(db, pTrig); assert( !pParse->pNewTrigger ); sqlite3DeleteTriggerStep(db, pStepList); }
/* ** 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 */ sqlite3 *db = pParse->db; /* Database connection */ Vdbe *v; #ifndef SQLITE_OMIT_TRIGGER char *zWhere = 0; /* Where clause to locate temp triggers */ #endif if( sqlite3_malloc_failed ) goto exit_rename_table; 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( (zWhere=whereTempTriggers(pParse, pTab)) ){ sqlite3NestedParse(pParse, "UPDATE sqlite_temp_master SET " "sql = sqlite_rename_trigger(sql, %Q), " "tbl_name = %Q " "WHERE %s;", zName, zName, zWhere); sqliteFree(zWhere); } #endif /* Drop and reload the internal table schema. */ reloadTableSchema(pParse, pTab, zName); exit_rename_table: sqlite3SrcListDelete(pSrc); sqliteFree(zName); }
/* ** This routine generates code that opens the sqlite_stat1 table for ** writing with cursor iStatCur. If the library was built with the ** SQLITE_ENABLE_STAT2 macro defined, then the sqlite_stat2 table is ** opened for writing using cursor (iStatCur+1) ** ** If the sqlite_stat1 tables does not previously exist, it is created. ** Similarly, if the sqlite_stat2 table does not exist and the library ** is compiled with SQLITE_ENABLE_STAT2 defined, it is created. ** ** Argument zWhere may be a pointer to a buffer containing a table name, ** or it may be a NULL pointer. If it is not NULL, then all entries in ** the sqlite_stat1 and (if applicable) sqlite_stat2 tables associated ** with the named table are deleted. If zWhere==0, then code is generated ** to delete all stat table entries. */ static void openStatTable( Parse *pParse, /* Parsing context */ int iDb, /* The database we are looking in */ int iStatCur, /* Open the sqlite_stat1 table on this cursor */ const char *zWhere, /* Delete entries for this table or index */ const char *zWhereType /* Either "tbl" or "idx" */ ){ static const struct { const char *zName; const char *zCols; } aTable[] = { { "sqlite_stat1", "tbl,idx,stat" }, #ifdef SQLITE_ENABLE_STAT2 { "sqlite_stat2", "tbl,idx,sampleno,sample" }, #endif }; int aRoot[] = {0, 0}; u8 aCreateTbl[] = {0, 0}; int i; sqlite3 *db = pParse->db; Db *pDb; Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3VdbeDb(v)==db ); pDb = &db->aDb[iDb]; for(i=0; i<ArraySize(aTable); i++){ const char *zTab = aTable[i].zName; Table *pStat; if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){ /* The sqlite_stat[12] table does not exist. Create it. Note that a ** side-effect of the CREATE TABLE statement is to leave the rootpage ** of the new table in register pParse->regRoot. This is important ** because the OpenWrite opcode below will be needing it. */ sqlite3NestedParse(pParse, "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols ); aRoot[i] = pParse->regRoot; aCreateTbl[i] = 1; }else{ /* The table already exists. If zWhere is not NULL, delete all entries ** associated with the table zWhere. If zWhere is NULL, delete the ** entire contents of the table. */ aRoot[i] = pStat->tnum; sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); if( zWhere ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE %s=%Q", pDb->zName, zTab, zWhereType, zWhere ); }else{ /* The sqlite_stat[12] table already exists. Delete all rows. */ sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb); } } } /* Open the sqlite_stat[12] tables for writing. */ for(i=0; i<ArraySize(aTable); i++){ sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb); sqlite3VdbeChangeP4(v, -1, (char *)3, P4_INT32); sqlite3VdbeChangeP5(v, aCreateTbl[i]); } }
/* ** This routine is called after all of the trigger actions have been parsed ** in order to complete the process of building the trigger. */ void sqlite3FinishTrigger( Parse *pParse, /* Parser context */ TriggerStep *pStepList, /* The triggered program */ Token *pAll /* Token that describes the complete CREATE TRIGGER */ ){ Trigger *pTrig = 0; /* The trigger whose construction is finishing up */ sqlite3 *db = pParse->db; /* The database */ DbFixer sFix; int iDb; /* Database containing the trigger */ pTrig = pParse->pNewTrigger; pParse->pNewTrigger = 0; if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup; iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); pTrig->step_list = pStepList; while( pStepList ){ pStepList->pTrig = pTrig; pStepList = pStepList->pNext; } if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &pTrig->nameToken) && sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){ goto triggerfinish_cleanup; } /* if we are not initializing, and this trigger is not on a TEMP table, ** build the sqlite_master entry */ if( !db->init.busy ){ Vdbe *v; char *z; /* Make an entry in the sqlite_master table */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrig->name, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf( db, "type='trigger' AND name='%q'", pTrig->name), P4_DYNAMIC ); } if( db->init.busy ){ int n; Table *pTab; Trigger *pDel; pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash, pTrig->name, sqlite3Strlen30(pTrig->name), pTrig); if( pDel ){ assert( pDel==pTrig ); db->mallocFailed = 1; goto triggerfinish_cleanup; } n = sqlite3Strlen30(pTrig->table) + 1; pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n); assert( pTab!=0 ); pTrig->pNext = pTab->pTrigger; pTab->pTrigger = pTrig; pTrig = 0; } triggerfinish_cleanup: sqlite3DeleteTrigger(db, pTrig); assert( !pParse->pNewTrigger ); sqlite3DeleteTriggerStep(db, pStepList); }
/* ** This function is called after an "ALTER TABLE ... ADD" statement ** has been parsed. Argument pColDef contains the text of the new ** column definition. ** ** The Table structure pParse->pNewTable was extended to include ** the new column during parsing. 在“ALTER TABLE…添加“声明解析后这个函数被调用。 参数pColDef包含新列定义的文本。 表结构pParse - > pNewTable扩大到包括在解析新列。 */ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ Table *pNew; /* Copy of pParse->pNewTable pParse->pNew表的副本*/ Table *pTab; /* Table being altered 被修改的表*/ int iDb; /* Database number 数据库数*/ const char *zDb; /* Database name 数据库名*/ const char *zTab; /* Table name 表名*/ char *zCol; /* Null-terminated column definition 空值终止列定义*/ Column *pCol; /* The new column 新列*/ Expr *pDflt; /* Default value for the new column 为新列默认数值*/ sqlite3 *db; /* The database connection; 数据库的连接*/ db = pParse->db; if( pParse->nErr || db->mallocFailed ) return; pNew = pParse->pNewTable; assert( pNew ); assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pNew->pSchema); zDb = db->aDb[iDb].zName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name 跳过“sqlite_altertab_”前缀的名称*/ pCol = &pNew->aCol[pNew->nCol-1]; pDflt = pCol->pDflt; pTab = sqlite3FindTable(db, zTab, zDb); assert( pTab ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. 调用授权回调*/ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ return; } #endif /* If the default value for the new column was specified with a ** literal NULL, then set pDflt to 0. This simplifies checking ** for an SQL NULL default below. 如果新列的默认值是用文字指定NULL,那么pDflt设置为0。 这简化了检查SQL空下面的默认。 */ if( pDflt && pDflt->op==TK_NULL ){ pDflt = 0; } /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. ** If there is a NOT NULL constraint, then the default value for the ** column must not be NULL. 检查新列没有指定主键或唯一的。 如果有一个非空约束,然后列的默认值不能为空。 */ if( pCol->isPrimKey ){ sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column"); return; } if( pNew->pIndex ){ sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); return; } if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){ sqlite3ErrorMsg(pParse, "Cannot add a REFERENCES column with non-NULL default value"); return; } if( pCol->notNull && !pDflt ){ sqlite3ErrorMsg(pParse, "Cannot add a NOT NULL column with default value NULL"); return; } /* Ensure the default expression is something that sqlite3ValueFromExpr() ** can handle (i.e. not CURRENT_TIME etc.) 确保默认表达式是sqlite3ValueFromExpr()可以处理的事(即不是当前时间等。) */ if( pDflt ){ sqlite3_value *pVal; if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){ db->mallocFailed = 1; return; } if( !pVal ){ sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default"); return; } sqlite3ValueFree(pVal); } /* Modify the CREATE TABLE statement. 修改CREATE TABLE语句。*/ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; int savedDbFlags = db->flags; while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){ *zEnd-- = '\0'; } db->flags |= SQLITE_PreferBuiltin; sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) " "WHERE type = 'table' AND name = %Q", zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1, zTab ); sqlite3DbFree(db, zCol); db->flags = savedDbFlags; } /* If the default value of the new column is NULL, then set the file ** format to 2. If the default value of the new column is not NULL, ** the file format becomes 3. 如果新列的默认值为空,那么将文件格式设置为2。如果新列的默认值不为空,文件格式变成3。 */ sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2); /* Reload the schema of the modified table. 重新加载修改后的表的模式。*/ reloadTableSchema(pParse, pTab, pTab->zName); }
/* ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" ** command. 生成代码来实现“ALTER TABLE xxx重命名yyy”命令。 */ 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 数据库iDb 的名称*/ Table *pTab; /* Table being renamed 正在重命名的表*/ char *zName = 0; /* NULL-terminated version of pName pName的空值终止版本*/ sqlite3 *db = pParse->db; /* Database connection 数据库的连接*/ int nTabName; /* Number of UTF-8 characters in zTabName 在 zTabName里的UTF-8类型的数目*/ const char *zTabName; /* Original name of the table 最初的数据库名称*/ Vdbe *v; #ifndef SQLITE_OMIT_TRIGGER char *zWhere = 0; /* Where clause to locate temp triggers Where 子句位于temp触发器*/ #endif VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() 如果是 一个v-tab 和一个xRename() ,则为零*/ int savedDbFlags; /* Saved value of db->flags db->flags的保留值*/ savedDbFlags = db->flags; if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); zDb = db->aDb[iDb].zName; db->flags |= SQLITE_PreferBuiltin; /* Get a NULL terminated version of the new table name. 得到一个空终止版本的新表的名称。*/ zName = sqlite3NameFromToken(db, 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.检查一个表或索引名叫“zName”不存在数据库iDb。 如果是这样,这是一个错误。 */ 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( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){ goto exit_rename_table; } if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_rename_table; } #ifndef SQLITE_OMIT_VIEW if( pTab->pSelect ){ sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName); goto exit_rename_table; } #endif #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. 调用授权回调。*/ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ goto exit_rename_table; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto exit_rename_table; } if( IsVirtual(pTab) ){ pVTab = sqlite3GetVTable(db, pTab); if( pVTab->pVtab->pModule->xRename==0 ){ pVTab = 0; } } #endif /* Begin a transaction and code the VerifyCookie for database iDb. ** Then modify the schema cookie (since the ALTER TABLE modifies the ** schema). Open a statement transaction if the table is a virtual ** table. 对于iDb数据库开始一个事务和代码的VerifyCookie。 然后修改模式cookie(因为ALTER TABLE修改模式)。 如果表是一个虚拟表打开一个声明事务。 */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } sqlite3BeginWriteOperation(pParse, pVTab!=0, iDb); sqlite3ChangeCookie(pParse, iDb); /* If this is a virtual table, invoke the xRename() function if ** one is defined. The xRename() callback will modify the names ** of any resources used by the v-table implementation (including other ** SQLite tables) that are identified by the name of the virtual table.、 如果这是一个虚拟表,调用xRename()函数如果一个定义。 xRename()回调将修改使用v-table实现的任何资源的名字(包括其他SQLite表), 这个v-table实现是确定的虚拟表的名称。 */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( pVTab ){ int i = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0); sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); sqlite3MayAbort(pParse); } #endif /* figure out how many UTF-8 characters are in zName 算出在zName里有多少utf - 8字符*/ zTabName = pTab->zName; nTabName = sqlite3Utf8CharLen(zTabName, -1); #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) if( db->flags&SQLITE_ForeignKeys ){ /* If foreign-key support is enabled, rewrite the CREATE TABLE ** statements corresponding to all child tables of foreign key constraints ** for which the renamed table is the parent table. 如果启用了外键的支持,重写CREATE TABLE语句对应的所有子表的外键约束重命名表的父表。*/ if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){ sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = sqlite_rename_parent(sql, %Q, %Q) " "WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere); sqlite3DbFree(db, zWhere); } } #endif /* Modify the sqlite_master table to use the new table name. 修改sqlite_master表来使用新的表名。*/ 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) " "ELSE name END " "WHERE tbl_name=%Q COLLATE nocase AND " "(type='table' OR type='index' OR type='trigger');", zDb, SCHEMA_TABLE(iDb), zName, zName, zName, #ifndef SQLITE_OMIT_TRIGGER zName, #endif zName, nTabName, zTabName ); #ifndef SQLITE_OMIT_AUTOINCREMENT /* If the sqlite_sequence table exists in this database, then update ** it with the new table name. 如果sqlite_sequence表存在于这个数据库中,那么用新表的名称更新它 */ if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ sqlite3NestedParse(pParse, "UPDATE \"%w\".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. 如果在这个表上有临时触发器,修改sqlite_temp_master表, 如果表被修改本身就是位于临时数据库,不要做这些。 */ if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ sqlite3NestedParse(pParse, "UPDATE sqlite_temp_master SET " "sql = sqlite_rename_trigger(sql, %Q), " "tbl_name = %Q " "WHERE %s;", zName, zName, zWhere); sqlite3DbFree(db, zWhere); } #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) if( db->flags&SQLITE_ForeignKeys ){ FKey *p; for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Table *pFrom = p->pFrom; if( pFrom!=pTab ){ reloadTableSchema(pParse, p->pFrom, pFrom->zName); } } } #endif /* Drop and reload the internal table schema. 删除和重新加载内部表模式。*/ reloadTableSchema(pParse, pTab, zName); exit_rename_table: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zName); db->flags = savedDbFlags; }