📄 build.c
字号:
assert( pTable ); /* A positive nCol means the columns names for this view are ** already known. */ if( pTable->nCol>0 ) return 0; /* A negative nCol is a special marker meaning that we are currently ** trying to compute the column names. If we enter this routine with ** a negative nCol, it means two or more views form a loop, like this: ** ** CREATE VIEW one AS SELECT * FROM two; ** CREATE VIEW two AS SELECT * FROM one; ** ** Actually, this error is caught previously and so the following test ** should always fail. But we will leave it in place just to be safe. */ if( pTable->nCol<0 ){ sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName); return 1; } /* If we get this far, it means we need to compute the table names. ** Note that the call to sqlite3ResultSetOfSelect() will expand any ** "*" elements in the results set of the view and will assign cursors ** to the elements of the FROM clause. But we do not want these changes ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ assert( pTable->pSelect ); pSel = sqlite3SelectDup(pTable->pSelect); n = pParse->nTab; sqlite3SrcListAssignCursors(pParse, pSel->pSrc); pTable->nCol = -1; pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel); pParse->nTab = n; if( pSelTab ){ assert( pTable->aCol==0 ); pTable->nCol = pSelTab->nCol; pTable->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; sqlite3DeleteTable(0, pSelTab); DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews); }else{ pTable->nCol = 0; nErr++; } sqlite3SelectDelete(pSel); return nErr; }#endif /* SQLITE_OMIT_VIEW */#ifndef SQLITE_OMIT_VIEW/*** Clear the column names from every VIEW in database idx.*/static void sqliteViewResetAll(sqlite3 *db, int idx){ HashElem *i; if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); if( pTab->pSelect ){ sqliteResetColumnNames(pTab); } } DbClearProperty(db, idx, DB_UnresetViews);}#else# define sqliteViewResetAll(A,B)#endif /* SQLITE_OMIT_VIEW *//*** This function is called by the VDBE to adjust the internal schema** used by SQLite when the btree layer moves a table root page. The** root-page of a table or index in database iDb has changed from iFrom** to iTo.*/#ifndef SQLITE_OMIT_AUTOVACUUMvoid sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){ HashElem *pElem; for(pElem=sqliteHashFirst(&pDb->tblHash); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); if( pTab->tnum==iFrom ){ pTab->tnum = iTo; return; } } for(pElem=sqliteHashFirst(&pDb->idxHash); pElem; pElem=sqliteHashNext(pElem)){ Index *pIdx = sqliteHashData(pElem); if( pIdx->tnum==iFrom ){ pIdx->tnum = iTo; return; } } assert(0);}#endif/*** Write code to erase the table with root-page iTable from database iDb.** Also write code to modify the sqlite_master table and internal schema** if a root-page of another table is moved by the btree-layer whilst** erasing iTable (this can happen with an auto-vacuum database).*/ static void destroyRootPage(Parse *pParse, int iTable, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); sqlite3VdbeAddOp(v, OP_Destroy, iTable, iDb);#ifndef SQLITE_OMIT_AUTOVACUUM /* OP_Destroy pushes an integer onto the stack. If this integer ** is non-zero, then it is the root page number of a table moved to ** 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( iDb==1 ){ code = SQLITE_DROP_TEMP_VIEW; }else{ code = SQLITE_DROP_VIEW; } }else{ if( 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 =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -