📄 build.c
字号:
#include "eDbInit.h"
void eDbBeginParse(Parser *pParse, int explainFlag){
pParse->explain = explainFlag;
pParse->nVar = 0;
}
void eDbExec(Parser *pParse){
}
Table *eDbFindTable(eDb *db, const char *zName, const char *zDatabase){
Table *p = 0;
p = eDbHashFind(&db->tblHash, zName, strlen(zName)+1);
return p;
}
Table *eDbLocateTable(Parser *pParse, const char *zName, const char *zDbase){
Table *p;
p = eDbFindTable(pParse->db, zName, zDbase);
if( p==0 ){
if( zDbase ){
eDbErrorMsg(pParse, "no such table: %s.%s", zDbase, zName);
}else if( eDbFindTable(pParse->db, zName, 0)!=0 ){
eDbErrorMsg(pParse, "table \"%s\" is not in database \"%s\"",
zName, zDbase);
}else{
eDbErrorMsg(pParse, "no such table: %s", zName);
}
}
return p;
}
Index *eDbFindIndex(eDb *db, const char *zName, const char *zDb){
Index *p = 0;
p = eDbHashFind(&db->idxHash, zName, strlen(zName)+1);
return p;
}
void eDbDeleteIndex(eDb *db, Index *p){
Index *pOld;
assert( db!=0 && p->zName!=0 );
pOld = eDbHashInsert(&db->idxHash, p->zName,
strlen(p->zName)+1, 0);
if( pOld!=0 && pOld!=p ){
eDbHashInsert(&db->idxHash, pOld->zName,
strlen(pOld->zName)+1, pOld);
}
eDbFree(p);
}
void eDbUnlinkAndDeleteIndex(eDb *db, Index *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;
}
}
eDbDeleteIndex(db, pIndex);
}
void eDbUnlinkIndex(eDb *db, Index *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;
}
}
}
void eDbDeleteTable(eDb *db, Table *pTable){
int i;
Index *pIndex, *pNext;
if( pTable==0 ) return;
/* Delete all indices associated with this table
*/
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext;
eDbDeleteIndex(db, pIndex);
}
/* Delete the Table structure itself.
*/
for(i=0; i<pTable->nCol; i++){
eDbFree(pTable->aCol[i].zName);
eDbFree(pTable->aCol[i].zDflt);
eDbFree(pTable->aCol[i].zType);
}
eDbFree(pTable->zName);
eDbFree(pTable->aCol);
eDbSelectDelete(pTable->pSelect);
eDbFree(pTable);
}
void eDbUnlinkAndDeleteTable(eDb *db, Table *p){
Table *pOld;
assert( db!=0 );
pOld = eDbHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, 0);
assert( pOld==0 || pOld==p );
eDbDeleteTable(db, p);
}
void eDbUnlinkTable(eDb *db, Table *p){
Table *pOld;
assert( db!=0 );
pOld = eDbHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, 0);
assert( pOld==0 || pOld==p );
}
char *eDbTableNameFromToken(Token *pName){
char *zName = eDbStrNDup(pName->z, pName->n);
eDbDequote(zName);
return zName;
}
void eDbStartTable(
Parser *pParse, /* Parser context */
Token *pStart, /* The "CREATE" token */
Token *pName /* Name of table or view to create */
){
char *zName;
Table *pTable;
Index *pIdx;
eDb *db = pParse->db;
pParse->sFirstToken = *pStart;
zName = eDbTableNameFromToken(pName);
if( zName==0 ) 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 eDb_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 = eDbFindTable(db, zName, 0);
if( pTable != 0){
eDbErrorMsg(pParse, "table %s already exists", pTable->zName);
eDbFree(zName);
return;
}
if( (pIdx = eDbFindIndex(db, zName, 0))!=0){
eDbErrorMsg(pParse, "there is already an index named %s", zName);
eDbFree(zName);
return;
}
pTable = eDbMalloc( sizeof(Table) );
if( pTable==0 ){
eDbFree(zName);
return;
}
pTable->zName = zName;
pTable->nCol = 0;
pTable->aCol = 0;
pTable->iPKey = -1;
pTable->pIndex = 0;
if( pParse->pNewTable ) eDbDeleteTable(db, pParse->pNewTable);
pParse->pNewTable = pTable;
}
/*
** Add a new column to the table currently being constructed.
*/
void eDbAddColumn(Parser *pParse, Token *pName){
Table *p;
int i;
char *z = 0;
Column *pCol;
if( (p = pParse->pNewTable)==0 ) return;
eDbSetNString(&z, pName->z, pName->n, 0);
if( z==0 ) return;
eDbDequote(z);
for(i=0; i<p->nCol; i++){
if( eDbStrICmp(z, p->aCol[i].zName)==0 ){
eDbErrorMsg(pParse, "duplicate column name: %s", z);
eDbFree(z);
return;
}
}
if( (p->nCol & 0x7)==0 ){
Column *aNew;
aNew = eDbRealloc( 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->type = eDb_SO_UNK;
p->nCol++;
}
/*
** 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 eDbAddColumnType(Parser *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);
eDbSetNString(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;
pCol->type = eDbCollateType(z, n);
}
/*
** 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 eDbAddDefaultValue(Parser *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 ){
eDbSetNString(pz, "-", 1, pVal->z, pVal->n, 0);
}else{
eDbSetNString(pz, pVal->z, pVal->n, 0);
}
eDbDequote(*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 eDbAddPrimaryKey(Parser *pParse, IdList *pList){
Table *pTab = pParse->pNewTable;
char *zType = 0;
int iCol = -1, i;
if( pTab==0 ) goto primary_key_exit;
if( pTab->hasPrimKey ){
eDbErrorMsg(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( eDbStrICmp(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(zType && eDbStrNICmp(zType, "INT",3)==0 ){
pTab->iPKey = iCol;
}else{
eDbCreateIndex(pParse, 0, 0, pList, OP_Unique, 0, 0);
pList = 0;
}
primary_key_exit:
eDbIdListDelete(pList);
return;
}
/*
** Return the appropriate collating type given a type name.
**
** The collation type is text (eDb_SO_TEXT) if the type
** name contains the character stream "text" or "char".
** the type is eDb_SO_DEC if name contains the character stream "decimal"
** Any other type name is collated as numeric(eDb_SO_NUM).
*/
int eDbCollateType(const char *zType, int nType){
int i;
for(i=0; i<nType-3; i++){
int c = *(zType++) | 0x60;
if( c=='c' && eDbStrNICmp(zType, "har", 3)==0 ){
return eDb_SO_TEXT;
}
if( c=='v' && eDbStrNICmp(zType, "archar", 6)==0 ){
return eDb_SO_TEXT;
}
if( c=='t' && eDbStrNICmp(zType, "ext", 3)==0 ){
return eDb_SO_TEXT;
}
if( c=='i' && eDbStrNICmp(zType, "nt", 2)==0 ){
return eDb_SO_NUM;
}
if( c=='d' && eDbStrNICmp(zType, "ecimal", 6)==0 ){
return eDb_SO_DEC;
}
}
return eDb_SO_NUM;
}
void eDbEndTable(Parser *pParse, Token *pEnd){
Table *p;
ParseResult *pRes;
eDb *db = pParse->db;
pParse->pResult = 0;
if( (pEnd==0) || pParse->nErr || eDb_malloc_failed ) return;
p = pParse->pNewTable;
if( p==0 ) return;
/*
** Add the table to hash table.
*/
if( pParse->explain==0 && pParse->nErr==0 ){
Table *pOld;
pOld = eDbHashInsert(&db->tblHash,
p->zName, strlen(p->zName)+1, p);
if( pOld ){
/*
** error occured while inserting intto hash table
*/
return;
}
/* need to do create table*/
pParse->pNewTable = 0;
db->nTable++;
pRes = eDbMalloc(sizeof(ParseResult));
pRes->pTable = p;
pRes->op = Op_CreateTable;
pParse->pResult = pRes;
}
}
/*
** Given a token, look up a table with that name. If not found, leave
** an error for the parser to find and return NULL.
*/
Table *eDbTableFromToken(Parser *pParse, Token *pTok){
char *zName;
Table *pTab;
zName = eDbTableNameFromToken(pTok);
if( zName==0 ) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -