List:Commits« Previous MessageNext Message »
From:dlenev Date:January 13 2006 3:09pm
Subject:bk commit into 5.0 tree (dlenev:1.1999) BUG#13525
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of dlenev. When dlenev 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
  1.1999 06/01/13 18:08:53 dlenev@stripped +6 -0
  Fix for bug #13525 "Rename table does not keep info of triggers".
  
  Let us transfer triggers associated with table when we rename it (but only if
  we are not changing database to which table belongs, in the latter case we will
  emit error).
  
  OTOH may be it is sensible simply prohibit renaming of tables to which triggers
  bound like DB2 does?

  sql/sql_yacc.yy
    1.446 06/01/13 18:08:45 dlenev@stripped +7 -9
    trigger_tail:
      To be able properly update triggers' definitions with new table names
      when renaming tables we need to know where in CREATE TRIGGER statement
      "ON db_name.table_name" part resides.
      Small cleanup - let us emphasize that for CREATE TRIGGER statement 
      lock type which is specified in table list is unimportant since
      name-locking is used.

  sql/sql_trigger.h
    1.18 06/01/13 18:08:45 dlenev@stripped +18 -1
    Table_triggers_list:
      Added on_table_names_list member to store pointers and lenghts of
      "ON table_name" parts in triggers' definitions to be able easily
      change them during RENAME TABLE.
      Added change_table_name() method and change_table_name_in_trignames/triggers()
      helper methods responsible for updating .TRG and .TRN files.

  sql/sql_trigger.cc
    1.39 06/01/13 18:08:45 dlenev@stripped +278 -21
    Added Table_triggers_list::change_table_name() method and
    change_table_name_in_triggers()/trignames() methods responsible for updating
    .TRG and .TRN files for table during its renaming.
    
    Two small cleanups - removed versioning for .TRG files (since it was not working
    before anyway) and emphasized that type of lock specified in tables list is
    unimportant for DROP TABLE (since this statement uses name-locking). 

  sql/sql_rename.cc
    1.32 06/01/13 18:08:45 dlenev@stripped +21 -2
    rename_tables():
      Now after renaming table's .FRM file and updating handler data we call
      Table_triggers_list::change_table_name() which is reponsible for
      updating .TRG and .TRN files.

  mysql-test/t/trigger.test
    1.32 06/01/13 18:08:44 dlenev@stripped +59 -0
    Added test for bug #13525 "Rename table does not keep info of triggers".

  mysql-test/r/trigger.result
    1.26 06/01/13 18:08:44 dlenev@stripped +69 -0
    Added test for bug #13525 "Rename table does not keep info of triggers".

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	dlenev
# Host:	brandersnatch.site
# Root:	/home/dlenev/src/mysql-5.0-bg13525

--- 1.445/sql/sql_yacc.yy	2005-12-11 10:30:53 +03:00
+++ 1.446/sql/sql_yacc.yy	2006-01-13 18:08:45 +03:00
@@ -9070,8 +9070,8 @@
 **************************************************************************/
 
 trigger_tail:
-	TRIGGER_SYM remember_name sp_name trg_action_time trg_event 
-	ON table_ident FOR_SYM EACH_SYM ROW_SYM
+	TRIGGER_SYM remember_name sp_name trg_action_time trg_event
+	ON remember_name table_ident remember_end FOR_SYM EACH_SYM ROW_SYM
 	{
 	  LEX *lex= Lex;
 	  sp_head *sp;
@@ -9088,7 +9088,9 @@
 	  sp->init(lex);
 	
 	  lex->trigger_definition_begin= $2;
-	  
+          lex->ident.str= $7;
+          lex->ident.length= $9 - $7;
+
 	  sp->m_type= TYPE_ENUM_TRIGGER;
 	  lex->sphead= sp;
 	  lex->spname= $3;
@@ -9123,15 +9125,11 @@
 	    We have to do it after parsing trigger body, because some of
 	    sp_proc_stmt alternatives are not saving/restoring LEX, so
 	    lex->query_tables can be wiped out.
-	    
-	    QQ: What are other consequences of this?
-	    
-	    QQ: Could we loosen lock type in certain cases ?
 	  */
-	  if (!lex->select_lex.add_table_to_list(YYTHD, $7, 
+	  if (!lex->select_lex.add_table_to_list(YYTHD, $8,
 	                                         (LEX_STRING*) 0,
 	                                         TL_OPTION_UPDATING,
-	                                         TL_WRITE))
+                                                 TL_IGNORE))
 	    YYABORT;
 	}
 	;

--- 1.25/mysql-test/r/trigger.result	2005-12-11 15:26:10 +03:00
+++ 1.26/mysql-test/r/trigger.result	2006-01-13 18:08:44 +03:00
@@ -786,3 +786,72 @@
 ERROR 3D000: No database selected
 drop trigger t1_bi;
 ERROR 3D000: No database selected
+create table t1 (id int);
+create trigger t1_bi before insert on t1 for each row set @a:=new.id;
+insert into t1 values (101);
+select @a;
+@a
+101
+select * from information_schema.triggers where event_object_schema = 'test';
+TRIGGER_CATALOG	TRIGGER_SCHEMA	TRIGGER_NAME	EVENT_MANIPULATION	EVENT_OBJECT_CATALOG	EVENT_OBJECT_SCHEMA	EVENT_OBJECT_TABLE	ACTION_ORDER	ACTION_CONDITION	ACTION_STATEMENT	ACTION_ORIENTATION	ACTION_TIMING	ACTION_REFERENCE_OLD_TABLE	ACTION_REFERENCE_NEW_TABLE	ACTION_REFERENCE_OLD_ROW	ACTION_REFERENCE_NEW_ROW	CREATED	SQL_MODE	DEFINER
+NULL	test	t1_bi	INSERT	NULL	test	t1	0	NULL	 set @a:=new.id	ROW	BEFORE	NULL	NULL	OLD	NEW	NULL		root@localhost
+rename table t1 to t2;
+insert into t2 values (102);
+select @a;
+@a
+102
+select * from information_schema.triggers where event_object_schema = 'test';
+TRIGGER_CATALOG	TRIGGER_SCHEMA	TRIGGER_NAME	EVENT_MANIPULATION	EVENT_OBJECT_CATALOG	EVENT_OBJECT_SCHEMA	EVENT_OBJECT_TABLE	ACTION_ORDER	ACTION_CONDITION	ACTION_STATEMENT	ACTION_ORIENTATION	ACTION_TIMING	ACTION_REFERENCE_OLD_TABLE	ACTION_REFERENCE_NEW_TABLE	ACTION_REFERENCE_OLD_ROW	ACTION_REFERENCE_NEW_ROW	CREATED	SQL_MODE	DEFINER
+NULL	test	t1_bi	INSERT	NULL	test	t2	0	NULL	 set @a:=new.id	ROW	BEFORE	NULL	NULL	OLD	NEW	NULL		root@localhost
+drop trigger t1_bi;
+drop table t2;
+create database mysqltest;
+use mysqltest;
+create table t1 (id int);
+create trigger t1_bi before insert on t1 for each row set @a:=new.id;
+insert into t1 values (101);
+select @a;
+@a
+101
+select * from information_schema.triggers where event_object_schema = 'mysqltest' or event_object_schema = 'test';
+TRIGGER_CATALOG	TRIGGER_SCHEMA	TRIGGER_NAME	EVENT_MANIPULATION	EVENT_OBJECT_CATALOG	EVENT_OBJECT_SCHEMA	EVENT_OBJECT_TABLE	ACTION_ORDER	ACTION_CONDITION	ACTION_STATEMENT	ACTION_ORIENTATION	ACTION_TIMING	ACTION_REFERENCE_OLD_TABLE	ACTION_REFERENCE_NEW_TABLE	ACTION_REFERENCE_OLD_ROW	ACTION_REFERENCE_NEW_ROW	CREATED	SQL_MODE	DEFINER
+NULL	mysqltest	t1_bi	INSERT	NULL	mysqltest	t1	0	NULL	 set @a:=new.id	ROW	BEFORE	NULL	NULL	OLD	NEW	NULL		root@localhost
+rename table t1 to test.t2;
+ERROR HY000: Trigger in wrong schema
+insert into t1 values (102);
+select @a;
+@a
+102
+select * from information_schema.triggers where event_object_schema = 'mysqltest' or event_object_schema = 'test';
+TRIGGER_CATALOG	TRIGGER_SCHEMA	TRIGGER_NAME	EVENT_MANIPULATION	EVENT_OBJECT_CATALOG	EVENT_OBJECT_SCHEMA	EVENT_OBJECT_TABLE	ACTION_ORDER	ACTION_CONDITION	ACTION_STATEMENT	ACTION_ORIENTATION	ACTION_TIMING	ACTION_REFERENCE_OLD_TABLE	ACTION_REFERENCE_NEW_TABLE	ACTION_REFERENCE_OLD_ROW	ACTION_REFERENCE_NEW_ROW	CREATED	SQL_MODE	DEFINER
+NULL	mysqltest	t1_bi	INSERT	NULL	mysqltest	t1	0	NULL	 set @a:=new.id	ROW	BEFORE	NULL	NULL	OLD	NEW	NULL		root@localhost
+drop trigger test.t1_bi;
+ERROR HY000: Trigger does not exist
+drop trigger t1_bi;
+drop table t1;
+drop database mysqltest;
+use test;
+create table t1 (id int);
+create trigger t1_bi before insert on t1 for each row set @a:=new.id;
+create trigger t1_ai after insert on t1 for each row set @b:=new.id;
+insert into t1 values (101);
+select @a, @b;
+@a	@b
+101	101
+select * from information_schema.triggers where event_object_schema = 'test';
+TRIGGER_CATALOG	TRIGGER_SCHEMA	TRIGGER_NAME	EVENT_MANIPULATION	EVENT_OBJECT_CATALOG	EVENT_OBJECT_SCHEMA	EVENT_OBJECT_TABLE	ACTION_ORDER	ACTION_CONDITION	ACTION_STATEMENT	ACTION_ORIENTATION	ACTION_TIMING	ACTION_REFERENCE_OLD_TABLE	ACTION_REFERENCE_NEW_TABLE	ACTION_REFERENCE_OLD_ROW	ACTION_REFERENCE_NEW_ROW	CREATED	SQL_MODE	DEFINER
+NULL	test	t1_bi	INSERT	NULL	test	t1	0	NULL	 set @a:=new.id	ROW	BEFORE	NULL	NULL	OLD	NEW	NULL		root@localhost
+NULL	test	t1_ai	INSERT	NULL	test	t1	0	NULL	 set @b:=new.id	ROW	AFTER	NULL	NULL	OLD	NEW	NULL		root@localhost
+rename table t1 to t2;
+ERROR HY000: Can't create/write to file './test/t1_ai.TRN~' (Errcode: 13)
+insert into t1 values (102);
+select @a, @b;
+@a	@b
+102	102
+select * from information_schema.triggers where event_object_schema = 'test';
+TRIGGER_CATALOG	TRIGGER_SCHEMA	TRIGGER_NAME	EVENT_MANIPULATION	EVENT_OBJECT_CATALOG	EVENT_OBJECT_SCHEMA	EVENT_OBJECT_TABLE	ACTION_ORDER	ACTION_CONDITION	ACTION_STATEMENT	ACTION_ORIENTATION	ACTION_TIMING	ACTION_REFERENCE_OLD_TABLE	ACTION_REFERENCE_NEW_TABLE	ACTION_REFERENCE_OLD_ROW	ACTION_REFERENCE_NEW_ROW	CREATED	SQL_MODE	DEFINER
+NULL	test	t1_bi	INSERT	NULL	test	t1	0	NULL	 set @a:=new.id	ROW	BEFORE	NULL	NULL	OLD	NEW	NULL		root@localhost
+NULL	test	t1_ai	INSERT	NULL	test	t1	0	NULL	 set @b:=new.id	ROW	AFTER	NULL	NULL	OLD	NEW	NULL		root@localhost
+drop trigger t1_bi;
+drop trigger t1_ai;
+drop table t1;

--- 1.31/mysql-test/t/trigger.test	2005-12-11 15:26:10 +03:00
+++ 1.32/mysql-test/t/trigger.test	2006-01-13 18:08:44 +03:00
@@ -961,3 +961,62 @@
 --error ER_NO_DB_ERROR
 drop trigger t1_bi;
 connection default;
+
+#
+# Test for bug #13525 "Rename table does not keep info of triggers"
+#
+create table t1 (id int);
+create trigger t1_bi before insert on t1 for each row set @a:=new.id;
+insert into t1 values (101);
+select @a;
+select * from information_schema.triggers where event_object_schema = 'test';
+rename table t1 to t2;
+# Trigger should work after rename
+insert into t2 values (102);
+select @a;
+select * from information_schema.triggers where event_object_schema = 'test';
+# .TRN file should be updated with new table name
+drop trigger t1_bi;
+drop table t2;
+# Rename between different databases if triggers exist should fail
+create database mysqltest;
+use mysqltest;
+create table t1 (id int);
+create trigger t1_bi before insert on t1 for each row set @a:=new.id;
+insert into t1 values (101);
+select @a;
+select * from information_schema.triggers where event_object_schema = 'mysqltest' or event_object_schema = 'test';
+--error ER_TRG_IN_WRONG_SCHEMA
+rename table t1 to test.t2;
+insert into t1 values (102);
+select @a;
+select * from information_schema.triggers where event_object_schema = 'mysqltest' or event_object_schema = 'test';
+# There should be no fantom .TRN files 
+--error ER_TRG_DOES_NOT_EXIST
+drop trigger test.t1_bi;
+drop trigger t1_bi;
+drop table t1;
+drop database mysqltest;
+use test;
+# And now let us check that the properly handle rename if there is some
+# error during it (that we rollback such renames completely).
+create table t1 (id int);
+create trigger t1_bi before insert on t1 for each row set @a:=new.id;
+create trigger t1_ai after insert on t1 for each row set @b:=new.id;
+insert into t1 values (101);
+select @a, @b;
+select * from information_schema.triggers where event_object_schema = 'test';
+# Trick which makes update of second .TRN file impossible
+system echo dummy >var/master-data/test/t1_ai.TRN~;
+system chmod 000 var/master-data/test/t1_ai.TRN~;
+--error 1
+rename table t1 to t2;
+# 't1' should be still there and triggers should work correctly
+insert into t1 values (102);
+select @a, @b;
+select * from information_schema.triggers where event_object_schema = 'test';
+system chmod 600 var/master-data/test/t1_ai.TRN;
+# Let us check that updates to .TRN files were rolled back too
+drop trigger t1_bi;
+drop trigger t1_ai;
+drop table t1;

--- 1.38/sql/sql_trigger.cc	2005-12-21 18:05:08 +03:00
+++ 1.39/sql/sql_trigger.cc	2006-01-13 18:08:45 +03:00
@@ -58,7 +58,6 @@
 */
 
 static const int TRG_NUM_REQUIRED_PARAMETERS= 4;
-static const int TRG_MAX_VERSIONS= 3;
 
 /*
   Structure representing contents of .TRN file which are used to support
@@ -455,8 +454,7 @@
                                definer_host->str, NullS) - trg_definer->str;
 
   if (!sql_create_definition_file(&dir, &file, &triggers_file_type,
-                                  (gptr)this, triggers_file_parameters,
-                                  TRG_MAX_VERSIONS))
+                                  (gptr)this, triggers_file_parameters, 0))
     return 0;
 
 err_with_cleanup:
@@ -480,7 +478,8 @@
     True  - error
 */
 
-static bool rm_trigger_file(char *path, char *db, char *table_name)
+static bool rm_trigger_file(char *path, const char *db,
+                            const char *table_name)
 {
   strxnmov(path, FN_REFLEN, mysql_data_home, "/", db, "/", table_name,
            triggers_file_ext, NullS);
@@ -504,7 +503,8 @@
     True  - error
 */
 
-static bool rm_trigname_file(char *path, char *db, char *trigger_name)
+static bool rm_trigname_file(char *path, const char *db,
+                             const char *trigger_name)
 {
   strxnmov(path, FN_REFLEN, mysql_data_home, "/", db, "/", trigger_name,
            trigname_file_ext, NullS);
@@ -514,6 +514,38 @@
 
 
 /*
+  Helper function that saves .TRG file for Table_triggers_list object.
+
+  SYNOPSIS
+    save_trigger_file()
+      triggers    Table_triggers_list object for which file should be saved
+      db          Name of database for subject table
+      table_name  Name of subject table
+
+  RETURN VALUE
+    FALSE  Success
+    TRUE   Error
+*/
+
+static bool save_trigger_file(Table_triggers_list *triggers, const char *db,
+                              const char *table_name)
+{
+  char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
+  LEX_STRING dir, file;
+
+  strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", db, "/", NullS);
+  dir.length= unpack_filename(dir_buff, dir_buff);
+  dir.str= dir_buff;
+  file.length=  strxnmov(file_buff, FN_REFLEN, table_name, triggers_file_ext,
+                         NullS) - file_buff;
+  file.str= file_buff;
+
+  return sql_create_definition_file(&dir, &file, &triggers_file_type,
+                                    (gptr)triggers, triggers_file_parameters, 0);
+}
+
+
+/*
   Drop trigger for table.
 
   SYNOPSIS
@@ -566,20 +598,7 @@
       }
       else
       {
-        char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
-        LEX_STRING dir, file;
-
-        strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", tables->db,
-                 "/", NullS);
-        dir.length= unpack_filename(dir_buff, dir_buff);
-        dir.str= dir_buff;
-        file.length=  strxnmov(file_buff, FN_REFLEN, tables->table_name,
-                               triggers_file_ext, NullS) - file_buff;
-        file.str= file_buff;
-
-        if (sql_create_definition_file(&dir, &file, &triggers_file_type,
-                                       (gptr)this, triggers_file_parameters,
-                                       TRG_MAX_VERSIONS))
+        if (save_trigger_file(this, tables->db, tables->table_name))
           return 1;
       }
 
@@ -819,13 +838,13 @@
       if (!names_only && triggers->prepare_record1_accessors(table))
         DBUG_RETURN(1);
 
-      char *trg_name_buff;
       List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
       List_iterator_fast<LEX_STRING> it_definer(triggers->
                                                 definers_list);
       LEX *old_lex= thd->lex, lex;
       sp_rcontext *save_spcont= thd->spcont;
       ulong save_sql_mode= thd->variables.sql_mode;
+      LEX_STRING *on_table_name;
 
       thd->lex= &lex;
 
@@ -890,6 +909,21 @@
                                            &table->mem_root))
             goto err_with_lex_cleanup;
 
+        if (!(on_table_name= (LEX_STRING*) alloc_root(&table->mem_root,
+                                                      sizeof(LEX_STRING))))
+          goto err_with_lex_cleanup;
+        *on_table_name=  lex.ident;
+        if (triggers->on_table_names_list.push_back(on_table_name, &table->mem_root))
+          goto err_with_lex_cleanup;
+
+        /*
+          Let us check that we correctly update trigger definitions when we
+          rename tables with triggers.
+        */
+        DBUG_ASSERT(!my_strcasecmp(table_alias_charset, lex.query_tables->db, db) &&
+                    !my_strcasecmp(table_alias_charset, lex.query_tables->table_name,
+                                   table_name));
+
         if (names_only)
         {
           lex_end(&lex);
@@ -1055,7 +1089,7 @@
   lex->query_tables= 0;
   lex->query_tables_last= &lex->query_tables;
   DBUG_RETURN(sp_add_to_query_tables(thd, lex, trig->m_db.str,
-                                     trigname.trigger_table.str, TL_WRITE));
+                                     trigname.trigger_table.str, TL_IGNORE));
 }
 
 
@@ -1124,6 +1158,229 @@
   DBUG_RETURN(result);
 }
 
+
+/*
+  Update .TRG file after renaming triggers' subject table
+  (change name of table in triggers' definitions).
+
+  SYNOPSIS
+    change_table_name_in_triggers()
+      thd                 Thread context
+      db_name             Database of subject table
+      old_table_name      Old subject table's name
+      new_table_name      New subject table's name
+      new_table_name_len  Length of new subject table's name
+
+  RETURN VALUE
+    FALSE  Success
+    TRUE   Failure
+*/
+
+bool
+Table_triggers_list::change_table_name_in_triggers(THD *thd,
+                                                   const char *db_name,
+                                                   const char *old_table_name,
+                                                   const char *new_table_name,
+                                                   uint new_table_name_len)
+{
+  char path_buff[FN_REFLEN];
+  LEX_STRING *def, *on_table_name, new_def;
+  ulonglong *sql_mode;
+  ulong save_sql_mode= thd->variables.sql_mode;
+  List_iterator_fast<LEX_STRING> it_def(definitions_list);
+  List_iterator_fast<LEX_STRING> it_on_table_name(on_table_names_list);
+  List_iterator_fast<ulonglong> it_mode(definition_modes_list);
+  uint on_q_table_name_len;
+  String buff;
+
+  DBUG_ASSERT(definitions_list.elements == on_table_names_list.elements &&
+              definitions_list.elements == definition_modes_list.elements);
+
+  while ((def= it_def++))
+  {
+    on_table_name= it_on_table_name++;
+    thd->variables.sql_mode= *(it_mode++);
+
+    /* Construct CREATE TRIGGER statement with new table name. */
+    buff.length(0);
+    buff.append(def->str, on_table_name->str - def->str);
+    on_q_table_name_len= buff.length();
+    buff.append(STRING_WITH_LEN("ON "));
+    append_identifier(thd, &buff, new_table_name, new_table_name_len);
+    on_q_table_name_len= buff.length() - on_q_table_name_len;
+    buff.append(on_table_name->str + on_table_name->length,
+                def->length - (on_table_name->str - def->str +
+                               on_table_name->length));
+    new_def.str= memdup_root(&table->mem_root, buff.ptr(), buff.length());
+    new_def.length= buff.length();
+    on_table_name->str= new_def.str + (on_table_name->str - def->str);
+    on_table_name->length= on_q_table_name_len;
+    *def= new_def;
+  }
+
+  thd->variables.sql_mode= save_sql_mode;
+
+  if (thd->is_fatal_error)
+    return TRUE; /* OOM */
+
+  if (save_trigger_file(this, db_name, new_table_name))
+    return TRUE;
+  if (rm_trigger_file(path_buff, db_name, old_table_name))
+  {
+    (void) rm_trigger_file(path_buff, db_name, new_table_name);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+
+/*
+  Iterate though Table_triggers_list::names_list list and update .TRN files
+  after renaming triggers' subject table.
+
+  SYNOPSIS
+    change_table_name_in_trignames()
+      db_name             Database of subject table
+      new_db_name         New name of database of subject table
+      new_table_name      New subject table's name
+      new_table_name_len  Length of new subject table's name
+      stopper             Pointer to Table_triggers_list::names_list at
+                          which we should stop updating.
+
+  RETURN VALUE
+    0      Success
+    non-0  Failure, pointer to Table_triggers_list::names_list element
+           for which update failed.
+*/
+
+LEX_STRING*
+Table_triggers_list::change_table_name_in_trignames(const char *db_name,
+                                                    const char *new_table_name,
+                                                    uint new_table_name_len,
+                                                    LEX_STRING *stopper)
+{
+  char dir_buff[FN_REFLEN], trigname_buff[FN_REFLEN];
+  struct st_trigname trigname;
+  LEX_STRING dir, trigname_file;
+  LEX_STRING *trigger;
+  List_iterator_fast<LEX_STRING> it_name(names_list);
+
+  strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", db_name, "/", NullS);
+  dir.length= unpack_filename(dir_buff, dir_buff);
+  dir.str= dir_buff;
+
+  while ((trigger= it_name++) != stopper)
+  {
+    trigname_file.length= strxnmov(trigname_buff, FN_REFLEN, trigger->str,
+                                   trigname_file_ext, NullS) - trigname_buff;
+    trigname_file.str= trigname_buff;
+
+    trigname.trigger_table.str= (char *) new_table_name;
+    trigname.trigger_table.length= new_table_name_len;
+
+    if (sql_create_definition_file(&dir, &trigname_file, &trigname_file_type,
+        (gptr)&trigname, trigname_file_parameters, 0))
+      return trigger;
+  }
+
+  return 0;
+}
+
+
+/*
+  Update .TRG and .TRN files after renaming triggers' subject table.
+
+  SYNOPSIS
+    change_table_name()
+      thd             Thread context
+      db_name         Old database of subject table
+      old_table_name  Old name of subject table
+      new_db_name     New database for subject table
+      new_table_name  New name of subject table
+
+  NOTE
+    This method tries to leave trigger related files in consistent state,
+    i.e. it either will complete successfully, or will fail leaving files
+    in their initial state.
+
+  RETURN VALUE
+    FALSE  Success
+    TRUE   Error
+*/
+
+bool Table_triggers_list::change_table_name(THD *thd, const char *db_name,
+                                            const char *old_table_name,
+                                            const char *new_db_name,
+                                            const char *new_table_name)
+{
+  TABLE table;
+  bool result= 0;
+  LEX_STRING *err_trigname;
+  uint table_name_len;
+  DBUG_ENTER("change_table_name");
+
+  bzero(&table, sizeof(table));
+  init_alloc_root(&table.mem_root, 8192, 0);
+
+  safe_mutex_assert_owner(&LOCK_open);
+
+  if (Table_triggers_list::check_n_load(thd, db_name, old_table_name,
+                                        &table, TRUE))
+  {
+    result= 1;
+    goto end;
+  }
+  if (table.triggers)
+  {
+    /*
+      Since triggers should be in the same schema as their subject tables
+      moving table with them between two schemas raises too much questions.
+      (E.g. what should happen if in new schema we already have trigger
+       with same name ?).
+    */
+    if (my_strcasecmp(table_alias_charset, db_name, new_db_name))
+    {
+      my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
+      result= 1;
+      goto end;
+    }
+    table_name_len= strlen(new_table_name);
+    if (table.triggers->change_table_name_in_triggers(thd, db_name,
+                                                      old_table_name,
+                                                      new_table_name,
+                                                      table_name_len))
+    {
+      result= 1;
+      goto end;
+    }
+    if ((err_trigname= table.triggers->change_table_name_in_trignames(
+                                         db_name, new_table_name,
+                                         table_name_len, 0)))
+    {
+      /*
+        If we were unable to update one of .TRN files properly we will
+        revert all changes that we have done and report about error.
+        We assume that we will be able to undo our changes without errors
+        (we can't do much if there will be an error anyway).
+      */
+      table_name_len= strlen(old_table_name);
+      (void) table.triggers->change_table_name_in_trignames(db_name,
+                                                            old_table_name,
+                                                            table_name_len,
+                                                            err_trigname);
+      (void) table.triggers->change_table_name_in_triggers(thd, db_name,
+                                                           new_table_name,
+                                                           old_table_name,
+                                                           table_name_len);
+      result= 1;
+      goto end;
+    }
+  }
+end:
+  delete table.triggers;
+  free_root(&table.mem_root, MYF(0));
+  DBUG_RETURN(result);
+}
 
 
 bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,

--- 1.17/sql/sql_trigger.h	2005-12-07 12:36:24 +03:00
+++ 1.18/sql/sql_trigger.h	2006-01-13 18:08:45 +03:00
@@ -47,6 +47,11 @@
   */
   List<LEX_STRING>  names_list;
   /*
+    List of "ON table_name" parts in trigger definitions, used for
+    updating trigger definitions during RENAME TABLE.
+  */
+  List<LEX_STRING>  on_table_names_list;
+  /*
     Key representing triggers for this table in set of all stored
     routines used by statement.
     TODO: We won't need this member once triggers namespace will be
@@ -97,7 +102,10 @@
   static bool check_n_load(THD *thd, const char *db, const char *table_name,
                            TABLE *table, bool names_only);
   static bool drop_all_triggers(THD *thd, char *db, char *table_name);
-
+  static bool change_table_name(THD *thd, const char *db_name,
+                                const char *old_table_name,
+                                const char *new_db_name,
+                                const char *new_table_name);
   bool has_delete_triggers()
   {
     return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
@@ -122,6 +130,15 @@
 
 private:
   bool prepare_record1_accessors(TABLE *table);
+  LEX_STRING* change_table_name_in_trignames(const char *db_name,
+                                             const char *new_table_name,
+                                             uint new_table_name_len,
+                                             LEX_STRING *stopper);
+  bool change_table_name_in_triggers(THD *thd,
+                                     const char *db_name,
+                                     const char *old_table_name,
+                                     const char *new_table_name,
+                                     uint new_table_name_len);
 };
 
 extern const LEX_STRING trg_action_time_type_names[];

--- 1.31/sql/sql_rename.cc	2005-11-03 17:10:04 +03:00
+++ 1.32/sql/sql_rename.cc	2006-01-13 18:08:45 +03:00
@@ -19,6 +19,7 @@
 */
 
 #include "mysql_priv.h"
+#include "sql_trigger.h"
 
 
 static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list,
@@ -176,8 +177,26 @@
         if (table_type == DB_TYPE_UNKNOWN) 
           my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
         else
-          rc= mysql_rename_table(table_type, ren_table->db, old_alias,
-                                 new_table->db, new_alias);
+        {
+          if (!(rc= mysql_rename_table(table_type, ren_table->db, old_alias,
+                                       new_table->db, new_alias)))
+          {
+            if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
+                                                            old_alias,
+                                                            new_table->db,
+                                                            new_alias)))
+            {
+              /*
+                We've succeeded in renaming table's .frm and in updating
+                corresponding handler data, but have failed to update table's
+                triggers appropriately. So let us revert operations on .frm
+                and handler's data and report about failure to rename table.
+              */
+              (void) mysql_rename_table(table_type, new_table->db, new_alias,
+                                        ren_table->db, old_alias);
+            }
+          }
+        }
         break;
       }
       case FRMTYPE_VIEW:
Thread
bk commit into 5.0 tree (dlenev:1.1999) BUG#13525dlenev13 Jan