-C Fix\sa\sbug\sin\sthe\scode\sfor\sREPLACE\sconflict\shandling\son\sIPK\scolumns\swhen\sthere\sare\sno\sindexes\son\sthe\stable.\sTriggers\sand\sforeign\skey\sprocessing\swere\sbeing\sbypassed.
-D 2009-09-24T16:52:28
+C Fixes\sand\stest\scases\sto\smake\ssure\sthe\saffinity\sand\scollation\ssequence\sassociated\swith\sthe\sparent\skey\sis\sused\swhen\scomparing\sit\swith\sa\schild\skey\svalue.
+D 2009-09-24T18:19:42
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 d5610f840b76e7b478d9700df9f3be0ab96ba1b8
+F src/fkey.c 5ec139b6d22a981a777fb195d9311068f5a8c75b
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 30dedac189b10da51c0cbdee84e334ed3119b8f0
+F test/fkey2.test c81035086cec3014838c0af60b3fc228c3875214
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 8a000a8aae4d356e68acf2bc1788d2c40279522c
-R 1cd4e9cb0400f55e65581cc0c3e21846
+P beb2094f94849c66d98bab5999ff474cd91eea11
+R b4aeb3f8101f131cf6580b25c102b171
U dan
-Z 294416087638c741514386eadd008bb9
+Z be9e9a4e87b8676ab6aa8bb0309f6406
if( pIdx==0 ){
/* If pIdx is NULL, then the parent key is the INTEGER PRIMARY KEY
** column of the parent table (table pTab). */
- int iReg = aiCol[0] + regData + 1;
+ int regTemp = sqlite3GetTempReg(pParse);
+
+ /* Invoke MustBeInt to coerce the child key value to an integer (i.e.
+ ** apply the affinity of the parent key). If this fails, then there
+ ** is no matching parent key. Before using MustBeInt, make a copy of
+ ** the value. Otherwise, the value inserted into the child key column
+ ** will have INTEGER affinity applied to it, which may not be correct. */
+ sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[0]+1+regData, regTemp);
+ sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0);
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
- sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iReg);
+ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp);
sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk);
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
+ sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-4);
+ sqlite3ReleaseTempReg(pParse, regTemp);
+ assert(
+ sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v)-4)->opcode==OP_MustBeInt
+ );
}else{
+ int nCol = pFKey->nCol;
+ int regTemp = sqlite3GetTempRange(pParse, nCol);
int regRec = sqlite3GetTempReg(pParse);
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF);
-
- if( pFKey->nCol>1 ){
- int nCol = pFKey->nCol;
- int regTemp = sqlite3GetTempRange(pParse, nCol);
- for(i=0; i<nCol; i++){
- sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[i]+1+regData, regTemp+i);
- }
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regTemp, nCol, regRec);
- sqlite3ReleaseTempRange(pParse, regTemp, nCol);
- }else{
- int iReg = aiCol[0] + regData + 1;
- sqlite3VdbeAddOp3(v, OP_MakeRecord, iReg, 1, regRec);
- sqlite3IndexAffinityStr(v, pIdx);
+ for(i=0; i<nCol; i++){
+ sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[i]+1+regData, regTemp+i);
}
-
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regTemp, nCol, regRec);
+ sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0);
sqlite3VdbeAddOp3(v, OP_Found, iCur, iOk, regRec);
sqlite3ReleaseTempReg(pParse, regRec);
+ sqlite3ReleaseTempRange(pParse, regTemp, nCol);
}
if( !pFKey->isDeferred && !pParse->pToplevel && !pParse->isMultiWrite ){
pLeft = sqlite3Expr(db, TK_REGISTER, 0);
if( pLeft ){
- pLeft->iTable = (pIdx ? (regData+pIdx->aiColumn[i]+1) : regData);
+ if( pIdx ){
+ int iCol = pIdx->aiColumn[i];
+ Column *pCol = &pIdx->pTable->aCol[iCol];
+ pLeft->iTable = regData+iCol+1;
+ pLeft->affinity = pCol->affinity;
+ pLeft->pColl = sqlite3LocateCollSeq(pParse, pCol->zColl);
+ }else{
+ pLeft->iTable = regData;
+ pLeft->affinity = SQLITE_AFF_INTEGER;
+ }
}
iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
assert( iCol>=0 );
4.11 "DELETE FROM t7 WHERE b=1" {1 {foreign key constraint failed}}
4.12 "UPDATE t7 SET b = 2" {1 {foreign key constraint failed}}
4.13 "UPDATE t7 SET b = 1" {0 {}}
+ 4.14 "INSERT INTO t8 VALUES('a', 'b')" {1 {foreign key constraint failed}}
5.1 "INSERT INTO t9 VALUES(1, 3)" {1 {no such table: main.nosuchtable}}
5.2 "INSERT INTO t10 VALUES(1, 3)" {1 {foreign key mismatch}}
execsql { PRAGMA count_changes = 0 }
drop_all_tables
+# Special test: When the parent key is an IPK, make sure the affinity of
+# the IPK is not applied to the child key value before it is inserted
+# into the child table.
+do_test fkey2-1.4.1 {
+ execsql {
+ CREATE TABLE i(i INTEGER PRIMARY KEY);
+ CREATE TABLE j(j REFERENCES i);
+ INSERT INTO i VALUES(35);
+ INSERT INTO j VALUES('35.0');
+ SELECT j, typeof(j) FROM j;
+ }
+} {35.0 text}
+do_test fkey2-1.4.2 {
+ catchsql { DELETE FROM i }
+} {1 {foreign key constraint failed}}
+
+# Same test using a regular primary key with integer affinity.
+drop_all_tables
+do_test fkey2-1.5.1 {
+ execsql {
+ CREATE TABLE i(i INT UNIQUE);
+ CREATE TABLE j(j REFERENCES i(i));
+ INSERT INTO i VALUES('35.0');
+ INSERT INTO j VALUES('35.0');
+ SELECT j, typeof(j) FROM j;
+ SELECT i, typeof(i) FROM i;
+ }
+} {35.0 text 35 integer}
+do_test fkey2-1.5.2 {
+ catchsql { DELETE FROM i }
+} {1 {foreign key constraint failed}}
+
+# Use a collation sequence on the parent key.
+drop_all_tables
+do_test fkey2-1.5.1 {
+ execsql {
+ CREATE TABLE i(i TEXT COLLATE nocase PRIMARY KEY);
+ CREATE TABLE j(j TEXT COLLATE binary REFERENCES i(i));
+ INSERT INTO i VALUES('SQLite');
+ INSERT INTO j VALUES('sqlite');
+ }
+ catchsql { DELETE FROM i }
+} {1 {foreign key constraint failed}}
+
#-------------------------------------------------------------------------
# This section (test cases fkey2-2.*) contains tests to check that the
# deferred foreign key constraint logic works.