summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <dlenev@mysql.com>2006-02-26 16:38:48 +0300
committerunknown <dlenev@mysql.com>2006-02-26 16:38:48 +0300
commit1c93eeaa16774f4c9c0e1a3be9376541b218f053 (patch)
tree4b1048c53e299ed44184fa45c4acce47e62f0c82
parent258ad72c83154ef23bb4b9c0f492aa3e97b0bbed (diff)
parentf8386dfa4821b79b6f88f8d9950ed370ba22e508 (diff)
downloadmariadb-git-1c93eeaa16774f4c9c0e1a3be9376541b218f053.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-5.0-runtime
into mysql.com:/home/dlenev/src/mysql-5.0-bg13525 sql/sql_table.cc: Auto merged sql/sql_trigger.cc: Auto merged sql/sql_trigger.h: Auto merged sql/sql_yacc.yy: Auto merged mysql-test/r/trigger.result: SCCS merged mysql-test/t/trigger.test: SCCS merged
-rw-r--r--mysql-test/r/trigger.result103
-rw-r--r--mysql-test/t/trigger.test87
-rw-r--r--sql/sql_rename.cc23
-rw-r--r--sql/sql_table.cc13
-rw-r--r--sql/sql_trigger.cc290
-rw-r--r--sql/sql_trigger.h17
-rw-r--r--sql/sql_yacc.yy16
7 files changed, 513 insertions, 36 deletions
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 62c0d01327d..ea232e081ba 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -1,4 +1,4 @@
-drop table if exists t1, t2, t3;
+drop table if exists t1, t2, t3, t4;
drop view if exists v1;
drop database if exists mysqltest;
drop function if exists f1;
@@ -785,6 +785,107 @@ create trigger test.t1_bi before insert on t1 for each row set @a:=0;
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 trigger_schema, trigger_name, event_object_schema,
+event_object_table, action_statement from information_schema.triggers
+where event_object_schema = 'test';
+trigger_schema trigger_name event_object_schema event_object_table action_statement
+test t1_bi test t1 set @a:=new.id
+rename table t1 to t2;
+insert into t2 values (102);
+select @a;
+@a
+102
+select trigger_schema, trigger_name, event_object_schema,
+event_object_table, action_statement from information_schema.triggers
+where event_object_schema = 'test';
+trigger_schema trigger_name event_object_schema event_object_table action_statement
+test t1_bi test t2 set @a:=new.id
+alter table t2 rename to t3;
+insert into t3 values (103);
+select @a;
+@a
+103
+select trigger_schema, trigger_name, event_object_schema,
+event_object_table, action_statement from information_schema.triggers
+where event_object_schema = 'test';
+trigger_schema trigger_name event_object_schema event_object_table action_statement
+test t1_bi test t3 set @a:=new.id
+alter table t3 rename to t4, add column val int default 0;
+insert into t4 values (104, 1);
+select @a;
+@a
+104
+select trigger_schema, trigger_name, event_object_schema,
+event_object_table, action_statement from information_schema.triggers
+where event_object_schema = 'test';
+trigger_schema trigger_name event_object_schema event_object_table action_statement
+test t1_bi test t4 set @a:=new.id
+drop trigger t1_bi;
+drop table t4;
+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 trigger_schema, trigger_name, event_object_schema,
+event_object_table, action_statement from information_schema.triggers
+where event_object_schema = 'test' or event_object_schema = 'mysqltest';
+trigger_schema trigger_name event_object_schema event_object_table action_statement
+mysqltest t1_bi mysqltest t1 set @a:=new.id
+rename table t1 to test.t2;
+ERROR HY000: Trigger in wrong schema
+insert into t1 values (102);
+select @a;
+@a
+102
+select trigger_schema, trigger_name, event_object_schema,
+event_object_table, action_statement from information_schema.triggers
+where event_object_schema = 'test' or event_object_schema = 'mysqltest';
+trigger_schema trigger_name event_object_schema event_object_table action_statement
+mysqltest t1_bi mysqltest t1 set @a:=new.id
+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 trigger_schema, trigger_name, event_object_schema,
+event_object_table, action_statement from information_schema.triggers
+where event_object_schema = 'test';
+trigger_schema trigger_name event_object_schema event_object_table action_statement
+test t1_bi test t1 set @a:=new.id
+test t1_ai test t1 set @b:=new.id
+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 trigger_schema, trigger_name, event_object_schema,
+event_object_table, action_statement from information_schema.triggers
+where event_object_schema = 'test';
+trigger_schema trigger_name event_object_schema event_object_table action_statement
+test t1_bi test t1 set @a:=new.id
+test t1_ai test t1 set @b:=new.id
+drop trigger t1_bi;
+drop trigger t1_ai;
+drop table t1;
create table t1 (i int);
create trigger t1_bi before insert on t1 for each row return 0;
ERROR 42000: RETURN is only allowed in a FUNCTION
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index c3cc8e3f8e8..e1564e33a43 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -3,7 +3,7 @@
#
--disable_warnings
-drop table if exists t1, t2, t3;
+drop table if exists t1, t2, t3, t4;
drop view if exists v1;
drop database if exists mysqltest;
drop function if exists f1;
@@ -959,6 +959,91 @@ create trigger test.t1_bi before insert on t1 for each row set @a:=0;
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 trigger_schema, trigger_name, event_object_schema,
+ event_object_table, action_statement 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 trigger_schema, trigger_name, event_object_schema,
+ event_object_table, action_statement from information_schema.triggers
+ where event_object_schema = 'test';
+# Let us check that the same works for simple ALTER TABLE ... RENAME
+alter table t2 rename to t3;
+insert into t3 values (103);
+select @a;
+select trigger_schema, trigger_name, event_object_schema,
+ event_object_table, action_statement from information_schema.triggers
+ where event_object_schema = 'test';
+# And for more complex ALTER TABLE
+alter table t3 rename to t4, add column val int default 0;
+insert into t4 values (104, 1);
+select @a;
+select trigger_schema, trigger_name, event_object_schema,
+ event_object_table, action_statement from information_schema.triggers
+ where event_object_schema = 'test';
+# .TRN file should be updated with new table name
+drop trigger t1_bi;
+drop table t4;
+# 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 trigger_schema, trigger_name, event_object_schema,
+ event_object_table, action_statement from information_schema.triggers
+ where event_object_schema = 'test' or event_object_schema = 'mysqltest';
+--error ER_TRG_IN_WRONG_SCHEMA
+rename table t1 to test.t2;
+insert into t1 values (102);
+select @a;
+select trigger_schema, trigger_name, event_object_schema,
+ event_object_table, action_statement from information_schema.triggers
+ where event_object_schema = 'test' or event_object_schema = 'mysqltest';
+# 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 trigger_schema, trigger_name, event_object_schema,
+ event_object_table, action_statement 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 trigger_schema, trigger_name, event_object_schema,
+ event_object_table, action_statement 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;
+
# Test for bug #16829 "Firing trigger with RETURN crashes the server"
# RETURN is not supposed to be used anywhere except functions, so error
# should be returned when one attempts to create trigger with RETURN.
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 80fcb973028..74951029de9 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -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 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
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:
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index de350b83985..c4b45e96ad7 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -3287,6 +3287,13 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
close_cached_table(thd, table);
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias))
error= -1;
+ else if (Table_triggers_list::change_table_name(thd, db, table_name,
+ new_db, new_alias))
+ {
+ VOID(mysql_rename_table(old_db_type, new_db, new_alias, db,
+ table_name));
+ error= -1;
+ }
}
VOID(pthread_mutex_unlock(&LOCK_open));
}
@@ -3835,7 +3842,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
VOID(quick_rm_table(new_db_type,new_db,tmp_name));
}
else if (mysql_rename_table(new_db_type,new_db,tmp_name,new_db,
- new_alias))
+ new_alias) ||
+ (new_name != table_name || new_db != db) && // we also do rename
+ Table_triggers_list::change_table_name(thd, db, table_name,
+ new_db, new_alias))
+
{ // Try to get everything back
error=1;
VOID(quick_rm_table(new_db_type,new_db,new_alias));
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 53743314782..4c3ae5c032d 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -65,7 +65,6 @@ File_option sql_modes_parameters=
*/
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
@@ -467,8 +466,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
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:
@@ -492,7 +490,8 @@ err_with_cleanup:
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);
@@ -516,7 +515,8 @@ static bool rm_trigger_file(char *path, char *db, char *table_name)
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);
@@ -526,6 +526,38 @@ static bool rm_trigname_file(char *path, char *db, char *trigger_name)
/*
+ 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
@@ -578,20 +610,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
}
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;
}
@@ -831,12 +850,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
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;
@@ -902,6 +921,21 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
&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);
@@ -1067,7 +1101,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
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));
}
@@ -1137,6 +1171,220 @@ end:
}
+/*
+ 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
+
+ RETURN VALUE
+ FALSE Success
+ TRUE Failure
+*/
+
+bool
+Table_triggers_list::change_table_name_in_triggers(THD *thd,
+ const char *db_name,
+ LEX_STRING *old_table_name,
+ LEX_STRING *new_table_name)
+{
+ 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, before_on_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);
+ before_on_len= on_table_name->str - def->str;
+ buff.append(def->str, before_on_len);
+ buff.append(STRING_WITH_LEN("ON "));
+ append_identifier(thd, &buff, new_table_name->str, new_table_name->length);
+ on_q_table_name_len= buff.length() - before_on_len;
+ buff.append(on_table_name->str + on_table_name->length,
+ def->length - (before_on_len + on_table_name->length));
+ /*
+ It is OK to allocate some memory on table's MEM_ROOT since this
+ table instance will be thrown out at the end of rename anyway.
+ */
+ new_def.str= memdup_root(&table->mem_root, buff.ptr(), buff.length());
+ new_def.length= buff.length();
+ on_table_name->str= new_def.str + before_on_len;
+ 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->str))
+ return TRUE;
+ if (rm_trigger_file(path_buff, db_name, old_table_name->str))
+ {
+ (void) rm_trigger_file(path_buff, db_name, new_table_name->str);
+ 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_table_name 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,
+ LEX_STRING *new_table_name,
+ 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= *new_table_name;
+
+ 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 Old database of subject table
+ old_table Old name of subject table
+ new_db New database for subject table
+ new_table 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,
+ const char *old_table,
+ const char *new_db,
+ const char *new_table)
+{
+ TABLE table;
+ bool result= 0;
+ LEX_STRING *err_trigname;
+ 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, old_table, &table, TRUE))
+ {
+ result= 1;
+ goto end;
+ }
+ if (table.triggers)
+ {
+ LEX_STRING_WITH_INIT old_table_name(old_table, strlen(old_table));
+ LEX_STRING_WITH_INIT new_table_name(new_table, strlen(new_table));
+ /*
+ Since triggers should be in the same schema as their subject tables
+ moving table with them between two schemas raises too many questions.
+ (E.g. what should happen if in new schema we already have trigger
+ with same name ?).
+ */
+ if (my_strcasecmp(table_alias_charset, db, new_db))
+ {
+ my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
+ result= 1;
+ goto end;
+ }
+ if (table.triggers->change_table_name_in_triggers(thd, db,
+ &old_table_name,
+ &new_table_name))
+ {
+ result= 1;
+ goto end;
+ }
+ if ((err_trigname= table.triggers->change_table_name_in_trignames(
+ db, &new_table_name, 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).
+ */
+ (void) table.triggers->change_table_name_in_trignames(db,
+ &old_table_name,
+ err_trigname);
+ (void) table.triggers->change_table_name_in_triggers(thd, db,
+ &new_table_name,
+ &old_table_name);
+ 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,
trg_action_time_type time_type,
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 8992de63b37..b67c22e0588 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -47,6 +47,11 @@ class Table_triggers_list: public Sql_alloc
*/
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 @@ public:
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,
+ const char *old_table,
+ const char *new_db,
+ const char *new_table);
bool has_delete_triggers()
{
return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
@@ -117,6 +125,13 @@ public:
private:
bool prepare_record1_accessors(TABLE *table);
+ LEX_STRING* change_table_name_in_trignames(const char *db_name,
+ LEX_STRING *new_table_name,
+ LEX_STRING *stopper);
+ bool change_table_name_in_triggers(THD *thd,
+ const char *db_name,
+ LEX_STRING *old_table_name,
+ LEX_STRING *new_table_name);
};
extern const LEX_STRING trg_action_time_type_names[];
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 97410333c48..d6d2939bed3 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -9126,8 +9126,8 @@ view_check_option:
**************************************************************************/
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;
@@ -9144,7 +9144,9 @@ trigger_tail:
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;
@@ -9181,15 +9183,11 @@ trigger_tail:
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;
}
;