1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Add the BTREE_FORDELETE and BTREE_AUXDELETE flags to the b-tree layer interface

and use them.  Add assert() statement to verify that they are correct.

FossilOrigin-Name: 85c467041c9378cae3038756da815e9117ee8c7d
This commit is contained in:
drh
2016-01-30 13:32:30 +00:00
10 changed files with 210 additions and 62 deletions

View File

@@ -551,6 +551,9 @@ int sqlite3VdbeExec(
Op *pOp = aOp; /* Current operation */
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
Op *pOrigOp; /* Value of pOp at the top of the loop */
#endif
#ifdef SQLITE_DEBUG
int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */
#endif
int rc = SQLITE_OK; /* Value to return */
sqlite3 *db = p->db; /* The database */
@@ -3397,6 +3400,9 @@ case OP_OpenWrite:
pCur->nullRow = 1;
pCur->isOrdered = 1;
pCur->pgnoRoot = p2;
#ifdef SQLITE_DEBUG
pCur->wrFlag = wrFlag;
#endif
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor);
pCur->pKeyInfo = pKeyInfo;
/* Set the VdbeCursor.isTable variable. Previous versions of
@@ -4356,14 +4362,22 @@ 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_AUXDELETE bit is set on P5, that indicates that this
** delete one of several associated with deleting a table row and all its
** associated index entries. Exactly one of those deletes is the "primary"
** delete. The others are all on OPFLAG_FORDELETE cursors or else are
** marked with the AUXDELETE flag.
**
** 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.
@@ -4399,7 +4413,26 @@ case OP_Delete: {
assert( pC->movetoTarget==iKey );
}
#endif
/* Only flags that can be set are SAVEPOISTION and AUXDELETE */
assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 );
assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION );
assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE );
#ifdef SQLITE_DEBUG
if( p->pFrame==0 ){
if( pC->isEphemeral==0
&& (pOp->p5 & OPFLAG_AUXDELETE)==0
&& (pC->wrFlag & OPFLAG_FORDELETE)==0
){
nExtraDelete++;
}
if( pOp->p2 & OPFLAG_NCHANGE ){
nExtraDelete--;
}
}
#endif
rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
pC->cacheStatus = CACHE_STALE;
@@ -4944,12 +4977,9 @@ case OP_IdxDelete: {
r.nField = (u16)pOp->p3;
r.default_rc = 0;
r.aMem = &aMem[pOp->p2];
#ifdef SQLITE_DEBUG
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
#endif
rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
if( rc==SQLITE_OK && res==0 ){
rc = sqlite3BtreeDelete(pCrsr, 0);
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
}
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
@@ -6768,6 +6798,9 @@ vdbe_return:
testcase( nVmStep>0 );
p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
sqlite3VdbeLeave(p);
assert( rc!=SQLITE_OK || nExtraDelete==0
|| sqlite3_strlike("DELETE%",p->zSql,0)!=0
);
return rc;
/* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH