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

📄 build.c

📁 一个小型的嵌入式数据库
💻 C
📖 第 1 页 / 共 5 页
字号:
  assert( pTable );  /* A positive nCol means the columns names for this view are  ** already known.  */  if( pTable->nCol>0 ) return 0;  /* A negative nCol is a special marker meaning that we are currently  ** trying to compute the column names.  If we enter this routine with  ** a negative nCol, it means two or more views form a loop, like this:  **  **     CREATE VIEW one AS SELECT * FROM two;  **     CREATE VIEW two AS SELECT * FROM one;  **  ** Actually, this error is caught previously and so the following test  ** should always fail.  But we will leave it in place just to be safe.  */  if( pTable->nCol<0 ){    sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName);    return 1;  }  /* If we get this far, it means we need to compute the table names.  ** Note that the call to sqlite3ResultSetOfSelect() will expand any  ** "*" elements in the results set of the view and will assign cursors  ** to the elements of the FROM clause.  But we do not want these changes  ** to be permanent.  So the computation is done on a copy of the SELECT  ** statement that defines the view.  */  assert( pTable->pSelect );  pSel = sqlite3SelectDup(pTable->pSelect);  n = pParse->nTab;  sqlite3SrcListAssignCursors(pParse, pSel->pSrc);  pTable->nCol = -1;  pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel);  pParse->nTab = n;  if( pSelTab ){    assert( pTable->aCol==0 );    pTable->nCol = pSelTab->nCol;    pTable->aCol = pSelTab->aCol;    pSelTab->nCol = 0;    pSelTab->aCol = 0;    sqlite3DeleteTable(0, pSelTab);    DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews);  }else{    pTable->nCol = 0;    nErr++;  }  sqlite3SelectDelete(pSel);  return nErr;  }#endif /* SQLITE_OMIT_VIEW */#ifndef SQLITE_OMIT_VIEW/*** Clear the column names from every VIEW in database idx.*/static void sqliteViewResetAll(sqlite3 *db, int idx){  HashElem *i;  if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;  for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){    Table *pTab = sqliteHashData(i);    if( pTab->pSelect ){      sqliteResetColumnNames(pTab);    }  }  DbClearProperty(db, idx, DB_UnresetViews);}#else# define sqliteViewResetAll(A,B)#endif /* SQLITE_OMIT_VIEW *//*** This function is called by the VDBE to adjust the internal schema** used by SQLite when the btree layer moves a table root page. The** root-page of a table or index in database iDb has changed from iFrom** to iTo.*/#ifndef SQLITE_OMIT_AUTOVACUUMvoid sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){  HashElem *pElem;    for(pElem=sqliteHashFirst(&pDb->tblHash); pElem; pElem=sqliteHashNext(pElem)){    Table *pTab = sqliteHashData(pElem);    if( pTab->tnum==iFrom ){      pTab->tnum = iTo;      return;    }  }  for(pElem=sqliteHashFirst(&pDb->idxHash); pElem; pElem=sqliteHashNext(pElem)){    Index *pIdx = sqliteHashData(pElem);    if( pIdx->tnum==iFrom ){      pIdx->tnum = iTo;      return;    }  }  assert(0);}#endif/*** Write code to erase the table with root-page iTable from database iDb.** Also write code to modify the sqlite_master table and internal schema** if a root-page of another table is moved by the btree-layer whilst** erasing iTable (this can happen with an auto-vacuum database).*/ static void destroyRootPage(Parse *pParse, int iTable, int iDb){  Vdbe *v = sqlite3GetVdbe(pParse);  sqlite3VdbeAddOp(v, OP_Destroy, iTable, iDb);#ifndef SQLITE_OMIT_AUTOVACUUM  /* OP_Destroy pushes an integer onto the stack. If this integer  ** is non-zero, then it is the root page number of a table moved to  ** location iTable. The following code modifies the sqlite_master table to  ** reflect this.  **  ** The "#0" in the SQL is a special constant that means whatever value  ** is on the top of the stack.  See sqlite3RegisterExpr().  */  sqlite3NestedParse(pParse,      "UPDATE %Q.%s SET rootpage=%d WHERE #0 AND rootpage=#0",     pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable);#endif}/*** Write VDBE code to erase table pTab and all associated indices on disk.** Code to update the sqlite_master tables and internal schema definitions** in case a root-page belonging to another table is moved by the btree layer** is also added (this can happen with an auto-vacuum database).*/static void destroyTable(Parse *pParse, Table *pTab){#ifdef SQLITE_OMIT_AUTOVACUUM  Index *pIdx;  destroyRootPage(pParse, pTab->tnum, pTab->iDb);  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){    destroyRootPage(pParse, pIdx->tnum, pIdx->iDb);  }#else  /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM  ** is not defined), then it is important to call OP_Destroy on the  ** table and index root-pages in order, starting with the numerically   ** largest root-page number. This guarantees that none of the root-pages  ** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the  ** following were coded:  **  ** OP_Destroy 4 0  ** ...  ** OP_Destroy 5 0  **  ** and root page 5 happened to be the largest root-page number in the  ** database, then root page 5 would be moved to page 4 by the   ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit  ** a free-list page.  */  int iTab = pTab->tnum;  int iDestroyed = 0;  while( 1 ){    Index *pIdx;    int iLargest = 0;    if( iDestroyed==0 || iTab<iDestroyed ){      iLargest = iTab;    }    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){      int iIdx = pIdx->tnum;      assert( pIdx->iDb==pTab->iDb );      if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){        iLargest = iIdx;      }    }    if( iLargest==0 ) return;    destroyRootPage(pParse, iLargest, pTab->iDb);    iDestroyed = iLargest;  }#endif}/*** This routine is called to do the work of a DROP TABLE statement.** pName is the name of the table to be dropped.*/void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){  Table *pTab;  Vdbe *v;  sqlite3 *db = pParse->db;  int iDb;  if( pParse->nErr || sqlite3_malloc_failed ) goto exit_drop_table;  assert( pName->nSrc==1 );  pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase);  if( pTab==0 ) goto exit_drop_table;  iDb = pTab->iDb;  assert( iDb>=0 && iDb<db->nDb );#ifndef SQLITE_OMIT_AUTHORIZATION  {    int code;    const char *zTab = SCHEMA_TABLE(pTab->iDb);    const char *zDb = db->aDb[pTab->iDb].zName;    if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){      goto exit_drop_table;    }    if( isView ){      if( iDb==1 ){        code = SQLITE_DROP_TEMP_VIEW;      }else{        code = SQLITE_DROP_VIEW;      }    }else{      if( iDb==1 ){        code = SQLITE_DROP_TEMP_TABLE;      }else{        code = SQLITE_DROP_TABLE;      }    }    if( sqlite3AuthCheck(pParse, code, pTab->zName, 0, zDb) ){      goto exit_drop_table;    }    if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){      goto exit_drop_table;    }  }#endif  if( pTab->readOnly || pTab==db->aDb[iDb].pSeqTab ){    sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);    goto exit_drop_table;  }#ifndef SQLITE_OMIT_VIEW  /* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used  ** on a table.  */  if( isView && pTab->pSelect==0 ){    sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName);    goto exit_drop_table;  }  if( !isView && pTab->pSelect ){    sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName);    goto exit_drop_table;  }#endif  /* Generate code to remove the table from the master table  ** on disk.  */  v = sqlite3GetVdbe(pParse);  if( v ){    Trigger *pTrigger;    int iDb = pTab->iDb;    Db *pDb = &db->aDb[iDb];    sqlite3BeginWriteOperation(pParse, 0, iDb);    /* Drop all triggers associated with the table being dropped. Code    ** is generated to remove entries from sqlite_master and/or    ** sqlite_temp_master if required.    */    pTrigger = pTab->pTrigger;    while( pTrigger ){      assert( pTrigger->iDb==iDb || pTrigger->iDb==1 );      sqlite3DropTriggerPtr(pParse, pTrigger, 1);      pTrigger = pTrigger->pNext;    }#ifndef SQLITE_OMIT_AUTOINCREMENT    /* Remove any entries of the sqlite_sequence table associated with    ** the table being dropped. This is done before the table is dropped    ** at the btree level, in case the sqlite_sequence table needs to    ** move as a result of the drop (can happen in auto-vacuum mode).    */    if( pTab->autoInc ){      sqlite3NestedParse(pParse,        "DELETE FROM %s.sqlite_sequence WHERE name=%Q",        pDb->zName, pTab->zName      );    }#endif    /* Drop all SQLITE_MASTER table and index entries that refer to the    ** table. The program name loops through the master table and deletes    ** every row that refers to a table of the same name as the one being    ** dropped. Triggers are handled seperately because a trigger can be    ** created in the temp database that refers to a table in another    ** database.    */    sqlite3NestedParse(pParse,         "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",        pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);    if( !isView ){      destroyTable(pParse, pTab);    }    /* Remove the table entry from SQLite's internal schema and modify    ** the schema cookie.    */    sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);    sqlite3ChangeCookie(db, v, iDb);  }  sqliteViewResetAll(db, iDb);exit_drop_table:  sqlite3SrcListDelete(pName);}/*** This routine is called to create a new foreign key on the table** currently under construction.  pFromCol determines which columns** in the current table point to the foreign key.  If pFromCol==0 then** connect the key to the last column inserted.  pTo is the name of** the table referred to.  pToCol is a list of tables in the other** pTo table that the foreign key points to.  flags contains all** information about the conflict resolution algorithms specified** in the ON DELETE, ON UPDATE and ON INSERT clauses.**** An FKey structure is created and added to the table currently** under construction in the pParse->pNewTable field.  The new FKey** is not linked into db->aFKey at this point - that does not happen** until sqlite3EndTable().**** The foreign key is set for IMMEDIATE processing.  A subsequent call** to sqlite3DeferForeignKey() might change this to DEFERRED.*/void sqlite3CreateForeignKey(  Parse *pParse,       /* Parsing context */  ExprList *pFromCol,  /* Columns in this table that point to other table */  Token *pTo,          /* Name of the other table */  ExprList *pToCol,    /* Columns in the other table */  int flags            /* Conflict resolution algorithms. */){#ifndef SQLITE_OMIT_FOREIGN_KEY  FKey *pFKey = 0;  Table *p = pParse->pNewTable;  int nByte;  int i;  int nCol;  char *z;  assert( pTo!=0 );  if( p==0 || pParse->nErr ) goto fk_end;  if( pFromCol==0 ){    int iCol = p->nCol-1;    if( iCol<0 ) goto fk_end;    if( pToCol && pToCol->nExpr!=1 ){      sqlite3ErrorMsg(pParse, "foreign key on %s"         " should reference only one column of table %T",         p->aCol[iCol].zName, pTo);      goto fk_end;    }    nCol = 1;  }else if( pToCol && pToCol->nExpr!=pFromCol->nExpr ){    sqlite3ErrorMsg(pParse,        "number of columns in foreign key does not match the number of "        "columns in the referenced table");    goto fk_end;  }else{    nCol = pFromCol->nExpr;  }  nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1;  if( pToCol ){    for(i=0; i<pToCol->nExpr; i++){      nByte += strlen(pToCol->a[i].zName) + 1;    }  }  pFKey = sqliteMalloc( nByte );  if( pFKey==0 ) goto fk_end;  pFKey->pFrom = p;  pFKey->pNextFrom = p->pFKey;  z = (char*)&pFKey[1];  pFKey->aCol = (struct sColMap*)z;  z += sizeof(struct sColMap)*nCol;  pFKey->zTo = z;  memcpy(z, pTo->z, pTo->n);  z[pTo->n] = 0;  z += pTo->n+1;  pFKey->pNextTo = 0;  pFKey->nCol = nCol;  if( pFromCol==0 ){    pFKey->aCol[0].iFrom = p->nCol-1;  }else{    for(i=0; i<nCol; i++){      int j;      for(j=0; j<p->nCol; j++){        if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){          pFKey->aCol[i].iFrom = j;          break;        }      }      if( j>=p->nCol ){        sqlite3ErrorMsg(pParse,           "unknown column \"%s\" in foreign key definition",           pFromCol->a[i].zName);        goto fk_end;      }    }  }  if( pToCol ){    for(i=0; i<nCol; i++){      int n = strlen(pToCol->a[i].zName);      pFKey->aCol[i].zCol = z;      memcpy(z, pToCol->a[i].zName, n);      z[n] = 0;      z += n+1;    }  }  pFKey->isDeferred = 0;  pFKey->deleteConf = flags & 0xff;  pFKey->updateConf = (flags >> 8 ) & 0xff;  pFKey->insertConf =

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -