aboutsummaryrefslogtreecommitdiff
path: root/src/vdbeaux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vdbeaux.c')
-rw-r--r--src/vdbeaux.c42
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{