diff --git a/client/Makefile.am b/client/Makefile.am index ccd0d8aada0..b455a34a58b 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -116,10 +116,10 @@ link_sources: @LN_CP_F@ $(top_srcdir)/sql/$$f $$f; \ done; \ for f in $(strings_src) ; do \ - rm -f $(srcdir)/$$f; \ + rm -f $$f; \ @LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \ done; \ - rm -f $(srcdir)/my_user.c; \ + rm -f my_user.c; \ @LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c; echo timestamp > link_sources; 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/client/mysqltest.cc b/client/mysqltest.cc index 52c76b8c68e..c2410b14c19 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -4461,13 +4461,14 @@ static int my_kill(int pid, int sig) command called command DESCRIPTION - shutdown [] + shutdown_server [] */ void do_shutdown_server(struct st_command *command) { - int timeout=60, pid; + long timeout=60; + int pid; DYNAMIC_STRING ds_pidfile_name; MYSQL* mysql = &cur_con->mysql; static DYNAMIC_STRING ds_timeout; @@ -4482,8 +4483,9 @@ void do_shutdown_server(struct st_command *command) if (ds_timeout.length) { - timeout= atoi(ds_timeout.str); - if (timeout == 0) + char* endptr; + timeout= strtol(ds_timeout.str, &endptr, 10); + if (*endptr != '\0') die("Illegal argument for timeout: '%s'", ds_timeout.str); } dynstr_free(&ds_timeout); @@ -4525,7 +4527,7 @@ void do_shutdown_server(struct st_command *command) DBUG_PRINT("info", ("Process %d does not exist anymore", pid)); DBUG_VOID_RETURN; } - DBUG_PRINT("info", ("Sleeping, timeout: %d", timeout)); + DBUG_PRINT("info", ("Sleeping, timeout: %ld", timeout)); my_sleep(1000000L); } @@ -9737,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 @@ -9757,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/cmd-line-utils/libedit/el.c b/cmd-line-utils/libedit/el.c index d99946eb68f..c7f8386773d 100644 --- a/cmd-line-utils/libedit/el.c +++ b/cmd-line-utils/libedit/el.c @@ -478,7 +478,13 @@ el_source(EditLine *el, const char *fname) fp = NULL; if (fname == NULL) { -#ifdef HAVE_ISSETUGID +/* XXXMYSQL: Bug#49967 */ +#if defined(HAVE_GETUID) && defined(HAVE_GETEUID) && \ + defined(HAVE_GETGID) && defined(HAVE_GETEGID) +#define HAVE_IDENTITY_FUNCS 1 +#endif + +#if (defined(HAVE_ISSETUGID) || defined(HAVE_IDENTITY_FUNCS)) static const char elpath[] = "/.editrc"; /* XXXMYSQL: Portability fix (for which platforms?) */ #ifdef MAXPATHLEN @@ -486,9 +492,13 @@ el_source(EditLine *el, const char *fname) #else char path[4096]; #endif - +#ifdef HAVE_ISSETUGID if (issetugid()) return (-1); +#elif defined(HAVE_IDENTITY_FUNCS) + if (getuid() != geteuid() || getgid() != getegid()) + return (-1); +#endif if ((ptr = getenv("HOME")) == NULL) return (-1); if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path)) @@ -498,9 +508,10 @@ el_source(EditLine *el, const char *fname) fname = path; #else /* - * If issetugid() is missing, always return an error, in order - * to keep from inadvertently opening up the user to a security - * hole. + * If issetugid() or the above mentioned get[e][u|g]id() + * functions are missing, always return an error, in order + * to keep from inadvertently opening up the user to a + * security hole. */ return (-1); #endif diff --git a/configure.in b/configure.in index 5bd823ab879..8ba208b1ef5 100644 --- a/configure.in +++ b/configure.in @@ -1963,7 +1963,7 @@ AC_CHECK_HEADER(vis.h, [AC_DEFINE([HAVE_VIS_H], [1],[Found vis.h and the strvis() function])])]) AC_CHECK_FUNCS(strlcat strlcpy) -AC_CHECK_FUNCS(issetugid) +AC_CHECK_FUNCS(issetugid getuid geteuid getgid getegid) AC_CHECK_FUNCS(fgetln) AC_CHECK_FUNCS(getline flockfile) 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/include/wait_until_disconnected.inc b/mysql-test/include/wait_until_disconnected.inc index a4362e52d01..8a989becc18 100644 --- a/mysql-test/include/wait_until_disconnected.inc +++ b/mysql-test/include/wait_until_disconnected.inc @@ -7,7 +7,7 @@ let $counter= 500; let $mysql_errno= 0; while (!$mysql_errno) { - --error 0,1053,2002,2006,2013 + --error 0,1040,1053,2002,2003,2006,2013 show status; dec $counter; 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/r/cast.result b/mysql-test/r/cast.result index dd61396e485..44d57055e7f 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -451,4 +451,21 @@ 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; +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 +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/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/r/gis.result b/mysql-test/r/gis.result index d82a86a6423..acb55d225a7 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1040,6 +1040,39 @@ 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); +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/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/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/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%'; diff --git a/mysql-test/suite/innodb/r/innodb_bug59410.result b/mysql-test/suite/innodb/r/innodb_bug59410.result new file mode 100644 index 00000000000..494d601ba4f --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug59410.result @@ -0,0 +1,17 @@ +create table `bug59410_1`(`a` int)engine=innodb; +insert into `bug59410_1` values (1),(2),(3); +select 1 from `bug59410_1` where `a` <> any ( +select 1 from `bug59410_1` where `a` <> 1 for update) +for update; +1 +1 +1 +drop table bug59410_1; +create table bug59410_2(`a` char(1),`b` int)engine=innodb; +insert into bug59410_2 values('0',0); +set transaction isolation level read uncommitted; +start transaction; +set @a=(select b from bug59410_2 where +(select 1 from bug59410_2 where a group by @a=b) +group by @a:=b); +drop table bug59410_2; diff --git a/mysql-test/suite/innodb/r/innodb_bug59641.result b/mysql-test/suite/innodb/r/innodb_bug59641.result new file mode 100644 index 00000000000..361172aa82b --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug59641.result @@ -0,0 +1,57 @@ +CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; +INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); +COMMIT; +XA START '123'; +INSERT INTO t VALUES(1,1); +XA END '123'; +XA PREPARE '123'; +XA START '456'; +INSERT INTO t VALUES(3,47),(5,67); +UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8; +XA END '456'; +XA PREPARE '456'; +XA START '789'; +UPDATE t SET b=4*a WHERE a=32; +XA END '789'; +XA PREPARE '789'; +call mtr.add_suppression("Found 3 prepared XA transactions"); +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SELECT * FROM t; +a b +1 1 +2 2 +3 47 +4 4 +5 134 +8 16 +16 16 +32 128 +COMMIT; +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SELECT * FROM t; +a b +1 1 +2 2 +3 47 +4 4 +5 134 +8 16 +16 16 +32 128 +COMMIT; +XA RECOVER; +formatID gtrid_length bqual_length data +1 3 0 789 +1 3 0 456 +1 3 0 123 +XA ROLLBACK '123'; +XA ROLLBACK '456'; +XA COMMIT '789'; +SELECT * FROM t; +a b +2 2 +4 4 +8 8 +16 16 +32 128 +DROP TABLE t; diff --git a/mysql-test/suite/innodb/t/innodb_bug59410.test b/mysql-test/suite/innodb/t/innodb_bug59410.test new file mode 100644 index 00000000000..30bb0642679 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug59410.test @@ -0,0 +1,24 @@ +# +# Bug#59410 read uncommitted: unlock row could not find a 3 mode lock on the record +# +-- source include/have_innodb.inc + +# only interested that the following do not produce something like +# InnoDB: Error: unlock row could not find a 2 mode lock on the record +# in the error log + +create table `bug59410_1`(`a` int)engine=innodb; +insert into `bug59410_1` values (1),(2),(3); +select 1 from `bug59410_1` where `a` <> any ( +select 1 from `bug59410_1` where `a` <> 1 for update) +for update; +drop table bug59410_1; + +create table bug59410_2(`a` char(1),`b` int)engine=innodb; +insert into bug59410_2 values('0',0); +set transaction isolation level read uncommitted; +start transaction; +set @a=(select b from bug59410_2 where +(select 1 from bug59410_2 where a group by @a=b) +group by @a:=b); +drop table bug59410_2; diff --git a/mysql-test/suite/innodb/t/innodb_bug59641.test b/mysql-test/suite/innodb/t/innodb_bug59641.test new file mode 100644 index 00000000000..0237673061c --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug59641.test @@ -0,0 +1,66 @@ +# Bug #59641 Prepared XA transaction causes shutdown hang after a crash + +-- source include/not_embedded.inc +-- source include/have_innodb.inc + +CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; +INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); +COMMIT; +XA START '123'; +INSERT INTO t VALUES(1,1); +XA END '123'; +XA PREPARE '123'; + +CONNECT (con1,localhost,root,,); +CONNECTION con1; + +XA START '456'; +INSERT INTO t VALUES(3,47),(5,67); +UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8; +XA END '456'; +XA PREPARE '456'; + +CONNECT (con2,localhost,root,,); +CONNECTION con2; + +XA START '789'; +UPDATE t SET b=4*a WHERE a=32; +XA END '789'; +XA PREPARE '789'; + +# The server would issue this warning on restart. +call mtr.add_suppression("Found 3 prepared XA transactions"); + +# Kill the server without sending a shutdown command +-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +-- shutdown_server 0 +-- source include/wait_until_disconnected.inc + +# Restart the server. +-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +-- enable_reconnect +-- source include/wait_until_connected_again.inc +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SELECT * FROM t; +COMMIT; + +# Shut down the server. This would hang because of the bug. +-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +-- shutdown_server +-- source include/wait_until_disconnected.inc + +# Restart the server. +-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +-- enable_reconnect +-- source include/wait_until_connected_again.inc + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SELECT * FROM t; +COMMIT; +XA RECOVER; +XA ROLLBACK '123'; +XA ROLLBACK '456'; +XA COMMIT '789'; +SELECT * FROM t; + +DROP TABLE t; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug59410.result b/mysql-test/suite/innodb_plugin/r/innodb_bug59410.result new file mode 100644 index 00000000000..494d601ba4f --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug59410.result @@ -0,0 +1,17 @@ +create table `bug59410_1`(`a` int)engine=innodb; +insert into `bug59410_1` values (1),(2),(3); +select 1 from `bug59410_1` where `a` <> any ( +select 1 from `bug59410_1` where `a` <> 1 for update) +for update; +1 +1 +1 +drop table bug59410_1; +create table bug59410_2(`a` char(1),`b` int)engine=innodb; +insert into bug59410_2 values('0',0); +set transaction isolation level read uncommitted; +start transaction; +set @a=(select b from bug59410_2 where +(select 1 from bug59410_2 where a group by @a=b) +group by @a:=b); +drop table bug59410_2; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result b/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result new file mode 100644 index 00000000000..361172aa82b --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result @@ -0,0 +1,57 @@ +CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; +INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); +COMMIT; +XA START '123'; +INSERT INTO t VALUES(1,1); +XA END '123'; +XA PREPARE '123'; +XA START '456'; +INSERT INTO t VALUES(3,47),(5,67); +UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8; +XA END '456'; +XA PREPARE '456'; +XA START '789'; +UPDATE t SET b=4*a WHERE a=32; +XA END '789'; +XA PREPARE '789'; +call mtr.add_suppression("Found 3 prepared XA transactions"); +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SELECT * FROM t; +a b +1 1 +2 2 +3 47 +4 4 +5 134 +8 16 +16 16 +32 128 +COMMIT; +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SELECT * FROM t; +a b +1 1 +2 2 +3 47 +4 4 +5 134 +8 16 +16 16 +32 128 +COMMIT; +XA RECOVER; +formatID gtrid_length bqual_length data +1 3 0 789 +1 3 0 456 +1 3 0 123 +XA ROLLBACK '123'; +XA ROLLBACK '456'; +XA COMMIT '789'; +SELECT * FROM t; +a b +2 2 +4 4 +8 8 +16 16 +32 128 +DROP TABLE t; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug59410.test b/mysql-test/suite/innodb_plugin/t/innodb_bug59410.test new file mode 100644 index 00000000000..6eabe0a8403 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug59410.test @@ -0,0 +1,24 @@ +# +# Bug#59410 read uncommitted: unlock row could not find a 3 mode lock on the record +# +-- source include/have_innodb_plugin.inc + +# only interested that the following do not produce something like +# InnoDB: Error: unlock row could not find a 2 mode lock on the record +# in the error log + +create table `bug59410_1`(`a` int)engine=innodb; +insert into `bug59410_1` values (1),(2),(3); +select 1 from `bug59410_1` where `a` <> any ( +select 1 from `bug59410_1` where `a` <> 1 for update) +for update; +drop table bug59410_1; + +create table bug59410_2(`a` char(1),`b` int)engine=innodb; +insert into bug59410_2 values('0',0); +set transaction isolation level read uncommitted; +start transaction; +set @a=(select b from bug59410_2 where +(select 1 from bug59410_2 where a group by @a=b) +group by @a:=b); +drop table bug59410_2; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test new file mode 100644 index 00000000000..0fb24e47a54 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test @@ -0,0 +1,70 @@ +# Bug #59641 Prepared XA transaction causes shutdown hang after a crash + +-- source include/not_embedded.inc +-- source include/have_innodb_plugin.inc + +let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; + +CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; +INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); +COMMIT; +XA START '123'; +INSERT INTO t VALUES(1,1); +XA END '123'; +XA PREPARE '123'; + +CONNECT (con1,localhost,root,,); +CONNECTION con1; + +XA START '456'; +INSERT INTO t VALUES(3,47),(5,67); +UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8; +XA END '456'; +XA PREPARE '456'; + +CONNECT (con2,localhost,root,,); +CONNECTION con2; + +XA START '789'; +UPDATE t SET b=4*a WHERE a=32; +XA END '789'; +XA PREPARE '789'; + +# The server would issue this warning on restart. +call mtr.add_suppression("Found 3 prepared XA transactions"); + +# Kill the server without sending a shutdown command +-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +-- shutdown_server 0 +-- source include/wait_until_disconnected.inc + +# Restart the server. +-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +-- enable_reconnect +-- source include/wait_until_connected_again.inc +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SELECT * FROM t; +COMMIT; + +# Shut down the server. This would hang because of the bug. +-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +-- shutdown_server +-- source include/wait_until_disconnected.inc + +# Restart the server. +-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +-- enable_reconnect +-- source include/wait_until_connected_again.inc + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SELECT * FROM t; +COMMIT; +XA RECOVER; +XA ROLLBACK '123'; +XA ROLLBACK '456'; +XA COMMIT '789'; +SELECT * FROM t; + +DROP TABLE t; +--disable_query_log +eval set global innodb_file_format_check=$innodb_file_format_check_orig; 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/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/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/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/mysql-test/t/gis.test b/mysql-test/t/gis.test index 94cec60944a..f8cec14d9ae 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -760,10 +760,56 @@ 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; +# +# 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/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; 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/scripts/make_win_bin_dist b/scripts/make_win_bin_dist index 1e4a9df42ab..2aeaed3b746 100755 --- a/scripts/make_win_bin_dist +++ b/scripts/make_win_bin_dist @@ -185,6 +185,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/ 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); } diff --git a/sql/field.cc b/sql/field.cc index 3707c5b056f..a5f946d600c 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/ha_partition.cc b/sql/ha_partition.cc index d09181822ee..d3858eae0d4 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4476,7 +4476,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 { @@ -6396,7 +6397,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); } 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/item_timefunc.cc b/sql/item_timefunc.cc index 1044b4682ef..a96922b94a1 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))) diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 26377bc1562..d3db28e370f 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) @@ -276,7 +277,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 a5077f397e3..97546c91da1 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/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/sql/sql_class.cc b/sql/sql_class.cc index a61ce7bfd14..ae21a5335fd 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3383,6 +3383,7 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state) xs->xa_state=xa_state; xs->xid.set(xid); xs->in_thd=0; + xs->rm_error=0; res=my_hash_insert(&xid_cache, (uchar*)xs); } pthread_mutex_unlock(&LOCK_xid_cache); diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 8129324e300..406998537e4 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -653,6 +653,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. @@ -666,7 +754,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; @@ -855,7 +942,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); @@ -867,39 +954,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) { 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)) diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 988337ec50e..e5c483daac5 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)) { @@ -1111,7 +1113,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); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 6f58fd70fbd..2afacf6d2a8 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -189,7 +189,7 @@ innobase_index_name_is_reserved( /*============================*/ /* out: true if index name matches a reserved name */ - const trx_t* trx, /* in: InnoDB transaction handle */ + THD* thd, /* in/out: MySQL connection */ const TABLE* form, /* in: information on table columns and indexes */ const char* norm_name); /* in: table name */ @@ -5285,10 +5285,6 @@ create_table_def( DBUG_PRINT("enter", ("table_name: %s", table_name)); ut_a(trx->mysql_thd != NULL); - if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, - (THD*) trx->mysql_thd)) { - DBUG_RETURN(HA_ERR_GENERIC); - } n_cols = form->s->fields; @@ -5397,6 +5393,8 @@ err_col: col_len); } + srv_lower_case_table_names = lower_case_table_names; + error = row_create_table_for_mysql(table, trx); innodb_check_for_record_too_big_error(flags & DICT_TF_COMPACT, error); @@ -5642,6 +5640,35 @@ ha_innobase::create( DBUG_RETURN(HA_ERR_TO_BIG_ROW); } + strcpy(name2, name); + + normalize_table_name(norm_name, name2); + + /* Create the table definition in InnoDB */ + + flags = form->s->row_type != ROW_TYPE_REDUNDANT ? DICT_TF_COMPACT : 0; + + /* Look for a primary key */ + + primary_key_no= (form->s->primary_key != MAX_KEY ? + (int) form->s->primary_key : + -1); + + /* Our function row_get_mysql_key_number_for_index assumes + the primary key is always number 0, if it exists */ + + DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0); + + /* Check for name conflicts (with reserved name) for + any user indices to be created. */ + if (innobase_index_name_is_reserved(thd, form, norm_name)) { + DBUG_RETURN(-1); + } + + if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) { + DBUG_RETURN(HA_ERR_GENERIC); + } + /* Get the transaction associated with the current thd, or create one if not yet created */ @@ -5665,48 +5692,12 @@ ha_innobase::create( trx->check_unique_secondary = FALSE; } - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - - strcpy(name2, name); - - normalize_table_name(norm_name, name2); - /* Latch the InnoDB data dictionary exclusively so that no deadlocks or lock waits can happen in it during a table create operation. Drop table etc. do this latching in row0mysql.c. */ row_mysql_lock_data_dictionary(trx); - /* Create the table definition in InnoDB */ - - flags = 0; - - if (form->s->row_type != ROW_TYPE_REDUNDANT) { - flags |= DICT_TF_COMPACT; - } - - /* Look for a primary key */ - - primary_key_no= (form->s->primary_key != MAX_KEY ? - (int) form->s->primary_key : - -1); - - /* Our function row_get_mysql_key_number_for_index assumes - the primary key is always number 0, if it exists */ - - DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0); - - /* Check for name conflicts (with reserved name) for - any user indices to be created. */ - if (innobase_index_name_is_reserved(trx, form, norm_name)) { - error = -1; - goto cleanup; - } - error = create_table_def(trx, form, norm_name, create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, flags); @@ -5936,12 +5927,6 @@ ha_innobase::delete_table( trx_search_latch_release_if_reserved(parent_trx); - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - trx = trx_allocate_for_mysql(); trx->mysql_thd = thd; @@ -5961,6 +5946,8 @@ ha_innobase::delete_table( /* Drop the table in InnoDB */ + srv_lower_case_table_names = lower_case_table_names; + error = row_drop_table_for_mysql(norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB); @@ -6089,12 +6076,6 @@ ha_innobase::rename_table( trx_search_latch_release_if_reserved(parent_trx); - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - trx = trx_allocate_for_mysql(); trx->mysql_thd = thd; INNOBASE_COPY_STMT(thd, trx); @@ -6114,6 +6095,8 @@ ha_innobase::rename_table( /* Rename the table in InnoDB */ + srv_lower_case_table_names = lower_case_table_names; + error = row_rename_table_for_mysql(norm_from, norm_to, trx); /* Flush the log to reduce probability that the .frm files and @@ -8565,7 +8548,7 @@ innobase_commit_by_xid( if (trx) { innobase_commit_low(trx); - + trx_free_for_background(trx); return(XA_OK); } else { return(XAER_NOTA); @@ -8588,7 +8571,9 @@ innobase_rollback_by_xid( trx = trx_get_trx_by_xid(xid); if (trx) { - return(innobase_rollback_trx(trx)); + int ret = innobase_rollback_trx(trx); + trx_free_for_background(trx); + return(ret); } else { return(XAER_NOTA); } @@ -8824,7 +8809,7 @@ innobase_index_name_is_reserved( /*============================*/ /* out: true if an index name matches the reserved name */ - const trx_t* trx, /* in: InnoDB transaction handle */ + THD* thd, /* in/out: MySQL connection */ const TABLE* form, /* in: information on table columns and indexes */ const char* norm_name) /* in: table name */ @@ -8838,7 +8823,7 @@ innobase_index_name_is_reserved( if (innobase_strcasecmp(key->name, innobase_index_reserve_name) == 0) { /* Push warning to mysql */ - push_warning_printf((THD*) trx->mysql_thd, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_CANT_CREATE_TABLE, "Cannot Create Index with name " diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 4652f45892e..7cb16107746 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -19,7 +19,12 @@ Created 3/26/1996 Heikki Tuuri #include "dict0types.h" #include "trx0xa.h" +/* Number of transactions currently allocated for MySQL: protected by +the kernel mutex */ extern ulint trx_n_mysql_transactions; +/* Number of transactions currently in the XA PREPARED state: protected by +the kernel mutex */ +extern ulint trx_n_prepared; /************************************************************************ Releases the search latch if trx has reserved it. */ diff --git a/storage/innobase/log/log0log.c b/storage/innobase/log/log0log.c index 3300997112b..092e3bfe37f 100644 --- a/storage/innobase/log/log0log.c +++ b/storage/innobase/log/log0log.c @@ -3052,12 +3052,13 @@ loop: goto loop; } - /* Check that there are no longer transactions. We need this wait even - for the 'very fast' shutdown, because the InnoDB layer may have - committed or prepared transactions and we don't want to lose them. */ + /* Check that there are no longer transactions, except for + PREPARED ones. We need this wait even for the 'very fast' + shutdown, because the InnoDB layer may have committed or + prepared transactions and we don't want to lose them. */ if (trx_n_mysql_transactions > 0 - || UT_LIST_GET_LEN(trx_sys->trx_list) > 0) { + || UT_LIST_GET_LEN(trx_sys->trx_list) > trx_n_prepared) { mutex_exit(&kernel_mutex); diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index a82d7f452fc..d174f1e1b37 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -41,6 +41,9 @@ sess_t* trx_dummy_sess = NULL; /* Number of transactions currently allocated for MySQL: protected by the kernel mutex */ ulint trx_n_mysql_transactions = 0; +/* Number of transactions currently in the XA PREPARED state: protected by +the kernel mutex */ +ulint trx_n_prepared = 0; /***************************************************************** Starts the transaction if it is not yet started. */ @@ -480,6 +483,7 @@ trx_lists_init_at_db_start(void) if (srv_force_recovery == 0) { trx->conc_state = TRX_PREPARED; + trx_n_prepared++; } else { fprintf(stderr, "InnoDB: Since" @@ -558,6 +562,7 @@ trx_lists_init_at_db_start(void) trx->conc_state = TRX_PREPARED; + trx_n_prepared++; } else { fprintf(stderr, "InnoDB: Since" @@ -832,6 +837,11 @@ trx_commit_off_kernel( || trx->conc_state == TRX_PREPARED); ut_ad(mutex_own(&kernel_mutex)); + if (UNIV_UNLIKELY(trx->conc_state == TRX_PREPARED)) { + ut_a(trx_n_prepared > 0); + trx_n_prepared--; + } + /* The following assignment makes the transaction committed in memory and makes its changes to data visible to other transactions. NOTE that there is a small discrepancy from the strict formal @@ -1882,6 +1892,7 @@ trx_prepare_off_kernel( /*--------------------------------------*/ trx->conc_state = TRX_PREPARED; + trx_n_prepared++; /*--------------------------------------*/ if (must_flush_log) { diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 100cf3690ce..0b201816819 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,15 @@ +2011-04-07 The InnoDB Team + + * handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc: + Fix Bug #52409 Assertion failure: long semaphore wait + +2011-04-07 The InnoDB Team + + * handler/ha_innodb.cc, include/trx0trx.h, include/trx0undo.h, + log/log0log.c, trx/trx0sys.c, trx/trx0trx.c, trx/trx0undo.c: + Fix Bug #59641 Prepared XA transaction in system after hard crash + causes future shutdown hang + 2011-03-30 The InnoDB Team * srv/srv0srv.c, sync/sync0arr.h, sync/sync0arr.c: diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index dda2fbaa4d2..2b0dbf82b34 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -6023,10 +6023,6 @@ create_table_def( DBUG_PRINT("enter", ("table_name: %s", table_name)); ut_a(trx->mysql_thd != NULL); - if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, - (THD*) trx->mysql_thd)) { - DBUG_RETURN(HA_ERR_GENERIC); - } /* MySQL does the name length check. But we do additional check on the name length here */ @@ -6146,6 +6142,8 @@ err_col: col_len); } + srv_lower_case_table_names = lower_case_table_names; + error = row_create_table_for_mysql(table, trx); if (error == DB_DUPLICATE_KEY) { @@ -6562,42 +6560,17 @@ ha_innobase::create( DBUG_RETURN(HA_ERR_TO_BIG_ROW); } - /* Get the transaction associated with the current thd, or create one - if not yet created */ - - parent_trx = check_trx_exists(thd); - - /* In case MySQL calls this in the middle of a SELECT query, release - possible adaptive hash latch to avoid deadlocks of threads */ - - trx_search_latch_release_if_reserved(parent_trx); - - trx = innobase_trx_allocate(thd); - - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - strcpy(name2, name); normalize_table_name(norm_name, name2); - /* Latch the InnoDB data dictionary exclusively so that no deadlocks - or lock waits can happen in it during a table create operation. - Drop table etc. do this latching in row0mysql.c. */ - - row_mysql_lock_data_dictionary(trx); - /* Create the table definition in InnoDB */ flags = 0; /* Validate create options if innodb_strict_mode is set. */ if (!create_options_are_valid(thd, form, create_info)) { - error = ER_ILLEGAL_HA_CREATE_OPTION; - goto cleanup; + DBUG_RETURN(ER_ILLEGAL_HA_CREATE_OPTION); } if (create_info->key_block_size) { @@ -6739,16 +6712,37 @@ ha_innobase::create( /* Check for name conflicts (with reserved name) for any user indices to be created. */ - if (innobase_index_name_is_reserved(trx, form->key_info, + if (innobase_index_name_is_reserved(thd, form->key_info, form->s->keys)) { - error = -1; - goto cleanup; + DBUG_RETURN(-1); + } + + if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) { + DBUG_RETURN(HA_ERR_GENERIC); } if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { flags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT; } + /* Get the transaction associated with the current thd, or create one + if not yet created */ + + parent_trx = check_trx_exists(thd); + + /* In case MySQL calls this in the middle of a SELECT query, release + possible adaptive hash latch to avoid deadlocks of threads */ + + trx_search_latch_release_if_reserved(parent_trx); + + trx = innobase_trx_allocate(thd); + + /* Latch the InnoDB data dictionary exclusively so that no deadlocks + or lock waits can happen in it during a table create operation. + Drop table etc. do this latching in row0mysql.c. */ + + row_mysql_lock_data_dictionary(trx); + error = create_table_def(trx, form, norm_name, create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, flags); @@ -6992,18 +6986,14 @@ ha_innobase::delete_table( trx = innobase_trx_allocate(thd); - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - name_len = strlen(name); ut_a(name_len < 1000); /* Drop the table in InnoDB */ + srv_lower_case_table_names = lower_case_table_names; + error = row_drop_table_for_mysql(norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB); @@ -7119,12 +7109,6 @@ innobase_rename_table( char* norm_to; char* norm_from; - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - // Magic number 64 arbitrary norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0)); norm_from = (char*) my_malloc(strlen(from) + 64, MYF(0)); @@ -7139,6 +7123,8 @@ innobase_rename_table( row_mysql_lock_data_dictionary(trx); } + srv_lower_case_table_names = lower_case_table_names; + error = row_rename_table_for_mysql( norm_from, norm_to, trx, lock_and_commit); @@ -9998,7 +9984,7 @@ innobase_commit_by_xid( if (trx) { innobase_commit_low(trx); - + trx_free_for_background(trx); return(XA_OK); } else { return(XAER_NOTA); @@ -10024,7 +10010,9 @@ innobase_rollback_by_xid( trx = trx_get_trx_by_xid(xid); if (trx) { - return(innobase_rollback_trx(trx)); + int ret = innobase_rollback_trx(trx); + trx_free_for_background(trx); + return(ret); } else { return(XAER_NOTA); } @@ -10698,19 +10686,19 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) return 0; } -/*********************************************************************** +/*********************************************************************//** This function checks each index name for a table against reserved -system default primary index name 'GEN_CLUST_INDEX'. If a name matches, -this function pushes an warning message to the client, and returns true. */ +system default primary index name 'GEN_CLUST_INDEX'. If a name +matches, this function pushes an warning message to the client, +and returns true. +@return true if the index name matches the reserved name */ extern "C" UNIV_INTERN bool innobase_index_name_is_reserved( /*============================*/ - /* out: true if an index name - matches the reserved name */ - const trx_t* trx, /* in: InnoDB transaction handle */ - const KEY* key_info, /* in: Indexes to be created */ - ulint num_of_keys) /* in: Number of indexes to + THD* thd, /*!< in/out: MySQL connection */ + const KEY* key_info, /*!< in: Indexes to be created */ + ulint num_of_keys) /*!< in: Number of indexes to be created. */ { const KEY* key; @@ -10722,7 +10710,7 @@ innobase_index_name_is_reserved( if (innobase_strcasecmp(key->name, innobase_index_reserve_name) == 0) { /* Push warning to mysql */ - push_warning_printf((THD*) trx->mysql_thd, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WRONG_NAME_FOR_INDEX, "Cannot Create Index with name " diff --git a/storage/innodb_plugin/handler/ha_innodb.h b/storage/innodb_plugin/handler/ha_innodb.h index 7a8f29853de..f7a5456b1a7 100644 --- a/storage/innodb_plugin/handler/ha_innodb.h +++ b/storage/innodb_plugin/handler/ha_innodb.h @@ -317,15 +317,14 @@ innobase_trx_allocate( This function checks each index name for a table against reserved system default primary index name 'GEN_CLUST_INDEX'. If a name matches, this function pushes an warning message to the client, -and returns true. */ +and returns true. +@return true if the index name matches the reserved name */ extern "C" bool innobase_index_name_is_reserved( /*============================*/ - /* out: true if the index name - matches the reserved name */ - const trx_t* trx, /* in: InnoDB transaction handle */ - const KEY* key_info, /* in: Indexes to be created */ - ulint num_of_keys); /* in: Number of indexes to + THD* thd, /*!< in/out: MySQL connection */ + const KEY* key_info, /*!< in: Indexes to be created */ + ulint num_of_keys); /*!< in: Number of indexes to be created. */ diff --git a/storage/innodb_plugin/handler/handler0alter.cc b/storage/innodb_plugin/handler/handler0alter.cc index dc1317d5c5a..485e03737e3 100644 --- a/storage/innodb_plugin/handler/handler0alter.cc +++ b/storage/innodb_plugin/handler/handler0alter.cc @@ -649,11 +649,30 @@ ha_innobase::add_index( update_thd(); - heap = mem_heap_create(1024); - /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads. */ trx_search_latch_release_if_reserved(prebuilt->trx); + + /* Check if the index name is reserved. */ + if (innobase_index_name_is_reserved(user_thd, key_info, num_of_keys)) { + DBUG_RETURN(-1); + } + + innodb_table = indexed_table + = dict_table_get(prebuilt->table->name, FALSE); + + if (UNIV_UNLIKELY(!innodb_table)) { + DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); + } + + /* Check that index keys are sensible */ + error = innobase_check_index_keys(key_info, num_of_keys, innodb_table); + + if (UNIV_UNLIKELY(error)) { + DBUG_RETURN(error); + } + + heap = mem_heap_create(1024); trx_start_if_not_started(prebuilt->trx); /* Create a background transaction for the operations on @@ -661,32 +680,6 @@ ha_innobase::add_index( trx = innobase_trx_allocate(user_thd); trx_start_if_not_started(trx); - innodb_table = indexed_table - = dict_table_get(prebuilt->table->name, FALSE); - - if (UNIV_UNLIKELY(!innodb_table)) { - error = HA_ERR_NO_SUCH_TABLE; - goto err_exit; - } - - /* Check if the index name is reserved. */ - if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) { - error = -1; - } else { - /* Check that index keys are sensible */ - error = innobase_check_index_keys(key_info, num_of_keys, - innodb_table); - } - - if (UNIV_UNLIKELY(error)) { -err_exit: - mem_heap_free(heap); - trx_general_rollback_for_mysql(trx, NULL); - trx_free_for_mysql(trx); - trx_commit_for_mysql(prebuilt->trx); - DBUG_RETURN(error); - } - /* Create table containing all indexes to be built in this alter table add index so that they are in the correct order in the table. */ @@ -758,8 +751,12 @@ err_exit: ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE)); + mem_heap_free(heap); + trx_general_rollback_for_mysql(trx, NULL); row_mysql_unlock_data_dictionary(trx); - goto err_exit; + trx_free_for_mysql(trx); + trx_commit_for_mysql(prebuilt->trx); + DBUG_RETURN(error); } trx->table_id = indexed_table->id; diff --git a/storage/innodb_plugin/include/trx0trx.h b/storage/innodb_plugin/include/trx0trx.h index 833bae4a4ff..4bf3e75a5ee 100644 --- a/storage/innodb_plugin/include/trx0trx.h +++ b/storage/innodb_plugin/include/trx0trx.h @@ -44,6 +44,9 @@ extern sess_t* trx_dummy_sess; /** Number of transactions currently allocated for MySQL: protected by the kernel mutex */ extern ulint trx_n_mysql_transactions; +/** Number of transactions currently in the XA PREPARED state: protected by +the kernel mutex */ +extern ulint trx_n_prepared; /********************************************************************//** Releases the search latch if trx has reserved it. */ @@ -108,6 +111,14 @@ trx_free( /*=====*/ trx_t* trx); /*!< in, own: trx object */ /********************************************************************//** +At shutdown, frees a transaction object that is in the PREPARED state. */ +UNIV_INTERN +void +trx_free_prepared( +/*==============*/ + trx_t* trx) /*!< in, own: trx object */ + __attribute__((nonnull)); +/********************************************************************//** Frees a transaction object for MySQL. */ UNIV_INTERN void diff --git a/storage/innodb_plugin/include/trx0undo.h b/storage/innodb_plugin/include/trx0undo.h index a084f2394b5..4f15cd85833 100644 --- a/storage/innodb_plugin/include/trx0undo.h +++ b/storage/innodb_plugin/include/trx0undo.h @@ -298,6 +298,15 @@ void trx_undo_insert_cleanup( /*====================*/ trx_t* trx); /*!< in: transaction handle */ + +/********************************************************************//** +At shutdown, frees the undo logs of a PREPARED transaction. */ +UNIV_INTERN +void +trx_undo_free_prepared( +/*===================*/ + trx_t* trx) /*!< in/out: PREPARED transaction */ + __attribute__((nonnull)); #endif /* !UNIV_HOTBACKUP */ /***********************************************************//** Parses the redo log entry of an undo log page initialization. diff --git a/storage/innodb_plugin/log/log0log.c b/storage/innodb_plugin/log/log0log.c index 183c24d2147..4bb9abdc1a4 100644 --- a/storage/innodb_plugin/log/log0log.c +++ b/storage/innodb_plugin/log/log0log.c @@ -3085,12 +3085,13 @@ loop: goto loop; } - /* Check that there are no longer transactions. We need this wait even - for the 'very fast' shutdown, because the InnoDB layer may have - committed or prepared transactions and we don't want to lose them. */ + /* Check that there are no longer transactions, except for + PREPARED ones. We need this wait even for the 'very fast' + shutdown, because the InnoDB layer may have committed or + prepared transactions and we don't want to lose them. */ if (trx_n_mysql_transactions > 0 - || UT_LIST_GET_LEN(trx_sys->trx_list) > 0) { + || UT_LIST_GET_LEN(trx_sys->trx_list) > trx_n_prepared) { mutex_exit(&kernel_mutex); diff --git a/storage/innodb_plugin/trx/trx0sys.c b/storage/innodb_plugin/trx/trx0sys.c index 6eb356947cc..352fa6af219 100644 --- a/storage/innodb_plugin/trx/trx0sys.c +++ b/storage/innodb_plugin/trx/trx0sys.c @@ -37,6 +37,7 @@ Created 3/26/1996 Heikki Tuuri #include "trx0rseg.h" #include "trx0undo.h" #include "srv0srv.h" +#include "srv0start.h" #include "trx0purge.h" #include "log0log.h" #include "os0file.h" @@ -1548,10 +1549,12 @@ void trx_sys_close(void) /*===============*/ { + trx_t* trx; trx_rseg_t* rseg; read_view_t* view; ut_ad(trx_sys != NULL); + ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS); /* Check that all read views are closed except read view owned by a purge. */ @@ -1583,6 +1586,13 @@ trx_sys_close(void) mem_free(trx_doublewrite); trx_doublewrite = NULL; + /* Only prepared transactions may be left in the system. Free them. */ + ut_a(UT_LIST_GET_LEN(trx_sys->trx_list) == trx_n_prepared); + + while ((trx = UT_LIST_GET_FIRST(trx_sys->trx_list)) != NULL) { + trx_free_prepared(trx); + } + /* There can't be any active transactions. */ rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list); diff --git a/storage/innodb_plugin/trx/trx0trx.c b/storage/innodb_plugin/trx/trx0trx.c index f0bbf220815..7f3a3fcb4bf 100644 --- a/storage/innodb_plugin/trx/trx0trx.c +++ b/storage/innodb_plugin/trx/trx0trx.c @@ -50,6 +50,9 @@ UNIV_INTERN sess_t* trx_dummy_sess = NULL; /** Number of transactions currently allocated for MySQL: protected by the kernel mutex */ UNIV_INTERN ulint trx_n_mysql_transactions = 0; +/* Number of transactions currently in the XA PREPARED state: protected by +the kernel mutex */ +UNIV_INTERN ulint trx_n_prepared = 0; /*************************************************************//** Set detailed error message for the transaction. */ @@ -333,6 +336,60 @@ trx_free( mem_free(trx); } +/********************************************************************//** +At shutdown, frees a transaction object that is in the PREPARED state. */ +UNIV_INTERN +void +trx_free_prepared( +/*==============*/ + trx_t* trx) /*!< in, own: trx object */ +{ + ut_ad(mutex_own(&kernel_mutex)); + ut_a(trx->conc_state == TRX_PREPARED); + ut_a(trx->magic_n == TRX_MAGIC_N); + + /* Prepared transactions are sort of active; they allow + ROLLBACK and COMMIT operations. Because the system does not + contain any other transactions than prepared transactions at + the shutdown stage and because a transaction cannot become + PREPARED while holding locks, it is safe to release the locks + held by PREPARED transactions here at shutdown.*/ + lock_release_off_kernel(trx); + + trx_undo_free_prepared(trx); + + mutex_free(&trx->undo_mutex); + + if (trx->undo_no_arr) { + trx_undo_arr_free(trx->undo_no_arr); + } + + ut_a(UT_LIST_GET_LEN(trx->signals) == 0); + ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0); + + ut_a(trx->wait_lock == NULL); + ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0); + + ut_a(!trx->has_search_latch); + + ut_a(trx->dict_operation_lock_mode == 0); + + if (trx->lock_heap) { + mem_heap_free(trx->lock_heap); + } + + if (trx->global_read_view_heap) { + mem_heap_free(trx->global_read_view_heap); + } + + ut_a(ib_vector_is_empty(trx->autoinc_locks)); + ib_vector_free(trx->autoinc_locks); + + UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx); + + mem_free(trx); +} + /********************************************************************//** Frees a transaction object for MySQL. */ UNIV_INTERN @@ -463,6 +520,7 @@ trx_lists_init_at_db_start(void) if (srv_force_recovery == 0) { trx->conc_state = TRX_PREPARED; + trx_n_prepared++; } else { fprintf(stderr, "InnoDB: Since" @@ -541,6 +599,7 @@ trx_lists_init_at_db_start(void) trx->conc_state = TRX_PREPARED; + trx_n_prepared++; } else { fprintf(stderr, "InnoDB: Since" @@ -820,6 +879,11 @@ trx_commit_off_kernel( || trx->conc_state == TRX_PREPARED); ut_ad(mutex_own(&kernel_mutex)); + if (UNIV_UNLIKELY(trx->conc_state == TRX_PREPARED)) { + ut_a(trx_n_prepared > 0); + trx_n_prepared--; + } + /* The following assignment makes the transaction committed in memory and makes its changes to data visible to other transactions. NOTE that there is a small discrepancy from the strict formal @@ -1857,6 +1921,7 @@ trx_prepare_off_kernel( /*--------------------------------------*/ trx->conc_state = TRX_PREPARED; + trx_n_prepared++; /*--------------------------------------*/ if (lsn) { @@ -2031,10 +2096,11 @@ trx_get_trx_by_xid( while (trx) { /* Compare two X/Open XA transaction id's: their length should be the same and binary comparison - of gtrid_lenght+bqual_length bytes should be + of gtrid_length+bqual_length bytes should be the same */ - if (trx->conc_state == TRX_PREPARED + if (trx->is_recovered + && trx->conc_state == TRX_PREPARED && xid->gtrid_length == trx->xid.gtrid_length && xid->bqual_length == trx->xid.bqual_length && memcmp(xid->data, trx->xid.data, diff --git a/storage/innodb_plugin/trx/trx0undo.c b/storage/innodb_plugin/trx/trx0undo.c index 76e88948e41..68ff82f618c 100644 --- a/storage/innodb_plugin/trx/trx0undo.c +++ b/storage/innodb_plugin/trx/trx0undo.c @@ -36,6 +36,7 @@ Created 3/26/1996 Heikki Tuuri #include "trx0rseg.h" #include "trx0trx.h" #include "srv0srv.h" +#include "srv0start.h" #include "trx0rec.h" #include "trx0purge.h" @@ -1976,4 +1977,31 @@ trx_undo_insert_cleanup( mutex_exit(&(rseg->mutex)); } + +/********************************************************************//** +At shutdown, frees the undo logs of a PREPARED transaction. */ +UNIV_INTERN +void +trx_undo_free_prepared( +/*===================*/ + trx_t* trx) /*!< in/out: PREPARED transaction */ +{ + mutex_enter(&trx->rseg->mutex); + + ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS); + + if (trx->update_undo) { + ut_a(trx->update_undo->state == TRX_UNDO_PREPARED); + UT_LIST_REMOVE(undo_list, trx->rseg->update_undo_list, + trx->update_undo); + trx_undo_mem_free(trx->update_undo); + } + if (trx->insert_undo) { + ut_a(trx->insert_undo->state == TRX_UNDO_PREPARED); + UT_LIST_REMOVE(undo_list, trx->rseg->insert_undo_list, + trx->insert_undo); + trx_undo_mem_free(trx->insert_undo); + } + mutex_exit(&trx->rseg->mutex); +} #endif /* !UNIV_HOTBACKUP */ 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/strings/decimal.c b/strings/decimal.c index e89669c3de5..32e35a64de7 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 ? 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); }