| OLD | NEW |
| (Empty) |
| 1 Index: src/btree.c | |
| 2 =================================================================== | |
| 3 --- src/btree.c 2009-09-09 06:45:19.000000000 -0700 | |
| 4 +++ src/btree.c 2009-09-14 18:17:53.000000000 -0700 | |
| 5 @@ -24,6 +24,12 @@ | |
| 6 static const char zMagicHeader[] = SQLITE_FILE_HEADER; | |
| 7 | |
| 8 /* | |
| 9 +** The header string that appears at the beginning of a SQLite | |
| 10 +** database which has been poisoned. | |
| 11 +*/ | |
| 12 +static const char zPoisonHeader[] = "SQLite poison 3"; | |
| 13 + | |
| 14 +/* | |
| 15 ** Set this global variable to 1 to enable tracing using the TRACE | |
| 16 ** macro. | |
| 17 */ | |
| 18 @@ -2337,6 +2343,7 @@ | |
| 19 if( rc ) return rc; | |
| 20 memcpy(data, zMagicHeader, sizeof(zMagicHeader)); | |
| 21 assert( sizeof(zMagicHeader)==16 ); | |
| 22 + assert( sizeof(zMagicHeader)==sizeof(zPoisonHeader) ); | |
| 23 put2byte(&data[16], pBt->pageSize); | |
| 24 data[18] = 1; | |
| 25 data[19] = 1; | |
| 26 @@ -7804,4 +7811,72 @@ | |
| 27 assert(!pCur->aOverflow); | |
| 28 pCur->isIncrblobHandle = 1; | |
| 29 } | |
| 30 + | |
| 31 +/* Poison the db so that other clients error out as quickly as | |
| 32 +** possible. | |
| 33 +*/ | |
| 34 +int sqlite3Poison(sqlite3 *db){ | |
| 35 + int rc; | |
| 36 + Btree *p; | |
| 37 + BtShared *pBt; | |
| 38 + unsigned char *pP1; | |
| 39 + | |
| 40 + if( db == NULL) return SQLITE_OK; | |
| 41 + | |
| 42 + /* Database 0 corrosponds to the main database. */ | |
| 43 + if( db->nDb<1 ) return SQLITE_OK; | |
| 44 + p = db->aDb[0].pBt; | |
| 45 + pBt = p->pBt; | |
| 46 + | |
| 47 + /* If in a transaction, roll it back. Committing any changes to a | |
| 48 + ** corrupt database may mess up evidence, we definitely don't want | |
| 49 + ** to allow poisoning to be rolled back, and the database is anyhow | |
| 50 + ** going bye-bye RSN. | |
| 51 + */ | |
| 52 + /* TODO(shess): Figure out if this might release the lock and let | |
| 53 + ** someone else get in there, which might deny us the lock a couple | |
| 54 + ** lines down. | |
| 55 + */ | |
| 56 + if( sqlite3BtreeIsInTrans(p) ) sqlite3BtreeRollback(p); | |
| 57 + | |
| 58 + /* Start an exclusive transaction. This will check the headers, so | |
| 59 + ** if someone else poisoned the database we should get an error. | |
| 60 + */ | |
| 61 + rc = sqlite3BtreeBeginTrans(p, 2); | |
| 62 + /* TODO(shess): Handle SQLITE_BUSY? */ | |
| 63 + if( rc!=SQLITE_OK ) return rc; | |
| 64 + | |
| 65 + /* Copied from sqlite3BtreeUpdateMeta(). Writing the old version of | |
| 66 + ** the page to the journal may be overkill, but it probably won't | |
| 67 + ** hurt. | |
| 68 + */ | |
| 69 + assert( pBt->inTrans==TRANS_WRITE ); | |
| 70 + assert( pBt->pPage1!=0 ); | |
| 71 + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); | |
| 72 + if( rc ) goto err; | |
| 73 + | |
| 74 + /* "SQLite format 3" changes to | |
| 75 + ** "SQLite poison 3". Be extra paranoid about making this change. | |
| 76 + */ | |
| 77 + if( sizeof(zMagicHeader)!=16 || | |
| 78 + sizeof(zPoisonHeader)!=sizeof(zMagicHeader) ){ | |
| 79 + rc = SQLITE_ERROR; | |
| 80 + goto err; | |
| 81 + } | |
| 82 + pP1 = pBt->pPage1->aData; | |
| 83 + if( memcmp(pP1, zMagicHeader, 16)!=0 ){ | |
| 84 + rc = SQLITE_CORRUPT; | |
| 85 + goto err; | |
| 86 + } | |
| 87 + memcpy(pP1, zPoisonHeader, 16); | |
| 88 + | |
| 89 + /* Push it to the database file. */ | |
| 90 + return sqlite3BtreeCommit(p); | |
| 91 + | |
| 92 + err: | |
| 93 + /* TODO(shess): What about errors, here? */ | |
| 94 + sqlite3BtreeRollback(p); | |
| 95 + return rc; | |
| 96 +} | |
| 97 + | |
| 98 #endif | |
| OLD | NEW |