📄 build.c
字号:
z = (const unsigned char*)pBegin->z; while( n>0 && (z[n-1]==';' || isspace(z[n-1])) ){ n--; } sEnd.z = &z[n-1]; sEnd.n = 1; /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ sqlite3EndTable(pParse, 0, &sEnd, 0); return;}#endif /* SQLITE_OMIT_VIEW */#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)/*** The Table structure pTable is really a VIEW. Fill in the names of** the columns of the view in the pTable structure. Return the number** of errors. If an error is seen leave an error message in pParse->zErrMsg.*/int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ Table *pSelTab; /* A fake table from which we get the result set */ Select *pSel; /* Copy of the SELECT that implements the view */ int nErr = 0; /* Number of errors encountered */ int n; /* Temporarily holds the number of cursors assigned */ assert( pTable );#ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3VtabCallConnect(pParse, pTable) ){ return SQLITE_ERROR; } if( IsVirtual(pTable) ) return 0;#endif#ifndef SQLITE_OMIT_VIEW /* 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; } assert( pTable->nCol>=0 ); /* 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); if( pSel ){ 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(pSelTab); pTable->pSchema->flags |= DB_UnresetViews; }else{ pTable->nCol = 0; nErr++; } sqlite3SelectDelete(pSel); } else { nErr++; }#endif /* SQLITE_OMIT_VIEW */ return nErr; }#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */#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].pSchema->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.**** Ticket #1728: The symbol table might still contain information** on tables and/or indices that are the process of being deleted.** If you are unlucky, one of those deleted indices or tables might** have the same rootpage number as the real table or index that is** being moved. So we cannot stop searching after the first match ** because the first match might be for one of the deleted indices** or tables and not the table/index that is actually being moved.** We must continue looping until all tables and indices with** rootpage==iFrom have been converted to have a rootpage of iTo** in order to be certain that we got the right one.*/#ifndef SQLITE_OMIT_AUTOVACUUMvoid sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){ HashElem *pElem; Hash *pHash; pHash = &pDb->pSchema->tblHash; for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); if( pTab->tnum==iFrom ){ pTab->tnum = iTo; } } pHash = &pDb->pSchema->idxHash; for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ Index *pIdx = sqliteHashData(pElem); if( pIdx->tnum==iFrom ){ pIdx->tnum = iTo; } }}#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; int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); destroyRootPage(pParse, pTab->tnum, iDb); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ destroyRootPage(pParse, pIdx->tnum, 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->pSchema==pTab->pSchema ); if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){ iLargest = iIdx; } } if( iLargest==0 ){ return; }else{ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); destroyRootPage(pParse, iLargest, 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, int noErr){ Table *pTab; Vdbe *v; sqlite3 *db = pParse->db; int iDb; if( pParse->nErr || sqlite3MallocFailed() ){ goto exit_drop_table; } assert( pName->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase); if( pTab==0 ){ if( noErr ){ sqlite3ErrorClear(pParse); } goto exit_drop_table; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 && iDb<db->nDb );#ifndef SQLITE_OMIT_AUTHORIZATION { int code; const char *zTab = SCHEMA_TABLE(iDb); const char *zDb = db->aDb[iDb].zName; const char *zArg2 = 0; 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; }#ifndef SQLITE_OMIT_VIRTUALTABLE }else if( IsVirtual(pTab) ){ if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto exit_drop_table; } code = SQLITE_DROP_VTABLE; zArg2 = pTab->pMod->zName;#endif }else{ if( !OMIT_TEMPDB && iDb==1 ){ code = SQLITE_DROP_TEMP_TABLE; }else{ code = SQLITE_DROP_TABLE; } } if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, 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].pSchema->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; Db *pDb = &db->aDb[iDb]; sqlite3BeginWriteOperation(pParse, 0, iDb);#ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ Vdbe *v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_VBegin, 0, 0); } }#endif /* 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->pSchema==pTab->pSchema || pTrigger->pSchema==db->aDb[1].pSchema ); sqlite3DropTriggerPtr(pParse, pTrigger); 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 && !IsVirtual(pTab) ){ destroyTable(pParse, pTab); } /* Remove the table entry from SQLite's internal schema and modify ** the schema cookie. */ if( IsVirtual(pTab) ){ sqlite3VdbeOp3(v, OP_VDestroy, iDb, 0, pTab->zName, 0); } 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 tabl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -