From 4b4a0532456fa05dc04c63d3e202e44573abaa4c Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 9 Nov 2015 15:25:01 +0100 Subject: [PATCH 01/97] Raise version number after cloning 5.5.47 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b85da230659ae..4bf30e8600ef1 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/97] 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 4d93ce202fe3f..638f54a93ce93 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 a3adf80c096e6..1842de91ef9be 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 f07a808985382..efdb67d01c41d 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/97] 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 61a0d1ae90903..172987cc1c618 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/97] 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 5f326d0e45f7e..ba1f975549a1c 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/97] 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 0000000000000..2efb3eba2b1bd --- /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 0000000000000..def8e8f50ecab --- /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 172987cc1c618..f559974c86b09 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 c3d2a092fd65c..05bb38d835890 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 c5886b3c14297..867997feb3986 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 @@ class Query_tables_list 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/97] 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 52b59da58cddd..72fcd3ef78776 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/97] 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 fd590574e567d..beb68c5d32166 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 629f9afa24184..831343de7ada6 100644 --- a/sql/item.h +++ b/sql/item.h @@ -960,7 +960,13 @@ class Item { */ 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 e6cc3272ceb26..b302440272e10 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 115d6db300d4e..00c7bccbfb87f 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1514,7 +1514,7 @@ class Item_cond :public Item_bool_func 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 @@ class Item_cond_and :public Item_cond 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 @@ class Item_cond_or :public Item_cond 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 05bb38d835890..629088dd86262 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 5a5e8b4875495..c990023161584 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2515,6 +2515,22 @@ class THD :public Statement, 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 1744677803476..50cdabe341a08 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 96f60d4665115..96271f26b0fec 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/97] 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 629088dd86262..4711009d7cd83 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/97] 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 0000000000000..b03c0057a6977 --- /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 0000000000000..a93fcbac82fee --- /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 38efb2a9c6b50..accb6a28dbd63 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 5da9f43d793a5..c936ea69a9714 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 16bfc5cdb6923..ad6494fd7d44d 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 0a58d9ade5b3e..3f64de7eac20f 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 11c339f4327c9ff88bfb62e342f45550d3c6140c Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Mon, 14 Dec 2015 23:45:23 +0100 Subject: [PATCH 10/97] - Fix MDEV-9279. Replacing exit(1) in yy_fatal_error by a longjmp. modified: storage/connect/fmdlex.c modified: storage/connect/plgdbutl.cpp --- storage/connect/fmdlex.c | 9 +++++++-- storage/connect/plgdbutl.cpp | 10 ++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/storage/connect/fmdlex.c b/storage/connect/fmdlex.c index 22c3a1e79ade1..548a7ae5b7e2d 100644 --- a/storage/connect/fmdlex.c +++ b/storage/connect/fmdlex.c @@ -1,3 +1,5 @@ +#include + #define yyFlexLexer fmdfFlexLexer #define yy_create_buffer fmdf_create_buffer #define yy_delete_buffer fmdf_delete_buffer @@ -506,13 +508,16 @@ YY_MALLOC_DECL #define YY_BREAK break; #endif +static jmp_buf env; + YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; - + if (setjmp(env)) + return -1; /*************************************************************************/ /* Flex parser to analyze date format and produce input and/or output */ @@ -1316,7 +1321,7 @@ char msg[]; #endif { (void) fprintf( stderr, "%s\n", msg ); - exit( 1 ); + longjmp(env, 1 ); } diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index 9e236da2d931c..1ec1108c639f7 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -679,7 +679,8 @@ void PlugConvertConstant(PGLOBAL g, void* & value, short& type) /* non quoted blanks are not included in the output format. */ /***********************************************************************/ PDTP MakeDateFormat(PGLOBAL g, PSZ dfmt, bool in, bool out, int flag) - { +{ + int rc; PDTP pdp = (PDTP)PlugSubAlloc(g, NULL, sizeof(DATPAR)); if (trace) @@ -708,7 +709,7 @@ PDTP MakeDateFormat(PGLOBAL g, PSZ dfmt, bool in, bool out, int flag) pthread_mutex_lock(&parmut); #endif // !__WIN__ #endif // THREAD - /*int rc =*/ fmdflex(pdp); + rc = fmdflex(pdp); #if defined(THREAD) #if defined(__WIN__) LeaveCriticalSection((LPCRITICAL_SECTION)&parsec); @@ -718,9 +719,10 @@ PDTP MakeDateFormat(PGLOBAL g, PSZ dfmt, bool in, bool out, int flag) #endif // THREAD if (trace) - htrc("Done: in=%s out=%s\n", SVP(pdp->InFmt), SVP(pdp->OutFmt)); + htrc("Done: in=%s out=%s rc=%d\n", SVP(pdp->InFmt), SVP(pdp->OutFmt), rc); + return pdp; - } // end of MakeDateFormat +} // end of MakeDateFormat /***********************************************************************/ /* Extract the date from a formatted string according to format. */ From c5ba706791910f7ab5d83056abc9e9266891fa46 Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Wed, 16 Dec 2015 10:48:57 +0530 Subject: [PATCH 11/97] 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 d322abcd742da..9e34532f1ac47 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 12/97] 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 12a1b16db806d..fab7b3627b31a 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 a76eaa114f88e..8a020b05ae66a 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 dc151e0322c4f..28472249eda16 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 cb42dfacf7167..91c708a583d52 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 6883e5c4c40d1411dcc7c43bbb7cbb3f2d0ab251 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sun, 27 Dec 2015 19:45:51 +0100 Subject: [PATCH 13/97] - Fix MDEV-9322. modified: storage/connect/json.cpp --- storage/connect/json.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index fc7edb84c0f49..75bf277b25bf5 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -594,8 +594,8 @@ PSZ Serialize(PGLOBAL g, PJSON jsp, char *fn, int pretty) if (fs) { fputs(EL, fs); fclose(fs); - str = (err) ? NULL : "Ok"; - } else if (!err) { + str = (err) ? NULL : strcpy(g->Message, "Ok"); + } else if (!err) { str = ((JOUTSTR*)jp)->Strp; jp->WriteChr('\0'); PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N); From 1ec594dd60aa3b58e7d1c686016695b5b0bc1aa1 Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Tue, 29 Dec 2015 15:58:44 +0530 Subject: [PATCH 14/97] 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 3f64de7eac20f..7b4d08613cfaf 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 15/97] 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 7f3ecc0d60237..2db5711a4b95d 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 b6c70485dbca2..3abfdc616ff6b 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 840c8e55efe3b..00145540e6d28 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 0418a0e96219d..3e3cd693613dd 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 16/97] 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 bf0e1c9f40ff5..81d573d0b20c5 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 b09b662c88c5a..0472b304679f6 100644 --- a/extra/yassl/include/crypto_wrapper.hpp +++ b/extra/yassl/include/crypto_wrapper.hpp @@ -378,6 +378,7 @@ class DiffieHellman { 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 b0a7592f8700f..095b3c6aa8033 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 3f819ee2349b2..95065932c5f15 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 1baa5adedf837..f190761604df4 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 c04c5a533528d..19ba6386efd26 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 17/97] 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 586119b2ffba8..1abfa95f8b3f5 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 98158ca806be6..1b79970a830f0 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 bbed14556b924..1b5a2cedfd5a3 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 8c93da072fb28..4548d0a221f24 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 28974a84c49c1..f90d36a01e42e 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 92676bd727c1d..6ff198ac6f379 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 4f0a3a32d8681..dc019b07bd988 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 @@ static int lfind(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, /* 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 ac0166c87b868..567721baf27cc 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 2e40fc8b5c541..40d577e43725e 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 18/97] 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 7eb49b9dd92ee..d98f19c3e014a 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 0891ae2fbb77c96a7fbeeb2ce9973d22da596f2a Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sat, 9 Jan 2016 20:52:17 +0100 Subject: [PATCH 19/97] - Fix MDEV-9239. Meanwhile, make all references to the database in XTAB Schema (was sometimes in XTAB Catalog) modified: storage/connect/mycat.cc modified: storage/connect/mycat.h modified: storage/connect/reldef.cpp modified: storage/connect/reldef.h modified: storage/connect/tabmysql.cpp modified: storage/connect/tabpivot.cpp modified: storage/connect/tabtbl.cpp modified: storage/connect/tabutil.cpp --- storage/connect/mycat.cc | 31 +++++++++++++++++-------------- storage/connect/mycat.h | 10 ++++++---- storage/connect/reldef.cpp | 13 ++++++++----- storage/connect/reldef.h | 12 +++++++----- storage/connect/tabmysql.cpp | 2 +- storage/connect/tabpivot.cpp | 4 ++-- storage/connect/tabtbl.cpp | 6 +++--- storage/connect/tabutil.cpp | 25 +++++++++++++++++-------- 8 files changed, 61 insertions(+), 42 deletions(-) diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc index 2e9085b4c87c1..97ad980dd6a7a 100644 --- a/storage/connect/mycat.cc +++ b/storage/connect/mycat.cc @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2015 +/* Copyright (C) Olivier Bertrand 2004 - 2016 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 @@ -18,7 +18,7 @@ /* ------------- */ /* Version 1.4 */ /* */ -/* Author: Olivier Bertrand 2012 - 2015 */ +/* Author: Olivier Bertrand 2012 - 2016 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -509,30 +509,33 @@ void MYCAT::SetPath(PGLOBAL g, LPCSTR *datapath, const char *path) /* GetTableDesc: retrieve a table descriptor. */ /* Look for a table descriptor matching the name and type. */ /***********************************************************************/ -PRELDEF MYCAT::GetTableDesc(PGLOBAL g, LPCSTR name, +PRELDEF MYCAT::GetTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR type, PRELDEF *) { if (trace) - printf("GetTableDesc: name=%s am=%s\n", name, SVP(type)); + printf("GetTableDesc: name=%s am=%s\n", tablep->GetName(), SVP(type)); // If not specified get the type of this table if (!type) type= Hc->GetStringOption("Type","*"); - return MakeTableDesc(g, name, type); + return MakeTableDesc(g, tablep, type); } // end of GetTableDesc /***********************************************************************/ /* MakeTableDesc: make a table/view description. */ /* Note: caller must check if name already exists before calling it. */ /***********************************************************************/ -PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am) +PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) { TABTYPE tc; + LPCSTR name = (PSZ)PlugDup(g, tablep->GetName()); + LPCSTR schema = (PSZ)PlugDup(g, tablep->GetSchema()); PRELDEF tdp= NULL; if (trace) - printf("MakeTableDesc: name=%s am=%s\n", name, SVP(am)); + printf("MakeTableDesc: name=%s schema=%s am=%s\n", + name, SVP(schema), SVP(am)); /*********************************************************************/ /* Get a unique enum identifier for types. */ @@ -571,11 +574,11 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am) case TAB_VIR: tdp= new(g) VIRDEF; break; case TAB_JSON: tdp= new(g) JSONDEF; break; default: - sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name); + sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name); } // endswitch // Do make the table/view definition - if (tdp && tdp->Define(g, this, name, am)) + if (tdp && tdp->Define(g, this, name, schema, am)) tdp= NULL; return tdp; @@ -588,20 +591,20 @@ PTDB MYCAT::GetTable(PGLOBAL g, PTABLE tablep, MODE mode, LPCSTR type) { PRELDEF tdp; PTDB tdbp= NULL; - LPCSTR name= tablep->GetName(); +// LPCSTR name= tablep->GetName(); if (trace) - printf("GetTableDB: name=%s\n", name); + printf("GetTableDB: name=%s\n", tablep->GetName()); // Look for the description of the requested table - tdp= GetTableDesc(g, name, type); + tdp= GetTableDesc(g, tablep, type); if (tdp) { if (trace) printf("tdb=%p type=%s\n", tdp, tdp->GetType()); - if (tablep->GetQualifier()) - tdp->Database = SetPath(g, tablep->GetQualifier()); + if (tablep->GetSchema()) + tdp->Database = SetPath(g, tablep->GetSchema()); tdbp= tdp->GetTable(g, mode); } // endif tdp diff --git a/storage/connect/mycat.h b/storage/connect/mycat.h index dfcbb2f67667f..05163f08f1ba3 100644 --- a/storage/connect/mycat.h +++ b/storage/connect/mycat.h @@ -100,15 +100,17 @@ class MYCAT : public CATALOG { //void SetDataPath(PGLOBAL g, const char *path) // {SetPath(g, &DataPath, path);} bool StoreIndex(PGLOBAL, PTABDEF) {return false;} // Temporary - PRELDEF GetTableDesc(PGLOBAL g, LPCSTR name, - LPCSTR type, PRELDEF *prp = NULL); +// PRELDEF GetTableDesc(PGLOBAL g, LPCSTR name, + PRELDEF GetTableDesc(PGLOBAL g, PTABLE tablep, + LPCSTR type, PRELDEF *prp = NULL); PTDB GetTable(PGLOBAL g, PTABLE tablep, MODE mode = MODE_READ, LPCSTR type = NULL); void ClearDB(PGLOBAL g); protected: - PRELDEF MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am); -//void SetPath(PGLOBAL g, LPCSTR *datapath, const char *path); +// PRELDEF MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am); + PRELDEF MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am); + //void SetPath(PGLOBAL g, LPCSTR *datapath, const char *path); // Members ha_connect *Hc; // The Connect handler diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp index 8f9328c0b2f7e..e455bc8f1a520 100644 --- a/storage/connect/reldef.cpp +++ b/storage/connect/reldef.cpp @@ -1,11 +1,11 @@ /************* RelDef CPP Program Source Code File (.CPP) **************/ /* PROGRAM NAME: RELDEF */ /* ------------- */ -/* Version 1.4 */ +/* Version 1.5 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2004-2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2004-2016 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -37,6 +37,7 @@ #include "plgdbsem.h" #include "reldef.h" #include "colblk.h" +#include "tabcol.h" #include "filamap.h" #include "filamfix.h" #include "filamvct.h" @@ -217,11 +218,13 @@ TABDEF::TABDEF(void) /***********************************************************************/ /* Define: initialize the table definition block from XDB file. */ /***********************************************************************/ -bool TABDEF::Define(PGLOBAL g, PCATLG cat, LPCSTR name, LPCSTR am) +bool TABDEF::Define(PGLOBAL g, PCATLG cat, + LPCSTR name, LPCSTR schema, LPCSTR am) { int poff = 0; - Name = (PSZ)PlugDup(g, name); + Name = (PSZ)name; + Schema = (PSZ)schema; Cat = cat; Hc = ((MYCAT*)cat)->GetHandler(); Catfunc = GetFuncID(GetStringCatInfo(g, "Catfunc", NULL)); @@ -569,7 +572,7 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g) } // endif Cbuf // Here "OEM" should be replace by a more useful value - if (xdefp->Define(g, cat, Name, "OEM")) + if (xdefp->Define(g, cat, Name, Schema, "OEM")) return NULL; // Ok, return external block diff --git a/storage/connect/reldef.h b/storage/connect/reldef.h index dada5716dbe50..bc1bd2ddd7446 100644 --- a/storage/connect/reldef.h +++ b/storage/connect/reldef.h @@ -1,7 +1,7 @@ /*************** RelDef H Declares Source Code File (.H) ***************/ -/* Name: RELDEF.H Version 1.5 */ +/* Name: RELDEF.H Version 1.6 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2004-2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2004-2016 */ /* */ /* This file contains the DEF classes definitions. */ /***********************************************************************/ @@ -50,7 +50,8 @@ class DllExport RELDEF : public BLOCK { // Relation definition block int GetCharCatInfo(PSZ what, PSZ sdef, char *buf, int size); char *GetStringCatInfo(PGLOBAL g, PSZ what, PSZ sdef); virtual int Indexable(void) {return 0;} - virtual bool Define(PGLOBAL g, PCATLG cat, LPCSTR name, LPCSTR am) = 0; + virtual bool Define(PGLOBAL g, PCATLG cat, + LPCSTR name, LPCSTR schema, LPCSTR am) = 0; virtual PTDB GetTable(PGLOBAL g, MODE mode) = 0; protected: @@ -97,8 +98,9 @@ class DllExport TABDEF : public RELDEF { /* Logical table descriptor */ int GetColCatInfo(PGLOBAL g); void SetIndexInfo(void); bool DropTable(PGLOBAL g, PSZ name); - virtual bool Define(PGLOBAL g, PCATLG cat, LPCSTR name, LPCSTR am); - virtual bool DefineAM(PGLOBAL, LPCSTR, int) = 0; + virtual bool Define(PGLOBAL g, PCATLG cat, + LPCSTR name, LPCSTR schema, LPCSTR am); + virtual bool DefineAM(PGLOBAL, LPCSTR, int) = 0; protected: // Members diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 658f3513b07d2..b9cede52a218f 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -334,7 +334,7 @@ bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int) Delayed = !!GetIntCatInfo("Delayed", 0); } else { // MYSQL access from a PROXY table - Database = GetStringCatInfo(g, "Database", "*"); + Database = GetStringCatInfo(g, "Database", Schema ? Schema : "*"); Isview = GetBoolCatInfo("View", false); // We must get other connection parms from the calling table diff --git a/storage/connect/tabpivot.cpp b/storage/connect/tabpivot.cpp index b628e26d3c789..256b454741c5c 100644 --- a/storage/connect/tabpivot.cpp +++ b/storage/connect/tabpivot.cpp @@ -348,7 +348,7 @@ bool PIVOTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) return TRUE; Tabname = (char*)Tablep->GetName(); - DB = (char*)Tablep->GetQualifier(); + DB = (char*)Tablep->GetSchema(); Tabsrc = (char*)Tablep->GetSrc(); Host = GetStringCatInfo(g, "Host", "localhost"); @@ -529,7 +529,7 @@ bool TDBPIVOT::GetSourceTable(PGLOBAL g) // Get the new table description block of this source table PTABLE tablep = new(g) XTAB("whatever", Tabsrc); - tablep->SetQualifier(Database); + tablep->SetSchema(Database); if (!(Tdbp = GetSubTable(g, tablep, true))) return true; diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp index 7f979eaf4be7e..6b72c715517f8 100644 --- a/storage/connect/tabtbl.cpp +++ b/storage/connect/tabtbl.cpp @@ -5,7 +5,7 @@ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to PlugDB Software Development 2008-2015 */ +/* (C) Copyright to PlugDB Software Development 2008-2016 */ /* Author: Olivier BERTRAND */ /* */ /* WHAT THIS PROGRAM DOES: */ @@ -130,10 +130,10 @@ bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR, int) // Allocate the TBLIST block for that table tbl = new(g) XTAB(pn, def); - tbl->SetQualifier(pdb); + tbl->SetSchema(pdb); if (trace) - htrc("TBL: Name=%s db=%s\n", tbl->GetName(), tbl->GetQualifier()); + htrc("TBL: Name=%s db=%s\n", tbl->GetName(), tbl->GetSchema()); // Link the blocks if (Tablep) diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp index 331a7f45d4d26..4069cdbed2a7b 100644 --- a/storage/connect/tabutil.cpp +++ b/storage/connect/tabutil.cpp @@ -1,7 +1,7 @@ /************* Tabutil cpp Declares Source Code File (.CPP) ************/ /* Name: TABUTIL.CPP Version 1.1 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2013 - 2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2013 - 2016 */ /* */ /* Utility function used by the PROXY, XCOL, OCCUR, and TBL tables. */ /***********************************************************************/ @@ -118,7 +118,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, FLD_LENGTH, FLD_SCALE, FLD_RADIX, FLD_NULL, FLD_REM, FLD_NO, FLD_CHARSET}; unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 32, 32}; - char *fld, *colname, *chset, *fmt, v; + char *pn, *tn, *fld, *colname, *chset, *fmt, v; int i, n, ncol = sizeof(buftyp) / sizeof(int); int prec, len, type, scale; int zconv = GetConvSize(); @@ -130,7 +130,16 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, PCOLRES crp; if (!info) { - if (!(s = GetTableShare(g, thd, db, name, mysql))) { + // Analyze the table name, it may have the format: [dbname.]tabname + if (strchr((char*)name, '.')) { + tn = (char*)PlugDup(g, name); + pn = strchr(tn, '.'); + *pn++ = 0; + db = tn; + name = pn; + } // endif pn + + if (!(s = GetTableShare(g, thd, db, name, mysql))) { return NULL; } else if (s->is_view) { strcpy(g->Message, "Use MYSQL type to see columns from a view"); @@ -315,7 +324,7 @@ bool PRXDEF::DefineAM(PGLOBAL g, LPCSTR, int) } // endif pn Tablep = new(g) XTAB(tab, def); - Tablep->SetQualifier(db); + Tablep->SetSchema(db); return false; } // end of DefineAM @@ -379,12 +388,12 @@ PTDBASE TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b) LPCSTR cdb, curdb = hc->GetDBName(NULL); THD *thd = (hc->GetTable())->in_use; - db = (char*)tabp->GetQualifier(); + db = (char*)(tabp->GetSchema() ? tabp->GetSchema() : curdb); name = (char*)tabp->GetName(); // Check for eventual loop for (PTABLE tp = To_Table; tp; tp = tp->Next) { - cdb = (tp->Qualifier) ? tp->Qualifier : curdb; + cdb = (tp->Schema) ? tp->Schema : curdb; if (!stricmp(name, tp->Name) && !stricmp(db, cdb)) { sprintf(g->Message, "Table %s.%s pointing on itself", db, name); @@ -423,7 +432,7 @@ PTDBASE TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b) } // endif Define if (db) - ((PTDBMY)tdbp)->SetDatabase(tabp->GetQualifier()); + ((PTDBMY)tdbp)->SetDatabase(tabp->GetSchema()); if (Mode == MODE_UPDATE || Mode == MODE_DELETE) tdbp->SetName(Name); // For Make_Command @@ -757,7 +766,7 @@ void PRXCOL::WriteColumn(PGLOBAL g) /***********************************************************************/ TDBTBC::TDBTBC(PPRXDEF tdp) : TDBCAT(tdp) { - Db = (PSZ)tdp->Tablep->GetQualifier(); + Db = (PSZ)tdp->Tablep->GetSchema(); Tab = (PSZ)tdp->Tablep->GetName(); } // end of TDBTBC constructor From 13380bf81f6bc20d39549f531f9acebdfb5a8c37 Mon Sep 17 00:00:00 2001 From: Yashwant Sahu Date: Mon, 11 Jan 2016 07:09:13 +0530 Subject: [PATCH 20/97] 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 0000000000000..21d6264a0ad83 --- /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 0000000000000..4203425a344ab --- /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 0000000000000..f8780f1f94ed7 --- /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 0000000000000..af1ae1e3ae12f --- /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 0000000000000..7ecc44f6d4896 --- /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 0000000000000..1da77329509e4 --- /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 0000000000000..7250d4db67e7b --- /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 c874086fc9c4b..0ef70eb7f56de 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 21/97] 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 7250d4db67e7b..20918349963d5 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 2a9f84b9a6e72f2d4facfaf49226736cdfe38d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Kek=C3=A4l=C3=A4inen?= Date: Mon, 11 Jan 2016 10:28:00 +0200 Subject: [PATCH 22/97] MDEV-9354: Debian: unmask the mysql.service on installation Unmask the systemd mysql.service if left behind by mysql-server-5.6 Without this a simple 'apt-get install mariadb-server' would end up with a system where mysqld is not running despite it was running OK with mysql-server-5.6 installed, and users might wrongly think mariadb-server package is broken when the real cause was the removal of mysql-server-5.6 that left a /etc/systemd/system/ file behind pointing to /dev/null. --- debian/dist/Debian/mariadb-server-10.0.postinst | 5 +++++ debian/dist/Ubuntu/mariadb-server-10.0.postinst | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/debian/dist/Debian/mariadb-server-10.0.postinst b/debian/dist/Debian/mariadb-server-10.0.postinst index 19594fb910eb2..19a69ed00cbe4 100644 --- a/debian/dist/Debian/mariadb-server-10.0.postinst +++ b/debian/dist/Debian/mariadb-server-10.0.postinst @@ -264,6 +264,11 @@ fi db_stop # in case invoke failes +# If we upgrade from MySQL mysql.service may be masked, which also +# means init.d script is disabled. Unmask mysql service explicitely. +# Ignore exit code as command is not available everywhere. +deb-systemd-helper unmask mysql.service > /dev/null || true + #DEBHELPER# exit 0 diff --git a/debian/dist/Ubuntu/mariadb-server-10.0.postinst b/debian/dist/Ubuntu/mariadb-server-10.0.postinst index 1acfbc8097041..2486a09a5af4b 100644 --- a/debian/dist/Ubuntu/mariadb-server-10.0.postinst +++ b/debian/dist/Ubuntu/mariadb-server-10.0.postinst @@ -280,6 +280,11 @@ fi db_stop # in case invoke failes +# If we upgrade from MySQL mysql.service may be masked, which also +# means init.d script is disabled. Unmask mysql service explicitely. +# Ignore exit code as command is not available everywhere. +deb-systemd-helper unmask mysql.service > /dev/null || true + #DEBHELPER# exit 0 From d9f89fff16671ba2623e7673e4a306ce90223aba Mon Sep 17 00:00:00 2001 From: Yashwant Sahu Date: Mon, 11 Jan 2016 14:44:49 +0530 Subject: [PATCH 23/97] 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 20918349963d5..1515fc623406d 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 24/97] 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 47b38689038a8..72cc70bbd163d 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 eb2bf260af3ac..7b6c28c2f5665 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 a28c3c9b8a122..e96ab0fe505e9 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">