1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-16 23:02:26 +03:00

Add a new hint bit on the flags parameter of sqlite3BtreeDelete(). The new

BTREE_IDXDELETE bit indicates that the call is to delete an index entry 
corresponding to a table row that has already been deleted.

FossilOrigin-Name: ac2cbadd8000947c097da5b00c00090fe58fdcff
This commit is contained in:
drh
2016-01-21 17:06:33 +00:00
parent 9c0c57a4ca
commit e807bdba86
7 changed files with 73 additions and 33 deletions

View File

@@ -4049,13 +4049,13 @@ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
** on the database already. If a write-cursor is requested, then
** the caller is assumed to have an open write transaction.
**
** If wrFlag==0, then the cursor can only be used for reading.
** If wrFlag==1, then the cursor can be used for reading or for
** writing if other conditions for writing are also met. These
** are the conditions that must be met in order for writing to
** be allowed:
** If the BTREE_WRCSR bit of wrFlag is clear, then the cursor can only
** be used for reading. If the BTREE_WRCSR bit is set, then the cursor
** can be used for reading or for writing if other conditions for writing
** are also met. These are the conditions that must be met in order
** for writing to be allowed:
**
** 1: The cursor must have been opened with wrFlag==1
** 1: The cursor must have been opened with wrFlag containing BTREE_WRCSR
**
** 2: Other database connections that share the same pager cache
** but which are not in the READ_UNCOMMITTED state may not have
@@ -4067,6 +4067,16 @@ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
**
** 4: There must be an active transaction.
**
** The BTREE_FORDELETE bit of wrFlag may optionally be set if BTREE_WRCSR
** is set. If FORDELETE is set, that is a hint to the implementation that
** this cursor will only be used to seek to and delete entries of an index
** as part of a larger DELETE statement. The FORDELETE hint is not used by
** this implementation. But in a hypothetical alternative storage engine
** in which index entries are automatically deleted when corresponding table
** rows are deleted, the FORDELETE flag is a hint that all SEEK and DELETE
** operations on this cursor can be no-ops and all READ operations can
** return a null row (2-bytes: 0x01 0x00).
**
** No checking is done to make sure that page iTable really is the
** root page of a b-tree. If it is not, then the cursor acquired
** will not work correctly.
@@ -8082,13 +8092,18 @@ end_insert:
/*
** 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.
** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then
** the cursor is left pointing at an arbitrary location after the delete.
** But if that bit is set, 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 have been on if the call to BtreeDelete() had been omitted.
**
** The BTREE_IDXDELETE bit of flags indicates that this is a delete of
** an index entry where the corresponding table row has already been deleted.
** The BTREE_IDXDELETE bit is a hint that is not used by this implementation,
** but which might be used by alternative storage engines.
*/
int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
Btree *p = pCur->pBtree;
BtShared *pBt = p->pBt;
int rc; /* Return code */
@@ -8098,6 +8113,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
int iCellDepth; /* Depth of node containing pCell */
u16 szCell; /* Size of the cell being deleted */
int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */
u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */
assert( cursorOwnsBtShared(pCur) );
assert( pBt->inTransaction==TRANS_WRITE );
@@ -8107,6 +8123,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->eState==CURSOR_VALID );
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_IDXDELETE))==0 );
iCellDepth = pCur->iPage;
iCellIdx = pCur->aiIdx[iCellDepth];

View File

@@ -245,7 +245,12 @@ int sqlite3BtreeMovetoUnpacked(
);
int sqlite3BtreeCursorHasMoved(BtCursor*);
int sqlite3BtreeCursorRestore(BtCursor*, int*);
int sqlite3BtreeDelete(BtCursor*, int);
int sqlite3BtreeDelete(BtCursor*, u8 flags);
/* Allowed flags for the 2nd argument to sqlite3BtreeDelete() */
#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
#define BTREE_IDXDELETE 0x04 /* this is index, table row already deleted */
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
const void *pData, int nData,
int nZero, int bias, int seekResult);

View File

@@ -718,6 +718,7 @@ void sqlite3GenerateRowDelete(
** a view (in which case the only effect of the DELETE statement is to
** fire the INSTEAD OF triggers). */
if( pTab->pSelect==0 ){
u8 p5 = 0;
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
if( count ){
@@ -725,8 +726,10 @@ void sqlite3GenerateRowDelete(
}
if( iIdxNoSeek>=0 ){
sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);
if( eMode!=ONEPASS_OFF ) p5 = OPFLAG_IDXDELETE;
}
sqlite3VdbeChangeP5(v, eMode==ONEPASS_MULTI);
if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION;
sqlite3VdbeChangeP5(v, p5);
}
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to

View File

@@ -2847,7 +2847,8 @@ struct AuthContext {
/*
** Bitfield flags for P5 value in various opcodes.
*/
#define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */
#define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */
/* Also used in P2 (not P5) of OP_Delete */
#define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */
#define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */
#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */
@@ -2860,6 +2861,8 @@ struct AuthContext {
#define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */
#define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */
#define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete: keep cursor position */
#define OPFLAG_IDXDELETE 0x04 /* OP_Delete: index in a DELETE op */
/*
* Each trigger present in the database schema is stored as an instance of

View File

@@ -4341,14 +4341,20 @@ case OP_InsertInt: {
**
** Delete the record at which the P1 cursor is currently pointing.
**
** If the P5 parameter is non-zero, the cursor will be left pointing at
** either the next or the previous record in the table. If it is left
** pointing at the next record, then the next Next instruction will be a
** no-op. As a result, in this case it is OK to delete a record from within a
** Next loop. If P5 is zero, then the cursor is left in an undefined state.
** If the OPFLAG_SAVEPOSITION bit of the P5 parameter is set, then
** the cursor will be left pointing at either the next or the previous
** record in the table. If it is left pointing at the next record, then
** the next Next instruction will be a no-op. As a result, in this case
** it is ok to delete a record from within a Next loop. If
** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be
** left in an undefined state.
**
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
** incremented (otherwise not).
** If the OPFLAG_IDXDELETE bit is set on P5, that indicates that this
** delete is on an index cursor where the corresponding table row has
** already been deleted.
**
** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row
** change count is incremented (otherwise not).
**
** P1 must not be pseudo-table. It has to be a real table with
** multiple rows.
@@ -4385,6 +4391,9 @@ case OP_Delete: {
}
#endif
assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_IDXDELETE))==0 );
assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION );
assert( OPFLAG_IDXDELETE==BTREE_IDXDELETE );
rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
pC->cacheStatus = CACHE_STALE;