summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqltest.c6
-rw-r--r--include/my_global.h9
-rwxr-xr-xmysql-test/mysql-test-run.pl3
-rw-r--r--mysql-test/mysql-test-run.sh1
-rw-r--r--mysql-test/r/index_merge.result22
-rw-r--r--mysql-test/r/merge.result2
-rw-r--r--mysql-test/r/ps.result14
-rw-r--r--mysql-test/r/trigger.result103
-rw-r--r--mysql-test/r/view.result10
-rw-r--r--mysql-test/t/index_merge.test26
-rw-r--r--mysql-test/t/ps.test21
-rw-r--r--mysql-test/t/trigger.test87
-rw-r--r--mysql-test/t/view.test15
-rw-r--r--sql/field.cc9
-rw-r--r--sql/field.h5
-rw-r--r--sql/ha_myisammrg.cc22
-rw-r--r--sql/sql_base.cc3
-rw-r--r--sql/sql_rename.cc28
-rw-r--r--sql/sql_select.h11
-rw-r--r--sql/sql_show.cc3
-rw-r--r--sql/sql_table.cc21
-rw-r--r--sql/sql_trigger.cc286
-rw-r--r--sql/sql_trigger.h17
-rw-r--r--sql/sql_yacc.yy14
-rw-r--r--storage/myisammrg/myrg_queue.c20
25 files changed, 698 insertions, 60 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 1450ee95c19..5777afaba4c 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -3662,8 +3662,10 @@ DYNAMIC_ARRAY patterns;
static void init_win_path_patterns()
{
/* List of string patterns to match in order to find paths */
- const char* paths[] = { "$MYSQL_TEST_DIR", "./test/", 0 };
- int num_paths= 2;
+ const char* paths[] = { "$MYSQL_TEST_DIR",
+ "$MYSQL_TMP_DIR",
+ "./test/", 0 };
+ int num_paths= 3;
int i;
char* p;
diff --git a/include/my_global.h b/include/my_global.h
index 82b0585757c..56aeb84d9ba 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -43,6 +43,15 @@
#define HAVE_ERRNO_AS_DEFINE
#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 */
#ifdef USE_PRAGMA_IMPLEMENTATION
#define USE_PRAGMA_INTERFACE
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 10645fdf12e..62ce4da253e 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -1156,6 +1156,7 @@ sub environment_setup () {
$ENV{'USE_RUNNING_SERVER'}= $glob_use_running_server;
$ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir;
$ENV{'MYSQLTEST_VARDIR'}= $opt_vardir;
+ $ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir;
$ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_mysock'};
$ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_mysock'};
$ENV{'MASTER_MYPORT'}= $master->[0]->{'path_myport'};
@@ -2876,7 +2877,7 @@ sub run_mysqltest ($) {
if ( $opt_debug )
{
$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 " .
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index ce62964a3c0..7869a9f6f3a 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -202,6 +202,7 @@ SYST=0
REALT=0
FAST_START=""
MYSQL_TMP_DIR=$MYSQL_TEST_DIR/var/tmp
+export MYSQL_TMP_DIR
# Use a relative path for where the slave will find the dumps
# generated by "LOAD DATA" on the master. The path is relative
diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result
index db87253e19a..3a69f56cbd3 100644
--- a/mysql-test/r/index_merge.result
+++ b/mysql-test/r/index_merge.result
@@ -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
1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 24 Using intersect(cola,colb); Using where
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;
diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result
index c700de5ccc6..caab508ad96 100644
--- a/mysql-test/r/merge.result
+++ b/mysql-test/r/merge.result
@@ -56,8 +56,8 @@ a b
4 Testing
5 table
5 table
-6 t1
6 t2
+6 t1
7 Testing
7 Testing
8 table
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 5c0a13fe640..e24cee9e875 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -859,6 +859,20 @@ count(*)
5
deallocate prepare stmt;
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);
prepare ins_call from "insert into t1 (id) values (1)";
execute ins_call;
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 62c0d01327d..320f4e5c3d9 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/r/view.result b/mysql-test/r/view.result
index 5396db82965..e3d683a58dc 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -2529,3 +2529,13 @@ Warnings:
Warning 1052 Column 'x' in group statement is ambiguous
DROP VIEW v1;
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`
diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test
index 10512902409..3da5711bf7a 100644
--- a/mysql-test/t/index_merge.test
+++ b/mysql-test/t/index_merge.test
@@ -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';
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;
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index 48a9f4c19f3..ffbba991fb6 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -900,6 +900,27 @@ execute stmt using @like;
deallocate prepare stmt;
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
#
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/mysql-test/t/view.test b/mysql-test/t/view.test
index 5d1b5a80a9b..294a254390f 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -2375,3 +2375,18 @@ SELECT IF(x IS NULL, 'blank', 'not blank') AS x FROM v1 GROUP BY x;
DROP VIEW v1;
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 ;//
diff --git a/sql/field.cc b/sql/field.cc
index c2c41bc2ee9..65c0d1b9397 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -8297,13 +8297,11 @@ void Field_bit_as_char::sql_type(String &res) const
create_field::create_length_to_internal_length()
DESCRIPTION
- Convert create_field::length from number of characters to number of bytes,
- save original value in chars_length.
+ Convert create_field::length from number of characters to number of bytes.
*/
void create_field::create_length_to_internal_length(void)
{
- chars_length= length;
switch (sql_type) {
case MYSQL_TYPE_TINY_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= "";
sql_type= sql_type_arg;
- length= length_arg;;
+ char_length= length= length_arg;;
unireg_check= Field::NONE;
interval= 0;
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:
DBUG_ASSERT(0); /* Was obsolete */
}
+ /* Remember the value of length */
+ char_length= length;
if (!(flags & BLOB_FLAG) &&
((length > max_field_charlength && fld_type != FIELD_TYPE_SET &&
@@ -9023,6 +9023,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
else
interval=0;
def=0;
+ char_length= length;
if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
old_field->ptr && orig_field &&
diff --git a/sql/field.h b/sql/field.h
index 15c54f65ef7..ad8b34594b7 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1410,9 +1410,10 @@ public:
*/
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;
Field::utype unireg_check;
TYPELIB *interval; // Which interval to use
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index a24b32435a8..ec015c5e320 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -308,7 +308,27 @@ void ha_myisammrg::info(uint flag)
table->s->keys_in_use.set_prefix(table->s->keys);
table->s->db_options_in_use= info.options;
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;
#if SIZEOF_OFF_T > 4
ref_length=6; // Should be big enough
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 73f651cb1eb..2e96b369924 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -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;
Natural_join_column *nj_col_1, *nj_col_2;
- const char *field_name_1;
Query_arena *arena, backup;
bool add_columns= 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 found= FALSE;
+ const char *field_name_1;
if (!(nj_col_1= it_1.get_or_create_column_ref(&is_created_1)))
goto err;
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;
Natural_join_column *nj_col_1, *nj_col_2;
- bool is_created;
Query_arena *arena, backup;
bool result= TRUE;
List<Natural_join_column> *non_join_columns;
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 5f20442cc84..e3468b2b5cf 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,
@@ -173,9 +174,30 @@ 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(ha_resolve_by_legacy_type(thd, table_type),
- ren_table->db, old_alias,
- new_table->db, new_alias);
+ {
+ if (!(rc= mysql_rename_table(ha_resolve_by_legacy_type(thd,
+ 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;
}
case FRMTYPE_VIEW:
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 02ee672b66e..459d2ff89a8 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -176,7 +176,9 @@ typedef struct st_rollup
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 **map2table; // mapping between table indexes and JOIN_TABs
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);
}
- 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,
select_result *result_arg)
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 15176b0c301..19cf68e5789 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -513,12 +513,15 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID)
DBUG_RETURN(TRUE);
+
/*
Clear all messages with 'error' level status and
issue a warning with 'warning' level status in
case of invalid view and last error is ER_VIEW_INVALID
*/
mysql_reset_errors(thd, true);
+ thd->clear_error();
+
push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
ER_VIEW_INVALID,
ER(ER_VIEW_INVALID),
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 17482c4a463..757321b5ccf 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1127,6 +1127,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
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)
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 ?
dup_field->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->key_length= dup_field->key_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);
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));
}
@@ -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));
}
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 0198dba780d..e33dc52df8f 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
@@ -318,8 +317,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
{
LEX *lex= thd->lex;
TABLE *table= tables->table;
- char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN],
- trigname_path[FN_REFLEN];
+ char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN];
LEX_STRING file, trigname_file;
LEX_STRING *trg_def, *name;
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;
if (!sql_create_definition_file(NULL, &file, &triggers_file_type,
- (gptr)this, triggers_file_parameters,
- TRG_MAX_VERSIONS))
+ (gptr)this, triggers_file_parameters, 0))
return 0;
err_with_cleanup:
- my_delete(trigname_path, MYF(MY_WME));
+ my_delete(trigname_buff, MYF(MY_WME));
return 1;
}
@@ -497,7 +494,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)
{
build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext);
return my_delete(path, MYF(MY_WME));
@@ -519,7 +517,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)
{
build_table_filename(path, FN_REFLEN-1, db, trigger_name, trigname_file_ext);
return my_delete(path, MYF(MY_WME));
@@ -527,6 +526,35 @@ 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 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.
SYNOPSIS
@@ -579,16 +607,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
}
else
{
- char file_buff[FN_REFLEN];
- 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))
+ if (save_trigger_file(this, tables->db, tables->table_name))
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))
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;
@@ -898,6 +917,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);
@@ -1063,7 +1097,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));
}
@@ -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,
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 c2c9c710ec6..db5e72d1637 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -10931,7 +10931,7 @@ 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
+ ON remember_name table_ident remember_end FOR_SYM EACH_SYM ROW_SYM
{
LEX *lex= Lex;
sp_head *sp;
@@ -10948,6 +10948,8 @@ 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;
@@ -10975,7 +10977,7 @@ trigger_tail:
sp->init_strings(YYTHD, lex, $3);
/* 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);
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
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;
}
;
diff --git a/storage/myisammrg/myrg_queue.c b/storage/myisammrg/myrg_queue.c
index 7172b9f0e2a..2e600a526c0 100644
--- a/storage/myisammrg/myrg_queue.c
+++ b/storage/myisammrg/myrg_queue.c
@@ -18,12 +18,26 @@
static int queue_key_cmp(void *keyseg, byte *a, byte *b)
{
- MI_INFO *aa=((MYRG_TABLE *)a)->table;
- MI_INFO *bb=((MYRG_TABLE *)b)->table;
+ MYRG_TABLE *ma= (MYRG_TABLE *)a;
+ MYRG_TABLE *mb= (MYRG_TABLE *)b;
+ MI_INFO *aa= ma->table;
+ MI_INFO *bb= mb->table;
uint not_used[2];
int ret= ha_key_cmp((HA_KEYSEG *)keyseg, aa->lastkey, bb->lastkey,
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 */