diff options
Diffstat (limited to 'src/vdbeaux.c')
-rw-r--r-- | src/vdbeaux.c | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/src/vdbeaux.c b/src/vdbeaux.c index c169b3727..fdf223e3b 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1895,6 +1895,13 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ } db->nStatement--; p->iStatement = 0; + + /* If the statement transaction is being rolled back, also restore the + ** database handles deferred constraint counter to the value it had when + ** the statement transaction was opened. */ + if( eOp==SAVEPOINT_ROLLBACK ){ + db->nDeferredCons = p->nStmtDefCons; + } } return rc; } @@ -1927,6 +1934,28 @@ void sqlite3VdbeMutexArrayEnter(Vdbe *p){ #endif /* +** This function is called when a transaction opened by the database +** handle associated with the VM passed as an argument is about to be +** committed. If there are outstanding deferred foreign key constraint +** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK. +** +** If there are outstanding FK violations and this function returns +** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT and write +** an error message to it. Then return SQLITE_ERROR. +*/ +#ifndef SQLITE_OMIT_FOREIGN_KEY +int sqlite3VdbeCheckDeferred(Vdbe *p){ + sqlite3 *db = p->db; + if( db->nDeferredCons ){ + p->rc = SQLITE_CONSTRAINT; + sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed"); + return SQLITE_ERROR; + } + return SQLITE_OK; +} +#endif + +/* ** This routine is called the when a VDBE tries to halt. If the VDBE ** has made changes and is in autocommit mode, then commit those ** changes. If a rollback is needed, then do the rollback. @@ -2012,10 +2041,14 @@ int sqlite3VdbeHalt(Vdbe *p){ && db->writeVdbeCnt==(p->readOnly==0) ){ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ - /* The auto-commit flag is true, and the vdbe program was - ** successful or hit an 'OR FAIL' constraint. This means a commit - ** is required. - */ + if( sqlite3VdbeCheckDeferred(p) ){ + sqlite3BtreeMutexArrayLeave(&p->aMutex); + return SQLITE_ERROR; + } + /* The auto-commit flag is true, the vdbe program was successful + ** or hit an 'OR FAIL' constraint and there are no deferred foreign + ** key constraints to hold up the transaction. This means a commit + ** is required. */ rc = vdbeCommit(db, p); if( rc==SQLITE_BUSY ){ sqlite3BtreeMutexArrayLeave(&p->aMutex); @@ -2024,6 +2057,7 @@ int sqlite3VdbeHalt(Vdbe *p){ p->rc = rc; sqlite3RollbackAll(db); }else{ + db->nDeferredCons = 0; sqlite3CommitInternalChanges(db); } }else{ |