List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:March 12 2008 2:13pm
Subject:bk commit into 5.0 tree (anozdrin:1.2596) BUG#34643
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of anozdrin.  When anozdrin does a push these changes
will be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2008-03-12 16:13:33+03:00, anozdrin@quad. +3 -0
  A fix for Bug#34643: TRUNCATE crash if trigger and foreign key.
    
  In cases when TRUNCATE was executed by invoking mysql_delete() rather
  than by table recreation (for example, when TRUNCATE was issued on
  InnoDB table with is referenced by foreign key) triggers were invoked.
  In debug builds this also led to crash because of an assertion, which
  assumes that some preliminary actions take place before trigger 
  invocation, which doesn't happen in case of TRUNCATE.
  
  The fix is not to execute triggers in mysql_delete() when this
  function is used by TRUNCATE.

  mysql-test/r/trigger-trans.result@stripped, 2008-03-12 16:13:32+03:00, anozdrin@quad. +19 -0
    Update result file.

  mysql-test/t/trigger-trans.test@stripped, 2008-03-12 16:13:32+03:00, anozdrin@quad. +32 -0
    A test case for Bug#34643: TRUNCATE crash if trigger and foreign key.

  sql/sql_delete.cc@stripped, 2008-03-12 16:13:32+03:00, anozdrin@quad. +10 -5
    Do not process triggers in TRUNCATE.

diff -Nrup a/mysql-test/r/trigger-trans.result b/mysql-test/r/trigger-trans.result
--- a/mysql-test/r/trigger-trans.result	2007-07-12 22:26:38 +04:00
+++ b/mysql-test/r/trigger-trans.result	2008-03-12 16:13:32 +03:00
@@ -140,4 +140,23 @@ select * from t3;
 c
 1
 drop table t1, t2, t3;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=innodb;
+CREATE TABLE t2(b INT, FOREIGN KEY(b) REFERENCES t1(a)) ENGINE=innodb;
+INSERT INTO t1 VALUES (1);
+CREATE TRIGGER t1_bd BEFORE DELETE ON t1 FOR EACH ROW SET @a = 1;
+CREATE TRIGGER t1_ad AFTER DELETE ON t1 FOR EACH ROW SET @b = 1;
+SET @a = 0;
+SET @b = 0;
+TRUNCATE t1;
+SELECT @a, @b;
+@a	@b
+0	0
+INSERT INTO t1 VALUES (1);
+DELETE FROM t1;
+SELECT @a, @b;
+@a	@b
+1	1
+DROP TABLE t2, t1;
 End of 5.0 tests
diff -Nrup a/mysql-test/t/trigger-trans.test b/mysql-test/t/trigger-trans.test
--- a/mysql-test/t/trigger-trans.test	2007-07-12 22:26:38 +04:00
+++ b/mysql-test/t/trigger-trans.test	2008-03-12 16:13:32 +03:00
@@ -128,5 +128,37 @@ drop table t1, t2, t3;
 disconnect connection_update;
 disconnect connection_aux;
 
+#
+# Bug#34643: TRUNCATE crash if trigger and foreign key.
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+--enable_warnings
+
+CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=innodb;
+CREATE TABLE t2(b INT, FOREIGN KEY(b) REFERENCES t1(a)) ENGINE=innodb;
+
+INSERT INTO t1 VALUES (1);
+
+CREATE TRIGGER t1_bd BEFORE DELETE ON t1 FOR EACH ROW SET @a = 1;
+CREATE TRIGGER t1_ad AFTER DELETE ON t1 FOR EACH ROW SET @b = 1;
+
+SET @a = 0;
+SET @b = 0;
+
+TRUNCATE t1;
+
+SELECT @a, @b;
+
+INSERT INTO t1 VALUES (1);
+
+DELETE FROM t1;
+
+SELECT @a, @b;
+
+DROP TABLE t2, t1;
+
 
 --echo End of 5.0 tests
diff -Nrup a/sql/sql_delete.cc b/sql/sql_delete.cc
--- a/sql/sql_delete.cc	2007-10-29 16:20:54 +03:00
+++ b/sql/sql_delete.cc	2008-03-12 16:13:32 +03:00
@@ -35,6 +35,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
   READ_RECORD	info;
   bool          using_limit=limit != HA_POS_ERROR;
   bool		transactional_table, safe_update, const_cond;
+  bool          triggers_applicable;
   ha_rows	deleted;
   uint usable_index= MAX_KEY;
   SELECT_LEX   *select_lex= &thd->lex->select_lex;
@@ -93,6 +94,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *
 
   select_lex->no_error= thd->lex->ignore;
 
+  /* NOTE: TRUNCATE must not invoke triggers. */
+
+  triggers_applicable= table->triggers &&
+                       thd->lex->sql_command != SQLCOM_TRUNCATE;
+
   /*
     Test if the user wants to delete all rows and deletion doesn't have
     any side-effects (because of triggers), so we can use optimized
@@ -102,8 +108,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
   */
   if (!using_limit && const_cond && (!conds || conds->val_int())
&&
       !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
-      (thd->lex->sql_command == SQLCOM_TRUNCATE ||
-       !(table->triggers && table->triggers->has_delete_triggers()))
+      !(triggers_applicable && table->triggers->has_delete_triggers())
      )
   {
     deleted= table->file->records;
@@ -217,7 +222,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
   init_ftfuncs(thd, select_lex, 1);
   thd->proc_info="updating";
 
-  if (table->triggers)
+  if (triggers_applicable)
   {
     table->triggers->mark_fields_used(thd, TRG_EVENT_DELETE);
     if (table->triggers->has_triggers(TRG_EVENT_DELETE,
@@ -239,7 +244,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
     if (!(select && select->skip_record())&& !thd->net.report_error
)
     {
 
-      if (table->triggers &&
+      if (triggers_applicable &&
           table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                             TRG_ACTION_BEFORE, FALSE))
       {
@@ -250,7 +255,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
       if (!(error=table->file->delete_row(table->record[0])))
       {
 	deleted++;
-        if (table->triggers &&
+        if (triggers_applicable &&
             table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                               TRG_ACTION_AFTER, FALSE))
         {
Thread
bk commit into 5.0 tree (anozdrin:1.2596) BUG#34643Alexander Nozdrin12 Mar 2008