mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Merge enhancements from trunk.
FossilOrigin-Name: 66fe06832614010d3156d7b21a760af9957018cc
This commit is contained in:
126
src/btree.c
126
src/btree.c
@@ -591,6 +591,49 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
|
||||
pCur->iPage = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
** The cursor passed as the only argument must point to a valid entry
|
||||
** when this function is called (i.e. have eState==CURSOR_VALID). This
|
||||
** function saves the current cursor key in variables pCur->nKey and
|
||||
** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error
|
||||
** code otherwise.
|
||||
**
|
||||
** If the cursor is open on an intkey table, then the integer key
|
||||
** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to
|
||||
** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is
|
||||
** set to point to a malloced buffer pCur->nKey bytes in size containing
|
||||
** the key.
|
||||
*/
|
||||
static int saveCursorKey(BtCursor *pCur){
|
||||
int rc;
|
||||
assert( CURSOR_VALID==pCur->eState );
|
||||
assert( 0==pCur->pKey );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
|
||||
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
|
||||
assert( rc==SQLITE_OK ); /* KeySize() cannot fail */
|
||||
|
||||
/* If this is an intKey table, then the above call to BtreeKeySize()
|
||||
** stores the integer key in pCur->nKey. In this case this value is
|
||||
** all that is required. Otherwise, if pCur is not open on an intKey
|
||||
** table, then malloc space for and store the pCur->nKey bytes of key
|
||||
** data. */
|
||||
if( 0==pCur->curIntKey ){
|
||||
void *pKey = sqlite3Malloc( pCur->nKey );
|
||||
if( pKey ){
|
||||
rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
|
||||
if( rc==SQLITE_OK ){
|
||||
pCur->pKey = pKey;
|
||||
}else{
|
||||
sqlite3_free(pKey);
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
assert( !pCur->curIntKey || !pCur->pKey );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Save the current cursor position in the variables BtCursor.nKey
|
||||
@@ -611,30 +654,8 @@ static int saveCursorPosition(BtCursor *pCur){
|
||||
}else{
|
||||
pCur->skipNext = 0;
|
||||
}
|
||||
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
|
||||
assert( rc==SQLITE_OK ); /* KeySize() cannot fail */
|
||||
|
||||
/* If this is an intKey table, then the above call to BtreeKeySize()
|
||||
** stores the integer key in pCur->nKey. In this case this value is
|
||||
** all that is required. Otherwise, if pCur is not open on an intKey
|
||||
** table, then malloc space for and store the pCur->nKey bytes of key
|
||||
** data.
|
||||
*/
|
||||
if( 0==pCur->curIntKey ){
|
||||
void *pKey = sqlite3Malloc( pCur->nKey );
|
||||
if( pKey ){
|
||||
rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
|
||||
if( rc==SQLITE_OK ){
|
||||
pCur->pKey = pKey;
|
||||
}else{
|
||||
sqlite3_free(pKey);
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
assert( !pCur->curIntKey || !pCur->pKey );
|
||||
|
||||
rc = saveCursorKey(pCur);
|
||||
if( rc==SQLITE_OK ){
|
||||
btreeReleaseAllCursorPages(pCur);
|
||||
pCur->eState = CURSOR_REQUIRESEEK;
|
||||
@@ -8047,10 +8068,15 @@ end_insert:
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the entry that the cursor is pointing to. The cursor
|
||||
** is left pointing at an arbitrary location.
|
||||
** Delete the entry that the cursor is pointing to.
|
||||
**
|
||||
** If the second parameter is zero, then the cursor is left pointing at an
|
||||
** arbitrary location after the delete. If it is non-zero, then the cursor
|
||||
** is left in a state such that the next call to BtreeNext() or BtreePrev()
|
||||
** moves it to the same row as it would if the call to BtreeDelete() had
|
||||
** been omitted.
|
||||
*/
|
||||
int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
|
||||
Btree *p = pCur->pBtree;
|
||||
BtShared *pBt = p->pBt;
|
||||
int rc; /* Return code */
|
||||
@@ -8059,6 +8085,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
int iCellIdx; /* Index of cell to delete */
|
||||
int iCellDepth; /* Depth of node containing pCell */
|
||||
u16 szCell; /* Size of the cell being deleted */
|
||||
int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pBt->inTransaction==TRANS_WRITE );
|
||||
@@ -8088,10 +8115,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
}
|
||||
|
||||
/* Save the positions of any other cursors open on this table before
|
||||
** making any modifications. Make the page containing the entry to be
|
||||
** deleted writable. Then free any overflow pages associated with the
|
||||
** entry and finally remove the cell itself from within the page.
|
||||
*/
|
||||
** making any modifications. */
|
||||
if( pCur->curFlags & BTCF_Multiple ){
|
||||
rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
|
||||
if( rc ) return rc;
|
||||
@@ -8103,6 +8127,31 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
invalidateIncrblobCursors(p, pCur->info.nKey, 0);
|
||||
}
|
||||
|
||||
/* If the bPreserve flag is set to true, then the cursor position must
|
||||
** be preserved following this delete operation. If the current delete
|
||||
** will cause a b-tree rebalance, then this is done by saving the cursor
|
||||
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
|
||||
** returning.
|
||||
**
|
||||
** Or, if the current delete will not cause a rebalance, then the cursor
|
||||
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
|
||||
** before or after the deleted entry. In this case set bSkipnext to true. */
|
||||
if( bPreserve ){
|
||||
if( !pPage->leaf
|
||||
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
|
||||
){
|
||||
/* A b-tree rebalance will be required after deleting this entry.
|
||||
** Save the cursor key. */
|
||||
rc = saveCursorKey(pCur);
|
||||
if( rc ) return rc;
|
||||
}else{
|
||||
bSkipnext = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make the page containing the entry to be deleted writable. Then free any
|
||||
** overflow pages associated with the entry and finally remove the cell
|
||||
** itself from within the page. */
|
||||
rc = sqlite3PagerWrite(pPage->pDbPage);
|
||||
if( rc ) return rc;
|
||||
rc = clearCell(pPage, pCell, &szCell);
|
||||
@@ -8156,7 +8205,22 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
moveToRoot(pCur);
|
||||
if( bSkipnext ){
|
||||
assert( bPreserve && pCur->iPage==iCellDepth );
|
||||
assert( pPage->nCell>0 && iCellIdx<=pPage->nCell );
|
||||
pCur->eState = CURSOR_SKIPNEXT;
|
||||
if( iCellIdx>=pPage->nCell ){
|
||||
pCur->skipNext = -1;
|
||||
pCur->aiIdx[iCellDepth] = pPage->nCell-1;
|
||||
}else{
|
||||
pCur->skipNext = 1;
|
||||
}
|
||||
}else{
|
||||
rc = moveToRoot(pCur);
|
||||
if( bPreserve ){
|
||||
pCur->eState = CURSOR_REQUIRESEEK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
Reference in New Issue
Block a user