From 1d0a11fd159fb05cd1c5c553b152c3848ceb552f Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Thu, 11 Nov 2010 09:46:49 +0000 Subject: [PATCH 01/34] Bug#55436: buffer overflow in debug binary of dbug_buff in Field_new_decimal::store_value There were some misunderstandings about parameters pertaining to buffer-size. Patches fixes the reported off by one and clarifies the documentation. --- mysql-test/r/type_newdecimal.result | 13 +++++++++++++ mysql-test/t/type_newdecimal.test | 14 ++++++++++++++ sql/field.cc | 6 +++--- sql/my_decimal.cc | 11 ++++++----- sql/my_decimal.h | 3 ++- strings/decimal.c | 5 +++-- 6 files changed, 41 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 70ee3a56cf3..c301a7dd629 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -1913,4 +1913,17 @@ group by PAY.id + 1; mult v_net_with_discount v_total 1.0000 27.18 27.180000 DROP TABLE currencies, payments, sub_tasks; +# +# Bug#55436: buffer overflow in debug binary of dbug_buff in +# Field_new_decimal::store_value +# +SET SQL_MODE=''; +CREATE TABLE t1(f1 DECIMAL(44,24)) ENGINE=MYISAM; +INSERT INTO t1 SET f1 = -64878E-85; +Warnings: +Note 1265 Data truncated for column 'f1' at row 1 +SELECT f1 FROM t1; +f1 +0.000000000000000000000000 +DROP TABLE IF EXISTS t1; End of 5.1 tests diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 2cf7ab8fbdf..31a8808da55 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1510,5 +1510,19 @@ group by PAY.id + 1; DROP TABLE currencies, payments, sub_tasks; +--echo # +--echo # Bug#55436: buffer overflow in debug binary of dbug_buff in +--echo # Field_new_decimal::store_value +--echo # + +# this threw memory warnings on Windows. Also make sure future changes +# don't change these results, as per usual. +SET SQL_MODE=''; +CREATE TABLE t1(f1 DECIMAL(44,24)) ENGINE=MYISAM; +INSERT INTO t1 SET f1 = -64878E-85; +SELECT f1 FROM t1; +DROP TABLE IF EXISTS t1; + + --echo End of 5.1 tests diff --git a/sql/field.cc b/sql/field.cc index c887a5f1c9b..cb23ae4fe9f 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2583,7 +2583,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) DBUG_ENTER("Field_new_decimal::store_value"); #ifndef DBUG_OFF { - char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; + char dbug_buff[DECIMAL_MAX_STR_LENGTH+2]; DBUG_PRINT("enter", ("value: %s", dbug_decimal_as_string(dbug_buff, decimal_value))); } #endif @@ -2598,7 +2598,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) } #ifndef DBUG_OFF { - char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; + char dbug_buff[DECIMAL_MAX_STR_LENGTH+2]; DBUG_PRINT("info", ("saving with precision %d scale: %d value %s", (int)precision, (int)dec, dbug_decimal_as_string(dbug_buff, decimal_value))); @@ -2673,7 +2673,7 @@ int Field_new_decimal::store(const char *from, uint length, } #ifndef DBUG_OFF - char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; + char dbug_buff[DECIMAL_MAX_STR_LENGTH+2]; DBUG_PRINT("enter", ("value: %s", dbug_decimal_as_string(dbug_buff, &decimal_value))); #endif diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 3aa01880b83..a38dc341684 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -95,10 +95,11 @@ int my_decimal2string(uint mask, const my_decimal *d, UNSIGNED. Hence the buffer for a ZEROFILLed value is the length the user requested, plus one for a possible decimal point, plus one if the user only wanted decimal places, but we force a leading - zero on them. Because the type is implicitly UNSIGNED, we do not - need to reserve a character for the sign. For all other cases, - fixed_prec will be 0, and my_decimal_string_length() will be called - instead to calculate the required size of the buffer. + zero on them, plus one for the '\0' terminator. Because the type + is implicitly UNSIGNED, we do not need to reserve a character for + the sign. For all other cases, fixed_prec will be 0, and + my_decimal_string_length() will be called instead to calculate the + required size of the buffer. */ int length= (fixed_prec ? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1) @@ -275,7 +276,7 @@ print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length) const char *dbug_decimal_as_string(char *buff, const my_decimal *val) { - int length= DECIMAL_MAX_STR_LENGTH; + int length= DECIMAL_MAX_STR_LENGTH + 1; /* minimum size for buff */ if (!val) return "NULL"; (void)decimal2string((decimal_t*) val, buff, &length, 0,0,0); diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 21669e82c44..2c13142bb60 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -55,7 +55,7 @@ C_MODE_END /** maximum length of string representation (number of maximum decimal - digits + 1 position for sign + 1 position for decimal point) + digits + 1 position for sign + 1 position for decimal point, no terminator) */ #define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2) @@ -212,6 +212,7 @@ inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale, inline int my_decimal_string_length(const my_decimal *d) { + /* length of string representation including terminating '\0' */ return decimal_string_size(d); } diff --git a/strings/decimal.c b/strings/decimal.c index bda296ce832..c91a5d1a7ec 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -320,8 +320,8 @@ int decimal_actual_fraction(decimal_t *from) from - value to convert to - points to buffer where string representation should be stored - *to_len - in: size of to buffer - out: length of the actually written string + *to_len - in: size of to buffer (incl. terminating '\0') + out: length of the actually written string (excl. '\0') fixed_precision - 0 if representation can be variable length and fixed_decimals will not be checked in this case. Put number as with fixed point position with this @@ -338,6 +338,7 @@ int decimal2string(decimal_t *from, char *to, int *to_len, int fixed_precision, int fixed_decimals, char filler) { + /* {intg_len, frac_len} output widths; {intg, frac} places in input */ int len, intg, frac= from->frac, i, intg_len, frac_len, fill; /* number digits before decimal point */ int fixed_intg= (fixed_precision ? From fb18601ee8c2e6cf8d2a9bfbaf6f7ca317b982af Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 8 Feb 2011 17:36:25 +0200 Subject: [PATCH 02/34] Bug #59815: Missing License information with enterprise GPL packages on behalf of Kent: Include the README into the binary packages --- scripts/make_win_bin_dist | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/make_win_bin_dist b/scripts/make_win_bin_dist index c1d01a0342d..7859f42ca29 100755 --- a/scripts/make_win_bin_dist +++ b/scripts/make_win_bin_dist @@ -198,6 +198,7 @@ cp Docs/INSTALL-BINARY $DESTDIR/Docs/ cp Docs/manual.chm $DESTDIR/Docs/ || /bin/true cp ChangeLog $DESTDIR/Docs/ || /bin/true cp support-files/my-*.ini $DESTDIR/ +cp README $DESTDIR/ if [ -f COPYING ] ; then cp COPYING $DESTDIR/ From d5ffcb42350efa6aff05815b237183836bcc778d Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Fri, 11 Feb 2011 11:32:03 +0100 Subject: [PATCH 03/34] Raise version number after cloning 5.1.56 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 6d5bc07ba9a..dc944386f22 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.56], [], [mysql]) +AC_INIT([MySQL Server], [5.1.57], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 9afa024034cff75cca62b5c5939da1ad01d32330 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Fri, 11 Feb 2011 11:50:37 +0100 Subject: [PATCH 04/34] Raise version number after cloning 5.5.10 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 17335ff3fc5..ca1578a8642 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=10 +MYSQL_VERSION_PATCH=11 MYSQL_VERSION_EXTRA= From a6ea6dc217f8ed4c4ff4a6f44e091801fed0420c Mon Sep 17 00:00:00 2001 From: Magne Mahre Date: Thu, 24 Feb 2011 12:23:38 +0100 Subject: [PATCH 05/34] Bug#11767480 - SPATIAL INDEXES ON NON-SPATIAL COLUMNS CAUSE CRASHES. This is a backport of the patch for MySQL Bug#50574. Adding a SPATIAL INDEX on non-geometrical columns caused a segmentation fault when the table was subsequently inserted into. A test was added in mysql_prepare_create_table to explicitly check whether non-geometrical columns are used in a spatial index, and throw an error if so. For MySQL 5.5 and later, a new and more meaningful error message was introduced. For 5.1, we (re-)use an existing error code. --- mysql-test/r/gis.result | 33 +++++++++++++++++++++++++++++ mysql-test/t/gis.test | 47 +++++++++++++++++++++++++++++++++++++++++ sql/sql_table.cc | 22 +++++++++++++------ 3 files changed, 96 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index a9beb9631ae..151d0cfffa1 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1034,4 +1034,37 @@ p NULL NULL drop table t1; +CREATE TABLE t0 (a BINARY(32) NOT NULL); +CREATE SPATIAL INDEX i on t0 (a); +ERROR HY000: Incorrect arguments to SPATIAL INDEX +INSERT INTO t0 VALUES (1); +CREATE TABLE t1( +col0 BINARY NOT NULL, +col2 TIMESTAMP, +SPATIAL INDEX i1 (col0) +) ENGINE=MyISAM; +ERROR HY000: Incorrect arguments to SPATIAL INDEX +CREATE TABLE t1 ( +col0 BINARY NOT NULL, +col2 TIMESTAMP +) ENGINE=MyISAM; +CREATE SPATIAL INDEX idx0 ON t1(col0); +ERROR HY000: Incorrect arguments to SPATIAL INDEX +ALTER TABLE t1 ADD SPATIAL INDEX i1 (col0); +ERROR HY000: Incorrect arguments to SPATIAL INDEX +CREATE TABLE t2 ( +col0 INTEGER NOT NULL, +col1 POINT, +col2 POINT +); +CREATE SPATIAL INDEX idx0 ON t2 (col1, col2); +ERROR HY000: Incorrect arguments to SPATIAL INDEX +CREATE TABLE t3 ( +col0 INTEGER NOT NULL, +col1 POINT, +col2 LINESTRING, +SPATIAL INDEX i1 (col1, col2) +); +ERROR HY000: Incorrect arguments to SPATIAL INDEX +DROP TABLE t0, t1, t2; End of 5.1 tests diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index bdbbfc7c064..b50df062d7e 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -754,4 +754,51 @@ insert into t1 values (geomfromtext("point(1 0)")); select * from (select polygon(t1.a) as p from t1 order by t1.a) d; drop table t1; +# +# Bug#11767480 - SPATIAL INDEXES ON NON-SPATIAL COLUMNS CAUSE CRASHES. +# +CREATE TABLE t0 (a BINARY(32) NOT NULL); +--error ER_WRONG_ARGUMENTS +CREATE SPATIAL INDEX i on t0 (a); +INSERT INTO t0 VALUES (1); + +--error ER_WRONG_ARGUMENTS +CREATE TABLE t1( + col0 BINARY NOT NULL, + col2 TIMESTAMP, + SPATIAL INDEX i1 (col0) +) ENGINE=MyISAM; + +# Test other ways to add indices +CREATE TABLE t1 ( + col0 BINARY NOT NULL, + col2 TIMESTAMP +) ENGINE=MyISAM; + +--error ER_WRONG_ARGUMENTS +CREATE SPATIAL INDEX idx0 ON t1(col0); + +--error ER_WRONG_ARGUMENTS +ALTER TABLE t1 ADD SPATIAL INDEX i1 (col0); + +CREATE TABLE t2 ( + col0 INTEGER NOT NULL, + col1 POINT, + col2 POINT +); + +--error ER_WRONG_ARGUMENTS +CREATE SPATIAL INDEX idx0 ON t2 (col1, col2); + +--error ER_WRONG_ARGUMENTS +CREATE TABLE t3 ( + col0 INTEGER NOT NULL, + col1 POINT, + col2 LINESTRING, + SPATIAL INDEX i1 (col1, col2) +); + +# cleanup +DROP TABLE t0, t1, t2; + --echo End of 5.1 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b919ea9eae7..c5fc037a49e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2011, 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 @@ -11,7 +11,8 @@ 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 */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA */ /* drop and alter of tables */ @@ -3184,11 +3185,20 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, { column->length*= sql_field->charset->mbmaxlen; - if (key->type == Key::SPATIAL && column->length) + if (key->type == Key::SPATIAL) { - my_error(ER_WRONG_SUB_KEY, MYF(0)); - DBUG_RETURN(TRUE); - } + if (column->length) + { + my_error(ER_WRONG_SUB_KEY, MYF(0)); + DBUG_RETURN(TRUE); + } + + if (!f_is_geom(sql_field->pack_flag)) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX"); + DBUG_RETURN(TRUE); + } + } if (f_is_blob(sql_field->pack_flag) || (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL)) From 929d13ca4977ed1fa3dcbe6628c393ffc148004f Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 3 Mar 2011 11:43:07 +0300 Subject: [PATCH 06/34] BUG#11764339 - valgrind errors, random data when returning ordered data from archive tables Archive was using wrong memory address to check if field is NULL (after filesort, when reading record again). --- mysql-test/r/archive.result | 16 ++++++++++++++++ mysql-test/t/archive.test | 15 +++++++++++++++ storage/archive/ha_archive.cc | 2 +- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index f90bcb521e1..15ded03f414 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -12756,3 +12756,19 @@ a 1 2 DROP TABLE t1; +# +# BUG#57162 - valgrind errors, random data when returning +# ordered data from archive tables +# +SET sort_buffer_size=32804; +CREATE TABLE t1(a INT, b CHAR(255), c CHAR(255), d CHAR(255), +e CHAR(255), f INT) ENGINE=ARCHIVE DEFAULT CHARSET utf8; +INSERT INTO t1 VALUES(-1,'b','c','d','e',1); +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT t1.* FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6; +SELECT * FROM t1 ORDER BY f LIMIT 1; +a b c d e f +-1 b c d e 1 +DROP TABLE t1; +SET sort_buffer_size=DEFAULT; diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index 7084f5f540e..98ba5e03ede 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1678,3 +1678,18 @@ SELECT * FROM t1; REPAIR TABLE t1 EXTENDED; SELECT * FROM t1; DROP TABLE t1; + +--echo # +--echo # BUG#57162 - valgrind errors, random data when returning +--echo # ordered data from archive tables +--echo # +SET sort_buffer_size=32804; +CREATE TABLE t1(a INT, b CHAR(255), c CHAR(255), d CHAR(255), + e CHAR(255), f INT) ENGINE=ARCHIVE DEFAULT CHARSET utf8; +INSERT INTO t1 VALUES(-1,'b','c','d','e',1); +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT t1.* FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6; +SELECT * FROM t1 ORDER BY f LIMIT 1; +DROP TABLE t1; +SET sort_buffer_size=DEFAULT; diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 988337ec50e..9740bf934cd 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -1111,7 +1111,7 @@ int ha_archive::unpack_row(azio_stream *file_to_read, uchar *record) ptr+= table->s->null_bytes; for (Field **field=table->field ; *field ; field++) { - if (!((*field)->is_null())) + if (!((*field)->is_null_in_record(record))) { ptr= (*field)->unpack(record + (*field)->offset(table->record[0]), ptr); } From 0e640801776173236c6eee57779a70474e27afee Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 9 Mar 2011 17:21:22 +0200 Subject: [PATCH 07/34] Fixed a wrong error code in gis.test --- mysql-test/r/gis.result | 2 +- mysql-test/t/gis.test | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index d700865d5f3..acb55d225a7 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1040,7 +1040,7 @@ drop table t1; # create table t1(a char(32) not null) engine=myisam; create spatial index i on t1 (a); -ERROR HY000: Can't create table '#sql-temporary' (errno: 140) +ERROR HY000: Incorrect arguments to SPATIAL INDEX drop table t1; CREATE TABLE t0 (a BINARY(32) NOT NULL); CREATE SPATIAL INDEX i on t0 (a); diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index f81cd4a72a6..f8cec14d9ae 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -760,8 +760,7 @@ drop table t1; --echo # on char > 31 bytes". --echo # create table t1(a char(32) not null) engine=myisam; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE +--error ER_WRONG_ARGUMENTS create spatial index i on t1 (a); drop table t1; From feeac7d1a4a804a69009d7b21c9e46c8758d0daa Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Fri, 11 Mar 2011 15:10:15 +0100 Subject: [PATCH 08/34] Certain fields in the protcol required a strict formatting. If off bound values were sent to the server this could under some circumstances lead to a crash on the Windows platform. --- sql/sql_connect.cc | 175 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 149 insertions(+), 26 deletions(-) diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 9fa6966baa2..4c4f30600de 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -630,6 +630,94 @@ bool init_new_connection_handler_thread() return 0; } +#ifndef EMBEDDED_LIBRARY +/** + Get a null character terminated string from a user-supplied buffer. + + @param buffer[in, out] Pointer to the buffer to be scanned. + @param max_bytes_available[in, out] Limit the bytes to scan. + @param string_length[out] The number of characters scanned not including + the null character. + + @remark The string_length does not include the terminating null character. + However, after the call, the buffer is increased by string_length+1 + bytes, beyond the null character if there still available bytes to + scan. + + @return pointer to beginning of the string scanned. + @retval NULL The buffer content is malformed +*/ + +static +char *get_null_terminated_string(char **buffer, + size_t *max_bytes_available, + size_t *string_length) +{ + char *str= (char *)memchr(*buffer, '\0', *max_bytes_available); + + if (str == NULL) + return NULL; + + *string_length= (size_t)(str - *buffer); + *max_bytes_available-= *string_length + 1; + str= *buffer; + *buffer += *string_length + 1; + + return str; +} + + +/** + Get a length encoded string from a user-supplied buffer. + + @param buffer[in, out] The buffer to scan; updates position after scan. + @param max_bytes_available[in, out] Limit the number of bytes to scan + @param string_length[out] Number of characters scanned + + @remark In case the length is zero, then the total size of the string is + considered to be 1 byte; the size byte. + + @return pointer to first byte after the header in buffer. + @retval NULL The buffer content is malformed +*/ + +static +char *get_length_encoded_string(char **buffer, + size_t *max_bytes_available, + size_t *string_length) +{ + if (*max_bytes_available == 0) + return NULL; + + /* Do double cast to prevent overflow from signed / unsigned conversion */ + size_t str_len= (size_t)(unsigned char)**buffer; + + /* + If the length encoded string has the length 0 + the total size of the string is only one byte long (the size byte) + */ + if (str_len == 0) + { + ++*buffer; + *string_length= 0; + /* + Return a pointer to the 0 character so the return value will be + an empty string. + */ + return *buffer-1; + } + + if (str_len >= *max_bytes_available) + return NULL; + + char *str= *buffer+1; + *string_length= str_len; + *max_bytes_available-= *string_length + 1; + *buffer+= *string_length + 1; + return str; +} + + /* Perform handshake, authorize client and update thd ACL variables. @@ -643,7 +731,6 @@ bool init_new_connection_handler_thread() > 0 error code (not sent to user) */ -#ifndef EMBEDDED_LIBRARY static int check_connection(THD *thd) { uint connect_errors= 0; @@ -831,7 +918,7 @@ static int check_connection(THD *thd) } #endif /* HAVE_OPENSSL */ - if (end >= (char*) net->read_pos+ pkt_len +2) + if (end > (char *)net->read_pos + pkt_len) { inc_host_errors(&thd->remote.sin_addr); my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); @@ -843,39 +930,75 @@ static int check_connection(THD *thd) if ((thd->client_capabilities & CLIENT_TRANSACTIONS) && opt_using_transactions) net->return_status= &thd->server_status; - - char *user= end; - char *passwd= strend(user)+1; - uint user_len= passwd - user - 1; - char *db= passwd; - char db_buff[NAME_LEN + 1]; // buffer to store db in utf8 - char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 - uint dummy_errors; - + /* - Old clients send null-terminated string as password; new clients send - the size (1 byte) + string (not null-terminated). Hence in case of empty - password both send '\0'. - - This strlen() can't be easily deleted without changing protocol. - - Cast *passwd to an unsigned char, so that it doesn't extend the sign for - *passwd > 127 and become 2**32-127+ after casting to uint. + In order to safely scan a head for '\0' string terminators + we must keep track of how many bytes remain in the allocated + buffer or we might read past the end of the buffer. */ - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - (uchar)(*passwd++) : strlen(passwd); - db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? - db + passwd_len + 1 : 0; - /* strlen() can't be easily deleted without changing protocol */ - uint db_len= db ? strlen(db) : 0; + size_t bytes_remaining_in_packet= pkt_len - (end - (char *)net->read_pos); - if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len) + size_t user_len; + char *user= get_null_terminated_string(&end, &bytes_remaining_in_packet, + &user_len); + if (user == NULL) { inc_host_errors(&thd->remote.sin_addr); my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); return 1; } + /* + Old clients send a null-terminated string as password; new clients send + the size (1 byte) + string (not null-terminated). Hence in case of empty + password both send '\0'. + */ + size_t passwd_len= 0; + char *passwd= NULL; + + if (thd->client_capabilities & CLIENT_SECURE_CONNECTION) + { + /* + 4.1+ password. First byte is password length. + */ + passwd= get_length_encoded_string(&end, &bytes_remaining_in_packet, + &passwd_len); + } + else + { + /* + Old passwords are zero terminated strings. + */ + passwd= get_null_terminated_string(&end, &bytes_remaining_in_packet, + &passwd_len); + } + + if (passwd == NULL) + { + inc_host_errors(&thd->remote.sin_addr); + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); + return 1; + } + + size_t db_len= 0; + char *db= NULL; + + if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB) + { + db= get_null_terminated_string(&end, &bytes_remaining_in_packet, + &db_len); + if (db == NULL) + { + inc_host_errors(&thd->remote.sin_addr); + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); + return 1; + } + } + + char db_buff[NAME_LEN + 1]; // buffer to store db in utf8 + char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 + uint dummy_errors; + /* Since 4.1 all database names are stored in utf8 */ if (db) { From 9f29134a4a319bebc2a7fc83439c747faa1ba26d Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Mon, 14 Mar 2011 11:13:11 +0100 Subject: [PATCH 09/34] Certain fields in the protcol required a strict formatting. If off bound values were sent to the server this could under some circumstances lead to a crash on the Windows platform. --- sql/sql_acl.cc | 176 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 144 insertions(+), 32 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index fae609c0d4d..09609a7fa0c 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8397,6 +8397,92 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length) DBUG_RETURN (0); } +/** + Get a null character terminated string from a user-supplied buffer. + + @param buffer[in, out] Pointer to the buffer to be scanned. + @param max_bytes_available[in, out] Limit the bytes to scan. + @param string_length[out] The number of characters scanned not including + the null character. + + @remark The string_length does not include the terminating null character. + However, after the call, the buffer is increased by string_length+1 + bytes, beyond the null character if there still available bytes to + scan. + + @return pointer to beginning of the string scanned. + @retval NULL The buffer content is malformed +*/ + +static +char *get_null_terminated_string(char **buffer, + size_t *max_bytes_available, + size_t *string_length) +{ + char *str= (char *)memchr(*buffer, '\0', *max_bytes_available); + + if (str == NULL) + return NULL; + + *string_length= (size_t)(str - *buffer); + *max_bytes_available-= *string_length + 1; + str= *buffer; + *buffer += *string_length + 1; + + return str; +} + +/** + Get a length encoded string from a user-supplied buffer. + + @param buffer[in, out] The buffer to scan; updates position after scan. + @param max_bytes_available[in, out] Limit the number of bytes to scan + @param string_length[out] Number of characters scanned + + @remark In case the length is zero, then the total size of the string is + considered to be 1 byte; the size byte. + + @return pointer to first byte after the header in buffer. + @retval NULL The buffer content is malformed +*/ + +static +char *get_length_encoded_string(char **buffer, + size_t *max_bytes_available, + size_t *string_length) +{ + if (*max_bytes_available == 0) + return NULL; + + /* Do double cast to prevent overflow from signed / unsigned conversion */ + size_t str_len= (size_t)(unsigned char)**buffer; + + /* + If the length encoded string has the length 0 + the total size of the string is only one byte long (the size byte) + */ + if (str_len == 0) + { + ++*buffer; + *string_length= 0; + /* + Return a pointer to the 0 character so the return value will be + an empty string. + */ + return *buffer-1; + } + + if (str_len >= *max_bytes_available) + return NULL; + + char *str= *buffer+1; + *string_length= str_len; + *max_bytes_available-= *string_length + 1; + *buffer+= *string_length + 1; + return str; +} + + /* the packet format is described in send_client_reply_packet() */ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, uchar **buff, ulong pkt_len) @@ -8461,50 +8547,76 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, } #endif - if (end >= (char*) net->read_pos + pkt_len + 2) + if (end > (char *)net->read_pos + pkt_len) return packet_error; if ((mpvio->client_capabilities & CLIENT_TRANSACTIONS) && opt_using_transactions) net->return_status= mpvio->server_status; + + /* + In order to safely scan a head for '\0' string terminators + we must keep track of how many bytes remain in the allocated + buffer or we might read past the end of the buffer. + */ + size_t bytes_remaining_in_packet= pkt_len - (end - (char *)net->read_pos); - char *user= end; - char *passwd= strend(user) + 1; - uint user_len= passwd - user - 1, db_len; - char *db= passwd; - char db_buff[NAME_LEN + 1]; // buffer to store db in utf8 - char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 - uint dummy_errors; + size_t user_len; + char *user= get_null_terminated_string(&end, &bytes_remaining_in_packet, + &user_len); + if (user == NULL) + return packet_error; /* - Old clients send null-terminated string as password; new clients send + Old clients send a null-terminated string as password; new clients send the size (1 byte) + string (not null-terminated). Hence in case of empty password both send '\0'. - - This strlen() can't be easily deleted without changing protocol. - - Cast *passwd to an unsigned char, so that it doesn't extend the sign for - *passwd > 127 and become 2**32-127+ after casting to uint. */ - uint passwd_len= mpvio->client_capabilities & CLIENT_SECURE_CONNECTION ? - (uchar) (*passwd++) : strlen(passwd); - - if (mpvio->client_capabilities & CLIENT_CONNECT_WITH_DB) + size_t passwd_len= 0; + char *passwd= NULL; + + if (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION) { - db= db + passwd_len + 1; - /* strlen() can't be easily deleted without changing protocol */ - db_len= strlen(db); + /* + 4.1+ password. First byte is password length. + */ + passwd= get_length_encoded_string(&end, &bytes_remaining_in_packet, + &passwd_len); } else { - db= 0; - db_len= 0; + /* + Old passwords are zero terminated strings. + */ + passwd= get_null_terminated_string(&end, &bytes_remaining_in_packet, + &passwd_len); } - if (passwd + passwd_len + db_len > (char *) net->read_pos + pkt_len) + if (passwd == NULL) return packet_error; - char *client_plugin= passwd + passwd_len + (db ? db_len + 1 : 0); + size_t db_len= 0; + char *db= NULL; + + if (mpvio->client_capabilities & CLIENT_CONNECT_WITH_DB) + { + db= get_null_terminated_string(&end, &bytes_remaining_in_packet, + &db_len); + if (db == NULL) + return packet_error; + } + + size_t client_plugin_len= 0; + char *client_plugin= get_null_terminated_string(&end, + &bytes_remaining_in_packet, + &client_plugin_len); + if (client_plugin == NULL) + client_plugin= &empty_c_string[0]; + + char db_buff[NAME_LEN + 1]; // buffer to store db in utf8 + char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8 + uint dummy_errors; + /* Since 4.1 all database names are stored in utf8 */ if (db) @@ -8550,18 +8662,18 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, if (find_mpvio_user(mpvio)) return packet_error; - if (mpvio->client_capabilities & CLIENT_PLUGIN_AUTH) - { - if ((client_plugin + strlen(client_plugin)) > - (char *) net->read_pos + pkt_len) - return packet_error; - } - else + if (!(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH)) { + /* + An old client is connecting + */ if (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION) client_plugin= native_password_plugin_name.str; else { + /* + A really old client is connecting + */ client_plugin= old_password_plugin_name.str; /* For a passwordless accounts we use native_password_plugin. From 2de6586287658f871a69167f6365d65051b5b7bc Mon Sep 17 00:00:00 2001 From: Jorgen Loland Date: Mon, 14 Mar 2011 14:30:36 +0100 Subject: [PATCH 10/34] BUG#11766234: ASSERT (TABLE_REF->TABLE || TABLE_REF->VIEW) FAILS IN SET_FIELD_ITERATOR (Former 59299) When a PROCEDURE does a natural join, resolving of which columns are used in the join is done only once; consecutive CALLs to the procedure will reuse this information: CREATE PROCEDURE proc() SELECT * FROM t1 NATURAL JOIN v1; CALL proc(); <- natural join columns resolved here CALL proc(); <- reuse resolved NJ columns from first CALL The second CALL knows that it can reuse the resolved NJ columns because the first CALL sets st_select_lex::first_natural_join_processing=false. The problem in this bug was that the table the view v1 depends on changed between CREATE PROCEDURE and the first CALL: CREATE PROCEDURE... ALTER TABLE t2 CHANGE COLUMN a b CHAR; CALL proc(); <- error when resolving natural join columns CALL proc(); <- tries to reuse from first CALL => crash The fix for this bug is to set first_natural_join_processing= FALSE iff the natural join columns resolving was successful. --- mysql-test/r/sp.result | 18 ++++++++++++++++++ mysql-test/t/sp.test | 22 ++++++++++++++++++++++ sql/sql_base.cc | 15 ++++++--------- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 243bfb6c07d..f1c86d016e2 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -7452,4 +7452,22 @@ c1 # Cleanup drop table t1; drop procedure p1; +# +# BUG#11766234: 59299: ASSERT (TABLE_REF->TABLE || TABLE_REF->VIEW) +# FAILS IN SET_FIELD_ITERATOR +# +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE VIEW v1 AS SELECT a FROM t2; +CREATE PROCEDURE proc() SELECT * FROM t1 NATURAL JOIN v1; +ALTER TABLE t2 CHANGE COLUMN a b CHAR; + +CALL proc(); +ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +CALL proc(); +ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them + +DROP TABLE t1,t2; +DROP VIEW v1; +DROP PROCEDURE proc; # End of 5.5 test diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 11edeaf9811..cf89a6ece80 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -8713,4 +8713,26 @@ call p1(3, 2); drop table t1; drop procedure p1; +--echo # +--echo # BUG#11766234: 59299: ASSERT (TABLE_REF->TABLE || TABLE_REF->VIEW) +--echo # FAILS IN SET_FIELD_ITERATOR +--echo # + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE VIEW v1 AS SELECT a FROM t2; +CREATE PROCEDURE proc() SELECT * FROM t1 NATURAL JOIN v1; +ALTER TABLE t2 CHANGE COLUMN a b CHAR; + +--echo +--error ER_VIEW_INVALID +CALL proc(); +--error ER_VIEW_INVALID +CALL proc(); + +--echo +DROP TABLE t1,t2; +DROP VIEW v1; +DROP PROCEDURE proc; + --echo # End of 5.5 test diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7c020515f87..f37f800d091 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7594,9 +7594,10 @@ static bool setup_natural_join_row_types(THD *thd, List *from_clause, Name_resolution_context *context) { + DBUG_ENTER("setup_natural_join_row_types"); thd->where= "from clause"; if (from_clause->elements == 0) - return FALSE; /* We come here in the case of UNIONs. */ + DBUG_RETURN(false); /* We come here in the case of UNIONs. */ List_iterator_fast table_ref_it(*from_clause); TABLE_LIST *table_ref; /* Current table reference. */ @@ -7604,10 +7605,6 @@ static bool setup_natural_join_row_types(THD *thd, TABLE_LIST *left_neighbor; /* Table reference to the right of the current. */ TABLE_LIST *right_neighbor= NULL; - bool save_first_natural_join_processing= - context->select_lex->first_natural_join_processing; - - context->select_lex->first_natural_join_processing= FALSE; /* Note that tables in the list are in reversed order */ for (left_neighbor= table_ref_it++; left_neighbor ; ) @@ -7619,12 +7616,11 @@ static bool setup_natural_join_row_types(THD *thd, 1) for stored procedures, 2) for multitable update after lock failure and table reopening. */ - if (save_first_natural_join_processing) + if (context->select_lex->first_natural_join_processing) { - context->select_lex->first_natural_join_processing= FALSE; if (store_top_level_join_columns(thd, table_ref, left_neighbor, right_neighbor)) - return TRUE; + DBUG_RETURN(true); if (left_neighbor) { TABLE_LIST *first_leaf_on_the_right; @@ -7644,8 +7640,9 @@ static bool setup_natural_join_row_types(THD *thd, DBUG_ASSERT(right_neighbor); context->first_name_resolution_table= right_neighbor->first_leaf_for_name_resolution(); + context->select_lex->first_natural_join_processing= false; - return FALSE; + DBUG_RETURN (false); } From 405f7ca69a36a2b2d7b02bdb945f1e6879c5aaea Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 15 Mar 2011 13:19:30 +0200 Subject: [PATCH 11/34] Bug #11765023: 57934: DOS POSSIBLE SINCE BINARY CASTING DOESN'T ADHERE TO MAX_ALLOWED_PACKET Added a check for max_packet_length in CONVERT(, BINARY|CHAR). Added a test case. --- mysql-test/r/cast.result | 15 +++++++++++++++ mysql-test/t/cast.test | 14 ++++++++++++++ sql/item_timefunc.cc | 13 +++++++++++++ 3 files changed, 42 insertions(+) diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index dd61396e485..974a6bee63f 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -451,4 +451,19 @@ SELECT CONVERT(t2.a USING UTF8) FROM t1, t1 t2 LIMIT 1 1 1 DROP TABLE t1; +# +# Bug #11765023: 57934: DOS POSSIBLE SINCE BINARY CASTING +# DOESN'T ADHERE TO MAX_ALLOWED_PACKET +SET @@GLOBAL.max_allowed_packet=2048; +SELECT CONVERT('a', BINARY(2049)); +CONVERT('a', BINARY(2049)) +NULL +Warnings: +Warning 1301 Result of cast_as_binary() was larger than max_allowed_packet (2048) - truncated +SELECT CONVERT('a', CHAR(2049)); +CONVERT('a', CHAR(2049)) +NULL +Warnings: +Warning 1301 Result of cast_as_char() was larger than max_allowed_packet (2048) - truncated +SET @@GLOBAL.max_allowed_packet=default; End of 5.1 tests diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index 8e60d548c2f..426d7c7fdf2 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -282,5 +282,19 @@ SELECT 1 FROM ) AS s LIMIT 1; DROP TABLE t1; +--echo # +--echo # Bug #11765023: 57934: DOS POSSIBLE SINCE BINARY CASTING +--echo # DOESN'T ADHERE TO MAX_ALLOWED_PACKET + +SET @@GLOBAL.max_allowed_packet=2048; +# reconnect to make the new max packet size take effect +--connect (newconn, localhost, root,,) + +SELECT CONVERT('a', BINARY(2049)); +SELECT CONVERT('a', CHAR(2049)); + +connection default; +disconnect newconn; +SET @@GLOBAL.max_allowed_packet=default; --echo End of 5.1 tests diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 6335199b8de..74aae94b6f2 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2444,6 +2444,19 @@ String *Item_char_typecast::val_str(String *str) String *res; uint32 length; + if (cast_length >= 0 && + ((unsigned) cast_length) > current_thd->variables.max_allowed_packet) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_ALLOWED_PACKET_OVERFLOWED, + ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), + cast_cs == &my_charset_bin ? + "cast_as_binary" : func_name(), + current_thd->variables.max_allowed_packet); + null_value= 1; + return 0; + } + if (!charset_conversion) { if (!(res= args[0]->val_str(str))) From f9756a6c16ea3343cef50ae8fafc0528896b0c6c Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 17 Mar 2011 13:29:59 +0200 Subject: [PATCH 12/34] Fixed a post-merge embedded compilation error --- sql/sql_acl.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 09609a7fa0c..9f8510cab03 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8397,6 +8397,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length) DBUG_RETURN (0); } +#ifndef EMBEDDED_LIBRARY /** Get a null character terminated string from a user-supplied buffer. @@ -8481,6 +8482,7 @@ char *get_length_encoded_string(char **buffer, *buffer+= *string_length + 1; return str; } +#endif /* the packet format is described in send_client_reply_packet() */ From 5a3586b1c31fefbb985f82a24e9dda875b423d7d Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 17 Mar 2011 14:07:18 +0200 Subject: [PATCH 13/34] Fixed the test cleanup code post-merge --- mysql-test/r/mysqldump.result | 1 + mysql-test/t/mysqldump.test | 1 + 2 files changed, 2 insertions(+) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 124a0d364ce..8f6add75fd3 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -4626,6 +4626,7 @@ DELIMITER ; /*!50003 SET collation_connection = @saved_col_connection */ ; ALTER DATABASE `test-database` CHARACTER SET utf8 COLLATE utf8_unicode_ci ; DROP DATABASE `test-database`; +USE test; # # End of 5.1 tests # diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 5ed66646432..4eed3f1d4a6 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -2198,6 +2198,7 @@ ALTER DATABASE `test-database` CHARACTER SET utf8 COLLATE utf8_unicode_ci ; --exec $MYSQL_DUMP --quote-names --compact test-database DROP DATABASE `test-database`; +USE test; --echo # --echo # End of 5.1 tests From 4a6d020e8dda2c76d9902820606cd534324f3df7 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Thu, 24 Mar 2011 11:27:11 +0100 Subject: [PATCH 14/34] Bug#11829785 EXPLAIN EXTENDED CRASH WITH RIGHT OUTER JOIN, SUBQUERIES This is a backport of Bug #46860 Crash/segfault using EXPLAIN EXTENDED on query using UNION in subquery. --- mysql-test/r/explain.result | 15 ++++++++++++++- mysql-test/r/func_gconcat.result | 1 - mysql-test/r/subselect3.result | 3 --- mysql-test/t/explain.test | 23 ++++++++++++++++++++++- sql/sql_parse.cc | 6 +++++- 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index b9ae362f6cd..b8f791b27f4 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -180,7 +180,6 @@ ERROR 42000: Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP col SHOW WARNINGS; Level Code Message Error 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause -Note 1003 select 1 AS `1` from `test`.`t1` where ((...)) SET SESSION sql_mode=@old_sql_mode; DROP TABLE t1; End of 5.0 tests. @@ -318,3 +317,17 @@ id select_type table type possible_keys key key_len ref rows Extra DEALLOCATE PREPARE stmt; DROP TABLE t1; End of 5.1 tests. +# +# Bug#11829785 EXPLAIN EXTENDED CRASH WITH RIGHT OUTER JOIN, SUBQUERIES +# +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (0), (0); +PREPARE s FROM +'EXPLAIN EXTENDED +SELECT SUBSTRING(1, (SELECT 1 FROM t1 a1 RIGHT OUTER JOIN t1 ON 0)) AS d +FROM t1 WHERE 0 > ANY (SELECT @a FROM t1)'; +EXECUTE s; +ERROR 21000: Subquery returns more than 1 row +DEALLOCATE PREPARE s; +DROP TABLE t1; +# diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 01b93df6894..6c400a8ddcc 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -1056,7 +1056,6 @@ ERROR HY000: Only constant XPATH queries are supported SHOW WARNINGS; Level Code Message Error 1105 Only constant XPATH queries are supported -Note 1003 select updatexml('1',`test`.`t1`.`a`,'1') AS `UPDATEXML('1', a, '1')` from `test`.`t1` order by (select group_concat(1 separator ',') from `test`.`t1`) DROP TABLE t1; End of 5.1 tests DROP TABLE IF EXISTS t1, t2; diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result index 2962a12d9a2..4e18a81b534 100644 --- a/mysql-test/r/subselect3.result +++ b/mysql-test/r/subselect3.result @@ -865,9 +865,6 @@ Level Code Message Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #2 Note 1276 Field or reference 'test.t1.c' of SELECT #3 was resolved in SELECT #2 Error 1054 Unknown column 'c' in 'field list' -Note 1003 select `c` AS `c` from (select (select count(`test`.`t1`.`a`) from dual group by `c`) AS `(SELECT COUNT(a) FROM -(SELECT COUNT(b) FROM t1) AS x GROUP BY c -)` from `test`.`t1` group by `test`.`t1`.`b`) `y` DROP TABLE t1; End of 5.0 tests create table t0 (a int); diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index 931948b1b65..8376fdf1ad1 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -1,5 +1,5 @@ # -# Test of different EXPLAIN's +# Test of different EXPLAINs --disable_warnings drop table if exists t1; @@ -275,3 +275,24 @@ DEALLOCATE PREPARE stmt; DROP TABLE t1; --echo End of 5.1 tests. + +--echo # +--echo # Bug#11829785 EXPLAIN EXTENDED CRASH WITH RIGHT OUTER JOIN, SUBQUERIES +--echo # + +CREATE TABLE t1(a INT); + +INSERT INTO t1 VALUES (0), (0); + +PREPARE s FROM +'EXPLAIN EXTENDED +SELECT SUBSTRING(1, (SELECT 1 FROM t1 a1 RIGHT OUTER JOIN t1 ON 0)) AS d +FROM t1 WHERE 0 > ANY (SELECT @a FROM t1)'; + +--error ER_SUBQUERY_NO_1_ROW +EXECUTE s; + +DEALLOCATE PREPARE s; +DROP TABLE t1; + +--echo # diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 367699ea6cb..7d0186c0752 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4434,7 +4434,11 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) return 1; /* purecov: inspected */ thd->send_explain_fields(result); res= mysql_explain_union(thd, &thd->lex->unit, result); - if (lex->describe & DESCRIBE_EXTENDED) + /* + The code which prints the extended description is not robust + against malformed queries, so skip it if we have an error. + */ + if (!res && (lex->describe & DESCRIBE_EXTENDED)) { char buff[1024]; String str(buff,(uint32) sizeof(buff), system_charset_info); From e1fbf1b186134f428c56cdf148dd4ef58bc26665 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 7 Apr 2011 14:44:26 +0300 Subject: [PATCH 15/34] fixed a missing warning --- mysql-test/r/cast.result | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 974a6bee63f..44d57055e7f 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -455,6 +455,8 @@ DROP TABLE t1; # Bug #11765023: 57934: DOS POSSIBLE SINCE BINARY CASTING # DOESN'T ADHERE TO MAX_ALLOWED_PACKET 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 CONVERT('a', BINARY(2049)); CONVERT('a', BINARY(2049)) NULL From b4a59e016b0a1987d9e488ad81a4bad9b8f32d88 Mon Sep 17 00:00:00 2001 From: "karen.langford@oracle.com" <> Date: Tue, 12 Apr 2011 01:36:38 +0200 Subject: [PATCH 16/34] Bug#11867664: Fix server crashes on update with join on partitioned table. --- sql/ha_partition.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index f55c48189fe..bd8e0d397c4 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4317,7 +4317,8 @@ int ha_partition::index_read_idx_map(uchar *buf, uint index, break; } } - m_last_part= part; + if (part <= m_part_spec.end_part) + m_last_part= part; } else { @@ -6237,7 +6238,14 @@ void ha_partition::print_error(int error, myf errflag) { /* In case m_file has not been initialized, like in bug#42438 */ if (m_file) + { + if (m_last_part >= m_tot_parts) + { + DBUG_ASSERT(0); + m_last_part= 0; + } m_file[m_last_part]->print_error(error, errflag); + } else handler::print_error(error, errflag); } From ca6e7781ef47ace73058fd231fd0057e87e86d76 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Wed, 4 May 2011 16:59:24 +0400 Subject: [PATCH 17/34] Patch for Bug#12394306: the sever may crash if mysql.event is corrupted. The problem was that wrong structure of mysql.event was not detected and the server continued to use wrongly-structured data. The fix is to check the structure of mysql.event after opening before any use. That makes operations with events more strict -- some operations that might work before throw errors now. That seems to be Ok. Another side-effect of the patch is that if mysql.event is corrupted, unrelated DROP DATABASE statements issue an SQL warning about inability to open mysql.event table. --- mysql-test/r/events_1.result | 106 ++++++++++++++++++++-------- mysql-test/r/events_restart.result | 3 + mysql-test/t/events_1.test | 109 ++++++++++++++++++++++------- mysql-test/t/events_restart.test | 2 + sql/event_db_repository.cc | 8 +++ 5 files changed, 172 insertions(+), 56 deletions(-) diff --git a/mysql-test/r/events_1.result b/mysql-test/r/events_1.result index e7b645f5556..e0c137ea877 100644 --- a/mysql-test/r/events_1.result +++ b/mysql-test/r/events_1.result @@ -1,3 +1,4 @@ +call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted"); drop database if exists events_test; drop database if exists db_x; drop database if exists mysqltest_db2; @@ -259,33 +260,36 @@ events_test intact_check root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLE Try to alter mysql.event: the server should fail to load event information after mysql.event was tampered with. -First, let's add a column to the end and make sure everything -works as before +First, let's add a column to the end and check the error is emitted. ALTER TABLE mysql.event ADD dummy INT; SHOW EVENTS; -Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation -events_test intact_check root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci +ERROR HY000: Failed to open mysql.event SELECT event_name FROM INFORMATION_SCHEMA.events; -event_name -intact_check +ERROR HY000: Failed to open mysql.event SHOW CREATE EVENT intact_check; -Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation -intact_check SYSTEM CREATE EVENT `intact_check` ON SCHEDULE EVERY 10 HOUR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO SELECT "nothing" latin1 latin1_swedish_ci latin1_swedish_ci +ERROR HY000: Failed to open mysql.event DROP EVENT no_such_event; -ERROR HY000: Unknown event 'no_such_event' +ERROR HY000: Failed to open mysql.event CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5; +ERROR HY000: Failed to open mysql.event ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8; +ERROR HY000: Failed to open mysql.event ALTER EVENT intact_check_1 RENAME TO intact_check_2; +ERROR HY000: Failed to open mysql.event DROP EVENT intact_check_1; -ERROR HY000: Unknown event 'intact_check_1' +ERROR HY000: Failed to open mysql.event DROP EVENT intact_check_2; +ERROR HY000: Failed to open mysql.event DROP EVENT intact_check; +ERROR HY000: Failed to open mysql.event DROP DATABASE IF EXISTS mysqltest_no_such_database; Warnings: Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist CREATE DATABASE mysqltest_db2; DROP DATABASE mysqltest_db2; +Warnings: +Error 1545 Failed to open mysql.event SELECT @@event_scheduler; @@event_scheduler OFF @@ -294,6 +298,7 @@ Variable_name Value event_scheduler OFF SET GLOBAL event_scheduler=OFF; ALTER TABLE mysql.event DROP dummy; +DROP EVENT intact_check; CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing"; Now let's add a column to the first position: the server @@ -301,30 +306,32 @@ expects to see event schema name there ALTER TABLE mysql.event ADD dummy INT FIRST; SHOW EVENTS; -ERROR HY000: Cannot load from mysql.event. The table is probably corrupted +ERROR HY000: Failed to open mysql.event SELECT event_name FROM INFORMATION_SCHEMA.events; -ERROR HY000: Cannot load from mysql.event. The table is probably corrupted +ERROR HY000: Failed to open mysql.event SHOW CREATE EVENT intact_check; -ERROR HY000: Unknown event 'intact_check' +ERROR HY000: Failed to open mysql.event DROP EVENT no_such_event; -ERROR HY000: Unknown event 'no_such_event' +ERROR HY000: Failed to open mysql.event CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5; -ERROR HY000: Failed to store event name. Error code 2 from storage engine. +ERROR HY000: Failed to open mysql.event ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8; -ERROR HY000: Unknown event 'intact_check_1' +ERROR HY000: Failed to open mysql.event ALTER EVENT intact_check_1 RENAME TO intact_check_2; -ERROR HY000: Unknown event 'intact_check_1' +ERROR HY000: Failed to open mysql.event DROP EVENT intact_check_1; -ERROR HY000: Unknown event 'intact_check_1' +ERROR HY000: Failed to open mysql.event DROP EVENT intact_check_2; -ERROR HY000: Unknown event 'intact_check_2' +ERROR HY000: Failed to open mysql.event DROP EVENT intact_check; -ERROR HY000: Unknown event 'intact_check' +ERROR HY000: Failed to open mysql.event DROP DATABASE IF EXISTS mysqltest_no_such_database; Warnings: Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist CREATE DATABASE mysqltest_db2; DROP DATABASE mysqltest_db2; +Warnings: +Error 1545 Failed to open mysql.event SELECT @@event_scheduler; @@event_scheduler OFF @@ -345,29 +352,32 @@ Drop some columns and try more checks. ALTER TABLE mysql.event DROP comment, DROP starts; SHOW EVENTS; -ERROR HY000: Cannot load from mysql.event. The table is probably corrupted +ERROR HY000: Failed to open mysql.event SELECT event_name FROM INFORMATION_SCHEMA.EVENTS; -ERROR HY000: Cannot load from mysql.event. The table is probably corrupted +ERROR HY000: Failed to open mysql.event SHOW CREATE EVENT intact_check; -ERROR HY000: Cannot load from mysql.event. The table is probably corrupted +ERROR HY000: Failed to open mysql.event DROP EVENT no_such_event; -ERROR HY000: Unknown event 'no_such_event' +ERROR HY000: Failed to open mysql.event CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5; -ERROR HY000: Column count of mysql.event is wrong. Expected 22, found 20. The table is probably corrupted +ERROR HY000: Failed to open mysql.event ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8; -ERROR HY000: Unknown event 'intact_check_1' +ERROR HY000: Failed to open mysql.event ALTER EVENT intact_check_1 RENAME TO intact_check_2; -ERROR HY000: Unknown event 'intact_check_1' +ERROR HY000: Failed to open mysql.event DROP EVENT intact_check_1; -ERROR HY000: Unknown event 'intact_check_1' +ERROR HY000: Failed to open mysql.event DROP EVENT intact_check_2; -ERROR HY000: Unknown event 'intact_check_2' +ERROR HY000: Failed to open mysql.event DROP EVENT intact_check; +ERROR HY000: Failed to open mysql.event DROP DATABASE IF EXISTS mysqltest_no_such_database; Warnings: Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist CREATE DATABASE mysqltest_db2; DROP DATABASE mysqltest_db2; +Warnings: +Error 1545 Failed to open mysql.event SELECT @@event_scheduler; @@event_scheduler OFF @@ -425,4 +435,42 @@ CREATE TABLE mysql.event like event_like; DROP TABLE event_like; SHOW EVENTS; Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation + +# +# Bug#12394306: the sever may crash if mysql.event is corrupted +# + +CREATE EVENT ev1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5; +ALTER EVENT ev1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8; + +CREATE TABLE event_original LIKE mysql.event; +INSERT INTO event_original SELECT * FROM mysql.event; + +ALTER TABLE mysql.event MODIFY modified CHAR(1); +Warnings: +Warning 1265 Data truncated for column 'modified' at row 1 + +SHOW EVENTS; +ERROR HY000: Failed to open mysql.event + +SELECT event_name, created, last_altered FROM information_schema.events; +ERROR HY000: Failed to open mysql.event + +CREATE EVENT ev2 ON SCHEDULE EVERY 5 HOUR DO SELECT 5; +ERROR HY000: Failed to open mysql.event + +ALTER EVENT ev1 ON SCHEDULE EVERY 9 HOUR DO SELECT 9; +ERROR HY000: Failed to open mysql.event + +DROP TABLE mysql.event; +RENAME TABLE event_original TO mysql.event; + +DROP EVENT ev1; + +SHOW EVENTS; +Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation + +# +# End of tests +# drop database events_test; diff --git a/mysql-test/r/events_restart.result b/mysql-test/r/events_restart.result index 4db61d357ce..6a751fa29f8 100644 --- a/mysql-test/r/events_restart.result +++ b/mysql-test/r/events_restart.result @@ -1,3 +1,4 @@ +call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted"); set global event_scheduler=off; drop database if exists events_test; create database events_test; @@ -52,6 +53,8 @@ Warnings: Note 1008 Can't drop database 'mysqltest_database_not_exists'; database doesn't exist create database mysqltest_db1; drop database mysqltest_db1; +Warnings: +Error 1545 Failed to open mysql.event Restore the original mysql.event table drop table mysql.event; rename table event_like to mysql.event; diff --git a/mysql-test/t/events_1.test b/mysql-test/t/events_1.test index ccdeb70d291..7f31e3fc881 100644 --- a/mysql-test/t/events_1.test +++ b/mysql-test/t/events_1.test @@ -4,6 +4,8 @@ # Can't test with embedded server that doesn't support grants -- source include/not_embedded.inc +call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted"); + --disable_warnings drop database if exists events_test; drop database if exists db_x; @@ -270,23 +272,28 @@ SHOW EVENTS; --echo Try to alter mysql.event: the server should fail to load --echo event information after mysql.event was tampered with. --echo ---echo First, let's add a column to the end and make sure everything ---echo works as before +--echo First, let's add a column to the end and check the error is emitted. --echo ALTER TABLE mysql.event ADD dummy INT; ---replace_column 8 # 9 # +--error ER_EVENT_OPEN_TABLE_FAILED SHOW EVENTS; +--error ER_EVENT_OPEN_TABLE_FAILED SELECT event_name FROM INFORMATION_SCHEMA.events; ---replace_regex /STARTS '[^']+'/STARTS '#'/ +--error ER_EVENT_OPEN_TABLE_FAILED SHOW CREATE EVENT intact_check; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT no_such_event; +--error ER_EVENT_OPEN_TABLE_FAILED CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5; +--error ER_EVENT_OPEN_TABLE_FAILED ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8; +--error ER_EVENT_OPEN_TABLE_FAILED ALTER EVENT intact_check_1 RENAME TO intact_check_2; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT intact_check_1; +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT intact_check_2; +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT intact_check; DROP DATABASE IF EXISTS mysqltest_no_such_database; CREATE DATABASE mysqltest_db2; @@ -296,6 +303,7 @@ SHOW VARIABLES LIKE 'event_scheduler'; SET GLOBAL event_scheduler=OFF; # Clean up ALTER TABLE mysql.event DROP dummy; +DROP EVENT intact_check; CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing"; --echo --echo Now let's add a column to the first position: the server @@ -303,24 +311,26 @@ CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing"; --echo ALTER TABLE mysql.event ADD dummy INT FIRST; --error ER_CANNOT_LOAD_FROM_TABLE +--error ER_EVENT_OPEN_TABLE_FAILED SHOW EVENTS; --error ER_CANNOT_LOAD_FROM_TABLE +--error ER_EVENT_OPEN_TABLE_FAILED SELECT event_name FROM INFORMATION_SCHEMA.events; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED SHOW CREATE EVENT intact_check; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT no_such_event; ---error ER_EVENT_STORE_FAILED +--error ER_EVENT_OPEN_TABLE_FAILED CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED ALTER EVENT intact_check_1 RENAME TO intact_check_2; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT intact_check_1; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT intact_check_2; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT intact_check; # Should work OK DROP DATABASE IF EXISTS mysqltest_no_such_database; @@ -341,25 +351,25 @@ INSERT INTO event_like SELECT * FROM mysql.event; --echo --echo ALTER TABLE mysql.event DROP comment, DROP starts; ---error ER_CANNOT_LOAD_FROM_TABLE +--error ER_EVENT_OPEN_TABLE_FAILED SHOW EVENTS; ---error ER_CANNOT_LOAD_FROM_TABLE +--error ER_EVENT_OPEN_TABLE_FAILED SELECT event_name FROM INFORMATION_SCHEMA.EVENTS; ---error ER_CANNOT_LOAD_FROM_TABLE +--error ER_EVENT_OPEN_TABLE_FAILED SHOW CREATE EVENT intact_check; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT no_such_event; ---error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED +--error ER_EVENT_OPEN_TABLE_FAILED CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED ALTER EVENT intact_check_1 RENAME TO intact_check_2; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT intact_check_1; ---error ER_EVENT_DOES_NOT_EXIST +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT intact_check_2; -# Should succeed +--error ER_EVENT_OPEN_TABLE_FAILED DROP EVENT intact_check; DROP DATABASE IF EXISTS mysqltest_no_such_database; CREATE DATABASE mysqltest_db2; @@ -407,9 +417,54 @@ CREATE TABLE mysql.event like event_like; DROP TABLE event_like; --replace_column 8 # 9 # SHOW EVENTS; -# -# End of tests -# + +--echo +--echo # +--echo # Bug#12394306: the sever may crash if mysql.event is corrupted +--echo # + +--echo +CREATE EVENT ev1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5; +ALTER EVENT ev1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8; + +--echo +CREATE TABLE event_original LIKE mysql.event; +INSERT INTO event_original SELECT * FROM mysql.event; + +--echo +ALTER TABLE mysql.event MODIFY modified CHAR(1); + +--echo +--error ER_EVENT_OPEN_TABLE_FAILED +SHOW EVENTS; + +--echo +--error ER_EVENT_OPEN_TABLE_FAILED +SELECT event_name, created, last_altered FROM information_schema.events; + +--echo +--error ER_EVENT_OPEN_TABLE_FAILED +CREATE EVENT ev2 ON SCHEDULE EVERY 5 HOUR DO SELECT 5; + +--echo +--error ER_EVENT_OPEN_TABLE_FAILED +ALTER EVENT ev1 ON SCHEDULE EVERY 9 HOUR DO SELECT 9; + +--echo +DROP TABLE mysql.event; +RENAME TABLE event_original TO mysql.event; + +--echo +DROP EVENT ev1; + +--echo +SHOW EVENTS; + + +--echo +--echo # +--echo # End of tests +--echo # let $wait_condition= select count(*) = 0 from information_schema.processlist diff --git a/mysql-test/t/events_restart.test b/mysql-test/t/events_restart.test index e155fe2ea16..facf2912087 100644 --- a/mysql-test/t/events_restart.test +++ b/mysql-test/t/events_restart.test @@ -1,6 +1,8 @@ # Can't test with embedded server that doesn't support grants -- source include/not_embedded.inc +call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted"); + # # Test that when the server is restarted, it checks mysql.event table, # and disables the scheduler if it's not up to date. diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 7473cf47188..a0765dc6d15 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -582,6 +582,14 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type, *table= tables.table; tables.table->use_all_columns(); + + if (table_intact.check(*table, &event_table_def)) + { + close_thread_tables(thd); + my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0)); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); } From 47ef8f3452bd82324e5459cc5964e31407789e05 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Wed, 4 May 2011 14:07:59 +0100 Subject: [PATCH 18/34] Automerged (cherrypicked) cset from 5.6: zhenxing.he@sun.com-20101202073812-iel8lvhmulyagtsv This takes care of valgrind warnings in 5.5 that exhibit the same trace as in BUG#11763880 (BUG#56650). --- plugin/semisync/semisync_slave_plugin.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/semisync/semisync_slave_plugin.cc b/plugin/semisync/semisync_slave_plugin.cc index 5aa32cdfd5f..cfb04bdd276 100644 --- a/plugin/semisync/semisync_slave_plugin.cc +++ b/plugin/semisync/semisync_slave_plugin.cc @@ -53,7 +53,6 @@ int repl_semi_slave_request_dump(Binlog_relay_IO_param *param, if (mysql_real_query(mysql, query, strlen(query)) || !(res= mysql_store_result(mysql))) { - mysql_free_result(mysql_store_result(mysql)); sql_print_error("Execution failed on master: %s", query); return 1; } @@ -65,8 +64,10 @@ int repl_semi_slave_request_dump(Binlog_relay_IO_param *param, sql_print_warning("Master server does not support semi-sync, " "fallback to asynchronous replication"); rpl_semi_sync_slave_status= 0; + mysql_free_result(res); return 0; } + mysql_free_result(res); /* Tell master dump thread that we want to do semi-sync @@ -76,7 +77,6 @@ int repl_semi_slave_request_dump(Binlog_relay_IO_param *param, if (mysql_real_query(mysql, query, strlen(query))) { sql_print_error("Set 'rpl_semi_sync_slave=1' on master failed"); - mysql_free_result(mysql_store_result(mysql)); return 1; } mysql_free_result(mysql_store_result(mysql)); From 96a41c47d4a74ea5971647f423f1d1dd01db1e92 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Wed, 4 May 2011 14:09:54 +0100 Subject: [PATCH 19/34] Automerged (cherrypicked) cset from 5.6: zhenxing.he@sun.com-20101117085902-n9gfvlkmm44t38y0 This takes care of valgrind warnings in 5.5 that exhibit the same trace as in BUG#11763879 (BUG#56649). --- sql/rpl_handler.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sql/rpl_handler.h b/sql/rpl_handler.h index bf207e53e2d..9a181250efc 100644 --- a/sql/rpl_handler.h +++ b/sql/rpl_handler.h @@ -73,7 +73,10 @@ public: while (info && info->observer != observer) info= iter++; if (info) + { iter.remove(); + delete info; + } else ret= TRUE; unlock(); From e367a789d11fa44f3e2507ff9feed49d50c58b33 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 5 May 2011 23:48:15 +0100 Subject: [PATCH 20/34] BUG#12354268: MYSQLBINLOG --BASE64-OUTPUT=DECODE-ROWS DOES NOT WORK WITH --START-POSITION If setting --start-position to start after the FD event, mysqlbinlog will output an error stating that it has not found an FD event. However, its not that mysqlbinlog does not find it but rather that it does not processes it in the regular way (i.e., it does not print it). Given that one is using --base64-output=DECODE-ROWS then not printing it is actually fine. To fix this, we make mysqlbinlog not to complain when it has not printed the FD event, is outputing in base64, but is decoding the rows. --- client/mysqlbinlog.cc | 3 ++- mysql-test/r/mysqlbinlog_base64.result | 10 +++++++++ mysql-test/t/mysqlbinlog_base64.test | 29 ++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 30a8bddc17c..f451e28de86 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -951,7 +951,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, passed --short-form, because --short-form disables printing row events. */ - if (!print_event_info->printed_fd_event && !short_form) + if (!print_event_info->printed_fd_event && !short_form && + opt_base64_output_mode != BASE64_OUTPUT_DECODE_ROWS) { const char* type_str= ev->get_type_str(); if (opt_base64_output_mode == BASE64_OUTPUT_NEVER) diff --git a/mysql-test/r/mysqlbinlog_base64.result b/mysql-test/r/mysqlbinlog_base64.result index c5e1e2f8ca1..72d49c16cc8 100644 --- a/mysql-test/r/mysqlbinlog_base64.result +++ b/mysql-test/r/mysqlbinlog_base64.result @@ -109,3 +109,13 @@ count(*) 35840 drop table t1; drop table t2; +RESET MASTER; +USE test; +SET @old_binlog_format= @@binlog_format; +SET SESSION binlog_format=ROW; +CREATE TABLE t1(c1 INT); +INSERT INTO t1 VALUES (1); +FLUSH LOGS; +DROP TABLE t1; +SET SESSION binlog_format= @old_binlog_format; +RESET MASTER; diff --git a/mysql-test/t/mysqlbinlog_base64.test b/mysql-test/t/mysqlbinlog_base64.test index fb21e28fdcb..3d3444cea1c 100644 --- a/mysql-test/t/mysqlbinlog_base64.test +++ b/mysql-test/t/mysqlbinlog_base64.test @@ -71,3 +71,32 @@ select count(*) from t2; --remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_base64.sql drop table t1; drop table t2; + +# +# BUG#12354268 +# +# This test verifies that using --start-position with DECODE-ROWS +# does not make mysqlbinlog to output an error stating that it +# does not contain any FD event. +# + +RESET MASTER; +USE test; +SET @old_binlog_format= @@binlog_format; +SET SESSION binlog_format=ROW; +CREATE TABLE t1(c1 INT); +--let $master_binlog= query_get_value(SHOW MASTER STATUS, File, 1) +--let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1) +--let $MYSQLD_DATADIR= `SELECT @@datadir` + +INSERT INTO t1 VALUES (1); + +FLUSH LOGS; + +--disable_result_log +--exec $MYSQL_BINLOG --base64-output=DECODE-ROWS --start-position=$master_pos -v $MYSQLD_DATADIR/$master_binlog +--enable_result_log + +DROP TABLE t1; +SET SESSION binlog_format= @old_binlog_format; +RESET MASTER; From ed6aae83c3dd8e78e024bbb2bae49467a3fc0de3 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Fri, 6 May 2011 00:46:53 +0100 Subject: [PATCH 21/34] BUG#11762616: BUG#55229: 'POSTION' Fix for all "postion" in Oracle files (s/postion/position). Updated the copyright notices where needed. --- client/mysqltest.cc | 4 +-- extra/replace.c | 18 ++++++------ mysql-test/suite/rpl/r/rpl_server_id2.result | 2 +- mysql-test/suite/rpl/t/rpl_row_until.test | 10 +++---- mysql-test/suite/rpl/t/rpl_server_id2.test | 2 +- sql/handler.h | 17 +++++------ sql/slave.cc | 6 ++-- storage/archive/ha_archive.cc | 26 +++++++++-------- storage/ndb/src/kernel/blocks/lgman.cpp | 16 ++++++----- vio/viosocket.c | 30 +++++++++++--------- 10 files changed, 70 insertions(+), 61 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index a1813838a24..c2410b14c19 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -9739,7 +9739,7 @@ int find_set(REP_SETS *sets,REP_SET *find) return i; } } - return i; /* return new postion */ + return i; /* return new position */ } /* find if there is a found_set with same table_offset & found_offset @@ -9759,7 +9759,7 @@ int find_found(FOUND_SET *found_set,uint table_offset, int found_offset) found_set[i].table_offset=table_offset; found_set[i].found_offset=found_offset; found_sets++; - return -i-2; /* return new postion */ + return -i-2; /* return new position */ } /* Return 1 if regexp starts with \b or ends with \b*/ diff --git a/extra/replace.c b/extra/replace.c index fd2d860c212..2df8a58e16a 100644 --- a/extra/replace.c +++ b/extra/replace.c @@ -1,17 +1,19 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (c) 2000, 2011, 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 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 + 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 */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA */ /* Replace strings in textfile @@ -819,7 +821,7 @@ static short find_set(REP_SETS *sets,REP_SET *find) return (short) i; } } - return (short) i; /* return new postion */ + return (short) i; /* return new position */ } @@ -842,7 +844,7 @@ static short find_found(FOUND_SET *found_set,uint table_offset, found_set[i].table_offset=table_offset; found_set[i].found_offset=found_offset; found_sets++; - return (short) (-i-2); /* return new postion */ + return (short) (-i-2); /* return new position */ } /* Return 1 if regexp starts with \b or ends with \b*/ diff --git a/mysql-test/suite/rpl/r/rpl_server_id2.result b/mysql-test/suite/rpl/r/rpl_server_id2.result index dacb69bc7cb..4f299a1b23b 100644 --- a/mysql-test/suite/rpl/r/rpl_server_id2.result +++ b/mysql-test/suite/rpl/r/rpl_server_id2.result @@ -19,7 +19,7 @@ change master to master_port=MASTER_PORT; start slave until master_log_file='master-bin.000001', master_log_pos=UNTIL_POS; include/wait_for_slave_io_to_start.inc include/wait_for_slave_sql_to_stop.inc -*** checking until postion execution: must be only t1 in the list *** +*** checking until position execution: must be only t1 in the list *** show tables; Tables_in_test t1 diff --git a/mysql-test/suite/rpl/t/rpl_row_until.test b/mysql-test/suite/rpl/t/rpl_row_until.test index afd964ca81a..bf38bd487ea 100644 --- a/mysql-test/suite/rpl/t/rpl_row_until.test +++ b/mysql-test/suite/rpl/t/rpl_row_until.test @@ -9,29 +9,29 @@ connection master; CREATE TABLE t1(n INT NOT NULL AUTO_INCREMENT PRIMARY KEY); INSERT INTO t1 VALUES (1),(2),(3),(4); DROP TABLE t1; -# Save master log postion for query DROP TABLE t1 +# Save master log position for query DROP TABLE t1 save_master_pos; let $master_pos_drop_t1= query_get_value(SHOW BINLOG EVENTS, Pos, 7); let $master_log_file= query_get_value(SHOW BINLOG EVENTS, Log_name, 7); CREATE TABLE t2(n INT NOT NULL AUTO_INCREMENT PRIMARY KEY); -# Save master log postion for query CREATE TABLE t2 +# Save master log position for query CREATE TABLE t2 save_master_pos; let $master_pos_create_t2= query_get_value(SHOW BINLOG EVENTS, Pos, 8); INSERT INTO t2 VALUES (1),(2); save_master_pos; -# Save master log postion for query INSERT INTO t2 VALUES (1),(2); +# Save master log position for query INSERT INTO t2 VALUES (1),(2); let $master_pos_insert1_t2= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 12); sync_slave_with_master; -# Save relay log postion for query INSERT INTO t2 VALUES (1),(2); +# Save relay log position for query INSERT INTO t2 VALUES (1),(2); let $relay_pos_insert1_t2= query_get_value(show slave status, Relay_Log_Pos, 1); connection master; INSERT INTO t2 VALUES (3),(4); DROP TABLE t2; -# Save master log postion for query INSERT INTO t2 VALUES (1),(2); +# Save master log position for query INSERT INTO t2 VALUES (1),(2); let $master_pos_drop_t2= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 17); sync_slave_with_master; diff --git a/mysql-test/suite/rpl/t/rpl_server_id2.test b/mysql-test/suite/rpl/t/rpl_server_id2.test index 32d5e1ec8f2..aeb7292ed17 100644 --- a/mysql-test/suite/rpl/t/rpl_server_id2.test +++ b/mysql-test/suite/rpl/t/rpl_server_id2.test @@ -47,7 +47,7 @@ eval start slave until master_log_file='master-bin.000001', master_log_pos=$unti --source include/wait_for_slave_io_to_start.inc --source include/wait_for_slave_sql_to_stop.inc ---echo *** checking until postion execution: must be only t1 in the list *** +--echo *** checking until position execution: must be only t1 in the list *** show tables; # cleanup diff --git a/sql/handler.h b/sql/handler.h index 9acdac700cd..03b0555ae86 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1,18 +1,19 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2011, 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 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 + 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 */ - + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA */ /* Definitions for parameters to do with handler-routines */ @@ -56,7 +57,7 @@ a table with rnd_next() - We will see all rows (including deleted ones) - Row positions are 'table->s->db_record_offset' apart - If this flag is not set, filesort will do a postion() call for each matched + If this flag is not set, filesort will do a position() call for each matched row to be able to find the row later. */ #define HA_REC_NOT_IN_SEQ (1 << 3) diff --git a/sql/slave.cc b/sql/slave.cc index 6d266245460..dd578064f24 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -97,7 +97,7 @@ static const char *reconnect_messages[SLAVE_RECON_ACT_MAX][SLAVE_RECON_MSG_MAX]= registration on master", "Reconnecting after a failed registration on master", "failed registering on master, reconnecting to try again, \ -log '%s' at postion %s", +log '%s' at position %s", "COM_REGISTER_SLAVE", "Slave I/O thread killed during or after reconnect" }, @@ -105,7 +105,7 @@ log '%s' at postion %s", "Waiting to reconnect after a failed binlog dump request", "Slave I/O thread killed while retrying master dump", "Reconnecting after a failed binlog dump request", - "failed dump request, reconnecting to try again, log '%s' at postion %s", + "failed dump request, reconnecting to try again, log '%s' at position %s", "COM_BINLOG_DUMP", "Slave I/O thread killed during or after reconnect" }, @@ -114,7 +114,7 @@ log '%s' at postion %s", "Slave I/O thread killed while waiting to reconnect after a failed read", "Reconnecting after a failed master event read", "Slave I/O thread: Failed reading log event, reconnecting to retry, \ -log '%s' at postion %s", +log '%s' at position %s", "", "Slave I/O thread killed during or after a reconnect done to recover from \ failed read" diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 988337ec50e..764ed16e931 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -1,17 +1,19 @@ -/* Copyright (C) 2003 MySQL AB +/* Copyright (c) 2003, 2011, 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 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. + 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 */ + 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., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA */ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -864,7 +866,7 @@ int ha_archive::write_row(uchar *buf) */ azflush(&(share->archive_write), Z_SYNC_FLUSH); /* - Set the position of the local read thread to the beginning postion. + Set the position of the local read thread to the beginning position. */ if (read_data_header(&archive)) { diff --git a/storage/ndb/src/kernel/blocks/lgman.cpp b/storage/ndb/src/kernel/blocks/lgman.cpp index 53cb1e113e1..7dc71e7399a 100644 --- a/storage/ndb/src/kernel/blocks/lgman.cpp +++ b/storage/ndb/src/kernel/blocks/lgman.cpp @@ -1,17 +1,19 @@ -/* Copyright (C) 2003 MySQL AB +/* Copyright (c) 2003, 2011, 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 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 + 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 */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA */ #include "lgman.hpp" #include "diskpage.hpp" @@ -2501,7 +2503,7 @@ Lgman::init_run_undo_log(Signal* signal) sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB); /** - * Insert in correct postion in list of logfile_group's + * Insert in correct position in list of logfile_group's */ Ptr pos; for(tmp.first(pos); !pos.isNull(); tmp.next(pos)) diff --git a/vio/viosocket.c b/vio/viosocket.c index f73b890c697..15942fb3e31 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -1,17 +1,19 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (c) 2000, 2011, 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 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 + 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 */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA */ /* Note that we can't have assertion on file descriptors; The reason for @@ -548,7 +550,7 @@ size_t vio_read_shared_memory(Vio * vio, uchar* buf, size_t size) { size_t length; size_t remain_local; - char *current_postion; + char *current_position; HANDLE events[2]; DBUG_ENTER("vio_read_shared_memory"); @@ -556,7 +558,7 @@ size_t vio_read_shared_memory(Vio * vio, uchar* buf, size_t size) size)); remain_local = size; - current_postion=buf; + current_position=buf; events[0]= vio->event_server_wrote; events[1]= vio->event_conn_closed; @@ -590,11 +592,11 @@ size_t vio_read_shared_memory(Vio * vio, uchar* buf, size_t size) if (length > remain_local) length = remain_local; - memcpy(current_postion,vio->shared_memory_pos,length); + memcpy(current_position,vio->shared_memory_pos,length); vio->shared_memory_remain-=length; vio->shared_memory_pos+=length; - current_postion+=length; + current_position+=length; remain_local-=length; if (!vio->shared_memory_remain) @@ -614,7 +616,7 @@ size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size) { size_t length, remain, sz; HANDLE pos; - const uchar *current_postion; + const uchar *current_position; HANDLE events[2]; DBUG_ENTER("vio_write_shared_memory"); @@ -622,7 +624,7 @@ size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size) size)); remain = size; - current_postion = buf; + current_position = buf; events[0]= vio->event_server_read; events[1]= vio->event_conn_closed; @@ -640,9 +642,9 @@ size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size) int4store(vio->handle_map,sz); pos = vio->handle_map + 4; - memcpy(pos,current_postion,sz); + memcpy(pos,current_position,sz); remain-=sz; - current_postion+=sz; + current_position+=sz; if (!SetEvent(vio->event_client_wrote)) DBUG_RETURN((size_t) -1); } From ec425cc5ac4281b26ed32b29c06437950357cbb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Fri, 6 May 2011 10:53:42 +0200 Subject: [PATCH 22/34] Merge in patch for bug 12380149 --- sql/sql_partition.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 5c2c0bb95d6..776ce01cc54 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3979,7 +3979,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, part_spec->start_part= 0; part_spec->end_part= num_parts - 1; if ((index < MAX_KEY) && - key_spec->flag == (uint)HA_READ_KEY_EXACT && + key_spec && key_spec->flag == (uint)HA_READ_KEY_EXACT && part_info->some_fields_in_PF.is_set(index)) { key_info= table->key_info+index; From b1ff2e68134479dcf5ca609d6915ffc56a8a51b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Fri, 6 May 2011 11:20:01 +0200 Subject: [PATCH 23/34] Add --with-debug=full support to BUILD/* scripts, this option has been lost between 5.1 and 5.5, it's purpose is to set the compiler flags in a way that does not optimize away the call stack(i.e don't use any -OX flags at all) --- BUILD/SETUP.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 2642788e360..c7f434d1bb3 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -31,6 +31,7 @@ Usage: $0 [-h|-n] [configure-options] -h, --help Show this help message. -n, --just-print Don't actually run any commands; just print them. -c, --just-configure Stop after running configure. + --with-debug=full Build with full debug(no optimizations, keep call stack). --warning-mode=[old|pedantic|maintainer] Influences the debug flags. Old is default. --prefix=path Build with prefix 'path'. @@ -46,6 +47,8 @@ parse_options() case "$1" in --prefix=*) prefix=`get_key_value "$1"`;; + --with-debug=full) + full_debug="=full";; --warning-mode=*) warning_mode=`get_key_value "$1"`;; -c | --just-configure) @@ -76,6 +79,7 @@ just_print= just_configure= warning_mode= maintainer_mode= +full_debug= parse_options "$@" @@ -154,7 +158,11 @@ base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti" fast_cflags="-O3 -fno-omit-frame-pointer" debug_configs="--with-debug" -debug_cflags="$debug_cflags $debug_extra_cflags" +if [ -z "$full_debug" ] +then + debug_cflags="$debug_cflags $debug_extra_cflags" +fi + # # Configuration options. From 2593b14ccb4d70d3f3b58f5d3fab886c1c4af7a0 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Fri, 6 May 2011 15:39:40 +0400 Subject: [PATCH 24/34] Preliminary patch for Bug#11848763 / 60025 (SUBSTRING inside a stored function works too slow). Background: - THD classes derives from Query_arena, thus inherits the 'state' attribute and related operations (is_stmt_prepare() & co). - Although these operations are available in THD, they must not be used. THD has its own attribute to point to the active Query_arena -- stmt_arena. - So, instead of using thd->is_stmt_prepare(), thd->stmt_arena->is_stmt_prepare() must be used. This was the root cause of Bug 60025. This patch enforces the proper way of calling those operations. is_stmt_prepare() & co are declared as private operations in THD (thus, they are hidden from being called on THD instance). The patch tries to minimize changes in 5.5. --- sql/item.cc | 6 +++--- sql/item_cmpfunc.cc | 4 ++-- sql/item_func.cc | 2 +- sql/item_row.cc | 2 +- sql/item_strfunc.cc | 2 +- sql/sql_class.h | 18 +++++++++++++----- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index af3917c09c1..788c7744c14 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -581,7 +581,7 @@ void Item::rename(char *new_name) Item* Item::transform(Item_transformer transformer, uchar *arg) { - DBUG_ASSERT(!current_thd->is_stmt_prepare()); + DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare()); return (this->*transformer)(arg); } @@ -1845,7 +1845,7 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname, been created in prepare. In this case register the change for rollback. */ - if (thd->is_stmt_prepare()) + if (thd->stmt_arena->is_stmt_prepare()) *arg= conv; else thd->change_item_tree(arg, conv); @@ -6965,7 +6965,7 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) Item *Item_default_value::transform(Item_transformer transformer, uchar *args) { - DBUG_ASSERT(!current_thd->is_stmt_prepare()); + DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare()); /* If the value of arg is NULL, then this object represents a constant, diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index cf5da5313d9..e0057d1550b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4345,7 +4345,7 @@ bool Item_cond::walk(Item_processor processor, bool walk_subquery, uchar *arg) Item *Item_cond::transform(Item_transformer transformer, uchar *arg) { - DBUG_ASSERT(!current_thd->is_stmt_prepare()); + DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare()); List_iterator li(list); Item *item; @@ -5718,7 +5718,7 @@ bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg) Item *Item_equal::transform(Item_transformer transformer, uchar *arg) { - DBUG_ASSERT(!current_thd->is_stmt_prepare()); + DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare()); List_iterator it(fields); Item *item; diff --git a/sql/item_func.cc b/sql/item_func.cc index 1388e0dc479..24d0d94c6c5 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -293,7 +293,7 @@ void Item_func::traverse_cond(Cond_traverser traverser, Item *Item_func::transform(Item_transformer transformer, uchar *argument) { - DBUG_ASSERT(!current_thd->is_stmt_prepare()); + DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare()); if (arg_count) { diff --git a/sql/item_row.cc b/sql/item_row.cc index 94515640625..0f5d6f27823 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -170,7 +170,7 @@ bool Item_row::walk(Item_processor processor, bool walk_subquery, uchar *arg) Item *Item_row::transform(Item_transformer transformer, uchar *arg) { - DBUG_ASSERT(!current_thd->is_stmt_prepare()); + DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare()); for (uint i= 0; i < arg_count; i++) { diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index e5c47c110f4..e1a4fcc8def 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2536,7 +2536,7 @@ String *Item_func_make_set::val_str(String *str) Item *Item_func_make_set::transform(Item_transformer transformer, uchar *arg) { - DBUG_ASSERT(!current_thd->is_stmt_prepare()); + DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare()); Item *new_item= item->transform(transformer, arg); if (!new_item) diff --git a/sql/sql_class.h b/sql/sql_class.h index 35c54b62a03..56d85e7cb6d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -655,15 +655,10 @@ public: virtual ~Query_arena() {}; inline bool is_stmt_prepare() const { return state == INITIALIZED; } - inline bool is_first_sp_execute() const - { return state == INITIALIZED_FOR_SP; } inline bool is_stmt_prepare_or_first_sp_execute() const { return (int)state < (int)PREPARED; } inline bool is_stmt_prepare_or_first_stmt_execute() const { return (int)state <= (int)PREPARED; } - inline bool is_first_stmt_execute() const { return state == PREPARED; } - inline bool is_stmt_execute() const - { return state == PREPARED || state == EXECUTED; } inline bool is_conventional() const { return state == CONVENTIONAL_EXECUTION; } @@ -1434,6 +1429,19 @@ extern "C" void my_message_sql(uint error, const char *str, myf MyFlags); class THD :public Statement, public Open_tables_state { +private: + inline bool is_stmt_prepare() const + { DBUG_ASSERT(0); return Statement::is_stmt_prepare(); } + + inline bool is_stmt_prepare_or_first_sp_execute() const + { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_sp_execute(); } + + inline bool is_stmt_prepare_or_first_stmt_execute() const + { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_stmt_execute(); } + + inline bool is_conventional() const + { DBUG_ASSERT(0); return Statement::is_conventional(); } + public: MDL_context mdl_context; From bc4095643b955e76f349daaf7472f33da7638597 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Fri, 6 May 2011 15:41:24 +0400 Subject: [PATCH 25/34] Patch for Bug#11848763 / 60025 (SUBSTRING inside a stored function works too slow). The user-visible problem was that the server started to consume memory if a stored-routine of some sort is executed subsequently. The memory was freed only after the corresponding connection was closed. Technically, the problem was that the memory needed for temporary string conversions was allocated on the connection ("persistent") memory root, instead of statement one. The root cause of this problem was the incorrect patch for Bug 55744. That patch wrongly fixed a crash in prepared-statement-mode introduced by another patch. The patch for Bug 55744 used wrong condition to check if prepared statement mode is active (or whether the connection-scoped or statement-scoped memory root should be used). The thing is that for prepared statements such conversions should be done in the connection memory root, so that that the transformations of item-tree were correctly remembered in the PREPARE-phase. The fix is to use proper condition to detect prepared-statement-mode and use proper memory root. --- sql/item.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 788c7744c14..bd231ec8687 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1781,14 +1781,17 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname, } THD *thd= current_thd; - Query_arena *arena, backup; bool res= FALSE; uint i; + /* In case we're in statement prepare, create conversion item in its memory: it will be reused on each execute. */ - arena= thd->activate_stmt_arena_if_needed(&backup); + Query_arena backup; + Query_arena *arena= thd->stmt_arena->is_stmt_prepare() ? + thd->activate_stmt_arena_if_needed(&backup) : + NULL; for (i= 0, arg= args; i < nargs; i++, arg+= item_sep) { From cd501675d8b88698d2a4a0d24ec638ed7e78a95b Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Fri, 6 May 2011 17:39:20 +0400 Subject: [PATCH 26/34] Patch for Bug#12374486 - SEVERE MEMORY LEAK IN PREPARED STATEMENTS THAT CALL STORED PROCEDURES. The bug was introduced by WL#4435. The problem was that if a stored procedure generated a few result sets with different set of columns, a new memory would be allocated after every EXECUTE for every result set. The fix is to introduce a new memory root in scope of MYSQL_STMT, and to store result-set metadata in that memory root. --- include/mysql.h | 4 ++- include/mysql.h.pp | 3 +- libmysql/libmysql.c | 75 ++++++++++++++++++++++++++++++++------------- 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index d3b24f0198a..1966caefdc1 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -573,6 +573,8 @@ typedef struct st_mysql_bind } MYSQL_BIND; +struct st_mysql_stmt_extension; + /* statement handler */ typedef struct st_mysql_stmt { @@ -618,7 +620,7 @@ typedef struct st_mysql_stmt metadata fields when doing mysql_stmt_store_result. */ my_bool update_max_length; - void *extension; + struct st_mysql_stmt_extension *extension; } MYSQL_STMT; enum enum_stmt_attr_type diff --git a/include/mysql.h.pp b/include/mysql.h.pp index 169a8b30e2b..15ec563dfc2 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -512,6 +512,7 @@ typedef struct st_mysql_bind my_bool is_null_value; void *extension; } MYSQL_BIND; +struct st_mysql_stmt_extension; typedef struct st_mysql_stmt { MEM_ROOT mem_root; @@ -541,7 +542,7 @@ typedef struct st_mysql_stmt unsigned char bind_result_done; my_bool unbuffered_fetch_cancelled; my_bool update_max_length; - void *extension; + struct st_mysql_stmt_extension *extension; } MYSQL_STMT; enum enum_stmt_attr_type { diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index f802387cf9a..ec48720a2f5 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -94,6 +94,11 @@ sig_handler my_pipe_sig_handler(int sig); static my_bool mysql_client_init= 0; static my_bool org_my_init_done= 0; +typedef struct st_mysql_stmt_extension +{ + MEM_ROOT fields_mem_root; +} MYSQL_STMT_EXT; + /* Initialize the MySQL client library @@ -1480,11 +1485,16 @@ mysql_stmt_init(MYSQL *mysql) MYSQL_STMT *stmt; DBUG_ENTER("mysql_stmt_init"); - if (!(stmt= (MYSQL_STMT *) my_malloc(sizeof(MYSQL_STMT), + if (!(stmt= + (MYSQL_STMT *) my_malloc(sizeof (MYSQL_STMT), + MYF(MY_WME | MY_ZEROFILL))) || + !(stmt->extension= + (MYSQL_STMT_EXT *) my_malloc(sizeof (MYSQL_STMT_EXT), MYF(MY_WME | MY_ZEROFILL)))) { set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); - DBUG_RETURN(0); + my_free(stmt); + DBUG_RETURN(NULL); } init_alloc_root(&stmt->mem_root, 2048, 2048); @@ -1499,6 +1509,8 @@ mysql_stmt_init(MYSQL *mysql) strmov(stmt->sqlstate, not_error_sqlstate); /* The rest of statement members was bzeroed inside malloc */ + init_alloc_root(&stmt->extension->fields_mem_root, 2048, 0); + DBUG_RETURN(stmt); } @@ -1571,6 +1583,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) stmt->bind_param_done= stmt->bind_result_done= FALSE; stmt->param_count= stmt->field_count= 0; free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC)); + free_root(&stmt->extension->fields_mem_root, MYF(0)); int4store(buff, stmt->stmt_id); @@ -1631,21 +1644,21 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) static void alloc_stmt_fields(MYSQL_STMT *stmt) { MYSQL_FIELD *fields, *field, *end; - MEM_ROOT *alloc= &stmt->mem_root; + MEM_ROOT *fields_mem_root= &stmt->extension->fields_mem_root; MYSQL *mysql= stmt->mysql; - DBUG_ASSERT(mysql->field_count); + DBUG_ASSERT(stmt->field_count); - stmt->field_count= mysql->field_count; + free_root(fields_mem_root, MYF(0)); /* Get the field information for non-select statements like SHOW and DESCRIBE commands */ - if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(alloc, + if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(fields_mem_root, sizeof(MYSQL_FIELD) * stmt->field_count)) || - !(stmt->bind= (MYSQL_BIND *) alloc_root(alloc, + !(stmt->bind= (MYSQL_BIND *) alloc_root(fields_mem_root, sizeof(MYSQL_BIND) * stmt->field_count))) { @@ -1658,18 +1671,36 @@ static void alloc_stmt_fields(MYSQL_STMT *stmt) field && fields < end; fields++, field++) { *field= *fields; /* To copy all numeric parts. */ - field->catalog= strmake_root(alloc, fields->catalog, + field->catalog= strmake_root(fields_mem_root, + fields->catalog, fields->catalog_length); - field->db= strmake_root(alloc, fields->db, fields->db_length); - field->table= strmake_root(alloc, fields->table, fields->table_length); - field->org_table= strmake_root(alloc, fields->org_table, + field->db= strmake_root(fields_mem_root, + fields->db, + fields->db_length); + field->table= strmake_root(fields_mem_root, + fields->table, + fields->table_length); + field->org_table= strmake_root(fields_mem_root, + fields->org_table, fields->org_table_length); - field->name= strmake_root(alloc, fields->name, fields->name_length); - field->org_name= strmake_root(alloc, fields->org_name, + field->name= strmake_root(fields_mem_root, + fields->name, + fields->name_length); + field->org_name= strmake_root(fields_mem_root, + fields->org_name, fields->org_name_length); - field->def= fields->def ? strmake_root(alloc, fields->def, - fields->def_length) : 0; - field->def_length= field->def ? fields->def_length : 0; + if (fields->def) + { + field->def= strmake_root(fields_mem_root, + fields->def, + fields->def_length); + field->def_length= fields->def_length; + } + else + { + field->def= NULL; + field->def_length= 0; + } field->extension= 0; /* Avoid dangling links. */ field->max_length= 0; /* max_length is set in mysql_stmt_store_result() */ } @@ -2387,6 +2418,9 @@ static void reinit_result_set_metadata(MYSQL_STMT *stmt) prepared statements can't send result set metadata for these queries on prepare stage. Read it now. */ + + stmt->field_count= stmt->mysql->field_count; + alloc_stmt_fields(stmt); } else @@ -2404,7 +2438,7 @@ static void reinit_result_set_metadata(MYSQL_STMT *stmt) previous branch always works. TODO: send metadata only when it's really necessary and add a warning 'Metadata changed' when it's sent twice. - */ + */ update_stmt_fields(stmt); } } @@ -4605,6 +4639,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) free_root(&stmt->result.alloc, MYF(0)); free_root(&stmt->mem_root, MYF(0)); + free_root(&stmt->extension->fields_mem_root, MYF(0)); if (mysql) { @@ -4639,6 +4674,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) } } + my_free(stmt->extension); my_free(stmt); DBUG_RETURN(test(rc)); @@ -4805,16 +4841,13 @@ int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt) stmt->state= MYSQL_STMT_EXECUTE_DONE; stmt->bind_result_done= FALSE; + stmt->field_count= mysql->field_count; if (mysql->field_count) { alloc_stmt_fields(stmt); prepare_to_fetch_result(stmt); } - else - { - stmt->field_count= mysql->field_count; - } DBUG_RETURN(0); } From 75498ef9245a6be70ad725e5b780672a217cf7e0 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Mon, 9 May 2011 12:29:23 +0400 Subject: [PATCH 27/34] Patch for Bug#12362125 (SP INOUT HANDLING IS BROKEN FOR TEXT TYPE). Attempts to assign value to a table column from trigger by using NEW.column_name pseudo-variable might result in garbled data. That happened when: - the column had a BLOB-based type (e.g. TEXT) and - the value being assigned was retrieved from stored routine variable of the same type. The problem was that BLOB values were not copied correctly in this case. Instead of doing a copy of a real value, the value's representation in record buffer was copied. This representation is essentially a pointer to a buffer associated with the virtual table for routine variables where the real value is stored. Since this buffer got freed once trigger was left or could have changed its contents when new value was assigned to corresponding routine variable such a shallow copying resulted in garbled data in NEW.colum_name column. It worked in 5.1 due to a subtle bug in create_virtual_tmp_table(): - in 5.1 create_virtual_tmp_table() returned a table which had db_low_byte_first == false. - in 5.5 and up create_virtual_tmp_table() returns a table which has db_low_byte_first == true. Actually, db_low_byte_first == false only for ISAM storage engine, which was deprecated and removed in 5.0. Having db_low_byte_first == false led to getting false in the complex condition for the 2nd "if" in field_conv(), which in turn led to copy-blob-behavior as a fall-back strategy: - to->table->s->db_low_byte_first was true (correct value) - from->table->s->db_low_byte_first was false (incorrect value) In 5.5 and up that condition is true, which means blob-values are not copied. --- mysql-test/r/trigger.result | 20 +++++++++++++++++++- mysql-test/t/trigger.test | 30 +++++++++++++++++++++++++++++- sql/item.cc | 22 ++++++++++++++++++++-- 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 11e0d7313b7..e759153eaaf 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -2208,4 +2208,22 @@ trigger_name # Clean-up. drop temporary table t1; drop table t1; -End of 6.0 tests. + +# +# Bug #12362125: SP INOUT HANDLING IS BROKEN FOR TEXT TYPE. +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(c TEXT); +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +BEGIN +DECLARE v TEXT; +SET v = 'aaa'; +SET NEW.c = v; +END| +INSERT INTO t1 VALUES('qazwsxedc'); +SELECT c FROM t1; +c +aaa +DROP TABLE t1; + +End of 5.5 tests. diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index e5039c3ea23..80dbcceb448 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -2583,4 +2583,32 @@ select trigger_name from information_schema.triggers drop temporary table t1; drop table t1; ---echo End of 6.0 tests. + +--echo +--echo # +--echo # Bug #12362125: SP INOUT HANDLING IS BROKEN FOR TEXT TYPE. +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1(c TEXT); + +delimiter |; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +BEGIN + DECLARE v TEXT; + SET v = 'aaa'; + SET NEW.c = v; +END| +delimiter ;| + +INSERT INTO t1 VALUES('qazwsxedc'); + +SELECT c FROM t1; + +DROP TABLE t1; + +--echo +--echo End of 5.5 tests. diff --git a/sql/item.cc b/sql/item.cc index bd231ec8687..5e5e07203f9 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7134,8 +7134,26 @@ bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it) { Item *item= sp_prepare_func_item(thd, it); - return (!item || (!fixed && fix_fields(thd, 0)) || - (item->save_in_field(field, 0) < 0)); + if (!item) + return true; + + if (!fixed) + { + if (fix_fields(thd, NULL)) + return true; + } + + // NOTE: field->table->copy_blobs should be false here, but let's + // remember the value at runtime to avoid subtle bugs. + bool copy_blobs_saved= field->table->copy_blobs; + + field->table->copy_blobs= true; + + int err_code= item->save_in_field(field, 0); + + field->table->copy_blobs= copy_blobs_saved; + + return err_code < 0; } From 4dde684315e64fb151963c3c54cafa33fd9702c9 Mon Sep 17 00:00:00 2001 From: Serge Kozlov Date: Mon, 9 May 2011 23:26:41 +0400 Subject: [PATCH 28/34] automerge 5.1->5.5 --- mysql-test/suite/binlog/t/binlog_bug23533.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/binlog/t/binlog_bug23533.test b/mysql-test/suite/binlog/t/binlog_bug23533.test index c05abe788c6..ca610e399e4 100644 --- a/mysql-test/suite/binlog/t/binlog_bug23533.test +++ b/mysql-test/suite/binlog/t/binlog_bug23533.test @@ -35,7 +35,7 @@ connect(default,localhost,root,,test); # Copied data from t1 into t2 large than max_binlog_cache_size START TRANSACTION; ---error 1197 +--error ER_TRANS_CACHE_FULL CREATE TABLE t2 SELECT * FROM t1; COMMIT; SHOW TABLES LIKE 't%'; From c9eef1d74af83a8839fe0b47497a496ffbeaa24d Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 10 May 2011 12:41:09 +0100 Subject: [PATCH 29/34] BUG#12416700: RPL_SHOW_SLAVE_HOSTS FAILS SPORADICALLY (TIMEOUT IN WAIT_SHOW_CONDITION) There was a typo in the name of one of the parameters to the include file wait_show_condition. The parameter name was being set to "connection" instead of "condition". We fix this typo, improve one instruction in the test case and deploy parameter checks inside wait_show_condition.inc. --- mysql-test/include/wait_show_condition.inc | 15 +++++++++++++++ .../suite/rpl/r/rpl_show_slave_hosts.result | 3 +-- mysql-test/suite/rpl/t/rpl_show_slave_hosts.test | 5 ++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/mysql-test/include/wait_show_condition.inc b/mysql-test/include/wait_show_condition.inc index 68e05ce4644..ae1600a7e30 100644 --- a/mysql-test/include/wait_show_condition.inc +++ b/mysql-test/include/wait_show_condition.inc @@ -31,6 +31,21 @@ # Created: 2009-02-18 mleich # +if (!$condition) +{ + --die ERROR IN TEST: the "condition" variable must be set +} + +if (!$field) +{ + --die ERROR IN TEST: the "field" variable must be set +} + +if (!$show_statement) +{ + --die ERROR IN TEST: the "show_statement" variable must be set +} + let $max_run_time= 30; if ($wait_timeout) { diff --git a/mysql-test/suite/rpl/r/rpl_show_slave_hosts.result b/mysql-test/suite/rpl/r/rpl_show_slave_hosts.result index 107cd8f63cc..2ada5670e04 100644 --- a/mysql-test/suite/rpl/r/rpl_show_slave_hosts.result +++ b/mysql-test/suite/rpl/r/rpl_show_slave_hosts.result @@ -8,8 +8,7 @@ SHOW SLAVE HOSTS; Server_id Host Port Master_id 3 slave2 DEFAULT_PORT 1 2 SLAVE_PORT 1 -STOP SLAVE IO_THREAD; -include/wait_for_slave_io_to_stop.inc +include/stop_slave_io.inc SHOW SLAVE HOSTS; Server_id Host Port Master_id 2 SLAVE_PORT 1 diff --git a/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test b/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test index eb2e883847f..105f1873659 100644 --- a/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test +++ b/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test @@ -23,14 +23,13 @@ connection master; let $show_statement= SHOW SLAVE HOSTS; let $field= Server_id; # 3 is server_id of slave2. -let $connection= ='3'; +let $condition= ='3'; source include/wait_show_condition.inc; --replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT SHOW SLAVE HOSTS; connection slave2; -STOP SLAVE IO_THREAD; -source include/wait_for_slave_io_to_stop.inc; +--source include/stop_slave_io.inc connection master; let $show_statement= SHOW SLAVE HOSTS; From f8e86f50e20f189b0061d18b7e8ac04d4ef8d667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Bl=C3=A5udd?= Date: Wed, 11 May 2011 09:49:23 +0200 Subject: [PATCH 30/34] Bug#12384993 EXTRA/RPL_TEST/CHECK_TYPE.INC NEED SUPPORT FOR SPECIFIC ENGINE - add support for choosing the engine of test table(t1) with $engine_type - add primary key to the test table(t1) to support replication of BLOB/TEXT (also with ENGINE=ndb) - change the suppression since the warning printed to error log now says "Column 1" --- mysql-test/extra/rpl_tests/check_type.inc | 14 ++++++++++++-- mysql-test/suite/rpl/r/rpl_typeconv.result | 2 +- mysql-test/suite/rpl/t/rpl_typeconv.test | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/mysql-test/extra/rpl_tests/check_type.inc b/mysql-test/extra/rpl_tests/check_type.inc index 63491d81da4..97300753d38 100644 --- a/mysql-test/extra/rpl_tests/check_type.inc +++ b/mysql-test/extra/rpl_tests/check_type.inc @@ -11,18 +11,28 @@ # on the slave) # $can_convert True if conversion shall work, false if it # shall generate an error +# $engine_type The storage engine to be used for storing table +# on both master and slave +if (!$engine_type) +{ + # Use the default storage engine + let $engine_type=`SELECT @@storage_engine`; +} connection master; disable_warnings; DROP TABLE IF EXISTS t1; enable_warnings; -eval CREATE TABLE t1 (a $source_type); +eval CREATE TABLE t1( + pk INT NOT NULL PRIMARY KEY, + a $source_type +) ENGINE=$engine_type; sync_slave_with_master; eval ALTER TABLE t1 MODIFY a $target_type; connection master; -eval INSERT INTO t1 VALUES($source_value); +eval INSERT INTO t1 VALUES(1, $source_value); if ($can_convert) { sync_slave_with_master; eval SELECT a = $target_value into @compare FROM t1; diff --git a/mysql-test/suite/rpl/r/rpl_typeconv.result b/mysql-test/suite/rpl/r/rpl_typeconv.result index 0d2f3cb26f7..f9d5b50b4e2 100644 --- a/mysql-test/suite/rpl/r/rpl_typeconv.result +++ b/mysql-test/suite/rpl/r/rpl_typeconv.result @@ -534,7 +534,7 @@ BIT(6) BIT(5) ALL_LOSSY,ALL_NON_LOSSY BIT(5) BIT(12) ALL_LOSSY,ALL_NON_LOSSY BIT(12) BIT(5) ALL_LOSSY,ALL_NON_LOSSY DROP TABLE type_conversions; -call mtr.add_suppression("Slave SQL.*Column 0 of table .test.t1. cannot be converted from type.* Error_code: 1677"); +call mtr.add_suppression("Slave SQL.*Column 1 of table .test.t1. cannot be converted from type.* Error_code: 1677"); DROP TABLE t1; set global slave_type_conversions = @saved_slave_type_conversions; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_typeconv.test b/mysql-test/suite/rpl/t/rpl_typeconv.test index efe3dc15353..efcbe97049f 100644 --- a/mysql-test/suite/rpl/t/rpl_typeconv.test +++ b/mysql-test/suite/rpl/t/rpl_typeconv.test @@ -61,7 +61,7 @@ SELECT RPAD(Source, 15, ' ') AS Source_Type, enable_query_log; DROP TABLE type_conversions; -call mtr.add_suppression("Slave SQL.*Column 0 of table .test.t1. cannot be converted from type.* Error_code: 1677"); +call mtr.add_suppression("Slave SQL.*Column 1 of table .test.t1. cannot be converted from type.* Error_code: 1677"); connection master; DROP TABLE t1; From a914a32191accdce6132486a9bcf71d9d7d4dd70 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 11 May 2011 14:11:57 +0300 Subject: [PATCH 31/34] Bug #11744875: 4082: integer lengths cause truncation with distinct concat and innodb The 5.5 version of the patch. The server doesn't restrict the data that can be inserted into integer columns with explicitly specified length that's smaller than what the type can handle, e.g. 1234 can be inserted into an INT(2) column just fine. Thus, when calcualting the maximum width of expressions involving such restricted integer columns we need to use the implicit maximum width of the field instead of the explicitly speficied one. Fixed the server to use the implicit maximum in such cases and made sure the implicit maximum is addjusted the same way as the explicit one wrt signedness. Fixed several test case results (ctype_*.result, metadata.result and type_ranges.result) to reflect the extended column widths. Added a regression test case in distinct.test. Note : this is the behavior preserving fix that makes 5.5 behave as 5.1 and earlier. In the mysql trunk we'll add a insert time check for the explict maximum size. --- mysql-test/r/ctype_binary.result | 4 +-- mysql-test/r/ctype_cp1251.result | 4 +-- mysql-test/r/ctype_latin1.result | 4 +-- mysql-test/r/ctype_ucs.result | 4 +-- mysql-test/r/ctype_utf8.result | 4 +-- mysql-test/r/distinct.result | 11 ++++++ mysql-test/r/metadata.result | 2 +- mysql-test/r/type_ranges.result | 2 +- mysql-test/t/distinct.test | 13 +++++++ sql/item.cc | 58 ++++++++++++++++++++++++++++++++ 10 files changed, 94 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/ctype_binary.result b/mysql-test/r/ctype_binary.result index 291dcfdf92a..a80c52ebf9d 100644 --- a/mysql-test/r/ctype_binary.result +++ b/mysql-test/r/ctype_binary.result @@ -2046,7 +2046,7 @@ create table t2 as select concat(a) from t1; show create table t2; Table Create Table t2 CREATE TABLE `t2` ( - `concat(a)` varbinary(2) DEFAULT NULL + `concat(a)` varbinary(4) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2; create table t1 (a year); @@ -2355,7 +2355,7 @@ insert into t1 values (1); create view v1(a) as select concat(a) from t1; show columns from v1; Field Type Null Key Default Extra -a varbinary(2) YES NULL +a varbinary(4) YES NULL select hex(a) from v1; hex(a) 3031 diff --git a/mysql-test/r/ctype_cp1251.result b/mysql-test/r/ctype_cp1251.result index 58f023b2b79..cff4f6b7442 100644 --- a/mysql-test/r/ctype_cp1251.result +++ b/mysql-test/r/ctype_cp1251.result @@ -2438,7 +2438,7 @@ create table t2 as select concat(a) from t1; show create table t2; Table Create Table t2 CREATE TABLE `t2` ( - `concat(a)` varchar(2) CHARACTER SET cp1251 DEFAULT NULL + `concat(a)` varchar(4) CHARACTER SET cp1251 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2; create table t1 (a year); @@ -2747,7 +2747,7 @@ insert into t1 values (1); create view v1(a) as select concat(a) from t1; show columns from v1; Field Type Null Key Default Extra -a varchar(2) YES NULL +a varchar(4) YES NULL select hex(a) from v1; hex(a) 3031 diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result index 2ecb9d6aeba..12a76302397 100644 --- a/mysql-test/r/ctype_latin1.result +++ b/mysql-test/r/ctype_latin1.result @@ -2465,7 +2465,7 @@ create table t2 as select concat(a) from t1; show create table t2; Table Create Table t2 CREATE TABLE `t2` ( - `concat(a)` varchar(2) DEFAULT NULL + `concat(a)` varchar(4) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2; create table t1 (a year); @@ -2774,7 +2774,7 @@ insert into t1 values (1); create view v1(a) as select concat(a) from t1; show columns from v1; Field Type Null Key Default Extra -a varchar(2) YES NULL +a varchar(4) YES NULL select hex(a) from v1; hex(a) 3031 diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index e687822c235..dc922f8490a 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -3299,7 +3299,7 @@ create table t2 as select concat(a) from t1; show create table t2; Table Create Table t2 CREATE TABLE `t2` ( - `concat(a)` varchar(2) CHARACTER SET ucs2 DEFAULT NULL + `concat(a)` varchar(4) CHARACTER SET ucs2 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2; create table t1 (a year); @@ -3608,7 +3608,7 @@ insert into t1 values (1); create view v1(a) as select concat(a) from t1; show columns from v1; Field Type Null Key Default Extra -a varchar(2) YES NULL +a varchar(4) YES NULL select hex(a) from v1; hex(a) 00300031 diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index db981fbe298..cfbf6cee3a2 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -4177,7 +4177,7 @@ create table t2 as select concat(a) from t1; show create table t2; Table Create Table t2 CREATE TABLE `t2` ( - `concat(a)` varchar(2) CHARACTER SET utf8 DEFAULT NULL + `concat(a)` varchar(4) CHARACTER SET utf8 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2; create table t1 (a year); @@ -4486,7 +4486,7 @@ insert into t1 values (1); create view v1(a) as select concat(a) from t1; show columns from v1; Field Type Null Key Default Extra -a varchar(2) YES NULL +a varchar(4) YES NULL select hex(a) from v1; hex(a) 3031 diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index b1cb70fa43c..74f2c19c8fe 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -794,3 +794,14 @@ DROP TABLE t1; SET @@sort_buffer_size = @old_sort_buffer_size; SET @@max_heap_table_size = @old_max_heap_table_size; End of 5.1 tests +# +# Bug #11744875: 4082: integer lengths cause truncation with distinct concat and innodb +# +CREATE TABLE t1 (a INT(1), b INT(1)); +INSERT INTO t1 VALUES (1111, 2222), (3333, 4444); +SELECT DISTINCT CONCAT(a,b) AS c FROM t1 ORDER BY 1; +c +11112222 +33334444 +DROP TABLE t1; +End of 5.5 tests diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 480cec792c0..3418348854f 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -126,7 +126,7 @@ renamed 1 select * from v3 where renamed=1 group by renamed; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def v3 v3 renamed renamed 8 11 0 Y 32896 0 63 +def v3 v3 renamed renamed 8 12 0 Y 32896 0 63 renamed drop table t1; drop view v1,v2,v3; diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index ac3d52b9ead..d99c2363d62 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -271,7 +271,7 @@ drop table t2; create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1; show full columns from t2; Field Type Collation Null Key Default Extra Privileges Comment -auto int(6) unsigned NULL NO PRI 0 # +auto int(11) unsigned NULL NO PRI 0 # t1 int(1) NULL NO 0 # t2 varchar(1) latin1_swedish_ci NO # t3 varchar(256) latin1_swedish_ci NO # diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index bf4c23562cf..84073d15109 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -614,3 +614,16 @@ SET @@sort_buffer_size = @old_sort_buffer_size; SET @@max_heap_table_size = @old_max_heap_table_size; --echo End of 5.1 tests + + +--echo # +--echo # Bug #11744875: 4082: integer lengths cause truncation with distinct concat and innodb +--echo # + +CREATE TABLE t1 (a INT(1), b INT(1)); +INSERT INTO t1 VALUES (1111, 2222), (3333, 4444); +SELECT DISTINCT CONCAT(a,b) AS c FROM t1 ORDER BY 1; +DROP TABLE t1; + + +--echo End of 5.5 tests diff --git a/sql/item.cc b/sql/item.cc index 5e5e07203f9..2c0da80b43b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2011,6 +2011,61 @@ Item_field::Item_field(THD *thd, Item_field *item) collation.set(DERIVATION_IMPLICIT); } + +/** + Calculate the max column length not taking into account the + limitations over integer types. + + When storing data into fields the server currently just ignores the + limits specified on integer types, e.g. 1234 can safely be stored in + an int(2) and will not cause an error. + Thus when creating temporary tables and doing transformations + we must adjust the maximum field length to reflect this fact. + We take the un-restricted maximum length and adjust it similarly to + how the declared length is adjusted wrt unsignedness etc. + TODO: this all needs to go when we disable storing 1234 in int(2). + + @param field_par Original field the use to calculate the lengths + @param max_length Item's calculated explicit max length + @return The adjusted max length +*/ + +inline static uint32 +adjust_max_effective_column_length(Field *field_par, uint32 max_length) +{ + uint32 new_max_length= field_par->max_display_length(); + uint32 sign_length= (field_par->flags & UNSIGNED_FLAG) ? 0 : 1; + + switch (field_par->type()) + { + case MYSQL_TYPE_INT24: + /* + Compensate for MAX_MEDIUMINT_WIDTH being 1 too long (8) + compared to the actual number of digits that can fit into + the column. + */ + new_max_length+= 1; + /* fall through */ + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + + /* Take out the sign and add a conditional sign */ + new_max_length= new_max_length - 1 + sign_length; + break; + + /* BINGINT is always 20 no matter the sign */ + case MYSQL_TYPE_LONGLONG: + /* make gcc happy */ + default: + break; + } + + /* Adjust only if the actual precision based one is bigger than specified */ + return new_max_length > max_length ? new_max_length : max_length; +} + + void Item_field::set_field(Field *field_par) { field=result_field=field_par; // for easy coding with fields @@ -2024,6 +2079,9 @@ void Item_field::set_field(Field *field_par) collation.set(field_par->charset(), field_par->derivation(), field_par->repertoire()); fix_char_length(field_par->char_length()); + + max_length= adjust_max_effective_column_length(field_par, max_length); + fixed= 1; if (field->table->s->tmp_table == SYSTEM_TMP_TABLE) any_privileges= 0; From 94f424652c0244e0efe185c4ddb0177a2d31b81b Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 11 May 2011 13:40:29 +0200 Subject: [PATCH 32/34] Cloning of the 5.5.13 release from Mysql-5.5, increase the version number by two --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3a52d76371e..796544a7013 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=13 +MYSQL_VERSION_PATCH=15 MYSQL_VERSION_EXTRA= From cbf455cf87a79b368f7456483fc7cf80d7e09aca Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Wed, 11 May 2011 16:45:57 +0400 Subject: [PATCH 33/34] Ignore auto-generated files. --- .bzrignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.bzrignore b/.bzrignore index 05597220950..2369d922ddf 100644 --- a/.bzrignore +++ b/.bzrignore @@ -3129,3 +3129,6 @@ libmysqld/examples/mysql_embedded sql/.empty mysys/thr_lock VERSION.dep +info_macros.cmake +Docs/INFO_BIN +Docs/INFO_SRC From 6fb68a22bd2d176f4fdf123634d1942a6b0b53d3 Mon Sep 17 00:00:00 2001 From: Tatjana Azundris Nuernberg Date: Thu, 12 May 2011 05:56:41 +0100 Subject: [PATCH 34/34] Bug#11902767/Bug#60580: Statement improperly replicated crashes slave SQL thread If LOAD DATA INFILE featured a SET clause, the name=value pairs would be regenerated using item::print. Unfortunately, that code is mostly optimized for EXPLAIN EXTENDED output and such, and can not be relied on to return valid SQL. We now name each value its original, user-supplied form and use that to create LOAD DATA INFILE statements for statement-based replication. --- .../r/binlog_stm_mix_innodb_myisam.result | 4 +- .../suite/rpl/r/rpl_loaddatalocal.result | 27 ++++++++++ mysql-test/suite/rpl/t/rpl_loaddatalocal.test | 51 +++++++++++++++++++ sql/sql_load.cc | 5 +- sql/sql_yacc.yy | 20 +++++++- 5 files changed, 100 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index 20d82557122..da2e24506fd 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -698,7 +698,7 @@ master-bin.000001 # Query # # BEGIN master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# master-bin.000001 # Intvar # # INSERT_ID=10 -master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a`, @b) SET `b`=((@b) + `bug27417`(2)) ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a`, @b) SET `b`= @b + bug27417(2) ;file_id=# master-bin.000001 # Query # # ROLLBACK /* the output must denote there is the query */; drop trigger trg_del_t2; @@ -950,7 +950,7 @@ master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci -master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a`, @b) SET `b`=((@b) + `bug27417`(2)) ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a`, @b) SET `b`= @b + bug27417(2) ;file_id=# master-bin.000001 # Query # # ROLLBACK drop trigger trg_del_t2; drop table t1,t2,t3,t4,t5; diff --git a/mysql-test/suite/rpl/r/rpl_loaddatalocal.result b/mysql-test/suite/rpl/r/rpl_loaddatalocal.result index 37936871993..84748259795 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddatalocal.result +++ b/mysql-test/suite/rpl/r/rpl_loaddatalocal.result @@ -78,4 +78,31 @@ LOAD DATA LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; DROP TABLE t1; SET SESSION sql_mode=@old_mode; [slave] + +Bug #60580/#11902767: +"statement improperly replicated crashes slave sql thread" + +[master] +CREATE TABLE t1(f1 INT, f2 INT); +CREATE TABLE t2(f1 INT, f2 TIMESTAMP); +INSERT INTO t2 VALUES(1, '2011-03-22 21:01:28'); +INSERT INTO t2 VALUES(2, '2011-03-21 21:01:28'); +INSERT INTO t2 VALUES(3, '2011-03-20 21:01:28'); +CREATE TABLE t3 AS SELECT * FROM t2; +CREATE VIEW v1 AS SELECT * FROM t2 +WHERE f1 IN (SELECT f1 FROM t3 WHERE (t3.f2 IS NULL)); +SELECT 1 INTO OUTFILE 'MYSQLD_DATADIR/bug60580.csv' FROM DUAL; +LOAD DATA LOCAL INFILE 'MYSQLD_DATADIR/bug60580.csv' INTO TABLE t1 (@f1) SET f2 = (SELECT f1 FROM v1 WHERE f1=@f1); +SELECT * FROM t1; +f1 f2 +NULL NULL +[slave] +SELECT * FROM t1; +f1 f2 +NULL NULL +[master] +DROP VIEW v1; +DROP TABLE t1, t2, t3; +[slave] include/rpl_end.inc +# End of 5.1 tests diff --git a/mysql-test/suite/rpl/t/rpl_loaddatalocal.test b/mysql-test/suite/rpl/t/rpl_loaddatalocal.test index 8848903a30c..ed6edeb3fbb 100644 --- a/mysql-test/suite/rpl/t/rpl_loaddatalocal.test +++ b/mysql-test/suite/rpl/t/rpl_loaddatalocal.test @@ -163,5 +163,56 @@ SET SESSION sql_mode=@old_mode; --echo [slave] sync_slave_with_master; +connection master; + +--echo +--echo Bug #60580/#11902767: +--echo "statement improperly replicated crashes slave sql thread" +--echo + +--echo [master] +connection master; +let $MYSQLD_DATADIR= `select @@datadir`; + +CREATE TABLE t1(f1 INT, f2 INT); +CREATE TABLE t2(f1 INT, f2 TIMESTAMP); + +INSERT INTO t2 VALUES(1, '2011-03-22 21:01:28'); +INSERT INTO t2 VALUES(2, '2011-03-21 21:01:28'); +INSERT INTO t2 VALUES(3, '2011-03-20 21:01:28'); + +CREATE TABLE t3 AS SELECT * FROM t2; + +CREATE VIEW v1 AS SELECT * FROM t2 + WHERE f1 IN (SELECT f1 FROM t3 WHERE (t3.f2 IS NULL)); + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval SELECT 1 INTO OUTFILE '$MYSQLD_DATADIR/bug60580.csv' FROM DUAL; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug60580.csv' INTO TABLE t1 (@f1) SET f2 = (SELECT f1 FROM v1 WHERE f1=@f1); + +SELECT * FROM t1; + +sleep 1; + +--echo [slave] +sync_slave_with_master; + +SELECT * FROM t1; + +--remove_file $MYSQLD_DATADIR/bug60580.csv + +--echo [master] +connection master; + +DROP VIEW v1; +DROP TABLE t1, t2, t3; + +--echo [slave] +sync_slave_with_master; + connection master; --source include/rpl_end.inc + +--echo # End of 5.1 tests diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 5ec6e4a0467..c089ac09b89 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011 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 @@ -743,8 +743,7 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, pfields.append("`"); pfields.append(item->name); pfields.append("`"); - pfields.append("="); - val->print(&pfields, QT_ORDINARY); + pfields.append(val->name); } } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 9aa938437b1..340ae819bfc 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011 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 @@ -11587,7 +11587,23 @@ field_or_var: opt_load_data_set_spec: /* empty */ {} - | SET insert_update_list {} + | SET load_data_set_list {} + ; + +load_data_set_list: + load_data_set_list ',' load_data_set_elem + | load_data_set_elem + ; + +load_data_set_elem: + simple_ident_nospvar equal remember_name expr_or_default remember_end + { + LEX *lex= Lex; + if (lex->update_list.push_back($1) || + lex->value_list.push_back($4)) + MYSQL_YYABORT; + $4->set_name($3, (uint) ($5 - $3), YYTHD->charset()); + } ; /* Common definitions */