mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
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
This commit is contained in:
35
manifest
35
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sharmless\scompiler\swarnings\sin\sthe\sprogress\scallback\slogic.
|
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-10T18:14:29.988
|
D 2013-07-11T15:03:32.117
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
|
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@@ -174,7 +174,7 @@ F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
|||||||
F src/delete.c aeabdabeeeaa0584127f291baa9617153d334778
|
F src/delete.c aeabdabeeeaa0584127f291baa9617153d334778
|
||||||
F src/expr.c 2b47ae9da6c9f34eff6736962ea2e102c6c4a755
|
F src/expr.c 2b47ae9da6c9f34eff6736962ea2e102c6c4a755
|
||||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||||
F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179
|
F src/fkey.c 914a6bbd987d857c41ac9d244efa6641f36faadb
|
||||||
F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef
|
F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef
|
||||||
F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
|
F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
|
||||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||||
@@ -185,7 +185,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
|||||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||||
F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2
|
F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2
|
||||||
F src/main.c 97b8ebbab272ab0d97966c791956dad1921357ba
|
F src/main.c e5810b2d7a0bd19f3d75ce60e3ed918cafc0a3f3
|
||||||
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
|
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
|
||||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||||
F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa
|
F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa
|
||||||
@@ -210,7 +210,7 @@ F src/parse.y 9acfcc83ddbf0cf82f0ed9582ccf0ad6c366ff37
|
|||||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||||
F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938
|
F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938
|
||||||
F src/pragma.c 67a611bd4be0754f27ee13eb87932c3b14415862
|
F src/pragma.c c87581d93a7518cba656b7919e32ded5d331b76a
|
||||||
F src/prepare.c 2306be166bbeddf454e18bf8b21dba8388d05328
|
F src/prepare.c 2306be166bbeddf454e18bf8b21dba8388d05328
|
||||||
F src/printf.c 41c49dac366a3a411190001a8ab495fa8887974e
|
F src/printf.c 41c49dac366a3a411190001a8ab495fa8887974e
|
||||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||||
@@ -218,12 +218,12 @@ F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8
|
|||||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||||
F src/select.c 91b62654caf8dfe292fb8882715e575d34ad3874
|
F src/select.c 91b62654caf8dfe292fb8882715e575d34ad3874
|
||||||
F src/shell.c c8cd06e6b66250a3ea0149c4edec30de14f57b6f
|
F src/shell.c c8cd06e6b66250a3ea0149c4edec30de14f57b6f
|
||||||
F src/sqlite.h.in 0a87152a6dde55381afb8f1cf37f337b2f32fd06
|
F src/sqlite.h.in 80d11140d401f366f7249f3c4fe031c49a5a06f8
|
||||||
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
|
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
|
||||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||||
F src/sqliteInt.h df1a921448e765227de3ed8933fcc1e22bebec82
|
F src/sqliteInt.h 074f5cdfb99e0d4dc8100c217824f384c16af56b
|
||||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||||
F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
|
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||||
F src/tclsqlite.c b8835978e853a89bf58de88acc943a5ca94d752e
|
F src/tclsqlite.c b8835978e853a89bf58de88acc943a5ca94d752e
|
||||||
F src/test1.c 870fc648a48cb6d6808393174f7ebe82b8c840fa
|
F src/test1.c 870fc648a48cb6d6808393174f7ebe82b8c840fa
|
||||||
@@ -250,7 +250,7 @@ F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61
|
|||||||
F src/test_intarray.h b999bb18d090b8d9d9c49d36ec37ef8f341fe169
|
F src/test_intarray.h b999bb18d090b8d9d9c49d36ec37ef8f341fe169
|
||||||
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
|
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
|
||||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
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.c 5d691eeb6cb6aa7888da28eba5e62a9a857d3c0f
|
||||||
F src/test_multiplex.h 9b63b95f07acedee425fdfe49a47197c9bf5f9d8
|
F src/test_multiplex.h 9b63b95f07acedee425fdfe49a47197c9bf5f9d8
|
||||||
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
|
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
|
||||||
@@ -277,11 +277,11 @@ F src/update.c 8e76c3d03e4b7b21cb250bd2df0c05e12993e577
|
|||||||
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
|
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
|
||||||
F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9
|
F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9
|
||||||
F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8
|
F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8
|
||||||
F src/vdbe.c b4d29f875ff2c8506783c6831b2d539cdeb39b91
|
F src/vdbe.c 0661945edc8b8d85dccc137925c45542fad9a5a4
|
||||||
F src/vdbe.h b52887278cb173e66188da84dfab216bea61119d
|
F src/vdbe.h b52887278cb173e66188da84dfab216bea61119d
|
||||||
F src/vdbeInt.h aa185c6df4f2b5ec9896cdb5f96789af1ef69f76
|
F src/vdbeInt.h 5e666c971c555c7977714b0e34cb8d4b20282557
|
||||||
F src/vdbeapi.c e3ad4cddb713a387527f982e79d9e001a0dbffa5
|
F src/vdbeapi.c c88222946d657984bdaf394604cb58ed1d641460
|
||||||
F src/vdbeaux.c 9683f262c7fd0af8cb03f0053651135005cdda8a
|
F src/vdbeaux.c 1633408f6dea06129441c5e2f22b2a5ce30fe97e
|
||||||
F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69
|
F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69
|
||||||
F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab
|
F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab
|
||||||
F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
|
F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
|
||||||
@@ -452,11 +452,12 @@ F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d
|
|||||||
F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7
|
F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7
|
||||||
F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a
|
F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a
|
||||||
F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146
|
F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146
|
||||||
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
|
F test/fkey1.test e1d1fa84cde579185ea01358436839703e415a5b
|
||||||
F test/fkey2.test 06e0b4cc9e1b3271ae2ae6feeb19755468432111
|
F test/fkey2.test 06e0b4cc9e1b3271ae2ae6feeb19755468432111
|
||||||
F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e
|
F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e
|
||||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||||
F test/fkey5.test 0bf64f2d19ad80433ca0b24edbf604a18b353d5f
|
F test/fkey5.test 0bf64f2d19ad80433ca0b24edbf604a18b353d5f
|
||||||
|
F test/fkey6.test 2d76497c54db0e5bfbecee0acf00bb8a706b37db
|
||||||
F test/fkey_malloc.test bb74c9cb8f8fceed03b58f8a7ef2df98520bbd51
|
F test/fkey_malloc.test bb74c9cb8f8fceed03b58f8a7ef2df98520bbd51
|
||||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||||
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
||||||
@@ -1101,7 +1102,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
|||||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||||
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
|
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
|
||||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||||
P 3e8b02011db2f393d4850115a471709b0a88594f
|
P 908141d5bf7a9ad8f40c2332476847733eca7fdc
|
||||||
R e1fccaff7bc35266cc5b7f175242cdcd
|
R f701d887eba2f81d7816617ba86ca3a2
|
||||||
U drh
|
U drh
|
||||||
Z 1564bfae3de8c8d60d1d15cc4d698c7c
|
Z 50e77e8dbcbbcc008f0da119505e5900
|
||||||
|
@@ -1 +1 @@
|
|||||||
908141d5bf7a9ad8f40c2332476847733eca7fdc
|
527121ac3cdc96ac33ad975c227a6685a2f7e999
|
@@ -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
|
/* Special case: If this is an INSERT statement that will insert exactly
|
||||||
** one row into the table, raise a constraint immediately instead of
|
** one row into the table, raise a constraint immediately instead of
|
||||||
** incrementing a counter. This is necessary as the VM code is being
|
** incrementing a counter. This is necessary as the VM code is being
|
||||||
@@ -813,7 +816,9 @@ void sqlite3FkCheck(
|
|||||||
SrcList *pSrc;
|
SrcList *pSrc;
|
||||||
int *aiCol = 0;
|
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 );
|
assert( regOld==0 && regNew!=0 );
|
||||||
/* Inserting a single row into a parent table cannot cause an immediate
|
/* Inserting a single row into a parent table cannot cause an immediate
|
||||||
** foreign key violation. So do nothing in this case. */
|
** foreign key violation. So do nothing in this case. */
|
||||||
|
@@ -1037,6 +1037,8 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
|||||||
|
|
||||||
/* Any deferred constraint violations have now been resolved. */
|
/* Any deferred constraint violations have now been resolved. */
|
||||||
db->nDeferredCons = 0;
|
db->nDeferredCons = 0;
|
||||||
|
db->nDeferredImmCons = 0;
|
||||||
|
db->flags &= ~SQLITE_DeferFKs;
|
||||||
|
|
||||||
/* If one has been configured, invoke the rollback-hook callback */
|
/* If one has been configured, invoke the rollback-hook callback */
|
||||||
if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
|
if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
|
||||||
|
@@ -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
|
/* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
|
||||||
** flag if there are any active statements. */
|
** flag if there are any active statements. */
|
||||||
{ "read_uncommitted", SQLITE_ReadUncommitted },
|
{ "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
|
/* This flag may only be set if both foreign-key and trigger support
|
||||||
** are present in the build. */
|
** are present in the build. */
|
||||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
||||||
{ "foreign_keys", SQLITE_ForeignKeys },
|
{ "foreign_keys", SQLITE_ForeignKeys },
|
||||||
|
{ "defer_foreign_keys", SQLITE_DeferFKs },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
@@ -228,6 +229,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
|||||||
db->flags |= mask;
|
db->flags |= mask;
|
||||||
}else{
|
}else{
|
||||||
db->flags &= ~mask;
|
db->flags &= ~mask;
|
||||||
|
if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Many of the flag-pragmas modify the code generated by the SQL
|
/* Many of the flag-pragmas modify the code generated by the SQL
|
||||||
|
@@ -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
|
** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The
|
||||||
** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
|
** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
|
||||||
** </dd>
|
** </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>
|
** </dl>
|
||||||
*/
|
*/
|
||||||
#define SQLITE_DBSTATUS_LOOKASIDE_USED 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_HIT 7
|
||||||
#define SQLITE_DBSTATUS_CACHE_MISS 8
|
#define SQLITE_DBSTATUS_CACHE_MISS 8
|
||||||
#define SQLITE_DBSTATUS_CACHE_WRITE 9
|
#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 */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -954,6 +954,7 @@ struct sqlite3 {
|
|||||||
int nSavepoint; /* Number of non-transaction savepoints */
|
int nSavepoint; /* Number of non-transaction savepoints */
|
||||||
int nStatement; /* Number of nested statement-transactions */
|
int nStatement; /* Number of nested statement-transactions */
|
||||||
i64 nDeferredCons; /* Net deferred constraints this transaction. */
|
i64 nDeferredCons; /* Net deferred constraints this transaction. */
|
||||||
|
i64 nDeferredImmCons; /* Net deferred immediate constraints */
|
||||||
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
|
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||||
@@ -1009,6 +1010,7 @@ struct sqlite3 {
|
|||||||
#define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */
|
#define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */
|
||||||
#define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */
|
#define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */
|
||||||
#define SQLITE_EnableTrigger 0x00400000 /* True to enable triggers */
|
#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
|
** Bits of the sqlite3.dbOptFlags field that are used by the
|
||||||
@@ -1155,6 +1157,7 @@ struct FuncDestructor {
|
|||||||
struct Savepoint {
|
struct Savepoint {
|
||||||
char *zName; /* Savepoint name (nul-terminated) */
|
char *zName; /* Savepoint name (nul-terminated) */
|
||||||
i64 nDeferredCons; /* Number of deferred fk violations */
|
i64 nDeferredCons; /* Number of deferred fk violations */
|
||||||
|
i64 nDeferredImmCons; /* Number of deferred imm fk. */
|
||||||
Savepoint *pNext; /* Parent savepoint (if any) */
|
Savepoint *pNext; /* Parent savepoint (if any) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
10
src/status.c
10
src/status.c
@@ -243,6 +243,16 @@ int sqlite3_db_status(
|
|||||||
break;
|
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: {
|
default: {
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
|
@@ -1349,7 +1349,8 @@ static int test_db_status(
|
|||||||
{ "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL },
|
{ "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL },
|
||||||
{ "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT },
|
{ "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT },
|
||||||
{ "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS },
|
{ "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;
|
Tcl_Obj *pResult;
|
||||||
if( objc!=4 ){
|
if( objc!=4 ){
|
||||||
|
13
src/vdbe.c
13
src/vdbe.c
@@ -874,7 +874,7 @@ case OP_Halt: {
|
|||||||
p->rc = rc = SQLITE_BUSY;
|
p->rc = rc = SQLITE_BUSY;
|
||||||
}else{
|
}else{
|
||||||
assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
|
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;
|
rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
|
||||||
}
|
}
|
||||||
goto vdbe_return;
|
goto vdbe_return;
|
||||||
@@ -2734,6 +2734,7 @@ case OP_Savepoint: {
|
|||||||
pNew->pNext = db->pSavepoint;
|
pNew->pNext = db->pSavepoint;
|
||||||
db->pSavepoint = pNew;
|
db->pSavepoint = pNew;
|
||||||
pNew->nDeferredCons = db->nDeferredCons;
|
pNew->nDeferredCons = db->nDeferredCons;
|
||||||
|
pNew->nDeferredImmCons = db->nDeferredImmCons;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@@ -2821,6 +2822,7 @@ case OP_Savepoint: {
|
|||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
db->nDeferredCons = pSavepoint->nDeferredCons;
|
db->nDeferredCons = pSavepoint->nDeferredCons;
|
||||||
|
db->nDeferredImmCons = pSavepoint->nDeferredImmCons;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !isTransaction ){
|
if( !isTransaction ){
|
||||||
@@ -2978,6 +2980,7 @@ case OP_Transaction: {
|
|||||||
** counter. If the statement transaction needs to be rolled back,
|
** counter. If the statement transaction needs to be rolled back,
|
||||||
** the value of this counter needs to be restored too. */
|
** the value of this counter needs to be restored too. */
|
||||||
p->nStmtDefCons = db->nDeferredCons;
|
p->nStmtDefCons = db->nDeferredCons;
|
||||||
|
p->nStmtDefImmCons = db->nDeferredImmCons;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -5287,7 +5290,9 @@ case OP_Param: { /* out2-prerelease */
|
|||||||
** statement counter is incremented (immediate foreign key constraints).
|
** statement counter is incremented (immediate foreign key constraints).
|
||||||
*/
|
*/
|
||||||
case OP_FkCounter: {
|
case OP_FkCounter: {
|
||||||
if( pOp->p1 ){
|
if( db->flags & SQLITE_DeferFKs ){
|
||||||
|
db->nDeferredImmCons += pOp->p2;
|
||||||
|
}else if( pOp->p1 ){
|
||||||
db->nDeferredCons += pOp->p2;
|
db->nDeferredCons += pOp->p2;
|
||||||
}else{
|
}else{
|
||||||
p->nFkConstraint += pOp->p2;
|
p->nFkConstraint += pOp->p2;
|
||||||
@@ -5308,9 +5313,9 @@ case OP_FkCounter: {
|
|||||||
*/
|
*/
|
||||||
case OP_FkIfZero: { /* jump */
|
case OP_FkIfZero: { /* jump */
|
||||||
if( pOp->p1 ){
|
if( pOp->p1 ){
|
||||||
if( db->nDeferredCons==0 ) pc = pOp->p2-1;
|
if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1;
|
||||||
}else{
|
}else{
|
||||||
if( p->nFkConstraint==0 ) pc = pOp->p2-1;
|
if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -351,6 +351,7 @@ struct Vdbe {
|
|||||||
#endif
|
#endif
|
||||||
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
|
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
|
||||||
i64 nStmtDefCons; /* Number of def. constraints when stmt started */
|
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 */
|
char *zSql; /* Text of the SQL statement that generated this */
|
||||||
void *pFree; /* Free this when deleting the vdbe */
|
void *pFree; /* Free this when deleting the vdbe */
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
|
@@ -386,7 +386,9 @@ static int sqlite3Step(Vdbe *p){
|
|||||||
db->u1.isInterrupted = 0;
|
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
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
if( db->xProfile && !db->init.busy ){
|
if( db->xProfile && !db->init.busy ){
|
||||||
|
@@ -2065,6 +2065,7 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
|
|||||||
** the statement transaction was opened. */
|
** the statement transaction was opened. */
|
||||||
if( eOp==SAVEPOINT_ROLLBACK ){
|
if( eOp==SAVEPOINT_ROLLBACK ){
|
||||||
db->nDeferredCons = p->nStmtDefCons;
|
db->nDeferredCons = p->nStmtDefCons;
|
||||||
|
db->nDeferredImmCons = p->nStmtDefImmCons;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
@@ -2083,7 +2084,9 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
|
|||||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||||
int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
|
int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
|
||||||
sqlite3 *db = p->db;
|
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->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
|
||||||
p->errorAction = OE_Abort;
|
p->errorAction = OE_Abort;
|
||||||
sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
|
sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
|
||||||
@@ -2216,6 +2219,8 @@ int sqlite3VdbeHalt(Vdbe *p){
|
|||||||
sqlite3RollbackAll(db, SQLITE_OK);
|
sqlite3RollbackAll(db, SQLITE_OK);
|
||||||
}else{
|
}else{
|
||||||
db->nDeferredCons = 0;
|
db->nDeferredCons = 0;
|
||||||
|
db->nDeferredImmCons = 0;
|
||||||
|
db->flags &= ~SQLITE_DeferFKs;
|
||||||
sqlite3CommitInternalChanges(db);
|
sqlite3CommitInternalChanges(db);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
@@ -117,5 +117,8 @@ do_test fkey1-3.4 {
|
|||||||
{0 0 t5 d {} {SET DEFAULT} CASCADE NONE} \
|
{0 0 t5 d {} {SET DEFAULT} CASCADE NONE} \
|
||||||
{0 1 t5 e {} {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
|
finish_test
|
||||||
|
103
test/fkey6.test
Normal file
103
test/fkey6.test
Normal file
@@ -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
|
Reference in New Issue
Block a user