diff --git a/manifest b/manifest index 8bac991d11..e48c40d930 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\scompilation\swith\sboth\sOMIT_UTF16\sand\sENABLE_STAT2\sdefined.\sTicket\s[56928bd084ea530eb8a0b3ebe5d2d9033fb1de7f|56928bd084]. -D 2009-09-21T16:34:24 +C Fix\sa\sproblem\swith\sforeign\skey\sconstraints\sthat\smap\sfrom\sand\sIPK\scolumn. +D 2009-09-21T18:56:24 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 4ca3f1dd6efa2075bcb27f4dc43eef749877740d F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -116,7 +116,7 @@ F src/date.c 6d936393716d21e6dc0d4222b3443137a60ebe93 F src/delete.c 15499f5d10047d38e68ce991b3f88cbddb6e0931 F src/expr.c 638b599adad562d41c3bf90f542f9419664aa7b8 F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff -F src/fkey.c 0f06ecda52a75a1624e01b7f861a235d97544b98 +F src/fkey.c 6aad270ae5ed7b0496e25020bce89097c2cf9c79 F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606 F src/global.c 271952d199a8cc59d4ce840b3bbbfd2f30c8ba32 F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7 @@ -330,7 +330,7 @@ F test/expr.test 80f3cf99f786ffbac19d2b0083673e7fc797030f F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8 F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43 F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da -F test/fkey2.test 62d02fb2c0d115715e990691961a7b679c902204 +F test/fkey2.test a8055d90eec17db00847cbcd527bc870d9218551 F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7 F test/fts1b.test 5d8a01aefbecc8b7442b36c94c05eb7a845462d5 @@ -752,7 +752,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P fb6ceed388f6d75bdc2ac2f43e5c98da74e2a448 -R 899a06e4349a5ceabc5fe389e0c0c2ac +P cd850d49a12a2852258cbd7d5db56715132dff17 +R d5353831002e80af9b93981303b50742 U dan -Z 4dbd21536703b59a6c4c05ce1d53ee70 +Z deb48eae30b76f10abf4df096870a1c2 diff --git a/manifest.uuid b/manifest.uuid index db528ce92f..63650843e9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cd850d49a12a2852258cbd7d5db56715132dff17 \ No newline at end of file +84129052623dc6a175c76db602ab07fa3e57f1eb \ No newline at end of file diff --git a/src/fkey.c b/src/fkey.c index 8e5a6a96fe..072a90aeed 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -258,7 +258,7 @@ static void fkCheckReference( ** NULL. If any are, then the constraint is satisfied. No need ** to search for a matching row in the referenced table. */ for(i=0; i<pFKey->nCol; i++){ - int iReg = pFKey->aCol[i].iFrom + regData + 1; + int iReg = aiCol[i] + regData + 1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); } @@ -277,7 +277,7 @@ static void fkCheckReference( sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF); - if( aiCol ){ + if( pFKey->nCol>1 ){ int nCol = pFKey->nCol; int regTemp = sqlite3GetTempRange(pParse, nCol); for(i=0; i<nCol; i++){ @@ -286,7 +286,7 @@ static void fkCheckReference( sqlite3VdbeAddOp3(v, OP_MakeRecord, regTemp, nCol, regRec); sqlite3ReleaseTempRange(pParse, regTemp, nCol); }else{ - int iReg = pFKey->aCol[0].iFrom + regData + 1; + int iReg = aiCol[0] + regData + 1; sqlite3VdbeAddOp3(v, OP_MakeRecord, iReg, 1, regRec); sqlite3IndexAffinityStr(v, pIdx); } @@ -426,7 +426,10 @@ void sqlite3FkCheck( for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ Table *pTo; /* Table referenced by this FK */ Index *pIdx = 0; /* Index on key columns in pTo */ - int *aiCol = 0; + int *aiFree = 0; + int *aiCol; + int iCol; + int i; if( pFKey->isDeferred==0 && regNew==0 ) continue; @@ -435,14 +438,26 @@ void sqlite3FkCheck( ** If either of these things cannot be located, set an error in pParse ** and return early. */ pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb); - if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiCol) ) return; - assert( pFKey->nCol==1 || (aiCol && pIdx) ); + if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ) return; + assert( pFKey->nCol==1 || (aiFree && pIdx) ); /* If the key does not overlap with the pChanges list, skip this FK. */ if( pChanges ){ /* TODO */ } + if( aiFree ){ + aiCol = aiFree; + }else{ + iCol = pFKey->aCol[0].iFrom; + aiCol = &iCol; + } + for(i=0; i<pFKey->nCol; i++){ + if( aiCol[i]==pTab->iPKey ){ + aiCol[i] = -1; + } + } + /* Take a shared-cache advisory read-lock on the referenced table. ** Allocate a cursor to use to search the unique index on the FK ** columns in the referenced table. */ @@ -456,7 +471,7 @@ void sqlite3FkCheck( fkCheckReference(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1); } - sqlite3DbFree(db, aiCol); + sqlite3DbFree(db, aiFree); } /* Loop through all the foreign key constraints that refer to this table */ diff --git a/test/fkey2.test b/test/fkey2.test index 80f7470a3b..a2793c788c 100644 --- a/test/fkey2.test +++ b/test/fkey2.test @@ -42,6 +42,8 @@ ifcapable {!foreignkey||!trigger} { # fkey2-6.*: Test that FK processing is automatically disabled when # running VACUUM. # +# fkey2-7.*: Test using an IPK as the key in the child (referencing) table. +# # fkey2-genfkey.*: Tests that were used with the shell tool .genfkey # command. Recycled to test the built-in implementation. # @@ -409,6 +411,42 @@ ifcapable vacuum { } {} } +#------------------------------------------------------------------------- +# Test that it is possible to use an INTEGER PRIMARY KEY as the child key +# of a foreign constraint. +drop_all_tables +do_test fkey2-7.1 { + execsql { + CREATE TABLE t1(a PRIMARY KEY, b); + CREATE TABLE t2(c INTEGER PRIMARY KEY REFERENCES t1, b); + } +} {} +do_test fkey2-7.2 { + catchsql { INSERT INTO t2 VALUES(1, 'A'); } +} {1 {foreign key constraint failed}} +do_test fkey2-7.3 { + execsql { + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(2, 3); + INSERT INTO t2 VALUES(1, 'A'); + } +} {} +do_test fkey2-7.4 { + execsql { UPDATE t2 SET c = 2 } +} {} +do_test fkey2-7.5 { + catchsql { UPDATE t2 SET c = 3 } +} {1 {foreign key constraint failed}} +do_test fkey2-7.6 { + catchsql { DELETE FROM t1 WHERE a = 2 } +} {1 {foreign key constraint failed}} +do_test fkey2-7.7 { + execsql { DELETE FROM t1 WHERE a = 1 } +} {} +do_test fkey2-7.8 { + catchsql { UPDATE t1 SET a = 3 } +} {1 {foreign key constraint failed}} + #------------------------------------------------------------------------- # The following block of tests, those prefixed with "fkey2-genfkey.", are # the same tests that were used to test the ".genfkey" command provided