From: drh Date: Thu, 11 Jul 2013 15:03:32 +0000 (+0000) Subject: Add the "defer_foreign_keys" pragma and the SQLITE_DBSTATUS_DEFERRED_FKS X-Git-Tag: version-3.8.0~91 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=648e264342fe3315d23979c8779a4200babea891;p=thirdparty%2Fsqlite.git Add the "defer_foreign_keys" pragma and the SQLITE_DBSTATUS_DEFERRED_FKS value for sqlite3_db_status(). This is a cherry-pick of a sequence of five checkins in the sessions branch between [1d44e5d3c2] and [d39e65fe70]. FossilOrigin-Name: 527121ac3cdc96ac33ad975c227a6685a2f7e999 --- diff --git a/manifest b/manifest index 817d63dd60..e85691eaa3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\scompiler\swarnings\sin\sthe\sprogress\scallback\slogic. -D 2013-07-10T18:14:29.988 +C Add\sthe\s"defer_foreign_keys"\spragma\sand\sthe\sSQLITE_DBSTATUS_DEFERRED_FKS\nvalue\sfor\ssqlite3_db_status().\s\sThis\sis\sa\scherry-pick\sof\sa\ssequence\sof\sfive\ncheckins\sin\sthe\ssessions\sbranch\sbetween\s[1d44e5d3c2]\sand\s[d39e65fe70]. +D 2013-07-11T15:03:32.117 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -174,7 +174,7 @@ F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/delete.c aeabdabeeeaa0584127f291baa9617153d334778 F src/expr.c 2b47ae9da6c9f34eff6736962ea2e102c6c4a755 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179 +F src/fkey.c 914a6bbd987d857c41ac9d244efa6641f36faadb F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4 @@ -185,7 +185,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2 -F src/main.c 97b8ebbab272ab0d97966c791956dad1921357ba +F src/main.c e5810b2d7a0bd19f3d75ce60e3ed918cafc0a3f3 F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa @@ -210,7 +210,7 @@ F src/parse.y 9acfcc83ddbf0cf82f0ed9582ccf0ad6c366ff37 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938 -F src/pragma.c 67a611bd4be0754f27ee13eb87932c3b14415862 +F src/pragma.c c87581d93a7518cba656b7919e32ded5d331b76a F src/prepare.c 2306be166bbeddf454e18bf8b21dba8388d05328 F src/printf.c 41c49dac366a3a411190001a8ab495fa8887974e F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 @@ -218,12 +218,12 @@ F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/select.c 91b62654caf8dfe292fb8882715e575d34ad3874 F src/shell.c c8cd06e6b66250a3ea0149c4edec30de14f57b6f -F src/sqlite.h.in 0a87152a6dde55381afb8f1cf37f337b2f32fd06 +F src/sqlite.h.in 80d11140d401f366f7249f3c4fe031c49a5a06f8 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h df1a921448e765227de3ed8933fcc1e22bebec82 +F src/sqliteInt.h 074f5cdfb99e0d4dc8100c217824f384c16af56b F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d -F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 +F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c b8835978e853a89bf58de88acc943a5ca94d752e F src/test1.c 870fc648a48cb6d6808393174f7ebe82b8c840fa @@ -250,7 +250,7 @@ F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61 F src/test_intarray.h b999bb18d090b8d9d9c49d36ec37ef8f341fe169 F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64 F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e -F src/test_malloc.c 2855429b8232107b3296409be2a8eb68345290c2 +F src/test_malloc.c a105801222c0514f8befa2a1712a95505cce099a F src/test_multiplex.c 5d691eeb6cb6aa7888da28eba5e62a9a857d3c0f F src/test_multiplex.h 9b63b95f07acedee425fdfe49a47197c9bf5f9d8 F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f @@ -277,11 +277,11 @@ F src/update.c 8e76c3d03e4b7b21cb250bd2df0c05e12993e577 F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9 F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8 -F src/vdbe.c b4d29f875ff2c8506783c6831b2d539cdeb39b91 +F src/vdbe.c 0661945edc8b8d85dccc137925c45542fad9a5a4 F src/vdbe.h b52887278cb173e66188da84dfab216bea61119d -F src/vdbeInt.h aa185c6df4f2b5ec9896cdb5f96789af1ef69f76 -F src/vdbeapi.c e3ad4cddb713a387527f982e79d9e001a0dbffa5 -F src/vdbeaux.c 9683f262c7fd0af8cb03f0053651135005cdda8a +F src/vdbeInt.h 5e666c971c555c7977714b0e34cb8d4b20282557 +F src/vdbeapi.c c88222946d657984bdaf394604cb58ed1d641460 +F src/vdbeaux.c 1633408f6dea06129441c5e2f22b2a5ce30fe97e F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69 F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017 @@ -452,11 +452,12 @@ F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7 F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146 -F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da +F test/fkey1.test e1d1fa84cde579185ea01358436839703e415a5b F test/fkey2.test 06e0b4cc9e1b3271ae2ae6feeb19755468432111 F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d F test/fkey5.test 0bf64f2d19ad80433ca0b24edbf604a18b353d5f +F test/fkey6.test 2d76497c54db0e5bfbecee0acf00bb8a706b37db F test/fkey_malloc.test bb74c9cb8f8fceed03b58f8a7ef2df98520bbd51 F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c @@ -1101,7 +1102,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 3e8b02011db2f393d4850115a471709b0a88594f -R e1fccaff7bc35266cc5b7f175242cdcd +P 908141d5bf7a9ad8f40c2332476847733eca7fdc +R f701d887eba2f81d7816617ba86ca3a2 U drh -Z 1564bfae3de8c8d60d1d15cc4d698c7c +Z 50e77e8dbcbbcc008f0da119505e5900 diff --git a/manifest.uuid b/manifest.uuid index 193a2a3d04..698be2beaf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -908141d5bf7a9ad8f40c2332476847733eca7fdc \ No newline at end of file +527121ac3cdc96ac33ad975c227a6685a2f7e999 \ No newline at end of file diff --git a/src/fkey.c b/src/fkey.c index ac35bc194c..bb59c656f6 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -422,7 +422,10 @@ static void fkLookupParent( } } - if( !pFKey->isDeferred && !pParse->pToplevel && !pParse->isMultiWrite ){ + if( !pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs) + && !pParse->pToplevel + && !pParse->isMultiWrite + ){ /* Special case: If this is an INSERT statement that will insert exactly ** one row into the table, raise a constraint immediately instead of ** incrementing a counter. This is necessary as the VM code is being @@ -813,7 +816,9 @@ void sqlite3FkCheck( SrcList *pSrc; int *aiCol = 0; - if( !pFKey->isDeferred && !pParse->pToplevel && !pParse->isMultiWrite ){ + if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs) + && !pParse->pToplevel && !pParse->isMultiWrite + ){ assert( regOld==0 && regNew!=0 ); /* Inserting a single row into a parent table cannot cause an immediate ** foreign key violation. So do nothing in this case. */ diff --git a/src/main.c b/src/main.c index fe30d43f2c..c23a6212d3 100644 --- a/src/main.c +++ b/src/main.c @@ -1037,6 +1037,8 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; + db->nDeferredImmCons = 0; + db->flags &= ~SQLITE_DeferFKs; /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ diff --git a/src/pragma.c b/src/pragma.c index 5803f6c4a5..fd0ebc727c 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -197,12 +197,13 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){ /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted ** flag if there are any active statements. */ { "read_uncommitted", SQLITE_ReadUncommitted }, - { "recursive_triggers", SQLITE_RecTriggers }, + { "recursive_triggers", SQLITE_RecTriggers }, /* This flag may only be set if both foreign-key and trigger support ** are present in the build. */ #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - { "foreign_keys", SQLITE_ForeignKeys }, + { "foreign_keys", SQLITE_ForeignKeys }, + { "defer_foreign_keys", SQLITE_DeferFKs }, #endif }; int i; @@ -228,6 +229,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){ db->flags |= mask; }else{ db->flags &= ~mask; + if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; } /* Many of the flag-pragmas modify the code generated by the SQL diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 87bce973a4..4d8ba21f30 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6239,6 +6239,12 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. ** +** +** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(
SQLITE_DBSTATUS_DEFERRED_FKS
+**
This parameter returns the zero for the current value if and only if +** there all foreign key constraints (deferred or immediate) have been +** resolved. The highwater mark is always 0. +**
** */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 @@ -6251,7 +6257,8 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 -#define SQLITE_DBSTATUS_MAX 9 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_DEFERRED_FKS 10 +#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */ /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d1d73cd5bb..dcd74f91d2 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -954,6 +954,7 @@ struct sqlite3 { int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ + i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY @@ -1009,6 +1010,7 @@ struct sqlite3 { #define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */ #define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */ #define SQLITE_EnableTrigger 0x00400000 /* True to enable triggers */ +#define SQLITE_DeferFKs 0x00800000 /* Defer all FK constraints */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the @@ -1155,6 +1157,7 @@ struct FuncDestructor { struct Savepoint { char *zName; /* Savepoint name (nul-terminated) */ i64 nDeferredCons; /* Number of deferred fk violations */ + i64 nDeferredImmCons; /* Number of deferred imm fk. */ Savepoint *pNext; /* Parent savepoint (if any) */ }; diff --git a/src/status.c b/src/status.c index 28349e6d3d..5fcb68ddc3 100644 --- a/src/status.c +++ b/src/status.c @@ -243,6 +243,16 @@ int sqlite3_db_status( break; } + /* Set *pCurrent to non-zero if there are unresolved deferred foreign + ** key constraints. Set *pCurrent to zero if all foreign key constraints + ** have been satisfied. The *pHighwater is always set to zero. + */ + case SQLITE_DBSTATUS_DEFERRED_FKS: { + *pHighwater = 0; + *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; + break; + } + default: { rc = SQLITE_ERROR; } diff --git a/src/test_malloc.c b/src/test_malloc.c index cf98a8fb21..2e31f0833d 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -1349,7 +1349,8 @@ static int test_db_status( { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL }, { "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT }, { "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS }, - { "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE } + { "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE }, + { "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS } }; Tcl_Obj *pResult; if( objc!=4 ){ diff --git a/src/vdbe.c b/src/vdbe.c index 9a56518c57..104ea8b702 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -874,7 +874,7 @@ case OP_Halt: { p->rc = rc = SQLITE_BUSY; }else{ assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ); - assert( rc==SQLITE_OK || db->nDeferredCons>0 ); + assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 ); rc = p->rc ? SQLITE_ERROR : SQLITE_DONE; } goto vdbe_return; @@ -2734,6 +2734,7 @@ case OP_Savepoint: { pNew->pNext = db->pSavepoint; db->pSavepoint = pNew; pNew->nDeferredCons = db->nDeferredCons; + pNew->nDeferredImmCons = db->nDeferredImmCons; } } }else{ @@ -2821,6 +2822,7 @@ case OP_Savepoint: { } }else{ db->nDeferredCons = pSavepoint->nDeferredCons; + db->nDeferredImmCons = pSavepoint->nDeferredImmCons; } if( !isTransaction ){ @@ -2978,6 +2980,7 @@ case OP_Transaction: { ** counter. If the statement transaction needs to be rolled back, ** the value of this counter needs to be restored too. */ p->nStmtDefCons = db->nDeferredCons; + p->nStmtDefImmCons = db->nDeferredImmCons; } } break; @@ -5287,7 +5290,9 @@ case OP_Param: { /* out2-prerelease */ ** statement counter is incremented (immediate foreign key constraints). */ case OP_FkCounter: { - if( pOp->p1 ){ + if( db->flags & SQLITE_DeferFKs ){ + db->nDeferredImmCons += pOp->p2; + }else if( pOp->p1 ){ db->nDeferredCons += pOp->p2; }else{ p->nFkConstraint += pOp->p2; @@ -5308,9 +5313,9 @@ case OP_FkCounter: { */ case OP_FkIfZero: { /* jump */ if( pOp->p1 ){ - if( db->nDeferredCons==0 ) pc = pOp->p2-1; + if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1; }else{ - if( p->nFkConstraint==0 ) pc = pOp->p2-1; + if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1; } break; } diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 289f83d45d..11c34fd524 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -351,6 +351,7 @@ struct Vdbe { #endif i64 nFkConstraint; /* Number of imm. FK constraints this VM */ i64 nStmtDefCons; /* Number of def. constraints when stmt started */ + i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ char *zSql; /* Text of the SQL statement that generated this */ void *pFree; /* Free this when deleting the vdbe */ #ifdef SQLITE_DEBUG diff --git a/src/vdbeapi.c b/src/vdbeapi.c index efa9e96962..ad3eea13a7 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -386,7 +386,9 @@ static int sqlite3Step(Vdbe *p){ db->u1.isInterrupted = 0; } - assert( db->nVdbeWrite>0 || db->autoCommit==0 || db->nDeferredCons==0 ); + assert( db->nVdbeWrite>0 || db->autoCommit==0 + || (db->nDeferredCons==0 && db->nDeferredImmCons==0) + ); #ifndef SQLITE_OMIT_TRACE if( db->xProfile && !db->init.busy ){ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index fb8294a256..dfdf7800a4 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2065,6 +2065,7 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ ** the statement transaction was opened. */ if( eOp==SAVEPOINT_ROLLBACK ){ db->nDeferredCons = p->nStmtDefCons; + db->nDeferredImmCons = p->nStmtDefImmCons; } } return rc; @@ -2083,7 +2084,9 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ #ifndef SQLITE_OMIT_FOREIGN_KEY int sqlite3VdbeCheckFk(Vdbe *p, int deferred){ sqlite3 *db = p->db; - if( (deferred && db->nDeferredCons>0) || (!deferred && p->nFkConstraint>0) ){ + if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0) + || (!deferred && p->nFkConstraint>0) + ){ p->rc = SQLITE_CONSTRAINT_FOREIGNKEY; p->errorAction = OE_Abort; sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed"); @@ -2216,6 +2219,8 @@ int sqlite3VdbeHalt(Vdbe *p){ sqlite3RollbackAll(db, SQLITE_OK); }else{ db->nDeferredCons = 0; + db->nDeferredImmCons = 0; + db->flags &= ~SQLITE_DeferFKs; sqlite3CommitInternalChanges(db); } }else{ diff --git a/test/fkey1.test b/test/fkey1.test index e7c00d16d4..90a4c44409 100644 --- a/test/fkey1.test +++ b/test/fkey1.test @@ -117,5 +117,8 @@ do_test fkey1-3.4 { {0 0 t5 d {} {SET DEFAULT} CASCADE NONE} \ {0 1 t5 e {} {SET DEFAULT} CASCADE NONE} \ ] +do_test fkey1-3.5 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 0 0} finish_test diff --git a/test/fkey6.test b/test/fkey6.test new file mode 100644 index 0000000000..66286b43ec --- /dev/null +++ b/test/fkey6.test @@ -0,0 +1,103 @@ +# 2012 December 17 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file tests the PRAGMA defer_foreign_keys and +# SQLITE_DBSTATUS_DEFERRED_FKS +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable {!foreignkey} { + finish_test + return +} + +do_execsql_test fkey6-1.1 { + PRAGMA foreign_keys=ON; + CREATE TABLE t1(x INTEGER PRIMARY KEY); + CREATE TABLE t2(y INTEGER PRIMARY KEY, + z INTEGER REFERENCES t1(x) DEFERRABLE INITIALLY DEFERRED); + CREATE INDEX t2z ON t2(z); + CREATE TABLE t3(u INTEGER PRIMARY KEY, v INTEGER REFERENCES t1(x)); + CREATE INDEX t3v ON t3(v); + INSERT INTO t1 VALUES(1),(2),(3),(4),(5); + INSERT INTO t2 VALUES(1,1),(2,2); + INSERT INTO t3 VALUES(3,3),(4,4); +} {} +do_test fkey6-1.2 { + catchsql {DELETE FROM t1 WHERE x=2;} +} {1 {foreign key constraint failed}} +do_test fkey6-1.3 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 0 0} +do_test fkey6-1.4 { + execsql { + BEGIN; + DELETE FROM t1 WHERE x=1; + } +} {} +do_test fkey6-1.5.1 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 1 +} {0 1 0} +do_test fkey6-1.5.2 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 1 0} +do_test fkey6-1.6 { + execsql { + ROLLBACK; + } +} {} +do_test fkey6-1.7 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 0 0} +do_test fkey6-1.8 { + execsql { + PRAGMA defer_foreign_keys=ON; + BEGIN; + DELETE FROM t1 WHERE x=3; + } +} {} +do_test fkey6-1.9 { + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 1 0} +do_test fkey6-1.10 { + execsql { + ROLLBACK; + PRAGMA defer_foreign_keys=OFF; + BEGIN; + } + catchsql {DELETE FROM t1 WHERE x=3} +} {1 {foreign key constraint failed}} +db eval {ROLLBACK} + +do_test fkey6-1.20 { + execsql { + BEGIN; + DELETE FROM t1 WHERE x=1; + } + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 1 0} +do_test fkey6-1.21 { + execsql { + DELETE FROM t2 WHERE y=1; + } + sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 +} {0 0 0} +do_test fkey6-1.22 { + execsql { + COMMIT; + } +} {} + + +finish_test