-C Prevent\sALTER\sTABLE\sfrom\sbeing\sused\sto\sadd\sa\scolumn\swith\sa\sREFERENCES\sclause\sand\sa\snon-NULL\sdefault\svalue\swhile\sforeign\skey\ssupport\sis\senabled.
-D 2009-09-25T11:26:55
+C Fix\scomments\sin\sfkey2.c\sto\sreflect\sthe\simmediate-constraint-counter\sapproach.
+D 2009-09-25T12:00:02
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 4ca3f1dd6efa2075bcb27f4dc43eef749877740d
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F src/delete.c 2a3d6fc0861b2f8dbd9feb7847b390267b281c60
F src/expr.c c7f3f718bd5c392344ec8694a41c1824f30cf375
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
-F src/fkey.c 5ec139b6d22a981a777fb195d9311068f5a8c75b
+F src/fkey.c 8719d0fa09f8f08d5b21abf54a59cbcb88172b1b
F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606
F src/global.c 271952d199a8cc59d4ce840b3bbbfd2f30c8ba32
F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8
F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
-F test/fkey2.test ad58088fbc09231f125b6c7e9594720aa1374019
+F test/fkey2.test 8f857439feef71b11a13821aa407399e3ed9f494
F test/fkey3.test 2183cac9075f3aae4875106eb9255bb73618444e
F test/fkey_malloc.test da912d000bb6ceb1cd11b655de1989762fa71ceb
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 76e8e74b49be4c80b9fb20d52e9b39db8001362e
-R 136d37129ec61260ba7a30de652f5973
+P 353b1b18253ab71ba38a887e555994f5469b87bd
+R 686fb8f7dc051b5c786ec23c8c348ab4
U dan
-Z 5dd61108ad33d708be4c046f1054dc1d
+Z 007854d1d118a1cdcf5b42c76aa6bc04
** is thrown, even if the FK constraint would be satisfied after the new
** row is inserted.
**
+** Immediate constraints are usually handled similarly. The only difference
+** is that the counter used is stored as part of each individual statement
+** object (struct Vdbe). If, after the statement has run, its immediate
+** constraint counter is greater than zero, it returns SQLITE_CONSTRAINT
+** and the statement transaction is rolled back. An exception is an INSERT
+** statement that inserts a single row only (no triggers). In this case,
+** instead of using a counter, an exception is thrown immediately if the
+** INSERT violates a foreign key constraint. This is necessary as such
+** an INSERT does not open a statement transaction.
+**
** TODO: How should dropping a table be handled? How should renaming a
** table be handled?
**
}
/*
-** This function is called when a row is inserted into the child table of
-** foreign key constraint pFKey and, if pFKey is deferred, when a row is
-** deleted from the child table of pFKey. If an SQL UPDATE is executed on
-** the child table of pFKey, this function is invoked twice for each row
+** This function is called when a row is inserted into or deleted from the
+** child table of foreign key constraint pFKey. If an SQL UPDATE is executed
+** on the child table of pFKey, this function is invoked twice for each row
** affected - once to "delete" the old row, and then again to "insert" the
** new row.
**
**
** Operation | FK type | Action taken
** --------------------------------------------------------------------------
-** INSERT immediate Throw a "foreign key constraint failed" exception.
+** INSERT immediate Increment the "immediate constraint counter".
+**
+** DELETE immediate Decrement the "immediate constraint counter".
**
** INSERT deferred Increment the "deferred constraint counter".
**
** DELETE deferred Decrement the "deferred constraint counter".
**
-** This function is never called for a delete on the child table of an
-** immediate foreign key constraint. These operations are identified in
-** the comment at the top of this file (fkey.c) as "I.1" and "D.1".
+** These operations are identified in the comment at the top of this file
+** (fkey.c) as "I.1" and "D.1".
*/
static void fkLookupParent(
Parse *pParse, /* Parse context */
**
** Operation | FK type | Action taken
** --------------------------------------------------------------------------
-** DELETE immediate Throw a "foreign key constraint failed" exception.
+** DELETE immediate Increment the "immediate constraint counter".
+** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
+** throw a "foreign key constraint failed" exception.
+**
+** INSERT immediate Decrement the "immediate constraint counter".
**
** DELETE deferred Increment the "deferred constraint counter".
** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
**
** INSERT deferred Decrement the "deferred constraint counter".
**
-** This function is never called for an INSERT operation on the parent table
-** of an immediate foreign key constraint. These operations are identified in
-** the comment at the top of this file (fkey.c) as "I.2" and "D.2".
+** These operations are identified in the comment at the top of this file
+** (fkey.c) as "I.2" and "D.2".
*/
static void fkScanChildren(
Parse *pParse, /* Parse context */
NameContext sNameContext; /* Context used to resolve WHERE clause */
WhereInfo *pWInfo; /* Context used by sqlite3WhereXXX() */
+ /* Create an Expr object representing an SQL expression like:
+ **
+ ** <parent-key1> = <child-key1> AND <parent-key2> = <child-key2> ...
+ **
+ ** The collation sequence used for the comparison should be that of
+ ** the parent key columns. The affinity of the parent key column should
+ ** be applied to each child key value before the comparison takes place.
+ */
for(i=0; i<pFKey->nCol; i++){
Expr *pLeft; /* Value from parent table row */
Expr *pRight; /* Column ref to child table */
pLeft = sqlite3Expr(db, TK_REGISTER, 0);
if( pLeft ){
+ /* Set the collation sequence and affinity of the LHS of each TK_EQ
+ ** expression to the parent key column defaults. */
if( pIdx ){
int iCol = pIdx->aiColumn[i];
Column *pCol = &pIdx->pTable->aCol[iCol];
** deferred constraint counter by nIncr for each row selected. */
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0);
if( nIncr==0 ){
- /* A RESTRICT Action. */
+ /* Special case: A RESTRICT Action. Throw an error immediately if one
+ ** of these is encountered. */
sqlite3HaltConstraint(
pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
);
# Use a collation sequence on the parent key.
drop_all_tables
-do_test fkey2-1.5.1 {
+do_test fkey2-1.6.1 {
execsql {
CREATE TABLE i(i TEXT COLLATE nocase PRIMARY KEY);
CREATE TABLE j(j TEXT COLLATE binary REFERENCES i(i));
catchsql { DELETE FROM i }
} {1 {foreign key constraint failed}}
+# Use the parent key collation even if it is default and the child key
+# has an explicit value.
+drop_all_tables
+do_test fkey2-1.6.2 {
+ execsql {
+ CREATE TABLE i(i TEXT PRIMARY KEY); -- Colseq is "BINARY"
+ CREATE TABLE j(j TEXT COLLATE nocase REFERENCES i(i));
+ INSERT INTO i VALUES('SQLite');
+ }
+ catchsql { INSERT INTO j VALUES('sqlite') }
+} {1 {foreign key constraint failed}}
+do_test fkey2-1.6.3 {
+ execsql {
+ INSERT INTO i VALUES('sqlite');
+ INSERT INTO j VALUES('sqlite');
+ DELETE FROM i WHERE i = 'SQLite';
+ }
+ catchsql { DELETE FROM i WHERE i = 'sqlite' }
+} {1 {foreign key constraint failed}}
+
#-------------------------------------------------------------------------
# This section (test cases fkey2-2.*) contains tests to check that the
# deferred foreign key constraint logic works.