📄 build.c
字号:
/*** Add a new column to the table currently being constructed.**** The parser calls this routine once for each column declaration** in a CREATE TABLE statement. sqlite3StartTable() gets called** first to get things going. Then this routine is called for each** column.*/void sqlite3AddColumn(Parse *pParse, Token *pName){ Table *p; int i; char *z; Column *pCol; if( (p = pParse->pNewTable)==0 ) return; z = sqlite3NameFromToken(pName); if( z==0 ) return; for(i=0; i<p->nCol; i++){ if( STRICMP(z, p->aCol[i].zName) ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); sqliteFree(z); return; } } if( (p->nCol & 0x7)==0 ){ Column *aNew; aNew = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0])); if( aNew==0 ){ sqliteFree(z); return; } p->aCol = aNew; } pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); pCol->zName = z; /* If there is no type specified, columns have the default affinity ** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will ** be called next to set pCol->affinity correctly. */ pCol->affinity = SQLITE_AFF_NONE; pCol->pColl = pParse->db->pDfltColl; p->nCol++;}/*** This routine is called by the parser while in the middle of** parsing a CREATE TABLE statement. A "NOT NULL" constraint has** been seen on a column. This routine sets the notNull flag on** the column currently under construction.*/void sqlite3AddNotNull(Parse *pParse, int onError){ Table *p; int i; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; if( i>=0 ) p->aCol[i].notNull = onError;}/*** Scan the column type name zType (length nType) and return the** associated affinity type.**** This routine does a case-independent search of zType for the ** substrings in the following table. If one of the substrings is** found, the corresponding affinity is returned. If zType contains** more than one of the substrings, entries toward the top of ** the table take priority. For example, if zType is 'BLOBINT', ** SQLITE_AFF_INTEGER is returned.**** Substring | Affinity** --------------------------------** 'INT' | SQLITE_AFF_INTEGER** 'CHAR' | SQLITE_AFF_TEXT** 'CLOB' | SQLITE_AFF_TEXT** 'TEXT' | SQLITE_AFF_TEXT** 'BLOB' | SQLITE_AFF_NONE**** If none of the substrings in the above table are found,** SQLITE_AFF_NUMERIC is returned.*/char sqlite3AffinityType(const Token *pType){ u32 h = 0; char aff = SQLITE_AFF_NUMERIC; const unsigned char *zIn = pType->z; const unsigned char *zEnd = &pType->z[pType->n]; while( zIn!=zEnd ){ h = (h<<8) + sqlite3UpperToLower[*zIn]; zIn++; if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */ aff = SQLITE_AFF_TEXT; }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */ aff = SQLITE_AFF_TEXT; }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */ aff = SQLITE_AFF_TEXT; }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */ && aff==SQLITE_AFF_NUMERIC ){ aff = SQLITE_AFF_NONE; }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */ aff = SQLITE_AFF_INTEGER; break; } } return aff;}/*** This routine is called by the parser while in the middle of** parsing a CREATE TABLE statement. The pFirst token is the first** token in the sequence of tokens that describe the type of the** column currently under construction. pLast is the last token** in the sequence. Use this information to construct a string** that contains the typename of the column and store that string** in zType.*/ void sqlite3AddColumnType(Parse *pParse, Token *pType){ Table *p; int i; Column *pCol; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; if( i<0 ) return; pCol = &p->aCol[i]; sqliteFree(pCol->zType); pCol->zType = sqlite3NameFromToken(pType); pCol->affinity = sqlite3AffinityType(pType);}/*** The expression is the default value for the most recently added column** of the table currently under construction.**** Default value expressions must be constant. Raise an exception if this** is not the case.**** This routine is called by the parser while in the middle of** parsing a CREATE TABLE statement.*/void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){ Table *p; Column *pCol; if( (p = pParse->pNewTable)!=0 ){ pCol = &(p->aCol[p->nCol-1]); if( !sqlite3ExprIsConstantOrFunction(pExpr) ){ sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", pCol->zName); }else{ sqlite3ExprDelete(pCol->pDflt); pCol->pDflt = sqlite3ExprDup(pExpr); } } sqlite3ExprDelete(pExpr);}/*** Designate the PRIMARY KEY for the table. pList is a list of names ** of columns that form the primary key. If pList is NULL, then the** most recently added column of the table is the primary key.**** A table can have at most one primary key. If the table already has** a primary key (and this is the second primary key) then create an** error.**** If the PRIMARY KEY is on a single column whose datatype is INTEGER,** then we will try to use that column as the rowid. Set the Table.iPKey** field of the table under construction to be the index of the** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is** no INTEGER PRIMARY KEY.**** If the key is not an INTEGER PRIMARY KEY, then create a unique** index for the key. No index is created for INTEGER PRIMARY KEYs.*/void sqlite3AddPrimaryKey( Parse *pParse, /* Parsing context */ ExprList *pList, /* List of field names to be indexed */ int onError, /* What to do with a uniqueness conflict */ int autoInc /* True if the AUTOINCREMENT keyword is present */){ Table *pTab = pParse->pNewTable; char *zType = 0; int iCol = -1, i; if( pTab==0 ) goto primary_key_exit; if( pTab->hasPrimKey ){ sqlite3ErrorMsg(pParse, "table \"%s\" has more than one primary key", pTab->zName); goto primary_key_exit; } pTab->hasPrimKey = 1; if( pList==0 ){ iCol = pTab->nCol - 1; pTab->aCol[iCol].isPrimKey = 1; }else{ for(i=0; i<pList->nExpr; i++){ for(iCol=0; iCol<pTab->nCol; iCol++){ if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){ break; } } if( iCol<pTab->nCol ){ pTab->aCol[iCol].isPrimKey = 1; } } if( pList->nExpr>1 ) iCol = -1; } if( iCol>=0 && iCol<pTab->nCol ){ zType = pTab->aCol[iCol].zType; } if( zType && sqlite3StrICmp(zType, "INTEGER")==0 ){ pTab->iPKey = iCol; pTab->keyConf = onError; pTab->autoInc = autoInc; }else if( autoInc ){#ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY");#endif }else{ sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0); pList = 0; }primary_key_exit: sqlite3ExprListDelete(pList); return;}/*** Set the collation function of the most recently parsed table column** to the CollSeq given.*/void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){ Table *p; Index *pIdx; CollSeq *pColl; int i; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; pColl = sqlite3LocateCollSeq(pParse, zType, nType); p->aCol[i].pColl = pColl; /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>", ** then an index may have been created on this column before the ** collation type was added. Correct this if it is the case. */ for(pIdx = p->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nColumn==1 ); if( pIdx->aiColumn[0]==i ) pIdx->keyInfo.aColl[0] = pColl; }}/*** Call sqlite3CheckCollSeq() for all collating sequences in an index,** in order to verify that all the necessary collating sequences are** loaded.*/int sqlite3CheckIndexCollSeq(Parse *pParse, Index *pIdx){ if( pIdx ){ int i; for(i=0; i<pIdx->nColumn; i++){ if( sqlite3CheckCollSeq(pParse, pIdx->keyInfo.aColl[i]) ){ return SQLITE_ERROR; } } } return SQLITE_OK;}/*** This function returns the collation sequence for database native text** encoding identified by the string zName, length nName.**** If the requested collation sequence is not available, or not available** in the database native encoding, the collation factory is invoked to** request it. If the collation factory does not supply such a sequence,** and the sequence is available in another text encoding, then that is** returned instead.**** If no versions of the requested collations sequence are available, or** another error occurs, NULL is returned and an error message written into** pParse.*/CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){ sqlite3 *db = pParse->db; u8 enc = db->enc; u8 initbusy = db->init.busy; CollSeq *pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy); if( !initbusy && (!pColl || !pColl->xCmp) ){ pColl = sqlite3GetCollSeq(db, pColl, zName, nName); if( !pColl ){ if( nName<0 ){ nName = strlen(zName); } sqlite3ErrorMsg(pParse, "no such collation sequence: %.*s", nName, zName); pColl = 0; } } return pColl;}/*** Generate code that will increment the schema cookie.**** The schema cookie is used to determine when the schema for the** database changes. After each schema change, the cookie value** changes. When a process first reads the schema it records the** cookie. Thereafter, whenever it goes to access the database,** it checks the cookie to make sure the schema has not changed** since it was last read.**** This plan is not completely bullet-proof. It is possible for** the schema to change multiple times and for the cookie to be** set back to prior value. But schema changes are infrequent** and the probability of hitting the same cookie value is only** 1 chance in 2^32. So we're safe enough.*/void sqlite3ChangeCookie(sqlite3 *db, Vdbe *v, int iDb){ sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].schema_cookie+1, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);}/*** Measure the number of characters needed to output the given** identifier. The number returned includes any quotes used** but does not include the null terminator.**** The estimate is conservative. It might be larger that what is** really needed.*/static int identLength(const char *z){ int n; for(n=0; *z; n++, z++){ if( *z=='"' ){ n++; } } return n + 2;}/*** Write an identifier onto the end of the given string. Add** quote characters as needed.*/static void identPut(char *z, int *pIdx, char *zSignedIdent){ unsigned char *zIdent = (unsigned char*)zSignedIdent; int i, j, needQuote; i = *pIdx; for(j=0; zIdent[j]; j++){ if( !isalnum(zIdent[j]) && zIdent[j]!='_' ) break; } needQuote = zIdent[j]!=0 || isdigit(zIdent[0]) || sqlite3KeywordCode(zIdent, j)!=TK_ID; if( needQuote ) z[i++] = '"'; for(j=0; zIdent[j]; j++){ z[i++] = zIdent[j]; if( zIdent[j]=='"' ) z[i++] = '"'; } if( needQuote ) z[i++] = '"'; z[i] = 0; *pIdx = i;}/*** Generate a CREATE TABLE statement appropriate for the given** table. Memory to hold the text of the statement is obtained** from sqliteMalloc() and must be freed by the calling function.*/static char *createTableStmt(Table *p){ int i, k, n; char *zStmt; char *zSep, *zSep2, *zEnd, *z; Column *pCol; n = 0; for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){ n += identLength(pCol->zName); z = pCol->zType; if( z ){ n += (strlen(z) + 1); } } n += identLength(p->zName); if( n<50 ){ zSep = ""; zSep2 = ","; zEnd = ")"; }else{ zSep = "\n "; zSep2 = ",\n "; zEnd = "\n)"; } n += 35 + 6*p->nCol; zStmt = sqliteMallocRaw( n ); if( zStmt==0 ) return 0; strcpy(zStmt, !OMIT_TEMPDB&&p->iDb==1 ? "CREATE TEMP TABLE ":"CREATE TABLE "); k = strlen(zStmt); identPut(zStmt, &k, p->zName); zStmt[k++] = '('; for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){ strcpy(&zStmt[k], zSep); k += strlen(&zStmt[k]); zSep = zSep2; identPut(zStmt, &k, pCol->zName); if( (z = pCol->zType)!=0 ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -