]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix the code generation for UPDATE and DELETE so that
authordrh <drh@noemail.net>
Sun, 11 Nov 2007 18:36:34 +0000 (18:36 +0000)
committerdrh <drh@noemail.net>
Sun, 11 Nov 2007 18:36:34 +0000 (18:36 +0000)
BEFORE triggers that use RAISE(IGNORE) do not leave extra
values on the stack.  Ticket #2767 (CVS 4535)

FossilOrigin-Name: 3391f4139ccfe62cc27739a06567c422ddae9c69

manifest
manifest.uuid
src/delete.c
src/update.c
test/tkt2767.test [new file with mode: 0644]

index 3ea526d264cdcc535c93f786f7578ec5a4556844..e0e78b472362bc053c0a90d00a6e1a95dc33fb2e 100644 (file)
--- 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
index 03ac0b94c02fcf42885206f72af401b3e937df9e..2fb785dfd529ac29502d58693dd2276eebdd359a 100644 (file)
@@ -1 +1 @@
-31eb4abc89e9c0fd90fde5486d4008f9d09fdf4e
\ No newline at end of file
+3391f4139ccfe62cc27739a06567c422ddae9c69
\ No newline at end of file
index 12e61cd96c1be366420fa50974931ac0f1d9db3a..187d1efc65d3d488b6ab4dc9f2cd7852cea7c15d 100644 (file)
@@ -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 ){
index 6cf7f736354a10630f165ce9e09aac7f15c9a9a3..319aa4f1861e42d6f79f7af98d6e123c652f57df 100644 (file)
@@ -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 (file)
index 0000000..18714b8
--- /dev/null
@@ -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