From 788536b16580154cb4f021275a3d8e8376dbd2b2 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 23 Sep 2009 03:01:58 +0000 Subject: [PATCH] Do not run ON UPDATE actions of a foreign key constraint unless at least one column value really does change. FossilOrigin-Name: 71ac8e28e55ff0250ebe2fe239159ce2458d9165 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/fkey.c | 30 ++++++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 212cfdf42e..6d7e25235b 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 -C Generalize\sthe\sIS\sand\sIS\sNOT\soperators\sso\sthat\stheir\sright-hand\sside\scan\sbe\nan\sarbitrary\sexpression\sand\snot\ssimple\sthe\sconstant\sNULL.\s\sThey\swork\slike\n=\sand\s<>\sexcept\sthat\sNULL\svalues\scompare\sequal\sto\sone\sanother\san\sunequal\sto\neverything\selse. -D 2009-09-23T02:29:37 +C Do\snot\srun\sON\sUPDATE\sactions\sof\sa\sforeign\skey\sconstraint\sunless\sat\sleast\sone\ncolumn\svalue\sreally\sdoes\schange. +D 2009-09-23T03:01:59 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 4ca3f1dd6efa2075bcb27f4dc43eef749877740d F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -119,7 +119,7 @@ F src/date.c 657ff12ca0f1195b531561afacbb38b772d16638 F src/delete.c 15499f5d10047d38e68ce991b3f88cbddb6e0931 F src/expr.c 8a663240f374a5326ee157df3d27751f58b7676a F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff -F src/fkey.c fa1ad144926a8536e23cbbf64c0e51b8f2fdd4bf +F src/fkey.c de296942345984960792f12ea4236a6bef2f800b F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606 F src/global.c 271952d199a8cc59d4ce840b3bbbfd2f30c8ba32 F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7 @@ -756,14 +756,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 3fc938c961fd7810594224b91a2d6e1ac9e48084 -R d99ab25244fa05bd56d10d71bb3bee44 +P 98853f6104076c50ea92175e17a3254bfbbd4619 +R 827ec94cc2eb4c57959ec45f4b3d8098 U drh -Z 4608482892179163853473e1fbf42a31 +Z ec752338f3000365feb24aa823e5d734 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) -iD8DBQFKuYgUoxKgR168RlERApeHAJ48L4oeCXw8ZV6ov3G5+bjNMfQIewCfX/Rc -qXj8iamFDJ6JXwF0VP/iAOI= -=lSDQ +iD8DBQFKuY+roxKgR168RlERAq1TAKCDsc87lQ7RxW/6hlefk/rm32wxUACdGuQz +1VFw5lE97EA4c5Tiy8ftXks= +=0G/k -----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index 82c45ac0f3..3c61b0a6f3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -98853f6104076c50ea92175e17a3254bfbbd4619 \ No newline at end of file +71ac8e28e55ff0250ebe2fe239159ce2458d9165 \ No newline at end of file diff --git a/src/fkey.c b/src/fkey.c index 32aef9bbe0..1e64310ead 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -395,6 +395,7 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ TriggerStep *pStep = p->step_list; sqlite3ExprDelete(dbMem, pStep->pWhere); sqlite3ExprListDelete(dbMem, pStep->pExprList); + sqlite3ExprDelete(dbMem, p->pWhen); sqlite3DbFree(dbMem, p); } } @@ -649,6 +650,7 @@ static Trigger *fkActionTrigger( Expr *pWhere = 0; /* WHERE clause of trigger step */ ExprList *pList = 0; /* Changes list if ON UPDATE CASCADE */ int i; /* Iterator variable */ + Expr *pWhen = 0; /* WHEN clause for the trigger */ if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0; assert( aiCol || pFKey->nCol==1 ); @@ -678,6 +680,25 @@ static Trigger *fkActionTrigger( , 0); pWhere = sqlite3ExprAnd(db, pWhere, pEq); + /* For ON UPDATE, construct the next term of the WHEN clause. + ** The final WHEN clause will be like this: + ** + ** WHEN NOT(old.col1 IS new.col1 AND ... AND old.colN IS new.colN) + */ + if( pChanges ){ + pEq = sqlite3PExpr(pParse, TK_IS, + sqlite3PExpr(pParse, TK_DOT, + sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld), + sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol), + 0), + sqlite3PExpr(pParse, TK_DOT, + sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew), + sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol), + 0), + 0); + pWhen = sqlite3ExprAnd(db, pWhen, pEq); + } + if( action!=OE_Cascade || pChanges ){ Expr *pNew; if( action==OE_Cascade ){ @@ -724,13 +745,18 @@ static Trigger *fkActionTrigger( pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE); + if( pWhen ){ + pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0, 0); + pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); + } } /* Re-enable the lookaside buffer, if it was disabled earlier. */ db->lookaside.bEnabled = enableLookaside; - sqlite3ExprDelete(pParse->db, pWhere); - sqlite3ExprListDelete(pParse->db, pList); + sqlite3ExprDelete(db, pWhere); + sqlite3ExprDelete(db, pWhen); + sqlite3ExprListDelete(db, pList); if( db->mallocFailed==1 ){ fkTriggerDelete(db, pTrigger); return 0;