From 9c23a442b257c0ddb9066930c7bf9b0aac6cacdd Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Fri, 13 Nov 2009 10:30:56 +0000 Subject: [PATCH 01/11] BUG#48738: Backport patch for Bug 34582 to 5.0 codebase. From BUG 34582 commit message: Issuing 'FLUSH LOGS' does not close and reopen indexfile. Instead a SEEK_SET is performed. This patch makes index file to be closed and reopened whenever a rotation happens (FLUSH LOGS is issued or binary log exceeds maximum configured size). --- .../r/binlog_delete_and_flush_index.result | 44 +++++ .../t/binlog_delete_and_flush_index.test | 176 ++++++++++++++++++ sql/log.cc | 10 +- 3 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 mysql-test/r/binlog_delete_and_flush_index.result create mode 100644 mysql-test/t/binlog_delete_and_flush_index.test diff --git a/mysql-test/r/binlog_delete_and_flush_index.result b/mysql-test/r/binlog_delete_and_flush_index.result new file mode 100644 index 00000000000..153900f3081 --- /dev/null +++ b/mysql-test/r/binlog_delete_and_flush_index.result @@ -0,0 +1,44 @@ +RESET MASTER; +CREATE TABLE t1 (a int); +### assertion: index file contains regular entries +SET @index=LOAD_FILE('MYSQLD_DATADIR/master-bin.index'); +master-bin.000001 + +### assertion: show original binlogs +show binary logs; +Log_name File_size +master-bin.000001 # +### assertion: binlog contents from regular entries +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a int) +FLUSH LOGS; +### assertion: index file contains renamed binlog and the new one +SET @index=LOAD_FILE('MYSQLD_DATADIR/master-bin.index'); +master-bin-b34582.000001 +master-bin.000002 + +### assertion: original binlog content still exists, despite we +### renamed and changed the index file +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin-b34582.000001 # Query # # use `test`; CREATE TABLE t1 (a int) +### assertion: user changed binlog index shows correct entries +show binary logs; +Log_name File_size +master-bin-b34582.000001 # +master-bin.000002 # +DROP TABLE t1; +### assertion: purging binlogs up to binlog created after instrumenting index file should work +PURGE BINARY LOGS TO 'master-bin.000002'; +### assertion: show binary logs should only contain latest binlog +show binary logs; +Log_name File_size +master-bin.000002 # +### assertion: assert that binlog files were indeed purged (using file_exists calls) +### assertion: assert that not purged binlog file exists +### assertion: show index file contents and these should match show binary logs issued above +SET @index=LOAD_FILE('MYSQLD_DATADIR/master-bin.index'); +master-bin.000002 + +RESET MASTER; diff --git a/mysql-test/t/binlog_delete_and_flush_index.test b/mysql-test/t/binlog_delete_and_flush_index.test new file mode 100644 index 00000000000..6784043386d --- /dev/null +++ b/mysql-test/t/binlog_delete_and_flush_index.test @@ -0,0 +1,176 @@ +# BUG#34582: FLUSH LOGS does not close and reopen the binlog index +# file +# +# WHAT +# ==== +# +# We want to test that FLUSH LOGS closes and reopens binlog index +# file. +# +# HOW +# === +# +# PREPARE: +# 1. create some binlog events +# 2. show index content, binlog events and binlog contents +# for mysql-bin.000001 +# 3. copy the mysql-bin.000001 to mysql-bin-b34582.000001 +# 4. change the index file so that mysql-bin.000001 is replaced +# with mysql-bin-b34582.000001 +# 5. FLUSH the logs so that new index is closed and reopened +# +# ASSERTIONS: +# 1. index file contents shows mysql-bin-b34582.000001 and +# mysql-bin.000002 +# 1. show binary logs shows current index entries +# 2. binlog contents for mysql-bin-b34582.000001 are displayed +# 3. Purge binlogs up to the latest one succeeds +# 4. SHOW BINARY LOGS presents the latest one only after purging +# 5. Purged binlogs files don't exist in the filesystem +# 6. Not purged binlog file exists in the filesystem +# +# CLEAN UP: +# 1. RESET MASTER +# + +-- source include/have_log_bin.inc + +RESET MASTER; + +-- let $datadir= $MYSQLTEST_VARDIR/log +-- let $index=$datadir/master-bin.index +-- chmod 0666 $index + +# action: issue one command so that binlog gets some event +CREATE TABLE t1 (a int); + +-- echo ### assertion: index file contains regular entries +-- replace_regex /[\\\/].*master/MYSQLD_DATADIR\/master/ +-- eval SET @index=LOAD_FILE('$index') +if (`SELECT convert(@@version_compile_os using latin1) + IN ('Win32','Win64','Windows')`) +{ + -- disable_query_log + -- disable_result_log + -- let $a= `SELECT REPLACE (@index, '$datadir\', '')` + -- enable_result_log + -- enable_query_log + + -- echo $a + +} +if (!`SELECT convert(@@version_compile_os using latin1) + IN ('Win32','Win64','Windows')`) +{ + -- disable_query_log + -- disable_result_log + -- let $a= `SELECT REPLACE (@index, '$datadir/', '')` + -- enable_result_log + -- enable_query_log + + -- echo $a +} + +--echo ### assertion: show original binlogs +-- source include/show_binary_logs.inc + +--echo ### assertion: binlog contents from regular entries +-- source include/show_binlog_events.inc + +# action: copy binlogs to other names and change entries in index file +-- copy_file $datadir/master-bin.000001 $datadir/master-bin-b34582.000001 +-- let newbinfile=$datadir/master-bin-b34582.000001 +let INDEX_FILE=$index; +perl; +$newbinfile= $ENV{'newbinfile'}; +$file= $ENV{'INDEX_FILE'}; +open(FILE, ">$file") || die "Unable to open $file."; +truncate(FILE,0); +print FILE $newbinfile . "\n"; +close ($file); +EOF + +# action: should cause rotation, and creation of new binlogs +FLUSH LOGS; + +# file is not used anymore - remove it (mysql closed on flush logs). +-- remove_file $datadir/master-bin.000001 + +-- echo ### assertion: index file contains renamed binlog and the new one +-- replace_regex /[\\\/].*master/MYSQLD_DATADIR\/master/ +-- eval SET @index=LOAD_FILE('$index') +if (`SELECT convert(@@version_compile_os using latin1) + IN ('Win32','Win64','Windows')`) +{ + -- disable_query_log + -- disable_result_log + -- let $a= `SELECT REPLACE (@index, '$datadir\', '')` + -- enable_result_log + -- enable_query_log + + -- echo $a + +} +if (!`SELECT convert(@@version_compile_os using latin1) + IN ('Win32','Win64','Windows')`) +{ + -- disable_query_log + -- disable_result_log + -- let $a= `SELECT REPLACE (@index, '$datadir/', '')` + -- enable_result_log + -- enable_query_log + + -- echo $a +} + +-- echo ### assertion: original binlog content still exists, despite we +-- echo ### renamed and changed the index file +-- source include/show_binlog_events.inc + +-- echo ### assertion: user changed binlog index shows correct entries +-- source include/show_binary_logs.inc + +DROP TABLE t1; + +-- echo ### assertion: purging binlogs up to binlog created after instrumenting index file should work +-- let $current_binlog= query_get_value(SHOW MASTER STATUS, File, 1) +-- eval PURGE BINARY LOGS TO '$current_binlog' + +-- echo ### assertion: show binary logs should only contain latest binlog +-- source include/show_binary_logs.inc + +-- echo ### assertion: assert that binlog files were indeed purged (using file_exists calls) +-- error 1 +-- file_exists $datadir/master-bin-b34852.000001 + +-- echo ### assertion: assert that not purged binlog file exists +-- file_exists $datadir/$current_binlog + +-- echo ### assertion: show index file contents and these should match show binary logs issued above +-- replace_regex /[\\\/].*master/MYSQLD_DATADIR\/master/ +-- eval SET @index=LOAD_FILE('$index') +if (`SELECT convert(@@version_compile_os using latin1) + IN ('Win32','Win64','Windows')`) +{ + -- disable_query_log + -- disable_result_log + -- let $a= `SELECT REPLACE (@index, '$datadir\', '')` + -- enable_result_log + -- enable_query_log + + -- echo $a + +} +if (!`SELECT convert(@@version_compile_os using latin1) + IN ('Win32','Win64','Windows')`) +{ + -- disable_query_log + -- disable_result_log + -- let $a= `SELECT REPLACE (@index, '$datadir/', '')` + -- enable_result_log + -- enable_query_log + + -- echo $a +} + +RESET MASTER; diff --git a/sql/log.cc b/sql/log.cc index c042651216c..8c0abaeff44 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1635,7 +1635,7 @@ void MYSQL_LOG::new_file(bool need_lock) old_name=name; save_log_type=log_type; name=0; // Don't free name - close(LOG_CLOSE_TO_BE_OPENED); + close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX); /* Note that at this point, log_type != LOG_CLOSED (important for is_open()). @@ -1649,9 +1649,11 @@ void MYSQL_LOG::new_file(bool need_lock) Format_description_log_event written at server startup, which should trigger temp tables deletion on slaves. */ - - open(old_name, save_log_type, new_name_ptr, - io_cache_type, no_auto_events, max_size, 1); + + /* reopen index binlog file, BUG#34582 */ + if (!open_index_file(index_file_name, 0)) + open(old_name, save_log_type, new_name_ptr, + io_cache_type, no_auto_events, max_size, 1); my_free(old_name,MYF(0)); end: From 87349334004e7f3ae3beeb347661ffba18df3e38 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 17 Nov 2009 20:02:16 +0100 Subject: [PATCH 02/11] Bug#48846: Too much time spent in ha_partition::records_in_range if not able to prune Problem was that ha_partition::records_in_range called records_in_range for all non pruned partitions, even if an estimate should be given. Solution is to only use 1/3 of the partitions (up to 10) for records_in_range and estimate the total from this subset. (And continue until a non zero return value from the called partitions records_in_range is given, since 0 means no rows will match.) sql/ha_partition.cc: Bug#48846: Too much time spent in ha_partition::records_in_range if not able to prune estimate_rows_upper_bound and records_in_range are very similar (the only difference is the function and its parameters to use) so I created a common function for this. Since these calls from the optimizer are only estimates, it is not neccesary to call them for every partition, it can use a much smaller subset of the used partitions instead, which improves performance for selects. sql/ha_partition.h: Bug#48846: Too much time spent in ha_partition::records_in_range if not able to prune Added two private functions to help some optimizer calls. --- sql/ha_partition.cc | 144 ++++++++++++++++++++++++++++---------------- sql/ha_partition.h | 12 ++++ 2 files changed, 105 insertions(+), 51 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 451631ff373..b854e270029 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5747,6 +5747,23 @@ const key_map *ha_partition::keys_to_use_for_scanning() DBUG_RETURN(m_file[0]->keys_to_use_for_scanning()); } +#define MAX_PARTS_FOR_OPTIMIZER_CALLS 10 +/* + Prepare start variables for estimating optimizer costs. + + @param[out] num_used_parts Number of partitions after pruning. + @param[out] check_min_num Number of partitions to call. + @param[out] first first used partition. +*/ +void ha_partition::partitions_optimizer_call_preparations(uint *first, + uint *num_used_parts, + uint *check_min_num) +{ + *first= bitmap_get_first_set(&(m_part_info->used_partitions)); + *num_used_parts= bitmap_bits_set(&(m_part_info->used_partitions)); + *check_min_num= min(MAX_PARTS_FOR_OPTIMIZER_CALLS, *num_used_parts); +} + /* Return time for a scan of the table @@ -5760,43 +5777,67 @@ const key_map *ha_partition::keys_to_use_for_scanning() double ha_partition::scan_time() { - double scan_time= 0; - handler **file; + double scan_time= 0.0; + uint first, part_id, num_used_parts, check_min_num, partitions_called= 0; DBUG_ENTER("ha_partition::scan_time"); - for (file= m_file; *file; file++) - if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file))) - scan_time+= (*file)->scan_time(); + partitions_optimizer_call_preparations(&first, &num_used_parts, &check_min_num); + for (part_id= first; partitions_called < num_used_parts ; part_id++) + { + if (!bitmap_is_set(&(m_part_info->used_partitions), part_id)) + continue; + scan_time+= m_file[part_id]->scan_time(); + partitions_called++; + if (partitions_called >= check_min_num && scan_time != 0.0) + { + DBUG_RETURN(scan_time * + (double) num_used_parts / (double) partitions_called); + } + } DBUG_RETURN(scan_time); } /* - Get time to read + Estimate rows for records_in_range or estimate_rows_upper_bound. - SYNOPSIS - read_time() - index Index number used - ranges Number of ranges - rows Number of rows + @param is_records_in_range call records_in_range instead of + estimate_rows_upper_bound. + @param inx (only for records_in_range) index to use. + @param min_key (only for records_in_range) start of range. + @param max_key (only for records_in_range) end of range. - RETURN VALUE - time for read - - DESCRIPTION - This will be optimised later to include whether or not the index can - be used with partitioning. To achieve we need to add another parameter - that specifies how many of the index fields that are bound in the ranges. - Possibly added as a new call to handlers. + @return Number of rows or HA_POS_ERROR. */ - -double ha_partition::read_time(uint index, uint ranges, ha_rows rows) +ha_rows ha_partition::estimate_rows(bool is_records_in_range, uint inx, + key_range *min_key, key_range *max_key) { - DBUG_ENTER("ha_partition::read_time"); + ha_rows rows, estimated_rows= 0; + uint first, part_id, num_used_parts, check_min_num, partitions_called= 0; + DBUG_ENTER("ha_partition::records_in_range"); - DBUG_RETURN(m_file[0]->read_time(index, ranges, rows)); + partitions_optimizer_call_preparations(&first, &num_used_parts, &check_min_num); + for (part_id= first; partitions_called < num_used_parts ; part_id++) + { + if (!bitmap_is_set(&(m_part_info->used_partitions), part_id)) + continue; + if (is_records_in_range) + rows= m_file[part_id]->records_in_range(inx, min_key, max_key); + else + rows= m_file[part_id]->estimate_rows_upper_bound(); + if (rows == HA_POS_ERROR) + DBUG_RETURN(HA_POS_ERROR); + estimated_rows+= rows; + partitions_called++; + if (partitions_called >= check_min_num && estimated_rows) + { + DBUG_RETURN(estimated_rows * num_used_parts / partitions_called); + } + } + DBUG_RETURN(estimated_rows); } + /* Find number of records in a range @@ -5824,22 +5865,9 @@ double ha_partition::read_time(uint index, uint ranges, ha_rows rows) ha_rows ha_partition::records_in_range(uint inx, key_range *min_key, key_range *max_key) { - handler **file; - ha_rows in_range= 0; DBUG_ENTER("ha_partition::records_in_range"); - file= m_file; - do - { - if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file))) - { - ha_rows tmp_in_range= (*file)->records_in_range(inx, min_key, max_key); - if (tmp_in_range == HA_POS_ERROR) - DBUG_RETURN(tmp_in_range); - in_range+= tmp_in_range; - } - } while (*(++file)); - DBUG_RETURN(in_range); + DBUG_RETURN(estimate_rows(TRUE, inx, min_key, max_key)); } @@ -5855,22 +5883,36 @@ ha_rows ha_partition::records_in_range(uint inx, key_range *min_key, ha_rows ha_partition::estimate_rows_upper_bound() { - ha_rows rows, tot_rows= 0; - handler **file; DBUG_ENTER("ha_partition::estimate_rows_upper_bound"); - file= m_file; - do - { - if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file))) - { - rows= (*file)->estimate_rows_upper_bound(); - if (rows == HA_POS_ERROR) - DBUG_RETURN(HA_POS_ERROR); - tot_rows+= rows; - } - } while (*(++file)); - DBUG_RETURN(tot_rows); + DBUG_RETURN(estimate_rows(FALSE, 0, NULL, NULL)); +} + + +/* + Get time to read + + SYNOPSIS + read_time() + index Index number used + ranges Number of ranges + rows Number of rows + + RETURN VALUE + time for read + + DESCRIPTION + This will be optimised later to include whether or not the index can + be used with partitioning. To achieve we need to add another parameter + that specifies how many of the index fields that are bound in the ranges. + Possibly added as a new call to handlers. +*/ + +double ha_partition::read_time(uint index, uint ranges, ha_rows rows) +{ + DBUG_ENTER("ha_partition::read_time"); + + DBUG_RETURN(m_file[0]->read_time(index, ranges, rows)); } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index c08b1f77eca..9f6d9e0a5ba 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -547,6 +547,18 @@ public: ------------------------------------------------------------------------- */ +private: + /* + Helper function to get the minimum number of partitions to use for + the optimizer hints/cost calls. + */ + void partitions_optimizer_call_preparations(uint *num_used_parts, + uint *check_min_num, + uint *first); + ha_rows estimate_rows(bool is_records_in_range, uint inx, + key_range *min_key, key_range *max_key); +public: + /* keys_to_use_for_scanning can probably be implemented as the intersection of all underlying handlers if mixed handlers are used. From adc17cd41e21cb68d63b9962a97ad075da02999f Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 16 Dec 2009 19:31:19 +0200 Subject: [PATCH 03/11] Bug #48866: mysql.test fails under Fedora 12 strmov() is not guaranteed to work correctly on overlapping source and destination buffers. On some OSes it may work, but Fedora 12 has a stpcpy() that's not working correctly on overlapping buffers. Fixed to use the overlap-safe version of strmov instead. Re-vitalized the overlap-safe version of strmov. --- client/mysql.cc | 2 +- include/m_string.h | 9 +++------ strings/strmov.c | 6 +----- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index e4eabe8de33..5ae58baa694 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -4108,7 +4108,7 @@ char *get_arg(char *line, my_bool get_next_arg) if (*ptr == '\\' && ptr[1]) // escaped character { // Remove the backslash - strmov(ptr, ptr+1); + strmov_overlapp(ptr, ptr+1); } else if ((!quoted && *ptr == ' ') || (quoted && *ptr == qtype)) { diff --git a/include/m_string.h b/include/m_string.h index c26d0fb9260..5411d0483ea 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -108,9 +108,7 @@ extern char NEAR _dig_vec_lower[]; /* Defined in strtod.c */ extern const double log_10[309]; -#ifdef BAD_STRING_COMPILER -#define strmov(A,B) (memccpy(A,B,0,INT_MAX)-1) -#else +#ifndef strmov #define strmov_overlapp(A,B) strmov(A,B) #define strmake_overlapp(A,B,C) strmake(A,B,C) #endif @@ -171,12 +169,11 @@ extern uint strinstr(const char *str,const char *search); extern uint r_strinstr(reg1 my_string str,int from, reg4 my_string search); extern char *strkey(char *dst,char *head,char *tail,char *flags); extern char *strmake(char *dst,const char *src,uint length); -#ifndef strmake_overlapp -extern char *strmake_overlapp(char *dst,const char *src, uint length); -#endif #ifndef strmov extern char *strmov(char *dst,const char *src); +#else +extern char *strmov_overlapp(char *dst,const char *src); #endif extern char *strnmov(char *dst,const char *src,uint n); extern char *strsuff(const char *src,const char *suffix); diff --git a/strings/strmov.c b/strings/strmov.c index 1393411dd8f..eedf22a4ef1 100644 --- a/strings/strmov.c +++ b/strings/strmov.c @@ -24,13 +24,11 @@ #include #include "m_string.h" -#ifdef BAD_STRING_COMPILER +#ifdef strmov #undef strmov #define strmov strmov_overlapp #endif -#ifndef strmov - #if !defined(MC68000) && !defined(DS90) char *strmov(register char *dst, register const char *src) @@ -53,5 +51,3 @@ char *strmov(dst, src) } #endif - -#endif /* strmov */ From 007d77afb9ea5fd7b7a369114f8963ab147fd2c5 Mon Sep 17 00:00:00 2001 From: Serge Kozlov Date: Mon, 21 Dec 2009 14:40:08 +0300 Subject: [PATCH 04/11] Bug#8693, Bug#45521. --- mysql-test/t/disabled.def | 2 -- 1 file changed, 2 deletions(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 062667c249e..61e1226c8e3 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -16,11 +16,9 @@ im_daemon_life_cycle : Bug#20294: Instance manager tests fail randomly im_options_set : Bug#20294: Instance manager tests fail randomly im_options_unset : Bug#20294: Instance manager tests fail randomly im_utils : Bug#20294: Instance manager tests fail randomly -rpl_log_pos : Bug#8693 Test 'rpl_log_pos' fails sometimes kill : Bug#29149 Test "kill" fails on Windows ps_7ndb : Bug#38315 "Cluster Failure" in ps_7ndb strict_autoinc_5ndb : Bug#35148 "Error '4009 Cluster Failure' in various tests on various platforms" -rpl_slave_skip : Bug#45521: rpl_slave_skip fails in pb2 loaddata_autocom_ndb : Bug#35148: Error '4009 Cluster Failure' in various tests on various platforms ndb_autodiscover3 : Bug#35148: Error '4009 Cluster Failure' in various tests on various platforms ndb_autodiscover : Bug#45972: ndb.ndb_autodiscover fails occasionally with pb2 From 081bcb3b8bc861bc5609a4ce92c8eb3528ffc078 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Tue, 22 Dec 2009 13:52:23 +0400 Subject: [PATCH 05/11] Bug#47371 reference by same column name At the end of execution top level join execution we cleanup this join with true argument. It leads to underlying join cleanup(subquery) with true argument too and to tmp_table_param->field array cleanup which is required later. The problem is that Item_func_set_user_var does not set result_filed which leads to unnecessary repeated excution of subquery on final stage. The fix is to set result_field for Item_func_set_user_var. mysql-test/r/count_distinct.result: test result mysql-test/r/user_var.result: test result mysql-test/t/count_distinct.test: test case mysql-test/t/user_var.test: test case sql/item_func.cc: At the end of execution top level join execution we cleanup this join with true argument. It leads to underlying join cleanup(subquery) with true argument too and to tmp_table_param->field array cleanup which is required later. The problem is that Item_func_set_user_var does not set result_filed which leads to unnecessary repeated excution of subquery on final stage. The fix is to set result_field for Item_func_set_user_var. --- mysql-test/r/count_distinct.result | 20 ++++++++++++++++++++ mysql-test/r/user_var.result | 15 +++++++++++++++ mysql-test/t/count_distinct.test | 19 +++++++++++++++++++ mysql-test/t/user_var.test | 20 ++++++++++++++++++++ sql/item_func.cc | 2 +- 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/count_distinct.result b/mysql-test/r/count_distinct.result index a21748359b9..804bc1f4788 100644 --- a/mysql-test/r/count_distinct.result +++ b/mysql-test/r/count_distinct.result @@ -40,6 +40,26 @@ select t2.isbn,city,t1.libname,count(distinct t1.libname) as a from t3 left join isbn city libname a 007 Berkeley Berkeley Public1 2 000 New York New York Public Libra 2 +select t2.isbn,city,@bar:=t1.libname,count(distinct t1.libname) as a +from t3 left join t1 on t3.libname=t1.libname left join t2 +on t3.isbn=t2.isbn group by city having count(distinct +t1.libname) > 1; +isbn city @bar:=t1.libname a +007 Berkeley Berkeley Public1 2 +000 New York New York Public Libra 2 +SELECT @bar; +@bar +Berkeley Public2 +select t2.isbn,city,concat(@bar:=t1.libname),count(distinct t1.libname) as a +from t3 left join t1 on t3.libname=t1.libname left join t2 +on t3.isbn=t2.isbn group by city having count(distinct +t1.libname) > 1; +isbn city concat(@bar:=t1.libname) a +007 Berkeley Berkeley Public1 2 +000 New York New York Public Libra 2 +SELECT @bar; +@bar +Berkeley Public2 drop table t1, t2, t3; create table t1 (f1 int); insert into t1 values (1); diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index bfa95d8f92b..8236dbe94ac 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -363,4 +363,19 @@ SELECT a, b FROM t1 WHERE a=2 AND b=3 GROUP BY a, b; a b 2 3 DROP TABLE t1; +CREATE TABLE t1 (f1 int(11) default NULL, f2 int(11) default NULL); +CREATE TABLE t2 (f1 int(11) default NULL, f2 int(11) default NULL, foo int(11)); +CREATE TABLE t3 (f1 int(11) default NULL, f2 int(11) default NULL); +INSERT INTO t1 VALUES(10, 10); +INSERT INTO t1 VALUES(10, 10); +INSERT INTO t2 VALUES(10, 10, 10); +INSERT INTO t2 VALUES(10, 10, 10); +INSERT INTO t3 VALUES(10, 10); +INSERT INTO t3 VALUES(10, 10); +SELECT MIN(t2.f1), +@bar:= (SELECT MIN(t3.f2) FROM t3 WHERE t3.f2 > foo) +FROM t1,t2 WHERE t1.f1 = t2.f1 ORDER BY t2.f1; +MIN(t2.f1) @bar:= (SELECT MIN(t3.f2) FROM t3 WHERE t3.f2 > foo) +10 NULL +DROP TABLE t1, t2, t3; End of 5.0 tests diff --git a/mysql-test/t/count_distinct.test b/mysql-test/t/count_distinct.test index e63bdabdb95..d0996689aeb 100644 --- a/mysql-test/t/count_distinct.test +++ b/mysql-test/t/count_distinct.test @@ -35,6 +35,25 @@ insert into t1 values ('NYC Lib','New York'); select t2.isbn,city,t1.libname,count(t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city,t1.libname; select t2.isbn,city,t1.libname,count(distinct t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city having count(distinct t1.libname) > 1; select t2.isbn,city,t1.libname,count(distinct t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city having count(distinct concat(t1.libname,'a')) > 1; + +select t2.isbn,city,@bar:=t1.libname,count(distinct t1.libname) as a + from t3 left join t1 on t3.libname=t1.libname left join t2 + on t3.isbn=t2.isbn group by city having count(distinct + t1.libname) > 1; +# +# Wrong result, see bug#49872 +# +SELECT @bar; + +select t2.isbn,city,concat(@bar:=t1.libname),count(distinct t1.libname) as a + from t3 left join t1 on t3.libname=t1.libname left join t2 + on t3.isbn=t2.isbn group by city having count(distinct + t1.libname) > 1; +# +# Wrong result, see bug#49872 +# +SELECT @bar; + drop table t1, t2, t3; # diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index d39b49a0e87..59a5238b35b 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -248,4 +248,24 @@ SELECT @a, @b; SELECT a, b FROM t1 WHERE a=2 AND b=3 GROUP BY a, b; DROP TABLE t1; +# +# Bug#47371: reference by same column name +# +CREATE TABLE t1 (f1 int(11) default NULL, f2 int(11) default NULL); +CREATE TABLE t2 (f1 int(11) default NULL, f2 int(11) default NULL, foo int(11)); +CREATE TABLE t3 (f1 int(11) default NULL, f2 int(11) default NULL); + +INSERT INTO t1 VALUES(10, 10); +INSERT INTO t1 VALUES(10, 10); +INSERT INTO t2 VALUES(10, 10, 10); +INSERT INTO t2 VALUES(10, 10, 10); +INSERT INTO t3 VALUES(10, 10); +INSERT INTO t3 VALUES(10, 10); + +SELECT MIN(t2.f1), +@bar:= (SELECT MIN(t3.f2) FROM t3 WHERE t3.f2 > foo) +FROM t1,t2 WHERE t1.f1 = t2.f1 ORDER BY t2.f1; + +DROP TABLE t1, t2, t3; + --echo End of 5.0 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index d6f315fda50..cb0d6bdbe5f 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -610,7 +610,7 @@ void Item_func::signal_divide_by_null() Item *Item_func::get_tmp_table_item(THD *thd) { - if (!with_sum_func && !const_item() && functype() != SUSERVAR_FUNC) + if (!with_sum_func && !const_item()) return new Item_field(result_field); return copy_or_same(thd); } From 8f0f1d0ddb73283f60adb696f5b46b376aed327e Mon Sep 17 00:00:00 2001 From: Satya B Date: Tue, 22 Dec 2009 18:33:39 +0530 Subject: [PATCH 06/11] Removing rpl.rpl_trigger from experimental list as it is Fixed by BUG#46656 --- mysql-test/collections/default.experimental | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 2c2e9cab626..3894f2a4368 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -20,7 +20,6 @@ ndb.* # joro : NDB tests marked as experiment rpl.rpl_get_master_version_and_clock* # Bug #49191 2009-12-01 Daogang rpl_get_master_version_and_clock failed on PB2: COM_REGISTER_SLAVE failed rpl.rpl_innodb_bug28430* @solaris # Bug#46029 -rpl.rpl_trigger* # Bug#47810 2009-10-04 joro rpl.rpl_trigger.test fails with valgrind errors with the innodb plugin rpl_ndb.* # joro : NDB tests marked as experimental as agreed with bochklin rpl_ndb.rpl_ndb_log # Bug#38998 From 877311779d8304bafc3aa24eee2e8af573d7f69f Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 23 Dec 2009 17:44:03 +0400 Subject: [PATCH 07/11] Bug#47649 crash during CALL procedure If first call of the procedure is failed on the open_table stage stmt_arena->state is set to EXECUTED state. On second call(if no errors on open_table stage) it leads to use of worng memory arena in find_field_in_view() function as thd->stmt_arena->is_stmt_prepare_or_first_sp_execute() returns FALSE for EXECUTED state. The item is created not in its own arena and it leads to crash on further calls of the procedure. The fix: change state of arena only if no errors on open_table stage happens. mysql-test/r/sp.result: test result mysql-test/t/sp.test: test case sql/sp_head.cc: If first call of the procedure is failed on the open_table stage stmt_arena->state is set to EXECUTED state. On second call(if no errors on open_table stage) it leads to use of worng memory arena in find_field_in_view() function as thd->stmt_arena->is_stmt_prepare_or_first_sp_execute() returns FALSE for EXECUTED state. The item is created not in its own arena and it leads to crash on further calls of the procedure. The fix: change state of arena only if no errors on open_table stage happens. --- mysql-test/r/sp.result | 16 ++++++++++++++++ mysql-test/t/sp.test | 19 +++++++++++++++++++ sql/sp_head.cc | 11 +++++++++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 83ad7545685..1e6227e7380 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6963,6 +6963,22 @@ CALL p1(); CALL p1(); DROP PROCEDURE p1; DROP TABLE t1; +CREATE TABLE t1 ( f1 integer, primary key (f1)); +CREATE TABLE t2 LIKE t1; +CREATE TEMPORARY TABLE t3 LIKE t1; +CREATE PROCEDURE p1 () BEGIN SELECT f1 FROM t3 AS A WHERE A.f1 IN ( SELECT f1 FROM t3 ) ; +END| +CALL p1; +ERROR HY000: Can't reopen table: 'A' +CREATE VIEW t3 AS SELECT f1 FROM t2 A WHERE A.f1 IN ( SELECT f1 FROM t2 ); +DROP TABLE t3; +CALL p1; +f1 +CALL p1; +f1 +DROP PROCEDURE p1; +DROP TABLE t1, t2; +DROP VIEW t3; # # Bug #46629: Item_in_subselect::val_int(): Assertion `0' # on subquery inside a SP diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 73ba62612b8..5cf050146dd 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -8242,6 +8242,25 @@ while ($tab_count) DROP PROCEDURE p1; DROP TABLE t1; +# +# Bug#47649 crash during CALL procedure +# +CREATE TABLE t1 ( f1 integer, primary key (f1)); +CREATE TABLE t2 LIKE t1; +CREATE TEMPORARY TABLE t3 LIKE t1; +delimiter |; +CREATE PROCEDURE p1 () BEGIN SELECT f1 FROM t3 AS A WHERE A.f1 IN ( SELECT f1 FROM t3 ) ; +END| +delimiter ;| +--error ER_CANT_REOPEN_TABLE +CALL p1; +CREATE VIEW t3 AS SELECT f1 FROM t2 A WHERE A.f1 IN ( SELECT f1 FROM t2 ); +DROP TABLE t3; +CALL p1; +CALL p1; +DROP PROCEDURE p1; +DROP TABLE t1, t2; +DROP VIEW t3; --echo # --echo # Bug #46629: Item_in_subselect::val_int(): Assertion `0' diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 51a731138ca..d74e195048f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2773,8 +2773,15 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, m_lex->mark_as_requiring_prelocking(NULL); } thd->rollback_item_tree_changes(); - /* Update the state of the active arena. */ - thd->stmt_arena->state= Query_arena::EXECUTED; + /* + Update the state of the active arena if no errors on + open_tables stage. + */ + if (!res || !thd->is_error() || + (thd->main_da.sql_errno() != ER_CANT_REOPEN_TABLE && + thd->main_da.sql_errno() != ER_NO_SUCH_TABLE && + thd->main_da.sql_errno() != ER_UPDATE_TABLE_USED)) + thd->stmt_arena->state= Query_arena::EXECUTED; /* Merge here with the saved parent's values From 1f55f5b617d0df650161c58f7d0707abd4ca42e2 Mon Sep 17 00:00:00 2001 From: Satya B Date: Thu, 24 Dec 2009 12:02:29 +0530 Subject: [PATCH 08/11] Bug#49898 - Fix for bug#37408 introduces a linker error the declaration of THR_LOCK_myisam_mmap in mi_static is redundant as it accessible via the extern declaration in include/myisam.h myisam/mi_static.c: Bug#49898 - Fix for bug#37408 introduces a linker error Remove THR_LOCK_myisam_mmap declaration as it is redundant --- myisam/mi_static.c | 1 - 1 file changed, 1 deletion(-) diff --git a/myisam/mi_static.c b/myisam/mi_static.c index b6464e452d7..f75ede48828 100644 --- a/myisam/mi_static.c +++ b/myisam/mi_static.c @@ -41,7 +41,6 @@ my_off_t myisam_max_temp_length= MAX_FILE_SIZE; ulong myisam_bulk_insert_tree_size=8192*1024; ulong myisam_data_pointer_size=4; ulonglong myisam_mmap_size= SIZE_T_MAX, myisam_mmap_used= 0; -pthread_mutex_t THR_LOCK_myisam_mmap; static int always_valid(const char *filename __attribute__((unused))) { From a21a0b47ca46212a528c4402e4b473fe51437422 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 18 Dec 2009 14:00:30 +0200 Subject: [PATCH 09/11] Bug #31145: ALTER TABLE DROP COLUMN, ADD COLUMN crashes (linux) or freezes (win) the server The check for equality was assuming the field object is always created. If it's not it was de-referencing a NULL pointer. Fixed to use the data in the create object instead. --- mysql-test/r/alter_table.result | 7 +++++++ mysql-test/t/alter_table.test | 12 ++++++++++++ sql/field.cc | 3 +-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 06f4e7fbe8a..004e2031fb1 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -1338,4 +1338,11 @@ ALTER TABLE t1 CHANGE COLUMN f1 f1_no_real_change TIMESTAMP NULL DEFAULT NULL; affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 DROP TABLE t1; +# +# Bug #31145: ALTER TABLE DROP COLUMN, ADD COLUMN crashes (linux) +# or freezes (win) the server +# +CREATE TABLE t1 (a TEXT, id INT, b INT); +ALTER TABLE t1 DROP COLUMN a, ADD COLUMN c TEXT FIRST; +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 5534aa0a234..4989a6c380c 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -1061,4 +1061,16 @@ ALTER TABLE t1 CHANGE COLUMN f1 f1_no_real_change TIMESTAMP NULL DEFAULT NULL; --disable_info DROP TABLE t1; + +--echo # +--echo # Bug #31145: ALTER TABLE DROP COLUMN, ADD COLUMN crashes (linux) +--echo # or freezes (win) the server +--echo # + +CREATE TABLE t1 (a TEXT, id INT, b INT); +ALTER TABLE t1 DROP COLUMN a, ADD COLUMN c TEXT FIRST; + +DROP TABLE t1; + + --echo End of 5.1 tests diff --git a/sql/field.cc b/sql/field.cc index 01ccc338782..d8db3fdbae4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8282,8 +8282,7 @@ uint Field_blob::is_equal(Create_field *new_field) return ((new_field->sql_type == get_blob_type_from_length(max_data_length())) && new_field->charset == field_charset && - ((Field_blob *)new_field->field)->max_data_length() == - max_data_length()); + new_field->pack_length == pack_length()); } From 2d8869d248188c1bf393fc87d9f0e31adf691c2d Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 22 Dec 2009 17:52:15 +0200 Subject: [PATCH 10/11] Bug #49734: Crash on EXPLAIN EXTENDED UNION ... ORDER BY Several problems fixed : 1. Non constant expressions in UNION ... ORDER BY were not correctly cleaned up in st_select_lex_unit::cleanup() causing crashes in EXPLAIN EXTENDED because of fields quoted by these expressions pointing to the already freed temporary table used to calculate the UNION. Fixed by correctly cleaning up expressions of any depth. 2. Subqueries in the order by part of UNION ... ORDER BY ... caused a crash in EXPLAIN EXTENDED because of a transformation attempt made during EXPLAIN EXTENDED execution. Fixed by not doing the transformation when in EXPLAIN. 3. Fulltext functions caused crash when in the ORDER BY part of an un-parenthesized UNION that gets "promoted" to be valid for the whole union, e.g. SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY MATCHES (a) AGAINST ('abc' IN BOOLEAN MODE). This is a case that demonstrates a more general problem of parts of the query being moved to another level. When doing such transformation late in the optimization run when most of the flags about the contents of the query are already aggregated it's possible to "split" the flags so that they correctly reflect the new queries after the transformation. In specific the ST_SELECT_LEX::ftfunc_list is holding all the free text function for all the parts of the second SELECT in the UNION and we don't know what part of that is in the ORDER BY that we're to move to the UNION level and what part is about the other parts of the second SELECT. Fixed by throwing and error when such statements are about to be processed by adding a check for the presence of MATCH() inside the ORDER BY clause that's going to get promoted to UNION. To workaround this new limitation one must parenthesize the UNION SELECTs and provide a real global ORDER BY for the UNION outside of the parenthesis. --- mysql-test/r/fulltext_order_by.result | 6 +-- mysql-test/r/union.result | 63 +++++++++++++++++++++++++++ mysql-test/t/fulltext_order_by.test | 5 ++- mysql-test/t/union.test | 53 ++++++++++++++++++++++ sql/item.h | 17 ++++++++ sql/item_func.h | 5 +++ sql/sql_select.cc | 2 +- sql/sql_union.cc | 31 ++++++++++++- 8 files changed, 175 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result index bc466b5aba7..bd3e79ec5c2 100644 --- a/mysql-test/r/fulltext_order_by.result +++ b/mysql-test/r/fulltext_order_by.result @@ -126,7 +126,7 @@ group by a.text, b.id, b.betreff order by match(b.betreff) against ('+abc' in boolean mode) desc; -ERROR 42S22: Unknown column 'b.betreff' in 'order clause' +ERROR 42000: Incorrect usage/placement of 'MATCH()' select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join @@ -142,7 +142,7 @@ where match(c.beitrag) against ('+abc' in boolean mode) order by match(b.betreff) against ('+abc' in boolean mode) desc; -ERROR 42S22: Unknown column 'b.betreff' in 'order clause' +ERROR 42000: Incorrect usage/placement of 'MATCH()' select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join @@ -158,7 +158,7 @@ where match(c.beitrag) against ('+abc' in boolean mode) order by match(betreff) against ('+abc' in boolean mode) desc; -text id betreff +ERROR 42000: Incorrect usage/placement of 'MATCH()' (select b.id, b.betreff from t3 b) union (select b.id, b.betreff from t3 b) order by match(betreff) against ('+abc' in boolean mode) desc; diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 44a3812725a..dce32d2ced4 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -1588,3 +1588,66 @@ Warnings: Note 1003 select '0' AS `a` from `test`.`t1` union select '0' AS `a` from `test`.`t1` order by `a` DROP TABLE t1; End of 5.0 tests +# +# Bug #49734: Crash on EXPLAIN EXTENDED UNION ... ORDER BY +# +# +CREATE TABLE t1 (a VARCHAR(10), FULLTEXT KEY a (a)); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (1),(2); +# Should not crash +EXPLAIN EXTENDED +SELECT * FROM t1 UNION SELECT * FROM t1 ORDER BY a + 12; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 +2 UNION t1 ALL NULL NULL NULL NULL 2 100.00 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Using filesort +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` union select `test`.`t1`.`a` AS `a` from `test`.`t1` order by (`a` + 12) +# Should not crash +SELECT * FROM t1 UNION SELECT * FROM t1 ORDER BY a + 12; +a +1 +2 +# Should not crash +EXPLAIN EXTENDED +SELECT * FROM t1 UNION SELECT * FROM t1 +ORDER BY MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE); +ERROR 42000: Incorrect usage/placement of 'MATCH()' +# Should not crash +SELECT * FROM t1 UNION SELECT * FROM t1 +ORDER BY MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE); +ERROR 42000: Incorrect usage/placement of 'MATCH()' +# Should not crash +(SELECT * FROM t1) UNION (SELECT * FROM t1) +ORDER BY MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE); +a +1 +2 +# Should not crash +EXPLAIN EXTENDED +SELECT * FROM t1 UNION SELECT * FROM t1 +ORDER BY (SELECT a FROM t2 WHERE b = 12); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 +2 UNION t1 ALL NULL NULL NULL NULL 2 100.00 +3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where +NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Using filesort +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #2 +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` union select `test`.`t1`.`a` AS `a` from `test`.`t1` order by (select `test`.`t1`.`a` AS `a` from `test`.`t2` where (`test`.`t2`.`b` = 12)) +# Should not crash +SELECT * FROM t1 UNION SELECT * FROM t1 +ORDER BY (SELECT a FROM t2 WHERE b = 12); +a +1 +2 +# Should not crash +SELECT * FROM t2 UNION SELECT * FROM t2 +ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE)); +b +1 +2 +DROP TABLE t1,t2; +End of 5.1 tests diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test index 074aefbf943..814cd4a5954 100644 --- a/mysql-test/t/fulltext_order_by.test +++ b/mysql-test/t/fulltext_order_by.test @@ -80,7 +80,7 @@ CREATE TABLE t3 ( FULLTEXT KEY betreff (betreff) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=996 ; ---error 1054 +--error ER_CANT_USE_OPTION_HERE select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join @@ -100,7 +100,7 @@ group by order by match(b.betreff) against ('+abc' in boolean mode) desc; ---error 1054 +--error ER_CANT_USE_OPTION_HERE select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join @@ -117,6 +117,7 @@ where order by match(b.betreff) against ('+abc' in boolean mode) desc; +--error ER_CANT_USE_OPTION_HERE select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index ec169838d59..91fc9546bbe 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -1102,3 +1102,56 @@ DROP TABLE t1; --echo End of 5.0 tests + + +--echo # +--echo # Bug #49734: Crash on EXPLAIN EXTENDED UNION ... ORDER BY +--echo # +--echo # + +CREATE TABLE t1 (a VARCHAR(10), FULLTEXT KEY a (a)); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (1),(2); + +--echo # Should not crash +EXPLAIN EXTENDED +SELECT * FROM t1 UNION SELECT * FROM t1 ORDER BY a + 12; + +--echo # Should not crash +SELECT * FROM t1 UNION SELECT * FROM t1 ORDER BY a + 12; + + +--echo # Should not crash +--error ER_CANT_USE_OPTION_HERE +EXPLAIN EXTENDED +SELECT * FROM t1 UNION SELECT * FROM t1 + ORDER BY MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE); + +--echo # Should not crash +--error ER_CANT_USE_OPTION_HERE +SELECT * FROM t1 UNION SELECT * FROM t1 + ORDER BY MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE); + +--echo # Should not crash +(SELECT * FROM t1) UNION (SELECT * FROM t1) + ORDER BY MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE); + + +--echo # Should not crash +EXPLAIN EXTENDED +SELECT * FROM t1 UNION SELECT * FROM t1 + ORDER BY (SELECT a FROM t2 WHERE b = 12); + +--echo # Should not crash +SELECT * FROM t1 UNION SELECT * FROM t1 + ORDER BY (SELECT a FROM t2 WHERE b = 12); + +--echo # Should not crash +SELECT * FROM t2 UNION SELECT * FROM t2 + ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE)); + +DROP TABLE t1,t2; + + +--echo End of 5.1 tests diff --git a/sql/item.h b/sql/item.h index b97808ac87f..8f0e5874f3f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -967,6 +967,23 @@ public: return FALSE; } + /** + Find a function of a given type + + @param arg the function type to search (enum Item_func::Functype) + @return + @retval TRUE the function type we're searching for is found + @retval FALSE the function type wasn't found + + @description + This function can be used (together with Item::walk()) to find functions + in an item tree fragment. + */ + virtual bool find_function_processor (uchar *arg) + { + return FALSE; + } + /* For SP local variable returns pointer to Item representing its current value and pointer to current Item otherwise. diff --git a/sql/item_func.h b/sql/item_func.h index 259316b0c41..71168c64e4b 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -212,6 +212,11 @@ public: { return has_timestamp_args(); } + + virtual bool find_function_processor (uchar *arg) + { + return functype() == *(Functype *) arg; + } }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6383fe63012..d50bb888850 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -519,7 +519,7 @@ JOIN::prepare(Item ***rref_pointer_array, thd->lex->allow_sum_func= save_allow_sum_func; } - if (!thd->lex->view_prepare_mode) + if (!thd->lex->view_prepare_mode && !(select_options & SELECT_DESCRIBE)) { Item_subselect *subselect; /* Is it subselect? */ diff --git a/sql/sql_union.cc b/sql/sql_union.cc index cbf94ad7181..1760670f9c8 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -335,6 +335,35 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } + /* + Disable the usage of fulltext searches in the last union branch. + This is a temporary 5.x limitation because of the way the fulltext + search functions are handled by the optimizer. + This is manifestation of the more general problems of "taking away" + parts of a SELECT statement post-fix_fields(). This is generally not + doable since various flags are collected in various places (e.g. + SELECT_LEX) that carry information about the presence of certain + expressions or constructs in the parts of the query. + When part of the query is taken away it's not clear how to "divide" + the meaning of these accumulated flags and what to carry over to the + recipient query (SELECT_LEX). + */ + if (global_parameters->ftfunc_list->elements && + global_parameters->order_list.elements && + global_parameters != fake_select_lex) + { + ORDER *ord; + Item_func::Functype ft= Item_func::FT_FUNC; + for (ord= (ORDER*)global_parameters->order_list.first; ord; ord= ord->next) + if ((*ord->item)->walk (&Item::find_function_processor, FALSE, + (uchar *) &ft)) + { + my_error (ER_CANT_USE_OPTION_HERE, MYF(0), "MATCH()"); + goto err; + } + } + + create_options= (first_sl->options | thd_arg->options | TMP_TABLE_ALL_COLUMNS); /* @@ -669,7 +698,7 @@ bool st_select_lex_unit::cleanup() { ORDER *ord; for (ord= (ORDER*)global_parameters->order_list.first; ord; ord= ord->next) - (*ord->item)->cleanup(); + (*ord->item)->walk (&Item::cleanup_processor, 0, 0); } } From 416df0eaada5b644931f5b3b15f897a376641a4d Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 24 Dec 2009 15:20:58 +0000 Subject: [PATCH 11/11] BUG#48738: post-push fix. Multi-platform test improvements, mainly to make the test run gracefully on windows. There was also a syntax error in windows part of the test. --- .../r/binlog_delete_and_flush_index.result | 14 ++- .../t/binlog_delete_and_flush_index.test | 95 ++++--------------- 2 files changed, 29 insertions(+), 80 deletions(-) diff --git a/mysql-test/r/binlog_delete_and_flush_index.result b/mysql-test/r/binlog_delete_and_flush_index.result index 153900f3081..7500c17759c 100644 --- a/mysql-test/r/binlog_delete_and_flush_index.result +++ b/mysql-test/r/binlog_delete_and_flush_index.result @@ -2,7 +2,9 @@ RESET MASTER; CREATE TABLE t1 (a int); ### assertion: index file contains regular entries SET @index=LOAD_FILE('MYSQLD_DATADIR/master-bin.index'); -master-bin.000001 +SELECT @index; +@index +MYSQLD_DATADIR/master-bin.000001 ### assertion: show original binlogs show binary logs; @@ -15,8 +17,10 @@ master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a int) FLUSH LOGS; ### assertion: index file contains renamed binlog and the new one SET @index=LOAD_FILE('MYSQLD_DATADIR/master-bin.index'); -master-bin-b34582.000001 -master-bin.000002 +SELECT @index; +@index +MYSQLD_DATADIR/master-bin-b34582.000001 +MYSQLD_DATADIR/master-bin.000002 ### assertion: original binlog content still exists, despite we ### renamed and changed the index file @@ -39,6 +43,8 @@ master-bin.000002 # ### assertion: assert that not purged binlog file exists ### assertion: show index file contents and these should match show binary logs issued above SET @index=LOAD_FILE('MYSQLD_DATADIR/master-bin.index'); -master-bin.000002 +SELECT @index; +@index +MYSQLD_DATADIR/master-bin.000002 RESET MASTER; diff --git a/mysql-test/t/binlog_delete_and_flush_index.test b/mysql-test/t/binlog_delete_and_flush_index.test index 6784043386d..2899b96e317 100644 --- a/mysql-test/t/binlog_delete_and_flush_index.test +++ b/mysql-test/t/binlog_delete_and_flush_index.test @@ -45,31 +45,10 @@ RESET MASTER; CREATE TABLE t1 (a int); -- echo ### assertion: index file contains regular entries --- replace_regex /[\\\/].*master/MYSQLD_DATADIR\/master/ +-- replace_result $datadir MYSQLD_DATADIR -- eval SET @index=LOAD_FILE('$index') -if (`SELECT convert(@@version_compile_os using latin1) - IN ('Win32','Win64','Windows')`) -{ - -- disable_query_log - -- disable_result_log - -- let $a= `SELECT REPLACE (@index, '$datadir\', '')` - -- enable_result_log - -- enable_query_log - - -- echo $a - -} -if (!`SELECT convert(@@version_compile_os using latin1) - IN ('Win32','Win64','Windows')`) -{ - -- disable_query_log - -- disable_result_log - -- let $a= `SELECT REPLACE (@index, '$datadir/', '')` - -- enable_result_log - -- enable_query_log - - -- echo $a -} +-- replace_result $datadir MYSQLD_DATADIR +SELECT @index; --echo ### assertion: show original binlogs -- source include/show_binary_logs.inc @@ -79,17 +58,23 @@ if (!`SELECT convert(@@version_compile_os using latin1) # action: copy binlogs to other names and change entries in index file -- copy_file $datadir/master-bin.000001 $datadir/master-bin-b34582.000001 --- let newbinfile=$datadir/master-bin-b34582.000001 -let INDEX_FILE=$index; +-- let newbinfile= $datadir/master-bin-b34582.000001 +-- let INDEX_FILE= $index perl; -$newbinfile= $ENV{'newbinfile'}; +use File::Spec; +$newbinfile= File::Spec->rel2abs($ENV{'newbinfile'}); $file= $ENV{'INDEX_FILE'}; open(FILE, ">$file") || die "Unable to open $file."; truncate(FILE,0); -print FILE $newbinfile . "\n"; +print FILE "$newbinfile"; close ($file); EOF +# append a new line (platform independent) +-- append_file $index + +EOF + # action: should cause rotation, and creation of new binlogs FLUSH LOGS; @@ -97,31 +82,10 @@ FLUSH LOGS; -- remove_file $datadir/master-bin.000001 -- echo ### assertion: index file contains renamed binlog and the new one --- replace_regex /[\\\/].*master/MYSQLD_DATADIR\/master/ +-- replace_result $datadir MYSQLD_DATADIR -- eval SET @index=LOAD_FILE('$index') -if (`SELECT convert(@@version_compile_os using latin1) - IN ('Win32','Win64','Windows')`) -{ - -- disable_query_log - -- disable_result_log - -- let $a= `SELECT REPLACE (@index, '$datadir\', '')` - -- enable_result_log - -- enable_query_log - - -- echo $a - -} -if (!`SELECT convert(@@version_compile_os using latin1) - IN ('Win32','Win64','Windows')`) -{ - -- disable_query_log - -- disable_result_log - -- let $a= `SELECT REPLACE (@index, '$datadir/', '')` - -- enable_result_log - -- enable_query_log - - -- echo $a -} +-- replace_result $datadir MYSQLD_DATADIR +SELECT @index; -- echo ### assertion: original binlog content still exists, despite we -- echo ### renamed and changed the index file @@ -147,30 +111,9 @@ DROP TABLE t1; -- file_exists $datadir/$current_binlog -- echo ### assertion: show index file contents and these should match show binary logs issued above --- replace_regex /[\\\/].*master/MYSQLD_DATADIR\/master/ +-- replace_result $datadir MYSQLD_DATADIR -- eval SET @index=LOAD_FILE('$index') -if (`SELECT convert(@@version_compile_os using latin1) - IN ('Win32','Win64','Windows')`) -{ - -- disable_query_log - -- disable_result_log - -- let $a= `SELECT REPLACE (@index, '$datadir\', '')` - -- enable_result_log - -- enable_query_log - - -- echo $a - -} -if (!`SELECT convert(@@version_compile_os using latin1) - IN ('Win32','Win64','Windows')`) -{ - -- disable_query_log - -- disable_result_log - -- let $a= `SELECT REPLACE (@index, '$datadir/', '')` - -- enable_result_log - -- enable_query_log - - -- echo $a -} +-- replace_result $datadir MYSQLD_DATADIR +SELECT @index; RESET MASTER;