diff options
author | drh <drh@noemail.net> | 2019-12-29 22:08:20 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2019-12-29 22:08:20 +0000 |
commit | 7b14b65d20a2ba85bd90689772f605ba5a32bfed (patch) | |
tree | 34eef6b441e57ad0a4489edc1fdb5cbced1e05b8 /src | |
parent | be3da24134f53a0c8f10291611af758dc0ced611 (diff) | |
download | sqlite-7b14b65d20a2ba85bd90689772f605ba5a32bfed.tar.gz sqlite-7b14b65d20a2ba85bd90689772f605ba5a32bfed.zip |
Do not allow triggers that run as part of REPLACE conflict resolution
during an UPDATE to modify the the table being updated. Otherwise, those
triggers might delete content out from under the update operation, leading
to all kinds of problems. Ticket [314cc133e5ada126]
FossilOrigin-Name: db4b7e1dc399c1f16b827ac087aa37c0815f4b2f41f1ffad59963eead2ab5562
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 15 | ||||
-rw-r--r-- | src/btree.h | 2 | ||||
-rw-r--r-- | src/btreeInt.h | 1 | ||||
-rw-r--r-- | src/insert.c | 6 | ||||
-rw-r--r-- | src/sqlite.h.in | 1 | ||||
-rw-r--r-- | src/vdbe.c | 30 |
6 files changed, 55 insertions, 0 deletions
diff --git a/src/btree.c b/src/btree.c index eb80816bb..a137da3c7 100644 --- a/src/btree.c +++ b/src/btree.c @@ -699,6 +699,9 @@ static int saveCursorPosition(BtCursor *pCur){ assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); + if( pCur->curFlags & BTCF_Pinned ){ + return SQLITE_CONSTRAINT_PINNED; + } if( pCur->eState==CURSOR_SKIPNEXT ){ pCur->eState = CURSOR_VALID; }else{ @@ -4562,6 +4565,18 @@ i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ return pCur->info.nKey; } +/* +** Pin or unpin a cursor. +*/ +void sqlite3BtreeCursorPin(BtCursor *pCur){ + assert( (pCur->curFlags & BTCF_Pinned)==0 ); + pCur->curFlags |= BTCF_Pinned; +} +void sqlite3BtreeCursorUnpin(BtCursor *pCur){ + assert( (pCur->curFlags & BTCF_Pinned)!=0 ); + pCur->curFlags &= ~BTCF_Pinned; +} + #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC /* ** Return the offset into the database file for the start of the diff --git a/src/btree.h b/src/btree.h index 4fd281dec..4bd41f7f3 100644 --- a/src/btree.h +++ b/src/btree.h @@ -306,6 +306,8 @@ int sqlite3BtreeNext(BtCursor*, int flags); int sqlite3BtreeEof(BtCursor*); int sqlite3BtreePrevious(BtCursor*, int flags); i64 sqlite3BtreeIntegerKey(BtCursor*); +void sqlite3BtreeCursorPin(BtCursor*); +void sqlite3BtreeCursorUnpin(BtCursor*); #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC i64 sqlite3BtreeOffset(BtCursor*); #endif diff --git a/src/btreeInt.h b/src/btreeInt.h index 72d877f33..7687a0f1e 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -542,6 +542,7 @@ struct BtCursor { #define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */ #define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */ #define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */ +#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */ /* ** Potential values for BtCursor.eState. diff --git a/src/insert.c b/src/insert.c index 423087e37..d778e4b45 100644 --- a/src/insert.c +++ b/src/insert.c @@ -2129,9 +2129,15 @@ void sqlite3GenerateConstraintChecks( sqlite3MultiWrite(pParse); nReplaceTrig++; } + if( pTrigger && isUpdate ){ + sqlite3VdbeAddOp1(v, OP_CursorLock, iDataCur); + } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); + if( pTrigger && isUpdate ){ + sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur); + } if( regTrigCnt ){ int addrBypass; /* Jump destination to bypass recheck logic */ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 944b5be3e..50976ee16 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -536,6 +536,7 @@ int sqlite3_exec( #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) +#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) diff --git a/src/vdbe.c b/src/vdbe.c index 0aeaa072c..40e022d62 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -7025,6 +7025,36 @@ case OP_Expire: { break; } +/* Opcode: CursorLock P1 * * * * +** +** Lock the btree to which cursor P1 is pointing so that the btree cannot be +** written by an other cursor. +*/ +case OP_CursorLock: { + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1<p->nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + sqlite3BtreeCursorPin(pC->uc.pCursor); + break; +} + +/* Opcode: CursorUnlock P1 * * * * +** +** Unlock the btree to which cursor P1 is pointing so that it can be +** written by other cursors. +*/ +case OP_CursorUnlock: { + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1<p->nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + sqlite3BtreeCursorUnpin(pC->uc.pCursor); + break; +} + #ifndef SQLITE_OMIT_SHARED_CACHE /* Opcode: TableLock P1 P2 P3 P4 * ** Synopsis: iDb=P1 root=P2 write=P3 |