⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 build.c

📁 sqlite数据库管理系统开放源码
💻 C
📖 第 1 页 / 共 5 页
字号:
  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 + -