Merge bk-internal.mysql.com:/home/bk/mysql-5.0-runtime
into mysql.com:/home/dlenev/src/mysql-5.0-bg13525
This commit is contained in:
commit
0b422c635d
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
@ -525,6 +525,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.
|
||||
|
||||
@ -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,
|
||||
|
@ -46,6 +46,11 @@ class Table_triggers_list: public Sql_alloc
|
||||
used in CREATE/DROP TRIGGER for looking up trigger by name.
|
||||
*/
|
||||
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.
|
||||
@ -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[];
|
||||
|
@ -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;
|
||||
}
|
||||
;
|
||||
|
Loading…
x
Reference in New Issue
Block a user