From 9aa79dc5966b6bba74c772d110265161a018cbf2 Mon Sep 17 00:00:00 2001 From: Manish Kumar Date: Mon, 21 May 2012 12:57:39 +0530 Subject: [PATCH 01/44] BUG#12400221 - 60926: BINARY LOG EVENTS LARGER THAN MAX_ALLOWED_PACKET Problem ======== SQL statements close to the size of max_allowed_packet produce binary log events larger than max_allowed_packet. The reason why this failure is occuring is because the event length is more than the total size of the max_allowed_packet + max_event_header length. Now since the event length exceeds this size master Dump thread is unable to send the packet on to the slave. That can happen e.g with row-based replication in Update_rows event. Fix ==== The problem was fixed by increasing the max_allowed_packet for the slave's threads (IO/SQL) by increasing it to 1GB. This is done using the new server option included which is used to regulate the max_allowed_packet of the slave thread (IO/SQL). This causes the large packets to be received by the slave and apply it successfully. --- mysql-test/suite/rpl/r/rpl_log_pos.result | 2 +- mysql-test/suite/rpl/r/rpl_packet.result | 11 +- mysql-test/suite/rpl/t/rpl_packet-slave.opt | 2 +- mysql-test/suite/rpl/t/rpl_packet.test | 11 +- .../inc/slave_max_allowed_packet_basic.inc | 177 ++++++++++++++++++ .../r/max_allowed_packet_basic.result | 12 ++ .../sys_vars/r/max_allowed_packet_func.result | 2 + .../sys_vars/r/net_buffer_length_basic.result | 2 + .../t/slave_max_allowed_packet_basic.test | 3 + sql/log_event.cc | 2 +- sql/log_event.h | 7 + sql/mysql_priv.h | 1 + sql/mysqld.cc | 7 + sql/set_var.cc | 2 + sql/share/errmsg.txt | 34 ++-- sql/slave.cc | 11 +- sql/sql_repl.cc | 2 +- 17 files changed, 252 insertions(+), 36 deletions(-) create mode 100644 mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc create mode 100644 mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index 91d307008f0..b2224dcd725 100644 --- a/mysql-test/suite/rpl/r/rpl_log_pos.result +++ b/mysql-test/suite/rpl/r/rpl_log_pos.result @@ -9,7 +9,7 @@ change master to master_log_pos=MASTER_LOG_POS; Read_Master_Log_Pos = '75' start slave; include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event'' include/stop_slave_sql.inc show master status; File Position Binlog_Do_DB Binlog_Ignore_DB diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index 7a7f8141ac8..6d68a094594 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -1,7 +1,7 @@ include/master-slave.inc [connection master] -call mtr.add_suppression("Slave I/O: Got a packet bigger than 'max_allowed_packet' bytes, Error_code: 1153"); -call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log:"); +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'slave_max_allowed_packet' bytes, Error_code: 1153"); +call mtr.add_suppression("Log entry on master is longer than slave_max_allowed_packet"); drop database if exists DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; create database DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; SET @@global.max_allowed_packet=1024; @@ -30,14 +30,14 @@ include/start_slave.inc CREATE TABLE `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); include/wait_for_slave_io_error.inc [errno=1153] -Last_IO_Error = 'Got a packet bigger than 'max_allowed_packet' bytes' +Last_IO_Error = 'Got a packet bigger than 'slave_max_allowed_packet' bytes' include/stop_slave_sql.inc include/rpl_reset.inc DROP TABLE t1; CREATE TABLE t1 (f1 int PRIMARY KEY, f2 LONGTEXT, f3 LONGTEXT) ENGINE=MyISAM; INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), REPEAT('b', @@global.max_allowed_packet)); -include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'' +include/wait_for_slave_io_error.inc [errno=1153] +Last_IO_Error = 'Got a packet bigger than 'slave_max_allowed_packet' bytes' STOP SLAVE; RESET SLAVE; RESET MASTER; @@ -52,6 +52,7 @@ SET @@global.max_allowed_packet= 1024; Warnings: Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SET @@global.net_buffer_length= 1024; +SET @@global.slave_max_allowed_packet= 1073741824; DROP TABLE t1; RESET SLAVE; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_packet-slave.opt b/mysql-test/suite/rpl/t/rpl_packet-slave.opt index 42d4f94c999..e0a7a203f99 100644 --- a/mysql-test/suite/rpl/t/rpl_packet-slave.opt +++ b/mysql-test/suite/rpl/t/rpl_packet-slave.opt @@ -1 +1 @@ --O max_allowed_packet=1024 -O net_buffer_length=1024 +-O max_allowed_packet=1024 -O net_buffer_length=1024 -O slave_max_allowed_packet=1024 diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index 3197b6160cd..7fbea87f71e 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -11,9 +11,8 @@ # max-out size db name source include/master-slave.inc; source include/have_binlog_format_row.inc; -call mtr.add_suppression("Slave I/O: Got a packet bigger than 'max_allowed_packet' bytes, Error_code: 1153"); -call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log:"); - +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'slave_max_allowed_packet' bytes, Error_code: 1153"); +call mtr.add_suppression("Log entry on master is longer than slave_max_allowed_packet"); let $db= DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; disable_warnings; eval drop database if exists $db; @@ -23,6 +22,7 @@ eval create database $db; connection master; let $old_max_allowed_packet= `SELECT @@global.max_allowed_packet`; let $old_net_buffer_length= `SELECT @@global.net_buffer_length`; +let $old_slave_max_allowed_packet= `SELECT @@global.slave_max_allowed_packet`; SET @@global.max_allowed_packet=1024; SET @@global.net_buffer_length=1024; @@ -124,8 +124,8 @@ INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), R connection slave; # The slave I/O thread must stop after receiving -# 1236=ER_MASTER_FATAL_ERROR_READING_BINLOG error message from master. ---let $slave_io_errno= 1236 +# 1153 = ER_NET_PACKET_TOO_LARGE +--let $slave_io_errno= 1153 --let $show_slave_io_error= 1 --source include/wait_for_slave_io_error.inc @@ -166,6 +166,7 @@ connection master; DROP TABLE t1; eval SET @@global.max_allowed_packet= $old_max_allowed_packet; eval SET @@global.net_buffer_length= $old_net_buffer_length; +eval SET @@global.slave_max_allowed_packet= $old_slave_max_allowed_packet; # slave is stopped connection slave; DROP TABLE t1; diff --git a/mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc b/mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc new file mode 100644 index 00000000000..4caaae84906 --- /dev/null +++ b/mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc @@ -0,0 +1,177 @@ +############## mysql-test\t\slave_max_allowed_packet_basic.test ################## +# # +# Variable Name: slave_max_allowed_packet # +# Scope: GLOBAL # +# Access Type: Dynamic # +# Data Type: numeric # +# Default Value:1073741824 # +# Range: 1024 - 1073741824 # +# # +# # +# # +# Description: Test Cases of Dynamic System Variable slave_max_allowed_packet # +# that checks the behavior of this variable in the following ways# +# * Default Value # +# * Valid & Invalid values # +# * Scope & Access method # +# * Data Integrity # +# # +############################################################################### + +--source include/load_sysvars.inc + +######################################################################## +# START OF slave_max_allowed_packet TESTS # +######################################################################## + + +########################################################################### +# Saving initial value of slave_max_allowed_packet in a temporary variable# +########################################################################### + +SET @start_value = @@global.slave_max_allowed_packet; +SELECT @start_value; + + +--echo '#--------------------FN_DYNVARS_072_01------------------------#' +######################################################################## +# Display the DEFAULT value of slave_max_allowed_packet # +######################################################################## + +SET @@global.slave_max_allowed_packet = 5000; +SET @@global.slave_max_allowed_packet = DEFAULT; +SELECT @@global.slave_max_allowed_packet; + + +--echo '#---------------------FN_DYNVARS_072_02-------------------------#' +############################################### +# Verify default value of variable # +############################################### + +SET @@global.slave_max_allowed_packet = @start_value; +SELECT @@global.slave_max_allowed_packet = 1073741824; +--echo 'Bug# 34876: Incorrect Default Value is assigned to variable'; + +--echo '#--------------------FN_DYNVARS_072_03------------------------#' +######################################################################## +# Change the value of slave_max_allowed_packet to a valid value # +######################################################################## + +SET @@global.slave_max_allowed_packet = 1024; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1073741824; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1073741824; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1025; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 65535; +SELECT @@global.slave_max_allowed_packet; +--echo 'Bug# 34877: Invalid Values are coming in variable on assigning valid values'; + + +--echo '#--------------------FN_DYNVARS_072_04-------------------------#' +########################################################################### +# Change the value of slave_max_allowed_packet to invalid value # +########################################################################### + +SET @@global.slave_max_allowed_packet = -1; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 100000000000; +SELECT @@global.slave_max_allowed_packet; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.slave_max_allowed_packet = 10000.01; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = -1024; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 4294967296; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1023; +SELECT @@global.slave_max_allowed_packet; + +--echo 'Bug # 34837: Errors are not coming on assigning invalid values to variable'; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.slave_max_allowed_packet = ON; +SELECT @@global.slave_max_allowed_packet; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.slave_max_allowed_packet = 'test'; +SELECT @@global.slave_max_allowed_packet; + + +--echo '#-------------------FN_DYNVARS_072_05----------------------------#' +########################################################################### +# Test if accessing session slave_max_allowed_packet gives error # +########################################################################### + +--Error ER_GLOBAL_VARIABLE +SET @@session.slave_max_allowed_packet = 4096; +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.slave_max_allowed_packet; + + +--echo '#----------------------FN_DYNVARS_072_06------------------------#' +############################################################################## +# Check if the value in GLOBAL & SESSION Tables matches values in variable # +############################################################################## + +SELECT @@global.slave_max_allowed_packet = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='slave_max_allowed_packet'; + +SELECT @@slave_max_allowed_packet = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.SESSION_VARIABLES +WHERE VARIABLE_NAME='slave_max_allowed_packet'; + + +--echo '#---------------------FN_DYNVARS_072_07----------------------#' +################################################################### +# Check if TRUE and FALSE values can be used on variable # +################################################################### + +SET @@global.slave_max_allowed_packet = TRUE; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = FALSE; +SELECT @@global.slave_max_allowed_packet; + + +--echo '#---------------------FN_DYNVARS_072_08----------------------#' +######################################################################################################## +# Check if accessing variable with SESSION,LOCAL and without SCOPE points to same session variable # +######################################################################################################## + +SET @@global.slave_max_allowed_packet = 5000; +SELECT @@slave_max_allowed_packet = @@global.slave_max_allowed_packet; + + +--echo '#---------------------FN_DYNVARS_072_09----------------------#' +################################################################################ +# Check if slave_max_allowed_packet can be accessed with and without @@ sign # +################################################################################ + +--Error ER_GLOBAL_VARIABLE +SET slave_max_allowed_packet = 6000; +SELECT @@slave_max_allowed_packet; +--Error ER_PARSE_ERROR +SET local.slave_max_allowed_packet = 7000; +--Error ER_UNKNOWN_TABLE +SELECT local.slave_max_allowed_packet; +--Error ER_PARSE_ERROR +SET global.slave_max_allowed_packet = 8000; +--Error ER_UNKNOWN_TABLE +SELECT global.slave_max_allowed_packet; +--Error ER_BAD_FIELD_ERROR +SELECT slave_max_allowed_packet = @@session.slave_max_allowed_packet; + + +############################## +# Restore initial value # +############################## + +SET @@global.slave_max_allowed_packet = @start_value; +SELECT @@global.slave_max_allowed_packet; + + +######################################################################## +# END OF slave_max_allowed_packet TESTS # +######################################################################## diff --git a/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result b/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result index ca5b87f19cb..810ddb00b79 100644 --- a/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result +++ b/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result @@ -7,6 +7,7 @@ SET @@global.max_allowed_packet = DEFAULT; SET @@global.max_allowed_packet = 1000; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '1000' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SET @@global.max_allowed_packet = DEFAULT; SELECT @@global.max_allowed_packet; @@global.max_allowed_packet @@ -25,10 +26,14 @@ SELECT @@global.max_allowed_packet = 1048576; 1 '#--------------------FN_DYNVARS_070_03-------------------------#' SET @@global.max_allowed_packet = 1024; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = 1025; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 @@ -71,18 +76,21 @@ SELECT @@session.max_allowed_packet; SET @@global.max_allowed_packet = 0; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '0' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = -1024; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '-1024' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = 1023; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '1023' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 @@ -146,17 +154,21 @@ WHERE VARIABLE_NAME='max_allowed_packet'; SET @@global.max_allowed_packet = TRUE; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '1' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = FALSE; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '0' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 '#---------------------FN_DYNVARS_070_09----------------------#' SET @@global.max_allowed_packet = 2048; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@max_allowed_packet = @@global.max_allowed_packet; @@max_allowed_packet = @@global.max_allowed_packet 0 diff --git a/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result b/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result index 0d682b65aea..a202701b60f 100644 --- a/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result +++ b/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result @@ -23,6 +23,8 @@ SELECT @@session.net_buffer_length; '#--------------------FN_DYNVARS_070_02-------------------------#' ## Setting value of max_allowed packet and net_buffer_length to 1024 ## SET @@global.max_allowed_packet = 1024; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SET @@global.net_buffer_length = 1024; SELECT @@global.max_allowed_packet; @@global.max_allowed_packet diff --git a/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result b/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result index 07f933b5a4b..026c883e501 100644 --- a/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result +++ b/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result @@ -63,12 +63,14 @@ SELECT @@global.net_buffer_length; SET @@global.net_buffer_length = 1048577; Warnings: Warning 1292 Truncated incorrect net_buffer_length value: '1048577' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.net_buffer_length; @@global.net_buffer_length 1048576 SET @@global.net_buffer_length = 104857633; Warnings: Warning 1292 Truncated incorrect net_buffer_length value: '104857633' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.net_buffer_length; @@global.net_buffer_length 1048576 diff --git a/mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test b/mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test new file mode 100644 index 00000000000..5b6a557738b --- /dev/null +++ b/mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test @@ -0,0 +1,3 @@ +--source suite/sys_vars/inc/slave_max_allowed_packet_basic.inc + + diff --git a/sql/log_event.cc b/sql/log_event.cc index afcc283a6d1..958b7e4ef36 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1122,7 +1122,7 @@ failed my_b_read")); Log_event *res= 0; #ifndef max_allowed_packet THD *thd=current_thd; - uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~(ulong)0; + uint max_allowed_packet= thd ? slave_max_allowed_packet:~(ulong)0; #endif if (data_len > max_allowed_packet) diff --git a/sql/log_event.h b/sql/log_event.h index 4c80148458c..39cd55f313e 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -275,6 +275,13 @@ struct sql_ex_info MAX_SIZE_LOG_EVENT_STATUS + /* status */ \ NAME_LEN + 1) +/* + The new option is added to handle large packets that are sent from the master + to the slave. It is used to increase the thd(max_allowed) for both the + DUMP thread on the master and the SQL/IO thread on the slave. +*/ +#define MAX_MAX_ALLOWED_PACKET 1024*1024*1024 + /* Event header offsets; these point to places inside the fixed header. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 359e84a3370..937617032dd 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1944,6 +1944,7 @@ extern ulong slave_net_timeout, slave_trans_retries; extern uint max_user_connections; extern ulong what_to_log,flush_time; extern ulong query_buff_size; +extern ulong slave_max_allowed_packet; extern ulong max_prepared_stmt_count, prepared_stmt_count; extern ulong binlog_cache_size, open_files_limit; extern ulonglong max_binlog_cache_size; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4a80fd043c8..db73504cb17 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -28,6 +28,7 @@ #include "mysys_err.h" #include "events.h" #include "debug_sync.h" +#include "log_event.h" #include "../storage/myisam/ha_myisam.h" @@ -574,6 +575,7 @@ static const char *slave_exec_mode_str= "STRICT"; ulong thread_cache_size=0, thread_pool_size= 0; ulong binlog_cache_size=0; ulonglong max_binlog_cache_size=0; +ulong slave_max_allowed_packet= 0; ulong query_cache_size=0; ulong refresh_version; /* Increments on each reload */ query_id_t global_query_id; @@ -5572,6 +5574,7 @@ enum options_mysqld OPT_KEY_CACHE_DIVISION_LIMIT, OPT_KEY_CACHE_AGE_THRESHOLD, OPT_LONG_QUERY_TIME, OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET, + OPT_SLAVE_MAX_ALLOWED_PACKET, OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE, OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS, OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE, @@ -6700,6 +6703,10 @@ thread is in the relay logs.", &global_system_variables.max_allowed_packet, &max_system_variables.max_allowed_packet, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, + {"slave_max_allowed_packet", OPT_SLAVE_MAX_ALLOWED_PACKET, + "The maximum packet length to sent successfully from the master to slave.", + &slave_max_allowed_packet, &slave_max_allowed_packet, 0, GET_ULONG, + REQUIRED_ARG, MAX_MAX_ALLOWED_PACKET, 1024, MAX_MAX_ALLOWED_PACKET, MALLOC_OVERHEAD, 1024, 0}, {"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE, "Can be used to restrict the total size used to cache a multi-transaction query.", &max_binlog_cache_size, &max_binlog_cache_size, 0, diff --git a/sql/set_var.cc b/sql/set_var.cc index d9133a25d98..bbc47c2d7e8 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -366,6 +366,8 @@ static sys_var_const sys_lower_case_table_names(&vars, static sys_var_thd_ulong_session_readonly sys_max_allowed_packet(&vars, "max_allowed_packet", &SV::max_allowed_packet, check_max_allowed_packet); +static sys_var_long_ptr sys_slave_max_allowed_packet(&vars, "slave_max_allowed_packet", + &slave_max_allowed_packet); static sys_var_ulonglong_ptr sys_max_binlog_cache_size(&vars, "max_binlog_cache_size", &max_binlog_cache_size); static sys_var_long_ptr sys_max_binlog_size(&vars, "max_binlog_size", diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 7cb9d9ebcc1..99bae298e49 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -3512,23 +3512,23 @@ ER_ABORTING_CONNECTION 08S01 swe "Avbröt länken för tråd %ld till db '%-.192s', användare '%-.48s' (%-.64s)" ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.192s' ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s' (%-.64s)" ER_NET_PACKET_TOO_LARGE 08S01 - cze "Zji-B¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'" - dan "Modtog en datapakke som var større end 'max_allowed_packet'" - nla "Groter pakket ontvangen dan 'max_allowed_packet'" - eng "Got a packet bigger than 'max_allowed_packet' bytes" - est "Saabus suurem pakett kui lubatud 'max_allowed_packet' muutujaga" - fre "Paquet plus grand que 'max_allowed_packet' reçu" - ger "Empfangenes Paket ist größer als 'max_allowed_packet' Bytes" - hun "A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'max_allowed_packet'" - ita "Ricevuto un pacchetto piu` grande di 'max_allowed_packet'" - kor "'max_allowed_packet'º¸´Ù ´õÅ« ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù." - por "Obteve um pacote maior do que a taxa máxima de pacotes definida (max_allowed_packet)" - rum "Un packet mai mare decit 'max_allowed_packet' a fost primit" - rus "ðÏÌÕÞÅÎÎÙÊ ÐÁËÅÔ ÂÏÌØÛÅ, ÞÅÍ 'max_allowed_packet'" - serbian "Primio sam mrežni paket veæi od definisane vrednosti 'max_allowed_packet'" - spa "Obtenido un paquete mayor que 'max_allowed_packet'" - swe "Kommunkationspaketet är större än 'max_allowed_packet'" - ukr "ïÔÒÉÍÁÎÏ ÐÁËÅÔ Â¦ÌØÛÉÊ Î¦Ö max_allowed_packet" + cze "Zji-B¹tìn pøíchozí packet del¹í ne¾ 'slave_max_allowed_packet'" + dan "Modtog en datapakke som var større end 'slave_max_allowed_packet'" + nla "Groter pakket ontvangen dan 'slave_max_allowed_packet'" + eng "Got a packet bigger than 'slave_max_allowed_packet' bytes" + est "Saabus suurem pakett kui lubatud 'slave_max_allowed_packet' muutujaga" + fre "Paquet plus grand que 'slave_max_allowed_packet' reçu" + ger "Empfangenes Paket ist größer als 'slave_max_allowed_packet' Bytes" + hun "A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'slave_max_allowed_packet'" + ita "Ricevuto un pacchetto piu` grande di 'slave_max_allowed_packet'" + kor "'slave_max_allowed_packet'º¸´Ù ´õÅ« ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù." + por "Obteve um pacote maior do que a taxa máxima de pacotes definida (slave_max_allowed_packet)" + rum "Un packet mai mare decit 'slave_max_allowed_packet' a fost primit" + rus "ðÏÌÕÞÅÎÎÙÊ ÐÁËÅÔ ÂÏÌØÛÅ, ÞÅÍ 'slave_max_allowed_packet'" + serbian "Primio sam mrežni paket veæi od definisane vrednosti 'slave_max_allowed_packet'" + spa "Obtenido un paquete mayor que 'slave_max_allowed_packet'" + swe "Kommunkationspaketet är större än 'slave_max_allowed_packet'" + ukr "ïÔÒÉÍÁÎÏ ÐÁËÅÔ Â¦ÌØÛÉÊ Î¦Ö slave_max_allowed_packet" ER_NET_READ_ERROR_FROM_PIPE 08S01 cze "Zji-B¹tìna chyba pøi ètení z roury spojení" dan "Fik læsefejl fra forbindelse (connection pipe)" diff --git a/sql/slave.cc b/sql/slave.cc index 437762cc318..b555d4351c9 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1884,8 +1884,8 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) slave threads, since a replication event can become this much larger than the corresponding packet (query) sent from client to master. */ - thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet - + MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */ + thd->variables.max_allowed_packet= slave_max_allowed_packet; + thd->net.max_packet_size= slave_max_allowed_packet; thd->slave_thread = 1; thd->enable_slow_log= opt_log_slow_slave_statements; set_slave_thread_options(thd); @@ -2630,6 +2630,7 @@ pthread_handler_t handle_slave_io(void *arg) thread, since a replication event can become this much larger than the corresponding packet (query) sent from client to master. */ + thd->net.max_packet_size= slave_max_allowed_packet; mysql->net.max_packet_size= thd->net.max_packet_size+= MAX_LOG_EVENT_HEADER; } else @@ -2761,10 +2762,10 @@ reading event")) switch (mysql_error_number) { case CR_NET_PACKET_TOO_LARGE: sql_print_error("\ -Log entry on master is longer than max_allowed_packet (%ld) on \ +Log entry on master is longer than slave_max_allowed_packet (%lu) on \ slave. If the entry is correct, restart the server with a higher value of \ -max_allowed_packet", - thd->variables.max_allowed_packet); +slave_max_allowed_packet", + slave_max_allowed_packet); mi->report(ERROR_LEVEL, ER_NET_PACKET_TOO_LARGE, "%s", ER(ER_NET_PACKET_TOO_LARGE)); goto err; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index c92d2db2c1e..e3188def206 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -469,7 +469,7 @@ impossible position"; this larger than the corresponding packet (query) sent from client to master. */ - thd->variables.max_allowed_packet+= MAX_LOG_EVENT_HEADER; + thd->variables.max_allowed_packet= ULONG_MAX; /* We can set log_lock now, it does not move (it's a member of From 4f106324c1321264af256a738c8bf423a95ef0d4 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Fri, 8 Jun 2012 16:31:03 +0200 Subject: [PATCH 02/44] Backport SuSE 11 fix to RPM spec file --- support-files/mysql.spec.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index a3d8554188e..5b9a296d90a 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -176,7 +176,7 @@ %endif %else %if %(test -f /etc/SuSE-release && echo 1 || echo 0) - %define susever %(rpm -qf --qf '%%{version}\\n' /etc/SuSE-release) + %define susever %(rpm -qf --qf '%%{version}\\n' /etc/SuSE-release | cut -d. -f1) %if "%susever" == "10" %define distro_description SUSE Linux Enterprise Server 10 %define distro_releasetag sles10 From 6aab1cececaf726c192048ae6d9e18247def696a Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Tue, 12 Jun 2012 15:04:57 +0200 Subject: [PATCH 03/44] Bug#13586591 RQG GRAMMAR CONF/ENGINES/ENGINE_STRESS.YY CRASHES INNODB | TRX_STATE_NOT_STARTED The problem was that if DELETE with subselect caused a deadlock inside InnoDB, this deadlock was not properly handled by the SQL layer. This meant that the SQL layer would try to unlock the row after InnoDB had rolled back the transaction. This caused an assertion inside InnoDB. This patch fixes the problem by checking for errors reported by SQL_SELECT::skip_record() and not calling unlock_row() if any errors have been reported. --- sql/sql_delete.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 4fd1815ad7f..1bbc9af0835 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -341,8 +341,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, break; } } - else + /* + Don't try unlocking the row if skip_record reported an error since in + this case the transaction might have been rolled back already. + */ + else if (!thd->is_error()) table->file->unlock_row(); // Row failed selection, release lock on it + else + break; } killed_status= thd->killed; if (killed_status != THD::NOT_KILLED || thd->is_error()) From 3ec0a7eb045d027cdf860228fa9b4d88f1f52b4e Mon Sep 17 00:00:00 2001 From: Harin Vadodaria Date: Wed, 13 Jun 2012 16:03:58 +0530 Subject: [PATCH 04/44] Bug#11753779: MAX_CONNECT_ERRORS WORKS ONLY WHEN 1ST INC_HOST_ERRORS() IS CALLED. Issue : Sequence of calling inc_host_errors() and reset_host_errors() required some changes in order to maintain correct connection error count. Solution : Call to reset_host_errors() is shifted to a location after which no calls to inc_host_errors() are made. --- sql/hostname.cc | 9 ++++++++ sql/sql_connect.cc | 54 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/sql/hostname.cc b/sql/hostname.cc index 9796755e9fb..38316a8ee19 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -214,6 +214,15 @@ char * ip_to_hostname(struct in_addr *in, uint *errors) } my_gethostbyname_r_free(); #else + + DBUG_EXECUTE_IF("addr_fake_ipv4", + { + const char* fake_host= "santa.claus.ipv4.example.com"; + name=my_strdup(fake_host, MYF(0)); + add_hostname(in,name); + DBUG_RETURN(name); + };); + VOID(pthread_mutex_lock(&LOCK_hostname)); if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET))) { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 21e2701d06c..7a934541d53 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -360,7 +360,6 @@ check_user(THD *thd, enum enum_server_command command, if (send_old_password_request(thd) || my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) { - inc_host_errors(&thd->remote.sin_addr); my_error(ER_HANDSHAKE_ERROR, MYF(0)); DBUG_RETURN(1); } @@ -832,6 +831,19 @@ static int check_connection(THD *thd) my_error(ER_BAD_HOST_ERROR, MYF(0)); return 1; } + /* BEGIN : DEBUG */ + DBUG_EXECUTE_IF("addr_fake_ipv4", + { + struct sockaddr *sa= (sockaddr *) &net->vio->remote; + sa->sa_family= AF_INET; + struct in_addr *ip4= &((struct sockaddr_in *)sa)->sin_addr; + /* See RFC 5737, 192.0.2.0/23 is reserved */ + const char* fake= "192.0.2.4"; + ip4->s_addr= inet_addr(fake); + strcpy(ip, fake); + };); + /* END : DEBUG */ + if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; @@ -935,8 +947,6 @@ static int check_connection(THD *thd) #ifdef _CUSTOMCONFIG_ #include "_cust_sql_parse.h" #endif - if (connect_errors) - reset_host_errors(&thd->remote.sin_addr); if (thd->packet.alloc(thd->variables.net_buffer_length)) return 1; /* The error is set by alloc(). */ @@ -953,6 +963,10 @@ static int check_connection(THD *thd) Peek ahead on the client capability packet and determine which version of the protocol should be used. */ + DBUG_EXECUTE_IF("host_error_packet_length", + { + bytes_remaining_in_packet= 0; + };); if (bytes_remaining_in_packet < 2) goto error; @@ -1011,6 +1025,10 @@ static int check_connection(THD *thd) skip_to_ssl: + DBUG_EXECUTE_IF("host_error_charset", + { + goto error; + };); DBUG_PRINT("info", ("client_character_set: %u", charset_code)); if (thd_init_client_charset(thd, charset_code)) goto error; @@ -1079,6 +1097,10 @@ skip_to_ssl: bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_40; } + DBUG_EXECUTE_IF("host_error_SSL_layering", + { + packet_has_required_size= 0; + };); if (!packet_has_required_size) goto error; } @@ -1104,6 +1126,11 @@ skip_to_ssl: get_string= get_40_protocol_string; user= get_string(&end, &bytes_remaining_in_packet, &user_len); + DBUG_EXECUTE_IF("host_error_user", + { + user= NULL; + };); + if (user == NULL) goto error; @@ -1131,6 +1158,11 @@ skip_to_ssl: passwd= get_string(&end, &bytes_remaining_in_packet, &passwd_len); } + DBUG_EXECUTE_IF("host_error_password", + { + passwd= NULL; + };); + if (passwd == NULL) goto error; @@ -1191,7 +1223,21 @@ skip_to_ssl: if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ - return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); + + if (!check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE)) + { + /* + Call to reset_host_errors() should be made only when all sanity checks + are done and connection is going to be a successful. + */ + reset_host_errors(&thd->remote.sin_addr); + return 0; + } + else + { + inc_host_errors(&thd->remote.sin_addr); + return 1; + } error: inc_host_errors(&thd->remote.sin_addr); From c2d38c306f11d122683b64fcee41deec16996472 Mon Sep 17 00:00:00 2001 From: "sayantan.dutta@oracle.com" <> Date: Thu, 14 Jun 2012 17:07:49 +0530 Subject: [PATCH 05/44] BUG #13946716: FEDERATED_PLUGIN TEST CASE FAIL ON 64BIT ARCHITECTURES --- mysql-test/mysql-test-run.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 294dcf13615..674abe7e102 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1969,6 +1969,7 @@ sub environment_setup { my $lib_example_plugin= mtr_file_exists(vs_config_dirs('storage/example',$plugin_filename), "$basedir/storage/example/.libs/".$plugin_filename, + "$basedir/lib64/mysql/plugin/".$plugin_filename, "$basedir/lib/mysql/plugin/".$plugin_filename); $ENV{'EXAMPLE_PLUGIN'}= ($lib_example_plugin ? basename($lib_example_plugin) : ""); @@ -1991,6 +1992,7 @@ sub environment_setup { my $lib_fed_plugin= mtr_file_exists(vs_config_dirs('storage/federated',$fedplug_filename), "$basedir/storage/federated/.libs/".$fedplug_filename, + "$basedir/lib64/mysql/plugin/".$fedplug_filename, "$basedir/lib/mysql/plugin/".$fedplug_filename); $ENV{'FEDERATED_PLUGIN'}= $fedplug_filename; From 36b2d459ba319fb7a9e837342c5733a5880a5cad Mon Sep 17 00:00:00 2001 From: Sunanda Menon Date: Fri, 15 Jun 2012 10:34:18 +0200 Subject: [PATCH 06/44] Raising the VERSION number after 5.5.26 clone-off --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a6ecc1acc76..2ac736f0617 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=26 +MYSQL_VERSION_PATCH=27 MYSQL_VERSION_EXTRA= From 2d16ce2b52744eb09261009c06907fe7540a6180 Mon Sep 17 00:00:00 2001 From: "kent.boortz@oracle.com" <> Date: Fri, 15 Jun 2012 13:31:27 +0200 Subject: [PATCH 07/44] Raise version number after cloning 5.1.64 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 84295a15f4a..4e7a3303353 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.64], [], [mysql]) +AC_INIT([MySQL Server], [5.1.65], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 5f61cc438ba490a6de65733aa41c1b60f095a2f6 Mon Sep 17 00:00:00 2001 From: "Norvald H. Ryeng" Date: Mon, 18 Jun 2012 09:20:12 +0200 Subject: [PATCH 08/44] Bug#13003736 CRASH IN ITEM_REF::WALK WITH SUBQUERIES Problem: Some queries with subqueries and a HAVING clause that consists only of a column not in the select or grouping lists causes the server to crash. During parsing, an Item_ref is constructed for the HAVING column. The name of the column is resolved when JOIN::prepare calls fix_fields() on its having clause. Since the column is not mentioned in the select or grouping lists, a ref pointer is not found and a new Item_field is created instead. The Item_ref is replaced by the Item_field in the tree of HAVING clauses. Since the tree consists only of this item, the pointer that is updated is JOIN::having. However, st_select_lex::having still points to the Item_ref as the root of the tree of HAVING clauses. The bug is triggered when doing filesort for create_sort_index(). When find_all_keys() calls select->cond->walk() it eventually reaches Item_subselect::walk() where it continues to walk the having clauses from lex->having. This means that it finds the Item_ref instead of the new Item_field, and Item_ref::walk() tries to dereference the ref pointer, which is still null. The crash is reproducible only in 5.5, but the problem lies latent in 5.1 and trunk as well. Fix: After calling fix_fields on the having clause in JOIN::prepare(), set select_lex::having to point to the same item as JOIN::having. This patch also fixes a bug in 5.1 and 5.5 that is triggered if the query is executed as a prepared statement. The Item_field is created in the runtime arena when the query is prepared, and the pointer to the item is saved by st_select_lex::fix_prepare_information() and brought back as a dangling pointer when the query is executed, after the runtime arena has been reclaimed. Fix: Backport fix from trunk that switches to the permanent arena before calling Item_ref::fix_fields() in JOIN::prepare(). --- sql/item.cc | 2 +- sql/sql_select.cc | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/item.cc b/sql/item.cc index 90bfb0d2852..356fe4827c8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6010,7 +6010,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) if (from_field != not_found_field) { Item_field* fld; - if (!(fld= new Item_field(from_field))) + if (!(fld= new Item_field(thd, last_checked_context, from_field))) goto error; thd->change_item_tree(reference, fld); mark_as_dependent(thd, last_checked_context->select_lex, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7c3d2de22bc..f2007f609e0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -528,6 +528,8 @@ JOIN::prepare(Item ***rref_pointer_array, if (having) { + Query_arena backup, *arena; + arena= thd->activate_stmt_arena_if_needed(&backup); nesting_map save_allow_sum_func= thd->lex->allow_sum_func; thd->where="having clause"; thd->lex->allow_sum_func|= 1 << select_lex_arg->nest_level; @@ -536,6 +538,10 @@ JOIN::prepare(Item ***rref_pointer_array, (having->fix_fields(thd, &having) || having->check_cols(1))); select_lex->having_fix_field= 0; + select_lex->having= having; + if (arena) + thd->restore_active_arena(arena, &backup); + if (having_fix_rc || thd->is_error()) DBUG_RETURN(-1); /* purecov: inspected */ thd->lex->allow_sum_func= save_allow_sum_func; From 78dce2d5c2e891151829724131953d14857f1167 Mon Sep 17 00:00:00 2001 From: Harin Vadodaria Date: Tue, 19 Jun 2012 12:56:40 +0530 Subject: [PATCH 09/44] Bug#11753779: MAX_CONNECT_ERRORS WORKS ONLY WHEN 1ST INC_HOST_ERRORS() IS CALLED. Description: Reverting patch 3755 for bug#11753779 --- sql/hostname.cc | 9 -------- sql/sql_connect.cc | 54 ++++------------------------------------------ 2 files changed, 4 insertions(+), 59 deletions(-) diff --git a/sql/hostname.cc b/sql/hostname.cc index 38316a8ee19..9796755e9fb 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -214,15 +214,6 @@ char * ip_to_hostname(struct in_addr *in, uint *errors) } my_gethostbyname_r_free(); #else - - DBUG_EXECUTE_IF("addr_fake_ipv4", - { - const char* fake_host= "santa.claus.ipv4.example.com"; - name=my_strdup(fake_host, MYF(0)); - add_hostname(in,name); - DBUG_RETURN(name); - };); - VOID(pthread_mutex_lock(&LOCK_hostname)); if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET))) { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 7a934541d53..21e2701d06c 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -360,6 +360,7 @@ check_user(THD *thd, enum enum_server_command command, if (send_old_password_request(thd) || my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) { + inc_host_errors(&thd->remote.sin_addr); my_error(ER_HANDSHAKE_ERROR, MYF(0)); DBUG_RETURN(1); } @@ -831,19 +832,6 @@ static int check_connection(THD *thd) my_error(ER_BAD_HOST_ERROR, MYF(0)); return 1; } - /* BEGIN : DEBUG */ - DBUG_EXECUTE_IF("addr_fake_ipv4", - { - struct sockaddr *sa= (sockaddr *) &net->vio->remote; - sa->sa_family= AF_INET; - struct in_addr *ip4= &((struct sockaddr_in *)sa)->sin_addr; - /* See RFC 5737, 192.0.2.0/23 is reserved */ - const char* fake= "192.0.2.4"; - ip4->s_addr= inet_addr(fake); - strcpy(ip, fake); - };); - /* END : DEBUG */ - if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; @@ -947,6 +935,8 @@ static int check_connection(THD *thd) #ifdef _CUSTOMCONFIG_ #include "_cust_sql_parse.h" #endif + if (connect_errors) + reset_host_errors(&thd->remote.sin_addr); if (thd->packet.alloc(thd->variables.net_buffer_length)) return 1; /* The error is set by alloc(). */ @@ -963,10 +953,6 @@ static int check_connection(THD *thd) Peek ahead on the client capability packet and determine which version of the protocol should be used. */ - DBUG_EXECUTE_IF("host_error_packet_length", - { - bytes_remaining_in_packet= 0; - };); if (bytes_remaining_in_packet < 2) goto error; @@ -1025,10 +1011,6 @@ static int check_connection(THD *thd) skip_to_ssl: - DBUG_EXECUTE_IF("host_error_charset", - { - goto error; - };); DBUG_PRINT("info", ("client_character_set: %u", charset_code)); if (thd_init_client_charset(thd, charset_code)) goto error; @@ -1097,10 +1079,6 @@ skip_to_ssl: bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_40; } - DBUG_EXECUTE_IF("host_error_SSL_layering", - { - packet_has_required_size= 0; - };); if (!packet_has_required_size) goto error; } @@ -1126,11 +1104,6 @@ skip_to_ssl: get_string= get_40_protocol_string; user= get_string(&end, &bytes_remaining_in_packet, &user_len); - DBUG_EXECUTE_IF("host_error_user", - { - user= NULL; - };); - if (user == NULL) goto error; @@ -1158,11 +1131,6 @@ skip_to_ssl: passwd= get_string(&end, &bytes_remaining_in_packet, &passwd_len); } - DBUG_EXECUTE_IF("host_error_password", - { - passwd= NULL; - };); - if (passwd == NULL) goto error; @@ -1223,21 +1191,7 @@ skip_to_ssl: if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ - - if (!check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE)) - { - /* - Call to reset_host_errors() should be made only when all sanity checks - are done and connection is going to be a successful. - */ - reset_host_errors(&thd->remote.sin_addr); - return 0; - } - else - { - inc_host_errors(&thd->remote.sin_addr); - return 1; - } + return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); error: inc_host_errors(&thd->remote.sin_addr); From 0f7888f7cae3edac5e168aea44ba39b99aa29026 Mon Sep 17 00:00:00 2001 From: Evgeny Potemkin Date: Thu, 28 Jun 2012 16:53:45 +0400 Subject: [PATCH 10/44] Bug#14248833: UPDATE ON INNODB TABLE ENTERS RECURSION Introduction of cost based decision on filesort vs index for UPDATE statements changed detection of the fact that the index used to scan the table is being updated. The new design missed the case of index merge when there is no single index to check. That was worked until a recent change in InnoDB after which it went into infinite recursion if update of the used index wasn't properly detected. The fix consists of 'used key being updated' detection code from 5.1. --- sql/sql_update.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 754170e4c55..c4a95edcfc2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -450,6 +450,15 @@ int mysql_update(THD *thd, { // Check if we are modifying a key that we are used to search with: used_key_is_modified= is_key_used(table, used_index, table->write_set); } + else if (select && select->quick) + { + /* + select->quick != NULL and used_index == MAX_KEY happens for index + merge and should be handled in a different way. + */ + used_key_is_modified= (!select->quick->unique_key_range() && + select->quick->is_keys_used(table->write_set)); + } #ifdef WITH_PARTITION_STORAGE_ENGINE if (used_key_is_modified || order || From 428ff7f8a0b1abfbe34b617411da42ef4159ea7c Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 28 Jun 2012 18:38:55 +0300 Subject: [PATCH 11/44] Bug #13708485: malformed resultset packet crashes client Several fixes : * sql-common/client.c Added a validity check of the fields metadata packet sent by the server. Now libmysql will check if the length of the data sent by the server matches what's expected by the protocol before using the data. * client/mysqltest.cc Fixed the error handling code in mysqltest to avoid sending new commands when the reading the result set failed (and there are unread data in the pipe). * sql_common.h + libmysql/libmysql.c + sql-common/client.c unpack_fields() now generates a proper error when it fails. Added a new argument to this function to support the error generation. * sql/protocol.cc Added a debug trigger to cause the server to send a NULL insted of the packet expected by the client for testing purposes. --- client/mysqltest.cc | 4 +++- include/sql_common.h | 8 +++++--- libmysql/libmysql.c | 8 ++++---- sql-common/client.c | 15 ++++++++++++--- sql/protocol.cc | 4 +++- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 593bb8ea290..e595493ccf0 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -6848,6 +6848,8 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, */ if ((counter==0) && mysql_read_query_result(mysql)) { + /* we've failed to collect the result set */ + cn->pending= TRUE; handle_error(command, mysql_errno(mysql), mysql_error(mysql), mysql_sqlstate(mysql), ds); goto end; diff --git a/include/sql_common.h b/include/sql_common.h index 9e43d076ba9..b64277ce7e1 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2003-2004, 2006 MySQL AB +/* + Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,8 +24,9 @@ extern "C" { #endif extern CHARSET_INFO *default_client_charset_info; -MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, - my_bool default_value, uint server_capabilities); +MYSQL_FIELD *unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc, + uint fields, my_bool default_value, + uint server_capabilities); void free_rows(MYSQL_DATA *cur); void free_old_query(MYSQL *mysql); void end_server(MYSQL *mysql); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 562da594fea..5d153317150 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1254,7 +1254,7 @@ MYSQL_FIELD *cli_list_fields(MYSQL *mysql) return NULL; mysql->field_count= (uint) query->rows; - return unpack_fields(query,&mysql->field_alloc, + return unpack_fields(mysql, query,&mysql->field_alloc, mysql->field_count, 1, mysql->server_capabilities); } @@ -1314,7 +1314,7 @@ mysql_list_processes(MYSQL *mysql) if (!(fields = (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*) 0, protocol_41(mysql) ? 7 : 5))) DBUG_RETURN(NULL); - if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0, + if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc,field_count,0, mysql->server_capabilities))) DBUG_RETURN(0); mysql->status=MYSQL_STATUS_GET_RESULT; @@ -1891,7 +1891,7 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) if (!(fields_data= (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,7))) DBUG_RETURN(1); - if (!(stmt->fields= unpack_fields(fields_data,&stmt->mem_root, + if (!(stmt->fields= unpack_fields(mysql, fields_data,&stmt->mem_root, field_count,0, mysql->server_capabilities))) DBUG_RETURN(1); diff --git a/sql-common/client.c b/sql-common/client.c index 0df7c242969..51911d913c7 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1268,7 +1268,7 @@ static void cli_fetch_lengths(ulong *to, MYSQL_ROW column, ***************************************************************************/ MYSQL_FIELD * -unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, +unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, my_bool default_value, uint server_capabilities) { MYSQL_ROWS *row; @@ -1281,6 +1281,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, if (!result) { free_rows(data); /* Free old data */ + set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); DBUG_RETURN(0); } bzero((char*) field, (uint) sizeof(MYSQL_FIELD)*fields); @@ -1308,6 +1309,14 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, field->org_name_length= lengths[5]; /* Unpack fixed length parts */ + if (lengths[6] != 12) + { + /* malformed packet. signal an error. */ + free_rows(data); /* Free old data */ + set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate); + DBUG_RETURN(0); + } + pos= (uchar*) row->data[6]; field->charsetnr= uint2korr(pos); field->length= (uint) uint4korr(pos+2); @@ -2868,7 +2877,7 @@ get_info: if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5))) DBUG_RETURN(1); - if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, + if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc, (uint) field_count,0, mysql->server_capabilities))) DBUG_RETURN(1); diff --git a/sql/protocol.cc b/sql/protocol.cc index 5a727d94c46..a74f6084df4 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -620,6 +620,8 @@ bool Protocol::send_fields(List *list, uint flags) /* Store fixed length fields */ pos= (char*) local_packet->ptr()+local_packet->length(); *pos++= 12; // Length of packed fields + /* inject a NULL to test the client */ + DBUG_EXECUTE_IF("poison_rs_fields", pos[-1]= 0xfb;); if (item->collation.collation == &my_charset_bin || thd_charset == NULL) { /* No conversion */ From 62884afab552e96467b3da03d84f0c7c97eb43c9 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Thu, 28 Jun 2012 20:03:53 +0200 Subject: [PATCH 12/44] Bug#65745: UPDATE ON INNODB TABLE ENTERS RECURSION Introduction of cost based decision on filesort vs index for UPDATE statements changed detection of the fact that the index used to scan the table is being updated. The new design missed the case of index merge when there is no single index to check. That was worked until a recent change in InnoDB after which it went into infinite recursion if update of the used index wasn't properly detected. The fix consists of 'used key being updated' detection code from 5.1. Patch done by Evgeny Potemkin and transferred into the 5.5.25a release build by Joerg Bruehe. This changeset is the difference between MySQL 5.5.25 and 5.5.25a. --- VERSION | 2 +- sql/sql_update.cc | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6111f6d453f..48e6c183915 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=25 +MYSQL_VERSION_PATCH=25a MYSQL_VERSION_EXTRA= diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 754170e4c55..c4a95edcfc2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -450,6 +450,15 @@ int mysql_update(THD *thd, { // Check if we are modifying a key that we are used to search with: used_key_is_modified= is_key_used(table, used_index, table->write_set); } + else if (select && select->quick) + { + /* + select->quick != NULL and used_index == MAX_KEY happens for index + merge and should be handled in a different way. + */ + used_key_is_modified= (!select->quick->unique_key_range() && + select->quick->is_keys_used(table->write_set)); + } #ifdef WITH_PARTITION_STORAGE_ENGINE if (used_key_is_modified || order || From 5a2ae8f4ee1387bb818b4e53cef85e185755d22f Mon Sep 17 00:00:00 2001 From: Yasufumi Kinoshita Date: Fri, 29 Jun 2012 12:04:44 +0900 Subject: [PATCH 13/44] Bug#14251529 : FIX FOR BUG 13704145 CREATES POSSIBLE RACE CONDITION make buf_read_page_low() to treat DB_TABLESPACE_DELETED error correctly rb#1129 approved by Inaam --- storage/innobase/buf/buf0buf.c | 9 ++++-- storage/innobase/buf/buf0lru.c | 14 +++++++++ storage/innobase/buf/buf0rea.c | 48 +++++++++++++++++++++++++++++- storage/innobase/include/buf0buf.h | 5 ++-- 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index fed07129b65..32d376136e6 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -3470,9 +3470,10 @@ buf_mark_space_corrupt( /********************************************************************//** Completes an asynchronous read or write request of a file page to or from -the buffer pool. */ +the buffer pool. +@return TRUE if successful */ UNIV_INTERN -void +ibool buf_page_io_complete( /*=================*/ buf_page_t* bpage) /*!< in: pointer to the block in question */ @@ -3599,7 +3600,7 @@ corrupt: table as corrupted instead of crashing server */ if (bpage->space > TRX_SYS_SPACE && buf_mark_space_corrupt(bpage)) { - return; + return(FALSE); } else { fputs("InnoDB: Ending processing" " because of" @@ -3689,6 +3690,8 @@ corrupt: mutex_exit(buf_page_get_mutex(bpage)); buf_pool_mutex_exit(buf_pool); + + return(TRUE); } /*********************************************************************//** diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index 8e787fdba17..7c8100df58e 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -2164,9 +2164,23 @@ buf_LRU_free_one_page( be in a state where it can be freed; there may or may not be a hash index to the page */ { +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); +#endif + mutex_t* block_mutex = buf_page_get_mutex(bpage); + + ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(mutex_own(block_mutex)); + if (buf_LRU_block_remove_hashed_page(bpage, TRUE) != BUF_BLOCK_ZIP_FREE) { buf_LRU_block_free_hashed_page((buf_block_t*) bpage); + } else { + /* The block_mutex should have been released by + buf_LRU_block_remove_hashed_page() when it returns + BUF_BLOCK_ZIP_FREE. */ + ut_ad(block_mutex == &buf_pool->zip_mutex); + mutex_enter(block_mutex); } } diff --git a/storage/innobase/buf/buf0rea.c b/storage/innobase/buf/buf0rea.c index da804a66b29..40550186191 100644 --- a/storage/innobase/buf/buf0rea.c +++ b/storage/innobase/buf/buf0rea.c @@ -50,6 +50,44 @@ read-ahead is not done: this is to prevent flooding the buffer pool with i/o-fixed buffer blocks */ #define BUF_READ_AHEAD_PEND_LIMIT 2 +/********************************************************************//** +Unfixes the pages, unlatches the page, +removes it from page_hash and removes it from LRU. */ +static +void +buf_read_page_handle_error( +/*=======================*/ + buf_page_t* bpage) /*!< in: pointer to the block */ +{ + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + const ibool uncompressed = (buf_page_get_state(bpage) + == BUF_BLOCK_FILE_PAGE); + + /* First unfix and release lock on the bpage */ + buf_pool_mutex_enter(buf_pool); + mutex_enter(buf_page_get_mutex(bpage)); + ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ); + ut_ad(bpage->buf_fix_count == 0); + + /* Set BUF_IO_NONE before we remove the block from LRU list */ + buf_page_set_io_fix(bpage, BUF_IO_NONE); + + if (uncompressed) { + rw_lock_x_unlock_gen( + &((buf_block_t*) bpage)->lock, + BUF_IO_READ); + } + + /* remove the block from LRU list */ + buf_LRU_free_one_page(bpage); + + ut_ad(buf_pool->n_pend_reads > 0); + buf_pool->n_pend_reads--; + + mutex_exit(buf_page_get_mutex(bpage)); + buf_pool_mutex_exit(buf_pool); +} + /********************************************************************//** Low-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there, in which case does nothing. @@ -152,12 +190,20 @@ buf_read_page_low( ((buf_block_t*) bpage)->frame, bpage); } thd_wait_end(NULL); + + if (*err == DB_TABLESPACE_DELETED) { + buf_read_page_handle_error(bpage); + return(0); + } + ut_a(*err == DB_SUCCESS); if (sync) { /* The i/o is already completed when we arrive from fil_read */ - buf_page_io_complete(bpage); + if (!buf_page_io_complete(bpage)) { + return(0); + } } return(1); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 7c81fe0c539..a39592943d8 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -1162,9 +1162,10 @@ buf_page_init_for_read( ulint offset);/*!< in: page number */ /********************************************************************//** Completes an asynchronous read or write request of a file page to or from -the buffer pool. */ +the buffer pool. +@return TRUE if successful */ UNIV_INTERN -void +ibool buf_page_io_complete( /*=================*/ buf_page_t* bpage); /*!< in: pointer to the block in question */ From ba966cff983ff71fa0c88f6b6a8f15afbf0230f1 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 29 Jun 2012 12:55:45 +0400 Subject: [PATCH 14/44] Backport of the deprecation warning from WL#6219: "Deprecate and remove YEAR(2) type" Print the warning(note): YEAR(x) is deprecated and will be removed in a future release. Please use YEAR(4) instead on "CREATE TABLE ... YEAR(x)" or "ALTER TABLE MODIFY ... YEAR(x)", where x != 4 --- mysql-test/r/func_group.result | 2 ++ mysql-test/r/type_blob.result | 4 ++++ mysql-test/r/type_year.result | 15 +++++++++++++++ .../suite/engines/iuds/r/delete_year.result | 6 ++++++ .../suite/engines/iuds/r/insert_year.result | 12 ++++++++++++ .../suite/engines/iuds/r/update_year.result | 6 ++++++ mysql-test/suite/funcs_1/r/innodb_views.result | 4 ++++ .../suite/funcs_1/r/is_columns_innodb.result | 6 ++++++ .../suite/funcs_1/r/is_columns_memory.result | 6 ++++++ .../suite/funcs_1/r/is_columns_myisam.result | 6 ++++++ .../r/is_columns_myisam_embedded.result | 6 ++++++ mysql-test/suite/funcs_1/r/memory_views.result | 4 ++++ .../suite/funcs_1/r/myisam_views-big.result | 4 ++++ mysql-test/suite/funcs_1/r/ndb_views.result | 4 ++++ mysql-test/suite/funcs_1/r/storedproc.result | 4 ++++ .../innodb_plugin/r/innodb_bug52745.result | 1 + mysql-test/t/type_year.test | 8 ++++++++ sql/field.cc | 11 +++++++++++ sql/sql_yacc.yy | 18 +++++++++++++++++- 19 files changed, 126 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index b90eb2a4c0f..74899a22636 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1524,6 +1524,8 @@ DROP TABLE t1; # Bug#43668: Wrong comparison and MIN/MAX for YEAR(2) # create table t1 (f1 year(2), f2 year(4), f3 date, f4 datetime); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead insert into t1 values (98,1998,19980101,"1998-01-01 00:00:00"), (00,2000,20000101,"2000-01-01 00:00:01"), diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index e6fd49b4247..8b4b6438842 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -878,6 +878,8 @@ ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT CREATE TABLE b15776 (a char(4294967296)); ERROR 42000: Display width out of range for column 'a' (max = 4294967295) CREATE TABLE b15776 (a year(4294967295)); +Warnings: +Note 1287 'YEAR(4294967295)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO b15776 VALUES (42); SELECT * FROM b15776; a @@ -886,6 +888,8 @@ DROP TABLE b15776; CREATE TABLE b15776 (a year(4294967296)); ERROR 42000: Display width out of range for column 'a' (max = 4294967295) CREATE TABLE b15776 (a year(0)); +Warnings: +Note 1287 'YEAR(0)' is deprecated and will be removed in a future release. Please use YEAR(4) instead DROP TABLE b15776; CREATE TABLE b15776 (a year(-2)); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-2))' at line 1 diff --git a/mysql-test/r/type_year.result b/mysql-test/r/type_year.result index 2dc491c6166..e00569c93c1 100644 --- a/mysql-test/r/type_year.result +++ b/mysql-test/r/type_year.result @@ -1,5 +1,7 @@ drop table if exists t1; create table t1 (y year,y2 year(2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead insert into t1 values (0,0),(1999,1999),(2000,2000),(2001,2001),(70,70),(69,69); select * from t1; y y2 @@ -50,6 +52,8 @@ End of 5.0 tests # Bug #49480: WHERE using YEAR columns returns unexpected results # CREATE TABLE t2(yy YEAR(2), c2 CHAR(4)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(yyyy YEAR(4), c4 CHAR(4)); INSERT INTO t2 (c2) VALUES (NULL),(1970),(1999),(2000),(2001),(2069); INSERT INTO t4 (c4) SELECT c2 FROM t2; @@ -355,4 +359,15 @@ total_rows min_value MAX(c1) 3 0 2155 DROP TABLE t1; # +# WL#6219: Deprecate and remove YEAR(2) type +# +CREATE TABLE t1 (c1 YEAR(2), c2 YEAR(4)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +ALTER TABLE t1 MODIFY COLUMN c2 YEAR(2); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +DROP TABLE t1; +# End of 5.1 tests diff --git a/mysql-test/suite/engines/iuds/r/delete_year.result b/mysql-test/suite/engines/iuds/r/delete_year.result index 02cbe24ecc9..c82f0dae7d9 100644 --- a/mysql-test/suite/engines/iuds/r/delete_year.result +++ b/mysql-test/suite/engines/iuds/r/delete_year.result @@ -2,7 +2,13 @@ DROP TABLE IF EXISTS t1,t2,t3,t4; CREATE TABLE t1(c1 YEAR NOT NULL,c2 YEAR, PRIMARY KEY(c1)); CREATE TABLE t2(c1 YEAR NOT NULL, c2 YEAR, UNIQUE INDEX idx(c1,c2)); CREATE TABLE t3(c1 YEAR(2) NOT NULL,c2 YEAR(2), PRIMARY KEY(c1)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(c1 YEAR(2), c2 YEAR(2), UNIQUE INDEX idx(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO t1 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t2 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t3 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); diff --git a/mysql-test/suite/engines/iuds/r/insert_year.result b/mysql-test/suite/engines/iuds/r/insert_year.result index 386c8090434..b9618ba4e2d 100644 --- a/mysql-test/suite/engines/iuds/r/insert_year.result +++ b/mysql-test/suite/engines/iuds/r/insert_year.result @@ -3235,9 +3235,21 @@ c1 c2 c3 c4 1999 1999 1998-12-30 1998-12-30 11:30:45 DROP TABLE t1,t2,t3,t4; CREATE TABLE t1(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME, PRIMARY KEY(c1), UNIQUE INDEX(c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t2(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME, PRIMARY KEY(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t3(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME, UNIQUE INDEX idx(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO t1 VALUES('1901','1901','98-12-31','98.12.31 11:30:45'),('1999','1999','98-12-30','98.12.30 11:30:45'),('2000','2000','98-12-29','98.12.29 11:30:45'),('2001','2001','98-12-28','98.12.28 11:30:45'),('2099','2099','98-12-27','98.12.27 11:30:45'),('2100','2100','98-12-26','98.12.26 11:30:45'),('2155','2155','98-12-26','98.12.26 11:30:45'); INSERT INTO t2 VALUES('1901','1901','98-12-31','98.12.31 11:30:45'),('1999','1999','98-12-30','98.12.30 11:30:45'),('2000','2000','98-12-29','98.12.29 11:30:45'),('2001','2001','98-12-28','98.12.28 11:30:45'),('2099','2099','98-12-27','98.12.27 11:30:45'),('2100','2100','98-12-26','98.12.26 11:30:45'),('2155','2155','98-12-26','98.12.26 11:30:45'); INSERT INTO t3 VALUES('1901','1901','98-12-31','98.12.31 11:30:45'),('1999','1999','98-12-30','98.12.30 11:30:45'),('2000','2000','98-12-29','98.12.29 11:30:45'),('2001','2001','98-12-28','98.12.28 11:30:45'),('2099','2099','98-12-27','98.12.27 11:30:45'),('2100','2100','98-12-26','98.12.26 11:30:45'),('2155','2155','98-12-26','98.12.26 11:30:45'); diff --git a/mysql-test/suite/engines/iuds/r/update_year.result b/mysql-test/suite/engines/iuds/r/update_year.result index 1b0ead45314..c762d70a276 100644 --- a/mysql-test/suite/engines/iuds/r/update_year.result +++ b/mysql-test/suite/engines/iuds/r/update_year.result @@ -2,7 +2,13 @@ DROP TABLE IF EXISTS t1,t2,t3,t4; CREATE TABLE t1(c1 YEAR NOT NULL,c2 YEAR, PRIMARY KEY(c1)); CREATE TABLE t2(c1 YEAR NOT NULL, c2 YEAR, UNIQUE INDEX idx(c1,c2)); CREATE TABLE t3(c1 YEAR(2) NOT NULL,c2 YEAR(2), PRIMARY KEY(c1)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(c1 YEAR(2), c2 YEAR(2), UNIQUE INDEX idx(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO t1 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t2 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t3 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); diff --git a/mysql-test/suite/funcs_1/r/innodb_views.result b/mysql-test/suite/funcs_1/r/innodb_views.result index a335e135a4f..951068e3300 100644 --- a/mysql-test/suite/funcs_1/r/innodb_views.result +++ b/mysql-test/suite/funcs_1/r/innodb_views.result @@ -53,6 +53,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; DROP DATABASE IF EXISTS test1; @@ -112,6 +114,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_innodb.result b/mysql-test/suite/funcs_1/r/is_columns_innodb.result index 61079b06666..0abe8e11cf3 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_innodb.result +++ b/mysql-test/suite/funcs_1/r/is_columns_innodb.result @@ -132,6 +132,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; drop table if exists tb3 ; @@ -262,6 +264,8 @@ f239 varchar(20000) binary, f240 varchar(2000), f241 char(100) ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb4.txt' into table tb4; USE test1; @@ -319,6 +323,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_memory.result b/mysql-test/suite/funcs_1/r/is_columns_memory.result index 60dea25e0e3..c476b930f60 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_memory.result +++ b/mysql-test/suite/funcs_1/r/is_columns_memory.result @@ -128,6 +128,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; drop table if exists tb3; @@ -251,6 +253,8 @@ f238 varchar(25000) binary, f239 varbinary(0), f240 varchar(1200) ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb4.txt' into table tb4; USE test1; @@ -308,6 +312,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_myisam.result b/mysql-test/suite/funcs_1/r/is_columns_myisam.result index 6d0a44d2223..0e464d0fbc1 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_myisam.result +++ b/mysql-test/suite/funcs_1/r/is_columns_myisam.result @@ -144,6 +144,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; drop table if exists tb3 ; @@ -283,6 +285,8 @@ f240 varchar(120), f241 char(100), f242 bit(30) ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb4.txt' into table tb4; USE test1; @@ -348,6 +352,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result b/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result index 739f62e371a..7424ba8573d 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result +++ b/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result @@ -144,6 +144,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; drop table if exists tb3 ; @@ -283,6 +285,8 @@ f240 varchar(120), f241 char(100), f242 bit(30) ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb4.txt' into table tb4; USE test1; @@ -348,6 +352,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/memory_views.result b/mysql-test/suite/funcs_1/r/memory_views.result index ccbd086b71f..0bb03e62192 100644 --- a/mysql-test/suite/funcs_1/r/memory_views.result +++ b/mysql-test/suite/funcs_1/r/memory_views.result @@ -54,6 +54,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; DROP DATABASE IF EXISTS test1; @@ -113,6 +115,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; USE test; diff --git a/mysql-test/suite/funcs_1/r/myisam_views-big.result b/mysql-test/suite/funcs_1/r/myisam_views-big.result index 9b07a0ae45b..0afb1d7d6c8 100644 --- a/mysql-test/suite/funcs_1/r/myisam_views-big.result +++ b/mysql-test/suite/funcs_1/r/myisam_views-big.result @@ -62,6 +62,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; DROP DATABASE IF EXISTS test1; @@ -129,6 +131,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/ndb_views.result b/mysql-test/suite/funcs_1/r/ndb_views.result index b75f4955986..17eaedce56b 100644 --- a/mysql-test/suite/funcs_1/r/ndb_views.result +++ b/mysql-test/suite/funcs_1/r/ndb_views.result @@ -53,6 +53,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = ndb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/ndb_tb2.txt' into table tb2 ; DROP DATABASE IF EXISTS test1; @@ -112,6 +114,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = ndb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/ndb_tb2.txt' into table tb2 ; USE test; diff --git a/mysql-test/suite/funcs_1/r/storedproc.result b/mysql-test/suite/funcs_1/r/storedproc.result index 8da7213bded..7647579820a 100644 --- a/mysql-test/suite/funcs_1/r/storedproc.result +++ b/mysql-test/suite/funcs_1/r/storedproc.result @@ -7526,9 +7526,13 @@ BEGIN declare x, y, z year(3) default 2005; SELECT x, y, z; END// +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CALL sp1(); x y z 2005 2005 2005 +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result b/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result index 74db8b0c20a..927ba0e0e53 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result @@ -58,6 +58,7 @@ col89 float unsigned zerofill DEFAULT NULL, col90 tinyblob ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead Note 1291 Column 'col82' has duplicated value '' in ENUM Note 1291 Column 'col82' has duplicated value '' in ENUM INSERT INTO bug52745 SET diff --git a/mysql-test/t/type_year.test b/mysql-test/t/type_year.test index 1a9e66478e1..8ba8260cfc4 100644 --- a/mysql-test/t/type_year.test +++ b/mysql-test/t/type_year.test @@ -159,6 +159,14 @@ SELECT * FROM t1; SELECT COUNT(*) AS total_rows, MIN(c1) AS min_value, MAX(c1) FROM t1; DROP TABLE t1; +--echo # +--echo # WL#6219: Deprecate and remove YEAR(2) type +--echo # + +CREATE TABLE t1 (c1 YEAR(2), c2 YEAR(4)); +ALTER TABLE t1 MODIFY COLUMN c2 YEAR(2); +DROP TABLE t1; + --echo # --echo End of 5.1 tests diff --git a/sql/field.cc b/sql/field.cc index f398642fdb0..1c937755c0c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10227,6 +10227,17 @@ Create_field::Create_field(Field *old_field,Field *orig_field) geom_type= ((Field_geom*)old_field)->geom_type; break; #endif + case MYSQL_TYPE_YEAR: + if (length != 4) + { + char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; + snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_WARN_DEPRECATED_SYNTAX, + ER(ER_WARN_DEPRECATED_SYNTAX), + buff, "YEAR(4)"); + } + break; default: break; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7e7ff7e91ca..854ba432362 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5034,7 +5034,23 @@ type: $$= MYSQL_TYPE_VARCHAR; } | YEAR_SYM opt_field_length field_options - { $$=MYSQL_TYPE_YEAR; } + { + if (Lex->length) + { + errno= 0; + ulong length= strtoul(Lex->length, NULL, 10); + if (errno == 0 && length <= MAX_FIELD_BLOBLENGTH && length != 4) + { + char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; + snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_WARN_DEPRECATED_SYNTAX, + ER(ER_WARN_DEPRECATED_SYNTAX), + buff, "YEAR(4)"); + } + } + $$=MYSQL_TYPE_YEAR; + } | DATE_SYM { $$=MYSQL_TYPE_DATE; } | TIME_SYM From ca3e45dce14102c2b2d305493c61f46972218e67 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 29 Jun 2012 14:04:24 +0300 Subject: [PATCH 15/44] Bug #12910665: AUTH-PLUGIN-DATA-LEN NOT TESTED FOR VALIDITY BY THE CLIENT Added a check for a negative second part of the scramble length. --- sql-common/client.c | 6 ++++++ sql/sql_acl.cc | 1 + 2 files changed, 7 insertions(+) diff --git a/sql-common/client.c b/sql-common/client.c index be24c5e89e4..ef1e3c1b7d4 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -3415,6 +3415,12 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, mysql->server_status=uint2korr(end+3); mysql->server_capabilities|= uint2korr(end+5) << 16; pkt_scramble_len= end[7]; + if (pkt_scramble_len < 0) + { + set_mysql_error(mysql, CR_MALFORMED_PACKET, + unknown_sqlstate); /* purecov: inspected */ + goto error; + } } end+= 18; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d3715fd2312..242967fff6a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8032,6 +8032,7 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio, int2store(end + 3, mpvio->server_status[0]); int2store(end + 5, mpvio->client_capabilities >> 16); end[7]= data_len; + DBUG_EXECUTE_IF("poison_srv_handshake_scramble_len", end[7]= -100;); bzero(end + 8, 10); end+= 18; /* write scramble tail */ From 435866976746d342847ad2a7a13be77cd77c556b Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Fri, 29 Jun 2012 13:25:57 +0200 Subject: [PATCH 16/44] Bug#14238406 NEW COMPILATION WARNINGS WITH GCC 4.7 (-WERROR=NARROWING) This patch fixes various compilation warnings of the type "error: narrowing conversion of 'x' from 'datatype1' to 'datatype2' --- client/mysqlbinlog.cc | 4 ++-- include/my_getopt.h | 4 ++-- sql/log.h | 6 ++--- sql/mysqld.cc | 27 +++++++++++----------- sql/sql_profile.cc | 6 ++--- storage/innobase/handler/ha_innodb.cc | 8 +++---- storage/innodb_plugin/handler/ha_innodb.cc | 12 +++++----- 7 files changed, 34 insertions(+), 33 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index dd09e7a0938..e7840865a58 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1149,7 +1149,7 @@ static struct my_option my_long_options[] = "Stop reading the binlog at position N. Applies to the last binlog " "passed on the command line.", &stop_position, &stop_position, 0, GET_ULL, - REQUIRED_ARG, (ulonglong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE, + REQUIRED_ARG, (longlong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE, (ulonglong)(~(my_off_t)0), 0, 0, 0}, {"to-last-log", 't', "Requires -R. Will not stop at the end of the \ requested binlog but rather continue printing until the end of the last \ diff --git a/include/my_getopt.h b/include/my_getopt.h index 8112303a6a5..5824518a085 100644 --- a/include/my_getopt.h +++ b/include/my_getopt.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -54,7 +54,7 @@ struct my_option enum get_opt_arg_type arg_type; longlong def_value; /* Default value */ longlong min_value; /* Min allowed value */ - longlong max_value; /* Max allowed value */ + ulonglong max_value; /* Max allowed value */ longlong sub_size; /* Subtract this from given value */ long block_size; /* Value should be a mult. of this */ void *app_type; /* To be used by an application */ diff --git a/sql/log.h b/sql/log.h index 9ed5db04e87..02721f1ddd0 100644 --- a/sql/log.h +++ b/sql/log.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -294,8 +294,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG int new_file_impl(bool need_lock); public: - MYSQL_LOG::generate_name; - MYSQL_LOG::is_open; + using MYSQL_LOG::generate_name; + using MYSQL_LOG::is_open; /* This is relay log */ bool is_relay_log; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index db73504cb17..d6397280e0d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -6710,7 +6710,7 @@ thread is in the relay logs.", {"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE, "Can be used to restrict the total size used to cache a multi-transaction query.", &max_binlog_cache_size, &max_binlog_cache_size, 0, - GET_ULL, REQUIRED_ARG, ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0}, + GET_ULL, REQUIRED_ARG, (longlong) ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0}, {"max_binlog_size", OPT_MAX_BINLOG_SIZE, "Binary log will be rotated automatically when the size exceeds this " "value. Will also apply to relay logs if max_relay_log_size is 0. " @@ -6748,7 +6748,7 @@ thread is in the relay logs.", "Joins that are probably going to read more than max_join_size records return an error.", &global_system_variables.max_join_size, &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG, - HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0}, + (longlong) HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0}, {"max_length_for_sort_data", OPT_MAX_LENGTH_FOR_SORT_DATA, "Max number of bytes in sorted records.", &global_system_variables.max_length_for_sort_data, @@ -6775,7 +6775,7 @@ thread is in the relay logs.", "Limit assumed max number of seeks when looking up rows based on a key.", &global_system_variables.max_seeks_for_key, &max_system_variables.max_seeks_for_key, 0, GET_ULONG, - REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0 }, + REQUIRED_ARG, (longlong) ULONG_MAX, 1, ULONG_MAX, 0, 1, 0 }, {"max_sort_length", OPT_MAX_SORT_LENGTH, "The number of bytes to use when sorting BLOB or TEXT values (only the " "first max_sort_length bytes of each value are used; the rest are ignored).", @@ -6799,7 +6799,7 @@ thread is in the relay logs.", {"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT, "After this many write locks, allow some read locks to run in between.", &max_write_lock_count, &max_write_lock_count, 0, GET_ULONG, - REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0}, + REQUIRED_ARG, (longlong) ULONG_MAX, 1, ULONG_MAX, 0, 1, 0}, {"min_examined_row_limit", OPT_MIN_EXAMINED_ROW_LIMIT, "Don't log queries which examine less than min_examined_row_limit rows to file.", &global_system_variables.min_examined_row_limit, @@ -6826,18 +6826,19 @@ thread is in the relay logs.", &global_system_variables.myisam_max_extra_sort_file_size, &max_system_variables.myisam_max_extra_sort_file_size, 0, GET_ULL, REQUIRED_ARG, (ulonglong) INT_MAX32, - 0, (ulonglong) MAX_FILE_SIZE, 0, 1, 0}, + 0, MAX_FILE_SIZE, 0, 1, 0}, {"myisam_max_sort_file_size", OPT_MYISAM_MAX_SORT_FILE_SIZE, "Don't use the fast sort index method to created index if the temporary " "file would get bigger than this.", &global_system_variables.myisam_max_sort_file_size, &max_system_variables.myisam_max_sort_file_size, 0, - GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, (ulonglong) MAX_FILE_SIZE, + GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, MAX_FILE_SIZE, 0, 1024*1024, 0}, {"myisam_mmap_size", OPT_MYISAM_MMAP_SIZE, "Can be used to restrict the total memory used for memory mmaping of myisam files", &myisam_mmap_size, &myisam_mmap_size, 0, - GET_ULL, REQUIRED_ARG, SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, 0, 1, 0}, + GET_ULL, REQUIRED_ARG, (longlong) SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, + 0, 1, 0}, {"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS, "Specifies whether several threads should be used when repairing MyISAM " "tables. For values > 1, one thread is used per index. The value of 1 " @@ -6850,7 +6851,7 @@ thread is in the relay logs.", "or when creating indexes with CREATE INDEX or ALTER TABLE.", &global_system_variables.myisam_sort_buff_size, &max_system_variables.myisam_sort_buff_size, 0, - GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, ~0L, 0, 1, 0}, + GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, ~0ULL, 0, 1, 0}, {"myisam_use_mmap", OPT_MYISAM_USE_MMAP, "Use memory mapping for reading and writing MyISAM tables.", &opt_myisam_use_mmap, &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG, @@ -6953,7 +6954,7 @@ thread is in the relay logs.", {"query_cache_size", OPT_QUERY_CACHE_SIZE, "The memory allocated to store results from old queries.", &query_cache_size, &query_cache_size, 0, GET_ULONG, - REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1024, 0}, + REQUIRED_ARG, 0, 0, ULONG_MAX, 0, 1024, 0}, #ifdef HAVE_QUERY_CACHE {"query_cache_type", OPT_QUERY_CACHE_TYPE, "0 = OFF = Don't cache or retrieve results. 1 = ON = Cache all results " @@ -7015,7 +7016,7 @@ thread is in the relay logs.", "Maximum space to use for all relay logs.", &relay_log_space_limit, &relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L, - (longlong) ULONG_MAX, 0, 1, 0}, + ULONG_MAX, 0, 1, 0}, {"slave_compressed_protocol", OPT_SLAVE_COMPRESSED_PROTOCOL, "Use compression on master/slave protocol.", &opt_slave_compressed_protocol, @@ -7030,7 +7031,7 @@ thread is in the relay logs.", "it failed with a deadlock or elapsed lock wait timeout, " "before giving up and stopping.", &slave_trans_retries, &slave_trans_retries, 0, - GET_ULONG, REQUIRED_ARG, 10L, 0L, (longlong) ULONG_MAX, 0, 1, 0}, + GET_ULONG, REQUIRED_ARG, 10L, 0L, ULONG_MAX, 0, 1, 0}, #endif /* HAVE_REPLICATION */ {"slow_launch_time", OPT_SLOW_LAUNCH_TIME, "If creating the thread takes longer than this value (in seconds), " @@ -7041,7 +7042,7 @@ thread is in the relay logs.", "Each thread that needs to do a sort allocates a buffer of this size.", &global_system_variables.sortbuff_size, &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG, - MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD, + MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0ULL, MALLOC_OVERHEAD, 1, 0}, {"sync-binlog", OPT_SYNC_BINLOG, "Synchronously flush binary log to disk after every #th event. " diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 1a6477e4c4d..49666dde476 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -84,8 +84,8 @@ ST_FIELD_INFO query_profile_statistics_info[]= int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table) { - int profile_options = thd->lex->profile_options; - int fields_include_condition_truth_values[]= { + uint profile_options = thd->lex->profile_options; + uint fields_include_condition_truth_values[]= { FALSE, /* Query_id */ FALSE, /* Seq */ TRUE, /* Status */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 51b7007145c..796f51d737b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -9128,7 +9128,7 @@ static MYSQL_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct, static MYSQL_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag, PLUGIN_VAR_RQCMDARG, "Desired maximum length of the purge queue (0 = no limit)", - NULL, NULL, 0, 0, ~0L, 0); + NULL, NULL, 0, 0, ~0UL, 0); static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, @@ -9182,7 +9182,7 @@ static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, PLUGIN_VAR_RQCMDARG, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", - NULL, NULL, 500L, 1L, ~0L, 0); + NULL, NULL, 500L, 1L, ~0UL, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, @@ -9227,7 +9227,7 @@ static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds, PLUGIN_VAR_RQCMDARG, "Count of spin-loop rounds in InnoDB mutexes", - NULL, NULL, 20L, 0L, ~0L, 0); + NULL, NULL, 20L, 0L, ~0UL, 0); static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, PLUGIN_VAR_RQCMDARG, @@ -9237,7 +9237,7 @@ static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay, PLUGIN_VAR_RQCMDARG, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep", - NULL, NULL, 10000L, 0L, ~0L, 0); + NULL, NULL, 10000L, 0L, ~0UL, 0); static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 2207f9d009d..412346e8349 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -10974,7 +10974,7 @@ static MYSQL_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite, static MYSQL_SYSVAR_ULONG(io_capacity, srv_io_capacity, PLUGIN_VAR_RQCMDARG, "Number of IOPs the server can do. Tunes the background IO rate", - NULL, NULL, 200, 100, ~0L, 0); + NULL, NULL, 200, 100, ~0UL, 0); static MYSQL_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown, PLUGIN_VAR_OPCMDARG, @@ -11052,7 +11052,7 @@ static MYSQL_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing, static MYSQL_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag, PLUGIN_VAR_RQCMDARG, "Desired maximum length of the purge queue (0 = no limit)", - NULL, NULL, 0, 0, ~0L, 0); + NULL, NULL, 0, 0, ~0UL, 0); static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, @@ -11109,7 +11109,7 @@ static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, PLUGIN_VAR_RQCMDARG, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", - NULL, NULL, 500L, 1L, ~0L, 0); + NULL, NULL, 500L, 1L, ~0UL, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR, @@ -11171,12 +11171,12 @@ static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds, PLUGIN_VAR_RQCMDARG, "Count of spin-loop rounds in InnoDB mutexes (30 by default)", - NULL, NULL, 30L, 0L, ~0L, 0); + NULL, NULL, 30L, 0L, ~0UL, 0); static MYSQL_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay, PLUGIN_VAR_OPCMDARG, "Maximum delay between polling for a spin lock (6 by default)", - NULL, NULL, 6L, 0L, ~0L, 0); + NULL, NULL, 6L, 0L, ~0UL, 0); static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, PLUGIN_VAR_RQCMDARG, @@ -11186,7 +11186,7 @@ static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay, PLUGIN_VAR_RQCMDARG, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep", - NULL, NULL, 10000L, 0L, ~0L, 0); + NULL, NULL, 10000L, 0L, ~0UL, 0); static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, From 72c642c097c1172f7e3c6ca5c060401b78e3bb9d Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Fri, 29 Jun 2012 14:19:31 +0200 Subject: [PATCH 17/44] Fix mysql_plugin test to handle version XXa --- mysql-test/t/mysql_plugin.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index 71617b86330..a05b5a624d9 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -372,11 +372,11 @@ let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQL_DATADIR --basedir=$MYSQ --echo # Show the help. --echo # replace_result $MYSQL_PLUGIN mysql_plugin; ---replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ /XX[a-z]/XX/ --exec $MYSQL_PLUGIN --help replace_result $MYSQL_PLUGIN mysql_plugin; ---replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ /XX[a-z]/XX/ --exec $MYSQL_PLUGIN --version # From 0b847cd4de1d07670664d92530b3ce207520b2b9 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 29 Jun 2012 18:24:43 +0400 Subject: [PATCH 18/44] minor update to make MSVS happy --- sql/field.cc | 2 +- sql/sql_yacc.yy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 1c937755c0c..ff631edd8d4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10231,7 +10231,7 @@ Create_field::Create_field(Field *old_field,Field *orig_field) if (length != 4) { char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; - snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length); push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 854ba432362..7a6981f778a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5042,7 +5042,7 @@ type: if (errno == 0 && length <= MAX_FIELD_BLOBLENGTH && length != 4) { char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; - snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length); push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), From 3941355dccfccf3bc47b1ac8150f3ee5261fcad8 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Mon, 2 Jul 2012 13:09:33 +0200 Subject: [PATCH 19/44] Added some extra optional path to test suites. --- mysql-test/lib/My/Find.pm | 7 ++++--- mysql-test/lib/mtr_cases.pm | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/mysql-test/lib/My/Find.pm b/mysql-test/lib/My/Find.pm index 952a3c4143d..1f99c470e73 100644 --- a/mysql-test/lib/My/Find.pm +++ b/mysql-test/lib/My/Find.pm @@ -126,9 +126,9 @@ sub my_find_file { # # sub my_find_dir { - my ($base, $paths, $dirs, $required)= @_; - croak "usage: my_find_dir(, [, ])" - unless (@_ == 3 or @_ == 2); + my ($base, $paths, $dirs, $optional)= @_; + croak "usage: my_find_dir(, [, [, ]])" + unless (@_ == 3 or @_ == 2 or @_ == 4); # ------------------------------------------------------- # Find and return the first directory @@ -136,6 +136,7 @@ sub my_find_dir { foreach my $path (my_find_paths($base, $paths, $dirs)) { return $path if ( -d $path ); } + return "" if $optional; find_error($base, $paths, $dirs); } diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index c8381e16061..2f68b70e3e2 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -137,6 +137,7 @@ sub collect_test_cases ($$$$) { { push(@$cases, collect_one_suite($suite, $opt_cases, $opt_skip_test_list)); last if $some_test_found; + push(@$cases, collect_one_suite("i_".$suite, $opt_cases, $opt_skip_test_list)); } } @@ -288,13 +289,15 @@ sub collect_one_suite($) $suitedir= my_find_dir($::basedir, ["share/mysql-test/suite", "mysql-test/suite", + "internal/mysql-test/suite", "mysql-test", # Look in storage engine specific suite dirs "storage/*/mtr", # Look in plugin specific suite dir "plugin/$suite/tests", ], - [$suite, "mtr"]); + [$suite, "mtr"], ($suite =~ /^i_/)); + return unless $suitedir; } mtr_verbose("suitedir: $suitedir"); } From 9f4f06996b2b7ec6007bb5ca9cd3063186c1a356 Mon Sep 17 00:00:00 2001 From: Mayank Prasad Date: Tue, 3 Jul 2012 09:55:51 +0530 Subject: [PATCH 20/44] Bug#13417440 : 63340: ARCHIVE FILE IO NOT INSTRUMENTED Details: - Modified test case to make sure its run for all and not only for archive Storage Engine. --- mysql-test/suite/perfschema/r/query_cache.result | 12 ++++++------ mysql-test/suite/perfschema/t/query_cache.test | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/perfschema/r/query_cache.result b/mysql-test/suite/perfschema/r/query_cache.result index 56511999ab2..8786cd055ca 100644 --- a/mysql-test/suite/perfschema/r/query_cache.result +++ b/mysql-test/suite/perfschema/r/query_cache.result @@ -36,9 +36,9 @@ Qcache_hits 1 select spins from performance_schema.events_waits_current order by event_name limit 1; spins NULL -select name from performance_schema.setup_instruments order by name limit 1; -name -wait/io/file/archive/data +select * from performance_schema.setup_timers where name='wait'; +NAME TIMER_NAME +wait CYCLE show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 1 @@ -51,9 +51,9 @@ Qcache_hits 1 select spins from performance_schema.events_waits_current order by event_name limit 1; spins NULL -select name from performance_schema.setup_instruments order by name limit 1; -name -wait/io/file/archive/data +select * from performance_schema.setup_timers where name='wait'; +NAME TIMER_NAME +wait CYCLE show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 1 diff --git a/mysql-test/suite/perfschema/t/query_cache.test b/mysql-test/suite/perfschema/t/query_cache.test index 08292306a25..60d4a648222 100644 --- a/mysql-test/suite/perfschema/t/query_cache.test +++ b/mysql-test/suite/perfschema/t/query_cache.test @@ -6,7 +6,6 @@ --source include/have_query_cache.inc --source include/not_embedded.inc --source include/have_perfschema.inc ---source include/have_archive.inc --disable_warnings drop table if exists t1; @@ -35,7 +34,7 @@ show status like "Qcache_hits"; select spins from performance_schema.events_waits_current order by event_name limit 1; -select name from performance_schema.setup_instruments order by name limit 1; +select * from performance_schema.setup_timers where name='wait'; show status like "Qcache_queries_in_cache"; show status like "Qcache_inserts"; @@ -43,7 +42,7 @@ show status like "Qcache_hits"; select spins from performance_schema.events_waits_current order by event_name limit 1; -select name from performance_schema.setup_instruments order by name limit 1; +select * from performance_schema.setup_timers where name='wait'; show status like "Qcache_queries_in_cache"; show status like "Qcache_inserts"; From 176d6b1dcae7470441ff1eefd3bfc27c6db137f8 Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Tue, 3 Jul 2012 18:00:21 +0530 Subject: [PATCH 21/44] BUG#11762667:MYSQLBINLOG IGNORES ERRORS WHILE WRITING OUTPUT This is a followup patch for the bug enabling the test i_binlog.binlog_mysqlbinlog_file_write.test this was disabled in mysql trunk and mysql 5.5 as in the release build mysqlbinlog was not debug compiled whereas the mysqld was. Since have_debug.inc script checks only for mysqld to be debug compiled, the test was not being skipped on release builds. We resolve this problem by creating a new inc file mysqlbinlog_have_debug.inc which checks exclusively for mysqlbinlog to be debug compiled. if not it skips the test. --- mysql-test/include/mysqlbinlog_have_debug.inc | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 mysql-test/include/mysqlbinlog_have_debug.inc diff --git a/mysql-test/include/mysqlbinlog_have_debug.inc b/mysql-test/include/mysqlbinlog_have_debug.inc new file mode 100644 index 00000000000..14da1379ecd --- /dev/null +++ b/mysql-test/include/mysqlbinlog_have_debug.inc @@ -0,0 +1,34 @@ +############################################# +# checks if mysqlbinlog is debug compiled +# this "cannot" be done simply by using +# have_debug.inc +############################################# + +--disable_query_log +--let $temp_out_help_file=$MYSQL_TMP_DIR/mysqlbinlog_help.tmp +--exec $MYSQL_BINLOG --help>$temp_out_help_file +let log_tmp=$temp_out_help_file; +--let $temp_inc=$MYSQL_TMP_DIR/temp.inc +let inc_tmp=$temp_inc; + +--perl +use strict; +my $tmp_file= $ENV{'log_tmp'} or die "log_tmp not set"; +open(FILE, "$tmp_file") or die("Unable to open $tmp_file: $!\n"); +my $count = () = grep(/Output debug log/g,); +close FILE; + +my $temp_inc= $ENV{'inc_tmp'} or die "temp_inc not set"; +open(FILE_INC,">", "$temp_inc") or die("can't open file \"$temp_inc\": $!"); +print FILE_INC '--let $is_debug= '.$count; +close FILE_INC; +EOF +--source $temp_inc + +if (!$is_debug) +{ + --skip mysqlbinlog needs to be debug compiled +} +--remove_file $temp_out_help_file +--remove_file $temp_inc +--enable_query_log From e6f0b97b50bd2267ef7fdb8c8ec80ae5a4c62dc2 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 4 Jul 2012 17:48:58 +0300 Subject: [PATCH 22/44] Bug #11753490: 44939: sql dumps containing broad views fail when executing The problem is that mysql lacks information about the objects a view depends on so it can't dump views and tables in the proper order. Thus it needs to create "stand-in" myisam tables for each view while dumping the tables that it later drops and replaces with the actual view view definition. But since views can have much more columns than an actual table creating these stand-in tables may be problematic. There's no way to portably find out how many columns an mysiam table can have. It's a complicated formula depending on internal server constants. Thus we can't have a reliable error check without repeating the logic and the formula inside mysqldump. 1. Changed the type of the columns of the stand-in tables mysqldump makes to satisfy view dependencies from the original type to smallint to save on row space. 2. Added a warning on the mysqldump's standard error for a possible problems replaying the dump file if the columns of a view exceed 1000. 3. Added a test case. --- client/mysqldump.c | 35 ++++++++++++++++++++------ mysql-test/r/mysqldump.result | 46 +++++++++++++++++------------------ 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index e273ca0e7fd..dcfe25a5f61 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2558,6 +2558,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, if (strcmp(field->name, "View") == 0) { char *scv_buff= NULL; + my_ulonglong n_cols; verbose_msg("-- It's a view, create dummy table for view\n"); @@ -2572,8 +2573,8 @@ static uint get_table_structure(char *table, char *db, char *table_type, the same name in order to satisfy views that depend on this view. The table will be removed when the actual view is created. - The properties of each column, aside from the data type, are not - preserved in this temporary table, because they are not necessary. + The properties of each column, are not preserved in this temporary + table, because they are not necessary. This will not be necessary once we can determine dependencies between views and can simply dump them in the appropriate order. @@ -2600,8 +2601,23 @@ static uint get_table_structure(char *table, char *db, char *table_type, else my_free(scv_buff); - if (mysql_num_rows(result)) + n_cols= mysql_num_rows(result); + if (0 != n_cols) { + + /* + The actual formula is based on the column names and how the .FRM + files are stored and is too volatile to be repeated here. + Thus we simply warn the user if the columns exceed a limit we + know works most of the time. + */ + if (n_cols >= 1000) + fprintf(stderr, + "-- Warning: Creating a stand-in table for view %s may" + " fail when replaying the dump file produced because " + "of the number of columns exceeding 1000. Exercise " + "caution when replaying the produced dump file.\n", + table); if (opt_drop) { /* @@ -2628,14 +2644,19 @@ static uint get_table_structure(char *table, char *db, char *table_type, row= mysql_fetch_row(result); - fprintf(sql_file, " %s %s", quote_name(row[0], name_buff, 0), - row[1]); + /* + The actual column type doesn't matter anyway, since the table will + be dropped at run time. + We do tinyint to avoid hitting the row size limit. + */ + fprintf(sql_file, " %s tinyint NOT NULL", + quote_name(row[0], name_buff, 0)); while((row= mysql_fetch_row(result))) { /* col name, col type */ - fprintf(sql_file, ",\n %s %s", - quote_name(row[0], name_buff, 0), row[1]); + fprintf(sql_file, ",\n %s tinyint NOT NULL", + quote_name(row[0], name_buff, 0)); } /* diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 15fdddb18be..5f3b29f5f7c 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1988,7 +1988,7 @@ DROP TABLE IF EXISTS `v2`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( - `a` varchar(30) + `a` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE IF EXISTS `v2`*/; @@ -2082,7 +2082,7 @@ DROP TABLE IF EXISTS `v1`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( - `a` int(11) + `a` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE IF EXISTS `v1`*/; @@ -2156,7 +2156,7 @@ DROP TABLE IF EXISTS `v2`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( - `a` varchar(30) + `a` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE IF EXISTS `v2`*/; @@ -2270,9 +2270,9 @@ DROP TABLE IF EXISTS `v1`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( - `a` int(11), - `b` int(11), - `c` varchar(30) + `a` tinyint NOT NULL, + `b` tinyint NOT NULL, + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v2`; @@ -2280,7 +2280,7 @@ DROP TABLE IF EXISTS `v2`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( - `a` int(11) + `a` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v3`; @@ -2288,9 +2288,9 @@ DROP TABLE IF EXISTS `v3`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v3` ( - `a` int(11), - `b` int(11), - `c` varchar(30) + `a` tinyint NOT NULL, + `b` tinyint NOT NULL, + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE IF EXISTS `v1`*/; @@ -3027,9 +3027,9 @@ DROP TABLE IF EXISTS `v0`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v0` ( - `a` int(11), - `b` varchar(32), - `c` varchar(32) + `a` tinyint NOT NULL, + `b` tinyint NOT NULL, + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v1`; @@ -3037,9 +3037,9 @@ DROP TABLE IF EXISTS `v1`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( - `a` int(11), - `b` varchar(32), - `c` varchar(32) + `a` tinyint NOT NULL, + `b` tinyint NOT NULL, + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v2`; @@ -3047,9 +3047,9 @@ DROP TABLE IF EXISTS `v2`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( - `a` int(11), - `b` varchar(32), - `c` varchar(32) + `a` tinyint NOT NULL, + `b` tinyint NOT NULL, + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; @@ -3429,7 +3429,7 @@ DROP TABLE IF EXISTS `v1`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( - `id` int(11) + `id` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; @@ -3489,7 +3489,7 @@ USE `mysqldump_views`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `nasishnasifu` ( - `id` bigint(20) unsigned + `id` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; @@ -3882,7 +3882,7 @@ DROP TABLE IF EXISTS `v2`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( - `c` int(11) + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE IF EXISTS `v2`*/; @@ -4299,7 +4299,7 @@ DROP TABLE IF EXISTS `v1`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( - `id` int(11) + `id` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; From 31a9208bd09afd16ce540be2cd66c7059b7bdeb8 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 5 Jul 2012 09:55:20 +0300 Subject: [PATCH 23/44] Bug #12998841: libmysql divulges plaintext password upon request in 5.5 1. Clear text password client plugin disabled by default. 2. Added an environment variable LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN, that when set to something starting with '1', 'Y' or 'y' will enable the clear text plugin for all connections. 3. Added a new mysql_options() option : MYSQL_ENABLE_CLEARTEXT_PLUGIN that takes an my_bool argument. When the value of the argument is non-zero the clear text plugin is enabled for this connection only. 4. Added an enable-cleartext-plugin config file option that takes a numeric argument. If the numeric value of the numeric argument is non-zero the clear text plugin is enabled for the connection 5. Added a boolean command line option "--enable_cleartext_plugin" to mysql, mysqlslap and mysqladmin. When specified it will call mysql_options with the effect of #3 6. Added a new CLEARTEXT option to the connect command in mysqltest. When specified it will enable the cleartext plugin for usage. 7. Added test cases and updated existing ones that need the clear text plugin. --- client/client_priv.h | 1 + client/mysql.cc | 13 +++++++ client/mysqladmin.cc | 13 +++++++ client/mysqlslap.c | 12 ++++++ client/mysqltest.cc | 8 +++- include/mysql.h | 3 +- include/mysql.h.pp | 3 +- include/sql_common.h | 2 + mysql-test/t/plugin_auth.test | 4 +- sql-common/client.c | 69 ++++++++++++++++++++++++++++++----- sql-common/client_plugin.c | 5 +++ 11 files changed, 119 insertions(+), 14 deletions(-) diff --git a/client/client_priv.h b/client/client_priv.h index b776dcf8014..2362811d2b3 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -87,6 +87,7 @@ enum options_client OPT_PLUGIN_DIR, OPT_DEFAULT_AUTH, OPT_DEFAULT_PLUGIN, + OPT_ENABLE_CLEARTEXT_PLUGIN, OPT_MAX_CLIENT_OPTION }; diff --git a/client/mysql.cc b/client/mysql.cc index b6bc2f4b68f..630c6215603 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -148,6 +148,8 @@ static my_bool column_types_flag; static my_bool preserve_comments= 0; static ulong opt_max_allowed_packet, opt_net_buffer_length; static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0; +static uint opt_enable_cleartext_plugin= 0; +static my_bool using_opt_enable_cleartext_plugin= 0; static uint my_end_arg; static char * opt_mysql_unix_port=0; static int connect_flag=CLIENT_INTERACTIVE; @@ -1409,6 +1411,10 @@ static struct my_option my_long_options[] = &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"delimiter", OPT_DELIMITER, "Delimiter to be used.", &delimiter_str, &delimiter_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN, + "Enable/disable the clear text authentication plugin.", + &opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"execute", 'e', "Execute command and quit. (Disables --force and history file.)", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"vertical", 'E', "Print the output of a query (rows) vertically.", @@ -1636,6 +1642,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case OPT_LOCAL_INFILE: using_opt_local_infile=1; break; + case OPT_ENABLE_CLEARTEXT_PLUGIN: + using_opt_enable_cleartext_plugin= TRUE; + break; case OPT_TEE: if (argument == disabled_my_option) { @@ -4321,6 +4330,10 @@ sql_real_connect(char *host,char *database,char *user,char *password, if (opt_default_auth && *opt_default_auth) mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (using_opt_enable_cleartext_plugin) + mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN, + (char*) &opt_enable_cleartext_plugin); + if (!mysql_real_connect(&mysql, host, user, password, database, opt_mysql_port, opt_mysql_unix_port, connect_flag | CLIENT_MULTI_STATEMENTS)) diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 3f33c25e664..321efd36642 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -43,6 +43,8 @@ static uint opt_count_iterations= 0, my_end_arg; static ulong opt_connect_timeout, opt_shutdown_timeout; static char * unix_port=0; static char *opt_plugin_dir= 0, *opt_default_auth= 0; +static uint opt_enable_cleartext_plugin= 0; +static my_bool using_opt_enable_cleartext_plugin= 0; #ifdef HAVE_SMEM static char *shared_memory_base_name=0; @@ -212,6 +214,10 @@ static struct my_option my_long_options[] = "Default authentication client-side plugin to use.", &opt_default_auth, &opt_default_auth, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN, + "Enable/disable the clear text authentication plugin.", + &opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -282,6 +288,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, opt->name); break; + case OPT_ENABLE_CLEARTEXT_PLUGIN: + using_opt_enable_cleartext_plugin= TRUE; + break; } if (error) { @@ -354,6 +363,10 @@ int main(int argc,char *argv[]) if (opt_default_auth && *opt_default_auth) mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (using_opt_enable_cleartext_plugin) + mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN, + (char*) &opt_enable_cleartext_plugin); + if (sql_connect(&mysql, option_wait)) { /* diff --git a/client/mysqlslap.c b/client/mysqlslap.c index a2c01b85b5a..ac1cc31733c 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -125,6 +125,8 @@ static char *host= NULL, *opt_password= NULL, *user= NULL, *post_system= NULL, *opt_mysql_unix_port= NULL; static char *opt_plugin_dir= 0, *opt_default_auth= 0; +static uint opt_enable_cleartext_plugin= 0; +static my_bool using_opt_enable_cleartext_plugin= 0; const char *delimiter= "\n"; @@ -348,6 +350,9 @@ int main(int argc, char **argv) if (opt_default_auth && *opt_default_auth) mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (using_opt_enable_cleartext_plugin) + mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN, + (char*) &opt_enable_cleartext_plugin); if (!opt_only_print) { if (!(mysql_real_connect(&mysql, host, user, opt_password, @@ -603,6 +608,10 @@ static struct my_option my_long_options[] = "Detach (close and reopen) connections after X number of requests.", &detach_rate, &detach_rate, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN, + "Enable/disable the clear text authentication plugin.", + &opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"engine", 'e', "Storage engine to use for creating the table.", &default_engine, &default_engine, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -761,6 +770,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'I': /* Info */ usage(); exit(0); + case OPT_ENABLE_CLEARTEXT_PLUGIN: + using_opt_enable_cleartext_plugin= TRUE; + break; } DBUG_RETURN(0); } diff --git a/client/mysqltest.cc b/client/mysqltest.cc index b1784fdc7b6..34d8edcbe0b 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -5456,7 +5456,7 @@ void do_connect(struct st_command *command) int con_port= opt_port; char *con_options; my_bool con_ssl= 0, con_compress= 0; - my_bool con_pipe= 0, con_shm= 0; + my_bool con_pipe= 0, con_shm= 0, con_cleartext_enable= 0; struct st_connection* con_slot; static DYNAMIC_STRING ds_connection_name; @@ -5546,6 +5546,8 @@ void do_connect(struct st_command *command) con_pipe= 1; else if (!strncmp(con_options, "SHM", 3)) con_shm= 1; + else if (!strncmp(con_options, "CLEARTEXT", 9)) + con_cleartext_enable= 1; else die("Illegal option to connect: %.*s", (int) (end - con_options), con_options); @@ -5642,6 +5644,10 @@ void do_connect(struct st_command *command) if (ds_default_auth.length) mysql_options(&con_slot->mysql, MYSQL_DEFAULT_AUTH, ds_default_auth.str); + + if (con_cleartext_enable) + mysql_options(&con_slot->mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN, + (char*) &con_cleartext_enable); /* Special database to allow one to connect without a database name */ if (ds_database.length && !strcmp(ds_database.str,"*NO-ONE*")) dynstr_set(&ds_database, ""); diff --git a/include/mysql.h b/include/mysql.h index cff8c647152..0ed35413a1c 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -166,7 +166,8 @@ enum mysql_option MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, - MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH + MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, + MYSQL_ENABLE_CLEARTEXT_PLUGIN }; /** diff --git a/include/mysql.h.pp b/include/mysql.h.pp index 15ec563dfc2..c2c5ba35044 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -262,7 +262,8 @@ enum mysql_option MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, - MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH + MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, + MYSQL_ENABLE_CLEARTEXT_PLUGIN }; struct st_mysql_options_extention; struct st_mysql_options { diff --git a/include/sql_common.h b/include/sql_common.h index 307b443d6d6..a2ea3ac45e7 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -31,6 +31,7 @@ extern const char *not_error_sqlstate; struct st_mysql_options_extention { char *plugin_dir; char *default_auth; + my_bool enable_cleartext_plugin; }; typedef struct st_mysql_methods @@ -104,6 +105,7 @@ int mysql_client_plugin_init(); void mysql_client_plugin_deinit(); struct st_mysql_client_plugin; extern struct st_mysql_client_plugin *mysql_client_builtins[]; +extern my_bool libmysql_cleartext_plugin_enabled; #ifdef __cplusplus } diff --git a/mysql-test/t/plugin_auth.test b/mysql-test/t/plugin_auth.test index f169360cf2e..75d3ef3e807 100644 --- a/mysql-test/t/plugin_auth.test +++ b/mysql-test/t/plugin_auth.test @@ -422,10 +422,10 @@ CREATE USER uplain@localhost IDENTIFIED WITH 'cleartext_plugin_server' --echo ## test plugin auth --disable_query_log --error ER_ACCESS_DENIED_ERROR : this should fail : no grant -connect(cleartext_fail_con,localhost,uplain,cleartext_test2); +connect(cleartext_fail_con,localhost,uplain,cleartext_test2,,,,CLEARTEXT); --enable_query_log -connect(cleartext_con,localhost,uplain,cleartext_test); +connect(cleartext_con,localhost,uplain,cleartext_test,,,,CLEARTEXT); connection cleartext_con; select USER(),CURRENT_USER(); diff --git a/sql-common/client.c b/sql-common/client.c index 08f4bfb1151..381768834cd 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1136,7 +1136,8 @@ static const char *default_options[]= "connect-timeout", "local-infile", "disable-local-infile", "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name", "multi-results", "multi-statements", "multi-queries", "secure-auth", - "report-data-truncation", "plugin-dir", "default-auth", + "report-data-truncation", "plugin-dir", "default-auth", + "enable-cleartext-plugin", NullS }; enum option_id { @@ -1148,6 +1149,7 @@ enum option_id { OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name, OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth, OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth, + OPT_enable_cleartext_plugin, OPT_keep_this_one_last }; @@ -1180,14 +1182,27 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd) return 0; } -#define EXTENSION_SET_STRING(OPTS, X, STR) \ - if ((OPTS)->extension) \ - my_free((OPTS)->extension->X); \ - else \ +#define ALLOCATE_EXTENSIONS(OPTS) \ (OPTS)->extension= (struct st_mysql_options_extention *) \ my_malloc(sizeof(struct st_mysql_options_extention), \ - MYF(MY_WME | MY_ZEROFILL)); \ - (OPTS)->extension->X= my_strdup((STR), MYF(MY_WME)); + MYF(MY_WME | MY_ZEROFILL)) \ + +#define ENSURE_EXTENSIONS_PRESENT(OPTS) \ + do { \ + if (!(OPTS)->extension) \ + ALLOCATE_EXTENSIONS(OPTS); \ + } while (0) + + +#define EXTENSION_SET_STRING(OPTS, X, STR) \ + do { \ + if ((OPTS)->extension) \ + my_free((OPTS)->extension->X); \ + else \ + ALLOCATE_EXTENSIONS(OPTS); \ + (OPTS)->extension->X= ((STR) != NULL) ? \ + my_strdup((STR), MYF(MY_WME)) : NULL; \ + } while (0) void mysql_read_default_options(struct st_mysql_options *options, const char *filename,const char *group) @@ -1386,6 +1401,12 @@ void mysql_read_default_options(struct st_mysql_options *options, case OPT_default_auth: EXTENSION_SET_STRING(options, default_auth, opt_arg); break; + + case OPT_enable_cleartext_plugin: + ENSURE_EXTENSIONS_PRESENT(options); + options->extension->enable_cleartext_plugin= + (!opt_arg || atoi(opt_arg) != 0) ? TRUE : FALSE; + default: DBUG_PRINT("warning",("unknown option: %s",option[0])); } @@ -2782,6 +2803,27 @@ static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio, mpvio_info(mpvio->mysql->net.vio, info); } + +my_bool libmysql_cleartext_plugin_enabled= 0; + +static my_bool check_plugin_enabled(MYSQL *mysql, auth_plugin_t *plugin) +{ + if (plugin == &clear_password_client_plugin && + (!libmysql_cleartext_plugin_enabled && + (!mysql->options.extension || + !mysql->options.extension->enable_cleartext_plugin))) + { + set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, + unknown_sqlstate, + ER(CR_AUTH_PLUGIN_CANNOT_LOAD), + clear_password_client_plugin.name, + "plugin not enabled"); + return TRUE; + } + return FALSE; +} + + /** Client side of the plugin driver authentication. @@ -2824,6 +2866,9 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, auth_plugin_name= auth_plugin->name; } + if (check_plugin_enabled(mysql, auth_plugin)) + DBUG_RETURN(1); + DBUG_PRINT ("info", ("using plugin %s", auth_plugin_name)); mysql->net.last_errno= 0; /* just in case */ @@ -2915,6 +2960,9 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) DBUG_RETURN (1); + if (check_plugin_enabled(mysql, auth_plugin)) + DBUG_RETURN(1); + mpvio.plugin= auth_plugin; res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql); @@ -4117,6 +4165,11 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) case MYSQL_DEFAULT_AUTH: EXTENSION_SET_STRING(&mysql->options, default_auth, arg); break; + case MYSQL_ENABLE_CLEARTEXT_PLUGIN: + ENSURE_EXTENSIONS_PRESENT(&mysql->options); + mysql->options.extension->enable_cleartext_plugin= + (*(my_bool*) arg) ? TRUE : FALSE; + break; default: DBUG_RETURN(1); } @@ -4336,5 +4389,3 @@ static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) return res ? CR_ERROR : CR_OK; } - - diff --git a/sql-common/client_plugin.c b/sql-common/client_plugin.c index 4016f0744be..75faeb7ee97 100644 --- a/sql-common/client_plugin.c +++ b/sql-common/client_plugin.c @@ -197,6 +197,10 @@ err1: static void load_env_plugins(MYSQL *mysql) { char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS"); + char *enable_cleartext_plugin= getenv("LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN"); + + if (enable_cleartext_plugin && strchr("1Yy", enable_cleartext_plugin[0])) + libmysql_cleartext_plugin_enabled= 1; /* no plugins to load */ if(!s) @@ -212,6 +216,7 @@ static void load_env_plugins(MYSQL *mysql) } while (s); my_free(free_env); + } /********** extern functions to be used by libmysql *********************/ From 58e78da60f2dbdcbd3c676c33de32cbb47a18527 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 5 Jul 2012 10:18:18 +0300 Subject: [PATCH 24/44] fixed a missing break --- sql-common/client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sql-common/client.c b/sql-common/client.c index 381768834cd..be24c5e89e4 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1406,6 +1406,7 @@ void mysql_read_default_options(struct st_mysql_options *options, ENSURE_EXTENSIONS_PRESENT(options); options->extension->enable_cleartext_plugin= (!opt_arg || atoi(opt_arg) != 0) ? TRUE : FALSE; + break; default: DBUG_PRINT("warning",("unknown option: %s",option[0])); From 42644a07469027c6b54351bd906c9cd037d32eb6 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 5 Jul 2012 13:41:16 +0300 Subject: [PATCH 25/44] Bug #13889741: HANDLE_FATAL_SIGNAL IN _DB_ENTER_ | HANDLE_FATAL_SIGNAL IN STRNLEN Fixed the following bounds checking problems : 1. in check_if_legal_filename() make sure the null terminated string is long enough before accessing the bytes in it. Prevents pottential read-past-buffer-end 2. in my_wc_mb_filename() of the filename charset check for the end of the destination buffer before sending single byte characters into it. Prevents write-past-end-of-buffer (and garbaling stack in the cases reported here) errors. Added test cases. --- mysys/my_access.c | 3 ++- strings/ctype-utf8.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mysys/my_access.c b/mysys/my_access.c index 210946d50a8..43917da7f98 100644 --- a/mysys/my_access.c +++ b/mysys/my_access.c @@ -148,7 +148,8 @@ static char reserved_map[256]= int check_if_legal_tablename(const char *name) { DBUG_ENTER("check_if_legal_tablename"); - DBUG_RETURN((reserved_map[(uchar) name[0]] & 1) && + DBUG_RETURN(name[0] != 0 && name[1] != 0 && + (reserved_map[(uchar) name[0]] & 1) && (reserved_map[(uchar) name[1]] & 2) && (reserved_map[(uchar) name[2]] & 4) && str_list_find(&reserved_names[1], name)); diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 205f8c61ddd..a0e69feedab 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -4326,6 +4326,10 @@ my_wc_mb_filename(CHARSET_INFO *cs __attribute__((unused)), { int code; char hex[]= "0123456789abcdef"; + + if (s >= e) + return MY_CS_TOOSMALL; + if (wc < 128 && filename_safe_char[wc]) { *s= (uchar) wc; From dbd63d008f00ee249a7e207014d17630cb8ffb7e Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Thu, 5 Jul 2012 14:37:48 +0300 Subject: [PATCH 26/44] Bug#14275000 Fixes for BUG11761686 left a flaw that managed to slip away from testing. Only effective filtering branch was actually tested with a regression test added to rpl_filter_tables_not_exist. The reason of the failure is destuction of too early mem-root-allocated memory at the end of the deferred User-var's do_apply_event(). Fixed with bypassing free_root() in the deferred execution branch. Deallocation of created in do_apply_event() items is done by the base code through THD::cleanup_after_query() -> free_items() that the parent Query can't miss. --- sql/log_event.cc | 16 ++++++++++++---- sql/log_event.h | 11 ++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index a47b3680d82..1822951cccf 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5640,6 +5640,9 @@ User_var_log_event:: User_var_log_event(const char* buf, const Format_description_log_event* description_event) :Log_event(buf, description_event) +#ifndef MYSQL_CLIENT + , deferred(false) +#endif { /* The Post-Header is empty. The Variable Data part begins immediately. */ buf+= description_event->common_header_len + @@ -5848,7 +5851,10 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) CHARSET_INFO *charset; if (rli->deferred_events_collecting) + { + set_deferred(); return rli->deferred_events->add(this); + } if (!(charset= get_charset(charset_number, MYF(MY_WME)))) return 1; @@ -5900,7 +5906,8 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) return 0; } } - Item_func_set_user_var e(user_var_name, it); + + Item_func_set_user_var *e= new Item_func_set_user_var(user_var_name, it); /* Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) @@ -5909,7 +5916,7 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) crash the server, so if fix fields fails, we just return with an error. */ - if (e.fix_fields(thd, 0)) + if (e->fix_fields(thd, 0)) return 1; /* @@ -5917,8 +5924,9 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) a single record and with a single column. Thus, like a column value, it could always have IMPLICIT derivation. */ - e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0); - free_root(thd->mem_root,0); + e->update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0); + if (!is_deferred()) + free_root(thd->mem_root,0); return 0; } diff --git a/sql/log_event.h b/sql/log_event.h index 39cd55f313e..e755b6a5a41 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -2483,11 +2483,13 @@ public: uint charset_number; bool is_null; #ifndef MYSQL_CLIENT + bool deferred; User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg, char *val_arg, ulong val_len_arg, Item_result type_arg, uint charset_number_arg) :Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg), - val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg) + val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg), + deferred(false) { is_null= !val; } void pack_info(Protocol* protocol); #else @@ -2500,6 +2502,13 @@ public: Log_event_type get_type_code() { return USER_VAR_EVENT;} #ifndef MYSQL_CLIENT bool write(IO_CACHE* file); + /* + Getter and setter for deferred User-event. + Returns true if the event is not applied directly + and which case the applier adjusts execution path. + */ + bool is_deferred() { return deferred; } + void set_deferred() { deferred= val; } #endif bool is_valid() const { return 1; } From 298202f2fdf9a0dad88fb206d3012cf0608b8c98 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Thu, 5 Jul 2012 23:53:07 +0300 Subject: [PATCH 27/44] merge bug14275000 fixes to 5.5: sql/log_event.h. --- sql/log_event.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sql/log_event.h b/sql/log_event.h index 387f020ee8b..000c7420ca8 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -2562,23 +2562,15 @@ public: Item_result type; uint charset_number; bool is_null; -<<<<<<< TREE uchar flags; #ifdef MYSQL_SERVER -======= -#ifndef MYSQL_CLIENT bool deferred; ->>>>>>> MERGE-SOURCE User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg, char *val_arg, ulong val_len_arg, Item_result type_arg, uint charset_number_arg, uchar flags_arg) :Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg), val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg), -<<<<<<< TREE - flags(flags_arg) -======= - deferred(false) ->>>>>>> MERGE-SOURCE + flags(flags_arg), deferred(false) { is_null= !val; } void pack_info(Protocol* protocol); #else From 2541041a45ce27410eb2d03240ce514b12d427ae Mon Sep 17 00:00:00 2001 From: "mysql-builder@oracle.com" <> Date: Fri, 6 Jul 2012 15:30:53 +0300 Subject: [PATCH 28/44] From c2b8dceaaede2a078b48694d04621eac2545acf2 Mon Sep 17 00:00:00 2001 From: "mysql-builder@oracle.com" <> Date: Fri, 6 Jul 2012 18:53:13 +0300 Subject: [PATCH 29/44] From 83e3a4c9ef34249552d5316abf41964c19f1f13f Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 9 Jul 2012 15:10:07 +0200 Subject: [PATCH 30/44] Refactor mysql_client_test.c into a framework part and a test part --- tests/Makefile.am | 1 + tests/mysql_client_fw.c | 1375 +++++++++++++++++++++++++++++++++++++ tests/mysql_client_test.c | 1358 +----------------------------------- 3 files changed, 1381 insertions(+), 1353 deletions(-) create mode 100644 tests/mysql_client_fw.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 876db7e8475..4929fa7ba9b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -47,6 +47,7 @@ LDADD = @CLIENT_EXTRA_LDFLAGS@ \ mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) mysql_client_test_SOURCES= mysql_client_test.c\ $(top_srcdir)/mysys/my_memmem.c +mysql_client_test.o: mysql_client_fw.c insert_test_SOURCES= insert_test.c select_test_SOURCES= select_test.c diff --git a/tests/mysql_client_fw.c b/tests/mysql_client_fw.c new file mode 100644 index 00000000000..27a06501d7a --- /dev/null +++ b/tests/mysql_client_fw.c @@ -0,0 +1,1375 @@ +/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include +#include +#include +#include + +#define VER "2.1" +#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ +#define MAX_KEY MAX_INDEXES +#define MAX_SERVER_ARGS 64 + +/* set default options */ +static int opt_testcase = 0; +static char *opt_db= 0; +static char *opt_user= 0; +static char *opt_password= 0; +static char *opt_host= 0; +static char *opt_unix_socket= 0; +#ifdef HAVE_SMEM +static char *shared_memory_base_name= 0; +#endif +static unsigned int opt_port; +static my_bool tty_password= 0, opt_silent= 0; + +static MYSQL *mysql= 0; +static char current_db[]= "client_test_db"; +static unsigned int test_count= 0; +static unsigned int opt_count= 0; +static unsigned int iter_count= 0; +static my_bool have_innodb= FALSE; + +static const char *opt_basedir= "./"; +static const char *opt_vardir= "mysql-test/var"; + +static longlong opt_getopt_ll_test= 0; + +static int embedded_server_arg_count= 0; +static char *embedded_server_args[MAX_SERVER_ARGS]; + +static const char *embedded_server_groups[]= { +"server", +"embedded", +"mysql_client_test_SERVER", +NullS +}; + +static time_t start_time, end_time; +static double total_time; + +const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace"; + +struct my_tests_st +{ +const char *name; +void (*function)(); +}; + +#define myheader(str) \ +DBUG_PRINT("test", ("name: %s", str)); \ + if (opt_silent < 2) \ + { \ + fprintf(stdout, "\n\n#####################################\n"); \ + fprintf(stdout, "%u of (%u/%u): %s", test_count++, iter_count, \ + opt_count, str); \ + fprintf(stdout, " \n#####################################\n"); \ + } + +#define myheader_r(str) \ +DBUG_PRINT("test", ("name: %s", str)); \ + if (!opt_silent) \ + { \ + fprintf(stdout, "\n\n#####################################\n"); \ + fprintf(stdout, "%s", str); \ + fprintf(stdout, " \n#####################################\n"); \ + } + +static void print_error(const char *msg); +static void print_st_error(MYSQL_STMT *stmt, const char *msg); +static void client_disconnect(MYSQL* mysql, my_bool drop_db); + + +/* +Abort unless given experssion is non-zero. + +SYNOPSIS +DIE_UNLESS(expr) + +DESCRIPTION +We can't use any kind of system assert as we need to +preserve tested invariants in release builds as well. +*/ + +#define DIE_UNLESS(expr) \ +((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) +#define DIE_IF(expr) \ +((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0)) +#define DIE(expr) \ +die(__FILE__, __LINE__, #expr) + +static void die(const char *file, int line, const char *expr) +{ + fflush(stdout); + fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); + fflush(stderr); + exit(1); +} + + +#define myerror(msg) print_error(msg) +#define mysterror(stmt, msg) print_st_error(stmt, msg) + +#define myquery(RES) \ +{ \ + int r= (RES); \ + if (r) \ + myerror(NULL); \ + DIE_UNLESS(r == 0); \ +} + +#define myquery_r(r) \ +{ \ + if (r) \ + myerror(NULL); \ + DIE_UNLESS(r != 0); \ +} + +#define check_execute(stmt, r) \ +{ \ + if (r) \ + mysterror(stmt, NULL); \ + DIE_UNLESS(r == 0); \ +} + +#define check_execute_r(stmt, r) \ +{ \ + if (r) \ + mysterror(stmt, NULL); \ + DIE_UNLESS(r != 0); \ +} + +#define check_stmt(stmt) \ +{ \ + if ( stmt == 0) \ + myerror(NULL); \ + DIE_UNLESS(stmt != 0); \ +} + +#define check_stmt_r(stmt) \ +{ \ + if (stmt == 0) \ + myerror(NULL); \ + DIE_UNLESS(stmt == 0); \ +} + +#define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);} +#define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);} + + +/* A workaround for Sun Forte 5.6 on Solaris x86 */ + +static int cmp_double(double *a, double *b) +{ + return *a == *b; +} + + +/* Print the error message */ + +static void print_error(const char *msg) +{ + if (!opt_silent) + { + if (mysql && mysql_errno(mysql)) + { + if (mysql->server_version) + fprintf(stdout, "\n [MySQL-%s]", mysql->server_version); + else + fprintf(stdout, "\n [MySQL]"); + fprintf(stdout, "[%d] %s\n", mysql_errno(mysql), mysql_error(mysql)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); + } +} + + +static void print_st_error(MYSQL_STMT *stmt, const char *msg) +{ + if (!opt_silent) + { + if (stmt && mysql_stmt_errno(stmt)) + { + if (stmt->mysql && stmt->mysql->server_version) + fprintf(stdout, "\n [MySQL-%s]", stmt->mysql->server_version); + else + fprintf(stdout, "\n [MySQL]"); + + fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); + } +} + +/* +Enhanced version of mysql_client_init(), which may also set shared memory +base on Windows. +*/ +static MYSQL *mysql_client_init(MYSQL* con) +{ + MYSQL* res = mysql_init(con); + #ifdef HAVE_SMEM + if (res && shared_memory_base_name) + mysql_options(res, MYSQL_SHARED_MEMORY_BASE_NAME, shared_memory_base_name); + #endif + return res; +} + +/* +Disable direct calls of mysql_init, as it disregards shared memory base. +*/ +#define mysql_init(A) Please use mysql_client_init instead of mysql_init + + +/* Check if the connection has InnoDB tables */ + +static my_bool check_have_innodb(MYSQL *conn) +{ + MYSQL_RES *res; + MYSQL_ROW row; + int rc; + my_bool result; + + rc= mysql_query(conn, "show variables like 'have_innodb'"); + myquery(rc); + res= mysql_use_result(conn); + DIE_UNLESS(res); + + row= mysql_fetch_row(res); + DIE_UNLESS(row); + + result= strcmp(row[1], "YES") == 0; + mysql_free_result(res); + return result; +} + + +/* +This is to be what mysql_query() is for mysql_real_query(), for +mysql_simple_prepare(): a variant without the 'length' parameter. +*/ + +static MYSQL_STMT *STDCALL +mysql_simple_prepare(MYSQL *mysql_arg, const char *query) +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql_arg); + if (stmt && mysql_stmt_prepare(stmt, query, (uint) strlen(query))) + { + mysql_stmt_close(stmt); + return 0; + } + return stmt; +} + + +/** +Connect to the server with options given by arguments to this application, +stored in global variables opt_host, opt_user, opt_password, opt_db, +opt_port and opt_unix_socket. + +@param flag[in] client_flag passed on to mysql_real_connect +@param protocol[in] MYSQL_PROTOCOL_* to use for this connection +@param auto_reconnect[in] set to 1 for auto reconnect + +@return pointer to initialized and connected MYSQL object +*/ +static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect) +{ + MYSQL* mysql; + int rc; + static char query[MAX_TEST_QUERY_LENGTH]; + myheader_r("client_connect"); + + if (!opt_silent) + fprintf(stdout, "\n Establishing a connection to '%s' ...", + opt_host ? opt_host : ""); + + if (!(mysql= mysql_client_init(NULL))) + { + opt_silent= 0; + myerror("mysql_client_init() failed"); + exit(1); + } + /* enable local infile, in non-binary builds often disabled by default */ + mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0); + mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol); + + if (!(mysql_real_connect(mysql, opt_host, opt_user, + opt_password, opt_db ? opt_db:"test", opt_port, + opt_unix_socket, flag))) + { + opt_silent= 0; + myerror("connection failed"); + mysql_close(mysql); + fprintf(stdout, "\n Check the connection options using --help or -?\n"); + exit(1); + } + mysql->reconnect= auto_reconnect; + + if (!opt_silent) + fprintf(stdout, "OK"); + + /* set AUTOCOMMIT to ON*/ + mysql_autocommit(mysql, TRUE); + + if (!opt_silent) + { + fprintf(stdout, "\nConnected to MySQL server version: %s (%lu)\n", + mysql_get_server_info(mysql), + (ulong) mysql_get_server_version(mysql)); + fprintf(stdout, "\n Creating a test database '%s' ...", current_db); + } + strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS); + + rc= mysql_query(mysql, query); + myquery(rc); + + strxmov(query, "USE ", current_db, NullS); + rc= mysql_query(mysql, query); + myquery(rc); + have_innodb= check_have_innodb(mysql); + + if (!opt_silent) + fprintf(stdout, "OK"); + + return mysql; +} + + +/* Close the connection */ + +static void client_disconnect(MYSQL* mysql, my_bool drop_db) +{ + static char query[MAX_TEST_QUERY_LENGTH]; + + myheader_r("client_disconnect"); + + if (mysql) + { + if (drop_db) + { + if (!opt_silent) + fprintf(stdout, "\n dropping the test database '%s' ...", current_db); + strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS); + + mysql_query(mysql, query); + if (!opt_silent) + fprintf(stdout, "OK"); + } + + if (!opt_silent) + fprintf(stdout, "\n closing the connection ..."); + mysql_close(mysql); + if (!opt_silent) + fprintf(stdout, "OK\n"); + } +} + + +/* Print dashes */ + +static void my_print_dashes(MYSQL_RES *result) +{ + MYSQL_FIELD *field; + unsigned int i, j; + + mysql_field_seek(result, 0); + fputc('\t', stdout); + fputc('+', stdout); + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + for(j= 0; j < field->max_length+2; j++) + fputc('-', stdout); + fputc('+', stdout); + } + fputc('\n', stdout); +} + + +/* Print resultset metadata information */ + +static void my_print_result_metadata(MYSQL_RES *result) +{ + MYSQL_FIELD *field; + unsigned int i, j; + unsigned int field_count; + + mysql_field_seek(result, 0); + if (!opt_silent) + { + fputc('\n', stdout); + fputc('\n', stdout); + } + + field_count= mysql_num_fields(result); + for(i= 0; i< field_count; i++) + { + field= mysql_fetch_field(result); + j= strlen(field->name); + if (j < field->max_length) + j= field->max_length; + if (j < 4 && !IS_NOT_NULL(field->flags)) + j= 4; + field->max_length= j; + } + if (!opt_silent) + { + my_print_dashes(result); + fputc('\t', stdout); + fputc('|', stdout); + } + + mysql_field_seek(result, 0); + for(i= 0; i< field_count; i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + fprintf(stdout, " %-*s |", (int) field->max_length, field->name); + } + if (!opt_silent) + { + fputc('\n', stdout); + my_print_dashes(result); + } +} + + +/* Process the result set */ + +static int my_process_result_set(MYSQL_RES *result) +{ + MYSQL_ROW row; + MYSQL_FIELD *field; + unsigned int i; + unsigned int row_count= 0; + + if (!result) + return 0; + + my_print_result_metadata(result); + + while ((row= mysql_fetch_row(result)) != NULL) + { + mysql_field_seek(result, 0); + if (!opt_silent) + { + fputc('\t', stdout); + fputc('|', stdout); + } + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + if (row[i] == NULL) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, row[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, row[i]); + } + } + if (!opt_silent) + { + fputc('\t', stdout); + fputc('\n', stdout); + } + row_count++; + } + if (!opt_silent) + { + if (row_count) + my_print_dashes(result); + + if (mysql_errno(mysql) != 0) + fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); + else + fprintf(stdout, "\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + } + return row_count; +} + + +static int my_process_result(MYSQL *mysql_arg) +{ + MYSQL_RES *result; + int row_count; + + if (!(result= mysql_store_result(mysql_arg))) + return 0; + + row_count= my_process_result_set(result); + + mysql_free_result(result); + return row_count; +} + + +/* Process the statement result set */ + +#define MAX_RES_FIELDS 50 +#define MAX_FIELD_DATA_SIZE 255 + +static int my_process_stmt_result(MYSQL_STMT *stmt) +{ + int field_count; + int row_count= 0; + MYSQL_BIND buffer[MAX_RES_FIELDS]; + MYSQL_FIELD *field; + MYSQL_RES *result; + char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE]; + ulong length[MAX_RES_FIELDS]; + my_bool is_null[MAX_RES_FIELDS]; + int rc, i; + + if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */ + { + while (!mysql_stmt_fetch(stmt)) + row_count++; + return row_count; + } + + field_count= min(mysql_num_fields(result), MAX_RES_FIELDS); + + bzero((char*) buffer, sizeof(buffer)); + bzero((char*) length, sizeof(length)); + bzero((char*) is_null, sizeof(is_null)); + + for(i= 0; i < field_count; i++) + { + buffer[i].buffer_type= MYSQL_TYPE_STRING; + buffer[i].buffer_length= MAX_FIELD_DATA_SIZE; + buffer[i].length= &length[i]; + buffer[i].buffer= (void *) data[i]; + buffer[i].is_null= &is_null[i]; + } + + rc= mysql_stmt_bind_result(stmt, buffer); + check_execute(stmt, rc); + + rc= 1; + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc); + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + { + fputc('\t', stdout); + fputc('|', stdout); + } + mysql_field_seek(result, 0); + for (i= 0; i < field_count; i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + if (is_null[i]) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (length[i] == 0) + { + data[i][0]= '\0'; /* unmodified buffer */ + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + } + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); + } + } + if (!opt_silent) + { + fputc('\t', stdout); + fputc('\n', stdout); + } + row_count++; + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + if (!opt_silent) + { + if (row_count) + my_print_dashes(result); + fprintf(stdout, "\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + } + mysql_free_result(result); + return row_count; +} + + +/* Prepare statement, execute, and process result set for given query */ + +int my_stmt_result(const char *buff) +{ + MYSQL_STMT *stmt; + int row_count; + int rc; + + if (!opt_silent) + fprintf(stdout, "\n\n %s", buff); + stmt= mysql_simple_prepare(mysql, buff); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + row_count= my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + + return row_count; +} + + +/* Utility function to verify a particular column data */ + +static void verify_col_data(const char *table, const char *col, +const char *exp_data) +{ + static char query[MAX_TEST_QUERY_LENGTH]; + MYSQL_RES *result; + MYSQL_ROW row; + int rc, field= 1; + + if (table && col) + { + strxmov(query, "SELECT ", col, " FROM ", table, " LIMIT 1", NullS); + if (!opt_silent) + fprintf(stdout, "\n %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + field= 0; + } + + result= mysql_use_result(mysql); + mytest(result); + + if (!(row= mysql_fetch_row(result)) || !row[field]) + { + fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + if (strcmp(row[field], exp_data)) + { + fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", + row[field], exp_data); + DIE_UNLESS(FALSE); + } + mysql_free_result(result); +} + + +/* Utility function to verify the field members */ + +#define verify_prepare_field(result,no,name,org_name,type,table, \ +org_table,db,length,def) \ +do_verify_prepare_field((result),(no),(name),(org_name),(type), \ +(table),(org_table),(db),(length),(def), \ +__FILE__, __LINE__) + +static void do_verify_prepare_field(MYSQL_RES *result, +unsigned int no, const char *name, +const char *org_name, +enum enum_field_types type, +const char *table, +const char *org_table, const char *db, +unsigned long length, const char *def, +const char *file, int line) +{ + MYSQL_FIELD *field; + CHARSET_INFO *cs; + ulonglong expected_field_length; + + if (!(field= mysql_fetch_field_direct(result, no))) + { + fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + cs= get_charset(field->charsetnr, 0); + DIE_UNLESS(cs); + if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32) + expected_field_length= UINT_MAX32; + if (!opt_silent) + { + fprintf(stdout, "\n field[%d]:", no); + fprintf(stdout, "\n name :`%s`\t(expected: `%s`)", field->name, name); + fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)", + field->org_name, org_name); + fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type); + if (table) + fprintf(stdout, "\n table :`%s`\t(expected: `%s`)", + field->table, table); + if (org_table) + fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", + field->org_table, org_table); + fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); + fprintf(stdout, "\n length :`%lu`\t(expected: `%llu`)", + field->length, expected_field_length); + fprintf(stdout, "\n maxlength:`%ld`", field->max_length); + fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); + fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", + field->def ? field->def : "(null)", def ? def: "(null)"); + fprintf(stdout, "\n"); + } + DIE_UNLESS(strcmp(field->name, name) == 0); + DIE_UNLESS(strcmp(field->org_name, org_name) == 0); + /* + XXX: silent column specification change works based on number of + bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even + for CHAR(2) column if its character set is multibyte. + VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would + expect. + */ + if (cs->mbmaxlen == 1) + { + if (field->type != type) + { + fprintf(stderr, + "Expected field type: %d, got type: %d in file %s, line %d\n", + (int) type, (int) field->type, file, line); + DIE_UNLESS(field->type == type); + } + } + if (table) + DIE_UNLESS(strcmp(field->table, table) == 0); + if (org_table) + DIE_UNLESS(strcmp(field->org_table, org_table) == 0); + DIE_UNLESS(strcmp(field->db, db) == 0); + /* + Character set should be taken into account for multibyte encodings, such + as utf8. Field length is calculated as number of characters * maximum + number of bytes a character can occupy. + */ + if (length && (field->length != expected_field_length)) + { + fprintf(stderr, "Expected field length: %llu, got length: %lu\n", + expected_field_length, field->length); + DIE_UNLESS(field->length == expected_field_length); + } + if (def) + DIE_UNLESS(strcmp(field->def, def) == 0); +} + + +/* Utility function to verify the parameter count */ + +static void verify_param_count(MYSQL_STMT *stmt, long exp_count) +{ + long param_count= mysql_stmt_param_count(stmt); + if (!opt_silent) + fprintf(stdout, "\n total parameters in stmt: `%ld` (expected: `%ld`)", + param_count, exp_count); + DIE_UNLESS(param_count == exp_count); +} + + +/* Utility function to verify the total affected rows */ + +static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count) +{ + ulonglong affected_rows= mysql_stmt_affected_rows(stmt); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + DIE_UNLESS(affected_rows == exp_count); +} + + +/* Utility function to verify the total affected rows */ + +static void verify_affected_rows(ulonglong exp_count) +{ + ulonglong affected_rows= mysql_affected_rows(mysql); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + DIE_UNLESS(affected_rows == exp_count); +} + + +/* Utility function to verify the total fields count */ + +static void verify_field_count(MYSQL_RES *result, uint exp_count) +{ + uint field_count= mysql_num_fields(result); + if (!opt_silent) + fprintf(stdout, "\n total fields in the result set: `%d` (expected: `%d`)", + field_count, exp_count); + DIE_UNLESS(field_count == exp_count); +} + + +/* Utility function to execute a query using prepare-execute */ + +#ifndef EMBEDDED_LIBRARY +static void execute_prepare_query(const char *query, ulonglong exp_count) +{ + MYSQL_STMT *stmt; + ulonglong affected_rows; + int rc; + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + myquery(rc); + + affected_rows= mysql_stmt_affected_rows(stmt); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + + DIE_UNLESS(affected_rows == exp_count); + mysql_stmt_close(stmt); +} +#endif + +/* +Accepts arbitrary number of queries and runs them against the database. +Used to fill tables for each test. +*/ + +void fill_tables(const char **query_list, unsigned query_count) +{ + int rc; + const char **query; + DBUG_ENTER("fill_tables"); + for (query= query_list; query < query_list + query_count; + ++query) + { + rc= mysql_query(mysql, *query); + myquery(rc); + } + DBUG_VOID_RETURN; +} + +/* +All state of fetch from one statement: statement handle, out buffers, +fetch position. +See fetch_n for for the only use case. +*/ + +enum { MAX_COLUMN_LENGTH= 255 }; + +typedef struct st_stmt_fetch +{ +const char *query; +unsigned stmt_no; +MYSQL_STMT *handle; +my_bool is_open; +MYSQL_BIND *bind_array; +char **out_data; +unsigned long *out_data_length; +unsigned column_count; +unsigned row_count; +} Stmt_fetch; + + +/* +Create statement handle, prepare it with statement, execute and allocate +fetch buffers. +*/ + +void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg, +const char *query_arg) +{ + unsigned long type= CURSOR_TYPE_READ_ONLY; + int rc; + unsigned i; + MYSQL_RES *metadata; + DBUG_ENTER("stmt_fetch_init"); + + /* Save query and statement number for error messages */ + fetch->stmt_no= stmt_no_arg; + fetch->query= query_arg; + + fetch->handle= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query)); + check_execute(fetch->handle, rc); + + /* + The attribute is sent to server on execute and asks to open read-only + for result set + */ + mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE, + (const void*) &type); + + rc= mysql_stmt_execute(fetch->handle); + check_execute(fetch->handle, rc); + + /* Find out total number of columns in result set */ + metadata= mysql_stmt_result_metadata(fetch->handle); + fetch->column_count= mysql_num_fields(metadata); + mysql_free_result(metadata); + + /* + Now allocate bind handles and buffers for output data: + calloc memory to reduce number of MYSQL_BIND members we need to + set up. + */ + + fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) * + fetch->column_count); + fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count); + fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) * + fetch->column_count); + for (i= 0; i < fetch->column_count; ++i) + { + fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH); + fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING; + fetch->bind_array[i].buffer= fetch->out_data[i]; + fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH; + fetch->bind_array[i].length= fetch->out_data_length + i; + } + + mysql_stmt_bind_result(fetch->handle, fetch->bind_array); + + fetch->row_count= 0; + fetch->is_open= TRUE; + + /* Ready for reading rows */ + DBUG_VOID_RETURN; +} + + +/* Fetch and print one row from cursor */ + +int stmt_fetch_fetch_row(Stmt_fetch *fetch) +{ + int rc; + unsigned i; + DBUG_ENTER("stmt_fetch_fetch_row"); + + if ((rc= mysql_stmt_fetch(fetch->handle)) == 0) + { + ++fetch->row_count; + if (!opt_silent) + printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count); + for (i= 0; i < fetch->column_count; ++i) + { + fetch->out_data[i][fetch->out_data_length[i]]= '\0'; + if (!opt_silent) + printf("column %d: %s\n", i+1, fetch->out_data[i]); + } + } + else + fetch->is_open= FALSE; + DBUG_RETURN(rc); +} + + +void stmt_fetch_close(Stmt_fetch *fetch) +{ + unsigned i; + DBUG_ENTER("stmt_fetch_close"); + + for (i= 0; i < fetch->column_count; ++i) + free(fetch->out_data[i]); + free(fetch->out_data); + free(fetch->out_data_length); + free(fetch->bind_array); + mysql_stmt_close(fetch->handle); + DBUG_VOID_RETURN; +} + +/* +For given array of queries, open query_count cursors and fetch +from them in simultaneous manner. +In case there was an error in one of the cursors, continue +reading from the rest. +*/ + +enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 }; + +my_bool fetch_n(const char **query_list, unsigned query_count, +enum fetch_type fetch_type) +{ + unsigned open_statements= query_count; + int rc, error_count= 0; + Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) * + query_count); + Stmt_fetch *fetch; + DBUG_ENTER("fetch_n"); + + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + /* Init will exit(1) in case of error */ + stmt_fetch_init(fetch, fetch - fetch_array, + query_list[fetch - fetch_array]); + } + + if (fetch_type == USE_STORE_RESULT) + { + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + rc= mysql_stmt_store_result(fetch->handle); + check_execute(fetch->handle, rc); + } + } + + while (open_statements) + { + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch))) + { + open_statements--; + /* + We try to fetch from the rest of the statements in case of + error + */ + if (rc != MYSQL_NO_DATA) + { + fprintf(stderr, + "Got error reading rows from statement %d,\n" + "query is: %s,\n" + "error message: %s", (int) (fetch - fetch_array), + fetch->query, + mysql_stmt_error(fetch->handle)); + error_count++; + } + } + } + } + if (error_count) + fprintf(stderr, "Fetch FAILED"); + else + { + unsigned total_row_count= 0; + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + total_row_count+= fetch->row_count; + if (!opt_silent) + printf("Success, total rows fetched: %d\n", total_row_count); + } + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + stmt_fetch_close(fetch); + free(fetch_array); + DBUG_RETURN(error_count != 0); +} + +/* Separate thread query to test some cases */ + +static my_bool thread_query(const char *query) +{ + MYSQL *l_mysql; + my_bool error; + + error= 0; + if (!opt_silent) + fprintf(stdout, "\n in thread_query(%s)", query); + if (!(l_mysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + return 1; + } + if (!(mysql_real_connect(l_mysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + error= 1; + goto end; + } + l_mysql->reconnect= 1; + if (mysql_query(l_mysql, query)) + { + fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql)); + error= 1; + goto end; + } + mysql_commit(l_mysql); + end: + mysql_close(l_mysql); + return error; +} + + +/* +Read and parse arguments and MySQL options from my.cnf +*/ + +static const char *client_test_load_default_groups[]= { "client", 0 }; +static char **defaults_argv; + +static struct my_option client_test_long_options[] = +{ +{"basedir", 'b', "Basedir for tests.", &opt_basedir, + &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"count", 't', "Number of times test to be executed", &opt_count, + &opt_count, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, +{"database", 'D', "Database to use", &opt_db, &opt_db, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"debug", '#', "Output debug log", &default_dbug_option, + &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +{"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, + 0, 0, 0, 0, 0}, +{"host", 'h', "Connect to host", &opt_host, &opt_host, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"password", 'p', + "Password to use when connecting to server. If password is not given it's asked from the tty.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +{"port", 'P', "Port number to use for connection or 0 for default to, in " + "order of preference, my.cnf, $MYSQL_TCP_PORT, " + #if MYSQL_PORT_DEFAULT == 0 + "/etc/services, " + #endif + "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", + &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"server-arg", 'A', "Send embedded server this as a parameter.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, +{"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, + 0}, +#ifdef HAVE_SMEM +{"shared-memory-base-name", 'm', "Base name of shared memory.", + &shared_memory_base_name, (uchar**)&shared_memory_base_name, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif +{"socket", 'S', "Socket file to use for connection", + &opt_unix_socket, &opt_unix_socket, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"testcase", 'c', + "May disable some code when runs as mysql-test-run testcase.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DONT_ALLOW_USER_CHANGE +{"user", 'u', "User for login if not current user", &opt_user, + &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif +{"vardir", 'v', "Data dir for tests.", &opt_vardir, + &opt_vardir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"getopt-ll-test", 'g', "Option for testing bug in getopt library", + &opt_getopt_ll_test, &opt_getopt_ll_test, 0, + GET_LL, REQUIRED_ARG, 0, 0, LONGLONG_MAX, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +static void usage(void) +{ +/* show the usage string when the user asks for this */ + putc('\n', stdout); + printf("%s Ver %s Distrib %s, for %s (%s)\n", + my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); + puts("By Monty, Venu, Kent and others\n"); + printf("\ +Copyright (C) 2002-2004 MySQL AB\n\ +This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ +and you are welcome to modify and redistribute it under the GPL license\n"); + printf("Usage: %s [OPTIONS] [TESTNAME1 TESTNAME2...]\n", my_progname); + my_print_help(client_test_long_options); + print_defaults("my", client_test_load_default_groups); + my_print_variables(client_test_long_options); +} + + +struct my_tests_st *get_my_tests(); /* Will be defined in main .c file */ + +static struct my_tests_st *my_testlist= 0; + +static my_bool +get_one_option(int optid, const struct my_option *opt __attribute__((unused)), +char *argument) +{ + switch (optid) { + case '#': + DBUG_PUSH(argument ? argument : default_dbug_option); + break; + case 'c': + opt_testcase = 1; + break; + case 'p': + if (argument) + { + char *start=argument; + my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + opt_password= my_strdup(argument, MYF(MY_FAE)); + while (*argument) *argument++= 'x'; /* Destroy argument */ + if (*start) + start[1]=0; + } + else + tty_password= 1; + break; + case 's': + if (argument == disabled_my_option) + opt_silent= 0; + else + opt_silent++; + break; + case 'A': + /* + When the embedded server is being tested, the test suite needs to be + able to pass command-line arguments to the embedded server so it can + locate the language files and data directory. The test suite + (mysql-test-run) never uses config files, just command-line options. + */ + if (!embedded_server_arg_count) + { + embedded_server_arg_count= 1; + embedded_server_args[0]= (char*) ""; + } + if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || + !(embedded_server_args[embedded_server_arg_count++]= + my_strdup(argument, MYF(MY_FAE)))) + { + DIE("Can't use server argument"); + } + break; + case 'T': + { + struct my_tests_st *fptr; + + printf("All possible test names:\n\n"); + for (fptr= my_testlist; fptr->name; fptr++) + printf("%s\n", fptr->name); + exit(0); + break; + } + case '?': + case 'I': /* Info */ + usage(); + exit(0); + break; + } + return 0; +} + +static void get_options(int *argc, char ***argv) +{ + int ho_error; + + if ((ho_error= handle_options(argc, argv, client_test_long_options, + get_one_option))) + exit(ho_error); + + if (tty_password) + opt_password= get_tty_password(NullS); + return; +} + +/* +Print the test output on successful execution before exiting +*/ + +static void print_test_output() +{ + if (opt_silent < 3) + { + fprintf(stdout, "\n\n"); + fprintf(stdout, "All '%d' tests were successful (in '%d' iterations)", + test_count-1, opt_count); + fprintf(stdout, "\n Total execution time: %g SECS", total_time); + if (opt_count > 1) + fprintf(stdout, " (Avg: %g SECS)", total_time/opt_count); + + fprintf(stdout, "\n\n!!! SUCCESS !!!\n"); + } +} + +/*************************************************************************** +main routine +***************************************************************************/ + + +int main(int argc, char **argv) +{ + struct my_tests_st *fptr; + my_testlist= get_my_tests(); + + MY_INIT(argv[0]); + + load_defaults("my", client_test_load_default_groups, &argc, &argv); + defaults_argv= argv; + get_options(&argc, &argv); + + if (mysql_server_init(embedded_server_arg_count, + embedded_server_args, + (char**) embedded_server_groups)) + DIE("Can't initialize MySQL server"); + + /* connect to server with no flags, default protocol, auto reconnect true */ + mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1); + + total_time= 0; + for (iter_count= 1; iter_count <= opt_count; iter_count++) + { + /* Start of tests */ + test_count= 1; + start_time= time((time_t *)0); + if (!argc) + { + for (fptr= my_testlist; fptr->name; fptr++) + (*fptr->function)(); + } + else + { + for ( ; *argv ; argv++) + { + for (fptr= my_testlist; fptr->name; fptr++) + { + if (!strcmp(fptr->name, *argv)) + { + (*fptr->function)(); + break; + } + } + if (!fptr->name) + { + fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv); + fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n", + my_progname); + client_disconnect(mysql, 1); + free_defaults(defaults_argv); + exit(1); + } + } + } + + end_time= time((time_t *)0); + total_time+= difftime(end_time, start_time); + + /* End of tests */ + } + + client_disconnect(mysql, 1); /* disconnect from server */ + + free_defaults(defaults_argv); + print_test_output(); + + while (embedded_server_arg_count > 1) + my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); + + mysql_server_end(); + + my_end(0); + + exit(0); +} diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index f553eb530ae..c38695db1b1 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,378 +25,12 @@ DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. */ - -#include -#include -#include -#include -#include -#include -#include - -#define VER "2.1" -#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ -#define MAX_KEY MAX_INDEXES -#define MAX_SERVER_ARGS 64 - -/* set default options */ -static int opt_testcase = 0; -static char *opt_db= 0; -static char *opt_user= 0; -static char *opt_password= 0; -static char *opt_host= 0; -static char *opt_unix_socket= 0; -#ifdef HAVE_SMEM -static char *shared_memory_base_name= 0; -#endif -static unsigned int opt_port; -static my_bool tty_password= 0, opt_silent= 0; - -static MYSQL *mysql= 0; -static char current_db[]= "client_test_db"; -static unsigned int test_count= 0; -static unsigned int opt_count= 0; -static unsigned int iter_count= 0; -static my_bool have_innodb= FALSE; - -static const char *opt_basedir= "./"; -static const char *opt_vardir= "mysql-test/var"; - -static longlong opt_getopt_ll_test= 0; - -static int embedded_server_arg_count= 0; -static char *embedded_server_args[MAX_SERVER_ARGS]; - -static const char *embedded_server_groups[]= { - "server", - "embedded", - "mysql_client_test_SERVER", - NullS -}; - -static time_t start_time, end_time; -static double total_time; - -const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace"; - -struct my_tests_st -{ - const char *name; - void (*function)(); -}; - -#define myheader(str) \ -DBUG_PRINT("test", ("name: %s", str)); \ -if (opt_silent < 2) \ -{ \ - fprintf(stdout, "\n\n#####################################\n"); \ - fprintf(stdout, "%u of (%u/%u): %s", test_count++, iter_count, \ - opt_count, str); \ - fprintf(stdout, " \n#####################################\n"); \ -} - -#define myheader_r(str) \ -DBUG_PRINT("test", ("name: %s", str)); \ -if (!opt_silent) \ -{ \ - fprintf(stdout, "\n\n#####################################\n"); \ - fprintf(stdout, "%s", str); \ - fprintf(stdout, " \n#####################################\n"); \ -} - -static void print_error(const char *msg); -static void print_st_error(MYSQL_STMT *stmt, const char *msg); -static void client_disconnect(MYSQL* mysql, my_bool drop_db); - - /* - Abort unless given experssion is non-zero. - - SYNOPSIS - DIE_UNLESS(expr) - - DESCRIPTION - We can't use any kind of system assert as we need to - preserve tested invariants in release builds as well. + The fw.c file includes all the mysql_client_test framework; this file + contains only the actual tests, plus the list of test functions to call. */ -#define DIE_UNLESS(expr) \ - ((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) -#define DIE_IF(expr) \ - ((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0)) -#define DIE(expr) \ - die(__FILE__, __LINE__, #expr) - -static void die(const char *file, int line, const char *expr) -{ - fflush(stdout); - fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); - fflush(stderr); - exit(1); -} - - -#define myerror(msg) print_error(msg) -#define mysterror(stmt, msg) print_st_error(stmt, msg) - -#define myquery(RES) \ -{ \ - int r= (RES); \ - if (r) \ - myerror(NULL); \ - DIE_UNLESS(r == 0); \ -} - -#define myquery_r(r) \ -{ \ -if (r) \ - myerror(NULL); \ -DIE_UNLESS(r != 0); \ -} - -#define check_execute(stmt, r) \ -{ \ -if (r) \ - mysterror(stmt, NULL); \ -DIE_UNLESS(r == 0);\ -} - -#define check_execute_r(stmt, r) \ -{ \ -if (r) \ - mysterror(stmt, NULL); \ -DIE_UNLESS(r != 0);\ -} - -#define check_stmt(stmt) \ -{ \ -if ( stmt == 0) \ - myerror(NULL); \ -DIE_UNLESS(stmt != 0); \ -} - -#define check_stmt_r(stmt) \ -{ \ -if (stmt == 0) \ - myerror(NULL);\ -DIE_UNLESS(stmt == 0);\ -} - -#define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);} -#define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);} - - -/* A workaround for Sun Forte 5.6 on Solaris x86 */ - -static int cmp_double(double *a, double *b) -{ - return *a == *b; -} - - -/* Print the error message */ - -static void print_error(const char *msg) -{ - if (!opt_silent) - { - if (mysql && mysql_errno(mysql)) - { - if (mysql->server_version) - fprintf(stdout, "\n [MySQL-%s]", mysql->server_version); - else - fprintf(stdout, "\n [MySQL]"); - fprintf(stdout, "[%d] %s\n", mysql_errno(mysql), mysql_error(mysql)); - } - else if (msg) - fprintf(stderr, " [MySQL] %s\n", msg); - } -} - - -static void print_st_error(MYSQL_STMT *stmt, const char *msg) -{ - if (!opt_silent) - { - if (stmt && mysql_stmt_errno(stmt)) - { - if (stmt->mysql && stmt->mysql->server_version) - fprintf(stdout, "\n [MySQL-%s]", stmt->mysql->server_version); - else - fprintf(stdout, "\n [MySQL]"); - - fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), - mysql_stmt_error(stmt)); - } - else if (msg) - fprintf(stderr, " [MySQL] %s\n", msg); - } -} - -/* - Enhanced version of mysql_client_init(), which may also set shared memory - base on Windows. -*/ -static MYSQL *mysql_client_init(MYSQL* con) -{ - MYSQL* res = mysql_init(con); -#ifdef HAVE_SMEM - if (res && shared_memory_base_name) - mysql_options(res, MYSQL_SHARED_MEMORY_BASE_NAME, shared_memory_base_name); -#endif - return res; -} - -/* - Disable direct calls of mysql_init, as it disregards shared memory base. -*/ -#define mysql_init(A) Please use mysql_client_init instead of mysql_init - - -/* Check if the connection has InnoDB tables */ - -static my_bool check_have_innodb(MYSQL *conn) -{ - MYSQL_RES *res; - MYSQL_ROW row; - int rc; - my_bool result; - - rc= mysql_query(conn, "show variables like 'have_innodb'"); - myquery(rc); - res= mysql_use_result(conn); - DIE_UNLESS(res); - - row= mysql_fetch_row(res); - DIE_UNLESS(row); - - result= strcmp(row[1], "YES") == 0; - mysql_free_result(res); - return result; -} - - -/* - This is to be what mysql_query() is for mysql_real_query(), for - mysql_simple_prepare(): a variant without the 'length' parameter. -*/ - -static MYSQL_STMT *STDCALL -mysql_simple_prepare(MYSQL *mysql_arg, const char *query) -{ - MYSQL_STMT *stmt= mysql_stmt_init(mysql_arg); - if (stmt && mysql_stmt_prepare(stmt, query, (uint) strlen(query))) - { - mysql_stmt_close(stmt); - return 0; - } - return stmt; -} - - -/** - Connect to the server with options given by arguments to this application, - stored in global variables opt_host, opt_user, opt_password, opt_db, - opt_port and opt_unix_socket. - - @param flag[in] client_flag passed on to mysql_real_connect - @param protocol[in] MYSQL_PROTOCOL_* to use for this connection - @param auto_reconnect[in] set to 1 for auto reconnect - - @return pointer to initialized and connected MYSQL object -*/ -static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect) -{ - MYSQL* mysql; - int rc; - static char query[MAX_TEST_QUERY_LENGTH]; - myheader_r("client_connect"); - - if (!opt_silent) - fprintf(stdout, "\n Establishing a connection to '%s' ...", - opt_host ? opt_host : ""); - - if (!(mysql= mysql_client_init(NULL))) - { - opt_silent= 0; - myerror("mysql_client_init() failed"); - exit(1); - } - /* enable local infile, in non-binary builds often disabled by default */ - mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0); - mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol); - - if (!(mysql_real_connect(mysql, opt_host, opt_user, - opt_password, opt_db ? opt_db:"test", opt_port, - opt_unix_socket, flag))) - { - opt_silent= 0; - myerror("connection failed"); - mysql_close(mysql); - fprintf(stdout, "\n Check the connection options using --help or -?\n"); - exit(1); - } - mysql->reconnect= auto_reconnect; - - if (!opt_silent) - fprintf(stdout, "OK"); - - /* set AUTOCOMMIT to ON*/ - mysql_autocommit(mysql, TRUE); - - if (!opt_silent) - { - fprintf(stdout, "\nConnected to MySQL server version: %s (%lu)\n", - mysql_get_server_info(mysql), - (ulong) mysql_get_server_version(mysql)); - fprintf(stdout, "\n Creating a test database '%s' ...", current_db); - } - strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS); - - rc= mysql_query(mysql, query); - myquery(rc); - - strxmov(query, "USE ", current_db, NullS); - rc= mysql_query(mysql, query); - myquery(rc); - have_innodb= check_have_innodb(mysql); - - if (!opt_silent) - fprintf(stdout, "OK"); - - return mysql; -} - - -/* Close the connection */ - -static void client_disconnect(MYSQL* mysql, my_bool drop_db) -{ - static char query[MAX_TEST_QUERY_LENGTH]; - - myheader_r("client_disconnect"); - - if (mysql) - { - if (drop_db) - { - if (!opt_silent) - fprintf(stdout, "\n dropping the test database '%s' ...", current_db); - strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS); - - mysql_query(mysql, query); - if (!opt_silent) - fprintf(stdout, "OK"); - } - - if (!opt_silent) - fprintf(stdout, "\n closing the connection ..."); - mysql_close(mysql); - if (!opt_silent) - fprintf(stdout, "OK\n"); - } -} - +#include "mysql_client_fw.c" /* Query processing */ @@ -443,471 +77,6 @@ static void client_query() } -/* Print dashes */ - -static void my_print_dashes(MYSQL_RES *result) -{ - MYSQL_FIELD *field; - unsigned int i, j; - - mysql_field_seek(result, 0); - fputc('\t', stdout); - fputc('+', stdout); - - for(i= 0; i< mysql_num_fields(result); i++) - { - field= mysql_fetch_field(result); - for(j= 0; j < field->max_length+2; j++) - fputc('-', stdout); - fputc('+', stdout); - } - fputc('\n', stdout); -} - - -/* Print resultset metadata information */ - -static void my_print_result_metadata(MYSQL_RES *result) -{ - MYSQL_FIELD *field; - unsigned int i, j; - unsigned int field_count; - - mysql_field_seek(result, 0); - if (!opt_silent) - { - fputc('\n', stdout); - fputc('\n', stdout); - } - - field_count= mysql_num_fields(result); - for(i= 0; i< field_count; i++) - { - field= mysql_fetch_field(result); - j= strlen(field->name); - if (j < field->max_length) - j= field->max_length; - if (j < 4 && !IS_NOT_NULL(field->flags)) - j= 4; - field->max_length= j; - } - if (!opt_silent) - { - my_print_dashes(result); - fputc('\t', stdout); - fputc('|', stdout); - } - - mysql_field_seek(result, 0); - for(i= 0; i< field_count; i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - fprintf(stdout, " %-*s |", (int) field->max_length, field->name); - } - if (!opt_silent) - { - fputc('\n', stdout); - my_print_dashes(result); - } -} - - -/* Process the result set */ - -static int my_process_result_set(MYSQL_RES *result) -{ - MYSQL_ROW row; - MYSQL_FIELD *field; - unsigned int i; - unsigned int row_count= 0; - - if (!result) - return 0; - - my_print_result_metadata(result); - - while ((row= mysql_fetch_row(result)) != NULL) - { - mysql_field_seek(result, 0); - if (!opt_silent) - { - fputc('\t', stdout); - fputc('|', stdout); - } - - for(i= 0; i< mysql_num_fields(result); i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - { - if (row[i] == NULL) - fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); - else if (IS_NUM(field->type)) - fprintf(stdout, " %*s |", (int) field->max_length, row[i]); - else - fprintf(stdout, " %-*s |", (int) field->max_length, row[i]); - } - } - if (!opt_silent) - { - fputc('\t', stdout); - fputc('\n', stdout); - } - row_count++; - } - if (!opt_silent) - { - if (row_count) - my_print_dashes(result); - - if (mysql_errno(mysql) != 0) - fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); - else - fprintf(stdout, "\n\t%d %s returned\n", row_count, - row_count == 1 ? "row" : "rows"); - } - return row_count; -} - - -static int my_process_result(MYSQL *mysql_arg) -{ - MYSQL_RES *result; - int row_count; - - if (!(result= mysql_store_result(mysql_arg))) - return 0; - - row_count= my_process_result_set(result); - - mysql_free_result(result); - return row_count; -} - - -/* Process the statement result set */ - -#define MAX_RES_FIELDS 50 -#define MAX_FIELD_DATA_SIZE 255 - -static int my_process_stmt_result(MYSQL_STMT *stmt) -{ - int field_count; - int row_count= 0; - MYSQL_BIND buffer[MAX_RES_FIELDS]; - MYSQL_FIELD *field; - MYSQL_RES *result; - char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE]; - ulong length[MAX_RES_FIELDS]; - my_bool is_null[MAX_RES_FIELDS]; - int rc, i; - - if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */ - { - while (!mysql_stmt_fetch(stmt)) - row_count++; - return row_count; - } - - field_count= min(mysql_num_fields(result), MAX_RES_FIELDS); - - bzero((char*) buffer, sizeof(buffer)); - bzero((char*) length, sizeof(length)); - bzero((char*) is_null, sizeof(is_null)); - - for(i= 0; i < field_count; i++) - { - buffer[i].buffer_type= MYSQL_TYPE_STRING; - buffer[i].buffer_length= MAX_FIELD_DATA_SIZE; - buffer[i].length= &length[i]; - buffer[i].buffer= (void *) data[i]; - buffer[i].is_null= &is_null[i]; - } - - rc= mysql_stmt_bind_result(stmt, buffer); - check_execute(stmt, rc); - - rc= 1; - mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc); - rc= mysql_stmt_store_result(stmt); - check_execute(stmt, rc); - my_print_result_metadata(result); - - mysql_field_seek(result, 0); - while ((rc= mysql_stmt_fetch(stmt)) == 0) - { - if (!opt_silent) - { - fputc('\t', stdout); - fputc('|', stdout); - } - mysql_field_seek(result, 0); - for (i= 0; i < field_count; i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - { - if (is_null[i]) - fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); - else if (length[i] == 0) - { - data[i][0]= '\0'; /* unmodified buffer */ - fprintf(stdout, " %*s |", (int) field->max_length, data[i]); - } - else if (IS_NUM(field->type)) - fprintf(stdout, " %*s |", (int) field->max_length, data[i]); - else - fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); - } - } - if (!opt_silent) - { - fputc('\t', stdout); - fputc('\n', stdout); - } - row_count++; - } - DIE_UNLESS(rc == MYSQL_NO_DATA); - if (!opt_silent) - { - if (row_count) - my_print_dashes(result); - fprintf(stdout, "\n\t%d %s returned\n", row_count, - row_count == 1 ? "row" : "rows"); - } - mysql_free_result(result); - return row_count; -} - - -/* Prepare statement, execute, and process result set for given query */ - -int my_stmt_result(const char *buff) -{ - MYSQL_STMT *stmt; - int row_count; - int rc; - - if (!opt_silent) - fprintf(stdout, "\n\n %s", buff); - stmt= mysql_simple_prepare(mysql, buff); - check_stmt(stmt); - - rc= mysql_stmt_execute(stmt); - check_execute(stmt, rc); - - row_count= my_process_stmt_result(stmt); - mysql_stmt_close(stmt); - - return row_count; -} - - -/* Utility function to verify a particular column data */ - -static void verify_col_data(const char *table, const char *col, - const char *exp_data) -{ - static char query[MAX_TEST_QUERY_LENGTH]; - MYSQL_RES *result; - MYSQL_ROW row; - int rc, field= 1; - - if (table && col) - { - strxmov(query, "SELECT ", col, " FROM ", table, " LIMIT 1", NullS); - if (!opt_silent) - fprintf(stdout, "\n %s", query); - rc= mysql_query(mysql, query); - myquery(rc); - - field= 0; - } - - result= mysql_use_result(mysql); - mytest(result); - - if (!(row= mysql_fetch_row(result)) || !row[field]) - { - fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); - exit(1); - } - if (strcmp(row[field], exp_data)) - { - fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", - row[field], exp_data); - DIE_UNLESS(FALSE); - } - mysql_free_result(result); -} - - -/* Utility function to verify the field members */ - -#define verify_prepare_field(result,no,name,org_name,type,table,\ - org_table,db,length,def) \ - do_verify_prepare_field((result),(no),(name),(org_name),(type), \ - (table),(org_table),(db),(length),(def), \ - __FILE__, __LINE__) - -static void do_verify_prepare_field(MYSQL_RES *result, - unsigned int no, const char *name, - const char *org_name, - enum enum_field_types type, - const char *table, - const char *org_table, const char *db, - unsigned long length, const char *def, - const char *file, int line) -{ - MYSQL_FIELD *field; - CHARSET_INFO *cs; - ulonglong expected_field_length; - - if (!(field= mysql_fetch_field_direct(result, no))) - { - fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); - exit(1); - } - cs= get_charset(field->charsetnr, 0); - DIE_UNLESS(cs); - if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32) - expected_field_length= UINT_MAX32; - if (!opt_silent) - { - fprintf(stdout, "\n field[%d]:", no); - fprintf(stdout, "\n name :`%s`\t(expected: `%s`)", field->name, name); - fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)", - field->org_name, org_name); - fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type); - if (table) - fprintf(stdout, "\n table :`%s`\t(expected: `%s`)", - field->table, table); - if (org_table) - fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", - field->org_table, org_table); - fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); - fprintf(stdout, "\n length :`%lu`\t(expected: `%llu`)", - field->length, expected_field_length); - fprintf(stdout, "\n maxlength:`%ld`", field->max_length); - fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); - fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", - field->def ? field->def : "(null)", def ? def: "(null)"); - fprintf(stdout, "\n"); - } - DIE_UNLESS(strcmp(field->name, name) == 0); - DIE_UNLESS(strcmp(field->org_name, org_name) == 0); - /* - XXX: silent column specification change works based on number of - bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even - for CHAR(2) column if its character set is multibyte. - VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would - expect. - */ - if (cs->mbmaxlen == 1) - { - if (field->type != type) - { - fprintf(stderr, - "Expected field type: %d, got type: %d in file %s, line %d\n", - (int) type, (int) field->type, file, line); - DIE_UNLESS(field->type == type); - } - } - if (table) - DIE_UNLESS(strcmp(field->table, table) == 0); - if (org_table) - DIE_UNLESS(strcmp(field->org_table, org_table) == 0); - DIE_UNLESS(strcmp(field->db, db) == 0); - /* - Character set should be taken into account for multibyte encodings, such - as utf8. Field length is calculated as number of characters * maximum - number of bytes a character can occupy. - */ - if (length && (field->length != expected_field_length)) - { - fprintf(stderr, "Expected field length: %llu, got length: %lu\n", - expected_field_length, field->length); - DIE_UNLESS(field->length == expected_field_length); - } - if (def) - DIE_UNLESS(strcmp(field->def, def) == 0); -} - - -/* Utility function to verify the parameter count */ - -static void verify_param_count(MYSQL_STMT *stmt, long exp_count) -{ - long param_count= mysql_stmt_param_count(stmt); - if (!opt_silent) - fprintf(stdout, "\n total parameters in stmt: `%ld` (expected: `%ld`)", - param_count, exp_count); - DIE_UNLESS(param_count == exp_count); -} - - -/* Utility function to verify the total affected rows */ - -static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count) -{ - ulonglong affected_rows= mysql_stmt_affected_rows(stmt); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - DIE_UNLESS(affected_rows == exp_count); -} - - -/* Utility function to verify the total affected rows */ - -static void verify_affected_rows(ulonglong exp_count) -{ - ulonglong affected_rows= mysql_affected_rows(mysql); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - DIE_UNLESS(affected_rows == exp_count); -} - - -/* Utility function to verify the total fields count */ - -static void verify_field_count(MYSQL_RES *result, uint exp_count) -{ - uint field_count= mysql_num_fields(result); - if (!opt_silent) - fprintf(stdout, "\n total fields in the result set: `%d` (expected: `%d`)", - field_count, exp_count); - DIE_UNLESS(field_count == exp_count); -} - - -/* Utility function to execute a query using prepare-execute */ - -#ifndef EMBEDDED_LIBRARY -static void execute_prepare_query(const char *query, ulonglong exp_count) -{ - MYSQL_STMT *stmt; - ulonglong affected_rows; - int rc; - - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); - - rc= mysql_stmt_execute(stmt); - myquery(rc); - - affected_rows= mysql_stmt_affected_rows(stmt); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - - DIE_UNLESS(affected_rows == exp_count); - mysql_stmt_close(stmt); -} -#endif - /* Store result processing */ static void client_store_result() @@ -949,267 +118,6 @@ static void client_use_result() } -/* - Accepts arbitrary number of queries and runs them against the database. - Used to fill tables for each test. -*/ - -void fill_tables(const char **query_list, unsigned query_count) -{ - int rc; - const char **query; - DBUG_ENTER("fill_tables"); - for (query= query_list; query < query_list + query_count; - ++query) - { - rc= mysql_query(mysql, *query); - myquery(rc); - } - DBUG_VOID_RETURN; -} - -/* - All state of fetch from one statement: statement handle, out buffers, - fetch position. - See fetch_n for for the only use case. -*/ - -enum { MAX_COLUMN_LENGTH= 255 }; - -typedef struct st_stmt_fetch -{ - const char *query; - unsigned stmt_no; - MYSQL_STMT *handle; - my_bool is_open; - MYSQL_BIND *bind_array; - char **out_data; - unsigned long *out_data_length; - unsigned column_count; - unsigned row_count; -} Stmt_fetch; - - -/* - Create statement handle, prepare it with statement, execute and allocate - fetch buffers. -*/ - -void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg, - const char *query_arg) -{ - unsigned long type= CURSOR_TYPE_READ_ONLY; - int rc; - unsigned i; - MYSQL_RES *metadata; - DBUG_ENTER("stmt_fetch_init"); - - /* Save query and statement number for error messages */ - fetch->stmt_no= stmt_no_arg; - fetch->query= query_arg; - - fetch->handle= mysql_stmt_init(mysql); - - rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query)); - check_execute(fetch->handle, rc); - - /* - The attribute is sent to server on execute and asks to open read-only - for result set - */ - mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE, - (const void*) &type); - - rc= mysql_stmt_execute(fetch->handle); - check_execute(fetch->handle, rc); - - /* Find out total number of columns in result set */ - metadata= mysql_stmt_result_metadata(fetch->handle); - fetch->column_count= mysql_num_fields(metadata); - mysql_free_result(metadata); - - /* - Now allocate bind handles and buffers for output data: - calloc memory to reduce number of MYSQL_BIND members we need to - set up. - */ - - fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) * - fetch->column_count); - fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count); - fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) * - fetch->column_count); - for (i= 0; i < fetch->column_count; ++i) - { - fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH); - fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING; - fetch->bind_array[i].buffer= fetch->out_data[i]; - fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH; - fetch->bind_array[i].length= fetch->out_data_length + i; - } - - mysql_stmt_bind_result(fetch->handle, fetch->bind_array); - - fetch->row_count= 0; - fetch->is_open= TRUE; - - /* Ready for reading rows */ - DBUG_VOID_RETURN; -} - - -/* Fetch and print one row from cursor */ - -int stmt_fetch_fetch_row(Stmt_fetch *fetch) -{ - int rc; - unsigned i; - DBUG_ENTER("stmt_fetch_fetch_row"); - - if ((rc= mysql_stmt_fetch(fetch->handle)) == 0) - { - ++fetch->row_count; - if (!opt_silent) - printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count); - for (i= 0; i < fetch->column_count; ++i) - { - fetch->out_data[i][fetch->out_data_length[i]]= '\0'; - if (!opt_silent) - printf("column %d: %s\n", i+1, fetch->out_data[i]); - } - } - else - fetch->is_open= FALSE; - DBUG_RETURN(rc); -} - - -void stmt_fetch_close(Stmt_fetch *fetch) -{ - unsigned i; - DBUG_ENTER("stmt_fetch_close"); - - for (i= 0; i < fetch->column_count; ++i) - free(fetch->out_data[i]); - free(fetch->out_data); - free(fetch->out_data_length); - free(fetch->bind_array); - mysql_stmt_close(fetch->handle); - DBUG_VOID_RETURN; -} - -/* - For given array of queries, open query_count cursors and fetch - from them in simultaneous manner. - In case there was an error in one of the cursors, continue - reading from the rest. -*/ - -enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 }; - -my_bool fetch_n(const char **query_list, unsigned query_count, - enum fetch_type fetch_type) -{ - unsigned open_statements= query_count; - int rc, error_count= 0; - Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) * - query_count); - Stmt_fetch *fetch; - DBUG_ENTER("fetch_n"); - - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - { - /* Init will exit(1) in case of error */ - stmt_fetch_init(fetch, fetch - fetch_array, - query_list[fetch - fetch_array]); - } - - if (fetch_type == USE_STORE_RESULT) - { - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - { - rc= mysql_stmt_store_result(fetch->handle); - check_execute(fetch->handle, rc); - } - } - - while (open_statements) - { - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - { - if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch))) - { - open_statements--; - /* - We try to fetch from the rest of the statements in case of - error - */ - if (rc != MYSQL_NO_DATA) - { - fprintf(stderr, - "Got error reading rows from statement %d,\n" - "query is: %s,\n" - "error message: %s", (int) (fetch - fetch_array), - fetch->query, - mysql_stmt_error(fetch->handle)); - error_count++; - } - } - } - } - if (error_count) - fprintf(stderr, "Fetch FAILED"); - else - { - unsigned total_row_count= 0; - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - total_row_count+= fetch->row_count; - if (!opt_silent) - printf("Success, total rows fetched: %d\n", total_row_count); - } - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - stmt_fetch_close(fetch); - free(fetch_array); - DBUG_RETURN(error_count != 0); -} - -/* Separate thread query to test some cases */ - -static my_bool thread_query(const char *query) -{ - MYSQL *l_mysql; - my_bool error; - - error= 0; - if (!opt_silent) - fprintf(stdout, "\n in thread_query(%s)", query); - if (!(l_mysql= mysql_client_init(NULL))) - { - myerror("mysql_client_init() failed"); - return 1; - } - if (!(mysql_real_connect(l_mysql, opt_host, opt_user, - opt_password, current_db, opt_port, - opt_unix_socket, 0))) - { - myerror("connection failed"); - error= 1; - goto end; - } - l_mysql->reconnect= 1; - if (mysql_query(l_mysql, query)) - { - fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql)); - error= 1; - goto end; - } - mysql_commit(l_mysql); -end: - mysql_close(l_mysql); - return error; -} - - /* Query processing */ static void test_debug_example() @@ -18593,85 +17501,6 @@ static void test_bug13001491() } -/* - Read and parse arguments and MySQL options from my.cnf -*/ - -static const char *client_test_load_default_groups[]= { "client", 0 }; -static char **defaults_argv; - -static struct my_option client_test_long_options[] = -{ - {"basedir", 'b', "Basedir for tests.", &opt_basedir, - &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"count", 't', "Number of times test to be executed", &opt_count, - &opt_count, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, - {"database", 'D', "Database to use", &opt_db, &opt_db, - 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"debug", '#', "Output debug log", &default_dbug_option, - &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, - 0, 0, 0, 0, 0}, - {"host", 'h', "Connect to host", &opt_host, &opt_host, - 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"password", 'p', - "Password to use when connecting to server. If password is not given it's asked from the tty.", - 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"port", 'P', "Port number to use for connection or 0 for default to, in " - "order of preference, my.cnf, $MYSQL_TCP_PORT, " -#if MYSQL_PORT_DEFAULT == 0 - "/etc/services, " -#endif - "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"server-arg", 'A', "Send embedded server this as a parameter.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, - {"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, - 0}, -#ifdef HAVE_SMEM - {"shared-memory-base-name", 'm', "Base name of shared memory.", - &shared_memory_base_name, (uchar**)&shared_memory_base_name, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif - {"socket", 'S', "Socket file to use for connection", - &opt_unix_socket, &opt_unix_socket, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"testcase", 'c', - "May disable some code when runs as mysql-test-run testcase.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifndef DONT_ALLOW_USER_CHANGE - {"user", 'u', "User for login if not current user", &opt_user, - &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif - {"vardir", 'v', "Data dir for tests.", &opt_vardir, - &opt_vardir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"getopt-ll-test", 'g', "Option for testing bug in getopt library", - &opt_getopt_ll_test, &opt_getopt_ll_test, 0, - GET_LL, REQUIRED_ARG, 0, 0, LONGLONG_MAX, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} -}; - - -static void usage(void) -{ - /* show the usage string when the user asks for this */ - putc('\n', stdout); - printf("%s Ver %s Distrib %s, for %s (%s)\n", - my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); - puts("By Monty, Venu, Kent and others\n"); - printf("\ -Copyright (C) 2002-2004 MySQL AB\n\ -This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ -and you are welcome to modify and redistribute it under the GPL license\n"); - printf("Usage: %s [OPTIONS] [TESTNAME1 TESTNAME2...]\n", my_progname); - my_print_help(client_test_long_options); - print_defaults("my", client_test_load_default_groups); - my_print_variables(client_test_long_options); -} - - static struct my_tests_st my_tests[]= { { "disable_query_logs", disable_query_logs }, { "test_view_sp_list_fields", test_view_sp_list_fields }, @@ -18926,181 +17755,4 @@ static struct my_tests_st my_tests[]= { }; -static my_bool -get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) -{ - switch (optid) { - case '#': - DBUG_PUSH(argument ? argument : default_dbug_option); - break; - case 'c': - opt_testcase = 1; - break; - case 'p': - if (argument) - { - char *start=argument; - my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); - opt_password= my_strdup(argument, MYF(MY_FAE)); - while (*argument) *argument++= 'x'; /* Destroy argument */ - if (*start) - start[1]=0; - } - else - tty_password= 1; - break; - case 's': - if (argument == disabled_my_option) - opt_silent= 0; - else - opt_silent++; - break; - case 'A': - /* - When the embedded server is being tested, the test suite needs to be - able to pass command-line arguments to the embedded server so it can - locate the language files and data directory. The test suite - (mysql-test-run) never uses config files, just command-line options. - */ - if (!embedded_server_arg_count) - { - embedded_server_arg_count= 1; - embedded_server_args[0]= (char*) ""; - } - if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || - !(embedded_server_args[embedded_server_arg_count++]= - my_strdup(argument, MYF(MY_FAE)))) - { - DIE("Can't use server argument"); - } - break; - case 'T': - { - struct my_tests_st *fptr; - - printf("All possible test names:\n\n"); - for (fptr= my_tests; fptr->name; fptr++) - printf("%s\n", fptr->name); - exit(0); - break; - } - case '?': - case 'I': /* Info */ - usage(); - exit(0); - break; - } - return 0; -} - -static void get_options(int *argc, char ***argv) -{ - int ho_error; - - if ((ho_error= handle_options(argc, argv, client_test_long_options, - get_one_option))) - exit(ho_error); - - if (tty_password) - opt_password= get_tty_password(NullS); - return; -} - -/* - Print the test output on successful execution before exiting -*/ - -static void print_test_output() -{ - if (opt_silent < 3) - { - fprintf(stdout, "\n\n"); - fprintf(stdout, "All '%d' tests were successful (in '%d' iterations)", - test_count-1, opt_count); - fprintf(stdout, "\n Total execution time: %g SECS", total_time); - if (opt_count > 1) - fprintf(stdout, " (Avg: %g SECS)", total_time/opt_count); - - fprintf(stdout, "\n\n!!! SUCCESS !!!\n"); - } -} - -/*************************************************************************** - main routine -***************************************************************************/ - - -int main(int argc, char **argv) -{ - struct my_tests_st *fptr; - - MY_INIT(argv[0]); - - load_defaults("my", client_test_load_default_groups, &argc, &argv); - defaults_argv= argv; - get_options(&argc, &argv); - - if (mysql_server_init(embedded_server_arg_count, - embedded_server_args, - (char**) embedded_server_groups)) - DIE("Can't initialize MySQL server"); - - /* connect to server with no flags, default protocol, auto reconnect true */ - mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1); - - total_time= 0; - for (iter_count= 1; iter_count <= opt_count; iter_count++) - { - /* Start of tests */ - test_count= 1; - start_time= time((time_t *)0); - if (!argc) - { - for (fptr= my_tests; fptr->name; fptr++) - (*fptr->function)(); - } - else - { - for ( ; *argv ; argv++) - { - for (fptr= my_tests; fptr->name; fptr++) - { - if (!strcmp(fptr->name, *argv)) - { - (*fptr->function)(); - break; - } - } - if (!fptr->name) - { - fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv); - fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n", - my_progname); - client_disconnect(mysql, 1); - free_defaults(defaults_argv); - exit(1); - } - } - } - - end_time= time((time_t *)0); - total_time+= difftime(end_time, start_time); - - /* End of tests */ - } - - client_disconnect(mysql, 1); /* disconnect from server */ - - free_defaults(defaults_argv); - print_test_output(); - - while (embedded_server_arg_count > 1) - my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); - - mysql_server_end(); - - my_end(0); - - exit(0); -} +static struct my_tests_st *get_my_tests() { return my_tests; } From db33b4994d92bb1da17c02981f94d2ec148d8048 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 9 Jul 2012 16:36:50 +0200 Subject: [PATCH 31/44] Fixed compile error in mysql_client_test using gcc --- tests/mysql_client_fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mysql_client_fw.c b/tests/mysql_client_fw.c index 27a06501d7a..34a4c05215b 100644 --- a/tests/mysql_client_fw.c +++ b/tests/mysql_client_fw.c @@ -1190,7 +1190,7 @@ and you are welcome to modify and redistribute it under the GPL license\n"); } -struct my_tests_st *get_my_tests(); /* Will be defined in main .c file */ +static struct my_tests_st *get_my_tests(); /* To be defined in main .c file */ static struct my_tests_st *my_testlist= 0; From fcc53fa77cc514a9bd5b07adf905c583bb063f4b Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 10 Jul 2012 10:04:57 +0200 Subject: [PATCH 32/44] mysql_client_test did not build within limbysqld/examples --- libmysqld/examples/CMakeLists.txt | 3 ++- libmysqld/examples/Makefile.am | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libmysqld/examples/CMakeLists.txt b/libmysqld/examples/CMakeLists.txt index 2b900a1fa8f..d7f994d9b9f 100644 --- a/libmysqld/examples/CMakeLists.txt +++ b/libmysqld/examples/CMakeLists.txt @@ -17,7 +17,8 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/libmysqld/include ${CMAKE_SOURCE_DIR}/regex - ${CMAKE_SOURCE_DIR}/zlib + ${CMAKE_SOURCE_DIR}/zlib + ${CMAKE_SOURCE_DIR}/tests ${CMAKE_SOURCE_DIR}/extra/yassl/include) # Currently does not work with DBUG, there are missing symbols reported. diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am index a732b209e27..a0f1a64ffdc 100644 --- a/libmysqld/examples/Makefile.am +++ b/libmysqld/examples/Makefile.am @@ -35,7 +35,7 @@ link_sources: DEFS = -DEMBEDDED_LIBRARY INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(srcdir) \ -I$(top_srcdir) -I$(top_srcdir)/client -I$(top_srcdir)/regex \ - $(openssl_includes) + -I$(top_srcdir)/tests $(openssl_includes) LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@ $(yassl_libs) LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @LIBDL@ $(CXXLDFLAGS) \ @NDB_SCI_LIBS@ @@ -51,6 +51,7 @@ mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) mysql_client_test_embedded_LINK = $(CXXLINK) nodist_mysql_client_test_embedded_SOURCES = mysql_client_test.c +mysql_client_test.o: $(top_srcdir)/tests/mysql_client_fw.c # Don't update the files from bitkeeper %::SCCS/s.% From cf858b71ce0cc18909983d7f928a6961a580d77b Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Tue, 10 Jul 2012 14:23:17 +0530 Subject: [PATCH 33/44] BUG#11762670:MY_B_WRITE RETURN VALUE IGNORED Problem: ======= The return value from my_b_write is ignored by: `my_b_write_quoted', `my_b_write_bit',`Query_log_event::print_query_header' Most callers of `my_b_printf' ignore the return value. `log_event.cc' has many calls to it. Analysis: ======== `my_b_write' is used to write data into a file. If the write fails it sets appropriate error number and error message through my_error() function call and sets the IO_CACHE::error == -1. `my_b_printf' function is also used to write data into a file, it internally invokes my_b_write to do the write operation. Upon success it returns number of characters written to file and on error it returns -1 and sets the error through my_error() and also sets IO_CACHE::error == -1. Most of the event specific print functions for example `Create_file_log_event::print', `Execute_load_log_event::print' etc are the ones which make several calls to the above two functions and they do not check for the return value after the 'print' call. All the above mentioned abuse cases deal with the client side. Fix: === As part of bug fix a check for IO_CACHE::error == -1 has been added at a very high level after the call to the 'print' function. There are few more places where the return value of "my_b_write" is ignored those are mentioned below. +++ mysys/mf_iocache2.c 2012-06-04 07:03:15 +0000 @@ -430,7 +430,8 @@ memset(buffz, '0', minimum_width - length2); else memset(buffz, ' ', minimum_width - length2); - my_b_write(info, buffz, minimum_width - length2); +++ sql/log.cc 2012-06-08 09:04:46 +0000 @@ -2388,7 +2388,12 @@ { end= strxmov(buff, "# administrator command: ", NullS); buff_len= (ulong) (end - buff); - my_b_write(&log_file, (uchar*) buff, buff_len); At these places appropriate return value handlers have been added. --- client/mysqlbinlog.cc | 13 ++++++++++++- mysys/mf_iocache2.c | 6 +++++- sql/log.cc | 5 ++++- sql/log_event.cc | 24 +++++++++++++++++++----- sql/rpl_utility.h | 2 +- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index e7840865a58..b5acfc5c169 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -784,8 +784,11 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, goto end; } else + { ce->print(result_file, print_event_info, TRUE); - + if (head->error == -1) + goto err; + } // If this binlog is not 3.23 ; why this test?? if (glob_description_event->binlog_version >= 3) { @@ -836,6 +839,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, ce->print(result_file, print_event_info, TRUE); my_free((char*)ce->fname,MYF(MY_WME)); delete ce; + if (head->error == -1) + goto err; } else warning("Ignoring Execute_load_log_event as there is no " @@ -890,6 +895,12 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, { convert_path_to_forward_slashes(fname); exlq->print(result_file, print_event_info, fname); + if (head->error == -1) + { + if (fname) + my_free(fname, MYF(MY_WME)); + goto err; + } } else warning("Ignoring Execute_load_query since there is no " diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 828145b7931..dd56e332433 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -430,7 +430,11 @@ process_flags: memset(buffz, '0', minimum_width - length2); else memset(buffz, ' ', minimum_width - length2); - my_b_write(info, buffz, minimum_width - length2); + if (my_b_write(info, buffz, minimum_width - length2)) + { + my_afree(buffz); + goto err; + } my_afree(buffz); } diff --git a/sql/log.cc b/sql/log.cc index 3714f1190be..57c14b24782 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2388,7 +2388,10 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, { end= strxmov(buff, "# administrator command: ", NullS); buff_len= (ulong) (end - buff); - my_b_write(&log_file, (uchar*) buff, buff_len); + DBUG_EXECUTE_IF("simulate_slow_log_write_error", + {DBUG_SET("+d,simulate_file_write_error");}); + if(my_b_write(&log_file, (uchar*) buff, buff_len)) + tmp_errno= errno; } if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) || my_b_write(&log_file, (uchar*) ";\n",2) || diff --git a/sql/log_event.cc b/sql/log_event.cc index a47b3680d82..2ad740698c6 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6312,11 +6312,18 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info { Load_log_event::print(file, print_event_info, !check_fname_outside_temp_buf()); - /* - That one is for "file_id: etc" below: in mysqlbinlog we want the #, in - SHOW BINLOG EVENTS we don't. - */ - my_b_printf(&cache, "#"); + /** + reduce the size of io cache so that the write function is called + for every call to my_b_printf(). + */ + DBUG_EXECUTE_IF ("simulate_create_event_write_error", + {(&cache)->write_pos= (&cache)->write_end; + DBUG_SET("+d,simulate_file_write_error");}); + /* + That one is for "file_id: etc" below: in mysqlbinlog we want the #, in + SHOW BINLOG EVENTS we don't. + */ + my_b_printf(&cache, "#"); } my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len); @@ -6992,6 +6999,13 @@ void Execute_load_query_log_event::print(FILE* file, Write_on_release_cache cache(&print_event_info->head_cache, file); print_query_header(&cache, print_event_info); + /** + reduce the size of io cache so that the write function is called + for every call to my_b_printf(). + */ + DBUG_EXECUTE_IF ("simulate_execute_event_write_error", + {(&cache)->write_pos= (&cache)->write_end; + DBUG_SET("+d,simulate_file_write_error");}); if (local_fname) { diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 81a10cca814..b2577643add 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -300,7 +300,7 @@ private: public: Deferred_log_events(Relay_log_info *rli); ~Deferred_log_events(); - /* queue for exection at Query-log-event time prior the Query */; + /* queue for exection at Query-log-event time prior the Query */ int add(Log_event *ev); bool is_empty(); bool execute(Relay_log_info *rli); From bd079618a222f1cdf590e24c238ca73660737b4b Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 10 Jul 2012 11:48:43 +0200 Subject: [PATCH 34/44] mysql_client_fw.c was not included in make dist --- tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 4929fa7ba9b..3da18683f85 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -33,6 +33,7 @@ EXTRA_DIST = auto_increment.res auto_increment.tst \ grant.pl grant.res test_delayed_insert.pl \ pmail.pl mail_to_db.pl table_types.pl \ myisam-big-rows.tst \ + mysql_client_fw.c \ CMakeLists.txt bin_PROGRAMS = mysql_client_test From bc4a83d5b4f83f158f9e27bf2ee70146e93c5edd Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 10 Jul 2012 11:57:24 +0200 Subject: [PATCH 35/44] mysql_client_fw.c was not included in make dist --- tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 4929fa7ba9b..3da18683f85 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -33,6 +33,7 @@ EXTRA_DIST = auto_increment.res auto_increment.tst \ grant.pl grant.res test_delayed_insert.pl \ pmail.pl mail_to_db.pl table_types.pl \ myisam-big-rows.tst \ + mysql_client_fw.c \ CMakeLists.txt bin_PROGRAMS = mysql_client_test From abf4b3fa6aab3dac2d532361b237ccbf6a1e633d Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Tue, 10 Jul 2012 18:24:11 +0530 Subject: [PATCH 36/44] BUG#11759333: SBR LOGGING WARNING MESSAGES FOR PRIMARY KEY UPDATES WITH A LIMIT OF 1 Problem: The unsafety warning for statements such as update...limit1 where pk=1 are thrown when binlog-format = STATEMENT,despite of the fact that such statements are actually safe. this leads to filling up of the disk space with false warnings. Solution: This is not a complete fix for the problem, but prevents the disks from getting filled up. This should therefore be regarded as a workaround. In the future this should be overriden by server general suppress/filtering framework. It should also be noted that another worklog is supposed to defeat this case's artificial unsafety. We use a warning suppression mechanism to detect warning flood, enable the suppression, and disable this when the average warnings/second has reduced to acceptable limits. Activation: The supression for LIMIT unsafe statements are activated when the last 50 warnings were logged in less than 50 seconds. Supression: Once activated this supression will prevent the individual warnings to be logged in the error log, but print the warning for every 50 warnings with the note: "The last warning was repeated N times in last S seconds" Noteworthy is the fact that this supression works only on the error logs and the warnings seen by the clients will remain as it is (i.e. one warning/ unsafe statement) Deactivation: The supression will be deactivated once the average # of warnings/sec have gone down to the acceptable limits. --- sql/sql_class.cc | 144 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 5 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7e93157c69e..c118030e7b4 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4806,6 +4806,140 @@ show_query_type(THD::enum_binlog_query_type qtype) } #endif +/* + Constants required for the limit unsafe warnings suppression +*/ +//seconds after which the limit unsafe warnings suppression will be activated +#define LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT 50 +//number of limit unsafe warnings after which the suppression will be activated +#define LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT 50 + +static struct timeval limit_unsafe_suppression_start_time; +static struct timezone limit_unsafe_suppression_start_time_zone; +static bool unsafe_warning_suppression_is_activated= false; +static int limit_unsafe_warning_count= 0; + +/** + Auxiliary function to reset the limit unsafety warning suppression. +*/ +static void reset_binlog_unsafe_suppression() +{ + DBUG_ENTER("reset_binlog_unsafe_suppression"); + unsafe_warning_suppression_is_activated= false; + limit_unsafe_warning_count= 0; + gettimeofday(&limit_unsafe_suppression_start_time, + &limit_unsafe_suppression_start_time_zone); + DBUG_VOID_RETURN; +} + +/** + Auxiliary function to print warning in the error log. +*/ +static void print_unsafe_warning_to_log(int unsafe_type, char* buf, + char* query) +{ + DBUG_ENTER("print_unsafe_warning_in_log"); + sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT), + ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type])); + sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query); + DBUG_VOID_RETURN; +} + +/** + Auxiliary function to check if the warning for limit unsafety should be + thrown or suppressed. Details of the implementation can be found in the + comments inline. + SYNOPSIS: + @params + buf - buffer to hold the warning message text + unsafe_type - The type of unsafety. + query - The actual query statement. + + TODO: Remove this function and implement a general service for all warnings + that would prevent flooding the error log. +*/ +static void do_unsafe_limit_checkout(char* buf, int unsafe_type, char* query) +{ + struct timeval now; + struct timezone tz_now; + DBUG_ENTER("do_unsafe_limit_checkout"); + DBUG_ASSERT(unsafe_type == LEX::BINLOG_STMT_UNSAFE_LIMIT); + limit_unsafe_warning_count++; + /* + INITIALIZING: + If this is the first time this function is called with log warning + enabled, the monitoring the unsafe warnings should start. + */ + if (limit_unsafe_suppression_start_time.tv_sec == 0) + { + gettimeofday(&limit_unsafe_suppression_start_time, + &limit_unsafe_suppression_start_time_zone); + print_unsafe_warning_to_log(unsafe_type, buf, query); + } + else + { + if (!unsafe_warning_suppression_is_activated) + print_unsafe_warning_to_log(unsafe_type, buf, query); + + if (limit_unsafe_warning_count >= + LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT) + { + gettimeofday (&now, &tz_now); + if (!unsafe_warning_suppression_is_activated) + { + /* + ACTIVATION: + We got LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT warnings in + less than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT we activate the + suppression. + */ + if ((now.tv_sec-limit_unsafe_suppression_start_time.tv_sec) <= + LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) + { + unsafe_warning_suppression_is_activated= true; + DBUG_PRINT("info",("A warning flood has been detected and the limit \ +unsafety warning suppression has been activated.")); + } + else + { + /* + there is no flooding till now, therefore we restart the monitoring + */ + gettimeofday(&limit_unsafe_suppression_start_time, + &limit_unsafe_suppression_start_time_zone); + limit_unsafe_warning_count= 0; + } + } + else + { + /* + Print the suppression note and the unsafe warning. + */ + sql_print_information("The following warning was suppressed %d times \ +during the last %d seconds in the error log", + limit_unsafe_warning_count, + (int) + (now.tv_sec - + limit_unsafe_suppression_start_time.tv_sec)); + print_unsafe_warning_to_log(unsafe_type, buf, query); + /* + DEACTIVATION: We got LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT + warnings in more than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT, the + suppression should be deactivated. + */ + if ((now.tv_sec - limit_unsafe_suppression_start_time.tv_sec) > + LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) + { + reset_binlog_unsafe_suppression(); + DBUG_PRINT("info",("The limit unsafety warning supression has been \ +deactivated")); + } + } + limit_unsafe_warning_count= 0; + } + } + DBUG_VOID_RETURN; +} /** Auxiliary method used by @c binlog_query() to raise warnings. @@ -4815,6 +4949,7 @@ show_query_type(THD::enum_binlog_query_type qtype) */ void THD::issue_unsafe_warnings() { + char buf[MYSQL_ERRMSG_SIZE * 2]; DBUG_ENTER("issue_unsafe_warnings"); /* Ensure that binlog_unsafe_warning_flags is big enough to hold all @@ -4840,17 +4975,16 @@ void THD::issue_unsafe_warnings() ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type])); if (global_system_variables.log_warnings) { - char buf[MYSQL_ERRMSG_SIZE * 2]; - sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT), - ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type])); - sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query()); + if (unsafe_type == LEX::BINLOG_STMT_UNSAFE_LIMIT) + do_unsafe_limit_checkout( buf, unsafe_type, query()); + else //cases other than LIMIT unsafety + print_unsafe_warning_to_log(unsafe_type, buf, query()); } } } DBUG_VOID_RETURN; } - /** Log the current query. From bb35915dbd67475ca60241db29e12c92b579a33d Mon Sep 17 00:00:00 2001 From: "mysql-builder@oracle.com" <> Date: Tue, 10 Jul 2012 18:55:07 +0530 Subject: [PATCH 37/44] From 96bb813a456a6095ba98de6bb5b23b3223698413 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Tue, 10 Jul 2012 16:13:02 +0200 Subject: [PATCH 38/44] Bug#12623923 Server can crash after failure to create primary key with innodb tables The bug was triggered if a single ALTER TABLE statement both added and dropped indexes and ALTER TABLE failed during drop (e.g. because the index was needed in a foreign key constraint). In such cases, the server index information would get out of sync with InnoDB - the added index would be present inside InnoDB, but not in the server. This could then lead to InnoDB error messages and/or server crashes. The root cause is that new indexes are added before old indexes are dropped. This means that if ALTER TABLE fails while dropping indexes, index changes will be reverted in the server but not inside InnoDB. This patch fixes the problem by dropping any added indexes if drop fails (for ALTER TABLE statements that both adds and drops indexes). However, this won't work if we added a primary key as this key might not be possible to drop inside InnoDB. Therefore, we resort to the copy algorithm if a primary key is added by an ALTER TABLE statement that also drops an index. In 5.6 this bug is more properly fixed by the handler interface changes done in the scope of WL#5534 "Online ALTER". --- sql/sql_table.cc | 49 +++++++++++++++++++---- storage/innobase/handler/ha_innodb.cc | 13 ++++-- storage/innobase/handler/handler0alter.cc | 14 +++---- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 60ae2ed800b..7d70fa8afd2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6313,11 +6313,23 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, the primary key is not added and dropped in the same statement. Otherwise we have to recreate the table. need_copy_table is no-zero at this place. + + Also, in-place is not possible if we add a primary key + and drop another key in the same statement. If the drop fails, + we will not be able to revert adding of primary key. */ if ( pk_changed < 2 ) { - if ((alter_flags & needed_inplace_with_read_flags) == - needed_inplace_with_read_flags) + if ((needed_inplace_with_read_flags & HA_INPLACE_ADD_PK_INDEX_NO_WRITE) && + index_drop_count > 0) + { + /* + Do copy, not in-place ALTER. + Avoid setting ALTER_TABLE_METADATA_ONLY. + */ + } + else if ((alter_flags & needed_inplace_with_read_flags) == + needed_inplace_with_read_flags) { /* All required in-place flags to allow concurrent reads are present. */ need_copy_table= ALTER_TABLE_METADATA_ONLY; @@ -6579,17 +6591,38 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, Tell the handler to prepare for drop indexes. This re-numbers the indexes to get rid of gaps. */ - if ((error= table->file->prepare_drop_index(table, key_numbers, - index_drop_count))) + error= table->file->prepare_drop_index(table, key_numbers, + index_drop_count); + if (!error) { - table->file->print_error(error, MYF(0)); - goto err_new_table_cleanup; + /* Tell the handler to finally drop the indexes. */ + error= table->file->final_drop_index(table); } - /* Tell the handler to finally drop the indexes. */ - if ((error= table->file->final_drop_index(table))) + if (error) { table->file->print_error(error, MYF(0)); + if (index_add_count) // Drop any new indexes added. + { + /* + Temporarily set table-key_info to include information about the + indexes added above that we now need to drop. + */ + KEY *save_key_info= table->key_info; + table->key_info= key_info_buffer; + if ((error= table->file->prepare_drop_index(table, index_add_buffer, + index_add_count))) + table->file->print_error(error, MYF(0)); + else if ((error= table->file->final_drop_index(table))) + table->file->print_error(error, MYF(0)); + table->key_info= save_key_info; + } + + /* + Mark this TABLE instance as stale to avoid + out-of-sync index information. + */ + table->m_needs_reopen= true; goto err_new_table_cleanup; } } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ea47a8160f9..60a62482f9c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8010,10 +8010,15 @@ innobase_get_mysql_key_number_for_index( } } - /* Print an error message if we cannot find the index - ** in the "index translation table". */ - sql_print_error("Cannot find index %s in InnoDB index " - "translation table.", index->name); + /* If index_count in translation table is set to 0, it + is possible we are in the process of rebuilding table, + do not spit error in this case */ + if (share->idx_trans_tbl.index_count) { + /* Print an error message if we cannot find the index + ** in the "index translation table". */ + sql_print_error("Cannot find index %s in InnoDB index " + "translation table.", index->name); + } } /* If we do not have an "index translation table", or not able diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index e8e3cb0e5cd..5e20bea36dd 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -773,7 +773,7 @@ ha_innobase::add_index( row_mysql_lock_data_dictionary(trx); dict_locked = TRUE; - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); /* If a new primary key is defined for the table we need to drop the original table and rebuild all indexes. */ @@ -809,7 +809,7 @@ ha_innobase::add_index( } ut_d(dict_table_check_for_dup_indexes(prebuilt->table, - FALSE)); + TRUE)); mem_heap_free(heap); trx_general_rollback_for_mysql(trx, NULL); row_mysql_unlock_data_dictionary(trx); @@ -1061,7 +1061,7 @@ ha_innobase::final_add_index( trx_commit_for_mysql(prebuilt->trx); } - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); row_mysql_unlock_data_dictionary(trx); trx_free_for_mysql(trx); @@ -1104,7 +1104,7 @@ ha_innobase::prepare_drop_index( /* Test and mark all the indexes to be dropped */ row_mysql_lock_data_dictionary(trx); - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); /* Check that none of the indexes have previously been flagged for deletion. */ @@ -1275,7 +1275,7 @@ func_exit: } while (index); } - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); row_mysql_unlock_data_dictionary(trx); DBUG_RETURN(err); @@ -1322,7 +1322,7 @@ ha_innobase::final_drop_index( prebuilt->table->flags, user_thd); row_mysql_lock_data_dictionary(trx); - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); if (UNIV_UNLIKELY(err)) { @@ -1366,7 +1366,7 @@ ha_innobase::final_drop_index( share->idx_trans_tbl.index_count = 0; func_exit: - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); trx_commit_for_mysql(trx); trx_commit_for_mysql(prebuilt->trx); row_mysql_unlock_data_dictionary(trx); From 7dcc643d10e158d83e5412adc89c5c6463530ff4 Mon Sep 17 00:00:00 2001 From: Mayank Prasad Date: Tue, 10 Jul 2012 19:59:59 +0530 Subject: [PATCH 39/44] Bug#13889741: HANDLE_FATAL_SIGNAL IN _DB_ENTER_ |HANDLE_FATAL_SIGNAL IN STRNLEN Follow up patch to resolve pb2 failure on windows platform --- sql/sql_show.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 189532b2479..e9873d2325f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2784,9 +2784,12 @@ int make_db_list(THD *thd, List *files, /* If we have db lookup vaule we just add it to list and - exit from the function + exit from the function. + We don't do this for database names longer than the maximum + path length. */ - if (lookup_field_vals->db_value.str) + if (lookup_field_vals->db_value.str && + lookup_field_vals->db_value.length < FN_REFLEN) { if (is_infoschema_db(lookup_field_vals->db_value.str, lookup_field_vals->db_value.length)) From 9689dd1fd2904546c8fb04554d0e7e7a074430af Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Tue, 10 Jul 2012 22:02:25 +0530 Subject: [PATCH 40/44] bug#11759333: follow-up patch for the failure on pb2 windows build --- sql/sql_class.cc | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c118030e7b4..8931d67dd25 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4814,8 +4814,7 @@ show_query_type(THD::enum_binlog_query_type qtype) //number of limit unsafe warnings after which the suppression will be activated #define LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT 50 -static struct timeval limit_unsafe_suppression_start_time; -static struct timezone limit_unsafe_suppression_start_time_zone; +static ulonglong limit_unsafe_suppression_start_time= 0; static bool unsafe_warning_suppression_is_activated= false; static int limit_unsafe_warning_count= 0; @@ -4827,8 +4826,7 @@ static void reset_binlog_unsafe_suppression() DBUG_ENTER("reset_binlog_unsafe_suppression"); unsafe_warning_suppression_is_activated= false; limit_unsafe_warning_count= 0; - gettimeofday(&limit_unsafe_suppression_start_time, - &limit_unsafe_suppression_start_time_zone); + limit_unsafe_suppression_start_time= my_getsystime()/10000000; DBUG_VOID_RETURN; } @@ -4860,8 +4858,7 @@ static void print_unsafe_warning_to_log(int unsafe_type, char* buf, */ static void do_unsafe_limit_checkout(char* buf, int unsafe_type, char* query) { - struct timeval now; - struct timezone tz_now; + ulonglong now= 0; DBUG_ENTER("do_unsafe_limit_checkout"); DBUG_ASSERT(unsafe_type == LEX::BINLOG_STMT_UNSAFE_LIMIT); limit_unsafe_warning_count++; @@ -4870,10 +4867,9 @@ static void do_unsafe_limit_checkout(char* buf, int unsafe_type, char* query) If this is the first time this function is called with log warning enabled, the monitoring the unsafe warnings should start. */ - if (limit_unsafe_suppression_start_time.tv_sec == 0) + if (limit_unsafe_suppression_start_time == 0) { - gettimeofday(&limit_unsafe_suppression_start_time, - &limit_unsafe_suppression_start_time_zone); + limit_unsafe_suppression_start_time= my_getsystime()/10000000; print_unsafe_warning_to_log(unsafe_type, buf, query); } else @@ -4884,7 +4880,7 @@ static void do_unsafe_limit_checkout(char* buf, int unsafe_type, char* query) if (limit_unsafe_warning_count >= LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT) { - gettimeofday (&now, &tz_now); + now= my_getsystime()/10000000; if (!unsafe_warning_suppression_is_activated) { /* @@ -4893,7 +4889,7 @@ static void do_unsafe_limit_checkout(char* buf, int unsafe_type, char* query) less than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT we activate the suppression. */ - if ((now.tv_sec-limit_unsafe_suppression_start_time.tv_sec) <= + if ((now-limit_unsafe_suppression_start_time) <= LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) { unsafe_warning_suppression_is_activated= true; @@ -4905,8 +4901,7 @@ unsafety warning suppression has been activated.")); /* there is no flooding till now, therefore we restart the monitoring */ - gettimeofday(&limit_unsafe_suppression_start_time, - &limit_unsafe_suppression_start_time_zone); + limit_unsafe_suppression_start_time= my_getsystime()/10000000; limit_unsafe_warning_count= 0; } } @@ -4919,15 +4914,14 @@ unsafety warning suppression has been activated.")); during the last %d seconds in the error log", limit_unsafe_warning_count, (int) - (now.tv_sec - - limit_unsafe_suppression_start_time.tv_sec)); + (now-limit_unsafe_suppression_start_time)); print_unsafe_warning_to_log(unsafe_type, buf, query); /* DEACTIVATION: We got LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT warnings in more than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT, the suppression should be deactivated. */ - if ((now.tv_sec - limit_unsafe_suppression_start_time.tv_sec) > + if ((now - limit_unsafe_suppression_start_time) > LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) { reset_binlog_unsafe_suppression(); From 781b05fbadbf51259ad1385ef79c3a7a30a62eba Mon Sep 17 00:00:00 2001 From: Chaithra Gopalareddy Date: Wed, 11 Jul 2012 08:19:17 +0530 Subject: [PATCH 41/44] Bug #13444084:PRIMARY KEY OR UNIQUE KEY >453 BYTES FAILS FOR COUNT DISTINCT GROUP BY PROBLEM: To calculate the final result of the count(distinct(select 1)) we call 'end_send' function instead of 'end_send_group'. 'end_send' cannot be called if we have aggregate functions that need to be evaluated. ANALYSIS: While evaluating for a possible loose_index_scan option for the query, the variable 'is_agg_distinct' is set to 'false' as the item in the distinct clause is not a field. But, we choose loose_index_scan by not taking this into consideration. So, while setting the final 'select_function' to evaluate the result, 'precomputed_group_by' is set to TRUE as in this case loose_index_scan is chosen and we do not have agg_distinct in the query (which is clearly wrong as we have one). As a result, 'end_send' function is chosen as the final select_function instead of 'end_send_group'. The difference between the two being, 'end_send_group' evaluates the aggregates while 'end_send' does not. Hence the wrong result. FIX: The variable 'is_agg_distinct' always represents if 'loose_idnex_scan' can be chosen for aggregate_distinct functions present in the select. So, we check for this variable to continue with loose_index_scan option. --- sql/opt_range.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 8a6607cf343..03f444c22b5 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -9463,9 +9463,10 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) have_min= TRUE; else if (min_max_item->sum_func() == Item_sum::MAX_FUNC) have_max= TRUE; - else if (min_max_item->sum_func() == Item_sum::COUNT_DISTINCT_FUNC || - min_max_item->sum_func() == Item_sum::SUM_DISTINCT_FUNC || - min_max_item->sum_func() == Item_sum::AVG_DISTINCT_FUNC) + else if (is_agg_distinct && + (min_max_item->sum_func() == Item_sum::COUNT_DISTINCT_FUNC || + min_max_item->sum_func() == Item_sum::SUM_DISTINCT_FUNC || + min_max_item->sum_func() == Item_sum::AVG_DISTINCT_FUNC)) continue; else DBUG_RETURN(NULL); From 181fcba45b0e4590a532d0d3114ebc92d9881c70 Mon Sep 17 00:00:00 2001 From: "mysql-builder@oracle.com" <> Date: Wed, 11 Jul 2012 08:43:26 +0200 Subject: [PATCH 42/44] From b6e860c8d47a27dbb09a1ea36cc892016e788b25 Mon Sep 17 00:00:00 2001 From: "mysql-builder@oracle.com" <> Date: Wed, 11 Jul 2012 16:42:55 +0530 Subject: [PATCH 43/44] From f4fd8bcfae5fc70a79f9f54f8db387489e373011 Mon Sep 17 00:00:00 2001 From: "bjorn.munch@oracle.com" <> Date: Wed, 11 Jul 2012 15:18:34 +0200 Subject: [PATCH 44/44] Raise version number after cloning 5.1.65 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 4e7a3303353..068328992e0 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.65], [], [mysql]) +AC_INIT([MySQL Server], [5.1.66], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM