mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Early detection of database corruption in balance_deeper().
FossilOrigin-Name: 61c2233654158e65a3d3baeea947903a919a569fcc4a5b342b2e9a68cec1b6f3
This commit is contained in:
33
src/btree.c
33
src/btree.c
@@ -5718,8 +5718,11 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
|
||||
** to be invalid here. This can only occur if a second cursor modifies
|
||||
** the page while cursor pCur is holding a reference to it. Which can
|
||||
** only happen if the database is corrupt in such a way as to link the
|
||||
** page into more than one b-tree structure. */
|
||||
testcase( idx>pPage->nCell );
|
||||
** page into more than one b-tree structure.
|
||||
**
|
||||
** Update 2019-12-23: appears to long longer be possible after the
|
||||
** addition of anotherValidCursor() condition on balance_deeper(). */
|
||||
harmless( idx>pPage->nCell );
|
||||
|
||||
if( idx>=pPage->nCell ){
|
||||
if( !pPage->leaf ){
|
||||
@@ -8308,6 +8311,30 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid
|
||||
** on the same B-tree as pCur.
|
||||
**
|
||||
** This can if a database is corrupt with two or more SQL tables
|
||||
** pointing to the same b-tree. If an insert occurs on one SQL table
|
||||
** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL
|
||||
** table linked to the same b-tree. If the secondary insert causes a
|
||||
** rebalance, that can change content out from under the cursor on the
|
||||
** first SQL table, violating invariants on the first insert.
|
||||
*/
|
||||
static int anotherValidCursor(BtCursor *pCur){
|
||||
BtCursor *pOther;
|
||||
for(pOther=pCur->pBt->pCursor; pOther; pOther=pOther->pNext){
|
||||
if( pOther!=pCur
|
||||
&& pOther->eState==CURSOR_VALID
|
||||
&& pOther->pPage==pCur->pPage
|
||||
){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The page that pCur currently points to has just been modified in
|
||||
** some way. This function figures out if this modification means the
|
||||
@@ -8335,7 +8362,7 @@ static int balance(BtCursor *pCur){
|
||||
if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
|
||||
break;
|
||||
}else if( (iPage = pCur->iPage)==0 ){
|
||||
if( pPage->nOverflow ){
|
||||
if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){
|
||||
/* The root page of the b-tree is overfull. In this case call the
|
||||
** balance_deeper() function to create a new child for the root-page
|
||||
** and copy the current contents of the root-page to it. The
|
||||
|
Reference in New Issue
Block a user