Merge mysql.com:/home/dlenev/src/mysql-5.0-bg13525
into mysql.com:/home/dlenev/src/mysql-5.1-merges2 client/mysqltest.c: Auto merged include/my_global.h: Auto merged mysql-test/mysql-test-run.pl: Auto merged mysql-test/mysql-test-run.sh: Auto merged mysql-test/r/heap.result: Auto merged mysql-test/r/merge.result: Auto merged mysql-test/r/ps.result: Auto merged mysql-test/r/trigger.result: Auto merged mysql-test/r/view.result: Auto merged mysql-test/t/ps.test: Auto merged mysql-test/t/trigger.test: Auto merged mysql-test/t/view.test: Auto merged sql/field.cc: Auto merged sql/field.h: Auto merged sql/ha_myisammrg.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_table.cc: Auto merged storage/myisammrg/myrg_queue.c: Auto merged sql/sql_rename.cc: Manual merge. sql/sql_trigger.cc: Manual merge. sql/sql_yacc.yy: Manual merge.
This commit is contained in:
commit
e54ecf09be
@ -3662,8 +3662,10 @@ DYNAMIC_ARRAY patterns;
|
|||||||
static void init_win_path_patterns()
|
static void init_win_path_patterns()
|
||||||
{
|
{
|
||||||
/* List of string patterns to match in order to find paths */
|
/* List of string patterns to match in order to find paths */
|
||||||
const char* paths[] = { "$MYSQL_TEST_DIR", "./test/", 0 };
|
const char* paths[] = { "$MYSQL_TEST_DIR",
|
||||||
int num_paths= 2;
|
"$MYSQL_TMP_DIR",
|
||||||
|
"./test/", 0 };
|
||||||
|
int num_paths= 3;
|
||||||
int i;
|
int i;
|
||||||
char* p;
|
char* p;
|
||||||
|
|
||||||
|
@ -43,6 +43,15 @@
|
|||||||
#define HAVE_ERRNO_AS_DEFINE
|
#define HAVE_ERRNO_AS_DEFINE
|
||||||
#endif /* __CYGWIN__ */
|
#endif /* __CYGWIN__ */
|
||||||
|
|
||||||
|
#if defined(__QNXNTO__) && !defined(FD_SETSIZE)
|
||||||
|
#define FD_SETSIZE 1024 /* Max number of file descriptor bits in
|
||||||
|
fd_set, used when calling 'select'
|
||||||
|
Must be defined before including
|
||||||
|
"sys/select.h" and "sys/time.h"
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* to make command line shorter we'll define USE_PRAGMA_INTERFACE here */
|
/* to make command line shorter we'll define USE_PRAGMA_INTERFACE here */
|
||||||
#ifdef USE_PRAGMA_IMPLEMENTATION
|
#ifdef USE_PRAGMA_IMPLEMENTATION
|
||||||
#define USE_PRAGMA_INTERFACE
|
#define USE_PRAGMA_INTERFACE
|
||||||
|
@ -1156,6 +1156,7 @@ sub environment_setup () {
|
|||||||
$ENV{'USE_RUNNING_SERVER'}= $glob_use_running_server;
|
$ENV{'USE_RUNNING_SERVER'}= $glob_use_running_server;
|
||||||
$ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir;
|
$ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir;
|
||||||
$ENV{'MYSQLTEST_VARDIR'}= $opt_vardir;
|
$ENV{'MYSQLTEST_VARDIR'}= $opt_vardir;
|
||||||
|
$ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir;
|
||||||
$ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_mysock'};
|
$ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_mysock'};
|
||||||
$ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_mysock'};
|
$ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_mysock'};
|
||||||
$ENV{'MASTER_MYPORT'}= $master->[0]->{'path_myport'};
|
$ENV{'MASTER_MYPORT'}= $master->[0]->{'path_myport'};
|
||||||
@ -2876,7 +2877,7 @@ sub run_mysqltest ($) {
|
|||||||
if ( $opt_debug )
|
if ( $opt_debug )
|
||||||
{
|
{
|
||||||
$cmdline_mysqlcheck .=
|
$cmdline_mysqlcheck .=
|
||||||
" --debug=d:t:A,$opt_vardir_trace/log/mysqldump.trace";
|
" --debug=d:t:A,$opt_vardir_trace/log/mysqlcheck.trace";
|
||||||
}
|
}
|
||||||
|
|
||||||
my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " .
|
my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " .
|
||||||
|
@ -202,6 +202,7 @@ SYST=0
|
|||||||
REALT=0
|
REALT=0
|
||||||
FAST_START=""
|
FAST_START=""
|
||||||
MYSQL_TMP_DIR=$MYSQL_TEST_DIR/var/tmp
|
MYSQL_TMP_DIR=$MYSQL_TEST_DIR/var/tmp
|
||||||
|
export MYSQL_TMP_DIR
|
||||||
|
|
||||||
# Use a relative path for where the slave will find the dumps
|
# Use a relative path for where the slave will find the dumps
|
||||||
# generated by "LOAD DATA" on the master. The path is relative
|
# generated by "LOAD DATA" on the master. The path is relative
|
||||||
|
@ -402,3 +402,25 @@ explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'b
|
|||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 24 Using intersect(cola,colb); Using where
|
1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 24 Using intersect(cola,colb); Using where
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
create table t0 (a int);
|
||||||
|
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||||
|
create table t1 (
|
||||||
|
a int, b int,
|
||||||
|
filler1 char(200), filler2 char(200),
|
||||||
|
key(a),key(b)
|
||||||
|
);
|
||||||
|
insert into t1 select @v:= A.a, @v, 't1', 'filler2' from t0 A, t0 B, t0 C;
|
||||||
|
create table t2 like t1;
|
||||||
|
create table t3 (
|
||||||
|
a int, b int,
|
||||||
|
filler1 char(200), filler2 char(200),
|
||||||
|
key(a),key(b)
|
||||||
|
) engine=merge union=(t1,t2);
|
||||||
|
explain select * from t1 where a=1 and b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 index_merge a,b a,b 5,5 NULL # Using intersect(a,b); Using where
|
||||||
|
explain select * from t3 where a=1 and b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t3 index_merge a,b a,b 5,5 NULL # Using intersect(a,b); Using where
|
||||||
|
drop table t3;
|
||||||
|
drop table t0, t1, t2;
|
||||||
|
@ -56,8 +56,8 @@ a b
|
|||||||
4 Testing
|
4 Testing
|
||||||
5 table
|
5 table
|
||||||
5 table
|
5 table
|
||||||
6 t1
|
|
||||||
6 t2
|
6 t2
|
||||||
|
6 t1
|
||||||
7 Testing
|
7 Testing
|
||||||
7 Testing
|
7 Testing
|
||||||
8 table
|
8 table
|
||||||
|
@ -859,6 +859,20 @@ count(*)
|
|||||||
5
|
5
|
||||||
deallocate prepare stmt;
|
deallocate prepare stmt;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
prepare stmt from 'create table t1 (a varchar(10) character set utf8)';
|
||||||
|
execute stmt;
|
||||||
|
insert into t1 (a) values (repeat('a', 20));
|
||||||
|
select length(a) from t1;
|
||||||
|
length(a)
|
||||||
|
10
|
||||||
|
drop table t1;
|
||||||
|
execute stmt;
|
||||||
|
insert into t1 (a) values (repeat('a', 20));
|
||||||
|
select length(a) from t1;
|
||||||
|
length(a)
|
||||||
|
10
|
||||||
|
drop table t1;
|
||||||
|
deallocate prepare stmt;
|
||||||
create table t1 (id int);
|
create table t1 (id int);
|
||||||
prepare ins_call from "insert into t1 (id) values (1)";
|
prepare ins_call from "insert into t1 (id) values (1)";
|
||||||
execute ins_call;
|
execute ins_call;
|
||||||
|
@ -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 view if exists v1;
|
||||||
drop database if exists mysqltest;
|
drop database if exists mysqltest;
|
||||||
drop function if exists f1;
|
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
|
ERROR 3D000: No database selected
|
||||||
drop trigger t1_bi;
|
drop trigger t1_bi;
|
||||||
ERROR 3D000: No database selected
|
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 table t1 (i int);
|
||||||
create trigger t1_bi before insert on t1 for each row return 0;
|
create trigger t1_bi before insert on t1 for each row return 0;
|
||||||
ERROR 42000: RETURN is only allowed in a FUNCTION
|
ERROR 42000: RETURN is only allowed in a FUNCTION
|
||||||
|
@ -2529,3 +2529,13 @@ Warnings:
|
|||||||
Warning 1052 Column 'x' in group statement is ambiguous
|
Warning 1052 Column 'x' in group statement is ambiguous
|
||||||
DROP VIEW v1;
|
DROP VIEW v1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
drop table if exists t1;
|
||||||
|
drop view if exists v1;
|
||||||
|
create table t1 (id int);
|
||||||
|
create view v1 as select * from t1;
|
||||||
|
drop table t1;
|
||||||
|
show create view v1;
|
||||||
|
drop view v1;
|
||||||
|
//
|
||||||
|
View Create View
|
||||||
|
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select sql_no_cache `test`.`t1`.`id` AS `id` from `t1`
|
||||||
|
@ -357,3 +357,29 @@ explain select * from t1 WHERE cola = 'foo' AND colb = 'bar';
|
|||||||
explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar';
|
explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar';
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUG#17314: Index_merge/intersection not choosen by the optimizer for MERGE tables
|
||||||
|
#
|
||||||
|
create table t0 (a int);
|
||||||
|
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||||
|
create table t1 (
|
||||||
|
a int, b int,
|
||||||
|
filler1 char(200), filler2 char(200),
|
||||||
|
key(a),key(b)
|
||||||
|
);
|
||||||
|
insert into t1 select @v:= A.a, @v, 't1', 'filler2' from t0 A, t0 B, t0 C;
|
||||||
|
create table t2 like t1;
|
||||||
|
|
||||||
|
create table t3 (
|
||||||
|
a int, b int,
|
||||||
|
filler1 char(200), filler2 char(200),
|
||||||
|
key(a),key(b)
|
||||||
|
) engine=merge union=(t1,t2);
|
||||||
|
|
||||||
|
--replace_column 9 #
|
||||||
|
explain select * from t1 where a=1 and b=1;
|
||||||
|
--replace_column 9 #
|
||||||
|
explain select * from t3 where a=1 and b=1;
|
||||||
|
|
||||||
|
drop table t3;
|
||||||
|
drop table t0, t1, t2;
|
||||||
|
@ -900,6 +900,27 @@ execute stmt using @like;
|
|||||||
deallocate prepare stmt;
|
deallocate prepare stmt;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug#13134 "Length of VARCHAR() utf8 column is increasing when table is
|
||||||
|
# recreated with PS/SP"
|
||||||
|
#
|
||||||
|
|
||||||
|
prepare stmt from 'create table t1 (a varchar(10) character set utf8)';
|
||||||
|
execute stmt;
|
||||||
|
--disable_warnings
|
||||||
|
insert into t1 (a) values (repeat('a', 20));
|
||||||
|
--enable_warnings
|
||||||
|
select length(a) from t1;
|
||||||
|
drop table t1;
|
||||||
|
execute stmt;
|
||||||
|
--disable_warnings
|
||||||
|
insert into t1 (a) values (repeat('a', 20));
|
||||||
|
--enable_warnings
|
||||||
|
# Check that the data is truncated to the same length
|
||||||
|
select length(a) from t1;
|
||||||
|
drop table t1;
|
||||||
|
deallocate prepare stmt;
|
||||||
|
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
--disable_warnings
|
--disable_warnings
|
||||||
drop table if exists t1, t2, t3;
|
drop table if exists t1, t2, t3, t4;
|
||||||
drop view if exists v1;
|
drop view if exists v1;
|
||||||
drop database if exists mysqltest;
|
drop database if exists mysqltest;
|
||||||
drop function if exists f1;
|
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;
|
drop trigger t1_bi;
|
||||||
connection default;
|
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"
|
# Test for bug #16829 "Firing trigger with RETURN crashes the server"
|
||||||
# RETURN is not supposed to be used anywhere except functions, so error
|
# RETURN is not supposed to be used anywhere except functions, so error
|
||||||
# should be returned when one attempts to create trigger with RETURN.
|
# should be returned when one attempts to create trigger with RETURN.
|
||||||
|
@ -2375,3 +2375,18 @@ SELECT IF(x IS NULL, 'blank', 'not blank') AS x FROM v1 GROUP BY x;
|
|||||||
|
|
||||||
DROP VIEW v1;
|
DROP VIEW v1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUG#15943: mysql_next_result hangs on invalid SHOW CREATE VIEW
|
||||||
|
#
|
||||||
|
|
||||||
|
delimiter //;
|
||||||
|
drop table if exists t1;
|
||||||
|
drop view if exists v1;
|
||||||
|
create table t1 (id int);
|
||||||
|
create view v1 as select * from t1;
|
||||||
|
drop table t1;
|
||||||
|
show create view v1;
|
||||||
|
drop view v1;
|
||||||
|
//
|
||||||
|
delimiter ;//
|
||||||
|
@ -8297,13 +8297,11 @@ void Field_bit_as_char::sql_type(String &res) const
|
|||||||
create_field::create_length_to_internal_length()
|
create_field::create_length_to_internal_length()
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
Convert create_field::length from number of characters to number of bytes,
|
Convert create_field::length from number of characters to number of bytes.
|
||||||
save original value in chars_length.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void create_field::create_length_to_internal_length(void)
|
void create_field::create_length_to_internal_length(void)
|
||||||
{
|
{
|
||||||
chars_length= length;
|
|
||||||
switch (sql_type) {
|
switch (sql_type) {
|
||||||
case MYSQL_TYPE_TINY_BLOB:
|
case MYSQL_TYPE_TINY_BLOB:
|
||||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||||
@ -8355,7 +8353,7 @@ void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
|
|||||||
{
|
{
|
||||||
field_name= "";
|
field_name= "";
|
||||||
sql_type= sql_type_arg;
|
sql_type= sql_type_arg;
|
||||||
length= length_arg;;
|
char_length= length= length_arg;;
|
||||||
unireg_check= Field::NONE;
|
unireg_check= Field::NONE;
|
||||||
interval= 0;
|
interval= 0;
|
||||||
charset= &my_charset_bin;
|
charset= &my_charset_bin;
|
||||||
@ -8683,6 +8681,8 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
|
|||||||
case FIELD_TYPE_DECIMAL:
|
case FIELD_TYPE_DECIMAL:
|
||||||
DBUG_ASSERT(0); /* Was obsolete */
|
DBUG_ASSERT(0); /* Was obsolete */
|
||||||
}
|
}
|
||||||
|
/* Remember the value of length */
|
||||||
|
char_length= length;
|
||||||
|
|
||||||
if (!(flags & BLOB_FLAG) &&
|
if (!(flags & BLOB_FLAG) &&
|
||||||
((length > max_field_charlength && fld_type != FIELD_TYPE_SET &&
|
((length > max_field_charlength && fld_type != FIELD_TYPE_SET &&
|
||||||
@ -9023,6 +9023,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
|
|||||||
else
|
else
|
||||||
interval=0;
|
interval=0;
|
||||||
def=0;
|
def=0;
|
||||||
|
char_length= length;
|
||||||
|
|
||||||
if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
|
if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
|
||||||
old_field->ptr && orig_field &&
|
old_field->ptr && orig_field &&
|
||||||
|
@ -1410,9 +1410,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
ulong length;
|
ulong length;
|
||||||
/*
|
/*
|
||||||
The value of 'length' before a call to create_length_to_internal_length
|
The value of `length' as set by parser: is the number of characters
|
||||||
|
for most of the types, or of bytes for BLOBs or numeric types.
|
||||||
*/
|
*/
|
||||||
uint32 chars_length;
|
uint32 char_length;
|
||||||
uint decimals, flags, pack_length, key_length;
|
uint decimals, flags, pack_length, key_length;
|
||||||
Field::utype unireg_check;
|
Field::utype unireg_check;
|
||||||
TYPELIB *interval; // Which interval to use
|
TYPELIB *interval; // Which interval to use
|
||||||
|
@ -308,7 +308,27 @@ void ha_myisammrg::info(uint flag)
|
|||||||
table->s->keys_in_use.set_prefix(table->s->keys);
|
table->s->keys_in_use.set_prefix(table->s->keys);
|
||||||
table->s->db_options_in_use= info.options;
|
table->s->db_options_in_use= info.options;
|
||||||
mean_rec_length= info.reclength;
|
mean_rec_length= info.reclength;
|
||||||
block_size=0;
|
|
||||||
|
/*
|
||||||
|
The handler::block_size is used all over the code in index scan cost
|
||||||
|
calculations. It is used to get number of disk seeks required to
|
||||||
|
retrieve a number of index tuples.
|
||||||
|
If the merge table has N underlying tables, then (assuming underlying
|
||||||
|
tables have equal size, the only "simple" approach we can use)
|
||||||
|
retrieving X index records from a merge table will require N times more
|
||||||
|
disk seeks compared to doing the same on a MyISAM table with equal
|
||||||
|
number of records.
|
||||||
|
In the edge case (file_tables > myisam_block_size) we'll get
|
||||||
|
block_size==0, and index calculation code will act as if we need one
|
||||||
|
disk seek to retrieve one index tuple.
|
||||||
|
|
||||||
|
TODO: In 5.2 index scan cost calculation will be factored out into a
|
||||||
|
virtual function in class handler and we'll be able to remove this hack.
|
||||||
|
*/
|
||||||
|
block_size= 0;
|
||||||
|
if (file->tables)
|
||||||
|
block_size= myisam_block_size / file->tables;
|
||||||
|
|
||||||
update_time=0;
|
update_time=0;
|
||||||
#if SIZEOF_OFF_T > 4
|
#if SIZEOF_OFF_T > 4
|
||||||
ref_length=6; // Should be big enough
|
ref_length=6; // Should be big enough
|
||||||
|
@ -4416,7 +4416,6 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
|
|||||||
{
|
{
|
||||||
Field_iterator_table_ref it_1, it_2;
|
Field_iterator_table_ref it_1, it_2;
|
||||||
Natural_join_column *nj_col_1, *nj_col_2;
|
Natural_join_column *nj_col_1, *nj_col_2;
|
||||||
const char *field_name_1;
|
|
||||||
Query_arena *arena, backup;
|
Query_arena *arena, backup;
|
||||||
bool add_columns= TRUE;
|
bool add_columns= TRUE;
|
||||||
bool result= TRUE;
|
bool result= TRUE;
|
||||||
@ -4449,6 +4448,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
|
|||||||
{
|
{
|
||||||
bool is_created_1;
|
bool is_created_1;
|
||||||
bool found= FALSE;
|
bool found= FALSE;
|
||||||
|
const char *field_name_1;
|
||||||
if (!(nj_col_1= it_1.get_or_create_column_ref(&is_created_1)))
|
if (!(nj_col_1= it_1.get_or_create_column_ref(&is_created_1)))
|
||||||
goto err;
|
goto err;
|
||||||
field_name_1= nj_col_1->name();
|
field_name_1= nj_col_1->name();
|
||||||
@ -4649,7 +4649,6 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
|
|||||||
{
|
{
|
||||||
Field_iterator_table_ref it_1, it_2;
|
Field_iterator_table_ref it_1, it_2;
|
||||||
Natural_join_column *nj_col_1, *nj_col_2;
|
Natural_join_column *nj_col_1, *nj_col_2;
|
||||||
bool is_created;
|
|
||||||
Query_arena *arena, backup;
|
Query_arena *arena, backup;
|
||||||
bool result= TRUE;
|
bool result= TRUE;
|
||||||
List<Natural_join_column> *non_join_columns;
|
List<Natural_join_column> *non_join_columns;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
|
#include "sql_trigger.h"
|
||||||
|
|
||||||
|
|
||||||
static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list,
|
static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list,
|
||||||
@ -173,9 +174,30 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
|
|||||||
if (table_type == DB_TYPE_UNKNOWN)
|
if (table_type == DB_TYPE_UNKNOWN)
|
||||||
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
||||||
else
|
else
|
||||||
rc= mysql_rename_table(ha_resolve_by_legacy_type(thd, table_type),
|
{
|
||||||
ren_table->db, old_alias,
|
if (!(rc= mysql_rename_table(ha_resolve_by_legacy_type(thd,
|
||||||
new_table->db, new_alias);
|
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(ha_resolve_by_legacy_type(thd,
|
||||||
|
table_type),
|
||||||
|
new_table->db, new_alias,
|
||||||
|
ren_table->db, old_alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FRMTYPE_VIEW:
|
case FRMTYPE_VIEW:
|
||||||
|
@ -176,7 +176,9 @@ typedef struct st_rollup
|
|||||||
|
|
||||||
class JOIN :public Sql_alloc
|
class JOIN :public Sql_alloc
|
||||||
{
|
{
|
||||||
public:
|
JOIN(const JOIN &rhs); /* not implemented */
|
||||||
|
JOIN& operator=(const JOIN &rhs); /* not implemented */
|
||||||
|
public:
|
||||||
JOIN_TAB *join_tab,**best_ref;
|
JOIN_TAB *join_tab,**best_ref;
|
||||||
JOIN_TAB **map2table; // mapping between table indexes and JOIN_TABs
|
JOIN_TAB **map2table; // mapping between table indexes and JOIN_TABs
|
||||||
JOIN_TAB *join_tab_save; // saved join_tab for subquery reexecution
|
JOIN_TAB *join_tab_save; // saved join_tab for subquery reexecution
|
||||||
@ -288,13 +290,6 @@ class JOIN :public Sql_alloc
|
|||||||
init(thd_arg, fields_arg, select_options_arg, result_arg);
|
init(thd_arg, fields_arg, select_options_arg, result_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
JOIN(JOIN &join)
|
|
||||||
:Sql_alloc(), fields_list(join.fields_list)
|
|
||||||
{
|
|
||||||
init(join.thd, join.fields_list, join.select_options,
|
|
||||||
join.result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
|
void init(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
|
||||||
select_result *result_arg)
|
select_result *result_arg)
|
||||||
{
|
{
|
||||||
|
@ -513,12 +513,15 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
|||||||
{
|
{
|
||||||
if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID)
|
if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID)
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Clear all messages with 'error' level status and
|
Clear all messages with 'error' level status and
|
||||||
issue a warning with 'warning' level status in
|
issue a warning with 'warning' level status in
|
||||||
case of invalid view and last error is ER_VIEW_INVALID
|
case of invalid view and last error is ER_VIEW_INVALID
|
||||||
*/
|
*/
|
||||||
mysql_reset_errors(thd, true);
|
mysql_reset_errors(thd, true);
|
||||||
|
thd->clear_error();
|
||||||
|
|
||||||
push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
|
push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||||
ER_VIEW_INVALID,
|
ER_VIEW_INVALID,
|
||||||
ER(ER_VIEW_INVALID),
|
ER(ER_VIEW_INVALID),
|
||||||
|
@ -1127,6 +1127,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
|||||||
{
|
{
|
||||||
CHARSET_INFO *save_cs;
|
CHARSET_INFO *save_cs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialize length from its original value (number of characters),
|
||||||
|
which was set in the parser. This is necessary if we're
|
||||||
|
executing a prepared statement for the second time.
|
||||||
|
*/
|
||||||
|
sql_field->length= sql_field->char_length;
|
||||||
if (!sql_field->charset)
|
if (!sql_field->charset)
|
||||||
sql_field->charset= create_info->default_table_charset;
|
sql_field->charset= create_info->default_table_charset;
|
||||||
/*
|
/*
|
||||||
@ -1311,7 +1317,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
|||||||
sql_field->charset= (dup_field->charset ?
|
sql_field->charset= (dup_field->charset ?
|
||||||
dup_field->charset :
|
dup_field->charset :
|
||||||
create_info->default_table_charset);
|
create_info->default_table_charset);
|
||||||
sql_field->length= dup_field->chars_length;
|
sql_field->length= dup_field->char_length;
|
||||||
sql_field->pack_length= dup_field->pack_length;
|
sql_field->pack_length= dup_field->pack_length;
|
||||||
sql_field->key_length= dup_field->key_length;
|
sql_field->key_length= dup_field->key_length;
|
||||||
sql_field->create_length_to_internal_length();
|
sql_field->create_length_to_internal_length();
|
||||||
@ -4031,6 +4037,13 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||||||
close_cached_table(thd, table);
|
close_cached_table(thd, table);
|
||||||
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias))
|
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias))
|
||||||
error= -1;
|
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));
|
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||||
}
|
}
|
||||||
@ -4933,7 +4946,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||||||
VOID(quick_rm_table(new_db_type,new_db,tmp_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,
|
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
|
{ // Try to get everything back
|
||||||
error=1;
|
error=1;
|
||||||
VOID(quick_rm_table(new_db_type,new_db,new_alias));
|
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_NUM_REQUIRED_PARAMETERS= 4;
|
||||||
static const int TRG_MAX_VERSIONS= 3;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Structure representing contents of .TRN file which are used to support
|
Structure representing contents of .TRN file which are used to support
|
||||||
@ -318,8 +317,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
|
|||||||
{
|
{
|
||||||
LEX *lex= thd->lex;
|
LEX *lex= thd->lex;
|
||||||
TABLE *table= tables->table;
|
TABLE *table= tables->table;
|
||||||
char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN],
|
char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN];
|
||||||
trigname_path[FN_REFLEN];
|
|
||||||
LEX_STRING file, trigname_file;
|
LEX_STRING file, trigname_file;
|
||||||
LEX_STRING *trg_def, *name;
|
LEX_STRING *trg_def, *name;
|
||||||
ulonglong *trg_sql_mode;
|
ulonglong *trg_sql_mode;
|
||||||
@ -472,12 +470,11 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
|
|||||||
definer_host->str, NullS) - trg_definer->str;
|
definer_host->str, NullS) - trg_definer->str;
|
||||||
|
|
||||||
if (!sql_create_definition_file(NULL, &file, &triggers_file_type,
|
if (!sql_create_definition_file(NULL, &file, &triggers_file_type,
|
||||||
(gptr)this, triggers_file_parameters,
|
(gptr)this, triggers_file_parameters, 0))
|
||||||
TRG_MAX_VERSIONS))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_with_cleanup:
|
err_with_cleanup:
|
||||||
my_delete(trigname_path, MYF(MY_WME));
|
my_delete(trigname_buff, MYF(MY_WME));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,7 +494,8 @@ err_with_cleanup:
|
|||||||
True - error
|
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)
|
||||||
{
|
{
|
||||||
build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext);
|
build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext);
|
||||||
return my_delete(path, MYF(MY_WME));
|
return my_delete(path, MYF(MY_WME));
|
||||||
@ -519,13 +517,43 @@ static bool rm_trigger_file(char *path, char *db, char *table_name)
|
|||||||
True - error
|
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)
|
||||||
{
|
{
|
||||||
build_table_filename(path, FN_REFLEN-1, db, trigger_name, trigname_file_ext);
|
build_table_filename(path, FN_REFLEN-1, db, trigger_name, trigname_file_ext);
|
||||||
return my_delete(path, MYF(MY_WME));
|
return my_delete(path, MYF(MY_WME));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 file_buff[FN_REFLEN];
|
||||||
|
LEX_STRING file;
|
||||||
|
|
||||||
|
file.length= build_table_filename(file_buff, FN_REFLEN-1, db, table_name,
|
||||||
|
triggers_file_ext);
|
||||||
|
file.str= file_buff;
|
||||||
|
return sql_create_definition_file(NULL, &file, &triggers_file_type,
|
||||||
|
(gptr)triggers, triggers_file_parameters,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Drop trigger for table.
|
Drop trigger for table.
|
||||||
|
|
||||||
@ -579,16 +607,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char file_buff[FN_REFLEN];
|
if (save_trigger_file(this, tables->db, tables->table_name))
|
||||||
LEX_STRING file;
|
|
||||||
|
|
||||||
file.length= build_table_filename(file_buff, FN_REFLEN-1,
|
|
||||||
tables->db, tables->table_name,
|
|
||||||
triggers_file_ext);
|
|
||||||
file.str= file_buff;
|
|
||||||
if (sql_create_definition_file(NULL, &file, &triggers_file_type,
|
|
||||||
(gptr)this, triggers_file_parameters,
|
|
||||||
TRG_MAX_VERSIONS))
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -827,12 +846,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
if (!names_only && triggers->prepare_record1_accessors(table))
|
if (!names_only && triggers->prepare_record1_accessors(table))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
char *trg_name_buff;
|
|
||||||
List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
|
List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
|
||||||
List_iterator_fast<LEX_STRING> it_definer(triggers->definers_list);
|
List_iterator_fast<LEX_STRING> it_definer(triggers->definers_list);
|
||||||
LEX *old_lex= thd->lex, lex;
|
LEX *old_lex= thd->lex, lex;
|
||||||
sp_rcontext *save_spcont= thd->spcont;
|
sp_rcontext *save_spcont= thd->spcont;
|
||||||
ulong save_sql_mode= thd->variables.sql_mode;
|
ulong save_sql_mode= thd->variables.sql_mode;
|
||||||
|
LEX_STRING *on_table_name;
|
||||||
|
|
||||||
thd->lex= &lex;
|
thd->lex= &lex;
|
||||||
|
|
||||||
@ -898,6 +917,21 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
&table->mem_root))
|
&table->mem_root))
|
||||||
goto err_with_lex_cleanup;
|
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)
|
if (names_only)
|
||||||
{
|
{
|
||||||
lex_end(&lex);
|
lex_end(&lex);
|
||||||
@ -1063,7 +1097,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
|
|||||||
lex->query_tables= 0;
|
lex->query_tables= 0;
|
||||||
lex->query_tables_last= &lex->query_tables;
|
lex->query_tables_last= &lex->query_tables;
|
||||||
DBUG_RETURN(sp_add_to_query_tables(thd, lex, trig->m_db.str,
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1133,6 +1167,218 @@ 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 trigname_buff[FN_REFLEN];
|
||||||
|
struct st_trigname trigname;
|
||||||
|
LEX_STRING trigname_file;
|
||||||
|
LEX_STRING *trigger;
|
||||||
|
List_iterator_fast<LEX_STRING> it_name(names_list);
|
||||||
|
|
||||||
|
while ((trigger= it_name++) != stopper)
|
||||||
|
{
|
||||||
|
trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1,
|
||||||
|
db_name, trigger->str,
|
||||||
|
trigname_file_ext);
|
||||||
|
trigname_file.str= trigname_buff;
|
||||||
|
|
||||||
|
trigname.trigger_table= *new_table_name;
|
||||||
|
|
||||||
|
if (sql_create_definition_file(NULL, &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,
|
bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
||||||
trg_action_time_type time_type,
|
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.
|
used in CREATE/DROP TRIGGER for looking up trigger by name.
|
||||||
*/
|
*/
|
||||||
List<LEX_STRING> names_list;
|
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
|
Key representing triggers for this table in set of all stored
|
||||||
routines used by statement.
|
routines used by statement.
|
||||||
@ -97,7 +102,10 @@ public:
|
|||||||
static bool check_n_load(THD *thd, const char *db, const char *table_name,
|
static bool check_n_load(THD *thd, const char *db, const char *table_name,
|
||||||
TABLE *table, bool names_only);
|
TABLE *table, bool names_only);
|
||||||
static bool drop_all_triggers(THD *thd, char *db, char *table_name);
|
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()
|
bool has_delete_triggers()
|
||||||
{
|
{
|
||||||
return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
|
return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
|
||||||
@ -117,6 +125,13 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool prepare_record1_accessors(TABLE *table);
|
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[];
|
extern const LEX_STRING trg_action_time_type_names[];
|
||||||
|
@ -10931,7 +10931,7 @@ view_check_option:
|
|||||||
|
|
||||||
trigger_tail:
|
trigger_tail:
|
||||||
TRIGGER_SYM remember_name sp_name trg_action_time trg_event
|
TRIGGER_SYM remember_name sp_name trg_action_time trg_event
|
||||||
ON table_ident FOR_SYM EACH_SYM ROW_SYM
|
ON remember_name table_ident remember_end FOR_SYM EACH_SYM ROW_SYM
|
||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_head *sp;
|
sp_head *sp;
|
||||||
@ -10948,6 +10948,8 @@ trigger_tail:
|
|||||||
sp->init(lex);
|
sp->init(lex);
|
||||||
|
|
||||||
lex->trigger_definition_begin= $2;
|
lex->trigger_definition_begin= $2;
|
||||||
|
lex->ident.str= $7;
|
||||||
|
lex->ident.length= $9 - $7;
|
||||||
|
|
||||||
sp->m_type= TYPE_ENUM_TRIGGER;
|
sp->m_type= TYPE_ENUM_TRIGGER;
|
||||||
lex->sphead= sp;
|
lex->sphead= sp;
|
||||||
@ -10975,7 +10977,7 @@ trigger_tail:
|
|||||||
sp->init_strings(YYTHD, lex, $3);
|
sp->init_strings(YYTHD, lex, $3);
|
||||||
/* Restore flag if it was cleared above */
|
/* Restore flag if it was cleared above */
|
||||||
|
|
||||||
YYTHD->client_capabilities |= $<ulong_num>11;
|
YYTHD->client_capabilities |= $<ulong_num>13;
|
||||||
sp->restore_thd_mem_root(YYTHD);
|
sp->restore_thd_mem_root(YYTHD);
|
||||||
|
|
||||||
if (sp->is_not_allowed_in_function("trigger"))
|
if (sp->is_not_allowed_in_function("trigger"))
|
||||||
@ -10985,15 +10987,11 @@ trigger_tail:
|
|||||||
We have to do it after parsing trigger body, because some of
|
We have to do it after parsing trigger body, because some of
|
||||||
sp_proc_stmt alternatives are not saving/restoring LEX, so
|
sp_proc_stmt alternatives are not saving/restoring LEX, so
|
||||||
lex->query_tables can be wiped out.
|
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,
|
(LEX_STRING*) 0,
|
||||||
TL_OPTION_UPDATING,
|
TL_OPTION_UPDATING,
|
||||||
TL_WRITE))
|
TL_IGNORE))
|
||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -18,12 +18,26 @@
|
|||||||
|
|
||||||
static int queue_key_cmp(void *keyseg, byte *a, byte *b)
|
static int queue_key_cmp(void *keyseg, byte *a, byte *b)
|
||||||
{
|
{
|
||||||
MI_INFO *aa=((MYRG_TABLE *)a)->table;
|
MYRG_TABLE *ma= (MYRG_TABLE *)a;
|
||||||
MI_INFO *bb=((MYRG_TABLE *)b)->table;
|
MYRG_TABLE *mb= (MYRG_TABLE *)b;
|
||||||
|
MI_INFO *aa= ma->table;
|
||||||
|
MI_INFO *bb= mb->table;
|
||||||
uint not_used[2];
|
uint not_used[2];
|
||||||
int ret= ha_key_cmp((HA_KEYSEG *)keyseg, aa->lastkey, bb->lastkey,
|
int ret= ha_key_cmp((HA_KEYSEG *)keyseg, aa->lastkey, bb->lastkey,
|
||||||
USE_WHOLE_KEY, SEARCH_FIND, not_used);
|
USE_WHOLE_KEY, SEARCH_FIND, not_used);
|
||||||
return ret < 0 ? -1 : ret > 0 ? 1 : 0;
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
if (ret > 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
If index tuples have the same values, let the record with least rowid
|
||||||
|
value be "smaller", so index scans return records ordered by (keytuple,
|
||||||
|
rowid). This is used by index_merge access method, grep for ROR in
|
||||||
|
sql/opt_range.cc for details.
|
||||||
|
*/
|
||||||
|
return (ma->file_offset < mb->file_offset)? -1 : (ma->file_offset >
|
||||||
|
mb->file_offset) ? 1 : 0;
|
||||||
} /* queue_key_cmp */
|
} /* queue_key_cmp */
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user