From 4b4a0532456fa05dc04c63d3e202e44573abaa4c Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 9 Nov 2015 15:25:01 +0100 Subject: [PATCH 01/57] Raise version number after cloning 5.5.47 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b85da230659..4bf30e8600e 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=47 +MYSQL_VERSION_PATCH=48 MYSQL_VERSION_EXTRA= From 15de3c6275ad8898aed5cd466762030df0fef015 Mon Sep 17 00:00:00 2001 From: Ajo Robert Date: Fri, 13 Nov 2015 17:51:18 +0530 Subject: [PATCH 02/57] Bug#19817021 CRASH IN TABLE_LIST::PREPARE_SECURITY WHEN DOING BAD DDL IN PREPARED STATEMENT Analysis ======== A repeat execution of the prepared statement 'ALTER TABLE v1 CHECK PARTITION' where v1 is a view leads to server exit. ALTER TABLE ... CHECK PARTITION is not applicable for views and check for the same check is missing. This leads to further execution and creation of derived table for the view (Allocated under temp_table mem_root). Any reference to open view or related pointers from second execution leads to server exit as the same was freed at previous execution closure. Fix: ====== Added check for view in mysql_admin_table() on PARTITION operation. This will prevent mysql_admin_table() from going ahead and creating temp table and related issues. Changed message on admin table view operation error to be more appropriate. --- mysql-test/r/sp.result | 18 +++++++++--------- mysql-test/r/view.result | 12 ++++++------ sql/sql_admin.cc | 14 +++++++++++--- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 4d93ce202fe..638f54a93ce 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -4414,57 +4414,57 @@ test.t1 repair status OK test.t2 repair status OK test.t3 repair status OK test.v1 repair Error 'test.v1' is not BASE TABLE -test.v1 repair error Corrupt +test.v1 repair status Operation failed Table Op Msg_type Msg_text test.t1 optimize status OK test.t2 optimize status OK test.t3 optimize status OK test.v1 optimize Error 'test.v1' is not BASE TABLE -test.v1 optimize error Corrupt +test.v1 optimize status Operation failed Table Op Msg_type Msg_text test.t1 analyze status Table is already up to date test.t2 analyze status Table is already up to date test.t3 analyze status Table is already up to date test.v1 analyze Error 'test.v1' is not BASE TABLE -test.v1 analyze error Corrupt +test.v1 analyze status Operation failed call bug13012()| Table Op Msg_type Msg_text test.t1 repair status OK test.t2 repair status OK test.t3 repair status OK test.v1 repair Error 'test.v1' is not BASE TABLE -test.v1 repair error Corrupt +test.v1 repair status Operation failed Table Op Msg_type Msg_text test.t1 optimize status OK test.t2 optimize status OK test.t3 optimize status OK test.v1 optimize Error 'test.v1' is not BASE TABLE -test.v1 optimize error Corrupt +test.v1 optimize status Operation failed Table Op Msg_type Msg_text test.t1 analyze status Table is already up to date test.t2 analyze status Table is already up to date test.t3 analyze status Table is already up to date test.v1 analyze Error 'test.v1' is not BASE TABLE -test.v1 analyze error Corrupt +test.v1 analyze status Operation failed call bug13012()| Table Op Msg_type Msg_text test.t1 repair status OK test.t2 repair status OK test.t3 repair status OK test.v1 repair Error 'test.v1' is not BASE TABLE -test.v1 repair error Corrupt +test.v1 repair status Operation failed Table Op Msg_type Msg_text test.t1 optimize status OK test.t2 optimize status OK test.t3 optimize status OK test.v1 optimize Error 'test.v1' is not BASE TABLE -test.v1 optimize error Corrupt +test.v1 optimize status Operation failed Table Op Msg_type Msg_text test.t1 analyze status Table is already up to date test.t2 analyze status Table is already up to date test.t3 analyze status Table is already up to date test.v1 analyze Error 'test.v1' is not BASE TABLE -test.v1 analyze error Corrupt +test.v1 analyze status Operation failed drop procedure bug13012| drop view v1| select * from t1 order by data| diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index a3adf80c096..1842de91ef9 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2402,28 +2402,28 @@ CREATE VIEW v1 AS SELECT id FROM t1; OPTIMIZE TABLE v1; Table Op Msg_type Msg_text test.v1 optimize Error 'test.v1' is not BASE TABLE -test.v1 optimize error Corrupt +test.v1 optimize status Operation failed ANALYZE TABLE v1; Table Op Msg_type Msg_text test.v1 analyze Error 'test.v1' is not BASE TABLE -test.v1 analyze error Corrupt +test.v1 analyze status Operation failed REPAIR TABLE v1; Table Op Msg_type Msg_text test.v1 repair Error 'test.v1' is not BASE TABLE -test.v1 repair error Corrupt +test.v1 repair status Operation failed DROP TABLE t1; OPTIMIZE TABLE v1; Table Op Msg_type Msg_text test.v1 optimize Error 'test.v1' is not BASE TABLE -test.v1 optimize error Corrupt +test.v1 optimize status Operation failed ANALYZE TABLE v1; Table Op Msg_type Msg_text test.v1 analyze Error 'test.v1' is not BASE TABLE -test.v1 analyze error Corrupt +test.v1 analyze status Operation failed REPAIR TABLE v1; Table Op Msg_type Msg_text test.v1 repair Error 'test.v1' is not BASE TABLE -test.v1 repair error Corrupt +test.v1 repair status Operation failed DROP VIEW v1; create definer = current_user() sql security invoker view v1 as select 1; show create view v1; diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index f07a8089853..efdb67d01c4 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2015, 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 @@ -248,7 +249,8 @@ static inline bool table_not_corrupt_error(uint sql_errno) sql_errno == ER_LOCK_WAIT_TIMEOUT || sql_errno == ER_LOCK_DEADLOCK || sql_errno == ER_CANT_LOCK_LOG_TABLE || - sql_errno == ER_OPEN_AS_READONLY); + sql_errno == ER_OPEN_AS_READONLY || + sql_errno == ER_WRONG_OBJECT); } @@ -333,7 +335,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, lex->query_tables_last= &table->next_global; lex->query_tables_own_last= 0; - if (view_operator_func == NULL) + /* + CHECK TABLE command is allowed for views as well. Check on alter flags + to differentiate from ALTER TABLE...CHECK PARTITION on which view is not + allowed. + */ + if (lex->alter_info.flags & ALTER_ADMIN_PARTITION || + view_operator_func == NULL) table->required_type=FRMTYPE_TABLE; if (!thd->locked_tables_mode && repair_table_use_frm) From 6d1e2fbca805cb9dde94def5f579b0ee45444f5b Mon Sep 17 00:00:00 2001 From: Ajo Robert Date: Fri, 13 Nov 2015 18:04:31 +0530 Subject: [PATCH 03/57] Bug#20691429 ASSERTION `CHILD_L' FAILED IN STORAGE/MYISAMMRG/ HA_MYISAMMRG.CC:631 Analysis ======== Any attempt to open a temporary MyISAM merge table consisting of a view in its list of tables (not the last table in the list) under LOCK TABLES causes the server to exit. Current implementation doesn't perform sanity checks during merge table creation. This allows merge table to be created with incompatible tables (table with non-myisam engine), views or even with table doesn't exist in the system. During view open, check to verify whether requested view is part of a merge table is missing under LOCK TABLES path in open_table(). This leads to opening of underlying table with parent_l having NULL value. Later when attaching child tables to parent, this hits an ASSERT as all child tables should have parent_l pointing to merge parent. If the operation does not happen under LOCK TABLES mode, open_table() checks for view's parent_l and returns error. Fix: ====== Check added before opening view Under LOCK TABLES in open_table() to verify whether it is part of merge table. Error is returned if the view is part of a merge table. --- sql/sql_base.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 61a0d1ae909..172987cc1c6 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2828,6 +2828,16 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, */ if (dd_frm_type(thd, path, ¬_used) == FRMTYPE_VIEW) { + /* + If parent_l of the table_list is non null then a merge table + has this view as child table, which is not supported. + */ + if (table_list->parent_l) + { + my_error(ER_WRONG_MRG_TABLE, MYF(0)); + DBUG_RETURN(true); + } + if (!tdc_open_view(thd, table_list, alias, key, key_length, mem_root, 0)) { From 63dc9c3f42858e0f855abb875f37cb096cf3ae27 Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Wed, 18 Nov 2015 08:04:04 +0530 Subject: [PATCH 04/57] Bug #22214852: MYSQL 5.5 AND 5.6: MAIN.KEY AND OTHER FAILURE WITH VALGRIND FOR RELEASE BUILD Issue: ------ Initialization of variable with UNINIT_VAR is flagged by valgrind 3.11. SOLUTION: --------- Initialize the variable to 0. This is a backport of Bug# 14580121. --- storage/myisam/mi_check.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index 5f326d0e45f..ba1f975549a 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2015, 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 @@ -138,7 +138,7 @@ int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag) { reg2 ha_rows i; uint delete_link_length; - my_off_t empty,next_link,UNINIT_VAR(old_link); + my_off_t empty, next_link, old_link= 0; char buff[22],buff2[22]; DBUG_ENTER("chk_del"); From bb56c30ad750465ab140477a1042cb34e714dcc5 Mon Sep 17 00:00:00 2001 From: Venkatesh Duggirala Date: Thu, 19 Nov 2015 13:59:27 +0530 Subject: [PATCH 05/57] Bug#17047208 REPLICATION DIFFERENCE FOR MULTIPLE TRIGGERS Problem & Analysis: If DML invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column, that DML has to be marked as 'unsafe' statement. If the tables are locked in the transaction prior to DML statement (using LOCK TABLES), then the same statement is not marked as 'unsafe' statement. The logic of checking whether unsafeness is protected with if (!thd->locked_tables_mode). Hence if we lock the tables prior to DML statement, it is *not* entering into this if condition. Hence the statement is not marked as unsafe statement. Fix: Irrespective of locked_tables_mode value, the unsafeness check should be done. Now with this patch, the code is moved out to 'decide_logging_format()' function where all these checks are happening and also with out 'if(!thd->locked_tables_mode)'. Along with the specified test case in the bug scenario (BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS), we also identified that other cases BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST, BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT, BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS are also protected with thd->locked_tables_mode which is not right. All of those checks also moved to 'decide_logging_format()' function. --- .../suite/rpl/r/rpl_unsafe_statements.result | 53 ++++++ .../suite/rpl/t/rpl_unsafe_statements.test | 175 ++++++++++++++++++ sql/sql_base.cc | 154 --------------- sql/sql_class.cc | 131 +++++++++++++ sql/sql_lex.h | 7 +- 5 files changed, 365 insertions(+), 155 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_unsafe_statements.result create mode 100644 mysql-test/suite/rpl/t/rpl_unsafe_statements.test diff --git a/mysql-test/suite/rpl/r/rpl_unsafe_statements.result b/mysql-test/suite/rpl/r/rpl_unsafe_statements.result new file mode 100644 index 00000000000..2efb3eba2b1 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_unsafe_statements.result @@ -0,0 +1,53 @@ +include/master-slave.inc +[connection master] +CREATE TABLE t1(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB; +CREATE TABLE t2(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB; +CREATE TRIGGER trig1 AFTER INSERT ON t1 +FOR EACH ROW +INSERT INTO t2(i) VALUES(new.i); +START TRANSACTION; +INSERT INTO t2(i) VALUES (1); +ROLLBACK; +INSERT INTO t1(i) VALUES(2); +START TRANSACTION; +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t1(i) VALUES(3); +UNLOCK TABLES; +COMMIT; +include/diff_tables.inc [master:t1, slave:t1] +include/diff_tables.inc [master:t2, slave:t2] +DROP TABLE t1,t2; +CREATE TABLE t1(i INT) ENGINE=INNODB; +CREATE TABLE t2(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB; +INSERT INTO t1 values (1), (2), (3); +START TRANSACTION; +INSERT INTO t2(i) VALUES (1); +ROLLBACK; +INSERT INTO t2(i) SELECT i FROM t1; +START TRANSACTION; +LOCK TABLES t2 WRITE, t1 READ; +INSERT INTO t2(i) SELECT i FROM t1; +UNLOCK TABLES; +COMMIT; +include/diff_tables.inc [master:t1, slave:t1] +include/diff_tables.inc [master:t2, slave:t2] +DROP TABLE t1,t2; +CREATE TABLE t1(i int, id INT AUTO_INCREMENT, PRIMARY KEY (i, id)) ENGINE=MYISAM; +INSERT INTO t1 (i) values (1); +START TRANSACTION; +LOCK TABLES t1 WRITE; +INSERT INTO t1 (i) values (2); +UNLOCK TABLES; +COMMIT; +include/diff_tables.inc [master:t1, slave:t1] +DROP TABLE t1; +CREATE TABLE t1(i INT, j INT, UNIQUE KEY(i), UNIQUE KEY(j)) ENGINE=INNODB; +INSERT INTO t1 (i,j) VALUES (1,2) ON DUPLICATE KEY UPDATE j=j+1; +START TRANSACTION; +LOCK TABLES t1 WRITE; +INSERT INTO t1 (i,j) VALUES (1,2) ON DUPLICATE KEY UPDATE j=j+1; +UNLOCK TABLES; +COMMIT; +include/diff_tables.inc [master:t1, slave:t1] +DROP TABLE t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_unsafe_statements.test b/mysql-test/suite/rpl/t/rpl_unsafe_statements.test new file mode 100644 index 00000000000..def8e8f50ec --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_unsafe_statements.test @@ -0,0 +1,175 @@ +################################################################################ +# Bug#17047208 REPLICATION DIFFERENCE FOR MULTIPLE TRIGGERS +# Problem: If DML invokes a trigger or a stored function that inserts into an +# AUTO_INCREMENT column, that DML has to be marked as 'unsafe' statement. If the +# tables are locked in the transaction prior to DML statement (using LOCK +# TABLES), then the DML statement is not marked as 'unsafe' statement. + +# Steps to reproduce the reported test case (BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS) +# Case-1: +# > Create a trigger on a table and do a insert in the trigger that updates +# auto increment column +# > A DML that executes the trigger in step.1 and check that DML is marked +# as unsafe and DML is written into binlog using row format (in MBR) +# > Execute the step 2 by locking the required tables prior to DML and check +# that DML is marked as unsafe and DML is written into binlog using row +# format (in MBR) +# +# This test script also adds test cases to cover few other unsafe statements. +# Case-2: BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT +# Case-3: BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST +# Case-4: BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS +################################################################################ + +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +# Case-1: BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS +# Statement is unsafe because it invokes a trigger or a +# stored function that inserts into an AUTO_INCREMENT column. + +# Step-1.1: Create two tables, one with AUTO_INCREMENT column. +CREATE TABLE t1(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB; +CREATE TABLE t2(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB; + +# Step-1.2: Create a trigger that inserts into an AUTO_INCREMENT column. +CREATE TRIGGER trig1 AFTER INSERT ON t1 +FOR EACH ROW + INSERT INTO t2(i) VALUES(new.i); + +# Step-1.3: Create some gap in auto increment value on master's t2 table +# but not on slave (by doing rollback). Just in case if the unsafe statements +# are written in statement format, diff tables will fail. +START TRANSACTION; +INSERT INTO t2(i) VALUES (1); +ROLLBACK; + +# Step-1.4: Insert a tuple into table t1 that triggers trig1 which inserts +# into an AUTO_INCREMENT column. +INSERT INTO t1(i) VALUES(2); + +# Step-1.5: Repeat step 1.4 but using 'LOCK TABLES' logic. +START TRANSACTION; +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t1(i) VALUES(3); +UNLOCK TABLES; +COMMIT; + +# Step-1.6: Sync slave with master +--sync_slave_with_master + +# Step-1.7: Diff master-slave tables to make sure everything is in sync. +--let $diff_tables=master:t1, slave:t1 +--source include/diff_tables.inc + +--let $diff_tables=master:t2, slave:t2 +--source include/diff_tables.inc + +# Step-1.8: Cleanup +--connection master +DROP TABLE t1,t2; + +# Case-2: BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT +# Statements writing to a table with an auto-increment column after selecting +# from another table are unsafe because the order in which rows are retrieved +# determines what (if any) rows will be written. This order cannot be +# predicted and may differ on master and the slave. + +# Step-2.1: Create two tables, one with AUTO_INCREMENT column. +CREATE TABLE t1(i INT) ENGINE=INNODB; +CREATE TABLE t2(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB; + +# Step-2.2: Create some tuples in table t1. +INSERT INTO t1 values (1), (2), (3); + +# Step-2.3: Create some gap in auto increment value on master's t2 table +# but not on slave (by doing rollback). Just in case if the unsafe statements +# are written in statement format, diff tables will fail. +START TRANSACTION; +INSERT INTO t2(i) VALUES (1); +ROLLBACK; + +# Step-2.4: Insert into t2 (table with an auto-increment) by selecting tuples +# from table t1. +INSERT INTO t2(i) SELECT i FROM t1; + +# Step-2.5: Repeat step 2.4 but now with 'LOCK TABLES' logic. +START TRANSACTION; +LOCK TABLES t2 WRITE, t1 READ; +INSERT INTO t2(i) SELECT i FROM t1; +UNLOCK TABLES; +COMMIT; + +# Step-2.6: Sync slave with master +--sync_slave_with_master + +# Step-2.7: Diff master-slave tables to make sure everything is in sync. +--let $diff_tables=master:t1, slave:t1 +--source include/diff_tables.inc + +--let $diff_tables=master:t2, slave:t2 +--source include/diff_tables.inc + +# Step-2.8: Cleanup +--connection master +DROP TABLE t1,t2; + +# Case-3: BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST +# INSERT into autoincrement field which is not the first part in the +# composed primary key is unsafe +# +# Step-3.1: Create a table with auto increment column and a composed primary key +# (second column is auto increment column). Such a definition is allowed only +# with 'myisam' engine. +CREATE TABLE t1(i int, id INT AUTO_INCREMENT, PRIMARY KEY (i, id)) ENGINE=MYISAM; + +# Step-3.2: Inserting into such a table is unsafe. +INSERT INTO t1 (i) values (1); + +# Step-3.3: Repeat step 3.2, now with 'LOCK TABLES' logic. +START TRANSACTION; +LOCK TABLES t1 WRITE; +INSERT INTO t1 (i) values (2); +UNLOCK TABLES; +COMMIT; + +# Step-3.4: Sync slave with master +--sync_slave_with_master + +# Step-3.5: Diff master-slave tables to make sure everything is in sync. +--let $diff_tables=master:t1, slave:t1 +--source include/diff_tables.inc + +# Step-3.6: Cleanup +--connection master +DROP TABLE t1; + +# Case-4: BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS +# INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY +# is unsafe Statement + +# Step-4.1: Create a table with two unique keys +CREATE TABLE t1(i INT, j INT, UNIQUE KEY(i), UNIQUE KEY(j)) ENGINE=INNODB; + +# Step-4.2: Inserting into such a table is unsafe. +INSERT INTO t1 (i,j) VALUES (1,2) ON DUPLICATE KEY UPDATE j=j+1; + +# Step-4.3: Repeat step 3.2, now with 'LOCK TABLES' logic. +START TRANSACTION; +LOCK TABLES t1 WRITE; +INSERT INTO t1 (i,j) VALUES (1,2) ON DUPLICATE KEY UPDATE j=j+1; +UNLOCK TABLES; +COMMIT; + +# Step-4.4: Sync slave with master +--sync_slave_with_master + +# Step-4.5: Diff master-slave tables to make sure everything is in sync. +--let $diff_tables=master:t1, slave:t1 +--source include/diff_tables.inc + +# Step-4.6: Cleanup +--connection master +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 172987cc1c6..f559974c86b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -212,11 +212,6 @@ static bool check_and_update_table_version(THD *thd, TABLE_LIST *tables, static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry); static bool auto_repair_table(THD *thd, TABLE_LIST *table_list); static void free_cache_entry(TABLE *entry); -static bool -has_write_table_with_auto_increment(TABLE_LIST *tables); -static bool -has_write_table_with_auto_increment_and_select(TABLE_LIST *tables); -static bool has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables); uint cached_open_tables(void) { @@ -5744,63 +5739,6 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, *(ptr++)= table->table; } - /* - DML statements that modify a table with an auto_increment column based on - rows selected from a table are unsafe as the order in which the rows are - fetched fron the select tables cannot be determined and may differ on - master and slave. - */ - if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables && - has_write_table_with_auto_increment_and_select(tables)) - thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT); - /* Todo: merge all has_write_table_auto_inc with decide_logging_format */ - if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables) - { - if (has_write_table_auto_increment_not_first_in_pk(tables)) - thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST); - } - - /* - INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique keys - can be unsafe. - */ - uint unique_keys= 0; - for (TABLE_LIST *query_table= tables; query_table && unique_keys <= 1; - query_table= query_table->next_global) - if(query_table->table) - { - uint keys= query_table->table->s->keys, i= 0; - unique_keys= 0; - for (KEY* keyinfo= query_table->table->s->key_info; - i < keys && unique_keys <= 1; i++, keyinfo++) - { - if (keyinfo->flags & HA_NOSAME) - unique_keys++; - } - if (!query_table->placeholder() && - query_table->lock_type >= TL_WRITE_ALLOW_WRITE && - unique_keys > 1 && thd->lex->sql_command == SQLCOM_INSERT && - /* Duplicate key update is not supported by INSERT DELAYED */ - thd->command != COM_DELAYED_INSERT && - thd->lex->duplicates == DUP_UPDATE) - thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS); - } - - /* We have to emulate LOCK TABLES if we are statement needs prelocking. */ - if (thd->lex->requires_prelocking()) - { - - /* - A query that modifies autoinc column in sub-statement can make the - master and slave inconsistent. - We can solve these problems in mixed mode by switching to binlogging - if at least one updated table is used by sub-statement - */ - if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables && - has_write_table_with_auto_increment(thd->lex->first_not_own_table())) - thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS); - } - DEBUG_SYNC(thd, "before_lock_tables_takes_lock"); if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start), @@ -9170,98 +9108,6 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) return a->length == b->length && !strncmp(a->str, b->str, a->length); } - -/* - Tells if two (or more) tables have auto_increment columns and we want to - lock those tables with a write lock. - - SYNOPSIS - has_two_write_locked_tables_with_auto_increment - tables Table list - - NOTES: - Call this function only when you have established the list of all tables - which you'll want to update (including stored functions, triggers, views - inside your statement). -*/ - -static bool -has_write_table_with_auto_increment(TABLE_LIST *tables) -{ - for (TABLE_LIST *table= tables; table; table= table->next_global) - { - /* we must do preliminary checks as table->table may be NULL */ - if (!table->placeholder() && - table->table->found_next_number_field && - (table->lock_type >= TL_WRITE_ALLOW_WRITE)) - return 1; - } - - return 0; -} - -/* - checks if we have select tables in the table list and write tables - with auto-increment column. - - SYNOPSIS - has_two_write_locked_tables_with_auto_increment_and_select - tables Table list - - RETURN VALUES - - -true if the table list has atleast one table with auto-increment column - - - and atleast one table to select from. - -false otherwise -*/ - -static bool -has_write_table_with_auto_increment_and_select(TABLE_LIST *tables) -{ - bool has_select= false; - bool has_auto_increment_tables = has_write_table_with_auto_increment(tables); - for(TABLE_LIST *table= tables; table; table= table->next_global) - { - if (!table->placeholder() && - (table->lock_type <= TL_READ_NO_INSERT)) - { - has_select= true; - break; - } - } - return(has_select && has_auto_increment_tables); -} - -/* - Tells if there is a table whose auto_increment column is a part - of a compound primary key while is not the first column in - the table definition. - - @param tables Table list - - @return true if the table exists, fais if does not. -*/ - -static bool -has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables) -{ - for (TABLE_LIST *table= tables; table; table= table->next_global) - { - /* we must do preliminary checks as table->table may be NULL */ - if (!table->placeholder() && - table->table->found_next_number_field && - (table->lock_type >= TL_WRITE_ALLOW_WRITE) - && table->table->s->next_number_keypart != 0) - return 1; - } - - return 0; -} - - - /* Open and lock system tables for read. diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c3d2a092fd6..05bb38d8358 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4142,6 +4142,94 @@ void xid_cache_delete(XID_STATE *xid_state) mysql_mutex_unlock(&LOCK_xid_cache); } +/* + Tells if two (or more) tables have auto_increment columns and we want to + lock those tables with a write lock. + + SYNOPSIS + has_two_write_locked_tables_with_auto_increment + tables Table list + + NOTES: + Call this function only when you have established the list of all tables + which you'll want to update (including stored functions, triggers, views + inside your statement). +*/ + +static bool +has_write_table_with_auto_increment(TABLE_LIST *tables) +{ + for (TABLE_LIST *table= tables; table; table= table->next_global) + { + /* we must do preliminary checks as table->table may be NULL */ + if (!table->placeholder() && + table->table->found_next_number_field && + (table->lock_type >= TL_WRITE_ALLOW_WRITE)) + return 1; + } + + return 0; +} + +/* + checks if we have select tables in the table list and write tables + with auto-increment column. + + SYNOPSIS + has_two_write_locked_tables_with_auto_increment_and_select + tables Table list + + RETURN VALUES + + -true if the table list has atleast one table with auto-increment column + + + and atleast one table to select from. + -false otherwise +*/ + +static bool +has_write_table_with_auto_increment_and_select(TABLE_LIST *tables) +{ + bool has_select= false; + bool has_auto_increment_tables = has_write_table_with_auto_increment(tables); + for(TABLE_LIST *table= tables; table; table= table->next_global) + { + if (!table->placeholder() && + (table->lock_type <= TL_READ_NO_INSERT)) + { + has_select= true; + break; + } + } + return(has_select && has_auto_increment_tables); +} + +/* + Tells if there is a table whose auto_increment column is a part + of a compound primary key while is not the first column in + the table definition. + + @param tables Table list + + @return true if the table exists, fais if does not. +*/ + +static bool +has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables) +{ + for (TABLE_LIST *table= tables; table; table= table->next_global) + { + /* we must do preliminary checks as table->table may be NULL */ + if (!table->placeholder() && + table->table->found_next_number_field && + (table->lock_type >= TL_WRITE_ALLOW_WRITE) + && table->table->s->next_number_keypart != 0) + return 1; + } + + return 0; +} /** Decide on logging format to use for the statement and issue errors @@ -4305,6 +4393,31 @@ int THD::decide_logging_format(TABLE_LIST *tables) } #endif + if (variables.binlog_format != BINLOG_FORMAT_ROW && tables) + { + /* + DML statements that modify a table with an auto_increment column based on + rows selected from a table are unsafe as the order in which the rows are + fetched fron the select tables cannot be determined and may differ on + master and slave. + */ + if (has_write_table_with_auto_increment_and_select(tables)) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT); + + if (has_write_table_auto_increment_not_first_in_pk(tables)) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST); + + /* + A query that modifies autoinc column in sub-statement can make the + master and slave inconsistent. + We can solve these problems in mixed mode by switching to binlogging + if at least one updated table is used by sub-statement + */ + if (lex->requires_prelocking() && + has_write_table_with_auto_increment(lex->first_not_own_table())) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS); + } + /* Get the capabilities vector for all involved storage engines and mask out the flags for the binary log. @@ -4343,6 +4456,24 @@ int THD::decide_logging_format(TABLE_LIST *tables) prev_write_table= table->table; + /* + INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique keys + can be unsafe. Check for it if the flag is already not marked for the + given statement. + */ + if (!lex->is_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS) && + lex->sql_command == SQLCOM_INSERT && lex->duplicates == DUP_UPDATE) + { + uint keys= table->table->s->keys, i= 0, unique_keys= 0; + for (KEY* keyinfo= table->table->s->key_info; + i < keys && unique_keys <= 1; i++, keyinfo++) + { + if (keyinfo->flags & HA_NOSAME) + unique_keys++; + } + if (unique_keys > 1 ) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS); + } } flags_access_some_set |= flags; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index c5886b3c142..867997feb39 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2015, 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 @@ -1362,6 +1362,11 @@ public: return get_stmt_unsafe_flags() != 0; } + inline bool is_stmt_unsafe(enum_binlog_stmt_unsafe unsafe) + { + return binlog_stmt_flags & (1 << unsafe); + } + /** Flag the current (top-level) statement as unsafe. The flag will be reset after the statement has finished. From f3554bf148710c73df2a1ca5547ea7ff7c21a969 Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Fri, 20 Nov 2015 05:40:39 +0530 Subject: [PATCH 06/57] Bug #22214867: MYSQL 5.5: MAIN.SUBSELECT AND OTHERS FAIL WITH NEW VALGRIND Issue: ------ Function signature in valgrind.supp requires a change with valgrind 3.11. Static function is replaced with wild card. --- mysql-test/valgrind.supp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 52b59da58cd..72fcd3ef787 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -1,4 +1,4 @@ -# Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2015, 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 Library General Public @@ -881,8 +881,8 @@ # write_keys() and find_all_keys(). # They both return ha_rows, which is platform dependent. # -# The '...' wildcards are for 'fun:inline_mysql_file_write' which *may* -# be inlined. +# The '...' wildcards are for 'fun:inline_mysql_file_write' and +# 'fun:find_all_keys' which *may* be inlined. { Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / one Memcheck:Param @@ -893,7 +893,7 @@ fun:my_b_flush_io_cache fun:_my_b_write fun:_Z*10write_keysP13st_sort_paramPPhjP11st_io_cacheS4_ - fun:_Z*13find_all_keysP13st_sort_paramP10SQL_SELECTPPhP11st_io_cacheS6_ + ... fun:_Z8filesortP3THDP5TABLEP13st_sort_fieldjP10SQL_SELECTybPy } From a7fb5aecfd527c6b9274db02dcec69daf06c97a3 Mon Sep 17 00:00:00 2001 From: Chaithra Gopalareddy Date: Fri, 20 Nov 2015 12:30:15 +0530 Subject: [PATCH 07/57] Bug#19941403: FATAL_SIGNAL(SIG 6) IN BUILD_EQUAL_ITEMS_FOR_COND | IN SQL/SQL_OPTIMIZER.CC:1657 Problem: At the end of first execution select_lex->prep_where is pointing to a runtime created object (temporary table field). As a result server exits trying to access a invalid pointer during second execution. Analysis: While optimizing the join conditions for the query, after the permanent transformation, optimizer makes a copy of the new where conditions in select_lex->prep_where. "prep_where" is what is used as the "where condition" for the query at the start of execution. W.r.t the query in question, "where" condition is actually pointing to a field in the temporary table. As a result, for the second execution the pointer is no more valid resulting in server exit. Fix: At the end of the first execution, select_lex->where will have the original item of the where condition. Make prep_where the new place where the original item of select->where has to be rolled back. Fixed in 5.7 with the wl#7082 - Move permanent transformations from JOIN::optimize to JOIN::prepare Patch for 5.5 includes the following backports from 5.6: Bugfix for Bug12603141 - This makes the first execute statement in the testcase pass in 5.5 However it was noted later in in Bug16163596 that the above bugfix needed to be modified. Although Bug16163596 is reproducible only with changes done for Bug12582849, we have decided include the fix. Considering that Bug12582849 is related to Bug12603141, the fix is also included here. However this results in Bug16317817, Bug16317685, Bug16739050. So fix for the above three bugs is also part of this patch. --- sql/item.cc | 2 +- sql/item.h | 8 +++++++- sql/item_cmpfunc.cc | 5 +++-- sql/item_cmpfunc.h | 10 +++++----- sql/sql_class.cc | 15 +++++++++++++++ sql/sql_class.h | 16 ++++++++++++++++ sql/sql_lex.cc | 23 +++++++++++++++++++++-- sql/sql_select.cc | 19 +++++++++++++++++-- 8 files changed, 85 insertions(+), 13 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index fd590574e56..beb68c5d321 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4684,7 +4684,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) It's not an Item_field in the select list so we must make a new Item_ref to point to the Item in the select list and replace the Item_field created by the parser with the new Item_ref. - + Ex: SELECT func1(col) as c ... ORDER BY func2(c); NOTE: If we are fixing an alias reference inside ORDER/GROUP BY item tree, then we use new Item_ref as an intermediate value to resolve referenced item only. diff --git a/sql/item.h b/sql/item.h index 629f9afa241..831343de7ad 100644 --- a/sql/item.h +++ b/sql/item.h @@ -960,7 +960,13 @@ public: */ virtual void no_rows_in_result() {} virtual Item *copy_or_same(THD *thd) { return this; } - virtual Item *copy_andor_structure(THD *thd) { return this; } + /** + @param real_items True <=> in the copy, replace any Item_ref with its + real_item() + @todo this argument should be always false and removed in WL#7082. + */ + virtual Item *copy_andor_structure(THD *thd, bool real_items= false) + { return real_items ? real_item() : this; } virtual Item *real_item() { return this; } virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index e6cc3272ceb..b302440272e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4303,11 +4303,12 @@ Item_cond::Item_cond(THD *thd, Item_cond *item) } -void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item) +void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item, bool real_items) { List_iterator_fast li(item->list); while (Item *it= li++) - list.push_back(it->copy_andor_structure(thd)); + list.push_back((real_items ? it->real_item() : it)-> + copy_andor_structure(thd, real_items)); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 115d6db300d..00c7bccbfb8 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1514,7 +1514,7 @@ public: friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds); void top_level_item() { abort_on_null=1; } - void copy_andor_arguments(THD *thd, Item_cond *item); + void copy_andor_arguments(THD *thd, Item_cond *item, bool real_items= false); bool walk(Item_processor processor, bool walk_subquery, uchar *arg); Item *transform(Item_transformer transformer, uchar *arg); void traverse_cond(Cond_traverser, void *arg, traverse_order order); @@ -1689,11 +1689,11 @@ public: const char *func_name() const { return "and"; } table_map not_null_tables() const { return abort_on_null ? not_null_tables_cache: and_tables_cache; } - Item* copy_andor_structure(THD *thd) + Item* copy_andor_structure(THD *thd, bool real_items) { Item_cond_and *item; if ((item= new Item_cond_and(thd, this))) - item->copy_andor_arguments(thd, this); + item->copy_andor_arguments(thd, this, real_items); return item; } Item *neg_transformer(THD *thd); @@ -1719,11 +1719,11 @@ public: longlong val_int(); const char *func_name() const { return "or"; } table_map not_null_tables() const { return and_tables_cache; } - Item* copy_andor_structure(THD *thd) + Item* copy_andor_structure(THD *thd, bool real_items) { Item_cond_or *item; if ((item= new Item_cond_or(thd, this))) - item->copy_andor_arguments(thd, this); + item->copy_andor_arguments(thd, this, real_items); return item; } Item *neg_transformer(THD *thd); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 05bb38d8358..629088dd862 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2064,6 +2064,21 @@ struct Item_change_record: public ilink static void operator delete(void *ptr, void *mem) { /* never called */ } }; +void THD::change_item_tree_place(Item **old_ref, Item **new_ref) +{ + I_List_iterator it(change_list); + Item_change_record *change; + while ((change= it++)) + { + if (change->place == old_ref) + { + DBUG_PRINT("info", ("change_item_tree_place old_ref %p new_ref %p", + old_ref, new_ref)); + change->place= new_ref; + break; + } + } +} /* Register an item tree tree transformation, performed by the query diff --git a/sql/sql_class.h b/sql/sql_class.h index 5a5e8b48754..c9900231615 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2515,6 +2515,22 @@ public: nocheck_register_item_tree_change(place, *place, mem_root); *place= new_value; } + + /* + Find and update change record of an underlying item. + + @param old_ref The old place of moved expression. @param new_ref The + new place of moved expression. @details During permanent + transformations, e.g. join flattening in simplify_joins, a condition + could be moved from one place to another, e.g. from on_expr to WHERE + condition. If the moved condition has replaced some other with + change_item_tree() function, the change record will restore old value to + the wrong place during rollback_item_tree_changes. This function goes + through the list of change records, and replaces + Item_change_record::place. + */ + void change_item_tree_place(Item **old_ref, Item **new_ref); + void nocheck_register_item_tree_change(Item **place, Item *old_value, MEM_ROOT *runtime_memroot); void rollback_item_tree_changes(); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 17446778034..50cdabe341a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2015, 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 @@ -3158,7 +3158,26 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds, } if (*conds) { - prep_where= *conds; + /* + In "WHERE outer_field", *conds may be an Item_outer_ref allocated in + the execution memroot. + @todo change this line in WL#7082. Currently, when we execute a SP, + containing "SELECT (SELECT ... WHERE t1.col) FROM t1", + resolution may make *conds equal to an Item_outer_ref, then below + *conds becomes Item_field, which then goes straight on to execution, + undoing the effects of putting Item_outer_ref in the first place... + With a PS the problem is not as severe, as after the code below we + don't go to execution: a next execution will do a new name resolution + which will create Item_outer_ref again. + + To reviewers: in WL#7082, + prep_where= (*conds)->real_item(); + becomes: + prep_where= *conds; + thd->change_item_tree_place(conds, &prep_where); + and same for HAVING. + */ + prep_where= (*conds)->real_item(); *conds= where= prep_where->copy_andor_structure(thd); } if (*having_conds) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 96f60d46651..96271f26b0f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -915,7 +915,22 @@ JOIN::optimize() conds= simplify_joins(this, join_list, conds, TRUE); build_bitmap_for_nested_joins(join_list, 0); - sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0; + /* + After permanent transformations above, prep_where created in + st_select_lex::fix_prepare_information() is out-of-date, we need to + refresh it. + For that We must copy "conds" because it contains AND/OR items in a + non-permanent memroot. And this copy must contain real items only, + because the new AND/OR items will not have their argument pointers + restored by rollback_item_tree_changes(). + @see st_select_lex::fix_prepare_information() for problems with this. + @todo in WL#7082 move transformations above to before + st_select_lex::fix_prepare_information(), and remove this second copy + below. + */ + sel->prep_where= conds ? conds->copy_andor_structure(thd, true) : NULL; + if (conds) + thd->change_item_tree_place(&conds, &select_lex->prep_where); if (arena) thd->restore_active_arena(arena, &backup); @@ -9061,7 +9076,7 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) DBUG_ASSERT(expr); table->on_expr= expr; - table->prep_on_expr= expr->copy_andor_structure(join->thd); + table->prep_on_expr= expr->copy_andor_structure(join->thd, true); } } nested_join->used_tables= (table_map) 0; From 08e929388b2cea170f6a44e9c8669f9c0f636808 Mon Sep 17 00:00:00 2001 From: Venkatesh Duggirala Date: Sat, 21 Nov 2015 11:08:44 +0530 Subject: [PATCH 08/57] Bug #17047208 REPLICATION DIFFERENCE FOR MULTIPLE TRIGGERS Fixing pb2 valgrind failure Missed a 'if condition' check while moving the logic from one place to another place. --- sql/sql_class.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 629088dd862..4711009d7cd 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4477,7 +4477,9 @@ int THD::decide_logging_format(TABLE_LIST *tables) given statement. */ if (!lex->is_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS) && - lex->sql_command == SQLCOM_INSERT && lex->duplicates == DUP_UPDATE) + lex->sql_command == SQLCOM_INSERT && + /* Duplicate key update is not supported by INSERT DELAYED */ + command != COM_DELAYED_INSERT && lex->duplicates == DUP_UPDATE) { uint keys= table->table->s->keys, i= 0, unique_keys= 0; for (KEY* keyinfo= table->table->s->key_info; From 2735f0b92020c8ac4bd07d7ea843a0946b19e8ad Mon Sep 17 00:00:00 2001 From: Venkatesh Duggirala Date: Tue, 1 Dec 2015 15:38:11 +0530 Subject: [PATCH 09/57] Bug#21205695 DROP TABLE MAY CAUSE SLAVES TO BREAK Problem: ======== 1) Drop table queries are re-generated by server before writing the events(queries) into binlog for various reasons. If table name/db name contains a non regular characters (like latin characters), the generated query is wrong. Hence it breaks the replication. 2) In the edge case, when table name/db name contains 64 characters, server is throwing an assert assert(M_TBLLEN < 128) 3) In the edge case, when db name contains 64 latin characters, binlog content is interpreted badly which is leading replication failure. Analysis & Fix : ================ 1) Parser reads the table name from the query and converts it to standard charset(utf8) and stores it in table_name variable. When drop table query is regenerated with the same table_name variable, it should be converted back to the original charset from standard charset(utf8). 2) Latin character takes two bytes for each character. Limit of the identifier is 64. SYSTEM_CHARSET_MBMAXLEN is set to '3'. So there is a possiblity that tablename/dbname contains 3 * 64. Hence assert is changed to (M_TBLLEN <= NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN) 3) db_len in the binlog event header is taking 1 byte. db_len is ranged from 0 to 192 bytes (3 * 64). While reading the db_len from the event, server is casting to uint instead of uchar which is leading to bad db_len. This problem is fixed by changing the cast type to uchar. --- .../rpl_autogen_query_multi_byte_char.result | 29 +++++++ .../t/rpl_autogen_query_multi_byte_char.test | 87 +++++++++++++++++++ sql/log_event.cc | 10 +-- sql/sql_show.cc | 57 +++++++----- sql/sql_show.h | 10 ++- sql/sql_table.cc | 12 ++- 6 files changed, 173 insertions(+), 32 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_autogen_query_multi_byte_char.result create mode 100644 mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test diff --git a/mysql-test/suite/rpl/r/rpl_autogen_query_multi_byte_char.result b/mysql-test/suite/rpl/r/rpl_autogen_query_multi_byte_char.result new file mode 100644 index 00000000000..b03c0057a69 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_autogen_query_multi_byte_char.result @@ -0,0 +1,29 @@ +include/master-slave.inc +[connection master] +Test case 1:- table name with one character latin name. +SET @s:=CONCAT("CREATE TABLE `",REPEAT(CHAR(131),1),"` (a INT)"); +PREPARE STMT FROM @s; +EXECUTE stmt; +SET @s:=CONCAT("INSERT INTO `",REPEAT(CHAR(131),1),"` VALUES (1)"); +PREPARE STMT FROM @s; +EXECUTE stmt; +SET @s:=CONCAT("DROP TABLE `",REPEAT(CHAR(131),1), "`"); +PREPARE STMT FROM @s; +EXECUTE stmt; +Test case 2:- table name and database names with one character latin name. +SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(131),1),"`"); +PREPARE STMT FROM @s; +EXECUTE stmt; +SET @s:=CONCAT("CREATE TABLE `",REPEAT(CHAR(131),1),"`.`",REPEAT(CHAR(131),1),"` (a INT)"); +PREPARE STMT FROM @s; +EXECUTE stmt; +SET @s:=CONCAT("INSERT INTO `",REPEAT(CHAR(131),1),"`.`",REPEAT(CHAR(131),1),"` VALUES (1)"); +PREPARE STMT FROM @s; +EXECUTE stmt; +SET @s:=CONCAT("DROP TABLE `",REPEAT(CHAR(131),1),"`.`",REPEAT(CHAR(131),1), "`"); +PREPARE STMT FROM @s; +EXECUTE stmt; +SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(131),1),"`"); +PREPARE STMT FROM @s; +EXECUTE stmt; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test b/mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test new file mode 100644 index 00000000000..a93fcbac82f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test @@ -0,0 +1,87 @@ +############################################################################### +# Bug#21205695 DROP TABLE MAY CAUSE SLAVES TO BREAK +# +# Problem: +# ======== +# 1) Drop table queries are re-generated by server +# before writing the events(queries) into binlog +# for various reasons. If table name/db name contains +# a non regular characters (like latin characters), +# the generated query is wrong. Hence it breaks the +# replication. +# 2) In the edge case, when table name contains +# 64 latin characters (latin takes 2 bytes), server is +# throwing an assert (M_TBLLEN < 128) +# +# 3) In the edge case, when db name contains 64 latin +# characters, binlog contents are interpreted wrongly +# which is leading to replication issues. +# +############################################################################### + +--source include/not_windows.inc +--source include/master-slave.inc + +--let iter=1 +# Change iteration to 4 after fixing Bug #22280214 +while ($iter <= 2) +{ + --connection master + if ($iter == 1) + { + --echo Test case 1:- table name with one character latin name. + --let $tblname= REPEAT(CHAR(131),1) + } + if ($iter == 2) + { + --echo Test case 2:- table name and database names with one character latin name. + --let $tblname= REPEAT(CHAR(131),1),"`.`",REPEAT(CHAR(131),1) + --eval SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(131),1),"`") + PREPARE STMT FROM @s; EXECUTE stmt; + } + # After fixing Bug #22280214 DATADIR LOCATION IS LIMITING + # IDENTIFIER MAX LENGTH, the following two tests (iter 3 and 4) can be + # uncommented. + #if ($iter == 3) + #{ + # --echo Test case 3:- table name and database names with 64 latin characters name. + # --let $tblname= REPEAT(CHAR(131),64),"`.`", REPEAT(CHAR(131),64) + # --eval SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(131),64),"`") + # PREPARE STMT FROM @s; EXECUTE stmt; + #} + #if ($iter == 4) + #{ + # --echo Test case 4:- table name and database names with 64 Euro(€) characters. + # --let $tblname= REPEAT(CHAR(226,130,172),64),"`.`", REPEAT(CHAR(226,130,172),64) + # --eval SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(226,130,172),64),"`") + # PREPARE STMT FROM @s; EXECUTE stmt; + #} + --eval SET @s:=CONCAT("CREATE TABLE `",$tblname,"` (a INT)") + PREPARE STMT FROM @s; EXECUTE stmt; + --eval SET @s:=CONCAT("INSERT INTO `",$tblname,"` VALUES (1)") + PREPARE STMT FROM @s; EXECUTE stmt; + --eval SET @s:=CONCAT("DROP TABLE `",$tblname, "`") + PREPARE STMT FROM @s; EXECUTE stmt; + if ($iter == 2) + { + --eval SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(131),1),"`") + PREPARE STMT FROM @s; EXECUTE stmt; + } + # After fixing Bug #22280214 DATADIR LOCATION IS LIMITING + # IDENTIFIER MAX LENGTH, the following two tests (iter 3 and 4) can be + # uncommented. + #if ($iter == 3) + #{ + # --eval SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(131),64),"`") + # PREPARE STMT FROM @s; EXECUTE stmt; + #} + #if ($iter == 4) + #{ + # --eval SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(226,130,172),64),"`") + # PREPARE STMT FROM @s; EXECUTE stmt; + #} + --sync_slave_with_master + --inc $iter +} + +--source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index 38efb2a9c6b..accb6a28dbd 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2015, 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 @@ -2792,7 +2792,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, slave_proxy_id= thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET); exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET); - db_len = (uint)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars + db_len = (uchar)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars error_code = uint2korr(buf + Q_ERR_CODE_OFFSET); /* @@ -8960,9 +8960,9 @@ bool Table_map_log_event::write_data_body(IO_CACHE *file) { DBUG_ASSERT(m_dbnam != NULL); DBUG_ASSERT(m_tblnam != NULL); - /* We use only one byte per length for storage in event: */ - DBUG_ASSERT(m_dblen < 128); - DBUG_ASSERT(m_tbllen < 128); + + DBUG_ASSERT(m_dblen <= NAME_LEN); + DBUG_ASSERT(m_tbllen <= NAME_LEN); uchar const dbuf[]= { (uchar) m_dblen }; uchar const tbuf[]= { (uchar) m_tbllen }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5da9f43d793..c936ea69a97 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -949,29 +949,44 @@ static const char *require_quotes(const char *name, uint name_length) } -/* - Quote the given identifier if needed and append it to the target string. - If the given identifier is empty, it will be quoted. - - SYNOPSIS - append_identifier() - thd thread handler - packet target string - name the identifier to be appended - name_length length of the appending identifier +/** + Convert and quote the given identifier if needed and append it to the + target string. If the given identifier is empty, it will be quoted. + @thd thread handler + @packet target string + @name the identifier to be appended + @length length of the appending identifier + @param from_cs Charset information about the input string + @param to_cs Charset information about the target string */ void -append_identifier(THD *thd, String *packet, const char *name, uint length) +append_identifier(THD *thd, String *packet, const char *name, uint length, + CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) { const char *name_end; char quote_char; int q; - q= thd ? get_quote_char_for_identifier(thd, name, length) : '`'; + CHARSET_INFO *cs_info= system_charset_info; + const char *to_name= name; + size_t to_length= length; + String to_string(name,length, from_cs); + + if (from_cs != NULL && to_cs != NULL && from_cs != to_cs) + thd->convert_string(&to_string, from_cs, to_cs); + + if (to_cs != NULL) + { + to_name= to_string.c_ptr(); + to_length= to_string.length(); + cs_info= to_cs; + } + + q= thd ? get_quote_char_for_identifier(thd, to_name, to_length) : '`'; if (q == EOF) { - packet->append(name, length, packet->charset()); + packet->append(to_name, to_length, packet->charset()); return; } @@ -980,14 +995,14 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) it's a keyword */ - (void) packet->reserve(length*2 + 2); + (void) packet->reserve(to_length*2 + 2); quote_char= (char) q; packet->append("e_char, 1, system_charset_info); - for (name_end= name+length ; name < name_end ; name+= length) + for (name_end= to_name+to_length ; to_name < name_end ; to_name+= to_length) { - uchar chr= (uchar) *name; - length= my_mbcharlen(system_charset_info, chr); + uchar chr= (uchar) *to_name; + to_length= my_mbcharlen(cs_info, chr); /* my_mbcharlen can return 0 on a wrong multibyte sequence. It is possible when upgrading from 4.0, @@ -995,11 +1010,11 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) The manual says it does not work. So we'll just change length to 1 not to hang in the endless loop. */ - if (!length) - length= 1; - if (length == 1 && chr == (uchar) quote_char) + if (!to_length) + to_length= 1; + if (to_length == 1 && chr == (uchar) quote_char) packet->append("e_char, 1, system_charset_info); - packet->append(name, length, system_charset_info); + packet->append(to_name, to_length, system_charset_info); } packet->append("e_char, 1, system_charset_info); } diff --git a/sql/sql_show.h b/sql/sql_show.h index 16bfc5cdb69..ad6494fd7d4 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -92,8 +92,14 @@ int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff); int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table); int get_quote_char_for_identifier(THD *thd, const char *name, uint length); -void append_identifier(THD *thd, String *packet, const char *name, - uint length); +void append_identifier(THD *thd, String *packet, const char *name, uint length, + CHARSET_INFO *from_cs, CHARSET_INFO *to_cs); +inline void append_identifier(THD *thd, String *packet, const char *name, + uint length) +{ + append_identifier(thd, packet, name, length, NULL, NULL); +} + void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild); int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd); bool mysqld_show_create(THD *thd, TABLE_LIST *table_list); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 0a58d9ade5b..3f64de7eac2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2138,11 +2138,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, if (thd->db == NULL || strcmp(db,thd->db) != 0 || is_drop_tmp_if_exists_added ) { - append_identifier(thd, built_ptr_query, db, db_len); + append_identifier(thd, built_ptr_query, db, db_len, + system_charset_info, thd->charset()); built_ptr_query->append("."); } append_identifier(thd, built_ptr_query, table->table_name, - strlen(table->table_name)); + strlen(table->table_name), system_charset_info, + thd->charset()); built_ptr_query->append(","); } /* @@ -2204,12 +2206,14 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, */ if (thd->db == NULL || strcmp(db,thd->db) != 0) { - append_identifier(thd, &built_query, db, db_len); + append_identifier(thd, &built_query, db, db_len, + system_charset_info, thd->charset()); built_query.append("."); } append_identifier(thd, &built_query, table->table_name, - strlen(table->table_name)); + strlen(table->table_name), system_charset_info, + thd->charset()); built_query.append(","); } } From c5ba706791910f7ab5d83056abc9e9266891fa46 Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Wed, 16 Dec 2015 10:48:57 +0530 Subject: [PATCH 10/57] Bug#22278455: MYSQL 5.5:RPL_BINLOG_INDEX FAILS IN VALGRIND. Problem: ======= rpl_binlog_index.test fails with following valgrind error. line Conditional jump or move depends on uninitialised value(s) at 0x4C2F842: __memcmp_sse4_1 (in /usr/lib64/valgrind/ vgpreload_memcheck-amd64-linux.so) 0x739E39: find_uniq_filename(char*) (log.cc:2212) 0x73A11B: MYSQL_LOG::generate_new_name(char*, char const*) (log.cc:2492) 0x73A1ED: MYSQL_LOG::init_and_set_log_file_name(char const*, char const*, enum_log_type, cache_type) (log.cc:2289) 0x73B6F5: MYSQL_BIN_LOG::open(char const*, enum_log_type, Analysis and fix: ================= This issue was fixed as part of Bug#20459363 fix in 5.6 and above. Hence backporting the fix to MySQL-5.5. --- sql/log.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index d322abcd742..9e34532f1ac 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2015, 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 @@ -2209,7 +2209,7 @@ static int find_uniq_filename(char *name) file_info= dir_info->dir_entry; for (i= dir_info->number_off_files ; i-- ; file_info++) { - if (memcmp(file_info->name, start, length) == 0 && + if (strncmp(file_info->name, start, length) == 0 && test_if_number(file_info->name+length, &number,0)) { set_if_bigger(max_found,(ulong) number); From 3c9ba967af3e8d2c47e7849760f018dcfc9d4d16 Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Wed, 16 Dec 2015 12:03:04 +0530 Subject: [PATCH 11/57] Bug#22361702 - /USR/BIN/MYSQL-SYSTEMD-START DOES NOT RETURN CONTROL TO COMMAND LINE If the configuration files contains multiple datadir lines, use the last datadir entry in the RPM installation scripts --- packaging/rpm-oel/mysql-systemd-start | 2 +- packaging/rpm-oel/mysql.spec.in | 2 +- packaging/rpm-sles/mysql-systemd-start | 2 +- packaging/rpm-sles/mysql.spec.in | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packaging/rpm-oel/mysql-systemd-start b/packaging/rpm-oel/mysql-systemd-start index 12a1b16db80..fab7b3627b3 100644 --- a/packaging/rpm-oel/mysql-systemd-start +++ b/packaging/rpm-oel/mysql-systemd-start @@ -12,7 +12,7 @@ get_option () { local section=$1 local option=$2 local default=$3 - ret=$(/usr/bin/my_print_defaults $section | grep '^--'${option}'=' | cut -d= -f2-) + ret=$(/usr/bin/my_print_defaults $section | grep '^--'${option}'=' | cut -d= -f2- | tail -n 1) [ -z "$ret" ] && ret=$default echo $ret } diff --git a/packaging/rpm-oel/mysql.spec.in b/packaging/rpm-oel/mysql.spec.in index a76eaa114f8..8a020b05ae6 100644 --- a/packaging/rpm-oel/mysql.spec.in +++ b/packaging/rpm-oel/mysql.spec.in @@ -626,7 +626,7 @@ rm -r $(readlink var) var -c "MySQL Server" -u 27 mysql >/dev/null 2>&1 || : %post server -datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p') +datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p' | tail -n 1) /bin/chmod 0755 "$datadir" /bin/touch /var/log/mysqld.log %if 0%{?systemd} diff --git a/packaging/rpm-sles/mysql-systemd-start b/packaging/rpm-sles/mysql-systemd-start index dc151e0322c..28472249eda 100644 --- a/packaging/rpm-sles/mysql-systemd-start +++ b/packaging/rpm-sles/mysql-systemd-start @@ -10,7 +10,7 @@ install_db () { # Note: something different than datadir=/var/lib/mysql requires SELinux policy changes (in enforcing mode) - datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p') + datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p' | tail -n 1) # Restore log, dir, perms and SELinux contexts [ -d "$datadir" ] || install -d -m 0755 -omysql -gmysql "$datadir" || exit 1 diff --git a/packaging/rpm-sles/mysql.spec.in b/packaging/rpm-sles/mysql.spec.in index cb42dfacf71..91c708a583d 100644 --- a/packaging/rpm-sles/mysql.spec.in +++ b/packaging/rpm-sles/mysql.spec.in @@ -489,7 +489,7 @@ rm -r $(readlink var) var -c "MySQL Server" -u 60 mysql >/dev/null 2>&1 || : %post server -datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p') +datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p' | tail -n 1) /bin/chmod 0755 "$datadir" /bin/touch /var/log/mysql/mysqld.log %if 0%{?systemd} From 1ec594dd60aa3b58e7d1c686016695b5b0bc1aa1 Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Tue, 29 Dec 2015 15:58:44 +0530 Subject: [PATCH 12/57] BUG#21902059: "CREATE TEMPORARY TABLE SELECT ..." AND BIT(1) COLUMNS ANALYSIS: ========= A valgrind error is reported when CREATE TABLE .. SELECT involving BIT columns triggers a column type redefinition. In general the pack_flag is set for BIT columns in 'mysql_prepare_create_table()'. However, during the above operation, redefined column types was handled after the special handling for BIT columns and thus pack_flag ended up not being set correctly triggering the valgrind error. FIX: ==== The patch fixes this problem by setting pack_flag correctly for BIT columns in the case of column type redefinition. --- sql/sql_table.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3f64de7eac2..7b4d08613cf 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3081,8 +3081,31 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, else { /* Field redefined */ + + /* + If we are replacing a BIT field, revert the increment + of total_uneven_bit_length that was done above. + */ + if (sql_field->sql_type == MYSQL_TYPE_BIT && + file->ha_table_flags() & HA_CAN_BIT_FIELD) + total_uneven_bit_length-= sql_field->length & 7; + sql_field->def= dup_field->def; sql_field->sql_type= dup_field->sql_type; + + /* + If we are replacing a field with a BIT field, we need + to initialize pack_flag. Note that we do not need to + increment total_uneven_bit_length here as this dup_field + has already been processed. + */ + if (sql_field->sql_type == MYSQL_TYPE_BIT) + { + sql_field->pack_flag= FIELDFLAG_NUMBER; + if (!(file->ha_table_flags() & HA_CAN_BIT_FIELD)) + sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; + } + sql_field->charset= (dup_field->charset ? dup_field->charset : create_info->default_table_charset); From cb15cce746db6c32cb62c70bd356b2db61267fd9 Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Thu, 31 Dec 2015 07:31:12 +0530 Subject: [PATCH 13/57] Bug #21564557: INCONSISTENT OUTPUT FROM 5.5 AND 5.6 UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%M" Issue: ----- When an invalid date is supplied to the UNIX_TIMESTAMP function from STR_TO_DATE, no check is performed before converting it to a timestamp value. SOLUTION: --------- Add the check_date function and only if it succeeds, proceed to the timestamp conversion. No warning will be returned for dates having zero in month/date, since partial dates are allowed. UNIX_TIMESTAMP will return only a zero for such values. The problem has been handled in 5.6+ with WL#946. --- mysql-test/r/func_time.result | 31 +++++++++++++++++++++++++++++++ mysql-test/t/func_time.test | 18 ++++++++++++++++++ sql/item_timefunc.cc | 13 +++++++++---- sql/sql_time.h | 7 ++++++- 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 7f3ecc0d602..2db5711a4b9 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -1672,3 +1672,34 @@ insert into t1 values ('00:00:00'),('00:01:00'); select 1 from t1 where 1 < some (select cast(a as datetime) from t1); 1 drop table t1; +# +# Bug #21564557: INCONSISTENT OUTPUT FROM 5.5 AND 5.6 +# UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%M" +# +SELECT UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m")); +UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m")) +0 +SELECT UNIX_TIMESTAMP('2015-06-00'); +UNIX_TIMESTAMP('2015-06-00') +0 +SELECT UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s')); +UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s')) +0 +set sql_mode= 'TRADITIONAL'; +SELECT @@sql_mode; +@@sql_mode +STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION +SELECT UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m")); +UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m")) +NULL +Warnings: +Warning 1411 Incorrect datetime value: '201506' for function str_to_date +SELECT UNIX_TIMESTAMP('2015-06-00'); +UNIX_TIMESTAMP('2015-06-00') +0 +SELECT UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s')); +UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s')) +NULL +Warnings: +Warning 1411 Incorrect datetime value: '0000-00-00 10:30:30' for function str_to_date +set sql_mode= default; diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index b6c70485dbc..3abfdc616ff 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -1026,3 +1026,21 @@ create table t1(a time); insert into t1 values ('00:00:00'),('00:01:00'); select 1 from t1 where 1 < some (select cast(a as datetime) from t1); drop table t1; + +--echo # +--echo # Bug #21564557: INCONSISTENT OUTPUT FROM 5.5 AND 5.6 +--echo # UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%M" +--echo # + +SELECT UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m")); +SELECT UNIX_TIMESTAMP('2015-06-00'); +SELECT UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s')); + +set sql_mode= 'TRADITIONAL'; +SELECT @@sql_mode; + +SELECT UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m")); +SELECT UNIX_TIMESTAMP('2015-06-00'); +SELECT UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s')); + +set sql_mode= default; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 840c8e55efe..00145540e6d 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2015, 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 @@ -1378,7 +1378,7 @@ longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp) longlong Item_func_unix_timestamp::val_int() { MYSQL_TIME ltime; - my_bool not_used; + my_bool not_used= 0; DBUG_ASSERT(fixed == 1); if (arg_count == 0) @@ -1390,7 +1390,7 @@ longlong Item_func_unix_timestamp::val_int() return ((Field_timestamp*) field)->get_timestamp(&null_value); } - if (get_arg0_date(<ime, 0)) + if (get_arg0_date(<ime, TIME_FUZZY_DATE)) { /* We have to set null_value again because get_arg0_date will also set it @@ -1400,7 +1400,11 @@ longlong Item_func_unix_timestamp::val_int() null_value= args[0]->null_value; return 0; } - + + int dummy= 0; + if (check_date(<ime, non_zero_date(<ime), TIME_NO_ZERO_IN_DATE, &dummy)) + return 0; + return (longlong) TIME_to_timestamp(current_thd, <ime, ¬_used); } @@ -3482,6 +3486,7 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date) String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val; String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format; + fuzzy_date|= sql_mode; val= args[0]->val_str(&val_string); format= args[1]->val_str(&format_str); if (args[0]->null_value || args[1]->null_value) diff --git a/sql/sql_time.h b/sql/sql_time.h index 0418a0e9621..3e3cd693613 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2015, 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 @@ -91,6 +91,11 @@ inline bool parse_date_time_format(timestamp_type format_type, date_time_format); } +static inline bool +non_zero_date(const MYSQL_TIME *ltime) +{ + return ltime->year || ltime->month || ltime->day; +} extern DATE_TIME_FORMAT global_date_format; extern DATE_TIME_FORMAT global_datetime_format; From 8c65e082f397a34cf393cfc6019daaa303ef5151 Mon Sep 17 00:00:00 2001 From: V S Murthy Sidagam Date: Mon, 4 Jan 2016 15:31:45 +0530 Subject: [PATCH 14/57] Description: yaSSL was only handling the cases of zero or one leading zeros for the key agreement instead of potentially any number. There is about 1 in 50,000 connections to fail when using DHE cipher suites. The second problem was the case where a server would send a public value shorter than the prime value, causing about 1 in 128 client connections to fail, and also caused the yaSSL client to read off the end of memory. All client side DHE cipher suite users should update. Note: The patch is received from YaSSL people --- extra/yassl/README | 11 +++++++++++ extra/yassl/include/crypto_wrapper.hpp | 1 + extra/yassl/include/openssl/ssl.h | 2 +- extra/yassl/src/crypto_wrapper.cpp | 11 ++++++++--- extra/yassl/src/yassl_imp.cpp | 15 ++++----------- extra/yassl/src/yassl_int.cpp | 15 +++++++++++++++ 6 files changed, 40 insertions(+), 15 deletions(-) diff --git a/extra/yassl/README b/extra/yassl/README index bf0e1c9f40f..81d573d0b20 100644 --- a/extra/yassl/README +++ b/extra/yassl/README @@ -12,6 +12,17 @@ before calling SSL_new(); *** end Note *** +yaSSL Release notes, version 2.3.9 (12/01/2015) + This release of yaSSL fixes two client side Diffie-Hellman problems. + yaSSL was only handling the cases of zero or one leading zeros for the key + agreement instead of potentially any number. This caused about 1 in 50,000 + connections to fail when using DHE cipher suites. The second problem was + the case where a server would send a public value shorter than the prime + value, causing about 1 in 128 client connections to fail, and also + caused the yaSSL client to read off the end of memory. All client side + DHE cipher suite users should update. + Thanks to Adam Langely (agl@imperialviolet.org) for the detailed report! + yaSSL Release notes, version 2.3.8 (9/17/2015) This release of yaSSL fixes a high security vulnerability. All users SHOULD update. If using yaSSL for TLS on the server side with private diff --git a/extra/yassl/include/crypto_wrapper.hpp b/extra/yassl/include/crypto_wrapper.hpp index b09b662c88c..0472b304679 100644 --- a/extra/yassl/include/crypto_wrapper.hpp +++ b/extra/yassl/include/crypto_wrapper.hpp @@ -378,6 +378,7 @@ public: uint get_agreedKeyLength() const; const byte* get_agreedKey() const; + uint get_publicKeyLength() const; const byte* get_publicKey() const; void makeAgreement(const byte*, unsigned int); diff --git a/extra/yassl/include/openssl/ssl.h b/extra/yassl/include/openssl/ssl.h index b0a7592f870..095b3c6aa80 100644 --- a/extra/yassl/include/openssl/ssl.h +++ b/extra/yassl/include/openssl/ssl.h @@ -35,7 +35,7 @@ #include "rsa.h" -#define YASSL_VERSION "2.3.8" +#define YASSL_VERSION "2.3.9" #if defined(__cplusplus) diff --git a/extra/yassl/src/crypto_wrapper.cpp b/extra/yassl/src/crypto_wrapper.cpp index 3f819ee2349..95065932c5f 100644 --- a/extra/yassl/src/crypto_wrapper.cpp +++ b/extra/yassl/src/crypto_wrapper.cpp @@ -751,9 +751,10 @@ struct DiffieHellman::DHImpl { byte* publicKey_; byte* privateKey_; byte* agreedKey_; + uint pubKeyLength_; DHImpl(TaoCrypt::RandomNumberGenerator& r) : ranPool_(r), publicKey_(0), - privateKey_(0), agreedKey_(0) {} + privateKey_(0), agreedKey_(0), pubKeyLength_(0) {} ~DHImpl() { ysArrayDelete(agreedKey_); @@ -762,7 +763,7 @@ struct DiffieHellman::DHImpl { } DHImpl(const DHImpl& that) : dh_(that.dh_), ranPool_(that.ranPool_), - publicKey_(0), privateKey_(0), agreedKey_(0) + publicKey_(0), privateKey_(0), agreedKey_(0), pubKeyLength_(0) { uint length = dh_.GetByteLength(); AllocKeys(length, length, length); @@ -810,7 +811,7 @@ DiffieHellman::DiffieHellman(const byte* p, unsigned int pSz, const byte* g, using TaoCrypt::Integer; pimpl_->dh_.Initialize(Integer(p, pSz).Ref(), Integer(g, gSz).Ref()); - pimpl_->publicKey_ = NEW_YS opaque[pubSz]; + pimpl_->publicKey_ = NEW_YS opaque[pimpl_->pubKeyLength_ = pubSz]; memcpy(pimpl_->publicKey_, pub, pubSz); } @@ -869,6 +870,10 @@ const byte* DiffieHellman::get_agreedKey() const return pimpl_->agreedKey_; } +uint DiffieHellman::get_publicKeyLength() const +{ + return pimpl_->pubKeyLength_; +} const byte* DiffieHellman::get_publicKey() const { diff --git a/extra/yassl/src/yassl_imp.cpp b/extra/yassl/src/yassl_imp.cpp index 1baa5adedf8..f190761604d 100644 --- a/extra/yassl/src/yassl_imp.cpp +++ b/extra/yassl/src/yassl_imp.cpp @@ -109,15 +109,12 @@ void ClientDiffieHellmanPublic::build(SSL& ssl) uint keyLength = dhClient.get_agreedKeyLength(); // pub and agree same alloc(keyLength, true); - dhClient.makeAgreement(dhServer.get_publicKey(), keyLength); + dhClient.makeAgreement(dhServer.get_publicKey(), + dhServer.get_publicKeyLength()); c16toa(keyLength, Yc_); memcpy(Yc_ + KEY_OFFSET, dhClient.get_publicKey(), keyLength); - // because of encoding first byte might be zero, don't use it for preMaster - if (*dhClient.get_agreedKey() == 0) - ssl.set_preMaster(dhClient.get_agreedKey() + 1, keyLength - 1); - else - ssl.set_preMaster(dhClient.get_agreedKey(), keyLength); + ssl.set_preMaster(dhClient.get_agreedKey(), keyLength); } @@ -321,11 +318,7 @@ void ClientDiffieHellmanPublic::read(SSL& ssl, input_buffer& input) } dh.makeAgreement(Yc_, keyLength); - // because of encoding, first byte might be 0, don't use for preMaster - if (*dh.get_agreedKey() == 0) - ssl.set_preMaster(dh.get_agreedKey() + 1, dh.get_agreedKeyLength() - 1); - else - ssl.set_preMaster(dh.get_agreedKey(), dh.get_agreedKeyLength()); + ssl.set_preMaster(dh.get_agreedKey(), dh.get_agreedKeyLength()); ssl.makeMasterSecret(); } diff --git a/extra/yassl/src/yassl_int.cpp b/extra/yassl/src/yassl_int.cpp index c04c5a53352..19ba6386efd 100644 --- a/extra/yassl/src/yassl_int.cpp +++ b/extra/yassl/src/yassl_int.cpp @@ -807,6 +807,19 @@ void SSL::set_random(const opaque* random, ConnectionEnd sender) // store client pre master secret void SSL::set_preMaster(const opaque* pre, uint sz) { + uint i(0); // trim leading zeros + uint fullSz(sz); + + while (i++ < fullSz && *pre == 0) { + sz--; + pre++; + } + + if (sz == 0) { + SetError(bad_input); + return; + } + secure_.use_connection().AllocPreSecret(sz); memcpy(secure_.use_connection().pre_master_secret_, pre, sz); } @@ -924,6 +937,8 @@ void SSL::order_error() // Create and store the master secret see page 32, 6.1 void SSL::makeMasterSecret() { + if (GetError()) return; + if (isTLS()) makeTLSMasterSecret(); else { From 3d1306f7b74077cfa197c8fa23baeb96c535af67 Mon Sep 17 00:00:00 2001 From: Ajo Robert Date: Thu, 7 Jan 2016 14:36:19 +0530 Subject: [PATCH 15/57] Bug#21770366 backport bug#21657078 to 5.5 and 5.6 Problem Statement ========= Fix various issues when building MySQL with Visual Studio 2015. Fix: ======= - Visual Studio 2015 adds support for timespec. Add check and related code to use this and only use our replacement if timespec is not defined. - Rename lfind/lsearch to my* to avoid redefinition problems. - Set default value for TMPDIR to "" on Windows as P_tmpdir no longer exists. - using VS definition of snprintf if available - tzname are now renamed to _tzname. --- CMakeLists.txt | 15 +++++++++++---- cmake/os/Windows.cmake | 4 +++- cmake/os/WindowsCache.cmake | 5 ++--- config.h.cmake | 4 +++- configure.cmake | 5 +++-- include/my_pthread.h | 12 ++++-------- mysys/lf_hash.c | 22 +++++++++++----------- mysys/my_wincond.c | 14 +++++++++++++- plugin/semisync/semisync_master.cc | 7 +++---- 9 files changed, 53 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 586119b2ffb..1abfa95f8b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2016, 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 @@ -328,9 +328,16 @@ IF(SYSCONFDIR) SET(DEFAULT_SYSCONFDIR "${SYSCONFDIR}") ENDIF() -SET(TMPDIR "P_tmpdir" - CACHE PATH - "PATH to MySQL TMP dir. Defaults to the P_tmpdir macro in ") +IF(WIN32) # P_tmpdir is not defined on Windows as of VS2015. + SET(TMPDIR "" # So we use empty path as default. In practice TMP/TEMP is used + CACHE PATH + "PATH to MySQL TMP dir") +ELSE() + SET(TMPDIR "P_tmpdir" + CACHE PATH + "PATH to MySQL TMP dir. Defaults to the P_tmpdir macro in ") +ENDIF() + IF(TMPDIR STREQUAL "P_tmpdir") # Do not quote it, to refer to the P_tmpdir macro. SET(DEFAULT_TMPDIR "P_tmpdir") diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index 98158ca806b..1b79970a830 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2016, 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 @@ -185,6 +185,8 @@ CHECK_SYMBOL_REPLACEMENT(SIGQUIT SIGTERM signal.h) CHECK_SYMBOL_REPLACEMENT(SIGPIPE SIGINT signal.h) CHECK_SYMBOL_REPLACEMENT(isnan _isnan float.h) CHECK_SYMBOL_REPLACEMENT(finite _finite float.h) +CHECK_SYMBOL_REPLACEMENT(tzname _tzname time.h) +CHECK_SYMBOL_REPLACEMENT(snprintf _snprintf stdio.h) CHECK_FUNCTION_REPLACEMENT(popen _popen) CHECK_FUNCTION_REPLACEMENT(pclose _pclose) CHECK_FUNCTION_REPLACEMENT(access _access) diff --git a/cmake/os/WindowsCache.cmake b/cmake/os/WindowsCache.cmake index bbed14556b9..1b5a2cedfd5 100644 --- a/cmake/os/WindowsCache.cmake +++ b/cmake/os/WindowsCache.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2016, 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 @@ -227,7 +227,6 @@ SET(HAVE_SIZEOF_ULONG FALSE CACHE INTERNAL "") SET(HAVE_SIZEOF_U_INT32_T FALSE CACHE INTERNAL "") SET(HAVE_SIZE_OF_SSIZE_T FALSE CACHE INTERNAL "") SET(HAVE_SLEEP CACHE INTERNAL "") -SET(HAVE_SNPRINTF CACHE INTERNAL "") SET(HAVE_SOCKADDR_STORAGE_SS_FAMILY 1 CACHE INTERNAL "") SET(HAVE_SOLARIS_STYLE_GETHOST CACHE INTERNAL "") SET(STACK_DIRECTION -1 CACHE INTERNAL "") @@ -301,7 +300,7 @@ SET(HAVE_TIME 1 CACHE INTERNAL "") SET(HAVE_TIMES CACHE INTERNAL "") SET(HAVE_TIMESPEC_TS_SEC CACHE INTERNAL "") SET(HAVE_TIME_H 1 CACHE INTERNAL "") -SET(HAVE_TZNAME 1 CACHE INTERNAL "") +SET(HAVE__tzname 1 CACHE INTERNAL "") SET(HAVE_UNISTD_H CACHE INTERNAL "") SET(HAVE_UTIME_H CACHE INTERNAL "") SET(HAVE_VALLOC CACHE INTERNAL "") diff --git a/config.h.cmake b/config.h.cmake index 8c93da072fb..4548d0a221f 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2009, 2016, 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 @@ -376,6 +376,7 @@ #cmakedefine HAVE_UINT64 1 #cmakedefine SIZEOF_BOOL @SIZEOF_BOOL@ #cmakedefine HAVE_BOOL 1 +#cmakedefine HAVE_STRUCT_TIMESPEC #cmakedefine SOCKET_SIZE_TYPE @SOCKET_SIZE_TYPE@ @@ -497,6 +498,7 @@ #cmakedefine strtok_r @strtok_r@ #cmakedefine strtoll @strtoll@ #cmakedefine strtoull @strtoull@ +#cmakedefine tzname @tzname@ #cmakedefine vsnprintf @vsnprintf@ #if (_MSC_VER > 1310) # define HAVE_SETENV diff --git a/configure.cmake b/configure.cmake index 28974a84c49..f90d36a01e4 100644 --- a/configure.cmake +++ b/configure.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2016, 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 @@ -561,7 +561,7 @@ MY_CHECK_TYPE_SIZE(char CHAR) MY_CHECK_TYPE_SIZE(short SHORT) MY_CHECK_TYPE_SIZE(int INT) MY_CHECK_TYPE_SIZE("long long" LONG_LONG) -SET(CMAKE_EXTRA_INCLUDE_FILES stdio.h sys/types.h) +SET(CMAKE_EXTRA_INCLUDE_FILES stdio.h sys/types.h time.h) MY_CHECK_TYPE_SIZE(off_t OFF_T) MY_CHECK_TYPE_SIZE(uchar UCHAR) MY_CHECK_TYPE_SIZE(uint UINT) @@ -576,6 +576,7 @@ MY_CHECK_TYPE_SIZE(u_int32_t U_INT32_T) MY_CHECK_TYPE_SIZE(int64 INT64) MY_CHECK_TYPE_SIZE(uint64 UINT64) MY_CHECK_TYPE_SIZE(time_t TIME_T) +MY_CHECK_TYPE_SIZE("struct timespec" STRUCT_TIMESPEC) SET (CMAKE_EXTRA_INCLUDE_FILES sys/types.h) MY_CHECK_TYPE_SIZE(bool BOOL) SET(CMAKE_EXTRA_INCLUDE_FILES) diff --git a/include/my_pthread.h b/include/my_pthread.h index 92676bd727c..6ff198ac6f3 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, 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 @@ -90,6 +90,7 @@ typedef volatile LONG my_pthread_once_t; windows implementation of pthread_cond_timedwait */ +#ifndef HAVE_STRUCT_TIMESPEC /* Declare a union to make sure FILETIME is properly aligned so it can be used directly as a 64 bit value. The value @@ -128,6 +129,7 @@ struct timespec { ((TS1.tv.i64 > TS2.tv.i64) ? 1 : \ ((TS1.tv.i64 < TS2.tv.i64) ? -1 : 0)) +#endif int win_pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_create(pthread_t *, const pthread_attr_t *, pthread_handler, void *); @@ -433,13 +435,7 @@ int my_pthread_mutex_trylock(pthread_mutex_t *mutex); #endif /* !set_timespec_nsec */ #else #ifndef set_timespec -#define set_timespec(ABSTIME,SEC) \ -{\ - struct timeval tv;\ - gettimeofday(&tv,0);\ - (ABSTIME).tv_sec=tv.tv_sec+(time_t) (SEC);\ - (ABSTIME).tv_nsec=tv.tv_usec*1000;\ -} +#define set_timespec(ABSTIME,SEC) set_timespec_nsec((ABSTIME),(SEC)*1000000000ULL) #endif /* !set_timespec */ #ifndef set_timespec_nsec #define set_timespec_nsec(ABSTIME,NSEC) \ diff --git a/mysys/lf_hash.c b/mysys/lf_hash.c index 4f0a3a32d86..dc019b07bd9 100644 --- a/mysys/lf_hash.c +++ b/mysys/lf_hash.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2016, 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 @@ -43,7 +43,7 @@ typedef struct { /* a structure to pass the context (pointers two the three successive elements - in a list) from lfind to linsert/ldelete + in a list) from my_lfind to linsert/ldelete */ typedef struct { intptr volatile *prev; @@ -70,7 +70,7 @@ typedef struct { cursor is positioned in either case pins[0..2] are used, they are NOT removed on return */ -static int lfind(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, +static int my_lfind(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, const uchar *key, uint keylen, CURSOR *cursor, LF_PINS *pins) { uint32 cur_hashnr; @@ -138,7 +138,7 @@ retry: /* DESCRIPTION insert a 'node' in the list that starts from 'head' in the correct - position (as found by lfind) + position (as found by my_lfind) RETURN 0 - inserted @@ -156,7 +156,7 @@ static LF_SLIST *linsert(LF_SLIST * volatile *head, CHARSET_INFO *cs, for (;;) { - if (lfind(head, cs, node->hashnr, node->key, node->keylen, + if (my_lfind(head, cs, node->hashnr, node->key, node->keylen, &cursor, pins) && (flags & LF_HASH_UNIQUE)) { @@ -207,7 +207,7 @@ static int ldelete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, for (;;) { - if (!lfind(head, cs, hashnr, key, keylen, &cursor, pins)) + if (!my_lfind(head, cs, hashnr, key, keylen, &cursor, pins)) { res= 1; /* not found */ break; @@ -231,7 +231,7 @@ static int ldelete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, (to ensure the number of "set DELETED flag" actions is equal to the number of "remove from the list" actions) */ - lfind(head, cs, hashnr, key, keylen, &cursor, pins); + my_lfind(head, cs, hashnr, key, keylen, &cursor, pins); } res= 0; break; @@ -257,12 +257,12 @@ static int ldelete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, it uses pins[0..2], on return the pin[2] keeps the node found all other pins are removed. */ -static LF_SLIST *lsearch(LF_SLIST * volatile *head, CHARSET_INFO *cs, +static LF_SLIST *my_lsearch(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, const uchar *key, uint keylen, LF_PINS *pins) { CURSOR cursor; - int res= lfind(head, cs, hashnr, key, keylen, &cursor, pins); + int res= my_lfind(head, cs, hashnr, key, keylen, &cursor, pins); if (res) _lf_pin(pins, 2, cursor.curr); _lf_unpin(pins, 0); @@ -443,7 +443,7 @@ int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) MY_ERRPTR if OOM NOTE - see lsearch() for pin usage notes + see my_lsearch() for pin usage notes */ void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) { @@ -457,7 +457,7 @@ void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) return MY_ERRPTR; if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins))) return MY_ERRPTR; - found= lsearch(el, hash->charset, my_reverse_bits(hashnr) | 1, + found= my_lsearch(el, hash->charset, my_reverse_bits(hashnr) | 1, (uchar *)key, keylen, pins); lf_rwunlock_by_pins(pins); return found ? found+1 : 0; diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c index ac0166c87b8..567721baf27 100644 --- a/mysys/my_wincond.c +++ b/mysys/my_wincond.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, 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 @@ -88,6 +88,7 @@ static void check_native_cond_availability(void) static DWORD get_milliseconds(const struct timespec *abstime) { +#ifndef HAVE_STRUCT_TIMESPEC long long millis; union ft64 now; @@ -118,6 +119,17 @@ static DWORD get_milliseconds(const struct timespec *abstime) millis= UINT_MAX; return (DWORD)millis; +#else + /* + Convert timespec to millis and subtract current time. + my_getsystime() returns time in 100 ns units. + */ + if (abstime == NULL) + return INFINITE; + + return (DWORD)(abstime->tv_sec * 1000 + abstime->tv_nsec / 1000000 - + my_getsystime() / 10000); +#endif } diff --git a/plugin/semisync/semisync_master.cc b/plugin/semisync/semisync_master.cc index 2e40fc8b5c5..40d577e4372 100644 --- a/plugin/semisync/semisync_master.cc +++ b/plugin/semisync/semisync_master.cc @@ -1,6 +1,5 @@ /* Copyright (C) 2007 Google Inc. - Copyright (c) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. - Use is subject to license terms. + Copyright (c) 2008, 2016, 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 @@ -48,7 +47,7 @@ static int getWaitTime(const struct timespec& start_ts); static unsigned long long timespec_to_usec(const struct timespec *ts) { -#ifndef __WIN__ +#ifdef HAVE_STRUCT_TIMESPEC return (unsigned long long) ts->tv_sec * TIME_MILLION + ts->tv_nsec / TIME_THOUSAND; #else return ts->tv.i64 / 10; @@ -683,7 +682,7 @@ int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name, } /* Calcuate the waiting period. */ -#ifdef __WIN__ +#ifndef HAVE_STRUCT_TIMESPEC abstime.tv.i64 = start_ts.tv.i64 + (__int64)wait_timeout_ * TIME_THOUSAND * 10; abstime.max_timeout_msec= (long)wait_timeout_; #else From 863f7cebd79e76f90bd8f1e3e0c1a1de5fe77d07 Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Fri, 8 Jan 2016 06:46:59 +0530 Subject: [PATCH 16/57] Bug #22232332: SAVING TEXT FIELD TO TEXT VARIABLE IN A PROCEDURE RESULTS IN GARBAGE BYTES Issue: ----- This problem occurs under the following conditions: a) Stored procedure has a variable is declared as TEXT/BLOB. b) Data is copied into the the variable using the SELECT...INTO syntax from a TEXT/BLOB column. Data corruption can occur in such cases. SOLUTION: --------- The blob type does not allocate space for the string to be stored. Instead it contains a pointer to the source string. Since the source is deallocated immediately after the select statement, this can cause data corruption. As part of the fix for Bug #21143080, when the source was part of the table's write-set, blob would allocate the neccessary space. But this fix missed the possibility that, as in the above case, the target might be a variable. The fix will add the copy_blobs check that was removed by the earlier fix. --- sql/field_conv.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 7eb49b9dd92..d98f19c3e01 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, 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 @@ -826,7 +826,12 @@ int field_conv(Field *to,Field *from) Field_blob *blob=(Field_blob*) to; from->val_str(&blob->value); - if (!blob->value.is_alloced() && from->is_updatable()) + /* + Copy value if copy_blobs is set, or source is part of the table's + writeset. + */ + if (to->table->copy_blobs || + (!blob->value.is_alloced() && from->is_updatable())) blob->value.copy(); return blob->store(blob->value.ptr(),blob->value.length(),from->charset()); From 13380bf81f6bc20d39549f531f9acebdfb5a8c37 Mon Sep 17 00:00:00 2001 From: Yashwant Sahu Date: Mon, 11 Jan 2016 07:09:13 +0530 Subject: [PATCH 17/57] Bug #22295186: CERTIFICATE VALIDATION BUG IN MYSQL MAY ALLOW MITM --- mysql-test/std_data/ca-cert-verify.pem | 20 +++++ .../std_data/server-cert-verify-fail.pem | 19 ++++ .../std_data/server-cert-verify-pass.pem | 19 ++++ .../std_data/server-key-verify-fail.pem | 27 ++++++ .../std_data/server-key-verify-pass.pem | 27 ++++++ .../suite/auth_sec/r/cert_verify.result | 5 ++ mysql-test/suite/auth_sec/t/cert_verify.test | 49 ++++++++++ sql-common/client.c | 90 +++++++++++++------ 8 files changed, 230 insertions(+), 26 deletions(-) create mode 100644 mysql-test/std_data/ca-cert-verify.pem create mode 100644 mysql-test/std_data/server-cert-verify-fail.pem create mode 100644 mysql-test/std_data/server-cert-verify-pass.pem create mode 100644 mysql-test/std_data/server-key-verify-fail.pem create mode 100644 mysql-test/std_data/server-key-verify-pass.pem create mode 100644 mysql-test/suite/auth_sec/r/cert_verify.result create mode 100644 mysql-test/suite/auth_sec/t/cert_verify.test diff --git a/mysql-test/std_data/ca-cert-verify.pem b/mysql-test/std_data/ca-cert-verify.pem new file mode 100644 index 00000000000..21d6264a0ad --- /dev/null +++ b/mysql-test/std_data/ca-cert-verify.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDWzCCAkOgAwIBAgIJAO/QdKLEDQdXMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNV +BAYTAklOMREwDwYDVQQIDAhLYXJuYXRrYTESMBAGA1UEBwwJQmFuZ2Fsb3JlMQ4w +DAYDVQQKDAVNeVNRTDAeFw0xNjAxMDUxMDA1MDhaFw0yNTExMTMxMDA1MDhaMEQx +CzAJBgNVBAYTAklOMREwDwYDVQQIDAhLYXJuYXRrYTESMBAGA1UEBwwJQmFuZ2Fs +b3JlMQ4wDAYDVQQKDAVNeVNRTDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAKdOCuS2CzfBTJ2x8SAzY0J7cYJfNJvMDF1cvANnhkIhtnkWt/HZ5DJ9NxeX +q5h7FJLAi4gddqdk/tvQJw0V6gZepJr/mKVnMPivF5+oHPc9ZJQMX6B3FBNwWylm +ACd5GKx8I/H/MXyuhQTcoV//Ab+2pI8RHeYbBsm3lHH+tX7bRU6mUFjneqMpiCkb +JHt6BWZiWR10O6pMuGQ9+dDdsLhEV1fj3CctEPwW6rs4IZzD8xl5n+8cy7qu6eYH +Wt/snwsTzkrufeMRqTtqelxON9eoQwYOR1oH3vNEVlcbuoJAvaWOqBROUBdf12SP +TYSdP9nlRh7lTKQOywN4kYt6LqUCAwEAAaNQME4wHQYDVR0OBBYEFJ4c9tKaUU0P +EjBq5G207jjXI7RAMB8GA1UdIwQYMBaAFJ4c9tKaUU0PEjBq5G207jjXI7RAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABRnUyj21oFi0SGJg/K5+8Lc +4n6OwVU/NgLOysIB0baIP/Rqeaze59xG/v9FPQgBlWcJK3RabOywx5bxAxdcus+1 +yp5j4h37Qq1/qkgqmevvdSAPa0OBQbLb+58/naV+ywUpCYZ6flLdCMH3fXuDSlSq +qrCznextjojtWbnzrBmCmJmXWGd2gSaJDvb90ZZp/Elt3vN1sgjW0M/JEkb4MJ1r +6nfD/FHr2lUwBHm2yk7Blovx7x4d/Ip3pglk63cNO/Rn0SBTdoVDS2LB9du3Phq2 +TZiL3NrRMGUNwmdaavyrJxaPq5D+Sfa4LYP3MMYD4KhLogNzIl299n5joyizlJw= +-----END CERTIFICATE----- diff --git a/mysql-test/std_data/server-cert-verify-fail.pem b/mysql-test/std_data/server-cert-verify-fail.pem new file mode 100644 index 00000000000..4203425a344 --- /dev/null +++ b/mysql-test/std_data/server-cert-verify-fail.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDJzCCAg8CAQEwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCSU4xETAPBgNV +BAgMCEthcm5hdGthMRIwEAYDVQQHDAlCYW5nYWxvcmUxDjAMBgNVBAoMBU15U1FM +MB4XDTE2MDEwNTEwMDgyN1oXDTI1MTExMzEwMDgyN1owbzELMAkGA1UEBhMCSU4x +EjAQBgNVBAgMCTpLYXJuYXRrYTETMBEGA1UEBwwKOkJhbmdhbG9yZTEPMA0GA1UE +CgwGOk15U1FMMRcwFQYDVQQLDA4vQ049bG9jYWxob3N0LzENMAsGA1UEAwwEZmFp +bDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3wnWuJodzZYq9TAJRm +HU7995FA3TEWdUinYTgGP79aTVQ4M9aeINlB6whWXOI8seh9Ja7C6kMzqOgYbgCl +WlDPAVJWktFYeWXOLxbpzh1KWkS6jBkWT02t7H7JcYbil7xjlJUxLz4UOOUDUDIP +6yqdA9VE3osESttjzj57Zm2xPqzbIHVJfORn7EexH4pryS7439p6i4XtfL31NJ8V +07M3j3a8GqbcEqXYvcUCrLnywDQ1igP817b6ta52nbgYWiqdn0mJs535UJ/p/rSl +D4Ae/6G3BSEY7whir6xY6vsd4KJ6w+wRCHnY0ky6OdDJVJLH1iqh7si7P3RBGkxw +Y7MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAggbw1jj2b7H5KDdeGJGIoOGkQAcs +GNSJussCfdk7qnzYXKmjyNppC86jjaOrXona5f+SNCuujdu86Tv8V69EH57k4lUc +DW7J4AD3vUb/tBzB0tsI/76Z4gm1XoCsnCGGpWd8GQAg/QNn/ZfJB2Vb/9ObN6rH +0HV7ouB6OGZSsb71+grKiN6mDyB1lZynCGvqBxOCKFISfcRbCNFHo/pONlHaNGPE +vjDH1bPZbEHj8owYgkdcQe0a8EbJYeQfm6fH8V8bmUcG7N60DrCnq4l1qwwVkh1S +7RpIDgrWkU+esIIdYZIIbtDxQP1Sm7kUh++7b+bcHnyw3KtDVSCw7MIedA== +-----END CERTIFICATE----- diff --git a/mysql-test/std_data/server-cert-verify-pass.pem b/mysql-test/std_data/server-cert-verify-pass.pem new file mode 100644 index 00000000000..f8780f1f94e --- /dev/null +++ b/mysql-test/std_data/server-cert-verify-pass.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDEzCCAfsCAQEwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCSU4xETAPBgNV +BAgMCEthcm5hdGthMRIwEAYDVQQHDAlCYW5nYWxvcmUxDjAMBgNVBAoMBU15U1FM +MB4XDTE2MDEwNTEwMDU1OVoXDTI1MTExMzEwMDU1OVowWzELMAkGA1UEBhMCSU4x +EjAQBgNVBAgMCTpLYXJuYXRrYTETMBEGA1UEBwwKOkJhbmdhbG9yZTEPMA0GA1UE +CgwGOk15U1FMMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDAmkbUwDe+nrqL8A8uwlIZk74HHCDjUAWrskKF9leEIQsB +5exFZ8JEo1u6mdR4laQWsxizGdTPqIEidkDyyEMh4+joHgyQEPD/G3rFVW8yEFHb +42O04O96BEPFXNPDRuX3MxI+lGbYDjxTS/WhVub4/3SqLjC28FJmEUXIHA0/A+c5 +hlYXK0u+aPAqXxHIjBgB4BxxHXZKqecmvR3LhXoVmhJmndsVfKajB27nDKc8/OTI +H2SXb6h3nRPDXRfwB/C5i+004tEsVeIgkYshcCgLSyDdeVieUP2pm3EAmDSjmtLF +6CgY/EBSfH+JCKFUk75bA4k8CCGzBfIeOcsKHwgFAgMBAAEwDQYJKoZIhvcNAQEL +BQADggEBAInDuHtDkeT6dkWmRJCP56c4xiQqib2QuYUuMSrAhf07xlLHc6iHnD2X +hCWCrja6uwF90DnPjeouKMAUe5txq/uKA8/Y/NfXN6nPiAeHLI0qnTv7Mr9TQ8zU +DNDwRz6onlI2cS4GhrwAnlpiaxu7AjMUWHtfBFGFrgn3PawjDQpsBZNcxw1QsLc0 +E0hFrWLOd0vDETEhoRge88N7a0jqK0Rd9cvRWnvjI+IsjQMLZzKufivIHPzI9K+9 +Wtp8iRHcaBr5DpsBjgsO7dqVRbsNyaWsdHdLt+CQSGXpv7P6fq3K6nJFTBeIgSfS +gflrHVKYZRkKDDDpX4yHNdnIqrvy4RU= +-----END CERTIFICATE----- diff --git a/mysql-test/std_data/server-key-verify-fail.pem b/mysql-test/std_data/server-key-verify-fail.pem new file mode 100644 index 00000000000..af1ae1e3ae1 --- /dev/null +++ b/mysql-test/std_data/server-key-verify-fail.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAvfCda4mh3Nlir1MAlGYdTv33kUDdMRZ1SKdhOAY/v1pNVDgz +1p4g2UHrCFZc4jyx6H0lrsLqQzOo6BhuAKVaUM8BUlaS0Vh5Zc4vFunOHUpaRLqM +GRZPTa3sfslxhuKXvGOUlTEvPhQ45QNQMg/rKp0D1UTeiwRK22POPntmbbE+rNsg +dUl85GfsR7EfimvJLvjf2nqLhe18vfU0nxXTszePdrwaptwSpdi9xQKsufLANDWK +A/zXtvq1rnaduBhaKp2fSYmznflQn+n+tKUPgB7/obcFIRjvCGKvrFjq+x3gonrD +7BEIedjSTLo50MlUksfWKqHuyLs/dEEaTHBjswIDAQABAoIBAQCSUyNzDPydXvsf +hhoUOParPAvU4tuETYDdD9Vdi7Lgf3jDQOjulbNIq/ec3KuBvrBwIrk9APvn+YxO +AUP9S2Vgi5jBDeDdVgNv4n90b3pSJk2UVQJI8V72wN5Ibnf/KeErSKvWo6V5daq/ +AuZtKsZIdd3WFtA62HuyuBjTGc23Alj1C0EKnN0Rx1uBwDvx/OVQ266Us/x8jJqW +ZxIOfcvfNzBQEa5hAzbQCReVaC+rBLRAcMM2yGP7aDa+8cRkwuVlSqpX8CXBdLoU +PqmU49etcW72Rb1AFt9WgEu1Oh9UYbHFSB+FEbO8IGcGBsuYHf9zkxQyjpy/iKyT +H5dTu7YBAoGBAOWqEGepZVrfB+P6X18n3vbJhgYmF0sa0mCmwkFYgk36yNqsZ8at +lQjm5mbn4wjEKHIcQ/T1taq73W471M+PxMnn0WTwoG5jsyarZGgy6/95YXiyZtQe +qgA4P3aKkCteRP22DjG7uxmm9Hoqx8Z31vfRTLAHN1IEHPHHkg/J3gPTAoGBANO4 +aqKeY4vcDvVkvxVbADrw++tZGwA+RuxfO4HKKru59VdA2PsAxhXwb3Dfejwj7hYW +yE9edHjGpMr1+dpf8YJYs7qjajHe1HxBOYqQGHycIdw+Gv56R4HpaS9eW3x8l/Pi +b4xnAodv2qIriACOe7br+rll4wKX46Wt64zdvpShAoGAT0r3HQM0Vjp4u/J+qRjX +9za+yjKuiiS5i9snaG5JlujGHhG2Rrc5pHgsBk17alRnbnZp1BJdZZQ1MFEB+aO2 +mssp1YLqsRJFEU3NfdhO+MaMq6JUtFnd8fN5ndDbU83ZXgtUPUGGqKWm9OL+VHyd +wLQHmSL0q6F16Ngxirf0qjcCgYEAtSmiJVA+gdhk/FmeoBlkEwtNpM50Kjsf2PaM +Jrzk4Al5A5Y7lFvPI8q+sOio4XklKsWH1VJPe2EOdZUQnGlocE6SS+u03MN9Mm1l +XUl7inTXDGwgEQx0z5b4KE4nHlhGdauWI5+pLFbrz8RL9Z32AkneGnIyU2/AnW46 +lijQAMECgYEAmgp/88ndIw49RCtMhYhtXQ87AsEAP6kzXQyKppDkn0os+xI5igIL +i/UDxB33hx3yjrUZwoGDV9MwlMhZNX5Tf5bwjPmmh1NR6KdEpPt5AkklX4s6uil2 +Bxl1P5l1jl/PbEYtv5LDZKIPANWRzViMSIWqjUWlbdqE7/vjx+Oo+cc= +-----END RSA PRIVATE KEY----- diff --git a/mysql-test/std_data/server-key-verify-pass.pem b/mysql-test/std_data/server-key-verify-pass.pem new file mode 100644 index 00000000000..7ecc44f6d48 --- /dev/null +++ b/mysql-test/std_data/server-key-verify-pass.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAwJpG1MA3vp66i/APLsJSGZO+Bxwg41AFq7JChfZXhCELAeXs +RWfCRKNbupnUeJWkFrMYsxnUz6iBInZA8shDIePo6B4MkBDw/xt6xVVvMhBR2+Nj +tODvegRDxVzTw0bl9zMSPpRm2A48U0v1oVbm+P90qi4wtvBSZhFFyBwNPwPnOYZW +FytLvmjwKl8RyIwYAeAccR12SqnnJr0dy4V6FZoSZp3bFXymowdu5wynPPzkyB9k +l2+od50Tw10X8AfwuYvtNOLRLFXiIJGLIXAoC0sg3XlYnlD9qZtxAJg0o5rSxego +GPxAUnx/iQihVJO+WwOJPAghswXyHjnLCh8IBQIDAQABAoIBAHPQUSc9LkgBSks7 +XuXPE28t1+aOk3gcdkx4NGg5aQaal/PcPea+LaL4WAAs4AZidPjxWLjZn43+1SfT +09opcbS/Rx3Mc+FtTn0YGQrwBJ0mExMV+K6bU2Ubi2TyHKQfzciHfUEEG5Nve/ba +hikuCFVRxuVOQRzABcw6NqvNsmlg892lfw6/+RDwMBcz7ocwzmiOUoIxgjyFo9G4 +aJvRmHLij5892H6qveik+A/Xr+8leGQHiQET2wW/F9MFP5ypIT7aeE6remeZH7fG +f4/Zfei/TE4xK2ElNR/91byzeKIVY4vjtTndAiBuqpfYuICb40MC02LNW5Oe6VN2 +3mQ6EgECgYEA7O4ndBnbs/00gyTGyNg6I+3wRTibhNH4R8RZFJiLfKRKOlUiLhUo ++bQeO4bCQ6YY++TYDvMEXTlA3jow9R9Mj2AWc6bNmQmJd/065QyFHftywT66I+V4 +rz1ohSJyHXcv4DxqNk3o3Vb4N8GFjZKcodSgTv2Lk+9ipDYFcQiZop0CgYEA0BrF +SIyLTnjoVht/7RbIGEqhMQUiz5mx7qQ1TPB+YTG77G2xXJNg5d6S7WT4LN+cqbxN +YdndIbW4NdV7bH7FlG9q7jfkuZ+AY2BPU047tcDeyO0HYYEhVY+EyZqHci/26mvt +JrawdqS5HQS1y/rKfytm7YBGTvqoNZHvOHc6aokCgYEAxcjlbJkte+pyzMuFmiJP +HrFBczeXM+BoJ9j0GCpjvvAS+vEYsGl/pDvFRSHwx7I/hv/5kTkzOnNSAHGJbwbq +zYGEHJVxakC43k6pvI2gDnBa0pD/qHmmLnvP5dvkcU6Oy90DOUP+kc9JNJo7V/y8 +/qdWD7q+qwcaTETAdCSexE0CgYA/DN1Y7bwHOnqqHArWOmDFe1b7EyNI4rgWJYpA +lVy09eyJ5XInKj/hZV3+rujCL723b2XCj89/tx7osJWEeaRDJL6xDh4uXzT25uch +xkIw/w6Asc/aqtT+p00EB92hqwaUX76qTA+K4r1zHUo3UvSnMu8sZgDnTOpJ0L05 +zmXUgQKBgDT+IFrAzOty4B0mJncTCC/TulpW704bEZwNJfQSdtiBQr/vqoXygBQc +bHfpncpSfhzHB5lhRUv02TqXgl53D70nM7JD5nx98WYTTBxsbvxPlt4gBRZkfgq5 +tHKclAArc1SbfW5Z8oYyl7h33LQJK116QSyiIIGieH5VXNPwnqUs +-----END RSA PRIVATE KEY----- diff --git a/mysql-test/suite/auth_sec/r/cert_verify.result b/mysql-test/suite/auth_sec/r/cert_verify.result new file mode 100644 index 00000000000..1da77329509 --- /dev/null +++ b/mysql-test/suite/auth_sec/r/cert_verify.result @@ -0,0 +1,5 @@ +#T1: Host name (/CN=localhost/) as OU name in the server certificate, server certificate verification should fail. +#T2: Host name (localhost) as common name in the server certificate, server certificate verification should pass. +Variable_name Value +Ssl_version TLS_VERSION +# restart server using restart diff --git a/mysql-test/suite/auth_sec/t/cert_verify.test b/mysql-test/suite/auth_sec/t/cert_verify.test new file mode 100644 index 00000000000..7250d4db67e --- /dev/null +++ b/mysql-test/suite/auth_sec/t/cert_verify.test @@ -0,0 +1,49 @@ +# Want to skip this test from Valgrind execution +--source include/no_valgrind_without_big.inc +# This test should work in embedded server after we fix mysqltest +-- source include/not_embedded.inc +-- source include/have_ssl_communication.inc +# Save the initial number of concurrent sessions +--source include/count_sessions.inc + +let $ssl_verify_fail_path = --ssl --ssl-ca=$MYSQL_TEST_DIR/std_data/ca-cert-verify.pem --ssl-key=$MYSQL_TEST_DIR/std_data/server-key-verify-fail.pem --ssl-cert=$MYSQL_TEST_DIR/std_data/server-cert-verify-fail.pem; +let $ssl_verify_pass_path = --ssl --ssl-ca=$MYSQL_TEST_DIR/std_data/ca-cert-verify.pem --ssl-key=$MYSQL_TEST_DIR/std_data/server-key-verify-pass.pem --ssl-cert=$MYSQL_TEST_DIR/std_data/server-cert-verify-pass.pem; + +let $tls_default= TLSv1.1; +let $openssl= query_get_value("SHOW STATUS LIKE 'Rsa_public_key'", Variable_name, 1); +if ($openssl == 'Rsa_public_key'){ + let $tls_default= TLSv1.2; +} + +--echo #T1: Host name (/CN=localhost/) as OU name in the server certificate, server certificate verification should fail. +--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--shutdown_server +--source include/wait_until_disconnected.inc + +--exec echo "restart:" $ssl_verify_fail_path > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--enable_reconnect +--source include/wait_until_connected_again.inc + +--error 1 +--exec $MYSQL --protocol=tcp --ssl-verify-server-cert -e "SHOW STATUS like 'Ssl_version'" + +--echo #T2: Host name (localhost) as common name in the server certificate, server certificate verification should pass. +--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--shutdown_server +--source include/wait_until_disconnected.inc + +--exec echo "restart:" $ssl_verify_pass_path > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--enable_reconnect +--source include/wait_until_connected_again.inc + +--replace_result $tls_default TLS_VERSION +--exec $MYSQL --protocol=tcp --ssl-verify-server-cert -e "SHOW STATUS like 'Ssl_version'" + +--echo # restart server using restart +--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--shutdown_server +--source include/wait_until_disconnected.inc + +--exec echo "restart: " > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--enable_reconnect +--source include/wait_until_connected_again.inc diff --git a/sql-common/client.c b/sql-common/client.c index c874086fc9c..0ef70eb7f56 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2003, 2016, 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 @@ -1885,35 +1885,39 @@ mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused))) static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const char **errptr) { SSL *ssl; - X509 *server_cert; - char *cp1, *cp2; - char buf[256]; + X509 *server_cert= NULL; + char *cn= NULL; + int cn_loc= -1; + ASN1_STRING *cn_asn1= NULL; + X509_NAME_ENTRY *cn_entry= NULL; + X509_NAME *subject= NULL; + int ret_validation= 1; + DBUG_ENTER("ssl_verify_server_cert"); DBUG_PRINT("enter", ("server_hostname: %s", server_hostname)); if (!(ssl= (SSL*)vio->ssl_arg)) { *errptr= "No SSL pointer found"; - DBUG_RETURN(1); + goto error; } if (!server_hostname) { *errptr= "No server hostname supplied"; - DBUG_RETURN(1); + goto error; } if (!(server_cert= SSL_get_peer_certificate(ssl))) { *errptr= "Could not get server certificate"; - DBUG_RETURN(1); + goto error; } if (X509_V_OK != SSL_get_verify_result(ssl)) { *errptr= "Failed to verify the server certificate"; - X509_free(server_cert); - DBUG_RETURN(1); + goto error; } /* We already know that the certificate exchanged was valid; the SSL library @@ -1921,27 +1925,61 @@ static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const c are what we expect. */ - X509_NAME_oneline(X509_get_subject_name(server_cert), buf, sizeof(buf)); - X509_free (server_cert); + /* + Some notes for future development + We should check host name in alternative name first and then if needed check in common name. + Currently yssl doesn't support alternative name. + openssl 1.0.2 support X509_check_host method for host name validation, we may need to start using + X509_check_host in the future. + */ - DBUG_PRINT("info", ("hostname in cert: %s", buf)); - cp1= strstr(buf, "/CN="); - if (cp1) + subject= X509_get_subject_name((X509 *) server_cert); + // Find the CN location in the subject + cn_loc= X509_NAME_get_index_by_NID(subject, NID_commonName, -1); + if (cn_loc < 0) { - cp1+= 4; /* Skip the "/CN=" that we found */ - /* Search for next / which might be the delimiter for email */ - cp2= strchr(cp1, '/'); - if (cp2) - *cp2= '\0'; - DBUG_PRINT("info", ("Server hostname in cert: %s", cp1)); - if (!strcmp(cp1, server_hostname)) - { - /* Success */ - DBUG_RETURN(0); - } + *errptr= "Failed to get CN location in the certificate subject"; + goto error; } + + // Get the CN entry for given location + cn_entry= X509_NAME_get_entry(subject, cn_loc); + if (cn_entry == NULL) + { + *errptr= "Failed to get CN entry using CN location"; + goto error; + } + + // Get CN from common name entry + cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry); + if (cn_asn1 == NULL) + { + *errptr= "Failed to get CN from CN entry"; + goto error; + } + + cn= (char *) ASN1_STRING_data(cn_asn1); + + // There should not be any NULL embedded in the CN + if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn)) + { + *errptr= "NULL embedded in the certificate CN"; + goto error; + } + + DBUG_PRINT("info", ("Server hostname in cert: %s", cn)); + if (!strcmp(cn, server_hostname)) + { + /* Success */ + ret_validation= 0; + } + *errptr= "SSL certificate validation failure"; - DBUG_RETURN(1); + +error: + if (server_cert != NULL) + X509_free (server_cert); + DBUG_RETURN(ret_validation); } #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ From 70f1aa4223fd6631736b73fb0ccc17aeaece84e7 Mon Sep 17 00:00:00 2001 From: Yashwant Sahu Date: Mon, 11 Jan 2016 09:23:31 +0530 Subject: [PATCH 18/57] Bug #22295186: CERTIFICATE VALIDATION BUG IN MYSQL MAY ALLOW MITM. Test Fix --- mysql-test/suite/auth_sec/t/cert_verify.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/auth_sec/t/cert_verify.test b/mysql-test/suite/auth_sec/t/cert_verify.test index 7250d4db67e..20918349963 100644 --- a/mysql-test/suite/auth_sec/t/cert_verify.test +++ b/mysql-test/suite/auth_sec/t/cert_verify.test @@ -25,7 +25,7 @@ if ($openssl == 'Rsa_public_key'){ --source include/wait_until_connected_again.inc --error 1 ---exec $MYSQL --protocol=tcp --ssl-verify-server-cert -e "SHOW STATUS like 'Ssl_version'" +--exec $MYSQL --protocol=tcp --ssl-ca=$MYSQL_TEST_DIR/std_data/ca-cert-verify.pem --ssl-verify-server-cert -e "SHOW STATUS like 'Ssl_version'" --echo #T2: Host name (localhost) as common name in the server certificate, server certificate verification should pass. --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect @@ -37,7 +37,7 @@ if ($openssl == 'Rsa_public_key'){ --source include/wait_until_connected_again.inc --replace_result $tls_default TLS_VERSION ---exec $MYSQL --protocol=tcp --ssl-verify-server-cert -e "SHOW STATUS like 'Ssl_version'" +--exec $MYSQL --protocol=tcp --ssl-ca=$MYSQL_TEST_DIR/std_data/ca-cert-verify.pem --ssl-verify-server-cert -e "SHOW STATUS like 'Ssl_version'" --echo # restart server using restart --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect From d9f89fff16671ba2623e7673e4a306ce90223aba Mon Sep 17 00:00:00 2001 From: Yashwant Sahu Date: Mon, 11 Jan 2016 14:44:49 +0530 Subject: [PATCH 19/57] Bug #22295186: CERTIFICATE VALIDATION BUG IN MYSQL MAY ALLOW MITM Test fix for 5.5 and 5.6 --- mysql-test/suite/auth_sec/t/cert_verify.test | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mysql-test/suite/auth_sec/t/cert_verify.test b/mysql-test/suite/auth_sec/t/cert_verify.test index 20918349963..1515fc62340 100644 --- a/mysql-test/suite/auth_sec/t/cert_verify.test +++ b/mysql-test/suite/auth_sec/t/cert_verify.test @@ -9,11 +9,7 @@ let $ssl_verify_fail_path = --ssl --ssl-ca=$MYSQL_TEST_DIR/std_data/ca-cert-verify.pem --ssl-key=$MYSQL_TEST_DIR/std_data/server-key-verify-fail.pem --ssl-cert=$MYSQL_TEST_DIR/std_data/server-cert-verify-fail.pem; let $ssl_verify_pass_path = --ssl --ssl-ca=$MYSQL_TEST_DIR/std_data/ca-cert-verify.pem --ssl-key=$MYSQL_TEST_DIR/std_data/server-key-verify-pass.pem --ssl-cert=$MYSQL_TEST_DIR/std_data/server-cert-verify-pass.pem; -let $tls_default= TLSv1.1; -let $openssl= query_get_value("SHOW STATUS LIKE 'Rsa_public_key'", Variable_name, 1); -if ($openssl == 'Rsa_public_key'){ - let $tls_default= TLSv1.2; -} +let $tls_default= TLSv1; --echo #T1: Host name (/CN=localhost/) as OU name in the server certificate, server certificate verification should fail. --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect From 0aab0e7a3d9afa5475d5a515142a19c6a09ae44c Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 11 Jan 2016 14:10:58 +0100 Subject: [PATCH 20/57] Updated copyright year in user visible text --- README | 2 +- include/welcome_copyright_notice.h | 4 ++-- packaging/WiX/custom_ui.wxs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README b/README index 47b38689038..72cc70bbd16 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ For the avoidance of doubt, this particular copy of the software is released under the version 2 of the GNU General Public License. MySQL is brought to you by Oracle. -Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. License information can be found in the COPYING file. diff --git a/include/welcome_copyright_notice.h b/include/welcome_copyright_notice.h index eb2bf260af3..7b6c28c2f56 100644 --- a/include/welcome_copyright_notice.h +++ b/include/welcome_copyright_notice.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2016, 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 @@ -16,7 +16,7 @@ #ifndef _welcome_copyright_notice_h_ #define _welcome_copyright_notice_h_ -#define COPYRIGHT_NOTICE_CURRENT_YEAR "2015" +#define COPYRIGHT_NOTICE_CURRENT_YEAR "2016" /* This define specifies copyright notice which is displayed by every MySQL diff --git a/packaging/WiX/custom_ui.wxs b/packaging/WiX/custom_ui.wxs index a28c3c9b8a1..e96ab0fe505 100644 --- a/packaging/WiX/custom_ui.wxs +++ b/packaging/WiX/custom_ui.wxs @@ -2,7 +2,7 @@ xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">