📄 build.c
字号:
/*** 2001 September 15**** The author disclaims copyright to this source code. In place of** a legal notice, here is a blessing:**** May you do good and not evil.** May you find forgiveness for yourself and forgive others.** May you share freely, never taking more than you give.***************************************************************************** This file contains C code routines that are called by the SQLite parser** when syntax rules are reduced. The routines in this file handle the** following kinds of SQL syntax:**** CREATE TABLE** DROP TABLE** CREATE INDEX** DROP INDEX** creating ID lists** BEGIN TRANSACTION** COMMIT** ROLLBACK**** $Id: build.c,v 1.326 2005/06/12 21:35:52 drh Exp $*/#include "sqliteInt.h"#include <ctype.h>/*** This routine is called when a new SQL statement is beginning to** be parsed. Initialize the pParse structure as needed.*/void sqlite3BeginParse(Parse *pParse, int explainFlag){ pParse->explain = explainFlag; pParse->nVar = 0;}/*** This routine is called after a single SQL statement has been** parsed and a VDBE program to execute that statement has been** prepared. This routine puts the finishing touches on the** VDBE program and resets the pParse structure for the next** parse.**** Note that if an error occurred, it might be the case that** no VDBE code was generated.*/void sqlite3FinishCoding(Parse *pParse){ sqlite3 *db; Vdbe *v; if( sqlite3_malloc_failed ) return; if( pParse->nested ) return; if( !pParse->pVdbe ){ if( pParse->rc==SQLITE_OK && pParse->nErr ){ pParse->rc = SQLITE_ERROR; } return; } /* Begin by generating some termination code at the end of the ** vdbe program */ db = pParse->db; v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_Halt, 0, 0); /* The cookie mask contains one bit for each database file open. ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are ** set for each database that is used. Generate code to start a ** transaction on each used database and to verify the schema cookie ** on each used database. */ if( pParse->cookieGoto>0 ){ u32 mask; int iDb; sqlite3VdbeChangeP2(v, pParse->cookieGoto-1, sqlite3VdbeCurrentAddr(v)); for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){ if( (mask & pParse->cookieMask)==0 ) continue; sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0); sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]); } sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto); } /* Add a No-op that contains the complete text of the compiled SQL ** statement as its P3 argument. This does not change the functionality ** of the program. ** ** This is used to implement sqlite3_trace(). */ sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql); } /* Get the VDBE program ready for execution */ if( v && pParse->nErr==0 ){ FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; sqlite3VdbeTrace(v, trace); sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3, pParse->nTab+3, pParse->nMaxDepth+1, pParse->explain); pParse->rc = SQLITE_DONE; pParse->colNamesSet = 0; }else if( pParse->rc==SQLITE_OK ){ pParse->rc = SQLITE_ERROR; } pParse->nTab = 0; pParse->nMem = 0; pParse->nSet = 0; pParse->nVar = 0; pParse->cookieMask = 0; pParse->cookieGoto = 0;}/*** Run the parser and code generator recursively in order to generate** code for the SQL statement given onto the end of the pParse context** currently under construction. When the parser is run recursively** this way, the final OP_Halt is not appended and other initialization** and finalization steps are omitted because those are handling by the** outermost parser.**** Not everything is nestable. This facility is designed to permit** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use** care if you decide to try to use this routine for some other purposes.*/void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ va_list ap; char *zSql; int rc;# define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar)) char saveBuf[SAVE_SZ]; if( pParse->nErr ) return; assert( pParse->nested<10 ); /* Nesting should only be of limited depth */ va_start(ap, zFormat); zSql = sqlite3VMPrintf(zFormat, ap); va_end(ap); if( zSql==0 ){ return; /* A malloc must have failed */ } pParse->nested++; memcpy(saveBuf, &pParse->nVar, SAVE_SZ); memset(&pParse->nVar, 0, SAVE_SZ); rc = sqlite3RunParser(pParse, zSql, 0); sqliteFree(zSql); memcpy(&pParse->nVar, saveBuf, SAVE_SZ); pParse->nested--;}/*** Locate the in-memory structure that describes a particular database** table given the name of that table and (optionally) the name of the** database containing the table. Return NULL if not found.**** If zDatabase is 0, all databases are searched for the table and the** first matching table is returned. (No checking for duplicate table** names is done.) The search order is TEMP first, then MAIN, then any** auxiliary databases added using the ATTACH command.**** See also sqlite3LocateTable().*/Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; assert( zName!=0 ); assert( (db->flags & SQLITE_Initialized) || db->init.busy ); for(i=OMIT_TEMPDB; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; p = sqlite3HashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1); if( p ) break; } return p;}/*** Locate the in-memory structure that describes a particular database** table given the name of that table and (optionally) the name of the** database containing the table. Return NULL if not found. Also leave an** error message in pParse->zErrMsg.**** The difference between this routine and sqlite3FindTable() is that this** routine leaves an error message in pParse->zErrMsg where** sqlite3FindTable() does not.*/Table *sqlite3LocateTable(Parse *pParse, const char *zName, const char *zDbase){ Table *p; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return 0; } p = sqlite3FindTable(pParse->db, zName, zDbase); if( p==0 ){ if( zDbase ){ sqlite3ErrorMsg(pParse, "no such table: %s.%s", zDbase, zName); }else if( sqlite3FindTable(pParse->db, zName, 0)!=0 ){ sqlite3ErrorMsg(pParse, "table \"%s\" is not in database \"%s\"", zName, zDbase); }else{ sqlite3ErrorMsg(pParse, "no such table: %s", zName); } pParse->checkSchema = 1; } return p;}/*** Locate the in-memory structure that describes ** a particular index given the name of that index** and the name of the database that contains the index.** Return NULL if not found.**** If zDatabase is 0, all databases are searched for the** table and the first matching index is returned. (No checking** for duplicate index names is done.) The search order is** TEMP first, then MAIN, then any auxiliary databases added** using the ATTACH command.*/Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){ Index *p = 0; int i; assert( (db->flags & SQLITE_Initialized) || db->init.busy ); for(i=OMIT_TEMPDB; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; p = sqlite3HashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1); if( p ) break; } return p;}/*** Reclaim the memory used by an index*/static void freeIndex(Index *p){ sqliteFree(p->zColAff); sqliteFree(p);}/*** Remove the given index from the index hash table, and free** its memory structures.**** The index is removed from the database hash tables but** it is not unlinked from the Table that it indexes.** Unlinking from the Table must be done by the calling function.*/static void sqliteDeleteIndex(sqlite3 *db, Index *p){ Index *pOld; assert( db!=0 && p->zName!=0 ); pOld = sqlite3HashInsert(&db->aDb[p->iDb].idxHash, p->zName, strlen(p->zName)+1, 0); if( pOld!=0 && pOld!=p ){ sqlite3HashInsert(&db->aDb[p->iDb].idxHash, pOld->zName, strlen(pOld->zName)+1, pOld); } freeIndex(p);}/*** For the index called zIdxName which is found in the database iDb,** unlike that index from its Table then remove the index from** the index hash table and free all memory structures associated** with the index.*/void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ Index *pIndex; int len; len = strlen(zIdxName); pIndex = sqlite3HashInsert(&db->aDb[iDb].idxHash, zIdxName, len+1, 0); if( pIndex ){ if( pIndex->pTable->pIndex==pIndex ){ pIndex->pTable->pIndex = pIndex->pNext; }else{ Index *p; for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){} if( p && p->pNext==pIndex ){ p->pNext = pIndex->pNext; } } freeIndex(pIndex); } db->flags |= SQLITE_InternChanges;}/*** Erase all schema information from the in-memory hash tables of** a single database. This routine is called to reclaim memory** before the database closes. It is also called during a rollback** if there were schema changes during the transaction or if a** schema-cookie mismatch occurs.**** If iDb<=0 then reset the internal schema tables for all database** files. If iDb>=2 then reset the internal schema for only the** single file indicated.*/void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ HashElem *pElem; Hash temp1; Hash temp2; int i, j; assert( iDb>=0 && iDb<db->nDb ); db->flags &= ~SQLITE_Initialized; for(i=iDb; i<db->nDb; i++){ Db *pDb = &db->aDb[i]; temp1 = pDb->tblHash; temp2 = pDb->trigHash; sqlite3HashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0); sqlite3HashClear(&pDb->aFKey); sqlite3HashClear(&pDb->idxHash); for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem)); } sqlite3HashClear(&temp2); sqlite3HashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0); for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); sqlite3DeleteTable(db, pTab); } sqlite3HashClear(&temp1); pDb->pSeqTab = 0; DbClearProperty(db, i, DB_SchemaLoaded); if( iDb>0 ) return; } assert( iDb==0 ); db->flags &= ~SQLITE_InternChanges; /* If one or more of the auxiliary database files has been closed, ** then remove then from the auxiliary database list. We take the ** opportunity to do this here since we have just deleted all of the ** schema hash tables and therefore do not have to make any changes ** to any of those tables. */ for(i=0; i<db->nDb; i++){ struct Db *pDb = &db->aDb[i]; if( pDb->pBt==0 ){ if( pDb->pAux && pDb->xFreeAux ) pDb->xFreeAux(pDb->pAux); pDb->pAux = 0; } } for(i=j=2; i<db->nDb; i++){ struct Db *pDb = &db->aDb[i]; if( pDb->pBt==0 ){ sqliteFree(pDb->zName); pDb->zName = 0; continue; } if( j<i ){ db->aDb[j] = db->aDb[i]; } j++; } memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j])); db->nDb = j; if( db->nDb<=2 && db->aDb!=db->aDbStatic ){ memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0])); sqliteFree(db->aDb); db->aDb = db->aDbStatic; }}/*** This routine is called whenever a rollback occurs. If there were** schema changes during the transaction, then we have to reset the** internal hash tables and reload them from disk.*/void sqlite3RollbackInternalChanges(sqlite3 *db){ if( db->flags & SQLITE_InternChanges ){ sqlite3ResetInternalSchema(db, 0); }}/*** This routine is called when a commit occurs.*/void sqlite3CommitInternalChanges(sqlite3 *db){ db->flags &= ~SQLITE_InternChanges;}/*** Clear the column names from a table or view.*/static void sqliteResetColumnNames(Table *pTable){ int i; Column *pCol; assert( pTable!=0 ); if( (pCol = pTable->aCol)!=0 ){ for(i=0; i<pTable->nCol; i++, pCol++){ sqliteFree(pCol->zName); sqlite3ExprDelete(pCol->pDflt); sqliteFree(pCol->zType); } sqliteFree(pTable->aCol); } pTable->aCol = 0; pTable->nCol = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -