]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the "defer_foreign_keys" pragma and the SQLITE_DBSTATUS_DEFERRED_FKS
authordrh <drh@noemail.net>
Thu, 11 Jul 2013 15:03:32 +0000 (15:03 +0000)
committerdrh <drh@noemail.net>
Thu, 11 Jul 2013 15:03:32 +0000 (15:03 +0000)
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

15 files changed:
manifest
manifest.uuid
src/fkey.c
src/main.c
src/pragma.c
src/sqlite.h.in
src/sqliteInt.h
src/status.c
src/test_malloc.c
src/vdbe.c
src/vdbeInt.h
src/vdbeapi.c
src/vdbeaux.c
test/fkey1.test
test/fkey6.test [new file with mode: 0644]

index 817d63dd608286e1533f43ce1dbcc1301a5df34f..e85691eaa309263deebfbe3dcaa9d321da32e6db 100644 (file)
--- 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
index 193a2a3d0461cdba49c75d80bf50663c707df2af..698be2beaf426c4f7f597193dd7a11bdf25ab0de 100644 (file)
@@ -1 +1 @@
-908141d5bf7a9ad8f40c2332476847733eca7fdc
\ No newline at end of file
+527121ac3cdc96ac33ad975c227a6685a2f7e999
\ No newline at end of file
index ac35bc194cdeb127989b094035cee06f57376f5e..bb59c656f6be009f314bafd7663abe1f050ce0a2 100644 (file)
@@ -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.  */
index fe30d43f2cda0880dd4e8d6876c57700e369c03c..c23a6212d3d62d67e7f8d851602e582fb36b148f 100644 (file)
@@ -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) ){
index 5803f6c4a5bcee5f975a237d7a79e82e46b4d2b3..fd0ebc727c2e6e087001b2aca89578d7a5a58eb1 100644 (file)
@@ -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 
index 87bce973a4b6951c70e73f391312c8e3aae33006..4d8ba21f307f53453815b161d3aa8e2a7f736ff5 100644 (file)
@@ -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.
 ** </dd>
+**
+** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
+** <dd>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.
+** </dd>
 ** </dl>
 */
 #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 */
 
 
 /*
index d1d73cd5bba1f5f710a06055ec859967e35b1cc1..dcd74f91d2b25480f5932fd804468d3eac9c5507 100644 (file)
@@ -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) */
 };
 
index 28349e6d3d2088e0003b76f80a8954faec5930ba..5fcb68ddc3836827f66264b1d6932079b1fb2e81 100644 (file)
@@ -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;
     }
index cf98a8fb2182c0baf50ad57979b675bb707a93b0..2e31f0833d2f57b81bf16f8dd3be480dba26b06e 100644 (file)
@@ -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 ){
index 9a56518c57912dedf365aaca9c1b6ac1b6eb0124..104ea8b7028aa216edf579ba5b791e37738b41ae 100644 (file)
@@ -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;
 }
index 289f83d45dda9670bb7d1c9c8424a5f585e5b460..11c34fd5240d629c9c4653577765024dc80895bb 100644 (file)
@@ -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
index efa9e96962279799f6a9b5ded72e02ec4d65c798..ad3eea13a7c3c114e95be16f5dcf39d585d7303e 100644 (file)
@@ -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 ){
index fb8294a256bd455e7c380effd1f6c598f1238883..dfdf7800a444be513d8bfb6e08ffd3df01360e36 100644 (file)
@@ -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{
index e7c00d16d4b38a9fbbc22f39f4c18ac735864c68..90a4c44409ed94d68188651efe3eabeedc7ce3eb 100644 (file)
@@ -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 (file)
index 0000000..66286b4
--- /dev/null
@@ -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