📄 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.433 2007/07/02 19:31:27 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;}#ifndef SQLITE_OMIT_SHARED_CACHE/*** The TableLock structure is only used by the sqlite3TableLock() and** codeTableLocks() functions.*/struct TableLock { int iDb; /* The database containing the table to be locked */ int iTab; /* The root page of the table to be locked */ u8 isWriteLock; /* True for write lock. False for a read lock */ const char *zName; /* Name of the table */};/*** Record the fact that we want to lock a table at run-time. **** The table to be locked has root page iTab and is found in database iDb.** A read or a write lock can be taken depending on isWritelock.**** This routine just records the fact that the lock is desired. The** code to make the lock occur is generated by a later call to** codeTableLocks() which occurs during sqlite3FinishCoding().*/void sqlite3TableLock( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database containing the table to lock */ int iTab, /* Root page number of the table to be locked */ u8 isWriteLock, /* True for a write lock */ const char *zName /* Name of the table to be locked */){ int i; int nBytes; TableLock *p; if( 0==sqlite3ThreadDataReadOnly()->useSharedData || iDb<0 ){ return; } for(i=0; i<pParse->nTableLock; i++){ p = &pParse->aTableLock[i]; if( p->iDb==iDb && p->iTab==iTab ){ p->isWriteLock = (p->isWriteLock || isWriteLock); return; } } nBytes = sizeof(TableLock) * (pParse->nTableLock+1); pParse->aTableLock = sqliteReallocOrFree(pParse->aTableLock, nBytes); if( pParse->aTableLock ){ p = &pParse->aTableLock[pParse->nTableLock++]; p->iDb = iDb; p->iTab = iTab; p->isWriteLock = isWriteLock; p->zName = zName; }}/*** Code an OP_TableLock instruction for each table locked by the** statement (configured by calls to sqlite3TableLock()).*/static void codeTableLocks(Parse *pParse){ int i; Vdbe *pVdbe; assert( sqlite3ThreadDataReadOnly()->useSharedData || pParse->nTableLock==0 ); if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){ return; } for(i=0; i<pParse->nTableLock; i++){ TableLock *p = &pParse->aTableLock[i]; int p1 = p->iDb; if( p->isWriteLock ){ p1 = -1*(p1+1); } sqlite3VdbeOp3(pVdbe, OP_TableLock, p1, p->iTab, p->zName, P3_STATIC); }}#else #define codeTableLocks(x)#endif/*** 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( sqlite3MallocFailed() ) 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; sqlite3VdbeJumpHere(v, pParse->cookieGoto-1); 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]); }#ifndef SQLITE_OMIT_VIRTUALTABLE if( pParse->pVirtualLock ){ char *vtab = (char *)pParse->pVirtualLock->pVtab; sqlite3VdbeOp3(v, OP_VBegin, 0, 0, vtab, P3_VTAB); }#endif /* Once all the cookies have been verified and transactions opened, ** obtain the required table-locks. This is a no-op unless the ** shared-cache feature is enabled. */ codeTableLocks(pParse); sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto); }#ifndef SQLITE_OMIT_TRACE /* 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);#endif /* SQLITE_OMIT_TRACE */ } /* Get the VDBE program ready for execution */ if( v && pParse->nErr==0 && !sqlite3MallocFailed() ){#ifdef SQLITE_DEBUG FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; sqlite3VdbeTrace(v, trace);#endif sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3, pParse->nTab+3, 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;# 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); 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 ); 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].pSchema->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{ 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; for(i=OMIT_TEMPDB; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ Schema *pSchema = db->aDb[j].pSchema; if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; assert( pSchema || (j==1 && !db->aDb[1].pBt) ); if( pSchema ){ p = sqlite3HashFind(&pSchema->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(Index *p){ Index *pOld; const char *zName = p->zName; pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName, strlen( zName)+1, 0); assert( pOld==0 || pOld==p ); 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; Hash *pHash = &db->aDb[iDb].pSchema->idxHash; len = strlen(zIdxName); pIndex = sqlite3HashInsert(pHash, 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){ int i, j; assert( iDb>=0 && iDb<db->nDb ); for(i=iDb; i<db->nDb; i++){ Db *pDb = &db->aDb[i]; if( pDb->pSchema ){ sqlite3SchemaFree(pDb->pSchema); } if( iDb>0 ) return; } assert( iDb==0 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -