📄 build.c
字号:
** location iTable. The following code modifies the sqlite_master table to ** reflect this. ** ** The "#0" in the SQL is a special constant that means whatever value ** is on the top of the stack. See sqlite3RegisterExpr(). */ sqlite3NestedParse(pParse, "UPDATE %Q.%s SET rootpage=%d WHERE #0 AND rootpage=#0", pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable);#endif}/*** Write VDBE code to erase table pTab and all associated indices on disk.** Code to update the sqlite_master tables and internal schema definitions** in case a root-page belonging to another table is moved by the btree layer** is also added (this can happen with an auto-vacuum database).*/static void destroyTable(Parse *pParse, Table *pTab){#ifdef SQLITE_OMIT_AUTOVACUUM Index *pIdx; destroyRootPage(pParse, pTab->tnum, pTab->iDb); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ destroyRootPage(pParse, pIdx->tnum, pIdx->iDb); }#else /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM ** is not defined), then it is important to call OP_Destroy on the ** table and index root-pages in order, starting with the numerically ** largest root-page number. This guarantees that none of the root-pages ** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the ** following were coded: ** ** OP_Destroy 4 0 ** ... ** OP_Destroy 5 0 ** ** and root page 5 happened to be the largest root-page number in the ** database, then root page 5 would be moved to page 4 by the ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit ** a free-list page. */ int iTab = pTab->tnum; int iDestroyed = 0; while( 1 ){ Index *pIdx; int iLargest = 0; if( iDestroyed==0 || iTab<iDestroyed ){ iLargest = iTab; } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int iIdx = pIdx->tnum; assert( pIdx->iDb==pTab->iDb ); if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){ iLargest = iIdx; } } if( iLargest==0 ) return; destroyRootPage(pParse, iLargest, pTab->iDb); iDestroyed = iLargest; }#endif}/*** This routine is called to do the work of a DROP TABLE statement.** pName is the name of the table to be dropped.*/void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ Table *pTab; Vdbe *v; sqlite3 *db = pParse->db; int iDb; if( pParse->nErr || sqlite3_malloc_failed ) goto exit_drop_table; assert( pName->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase); if( pTab==0 ) goto exit_drop_table; iDb = pTab->iDb; assert( iDb>=0 && iDb<db->nDb );#ifndef SQLITE_OMIT_AUTHORIZATION { int code; const char *zTab = SCHEMA_TABLE(pTab->iDb); const char *zDb = db->aDb[pTab->iDb].zName; if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ goto exit_drop_table; } if( isView ){ if( !OMIT_TEMPDB && iDb==1 ){ code = SQLITE_DROP_TEMP_VIEW; }else{ code = SQLITE_DROP_VIEW; } }else{ if( !OMIT_TEMPDB && iDb==1 ){ code = SQLITE_DROP_TEMP_TABLE; }else{ code = SQLITE_DROP_TABLE; } } if( sqlite3AuthCheck(pParse, code, pTab->zName, 0, zDb) ){ goto exit_drop_table; } if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto exit_drop_table; } }#endif if( pTab->readOnly || pTab==db->aDb[iDb].pSeqTab ){ sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); goto exit_drop_table; }#ifndef SQLITE_OMIT_VIEW /* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used ** on a table. */ if( isView && pTab->pSelect==0 ){ sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName); goto exit_drop_table; } if( !isView && pTab->pSelect ){ sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName); goto exit_drop_table; }#endif /* Generate code to remove the table from the master table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ Trigger *pTrigger; int iDb = pTab->iDb; Db *pDb = &db->aDb[iDb]; sqlite3BeginWriteOperation(pParse, 0, iDb); /* Drop all triggers associated with the table being dropped. Code ** is generated to remove entries from sqlite_master and/or ** sqlite_temp_master if required. */ pTrigger = pTab->pTrigger; while( pTrigger ){ assert( pTrigger->iDb==iDb || pTrigger->iDb==1 ); sqlite3DropTriggerPtr(pParse, pTrigger, 1); pTrigger = pTrigger->pNext; }#ifndef SQLITE_OMIT_AUTOINCREMENT /* Remove any entries of the sqlite_sequence table associated with ** the table being dropped. This is done before the table is dropped ** at the btree level, in case the sqlite_sequence table needs to ** move as a result of the drop (can happen in auto-vacuum mode). */ if( pTab->autoInc ){ sqlite3NestedParse(pParse, "DELETE FROM %s.sqlite_sequence WHERE name=%Q", pDb->zName, pTab->zName ); }#endif /* Drop all SQLITE_MASTER table and index entries that refer to the ** table. The program name loops through the master table and deletes ** every row that refers to a table of the same name as the one being ** dropped. Triggers are handled seperately because a trigger can be ** created in the temp database that refers to a table in another ** database. */ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", pDb->zName, SCHEMA_TABLE(iDb), pTab->zName); if( !isView ){ destroyTable(pParse, pTab); } /* Remove the table entry from SQLite's internal schema and modify ** the schema cookie. */ sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); sqlite3ChangeCookie(db, v, iDb); } sqliteViewResetAll(db, iDb);exit_drop_table: sqlite3SrcListDelete(pName);}/*** This routine is called to create a new foreign key on the table** currently under construction. pFromCol determines which columns** in the current table point to the foreign key. If pFromCol==0 then** connect the key to the last column inserted. pTo is the name of** the table referred to. pToCol is a list of tables in the other** pTo table that the foreign key points to. flags contains all** information about the conflict resolution algorithms specified** in the ON DELETE, ON UPDATE and ON INSERT clauses.**** An FKey structure is created and added to the table currently** under construction in the pParse->pNewTable field. The new FKey** is not linked into db->aFKey at this point - that does not happen** until sqlite3EndTable().**** The foreign key is set for IMMEDIATE processing. A subsequent call** to sqlite3DeferForeignKey() might change this to DEFERRED.*/void sqlite3CreateForeignKey( Parse *pParse, /* Parsing context */ ExprList *pFromCol, /* Columns in this table that point to other table */ Token *pTo, /* Name of the other table */ ExprList *pToCol, /* Columns in the other table */ int flags /* Conflict resolution algorithms. */){#ifndef SQLITE_OMIT_FOREIGN_KEY FKey *pFKey = 0; Table *p = pParse->pNewTable; int nByte; int i; int nCol; char *z; assert( pTo!=0 ); if( p==0 || pParse->nErr ) goto fk_end; if( pFromCol==0 ){ int iCol = p->nCol-1; if( iCol<0 ) goto fk_end; if( pToCol && pToCol->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "foreign key on %s" " should reference only one column of table %T", p->aCol[iCol].zName, pTo); goto fk_end; } nCol = 1; }else if( pToCol && pToCol->nExpr!=pFromCol->nExpr ){ sqlite3ErrorMsg(pParse, "number of columns in foreign key does not match the number of " "columns in the referenced table"); goto fk_end; }else{ nCol = pFromCol->nExpr; } nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1; if( pToCol ){ for(i=0; i<pToCol->nExpr; i++){ nByte += strlen(pToCol->a[i].zName) + 1; } } pFKey = sqliteMalloc( nByte ); if( pFKey==0 ) goto fk_end; pFKey->pFrom = p; pFKey->pNextFrom = p->pFKey; z = (char*)&pFKey[1]; pFKey->aCol = (struct sColMap*)z; z += sizeof(struct sColMap)*nCol; pFKey->zTo = z; memcpy(z, pTo->z, pTo->n); z[pTo->n] = 0; z += pTo->n+1; pFKey->pNextTo = 0; pFKey->nCol = nCol; if( pFromCol==0 ){ pFKey->aCol[0].iFrom = p->nCol-1; }else{ for(i=0; i<nCol; i++){ int j; for(j=0; j<p->nCol; j++){ if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){ pFKey->aCol[i].iFrom = j; break; } } if( j>=p->nCol ){ sqlite3ErrorMsg(pParse, "unknown column \"%s\" in foreign key definition", pFromCol->a[i].zName); goto fk_end; } } } if( pToCol ){ for(i=0; i<nCol; i++){ int n = strlen(pToCol->a[i].zName); pFKey->aCol[i].zCol = z; memcpy(z, pToCol->a[i].zName, n); z[n] = 0; z += n+1; } } pFKey->isDeferred = 0; pFKey->deleteConf = flags & 0xff; pFKey->updateConf = (flags >> 8 ) & 0xff; pFKey->insertConf = (flags >> 16 ) & 0xff; /* Link the foreign key to the table as the last step. */ p->pFKey = pFKey; pFKey = 0;fk_end: sqliteFree(pFKey);#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ sqlite3ExprListDelete(pFromCol); sqlite3ExprListDelete(pToCol);}/*** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED** clause is seen as part of a foreign key definition. The isDeferred** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE.** The behavior of the most recently created foreign key is adjusted** accordingly.*/void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){#ifndef SQLITE_OMIT_FOREIGN_KEY Table *pTab; FKey *pFKey; if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return; pFKey->isDeferred = isDeferred;#endif}/*** Generate code that will erase and refill index *pIdx. This is** used to initialize a newly created index or to recompute the** content of an index in response to a REINDEX command.**** if memRootPage is not negative, it means that the index is newly** created. The memory cell specified by memRootPage contains the** root page number of the index. If memRootPage is negative, then** the index already exists and must be cleared before being refilled and** the root page number of the index is taken from pIndex->tnum.*/static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ Table *pTab = pIndex->pTable; /* The table that is indexed */ int iTab = pParse->nTab; /* Btree cursor used for pTab */ int iIdx = pParse->nTab+1; /* Btree cursor used for pIndex */ int addr1; /* Address of top of loop */ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ int isUnique; /* True for a unique index */#ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, pParse->db->aDb[pIndex->iDb].zName ) ){ return; }#endif /* Ensure all the required collation sequences are available. This ** routine will invoke the collation-needed callback if necessary (and ** if one has been registered). */ if( sqlite3CheckIndexCollSeq(pParse, pIndex) ){ return; } v = sqlite3GetVdbe(pParse); if( v==0 ) return; if( memRootPage>=0 ){ sqlite3VdbeAddOp(v, OP_MemLoad, memRootPage, 0); tnum = 0; }else{ tnum = pIndex->tnum; sqlite3VdbeAddOp(v, OP_Clear, tnum, pIndex->iDb); } sqlite3VdbeAddOp(v, OP_Integer, pIndex->iDb, 0); sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, (char*)&pIndex->keyInfo, P3_KEYINFO); sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqlite3VdbeAddOp(v, OP_OpenRead, iTab, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, iTab, pTab->nCol); addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0); sqlite3GenerateIndexKey(v, pIndex, iTab); isUnique = pIndex->onError!=OE_None; sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, isUnique); if( isUnique ){ sqlite3VdbeChangeP3(v, -1, "indexed columns are not unique", P3_STATIC); } sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1); sqlite3VdbeChangeP2(v, addr1, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp(v, OP_Close, iTab, 0); sqlite3VdbeAddOp(v, OP_Close, iIdx, 0);}/*** Create a new index for an SQL table. pName1.pName2 is the name of the index ** and pTblList is the name of the table that is to be indexed. Both will ** be NULL for a primary key or an index that is created to satisfy a** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable** as the table to be indexed. pParse->pNewTable is a table that is** currently being constructed by a CREATE TABLE statement.**** pList is a list of columns to be indexed. pList will be NULL if this** is a primary key or unique-constraint on the most recent column added** to the table currently under construction. */void sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ Token *pName1, /* First part of index name. May be NULL */ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -