From: dan Date: Fri, 10 Jun 2011 16:33:25 +0000 (+0000) Subject: Fix minor problems with foreign key constraints where the parent table is the same... X-Git-Tag: version-3.7.7~65 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b328debc6a035a9c91306b5a3bf95aea2fc564be;p=thirdparty%2Fsqlite.git Fix minor problems with foreign key constraints where the parent table is the same as the child table. FossilOrigin-Name: 442d8d8bfe443797482354ba8766d97d3d6acaae --- diff --git a/manifest b/manifest index ded9d9cb63..79636217b0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sline\sin\spcache1.c\swhere\sa\sglobal\sdata\sstructure\sis\saccessed\swithout\susing\sthe\sGLOBAL()\smacro.\sThis\scauses\sa\ssubtle\smalfunction\son\stest\ssystems\sthat\suse\sSQLITE_OMIT_WSD. -D 2011-06-09T17:53:43.990 +C Fix\sminor\sproblems\swith\sforeign\skey\sconstraints\swhere\sthe\sparent\stable\sis\sthe\ssame\sas\sthe\schild\stable. +D 2011-06-10T16:33:25.121 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 11dcc00a8d0e5202def00e81732784fb0cc4fe1d F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -133,7 +133,7 @@ F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b F src/delete.c cecc926c70783452f3e8eb452c728291ce1a0b21 F src/expr.c ab46ab0f0c44979a8164ca31728d7d10ae5e8106 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c a43ba8a005fb5efd1deeee06853e3a6120d46a91 +F src/fkey.c 9fabba17a4d4778dc660f0cb9d781fc86d7b9d41 F src/func.c b9117e40975245b8504cf3625d7e321d8d4b63dc F src/global.c 29bfb85611dd816b04f10fba0ca910366e128d38 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af @@ -398,7 +398,7 @@ F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e F test/filefmt.test f178cfc29501a14565954c961b226e61877dd32c F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da F test/fkey2.test 080969fe219b3b082b0e097ac18c6af2e5b0631f -F test/fkey3.test 42f88d6048d8dc079e2a8cf7baad1cc1483a7620 +F test/fkey3.test 0c4d36b6d5b88f2c233cf8a512d3e2eaedc06fd6 F test/fkey4.test c6c8f9f9be885f95c85c7bceb26f243ad906fd49 F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8 F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb @@ -942,7 +942,7 @@ F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/symbols.sh bc2a3709940d47c8ac8e0a1fdf17ec801f015a00 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings.sh 347d974d143cf132f953b565fbc03026f19fcb4d -P 095cd9a6ec175b703ff3fcafeffb3349f21bd831 -R 7c10b21d6dc959e0ea4f54033f3d408b +P b11b2e1f8ccadf78bebe2278f05a8e3d3e543328 +R 82679520a5c6b1fbd50bacf672964c79 U dan -Z e98f319e77bc2f43df3a70aff2c9cf53 +Z 3e44af2707cf5eb06c1e283bd2e9d2ca diff --git a/manifest.uuid b/manifest.uuid index 4449540538..3b5ddc572a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b11b2e1f8ccadf78bebe2278f05a8e3d3e543328 \ No newline at end of file +442d8d8bfe443797482354ba8766d97d3d6acaae \ No newline at end of file diff --git a/src/fkey.c b/src/fkey.c index 34fdfda5d9..dda8a50d44 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -386,13 +386,25 @@ static void fkLookupParent( /* If the parent table is the same as the child table, and we are about ** to increment the constraint-counter (i.e. this is an INSERT operation), ** then check if the row being inserted matches itself. If so, do not - ** increment the constraint-counter. */ + ** increment the constraint-counter. + ** + ** If any of the parent-key values are NULL, then the row cannot match + ** itself. So set JUMPIFNULL to make sure we do the OP_Found if any + ** of the parent-key values are NULL (at this point it is known that + ** none of the child key values are). + */ if( pTab==pFKey->pFrom && nIncr==1 ){ int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1; for(i=0; iaiColumn[i]+1+regData; + assert( aiCol[i]!=pTab->iPKey ); + if( pIdx->aiColumn[i]==pTab->iPKey ){ + /* The parent key is a composite key that includes the IPK column */ + iParent = regData; + } sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); + sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); } sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk); } diff --git a/test/fkey3.test b/test/fkey3.test index 88b5aad370..2df3be530e 100644 --- a/test/fkey3.test +++ b/test/fkey3.test @@ -21,6 +21,8 @@ ifcapable {!foreignkey||!trigger} { return } +set testprefix fkey3 + # Create a table and some data to work with. # do_test fkey3-1.1 { @@ -77,4 +79,79 @@ do_test fkey3-2.1 { } } {1 100 1 101 2 100 2 101} + +#------------------------------------------------------------------------- +# The following tests - fkey-3.* - test some edge cases to do with +# inserting rows into tables that have foreign keys where the parent +# table is the same as the child table. Especially cases where the +# new row being inserted matches itself. +# +do_execsql_test 3.1.1 { + CREATE TABLE t3(a, b, c, d, + UNIQUE(a, b), + FOREIGN KEY(c, d) REFERENCES t3(a, b) + ); + INSERT INTO t3 VALUES(1, 2, 1, 2); +} {} +do_catchsql_test 3.1.2 { + INSERT INTO t3 VALUES(NULL, 2, 5, 2); +} {1 {foreign key constraint failed}} +do_catchsql_test 3.1.3 { + INSERT INTO t3 VALUES(NULL, 3, 5, 2); +} {1 {foreign key constraint failed}} + +do_execsql_test 3.2.1 { + CREATE TABLE t4(a UNIQUE, b REFERENCES t4(a)); +} +do_catchsql_test 3.2.2 { + INSERT INTO t4 VALUES(NULL, 1); +} {1 {foreign key constraint failed}} + +do_execsql_test 3.3.1 { + CREATE TABLE t5(a INTEGER PRIMARY KEY, b REFERENCES t5(a)); + INSERT INTO t5 VALUES(NULL, 1); +} {} +do_catchsql_test 3.3.2 { + INSERT INTO t5 VALUES(NULL, 3); +} {1 {foreign key constraint failed}} + +do_execsql_test 3.4.1 { + CREATE TABLE t6(a INTEGER PRIMARY KEY, b, c, d, + FOREIGN KEY(c, d) REFERENCES t6(a, b) + ); + CREATE UNIQUE INDEX t6i ON t6(b, a); +} +do_execsql_test 3.4.2 { INSERT INTO t6 VALUES(NULL, 'a', 1, 'a'); } {} +do_execsql_test 3.4.3 { INSERT INTO t6 VALUES(2, 'a', 2, 'a'); } {} +do_execsql_test 3.4.4 { INSERT INTO t6 VALUES(NULL, 'a', 1, 'a'); } {} +do_execsql_test 3.4.5 { INSERT INTO t6 VALUES(5, 'a', 2, 'a'); } {} +do_catchsql_test 3.4.6 { + INSERT INTO t6 VALUES(NULL, 'a', 65, 'a'); +} {1 {foreign key constraint failed}} + +do_execsql_test 3.4.7 { + INSERT INTO t6 VALUES(100, 'one', 100, 'one'); + DELETE FROM t6 WHERE a = 100; +} +do_execsql_test 3.4.8 { + INSERT INTO t6 VALUES(100, 'one', 100, 'one'); + UPDATE t6 SET c = 1, d = 'a' WHERE a = 100; + DELETE FROM t6 WHERE a = 100; +} + +do_execsql_test 3.5.1 { + CREATE TABLE t7(a, b, c, d INTEGER PRIMARY KEY, + FOREIGN KEY(c, d) REFERENCES t7(a, b) + ); + CREATE UNIQUE INDEX t7i ON t7(a, b); +} +do_execsql_test 3.5.2 { INSERT INTO t7 VALUES('x', 1, 'x', NULL) } {} +do_execsql_test 3.5.3 { INSERT INTO t7 VALUES('x', 2, 'x', 2) } {} +do_catchsql_test 3.5.4 { + INSERT INTO t7 VALUES('x', 450, 'x', NULL); +} {1 {foreign key constraint failed}} +do_catchsql_test 3.5.5 { + INSERT INTO t7 VALUES('x', 450, 'x', 451); +} {1 {foreign key constraint failed}} + finish_test