| Index: third_party/sqlite/src/src/build.c
|
| diff --git a/third_party/sqlite/src/src/build.c b/third_party/sqlite/src/src/build.c
|
| index d5846daeccc4e3776eb1ece83f3a429ba5f4ff08..323a6160fd0a027280242c483042865ef3cfb786 100644
|
| --- a/third_party/sqlite/src/src/build.c
|
| +++ b/third_party/sqlite/src/src/build.c
|
| @@ -21,8 +21,6 @@
|
| ** BEGIN TRANSACTION
|
| ** COMMIT
|
| ** ROLLBACK
|
| -**
|
| -** $Id: build.c,v 1.557 2009/07/24 17:58:53 danielk1977 Exp $
|
| */
|
| #include "sqliteInt.h"
|
|
|
| @@ -153,7 +151,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
| ** on each used database.
|
| */
|
| if( pParse->cookieGoto>0 ){
|
| - u32 mask;
|
| + yDbMask mask;
|
| int iDb;
|
| sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
|
| for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
| @@ -161,7 +159,10 @@ void sqlite3FinishCoding(Parse *pParse){
|
| sqlite3VdbeUsesBtree(v, iDb);
|
| sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
| if( db->init.busy==0 ){
|
| - sqlite3VdbeAddOp2(v,OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + sqlite3VdbeAddOp3(v, OP_VerifyCookie,
|
| + iDb, pParse->cookieValue[iDb],
|
| + db->aDb[iDb].pSchema->iGeneration);
|
| }
|
| }
|
| #ifndef SQLITE_OMIT_VIRTUALTABLE
|
| @@ -199,12 +200,15 @@ void sqlite3FinishCoding(Parse *pParse){
|
| sqlite3VdbeTrace(v, trace);
|
| #endif
|
| assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */
|
| + /* A minimum of one cursor is required if autoincrement is used
|
| + * See ticket [a696379c1f08866] */
|
| + if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
|
| sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
|
| pParse->nTab, pParse->nMaxArg, pParse->explain,
|
| pParse->isMultiWrite && pParse->mayAbort);
|
| pParse->rc = SQLITE_DONE;
|
| pParse->colNamesSet = 0;
|
| - }else if( pParse->rc==SQLITE_OK ){
|
| + }else{
|
| pParse->rc = SQLITE_ERROR;
|
| }
|
| pParse->nTab = 0;
|
| @@ -271,9 +275,12 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
| int nName;
|
| assert( zName!=0 );
|
| nName = sqlite3Strlen30(zName);
|
| + /* All mutexes are required for schema access. Make sure we hold them. */
|
| + assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
| for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
| int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
| if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
|
| + assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
| p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, nName);
|
| if( p ) break;
|
| }
|
| @@ -333,11 +340,14 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
|
| Index *p = 0;
|
| int i;
|
| int nName = sqlite3Strlen30(zName);
|
| + /* All mutexes are required for schema access. Make sure we hold them. */
|
| + assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
| for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
| int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
| Schema *pSchema = db->aDb[j].pSchema;
|
| assert( pSchema );
|
| if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
|
| + assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
| p = sqlite3HashFind(&pSchema->idxHash, zName, nName);
|
| if( p ) break;
|
| }
|
| @@ -347,34 +357,15 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
|
| /*
|
| ** Reclaim the memory used by an index
|
| */
|
| -static void freeIndex(Index *p){
|
| - sqlite3 *db = p->pTable->dbMem;
|
| +static void freeIndex(sqlite3 *db, Index *p){
|
| #ifndef SQLITE_OMIT_ANALYZE
|
| - sqlite3DeleteIndexSamples(p);
|
| + sqlite3DeleteIndexSamples(db, p);
|
| #endif
|
| sqlite3DbFree(db, p->zColAff);
|
| sqlite3DbFree(db, p);
|
| }
|
|
|
| /*
|
| -** Remove the given index from the index hash table, and free
|
| -** its memory structures.
|
| -**
|
| -** The index is removed from the database hash tables but
|
| -** it is not unlinked from the Table that it indexes.
|
| -** Unlinking from the Table must be done by the calling function.
|
| -*/
|
| -static void sqlite3DeleteIndex(Index *p){
|
| - Index *pOld;
|
| - const char *zName = p->zName;
|
| -
|
| - pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName,
|
| - sqlite3Strlen30(zName), 0);
|
| - assert( pOld==0 || pOld==p );
|
| - freeIndex(p);
|
| -}
|
| -
|
| -/*
|
| ** For the index called zIdxName which is found in the database iDb,
|
| ** unlike that index from its Table then remove the index from
|
| ** the index hash table and free all memory structures associated
|
| @@ -383,11 +374,13 @@ static void sqlite3DeleteIndex(Index *p){
|
| void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
| Index *pIndex;
|
| int len;
|
| - Hash *pHash = &db->aDb[iDb].pSchema->idxHash;
|
| + Hash *pHash;
|
|
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + pHash = &db->aDb[iDb].pSchema->idxHash;
|
| len = sqlite3Strlen30(zIdxName);
|
| pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0);
|
| - if( pIndex ){
|
| + if( ALWAYS(pIndex) ){
|
| if( pIndex->pTable->pIndex==pIndex ){
|
| pIndex->pTable->pIndex = pIndex->pNext;
|
| }else{
|
| @@ -400,7 +393,7 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
| p->pNext = pIndex->pNext;
|
| }
|
| }
|
| - freeIndex(pIndex);
|
| + freeIndex(db, pIndex);
|
| }
|
| db->flags |= SQLITE_InternChanges;
|
| }
|
| @@ -412,26 +405,42 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
| ** if there were schema changes during the transaction or if a
|
| ** schema-cookie mismatch occurs.
|
| **
|
| -** If iDb==0 then reset the internal schema tables for all database
|
| -** files. If iDb>=1 then reset the internal schema for only the
|
| +** If iDb<0 then reset the internal schema tables for all database
|
| +** files. If iDb>=0 then reset the internal schema for only the
|
| ** single file indicated.
|
| */
|
| void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
|
| int i, j;
|
| - assert( iDb>=0 && iDb<db->nDb );
|
| + assert( iDb<db->nDb );
|
| +
|
| + if( iDb>=0 ){
|
| + /* Case 1: Reset the single schema identified by iDb */
|
| + Db *pDb = &db->aDb[iDb];
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + assert( pDb->pSchema!=0 );
|
| + sqlite3SchemaClear(pDb->pSchema);
|
|
|
| - if( iDb==0 ){
|
| - sqlite3BtreeEnterAll(db);
|
| + /* If any database other than TEMP is reset, then also reset TEMP
|
| + ** since TEMP might be holding triggers that reference tables in the
|
| + ** other database.
|
| + */
|
| + if( iDb!=1 ){
|
| + pDb = &db->aDb[1];
|
| + assert( pDb->pSchema!=0 );
|
| + sqlite3SchemaClear(pDb->pSchema);
|
| + }
|
| + return;
|
| }
|
| - for(i=iDb; i<db->nDb; i++){
|
| + /* Case 2 (from here to the end): Reset all schemas for all attached
|
| + ** databases. */
|
| + assert( iDb<0 );
|
| + sqlite3BtreeEnterAll(db);
|
| + for(i=0; i<db->nDb; i++){
|
| Db *pDb = &db->aDb[i];
|
| if( pDb->pSchema ){
|
| - assert(i==1 || (pDb->pBt && sqlite3BtreeHoldsMutex(pDb->pBt)));
|
| - sqlite3SchemaFree(pDb->pSchema);
|
| + sqlite3SchemaClear(pDb->pSchema);
|
| }
|
| - if( iDb>0 ) return;
|
| }
|
| - assert( iDb==0 );
|
| db->flags &= ~SQLITE_InternChanges;
|
| sqlite3VtabUnlockList(db);
|
| sqlite3BtreeLeaveAll(db);
|
| @@ -471,13 +480,12 @@ void sqlite3CommitInternalChanges(sqlite3 *db){
|
| }
|
|
|
| /*
|
| -** Clear the column names from a table or view.
|
| +** Delete memory allocated for the column names of a table or view (the
|
| +** Table.aCol[] array).
|
| */
|
| -static void sqliteResetColumnNames(Table *pTable){
|
| +static void sqliteDeleteColumnNames(sqlite3 *db, Table *pTable){
|
| int i;
|
| Column *pCol;
|
| - sqlite3 *db = pTable->dbMem;
|
| - testcase( db==0 );
|
| assert( pTable!=0 );
|
| if( (pCol = pTable->aCol)!=0 ){
|
| for(i=0; i<pTable->nCol; i++, pCol++){
|
| @@ -489,8 +497,6 @@ static void sqliteResetColumnNames(Table *pTable){
|
| }
|
| sqlite3DbFree(db, pTable->aCol);
|
| }
|
| - pTable->aCol = 0;
|
| - pTable->nCol = 0;
|
| }
|
|
|
| /*
|
| @@ -502,48 +508,45 @@ static void sqliteResetColumnNames(Table *pTable){
|
| ** memory structures of the indices and foreign keys associated with
|
| ** the table.
|
| */
|
| -void sqlite3DeleteTable(Table *pTable){
|
| +void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
| Index *pIndex, *pNext;
|
| - FKey *pFKey, *pNextFKey;
|
| - sqlite3 *db;
|
|
|
| - if( pTable==0 ) return;
|
| - db = pTable->dbMem;
|
| - testcase( db==0 );
|
| + assert( !pTable || pTable->nRef>0 );
|
|
|
| /* Do not delete the table until the reference count reaches zero. */
|
| - pTable->nRef--;
|
| - if( pTable->nRef>0 ){
|
| - return;
|
| - }
|
| - assert( pTable->nRef==0 );
|
| + if( !pTable ) return;
|
| + if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
|
|
|
| - /* Delete all indices associated with this table
|
| - */
|
| + /* Delete all indices associated with this table. */
|
| for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
|
| pNext = pIndex->pNext;
|
| assert( pIndex->pSchema==pTable->pSchema );
|
| - sqlite3DeleteIndex(pIndex);
|
| + if( !db || db->pnBytesFreed==0 ){
|
| + char *zName = pIndex->zName;
|
| + TESTONLY ( Index *pOld = ) sqlite3HashInsert(
|
| + &pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0
|
| + );
|
| + assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
| + assert( pOld==pIndex || pOld==0 );
|
| + }
|
| + freeIndex(db, pIndex);
|
| }
|
|
|
| -#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| - /* Delete all foreign keys associated with this table. */
|
| - for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
|
| - pNextFKey = pFKey->pNextFrom;
|
| - sqlite3DbFree(db, pFKey);
|
| - }
|
| -#endif
|
| + /* Delete any foreign keys attached to this table. */
|
| + sqlite3FkDelete(db, pTable);
|
|
|
| /* Delete the Table structure itself.
|
| */
|
| - sqliteResetColumnNames(pTable);
|
| + sqliteDeleteColumnNames(db, pTable);
|
| sqlite3DbFree(db, pTable->zName);
|
| sqlite3DbFree(db, pTable->zColAff);
|
| sqlite3SelectDelete(db, pTable->pSelect);
|
| #ifndef SQLITE_OMIT_CHECK
|
| sqlite3ExprDelete(db, pTable->pCheck);
|
| #endif
|
| - sqlite3VtabClear(pTable);
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + sqlite3VtabClear(db, pTable);
|
| +#endif
|
| sqlite3DbFree(db, pTable);
|
| }
|
|
|
| @@ -557,11 +560,13 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
|
|
|
| assert( db!=0 );
|
| assert( iDb>=0 && iDb<db->nDb );
|
| - assert( zTabName && zTabName[0] );
|
| + assert( zTabName );
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */
|
| pDb = &db->aDb[iDb];
|
| p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName,
|
| sqlite3Strlen30(zTabName),0);
|
| - sqlite3DeleteTable(p);
|
| + sqlite3DeleteTable(db, p);
|
| db->flags |= SQLITE_InternChanges;
|
| }
|
|
|
| @@ -753,8 +758,9 @@ void sqlite3StartTable(
|
| */
|
| iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
| if( iDb<0 ) return;
|
| - if( !OMIT_TEMPDB && isTemp && iDb>1 ){
|
| - /* If creating a temp table, the name may not be qualified */
|
| + if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
|
| + /* If creating a temp table, the name may not be qualified. Unless
|
| + ** the database name is "temp" anyway. */
|
| sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
|
| return;
|
| }
|
| @@ -802,17 +808,21 @@ void sqlite3StartTable(
|
| ** collisions.
|
| */
|
| if( !IN_DECLARE_VTAB ){
|
| + char *zDb = db->aDb[iDb].zName;
|
| if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
| goto begin_table_error;
|
| }
|
| - pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
|
| + pTable = sqlite3FindTable(db, zName, zDb);
|
| if( pTable ){
|
| if( !noErr ){
|
| sqlite3ErrorMsg(pParse, "table %T already exists", pName);
|
| + }else{
|
| + assert( !db->init.busy );
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| }
|
| goto begin_table_error;
|
| }
|
| - if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
|
| + if( sqlite3FindIndex(db, zName, zDb)!=0 ){
|
| sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
|
| goto begin_table_error;
|
| }
|
| @@ -829,7 +839,7 @@ void sqlite3StartTable(
|
| pTable->iPKey = -1;
|
| pTable->pSchema = db->aDb[iDb].pSchema;
|
| pTable->nRef = 1;
|
| - pTable->dbMem = 0;
|
| + pTable->nRowEst = 1000000;
|
| assert( pParse->pNewTable==0 );
|
| pParse->pNewTable = pTable;
|
|
|
| @@ -839,6 +849,7 @@ void sqlite3StartTable(
|
| */
|
| #ifndef SQLITE_OMIT_AUTOINCREMENT
|
| if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| pTable->pSchema->pSeqTab = pTable;
|
| }
|
| #endif
|
| @@ -1174,7 +1185,11 @@ void sqlite3AddPrimaryKey(
|
| "INTEGER PRIMARY KEY");
|
| #endif
|
| }else{
|
| - sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0);
|
| + Index *p;
|
| + p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0);
|
| + if( p ){
|
| + p->autoIndex = 2;
|
| + }
|
| pList = 0;
|
| }
|
|
|
| @@ -1295,6 +1310,7 @@ void sqlite3ChangeCookie(Parse *pParse, int iDb){
|
| int r1 = sqlite3GetTempReg(pParse);
|
| sqlite3 *db = pParse->db;
|
| Vdbe *v = pParse->pVdbe;
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| sqlite3VdbeAddOp2(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, r1);
|
| sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, r1);
|
| sqlite3ReleaseTempReg(pParse, r1);
|
| @@ -1377,7 +1393,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
| zEnd = "\n)";
|
| }
|
| n += 35 + 6*p->nCol;
|
| - zStmt = sqlite3Malloc( n );
|
| + zStmt = sqlite3DbMallocRaw(0, n);
|
| if( zStmt==0 ){
|
| db->mallocFailed = 1;
|
| return 0;
|
| @@ -1402,7 +1418,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
| zSep = zSep2;
|
| identPut(zStmt, &k, pCol->zName);
|
| assert( pCol->affinity-SQLITE_AFF_TEXT >= 0 );
|
| - assert( pCol->affinity-SQLITE_AFF_TEXT < sizeof(azType)/sizeof(azType[0]) );
|
| + assert( pCol->affinity-SQLITE_AFF_TEXT < ArraySize(azType) );
|
| testcase( pCol->affinity==SQLITE_AFF_TEXT );
|
| testcase( pCol->affinity==SQLITE_AFF_NONE );
|
| testcase( pCol->affinity==SQLITE_AFF_NUMERIC );
|
| @@ -1558,7 +1574,7 @@ void sqlite3EndTable(
|
| p->aCol = pSelTab->aCol;
|
| pSelTab->nCol = 0;
|
| pSelTab->aCol = 0;
|
| - sqlite3DeleteTable(pSelTab);
|
| + sqlite3DeleteTable(db, pSelTab);
|
| }
|
| }
|
|
|
| @@ -1597,6 +1613,7 @@ void sqlite3EndTable(
|
| */
|
| if( p->tabFlags & TF_Autoincrement ){
|
| Db *pDb = &db->aDb[iDb];
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| if( pDb->pSchema->pSeqTab==0 ){
|
| sqlite3NestedParse(pParse,
|
| "CREATE TABLE %Q.sqlite_sequence(name,seq)",
|
| @@ -1617,6 +1634,7 @@ void sqlite3EndTable(
|
| if( db->init.busy ){
|
| Table *pOld;
|
| Schema *pSchema = p->pSchema;
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName,
|
| sqlite3Strlen30(p->zName),p);
|
| if( pOld ){
|
| @@ -1672,12 +1690,10 @@ void sqlite3CreateView(
|
| }
|
| sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
|
| p = pParse->pNewTable;
|
| - if( p==0 ){
|
| + if( p==0 || pParse->nErr ){
|
| sqlite3SelectDelete(db, pSelect);
|
| return;
|
| }
|
| - assert( pParse->nErr==0 ); /* If sqlite3StartTable return non-NULL then
|
| - ** there could not have been an error */
|
| sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
| iDb = sqlite3SchemaToIndex(db, p->pSchema);
|
| if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
|
| @@ -1802,7 +1818,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
| pTable->aCol = pSelTab->aCol;
|
| pSelTab->nCol = 0;
|
| pSelTab->aCol = 0;
|
| - sqlite3DeleteTable(pSelTab);
|
| + sqlite3DeleteTable(db, pSelTab);
|
| + assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
| pTable->pSchema->flags |= DB_UnresetViews;
|
| }else{
|
| pTable->nCol = 0;
|
| @@ -1823,11 +1840,14 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
| */
|
| static void sqliteViewResetAll(sqlite3 *db, int idx){
|
| HashElem *i;
|
| + assert( sqlite3SchemaMutexHeld(db, idx, 0) );
|
| if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
|
| for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
|
| Table *pTab = sqliteHashData(i);
|
| if( pTab->pSelect ){
|
| - sqliteResetColumnNames(pTab);
|
| + sqliteDeleteColumnNames(db, pTab);
|
| + pTab->aCol = 0;
|
| + pTab->nCol = 0;
|
| }
|
| }
|
| DbClearProperty(db, idx, DB_UnresetViews);
|
| @@ -1854,10 +1874,13 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
|
| ** in order to be certain that we got the right one.
|
| */
|
| #ifndef SQLITE_OMIT_AUTOVACUUM
|
| -void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
|
| +void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
|
| HashElem *pElem;
|
| Hash *pHash;
|
| + Db *pDb;
|
|
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + pDb = &db->aDb[iDb];
|
| pHash = &pDb->pSchema->tblHash;
|
| for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){
|
| Table *pTab = sqliteHashData(pElem);
|
| @@ -1977,13 +2000,13 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
| }
|
| assert( pParse->nErr==0 );
|
| assert( pName->nSrc==1 );
|
| + if( noErr ) db->suppressErr++;
|
| pTab = sqlite3LocateTable(pParse, isView,
|
| pName->a[0].zName, pName->a[0].zDatabase);
|
| + if( noErr ) db->suppressErr--;
|
|
|
| if( pTab==0 ){
|
| - if( noErr ){
|
| - sqlite3ErrorClear(pParse);
|
| - }
|
| + if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
| goto exit_drop_table;
|
| }
|
| iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| @@ -2063,6 +2086,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
| sqlite3VdbeAddOp0(v, OP_VBegin);
|
| }
|
| #endif
|
| + sqlite3FkDropTable(pParse, pName, pTab);
|
|
|
| /* Drop all triggers associated with the table being dropped. Code
|
| ** is generated to remove entries from sqlite_master and/or
|
| @@ -2153,6 +2177,7 @@ void sqlite3CreateForeignKey(
|
| sqlite3 *db = pParse->db;
|
| #ifndef SQLITE_OMIT_FOREIGN_KEY
|
| FKey *pFKey = 0;
|
| + FKey *pNextTo;
|
| Table *p = pParse->pNewTable;
|
| int nByte;
|
| int i;
|
| @@ -2227,9 +2252,22 @@ void sqlite3CreateForeignKey(
|
| }
|
| }
|
| pFKey->isDeferred = 0;
|
| - pFKey->deleteConf = (u8)(flags & 0xff);
|
| - pFKey->updateConf = (u8)((flags >> 8 ) & 0xff);
|
| - pFKey->insertConf = (u8)((flags >> 16 ) & 0xff);
|
| + pFKey->aAction[0] = (u8)(flags & 0xff); /* ON DELETE action */
|
| + pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); /* ON UPDATE action */
|
| +
|
| + assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
|
| + pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash,
|
| + pFKey->zTo, sqlite3Strlen30(pFKey->zTo), (void *)pFKey
|
| + );
|
| + if( pNextTo==pFKey ){
|
| + db->mallocFailed = 1;
|
| + goto fk_end;
|
| + }
|
| + if( pNextTo ){
|
| + assert( pNextTo->pPrevTo==0 );
|
| + pFKey->pNextTo = pNextTo;
|
| + pNextTo->pPrevTo = pFKey;
|
| + }
|
|
|
| /* Link the foreign key to the table as the last step.
|
| */
|
| @@ -2255,7 +2293,7 @@ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
|
| Table *pTab;
|
| FKey *pFKey;
|
| if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return;
|
| - assert( isDeferred==0 || isDeferred==1 );
|
| + assert( isDeferred==0 || isDeferred==1 ); /* EV: R-30323-21917 */
|
| pFKey->isDeferred = (u8)isDeferred;
|
| #endif
|
| }
|
| @@ -2350,8 +2388,12 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
| ** 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.
|
| +**
|
| +** If the index is created successfully, return a pointer to the new Index
|
| +** structure. This is used by sqlite3AddPrimaryKey() to mark the index
|
| +** as the tables primary key (Index.autoIndex==2).
|
| */
|
| -void sqlite3CreateIndex(
|
| +Index *sqlite3CreateIndex(
|
| Parse *pParse, /* All information about this parse */
|
| Token *pName1, /* First part of index name. May be NULL */
|
| Token *pName2, /* Second part of index name. May be NULL */
|
| @@ -2363,6 +2405,7 @@ void sqlite3CreateIndex(
|
| int sortOrder, /* Sort order of primary key when pList==NULL */
|
| int ifNotExist /* Omit error if index already exists */
|
| ){
|
| + Index *pRet = 0; /* Pointer to return */
|
| Table *pTab = 0; /* Table to be indexed */
|
| Index *pIndex = 0; /* The index to be created */
|
| char *zName = 0; /* Name of the index */
|
| @@ -2482,6 +2525,9 @@ void sqlite3CreateIndex(
|
| if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
|
| if( !ifNotExist ){
|
| sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
| + }else{
|
| + assert( !db->init.busy );
|
| + sqlite3CodeVerifySchema(pParse, iDb);
|
| }
|
| goto exit_create_index;
|
| }
|
| @@ -2568,6 +2614,7 @@ void sqlite3CreateIndex(
|
| pIndex->onError = (u8)onError;
|
| pIndex->autoIndex = (u8)(pName==0);
|
| pIndex->pSchema = db->aDb[iDb].pSchema;
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
|
|
| /* Check to see if we should honor DESC requests on index columns
|
| */
|
| @@ -2599,6 +2646,7 @@ void sqlite3CreateIndex(
|
| if( j>=pTab->nCol ){
|
| sqlite3ErrorMsg(pParse, "table %s has no column named %s",
|
| pTab->zName, zColName);
|
| + pParse->checkSchema = 1;
|
| goto exit_create_index;
|
| }
|
| pIndex->aiColumn[i] = j;
|
| @@ -2696,6 +2744,7 @@ void sqlite3CreateIndex(
|
| */
|
| if( db->init.busy ){
|
| Index *p;
|
| + assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
| p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
|
| pIndex->zName, sqlite3Strlen30(pIndex->zName),
|
| pIndex);
|
| @@ -2774,7 +2823,8 @@ void sqlite3CreateIndex(
|
| sqlite3RefillIndex(pParse, pIndex, iMem);
|
| sqlite3ChangeCookie(pParse, iDb);
|
| sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
|
| - sqlite3MPrintf(db, "name='%q'", pIndex->zName), P4_DYNAMIC);
|
| + sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName),
|
| + P4_DYNAMIC);
|
| sqlite3VdbeAddOp1(v, OP_Expire, 0);
|
| }
|
| }
|
| @@ -2798,19 +2848,20 @@ void sqlite3CreateIndex(
|
| pIndex->pNext = pOther->pNext;
|
| pOther->pNext = pIndex;
|
| }
|
| + pRet = pIndex;
|
| pIndex = 0;
|
| }
|
|
|
| /* Clean up before exiting */
|
| exit_create_index:
|
| if( pIndex ){
|
| - sqlite3_free(pIndex->zColAff);
|
| + sqlite3DbFree(db, pIndex->zColAff);
|
| sqlite3DbFree(db, pIndex);
|
| }
|
| sqlite3ExprListDelete(db, pList);
|
| sqlite3SrcListDelete(db, pTblName);
|
| sqlite3DbFree(db, zName);
|
| - return;
|
| + return pRet;
|
| }
|
|
|
| /*
|
| @@ -2834,14 +2885,14 @@ exit_create_index:
|
| void sqlite3DefaultRowEst(Index *pIdx){
|
| unsigned *a = pIdx->aiRowEst;
|
| int i;
|
| + unsigned n;
|
| assert( a!=0 );
|
| - a[0] = 1000000;
|
| - for(i=pIdx->nColumn; i>=5; i--){
|
| - a[i] = 5;
|
| - }
|
| - while( i>=1 ){
|
| - a[i] = 11 - i;
|
| - i--;
|
| + a[0] = pIdx->pTable->nRowEst;
|
| + if( a[0]<10 ) a[0] = 10;
|
| + n = 10;
|
| + for(i=1; i<=pIdx->nColumn; i++){
|
| + a[i] = n;
|
| + if( n>5 ) n--;
|
| }
|
| if( pIdx->onError!=OE_None ){
|
| a[pIdx->nColumn] = 1;
|
| @@ -2870,6 +2921,8 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
| if( pIndex==0 ){
|
| if( !ifExists ){
|
| sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
|
| + }else{
|
| + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
| }
|
| pParse->checkSchema = 1;
|
| goto exit_drop_index;
|
| @@ -2901,7 +2954,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
| if( v ){
|
| sqlite3BeginWriteOperation(pParse, 1, iDb);
|
| sqlite3NestedParse(pParse,
|
| - "DELETE FROM %Q.%s WHERE name=%Q",
|
| + "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
|
| db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
| pIndex->zName
|
| );
|
| @@ -3183,7 +3236,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
| sqlite3DbFree(db, pItem->zName);
|
| sqlite3DbFree(db, pItem->zAlias);
|
| sqlite3DbFree(db, pItem->zIndex);
|
| - sqlite3DeleteTable(pItem->pTab);
|
| + sqlite3DeleteTable(db, pItem->pTab);
|
| sqlite3SelectDelete(db, pItem->pSelect);
|
| sqlite3ExprDelete(db, pItem->pOn);
|
| sqlite3IdListDelete(db, pItem->pUsing);
|
| @@ -3366,7 +3419,7 @@ void sqlite3Savepoint(Parse *pParse, int op, Token *pName){
|
| if( zName ){
|
| Vdbe *v = sqlite3GetVdbe(pParse);
|
| #ifndef SQLITE_OMIT_AUTHORIZATION
|
| - static const char *az[] = { "BEGIN", "RELEASE", "ROLLBACK" };
|
| + static const char * const az[] = { "BEGIN", "RELEASE", "ROLLBACK" };
|
| assert( !SAVEPOINT_BEGIN && SAVEPOINT_RELEASE==1 && SAVEPOINT_ROLLBACK==2 );
|
| #endif
|
| if( !v || sqlite3AuthCheck(pParse, SQLITE_SAVEPOINT, az[op], zName, 0) ){
|
| @@ -3385,6 +3438,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
| sqlite3 *db = pParse->db;
|
| if( db->aDb[1].pBt==0 && !pParse->explain ){
|
| int rc;
|
| + Btree *pBt;
|
| static const int flags =
|
| SQLITE_OPEN_READWRITE |
|
| SQLITE_OPEN_CREATE |
|
| @@ -3392,18 +3446,19 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
| SQLITE_OPEN_DELETEONCLOSE |
|
| SQLITE_OPEN_TEMP_DB;
|
|
|
| - rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags,
|
| - &db->aDb[1].pBt);
|
| + rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags);
|
| if( rc!=SQLITE_OK ){
|
| sqlite3ErrorMsg(pParse, "unable to open a temporary database "
|
| "file for storing temporary tables");
|
| pParse->rc = rc;
|
| return 1;
|
| }
|
| - assert( (db->flags & SQLITE_InTrans)==0 || db->autoCommit );
|
| + db->aDb[1].pBt = pBt;
|
| assert( db->aDb[1].pSchema );
|
| - sqlite3PagerJournalMode(sqlite3BtreePager(db->aDb[1].pBt),
|
| - db->dfltJournalMode);
|
| + if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
|
| + db->mallocFailed = 1;
|
| + return 1;
|
| + }
|
| }
|
| return 0;
|
| }
|
| @@ -3440,12 +3495,13 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
| }
|
| if( iDb>=0 ){
|
| sqlite3 *db = pToplevel->db;
|
| - int mask;
|
| + yDbMask mask;
|
|
|
| assert( iDb<db->nDb );
|
| assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
| assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
| - mask = 1<<iDb;
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + mask = ((yDbMask)1)<<iDb;
|
| if( (pToplevel->cookieMask & mask)==0 ){
|
| pToplevel->cookieMask |= mask;
|
| pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
|
| @@ -3457,6 +3513,21 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
| }
|
|
|
| /*
|
| +** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each
|
| +** attached database. Otherwise, invoke it for the database named zDb only.
|
| +*/
|
| +void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){
|
| + sqlite3 *db = pParse->db;
|
| + int i;
|
| + for(i=0; i<db->nDb; i++){
|
| + Db *pDb = &db->aDb[i];
|
| + if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){
|
| + sqlite3CodeVerifySchema(pParse, i);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| ** Generate VDBE code that prepares for doing an operation that
|
| ** might change the database.
|
| **
|
| @@ -3472,13 +3543,37 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
| void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
|
| Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| sqlite3CodeVerifySchema(pParse, iDb);
|
| - pToplevel->writeMask |= 1<<iDb;
|
| + pToplevel->writeMask |= ((yDbMask)1)<<iDb;
|
| pToplevel->isMultiWrite |= setStatement;
|
| }
|
|
|
| +/*
|
| +** Indicate that the statement currently under construction might write
|
| +** more than one entry (example: deleting one row then inserting another,
|
| +** inserting multiple rows in a table, or inserting a row and index entries.)
|
| +** If an abort occurs after some of these writes have completed, then it will
|
| +** be necessary to undo the completed writes.
|
| +*/
|
| +void sqlite3MultiWrite(Parse *pParse){
|
| + Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| + pToplevel->isMultiWrite = 1;
|
| +}
|
| +
|
| /*
|
| -** Set the "may throw abort exception" flag for the statement currently
|
| -** being coded.
|
| +** The code generator calls this routine if is discovers that it is
|
| +** possible to abort a statement prior to completion. In order to
|
| +** perform this abort without corrupting the database, we need to make
|
| +** sure that the statement is protected by a statement transaction.
|
| +**
|
| +** Technically, we only need to set the mayAbort flag if the
|
| +** isMultiWrite flag was previously set. There is a time dependency
|
| +** such that the abort must occur after the multiwrite. This makes
|
| +** some statements involving the REPLACE conflict resolution algorithm
|
| +** go a little faster. But taking advantage of this time dependency
|
| +** makes it more difficult to prove that the code is correct (in
|
| +** particular, it prevents us from writing an effective
|
| +** implementation of sqlite3AssertMayAbort()) and so we have chosen
|
| +** to take the safe route and skip the optimization.
|
| */
|
| void sqlite3MayAbort(Parse *pParse){
|
| Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| @@ -3548,6 +3643,7 @@ static void reindexDatabases(Parse *pParse, char const *zColl){
|
| HashElem *k; /* For looping over tables in pDb */
|
| Table *pTab; /* A table in the database */
|
|
|
| + assert( sqlite3BtreeHoldsAllMutexes(db) ); /* Needed for schema access */
|
| for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
|
| assert( pDb!=0 );
|
| for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
|
|
|