📄 build.c
字号:
pTable->zName, 0); pParse->nErr++; return; } if( !isView && pTable->pSelect ){ sqliteSetString(&pParse->zErrMsg, "use DROP VIEW to delete view ", pTable->zName, 0); pParse->nErr++; return; } /* Generate code to remove the table from the master table ** on disk. */ v = sqliteGetVdbe(pParse); if( v ){ static VdbeOp dropTable[] = { { OP_Rewind, 0, ADDR(8), 0}, { OP_String, 0, 0, 0}, /* 1 */ { OP_MemStore, 1, 1, 0}, { OP_MemLoad, 1, 0, 0}, /* 3 */ { OP_Column, 0, 2, 0}, { OP_Ne, 0, ADDR(7), 0}, { OP_Delete, 0, 0, 0}, { OP_Next, 0, ADDR(3), 0}, /* 7 */ }; Index *pIdx; Trigger *pTrigger; sqliteBeginWriteOperation(pParse, 0, pTable->iDb); /* Drop all triggers associated with the table being dropped */ pTrigger = pTable->pTrigger; while( pTrigger ){ assert( pTrigger->iDb==pTable->iDb || pTrigger->iDb==1 ); sqliteDropTriggerPtr(pParse, pTrigger, 1); if( pParse->explain ){ pTrigger = pTrigger->pNext; }else{ pTrigger = pTable->pTrigger; } } /* Drop all SQLITE_MASTER entries that refer to the table */ sqliteOpenMasterTable(v, pTable->iDb); base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); sqliteVdbeChangeP3(v, base+1, pTable->zName, 0); /* Drop all SQLITE_TEMP_MASTER entries that refer to the table */ if( pTable->iDb!=1 ){ sqliteOpenMasterTable(v, 1); base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); sqliteVdbeChangeP3(v, base+1, pTable->zName, 0); } if( pTable->iDb==0 ){ sqliteChangeCookie(db, v); } sqliteVdbeAddOp(v, OP_Close, 0, 0); if( !isView ){ sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->iDb); for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pIdx->iDb); } } sqliteEndWriteOperation(pParse); } /* Delete the in-memory description of the table. ** ** Exception: if the SQL statement began with the EXPLAIN keyword, ** then no changes should be made. */ if( !pParse->explain ){ sqliteUnlinkAndDeleteTable(db, pTable); db->flags |= SQLITE_InternChanges; } sqliteViewResetAll(db, iDb);}/*** This routine constructs a P3 string suitable for an OP_MakeIdxKey** opcode and adds that P3 string to the most recently inserted instruction** in the virtual machine. The P3 string consists of a single character** for each column in the index pIdx of table pTab. If the column uses** a numeric sort order, then the P3 string character corresponding to** that column is 'n'. If the column uses a text sort order, then the** P3 string is 't'. See the OP_MakeIdxKey opcode documentation for** additional information. See also the sqliteAddKeyType() routine.*/void sqliteAddIdxKeyType(Vdbe *v, Index *pIdx){ char *zType; Table *pTab; int i, n; assert( pIdx!=0 && pIdx->pTable!=0 ); pTab = pIdx->pTable; n = pIdx->nColumn; zType = sqliteMallocRaw( n+1 ); if( zType==0 ) return; for(i=0; i<n; i++){ int iCol = pIdx->aiColumn[i]; assert( iCol>=0 && iCol<pTab->nCol ); if( (pTab->aCol[iCol].sortOrder & SQLITE_SO_TYPEMASK)==SQLITE_SO_TEXT ){ zType[i] = 't'; }else{ zType[i] = 'n'; } } zType[n] = 0; sqliteVdbeChangeP3(v, -1, zType, n); sqliteFree(zType);}/*** 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 sqliteEndTable().**** The foreign key is set for IMMEDIATE processing. A subsequent call** to sqliteDeferForeignKey() might change this to DEFERRED.*/void sqliteCreateForeignKey( Parse *pParse, /* Parsing context */ IdList *pFromCol, /* Columns in this table that point to other table */ Token *pTo, /* Name of the other table */ IdList *pToCol, /* Columns in the other table */ int flags /* Conflict resolution algorithms. */){ Table *p = pParse->pNewTable; int nByte; int i; int nCol; char *z; FKey *pFKey = 0; 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->nId!=1 ){ sqliteSetNString(&pParse->zErrMsg, "foreign key on ", -1, p->aCol[iCol].zName, -1, " should reference only one column of table ", -1, pTo->z, pTo->n, 0); pParse->nErr++; goto fk_end; } nCol = 1; }else if( pToCol && pToCol->nId!=pFromCol->nId ){ sqliteSetString(&pParse->zErrMsg, "number of columns in foreign key does not match the number of " "columns in the referenced table", 0); pParse->nErr++; goto fk_end; }else{ nCol = pFromCol->nId; } nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1; if( pToCol ){ for(i=0; i<pToCol->nId; 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( sqliteStrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){ pFKey->aCol[i].iFrom = j; break; } } if( j>=p->nCol ){ sqliteSetString(&pParse->zErrMsg, "unknown column \"", pFromCol->a[i].zName, "\" in foreign key definition", 0); pParse->nErr++; 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 = (flags >> 16 ) & 0xff; /* Link the foreign key to the table as the last step. */ p->pFKey = pFKey; pFKey = 0;fk_end: sqliteFree(pFKey); sqliteIdListDelete(pFromCol); sqliteIdListDelete(pToCol);}/*** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED** clause is seen as part of a foreign key definition. The isDeferred** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE.** The behavior of the most recently created foreign key is adjusted** accordingly.*/void sqliteDeferForeignKey(Parse *pParse, int isDeferred){ Table *pTab; FKey *pFKey; if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return; pFKey->isDeferred = isDeferred;}/*** Create a new index for an SQL table. pIndex is the name of the index ** and pTable is the name of the table that is to be indexed. Both will ** be NULL for a primary key or an index that is created to satisfy a** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable** as the table to be indexed. pParse->pNewTable is a table that is** currently being constructed by a CREATE TABLE statement.**** pList is a list of columns to be indexed. pList will be NULL if this** is a primary key or unique-constraint on the most recent column added** to the table currently under construction. */void sqliteCreateIndex( Parse *pParse, /* All information about this parse */ Token *pName, /* Name of the index. May be NULL */ SrcList *pTable, /* Name of the table to index. Use pParse->pNewTable if 0 */ IdList *pList, /* A list of columns to be indexed */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ int isTemp, /* True if this is a temporary index */ Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */ Token *pEnd /* The ")" that closes the CREATE INDEX statement */){ Table *pTab; /* Table to be indexed */ Index *pIndex; /* The index to be created */ char *zName = 0; int i, j; Token nullId; /* Fake token for an empty ID list */ DbFixer sFix; /* For assigning database names to pTable */ sqlite *db = pParse->db; if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index; if( !isTemp && pParse->initFlag && sqliteFixInit(&sFix, pParse, pParse->iDb, "index", pName) && sqliteFixSrcList(&sFix, pTable) ){ goto exit_create_index; } /* ** Find the table that is to be indexed. Return early if not found. */ if( pTable!=0 ){ assert( pName!=0 ); assert( pTable->nSrc==1 ); pTab = sqliteSrcListLookup(pParse, pTable); }else{ assert( pName==0 ); pTab = pParse->pNewTable; } if( pTab==0 || pParse->nErr ) goto exit_create_index; if( pTab->readOnly ){ sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " may not be indexed", 0); pParse->nErr++; goto exit_create_index; } if( !isTemp && pTab->iDb>=2 && pParse->initFlag==0 ){ sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " may not have non-temporary indices added", 0); pParse->nErr++; goto exit_create_index; } if( pTab->pSelect ){ sqliteSetString(&pParse->zErrMsg, "views may not be indexed", 0); pParse->nErr++; goto exit_create_index; } if( pTab->iDb==1 ){ isTemp = 1; } /* ** Find the name of the index. Make sure there is not already another ** index or table with the same name. ** ** Exception: If we are reading the names of permanent indices from the ** sqlite_master table (because some other process changed the schema) and ** one of the index names collides with the name of a temporary table or ** index, then we will continue to process this index. ** ** If pName==0 it means that we are ** dealing with a primary key or UNIQUE constraint. We have to invent our ** own name. */ if( pName && !pParse->initFlag ){ Index *pISameName; /* Another index with the same name */ Table *pTSameName; /* A table with same name as the index */ zName = sqliteStrNDup(pName->z, pName->n); if( zName==0 ) goto exit_create_index; if( (pISameName = sqliteFindIndex(db, zName, 0))!=0 ){ sqliteSetString(&pParse->zErrMsg, "index ", zName, " already exists", 0); pParse->nErr++; goto exit_create_index; } if( (pTSameName = sqliteFindTable(db, zName, 0))!=0 ){ sqliteSetString(&pParse->zErrMsg, "there is already a table named ", zName, 0); pParse->nErr++; goto exit_create_index; } }else if( pName==0 ){ char zBuf[30]; int n; Index *pLoop; for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} sprintf(zBuf,"%d)",n); zName = 0; sqliteSetString(&zName, "(", pTab->zName, " autoindex ", zBuf, 0); if( zName==0 ) goto exit_create_index; }else{ zName = sqliteStrNDup(pName->z, pName->n); } /* Check for authorization to create an index. */#ifndef SQLITE_OMIT_AUTHORIZATION { const char *zDb = db->aDb[pTab->iDb].zName; assert( isTemp==0 || isTemp==1 ); assert( pTab->iDb==pParse->iDb || isTemp==1 ); if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ goto exit_create_index; } i = SQLITE_CREATE_INDEX; if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX; if( sqliteAuthCheck(pParse, i, zName, pTab->zName, zDb) ){ goto exit_create_index; } }#endif /* If pList==0, it means this routine was called to make a primary ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ nullId.z = pTab->aCol[pTab->nCol-1].zName; nullId.n = strlen(nullId.z); pList = sqliteIdListAppend(0, &nullId); if( pList==0 ) goto exit_create_index; } /* ** Allocate the index structure. */ pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + sizeof(int)*pList->nId ); if( pIndex==0 ) goto exit_create_index; pIndex->aiColumn = (int*)&pIndex[1]; pIndex->zName = (char*)&pIndex->aiColumn[pList->nId]; strcpy(pIndex->zName, zName); pIndex->pTable = pTab; pIndex->nColumn = pList->nId; pIndex->onError = onError; pIndex->autoIndex = pName==0; pIndex->iDb = isTemp ? 1 : pParse->iDb; /* Scan the names of the columns of the table to be indexed and ** load the column indices into the Index structure. Report an error ** if any column is not found. */ for(i=0; i<pList->nId; i++){ for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break; } if( j>=pTab->nCol ){ sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " has no column named ", pList->a[i].zName, 0); pParse->nErr++; sqliteFree(pIndex); goto exit_create_index; } pIndex->aiColumn[i] = j; } /* Link the new Index structure to its table and to the other ** in-memory database structures.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -