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:
commit
4b09ec6e11
27
manifest
27
manifest
@ -1,5 +1,5 @@
|
||||
C Simplification\sand\ssize\sreduction\sto\sthe\sprintf\slogic.\s\sRemove\sthe\sbFlags\nparameter\sfrom\ssqlite3VXPrintf()\sand\ssqlite3XPrintf().\s\sUse\ssqlite3XPrintf()\ninstead\sof\ssqlite3_snprintf()\sfor\srendering\sP4\svalues\sin\sEXPLAIN\soutput.
|
||||
D 2016-01-30T12:50:25.204
|
||||
C Add\sthe\sBTREE_FORDELETE\sand\sBTREE_AUXDELETE\sflags\sto\sthe\sb-tree\slayer\sinterface\nand\suse\sthem.\s\sAdd\sassert()\sstatement\sto\sverify\sthat\sthey\sare\scorrect.
|
||||
D 2016-01-30T13:32:30.291
|
||||
F Makefile.in 027c1603f255390c43a426671055a31c0a65fdb4
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 72b7858f02017611c3ac1ddc965251017fed0845
|
||||
@ -290,8 +290,8 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c 2869a76c03eb393ee795416e2387005553df72bc
|
||||
F src/bitvec.c 1a78d450a17c5016710eec900bedfc5729bf9bdf
|
||||
F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73
|
||||
F src/btree.c 5e3435a31afbe9d839c5ee2630b8390712847415
|
||||
F src/btree.h 526137361963e746949ab966a910c7f455ac6b04
|
||||
F src/btree.c e3929afb9bfbaa6b39685b5e5a207036ac862a75
|
||||
F src/btree.h 368ceeb4bd9312dc8df2ffd64b4b7dbcf4db5f8e
|
||||
F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
|
||||
F src/build.c 0510844c48d80732aead74b5727403b493dd1cd5
|
||||
F src/callback.c 29ae4faba226c7ebb9aee93016b5ce8a8f071261
|
||||
@ -299,7 +299,7 @@ F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f
|
||||
F src/ctime.c 60e135af364d777a9ab41c97e5e89cd224da6198
|
||||
F src/date.c 997651e3ee6c2818fbf7fcdb7156cef9eb3ece20
|
||||
F src/dbstat.c b2ec6793eef97aebb4d171d490a4ffdfa9f2475c
|
||||
F src/delete.c 00af9f08a15ddc5cba5962d3d3e5bf2d67b2e7da
|
||||
F src/delete.c 33ed87dc0746b1f8ce186f62b608bf40801af9c0
|
||||
F src/expr.c d10c1cdef5810cdbf73adc9f9b383684230b360a
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c c66d3e5b35d4d95b5c1e2ee6c12f5df13a7f9ad6
|
||||
@ -308,7 +308,7 @@ F src/global.c bd5a0af3f30b0c01be6db756c626cd3c33a3d260
|
||||
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
|
||||
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c a00e6d8a843dc22e2c136df04e6300c4528d9b9f
|
||||
F src/insert.c 410f52b9ef4603dc0aebb169b7cb6b3c60eda07e
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
|
||||
F src/loadext.c 84996d7d70a605597d79c1f1d7b2012a5fd34f2b
|
||||
@ -352,7 +352,7 @@ F src/shell.c dcd7a83645ef2a58ee9c6d0ea4714d877d7835c4
|
||||
F src/sqlite.h.in 214476a62012e578f42133a9a3b4f97a9aa421a3
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
|
||||
F src/sqliteInt.h 5b552cc0eee50d519e2e020f16abbc68947b0e59
|
||||
F src/sqliteInt.h 2f80b9b1506a8d602b2a99f3f0bfae22df3e7d70
|
||||
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
|
||||
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
|
||||
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
|
||||
@ -412,9 +412,9 @@ F src/update.c 17332f9fe818cbc0444c36a811800af8498af4c3
|
||||
F src/utf.c 32d7f82aa921322f3e1c956f4b58f019ebd2c6b3
|
||||
F src/util.c 72d40df0a52d3f30b462a15f0e094fcbade6dc82
|
||||
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
|
||||
F src/vdbe.c 0686ef5ee103935548d1aa2c0c28e52f1ae6e5a8
|
||||
F src/vdbe.c d9d2406d8a3baca537d2b05a2354afaa25e1ca84
|
||||
F src/vdbe.h 7a733ea8aac1b77305a67698e784fa3484ee3337
|
||||
F src/vdbeInt.h 171fdc5f6af4eeb0ff0559dbf0a71244d726a670
|
||||
F src/vdbeInt.h 716df83ac45b70ff000b515040ea606d0cb5d0f3
|
||||
F src/vdbeapi.c ffae8f5af4570fbd548504e815e9fb7227f0822e
|
||||
F src/vdbeaux.c 221631e40111b5efa96ea557c6e2e7f62fd32b2a
|
||||
F src/vdbeblob.c 37c3d11a753e403698c69e17383d282e1ae73e75
|
||||
@ -642,7 +642,7 @@ F test/fkey6.test abb59f866c1b44926fd02d1fdd217d831fe04f48
|
||||
F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13
|
||||
F test/fkey8.test 8f08203458321e6c19a263829de4cfc936274ab0
|
||||
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
|
||||
F test/fordelete.test ba12ec1d27cc34a4c23db4446029126d773f3849
|
||||
F test/fordelete.test 57ed9b953eeace09dd2eac3251b40bf9d6990aec
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
||||
F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
|
||||
@ -1422,7 +1422,8 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 9de3d7123007636aa97da1c70bc34344b0391078
|
||||
R 821c09620afbfbde9b9d6d9359867747
|
||||
P 0bdb41c45aa1cc8e5c136aaa6605d54b401483bd 46080b0474363ca6594d2e5c249a280e2b4fc67a
|
||||
R 54437ffc6525e4a6d93d7714d1fd6e2f
|
||||
T +closed 46080b0474363ca6594d2e5c249a280e2b4fc67a
|
||||
U drh
|
||||
Z e57134af984dbdd8b3338eb2a295687a
|
||||
Z 640a4b96ac8cc992fda6dcd328c886fd
|
||||
|
@ -1 +1 @@
|
||||
0bdb41c45aa1cc8e5c136aaa6605d54b401483bd
|
||||
85c467041c9378cae3038756da815e9117ee8c7d
|
44
src/btree.c
44
src/btree.c
@ -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,21 @@ 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_AUXDELETE bit of flags indicates that is one of several deletes
|
||||
** associated with a single table entry and its indexes. Only one of those
|
||||
** deletes is considered the "primary" delete. The primary delete occurs
|
||||
** on a cursor that is not a BTREE_FORDELETE cursor. All but one delete
|
||||
** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag.
|
||||
** The BTREE_AUXDELETE 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 +8116,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 +8126,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_AUXDELETE))==0 );
|
||||
|
||||
iCellDepth = pCur->iPage;
|
||||
iCellIdx = pCur->aiIdx[iCellDepth];
|
||||
|
@ -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_AUXDELETE 0x04 /* not the primary delete operation */
|
||||
|
||||
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
|
||||
const void *pData, int nData,
|
||||
int nZero, int bias, int seekResult);
|
||||
|
12
src/delete.c
12
src/delete.c
@ -479,13 +479,12 @@ void sqlite3DeleteFrom(
|
||||
*/
|
||||
if( !isView ){
|
||||
int iAddrOnce = 0;
|
||||
u8 p5 = (eOnePass==ONEPASS_OFF ? 0 : OPFLAG_FORDELETE);
|
||||
if( eOnePass==ONEPASS_MULTI ){
|
||||
iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||
}
|
||||
testcase( IsVirtual(pTab) );
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, p5, iTabCur,
|
||||
aToOpen, &iDataCur, &iIdxCur);
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE,
|
||||
iTabCur, aToOpen, &iDataCur, &iIdxCur);
|
||||
assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
|
||||
assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
|
||||
if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);
|
||||
@ -718,15 +717,20 @@ 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 ){
|
||||
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
|
||||
}
|
||||
if( eMode!=ONEPASS_OFF ){
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
|
||||
}
|
||||
if( iIdxNoSeek>=0 ){
|
||||
sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);
|
||||
}
|
||||
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
|
||||
|
11
src/insert.c
11
src/insert.c
@ -1647,7 +1647,7 @@ int sqlite3OpenTableAndIndices(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Table *pTab, /* Table to be opened */
|
||||
int op, /* OP_OpenRead or OP_OpenWrite */
|
||||
u8 p5, /* P5 value for OP_Open* instructions */
|
||||
u8 p5, /* P5 value for OP_Open* opcodes (except on WITHOUT ROWID) */
|
||||
int iBase, /* Use this for the table cursor, if there is one */
|
||||
u8 *aToOpen, /* If not NULL: boolean for each table and index */
|
||||
int *piDataCur, /* Write the database source cursor number here */
|
||||
@ -1682,15 +1682,16 @@ int sqlite3OpenTableAndIndices(
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
int iIdxCur = iBase++;
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){
|
||||
*piDataCur = iIdxCur;
|
||||
}
|
||||
if( aToOpen==0 || aToOpen[i+1] ){
|
||||
sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
||||
sqlite3VdbeChangeP5(v, p5);
|
||||
VdbeComment((v, "%s", pIdx->zName));
|
||||
}
|
||||
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
||||
if( piDataCur ) *piDataCur = iIdxCur;
|
||||
}else{
|
||||
sqlite3VdbeChangeP5(v, p5);
|
||||
}
|
||||
}
|
||||
if( iBase>pParse->nTab ) pParse->nTab = iBase;
|
||||
return i;
|
||||
|
@ -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_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */
|
||||
|
||||
/*
|
||||
* Each trigger present in the database schema is stored as an instance of
|
||||
|
57
src/vdbe.c
57
src/vdbe.c
@ -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
|
||||
|
@ -83,6 +83,7 @@ struct VdbeCursor {
|
||||
u8 isTable; /* True for rowid tables. False for indexes */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 seekOp; /* Most recent seek operation on this cursor */
|
||||
u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */
|
||||
#endif
|
||||
Bool isEphemeral:1; /* True for an ephemeral table */
|
||||
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
|
||||
|
@ -30,17 +30,49 @@ proc analyze_delete_program {sql} {
|
||||
} {
|
||||
set T($rootpage) $name
|
||||
}
|
||||
|
||||
# Calculate the results.
|
||||
set res [list]
|
||||
|
||||
# For each OpenWrite instruction generated for the proposed DELETE
|
||||
# statement, add the following array entries:
|
||||
#
|
||||
# $M(<cursor number>) -> <object name>
|
||||
# $O(<object name>) -> "*" | ""
|
||||
#
|
||||
# The O() entry is set to "*" if the BTREE_FORDELETE flag is specified,
|
||||
# or "" otherwise.
|
||||
#
|
||||
db eval "EXPLAIN $sql" R {
|
||||
if {$R(opcode) == "OpenWrite"} {
|
||||
set obj $T($R(p2))
|
||||
if {"0x$R(p5)" & 0x08} { append obj *}
|
||||
lappend res $obj
|
||||
if {$R(opcode)=="OpenWrite"} {
|
||||
set root $R(p2)
|
||||
set csr $R(p1)
|
||||
if {[info exists T($root)]} { set M($csr) $T($root) }
|
||||
|
||||
set obj $T($root)
|
||||
set O($obj) ""
|
||||
if {"0x$R(p5)" & 0x08} {
|
||||
set O($obj) *
|
||||
} else {
|
||||
set O($obj) ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db eval "EXPLAIN $sql" R {
|
||||
if {$R(opcode) == "Delete"} {
|
||||
set csr $R(p1)
|
||||
if {[info exists M($csr)]} {
|
||||
set idxdelete [expr {("0x$R(p5)" & 0x04) ? 1 : 0}]
|
||||
if {$idxdelete} {
|
||||
append O($M($csr)) "+"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set res [list]
|
||||
foreach {k v} [array get O] {
|
||||
lappend res "${k}${v}"
|
||||
}
|
||||
|
||||
lsort $res
|
||||
}
|
||||
|
||||
@ -53,10 +85,10 @@ do_execsql_test 1.0 {
|
||||
}
|
||||
|
||||
foreach {tn sql res} {
|
||||
1 { DELETE FROM t1 WHERE a=?} { sqlite_autoindex_t1_1 t1* }
|
||||
2 { DELETE FROM t1 WHERE a=? AND b=? } { sqlite_autoindex_t1_1 t1 }
|
||||
3 { DELETE FROM t1 WHERE a>? } { sqlite_autoindex_t1_1 t1* }
|
||||
4 { DELETE FROM t1 WHERE rowid=? } { sqlite_autoindex_t1_1* t1 }
|
||||
1 { DELETE FROM t1 WHERE a=?} { sqlite_autoindex_t1_1 t1*+ }
|
||||
2 { DELETE FROM t1 WHERE a=? AND b=? } { sqlite_autoindex_t1_1 t1+ }
|
||||
3 { DELETE FROM t1 WHERE a>? } { sqlite_autoindex_t1_1 t1*+ }
|
||||
4 { DELETE FROM t1 WHERE rowid=? } { sqlite_autoindex_t1_1* t1 }
|
||||
} {
|
||||
do_adp_test 1.$tn $sql $res
|
||||
}
|
||||
@ -68,8 +100,8 @@ do_execsql_test 2.0 {
|
||||
CREATE INDEX t2c ON t2(c);
|
||||
}
|
||||
foreach {tn sql res} {
|
||||
1 { DELETE FROM t2 WHERE a=?} { t2* t2a t2b* t2c* }
|
||||
2 { DELETE FROM t2 WHERE a=? AND +b=?} { t2 t2a t2b* t2c* }
|
||||
1 { DELETE FROM t2 WHERE a=?} { t2*+ t2a t2b* t2c* }
|
||||
2 { DELETE FROM t2 WHERE a=? AND +b=?} { t2+ t2a t2b* t2c* }
|
||||
3 { DELETE FROM t2 WHERE a=? OR b=?} { t2 t2a* t2b* t2c* }
|
||||
4 { DELETE FROM t2 WHERE +a=? } { t2 t2a* t2b* t2c* }
|
||||
5 { DELETE FROM t2 WHERE rowid=? } { t2 t2a* t2b* t2c* }
|
||||
@ -126,5 +158,53 @@ do_test 3.2 {
|
||||
}
|
||||
} {6 {} {} {}}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE log(x);
|
||||
CREATE TABLE p1(one PRIMARY KEY, two);
|
||||
|
||||
CREATE TRIGGER tr_bd BEFORE DELETE ON p1 BEGIN
|
||||
INSERT INTO log VALUES('delete');
|
||||
END;
|
||||
INSERT INTO p1 VALUES('a', 'A'), ('b', 'B'), ('c', 'C');
|
||||
DELETE FROM p1 WHERE one = 'a';
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 4.1 {
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE tbl(a PRIMARY KEY, b, c);
|
||||
CREATE TABLE log(a, b, c);
|
||||
INSERT INTO "tbl" VALUES(1,2,3);
|
||||
CREATE TRIGGER the_trigger BEFORE DELETE ON tbl BEGIN
|
||||
INSERT INTO log VALUES(1, 2,3);
|
||||
END;
|
||||
COMMIT;
|
||||
DELETE FROM tbl WHERE a=1;
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 5.1 {
|
||||
PRAGMA foreign_keys = 1;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t2(
|
||||
c INTEGER PRIMARY KEY,
|
||||
d INTEGER DEFAULT 1 REFERENCES t1 ON DELETE SET DEFAULT
|
||||
);
|
||||
} {}
|
||||
do_execsql_test 5.2 {
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t2 VALUES(1, 2);
|
||||
SELECT * FROM t2;
|
||||
} {1 2}
|
||||
do_execsql_test 5.3 {
|
||||
DELETE FROM t1 WHERE a = 2;
|
||||
} {}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user