From: drh Date: Sun, 11 Nov 2007 18:36:34 +0000 (+0000) Subject: Fix the code generation for UPDATE and DELETE so that X-Git-Tag: version-3.6.10~1642 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=95c07754849bf9ad32c08bb762eecb104e0c0abc;p=thirdparty%2Fsqlite.git Fix the code generation for UPDATE and DELETE so that BEFORE triggers that use RAISE(IGNORE) do not leave extra values on the stack. Ticket #2767 (CVS 4535) FossilOrigin-Name: 3391f4139ccfe62cc27739a06567c422ddae9c69 --- diff --git a/manifest b/manifest index 3ea526d264..e0e78b4723 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sasserts\son\ssqlite3_mutex_held()\sto\sthe\szero-malloc\smemory\sallocator,\nin\sorder\sto\sprove\sthat\sthe\smutex\sis\sheld\swhen\sit\sis\sneeded.\s(CVS\s4534) -D 2007-11-07T15:13:25 +C Fix\sthe\scode\sgeneration\sfor\sUPDATE\sand\sDELETE\sso\sthat\nBEFORE\striggers\sthat\suse\sRAISE(IGNORE)\sdo\snot\sleave\sextra\nvalues\son\sthe\sstack.\s\sTicket\s#2767\s(CVS\s4535) +D 2007-11-11T18:36:34 F Makefile.in 30c7e3ba426ddb253b8ef037d1873425da6009a8 F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -88,7 +88,7 @@ F src/build.c d4ace66c2612d8973a17afdfe34b2a62f1a80178 F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0 F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6 -F src/delete.c 849846d06d29851dde0d9f424a5de5817eb140d1 +F src/delete.c 034b87768c4135a22038a86a205f9d2d5f68a143 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b F src/expr.c 23fac3749024deeaaa6c25b6b5c521e8d140a2c5 F src/func.c 73b4974e5ff03cc71345cc3a33b0022f7b99974a @@ -161,7 +161,7 @@ F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59 F src/test_thread.c a98d69cae883e53d3686fc25889a5fa5f51439f8 F src/tokenize.c 67e42600ab34f976f2b1288c499ad6c98d652f0e F src/trigger.c 724a77d54609a33bde90618934fbeddfcc729a10 -F src/update.c e89b980b443d44b68bfc0b1746cdb6308e049ac9 +F src/update.c 2add92a6159fa73128653706574afbcd8fd1dd80 F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624 F src/vacuum.c a5e51c77370c1a6445e86d42abfc43867cdd482d @@ -465,6 +465,7 @@ F test/tkt2450.test 77ed94863f2049c1420288ddfea2d41e5e0971d6 F test/tkt2640.test c513e7992a602a87ef3a2cc9ca1cba4146924e9b F test/tkt2643.test 3f3ebb743da00d4fed4fcf6daed92a0e18e57813 F test/tkt2686.test 8815c3eeae7c8363bd7c2889349ec39e8bc8000d +F test/tkt2767.test 6b02308d553d194f329a469bf5c157fe724738d4 F test/trace.test 75ffc1b992c780d054748a656e3e7fd674f18567 F test/trans.test b73289992b46d38d9479ecc4fdc03d8edb2413dc F test/trigger1.test 7c13f39ca36f529bf856e05c7d004fc0531d48b4 @@ -584,7 +585,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P c1fe27de7b6f0080466cc3f827979db9997e22a4 -R 4d22767fe7548ed57a40b50ba1b3d0b1 +P 31eb4abc89e9c0fd90fde5486d4008f9d09fdf4e +R a1f586a7644a244540f38fb9992343e8 U drh -Z 591ee87bae6e45cc97f6c36812f304cb +Z 9a344de272865e137595258a6a6021fd diff --git a/manifest.uuid b/manifest.uuid index 03ac0b94c0..2fb785dfd5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -31eb4abc89e9c0fd90fde5486d4008f9d09fdf4e \ No newline at end of file +3391f4139ccfe62cc27739a06567c422ddae9c69 \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index 12e61cd96c..187d1efc65 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.130 2007/08/16 04:30:40 drh Exp $ +** $Id: delete.c,v 1.131 2007/11/11 18:36:34 drh Exp $ */ #include "sqliteInt.h" @@ -277,9 +277,10 @@ void sqlite3DeleteFrom( ** row triggers. */ if( triggers_exist ){ + int mem1 = pParse->nMem++; addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end); + sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0); if( !isView ){ - sqlite3VdbeAddOp(v, OP_Dup, 0, 0); sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); } sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); @@ -293,6 +294,9 @@ void sqlite3DeleteFrom( (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab, -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, addr); + if( !isView ){ + sqlite3VdbeAddOp(v, OP_MemLoad, mem1, 0); + } } if( !isView ){ diff --git a/src/update.c b/src/update.c index 6cf7f73635..319aa4f186 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.140 2007/08/16 10:09:03 danielk1977 Exp $ +** $Id: update.c,v 1.141 2007/11/11 18:36:34 drh Exp $ */ #include "sqliteInt.h" @@ -318,6 +318,8 @@ void sqlite3Update( } if( triggers_exist ){ + int mem1; /* Memory address storing the rowid for next row to update */ + /* Create pseudo-tables for NEW and OLD */ sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); @@ -328,10 +330,10 @@ void sqlite3Update( /* The top of the update loop for when there are triggers. */ addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0); - + mem1 = pParse->nMem++; + sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0); + if( !isView ){ - sqlite3VdbeAddOp(v, OP_Dup, 0, 0); - sqlite3VdbeAddOp(v, OP_Dup, 0, 0); /* Open a cursor and make it point to the record that is ** being updated. */ @@ -381,6 +383,11 @@ void sqlite3Update( newIdx, oldIdx, onError, addr) ){ goto update_cleanup; } + + if( !isView ){ + sqlite3VdbeAddOp(v, OP_MemLoad, mem1, 0); + sqlite3VdbeAddOp(v, OP_Dup, 0, 0); + } } if( !isView && !IsVirtual(pTab) ){ diff --git a/test/tkt2767.test b/test/tkt2767.test new file mode 100644 index 0000000000..18714b8c9d --- /dev/null +++ b/test/tkt2767.test @@ -0,0 +1,88 @@ +# 2007 Oct 3 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file is to test that ticket #2767 has been fixed. +# Ticket #2767 is for a VDBE stack overflow on BEFORE +# triggers that run RAISE(IGNORE). +# +# $Id: tkt2767.test,v 1.1 2007/11/11 18:36:35 drh Exp $ +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_test tkt2767-1.1 { + execsql { + -- Construct a table with many rows of data + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1); + INSERT INTO t1 VALUES(2); + INSERT INTO t1 SELECT x+2 FROM t1; + INSERT INTO t1 SELECT x+4 FROM t1; + INSERT INTO t1 SELECT x+8 FROM t1; + INSERT INTO t1 SELECT x+16 FROM t1; + + -- BEFORE triggers that invoke raise(ignore). The effect of + -- these triggers should be to make INSERTs, UPDATEs, and DELETEs + -- into no-ops. + CREATE TRIGGER r1 BEFORE UPDATE ON t1 BEGIN + SELECT raise(ignore); + END; + CREATE TRIGGER r2 BEFORE DELETE ON t1 BEGIN + SELECT raise(ignore); + END; + CREATE TRIGGER r3 BEFORE INSERT ON t1 BEGIN + SELECT raise(ignore); + END; + + -- Verify the table content + SELECT count(*), sum(x) FROM t1; + } +} {32 528} + +# Try to delete all elements of the table. This will invoke the +# DELETE trigger 32 times, which should overflow the VDBE stack if +# the problem of #2767 is not fixed. If the problem is fixed, all +# the deletes should be no-ops so the table should remain unchanged. +# +do_test tkt2767-1.2 { + execsql { + DELETE FROM t1 WHERE x>0; + SELECT count(*), sum(x) FROM t1; + } +} {32 528} + +# Try to update all elements of the table. This will invoke the +# UPDATE trigger 32 times, which should overflow the VDBE stack if +# the problem of #2767 is not fixed. If the problem is fixed, all +# the updates should be no-ops so the table should remain unchanged. +# +do_test tkt2767-1.3 { + execsql { + UPDATE t1 SET x=x+1; + SELECT count(*), sum(x) FROM t1; + } +} {32 528} + +# Invoke the insert trigger. The insert trigger was working +# even prior to the fix of #2767. But it seems good to go ahead +# and verify that it works. +# +do_test tkt2767-1.4 { + execsql { + INSERT INTO t1 SELECT x+32 FROM t1; + SELECT count(*), sum(x) FROM t1; + } +} {32 528} + + + +finish_test \ No newline at end of file