?? build.c
字號:
Parse *pParse, /* Parser context */ Token *pStart, /* The "CREATE" token */ Token *pName, /* Name of table or view to create */ int isTemp, /* True if this is a TEMP table */ int isView /* True if this is a VIEW */){ Table *pTable; Index *pIdx; char *zName; sqlite *db = pParse->db; Vdbe *v; int iDb; pParse->sFirstToken = *pStart; zName = sqliteTableNameFromToken(pName); if( zName==0 ) return; if( db->init.iDb==1 ) isTemp = 1;#ifndef SQLITE_OMIT_AUTHORIZATION assert( (isTemp & 1)==isTemp ); { int code; char *zDb = isTemp ? "temp" : "main"; if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ sqliteFree(zName); return; } if( isView ){ if( isTemp ){ code = SQLITE_CREATE_TEMP_VIEW; }else{ code = SQLITE_CREATE_VIEW; } }else{ if( isTemp ){ code = SQLITE_CREATE_TEMP_TABLE; }else{ code = SQLITE_CREATE_TABLE; } } if( sqliteAuthCheck(pParse, code, zName, 0, zDb) ){ sqliteFree(zName); return; } }#endif /* Before trying to create a temporary table, make sure the Btree for ** holding temporary tables is open. */ if( isTemp && db->aDb[1].pBt==0 && !pParse->explain ){ int rc = sqliteBtreeFactory(db, 0, 0, MAX_PAGES, &db->aDb[1].pBt); if( rc!=SQLITE_OK ){ sqliteErrorMsg(pParse, "unable to open a temporary database " "file for storing temporary tables"); pParse->nErr++; return; } if( db->flags & SQLITE_InTrans ){ rc = sqliteBtreeBeginTrans(db->aDb[1].pBt); if( rc!=SQLITE_OK ){ sqliteErrorMsg(pParse, "unable to get a write lock on " "the temporary database file"); return; } } } /* Make sure the new table name does not collide with an existing ** index or table name. Issue an error message if it does. ** ** If we are re-reading the sqlite_master table because of a schema ** change and a new permanent table is found whose name collides with ** an existing temporary table, that is not an error. */ pTable = sqliteFindTable(db, zName, 0); iDb = isTemp ? 1 : db->init.iDb; if( pTable!=0 && (pTable->iDb==iDb || !db->init.busy) ){ sqliteErrorMsg(pParse, "table %T already exists", pName); sqliteFree(zName); return; } if( (pIdx = sqliteFindIndex(db, zName, 0))!=0 && (pIdx->iDb==0 || !db->init.busy) ){ sqliteErrorMsg(pParse, "there is already an index named %s", zName); sqliteFree(zName); return; } pTable = sqliteMalloc( sizeof(Table) ); if( pTable==0 ){ sqliteFree(zName); return; } pTable->zName = zName; pTable->nCol = 0; pTable->aCol = 0; pTable->iPKey = -1; pTable->pIndex = 0; pTable->iDb = iDb; if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; /* Begin generating the code that will insert the table record into ** the SQLITE_MASTER table. Note in particular that we must go ahead ** and allocate the record number for the table entry now. Before any ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause ** indices to be created and the table record must come before the ** indices. Hence, the record number for the table must be allocated ** now. */ if( !db->init.busy && (v = sqliteGetVdbe(pParse))!=0 ){ sqliteBeginWriteOperation(pParse, 0, isTemp); if( !isTemp ){ sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0); sqliteVdbeAddOp(v, OP_SetCookie, 0, 1); } sqliteOpenMasterTable(v, isTemp); sqliteVdbeAddOp(v, OP_NewRecno, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); }}/*** 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. sqliteStartTable() gets called** first to get things going. Then this routine is called for each** column.*/void sqliteAddColumn(Parse *pParse, Token *pName){ Table *p; int i; char *z = 0; Column *pCol; if( (p = pParse->pNewTable)==0 ) return; sqliteSetNString(&z, pName->z, pName->n, 0); if( z==0 ) return; sqliteDequote(z); for(i=0; i<p->nCol; i++){ if( sqliteStrICmp(z, p->aCol[i].zName)==0 ){ sqliteErrorMsg(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 ) return; p->aCol = aNew; } pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); pCol->zName = z; pCol->sortOrder = SQLITE_SO_NUM; 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 sqliteAddNotNull(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;}/*** 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 sqliteAddColumnType(Parse *pParse, Token *pFirst, Token *pLast){ Table *p; int i, j; int n; char *z, **pz; Column *pCol; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; if( i<0 ) return; pCol = &p->aCol[i]; pz = &pCol->zType; n = pLast->n + Addr(pLast->z) - Addr(pFirst->z); sqliteSetNString(pz, pFirst->z, n, 0); z = *pz; if( z==0 ) return; for(i=j=0; z[i]; i++){ int c = z[i]; if( isspace(c) ) continue; z[j++] = c; } z[j] = 0; if( pParse->db->file_format>=4 ){ pCol->sortOrder = sqliteCollateType(z, n); }else{ pCol->sortOrder = SQLITE_SO_NUM; }}/*** The given token is the default value for the last column added to** the table currently under construction. If "minusFlag" is true, it** means the value token was preceded by a minus sign.**** This routine is called by the parser while in the middle of** parsing a CREATE TABLE statement.*/void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){ Table *p; int i; char **pz; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; if( i<0 ) return; pz = &p->aCol[i].zDflt; if( minusFlag ){ sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0); }else{ sqliteSetNString(pz, pVal->z, pVal->n, 0); } sqliteDequote(*pz);}/*** 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 row id. (Exception:** For backwards compatibility with older databases, do not do this** if the file format version number is less than 1.) 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 sqliteAddPrimaryKey(Parse *pParse, IdList *pList, int onError){ Table *pTab = pParse->pNewTable; char *zType = 0; int iCol = -1, i; if( pTab==0 ) goto primary_key_exit; if( pTab->hasPrimKey ){ sqliteErrorMsg(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->nId; i++){ for(iCol=0; iCol<pTab->nCol; iCol++){ if( sqliteStrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ) break; } if( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1; } if( pList->nId>1 ) iCol = -1; } if( iCol>=0 && iCol<pTab->nCol ){ zType = pTab->aCol[iCol].zType; } if( pParse->db->file_format>=1 && zType && sqliteStrICmp(zType, "INTEGER")==0 ){ pTab->iPKey = iCol; pTab->keyConf = onError; }else{ sqliteCreateIndex(pParse, 0, 0, pList, onError, 0, 0); pList = 0; }primary_key_exit: sqliteIdListDelete(pList); return;}/*** Return the appropriate collating type given a type name.**** The collation type is text (SQLITE_SO_TEXT) if the type** name contains the character stream "text" or "blob" or** "clob". Any other type name is collated as numeric** (SQLITE_SO_NUM).*/int sqliteCollateType(const char *zType, int nType){ int i; for(i=0; i<nType-3; i++){ int c = *(zType++) | 0x60; if( (c=='b' || c=='c') && sqliteStrNICmp(zType, "lob", 3)==0 ){ return SQLITE_SO_TEXT; } if( c=='c' && sqliteStrNICmp(zType, "har", 3)==0 ){ return SQLITE_SO_TEXT; } if( c=='t' && sqliteStrNICmp(zType, "ext", 3)==0 ){ return SQLITE_SO_TEXT; } } return SQLITE_SO_NUM;}/*** This routine is called by the parser while in the middle of** parsing a CREATE TABLE statement. A "COLLATE" clause has** been seen on a column. This routine sets the Column.sortOrder on** the column currently under construction.*/void sqliteAddCollateType(Parse *pParse, int collType){ Table *p; int i; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; if( i>=0 ) p->aCol[i].sortOrder = collType;}/*** Come up with a new random value for the schema cookie. Make sure** the new value is different from the old.**** 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 sqliteChangeCookie(sqlite *db, Vdbe *v){ if( db->next_cookie==db->aDb[0].schema_cookie ){ unsigned char r; sqliteRandomness(1, &r); db->next_cookie = db->aDb[0].schema_cookie + r + 1; db->flags |= SQLITE_InternChanges; sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0); sqliteVdbeAddOp(v, OP_SetCookie, 0, 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.*/static int identLength(const char *z){ int n; int needQuote = 0; for(n=0; *z; n++, z++){ if( *z=='\'' ){ n++; needQuote=1; } } return n + needQuote*2;}/*** Write an identifier onto the end of the given string. Add** quote characters as needed.*/static void identPut(char *z, int *pIdx, char *zIdent){ 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]) || sqliteKeywordCode(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; n = 0; for(i=0; i<p->nCol; i++){ n += identLength(p->aCol[i].zName); } n += identLength(p->zName); if( n<40 ){ zSep = ""; zSep2 = ","; zEnd = ")"; }else{ zSep = "\n "; zSep2 = ",\n "; zEnd = "\n)"; } n += 35 + 6*p->nCol;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -