From 51e049cff6a3110504b67644bf02a037dc8b1c5c Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Mon, 27 Nov 2017 15:33:02 +0530 Subject: Raise version number after cloning 5.5.59 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 87b72051a84..44f719ca097 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=59 +MYSQL_VERSION_PATCH=60 MYSQL_VERSION_EXTRA= -- cgit v1.2.1 From 8bc828b982f678d6b57c1853bbe78080c8f84e84 Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Mon, 27 Nov 2017 19:59:29 +0530 Subject: BUG#26502135: MYSQLD SEGFAULTS IN MDL_CONTEXT::TRY_ACQUIRE_LOCK_IMPL ANALYSIS: ========= Server sometimes exited when multiple threads tried to acquire and release metadata locks simultaneously (for example, necessary to access a table). The same problem could have occurred when new objects were registered/ deregistered in Performance Schema. The problem was caused by a bug in LF_HASH - our lock free hash implementation which is used by metadata locking subsystem in 5.7 branch. In 5.5 and 5.6 we only use LF_HASH in Performance Schema Instrumentation implementation. So for these versions, the problem was limited to P_S. The problem was in my_lfind() function, which searches for the specific hash element by going through the elements list. During this search it loads information about element checked such as key pointer and hash value into local variables. Then it confirms that they are not corrupted by concurrent delete operation (which will set pointer to 0) by checking if element is still in the list. The latter check did not take into account that compiler (and processor) can reorder reads in such a way that load of key pointer will happen after it, making result of the check invalid. FIX: ==== This patch fixes the problem by ensuring that no such reordering can take place. This is achieved by using my_atomic_loadptr() which contains compiler and processor memory barriers for the check mentioned above and other similar places. The default (for non-Windows systems) implementation of my_atomic*() relies on old __sync intrisics and implements my_atomic_loadptr() as read-modify operation. To avoid scalability/performance penalty associated with addition of my_atomic_loadptr()'s we change the my_atomic*() to use newer __atomic intrisics when available. This new default implementation doesn't have such a drawback. --- mysys/lf_hash.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mysys/lf_hash.c b/mysys/lf_hash.c index dc019b07bd9..3a3f665a4f1 100644 --- a/mysys/lf_hash.c +++ b/mysys/lf_hash.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2017, 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 @@ -83,7 +83,8 @@ retry: do { /* PTR() isn't necessary below, head is a dummy node */ cursor->curr= (LF_SLIST *)(*cursor->prev); _lf_pin(pins, 1, cursor->curr); - } while (*cursor->prev != (intptr)cursor->curr && LF_BACKOFF); + } while (my_atomic_loadptr((void**)cursor->prev) != cursor->curr && + LF_BACKOFF); for (;;) { if (unlikely(!cursor->curr)) @@ -97,7 +98,7 @@ retry: cur_hashnr= cursor->curr->hashnr; cur_key= cursor->curr->key; cur_keylen= cursor->curr->keylen; - if (*cursor->prev != (intptr)cursor->curr) + if (my_atomic_loadptr((void**)cursor->prev) != cursor->curr) { (void)LF_BACKOFF; goto retry; -- cgit v1.2.1 From ecc5a07874d44307b835ff5dbd091343961fbc93 Mon Sep 17 00:00:00 2001 From: Shishir Jaiswal Date: Sat, 2 Dec 2017 15:12:32 +0530 Subject: Bug#26585560 - MYSQL DAEMON SHOULD CREATE ITS PID FILE AS ROOT DESCRIPTION =========== If the .pid file is created at a world-writable location, it can be compromised by replacing the server's pid with another running server's (or some other non-mysql process) PID causing abnormal behaviour. ANALYSIS ======== In such a case, user should be warned that .pid file is being created at a world-writable location. FIX === A new function is_file_or_dir_world_writable() is defined and it is called in create_pid_file() before .pid file creation. If the location is world-writable, a relevant warning is thrown. NOTE ==== 1. PID file is always created with permission bit 0664, so for outside world its read-only. 2. Ignoring the case when permission is denied to get the dir stats since the .pid file creation would fail anyway in such a case. --- include/sql_common.h | 1 + mysql-test/include/mtr_warnings.sql | 8 +++++- sql-common/my_path_permissions.cc | 54 +++++++++++++++++++++++++++++++++++++ sql/CMakeLists.txt | 2 +- sql/mysqld.cc | 36 ++++++++++++++++++++++++- 5 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 sql-common/my_path_permissions.cc diff --git a/include/sql_common.h b/include/sql_common.h index 05bbb5a4f53..45e90d438fb 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -107,6 +107,7 @@ void mysql_client_plugin_deinit(); struct st_mysql_client_plugin; extern struct st_mysql_client_plugin *mysql_client_builtins[]; extern my_bool libmysql_cleartext_plugin_enabled; +int is_file_or_dir_world_writable(const char *filepath); #ifdef __cplusplus } diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index 0a3c3bc60b3..fb6d24c03e9 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -1,4 +1,4 @@ --- Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. +-- Copyright (c) 2008, 2017, 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 @@ -209,6 +209,12 @@ INSERT INTO global_suppressions VALUES */ ("Insecure configuration for --secure-file-priv:*"), + /* + Bug#26585560, warning related to --pid-file + */ + ("Insecure configuration for --pid-file:*"), + ("Few location(s) are inaccessible while checking PID filepath"), + ("THE_LAST_SUPPRESSION")|| diff --git a/sql-common/my_path_permissions.cc b/sql-common/my_path_permissions.cc new file mode 100644 index 00000000000..22cd748ff03 --- /dev/null +++ b/sql-common/my_path_permissions.cc @@ -0,0 +1,54 @@ +/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA */ + +#include "my_dir.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Check if a file/dir is world-writable (only on non-Windows platforms) + + @param [in] Path of the file/dir to be checked + + @returns Status of the file/dir check + @retval -2 Permission denied to check attributes of file/dir + @retval -1 Error in reading file/dir + @retval 0 File/dir is not world-writable + @retval 1 File/dir is world-writable + */ + +int is_file_or_dir_world_writable(const char *path) +{ + MY_STAT stat_info; + (void)path; // avoid unused param warning when built on Windows +#ifndef _WIN32 + if (!my_stat(path, &stat_info, MYF(0))) + { + return (errno == EACCES) ? -2 : -1; + } + if ((stat_info.st_mode & S_IWOTH) && + ((stat_info.st_mode & S_IFMT) == S_IFREG || /* file */ + (stat_info.st_mode & S_IFMT) == S_IFDIR)) /* or dir */ + return 1; +#endif + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 531561ac36d..aa7e0312e05 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -78,7 +78,7 @@ SET (SQL_SOURCE sql_profile.cc event_parse_data.cc sql_alter.cc sql_signal.cc rpl_handler.cc mdl.cc sql_admin.cc transaction.cc sys_vars.cc sql_truncate.cc datadict.cc - sql_reload.cc + sql_reload.cc ../sql-common/my_path_permissions.cc ${GEN_SOURCES} ${CONF_SOURCES} ${MYSYS_LIBWRAP_SOURCE}) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c969fd8a62a..fd39e252c26 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights +/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify @@ -7996,6 +7996,40 @@ static int test_if_case_insensitive(const char *dir_name) static void create_pid_file() { File file; + bool check_parent_path= 1, is_path_accessible= 1; + char pid_filepath[FN_REFLEN], *pos= NULL; + /* Copy pid file name to get pid file path */ + strcpy(pid_filepath, pidfile_name); + + /* Iterate through the entire path to check if even one of the sub-dirs + is world-writable */ + while (check_parent_path && (pos= strrchr(pid_filepath, FN_LIBCHAR)) + && (pos != pid_filepath)) /* shouldn't check root */ + { + *pos= '\0'; /* Trim the inner-most dir */ + switch (is_file_or_dir_world_writable(pid_filepath)) + { + case -2: + is_path_accessible= 0; + break; + case -1: + sql_perror("Can't start server: can't check PID filepath"); + exit(1); + case 1: + sql_print_warning("Insecure configuration for --pid-file: Location " + "'%s' in the path is accessible to all OS users. " + "Consider choosing a different directory.", + pid_filepath); + check_parent_path= 0; + break; + case 0: + continue; /* Keep checking the parent dir */ + } + } + if (!is_path_accessible) + { + sql_print_warning("Few location(s) are inaccessible while checking PID filepath."); + } if ((file= mysql_file_create(key_file_pid, pidfile_name, 0664, O_WRONLY | O_TRUNC, MYF(MY_WME))) >= 0) { -- cgit v1.2.1 From 9e1035c64f2db233995082397921f553810bdfbc Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Tue, 5 Dec 2017 19:49:59 +0530 Subject: BUG#26881798: SERVER EXITS WHEN PRIMARY KEY IN MYSQL.PROC IS DROPPED ANALYSIS: ========= It is advised not to tamper with the system tables. When primary key is dropped from a system table, certain operations on the table which tries to access the table key information may lead to server exit. FIX: ==== An appropriate error is now reported in such a case. --- sql/event_db_repository.cc | 4 +++- sql/sp.cc | 4 ++-- sql/sql_acl.cc | 4 +++- sql/sql_plugin.cc | 12 +++++++++++- sql/table.cc | 16 ++++++++++++++-- sql/table.h | 5 +++-- 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 74da4d8f587..96d1279573d 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2006, 2017, 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 @@ -174,6 +174,8 @@ protected: error_log_print(ERROR_LEVEL, fmt, args); va_end(args); } +public: + Event_db_intact() { has_keys= TRUE; } }; /** In case of an error, a message is printed to the error log. */ diff --git a/sql/sp.cc b/sql/sp.cc index 56a439481f5..82d25880168 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2002, 2017, 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 @@ -351,7 +351,7 @@ private: bool m_print_once; public: - Proc_table_intact() : m_print_once(TRUE) {} + Proc_table_intact() : m_print_once(TRUE) { has_keys= TRUE; } protected: void report_error(uint code, const char *fmt, ...); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b48b8562679..385484f2b01 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2017, 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 @@ -949,6 +949,8 @@ protected: va_end(args); } } +public: + Acl_table_intact() { has_keys= TRUE; } }; #define IP_ADDR_STRLEN (3 + 1 + 3 + 1 + 3 + 1 + 3) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 9ec0390483a..3af9136d37f 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2005, 2017, 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 @@ -1899,6 +1899,16 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) DBUG_RETURN(TRUE); + if (!table->key_info) + { + my_printf_error(ER_UNKNOWN_ERROR, + "The table '%s.%s' does not have the necessary key(s) " + "defined on it. Please check the table definition and " + "create index(s) accordingly.", MYF(0), + table->s->db.str, table->s->table_name.str); + DBUG_RETURN(TRUE); + } + /* Pre-acquire audit plugins for events that may potentially occur during [UN]INSTALL PLUGIN. diff --git a/sql/table.cc b/sql/table.cc index 5bc3ccdbf39..46397b794ee 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2017, 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 @@ -3013,7 +3013,7 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) /* Whether the table definition has already been validated. */ if (table->s->table_field_def_cache == table_def) - DBUG_RETURN(FALSE); + goto end; if (table->s->fields != table_def->count) { @@ -3129,6 +3129,18 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) if (! error) table->s->table_field_def_cache= table_def; +end: + + if (has_keys && !error && !table->key_info) + { + my_printf_error(ER_UNKNOWN_ERROR, + "The table '%s.%s' does not have the necessary key(s) " + "defined on it. Please check the table definition and " + "create index(s) accordingly.", MYF(0), + table->s->db.str, table->s->table_name.str); + error= TRUE; + } + DBUG_RETURN(error); } diff --git a/sql/table.h b/sql/table.h index ac3533dc5d7..31cd385ef35 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1,7 +1,7 @@ #ifndef TABLE_INCLUDED #define TABLE_INCLUDED -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2017, 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 @@ -484,10 +484,11 @@ typedef struct st_ha_data_partition class Table_check_intact { protected: + bool has_keys; virtual void report_error(uint code, const char *fmt, ...)= 0; public: - Table_check_intact() {} + Table_check_intact() : has_keys(FALSE) {} virtual ~Table_check_intact() {} /** Checks whether a table is intact. */ -- cgit v1.2.1 -- cgit v1.2.1 -- cgit v1.2.1 From 20e75a3efdd12540bf0078e27c62e0daad034cb7 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 11 Jan 2018 09:31:36 +0100 Subject: Bug #27021754 MYSQLTEST MAN PAGES WILL BE REMOVED, PACKAGING MUST BE PREPARED Followup: now that the man pages have actually been removed, we no longer need to take deliberate action to ignore them. Thus we can remove that part of the original change. RPM: drop the conditional removal DEB: remove from the exclude list --- packaging/rpm-oel/mysql.spec.in | 13 ++++--------- packaging/rpm-sles/mysql.spec.in | 13 ++++--------- support-files/mysql.spec.sh | 11 ++++------- 3 files changed, 12 insertions(+), 25 deletions(-) diff --git a/packaging/rpm-oel/mysql.spec.in b/packaging/rpm-oel/mysql.spec.in index 755f922026e..f3f65da6605 100644 --- a/packaging/rpm-oel/mysql.spec.in +++ b/packaging/rpm-oel/mysql.spec.in @@ -1,4 +1,4 @@ -# Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2018, 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 @@ -609,14 +609,6 @@ rm -rf %{buildroot}%{_bindir}/mysql_embedded rm -rf %{buildroot}%{_bindir}/mysql_setpermission rm -rf %{buildroot}%{_mandir}/man1/mysql_setpermission.1* -# Remove obsoleted man pages -rm -f %{buildroot}%{_mandir}/man1/mysql-stress-test.pl.1 -rm -f %{buildroot}%{_mandir}/man1/mysql-test-run.pl.1 -rm -f %{buildroot}%{_mandir}/man1/mysql_client_test.1 -rm -f %{buildroot}%{_mandir}/man1/mysql_client_test_embedded.1 -rm -f %{buildroot}%{_mandir}/man1/mysqltest.1 -rm -f %{buildroot}%{_mandir}/man1/mysqltest_embedded.1 - %check %if 0%{?runselftest} pushd release @@ -920,6 +912,9 @@ fi %endif %changelog +* Wed Jan 10 2018 Bjorn Munch - 5.5.60-1 +- No longer need to remove obsoleted mysqltest man pages + * Tue Oct 31 2017 Bjorn Munch - 5.5.59-1 - Remove obsoleted mysqltest man pages diff --git a/packaging/rpm-sles/mysql.spec.in b/packaging/rpm-sles/mysql.spec.in index d5a3ba8deff..75e0271b590 100644 --- a/packaging/rpm-sles/mysql.spec.in +++ b/packaging/rpm-sles/mysql.spec.in @@ -1,4 +1,4 @@ -# Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2018, 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 @@ -446,14 +446,6 @@ rm -rf %{buildroot}%{_bindir}/mysql_embedded rm -rf %{buildroot}%{_bindir}/mysql_setpermission rm -rf %{buildroot}%{_mandir}/man1/mysql_setpermission.1* -# Remove obsoleted man pages -rm -f %{buildroot}%{_mandir}/man1/mysql-stress-test.pl.1 -rm -f %{buildroot}%{_mandir}/man1/mysql-test-run.pl.1 -rm -f %{buildroot}%{_mandir}/man1/mysql_client_test.1 -rm -f %{buildroot}%{_mandir}/man1/mysql_client_test_embedded.1 -rm -f %{buildroot}%{_mandir}/man1/mysqltest.1 -rm -f %{buildroot}%{_mandir}/man1/mysqltest_embedded.1 - # rcmysql symlink install -d %{buildroot}%{_sbindir} ln -sf %{_initrddir}/mysql %{buildroot}%{_sbindir}/rcmysql @@ -742,6 +734,9 @@ fi %attr(755, root, root) %{_libdir}/mysql/libmysqld.so %changelog +* Wed Jan 10 2018 Bjorn Munch - 5.5.60-1 +- No longer need to remove obsoleted mysqltest man pages + * Tue Oct 31 2017 Bjorn Munch - 5.5.59-1 - Remove obsoleted mysqltest man pages diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 4060284ce9d..cb1462c57e5 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -1,4 +1,4 @@ -# Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2018, 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 @@ -621,12 +621,6 @@ install -m 644 "%{malloc_lib_source}" \ # Remove man pages we explicitly do not want to package, avoids 'unpackaged # files' warning. # This has become obsolete: rm -f $RBR%{_mandir}/man1/make_win_bin_dist.1* -rm -f $RBR%{_mandir}/man1/mysql-stress-test.pl.1 -rm -f $RBR%{_mandir}/man1/mysql-test-run.pl.1 -rm -f $RBR%{_mandir}/man1/mysql_client_test.1 -rm -f $RBR%{_mandir}/man1/mysql_client_test_embedded.1 -rm -f $RBR%{_mandir}/man1/mysqltest.1 -rm -f $RBR%{_mandir}/man1/mysqltest_embedded.1 ############################################################################## # Post processing actions, i.e. when installed @@ -1228,6 +1222,9 @@ echo "=====" >> $STATUS_HISTORY # merging BK trees) ############################################################################## %changelog +* Wed Jan 10 2018 Bjorn Munch +- No longer need to remove obsoleted mysqltest man pages + * Tue Oct 31 2017 Bjorn Munch - Remove obsoleted mysqltest man pages -- cgit v1.2.1 From 2af9e8af6efba951e33e148d0b1a34beb25be831 Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Thu, 11 Jan 2018 19:48:12 +0530 Subject: BUG#27160888: MISSING FILE PRIVILEDGE CHECKS ON SOME STATEMENTS ANALYSIS: ========= A user not having FILE privilege is not allowed to create custom data/index directories for a table or for its partitions via CREATE TABLE but is allowed to do so via ALTER TABLE statement. ALTER TABLE ignores DATA DIRECTORY and INDEX DIRECTORY when given as table options. The issue occurs during the creation of partitions for a table via ALTER TABLE statement with the DATA DIRECTORY and/or INDEX DIRECTORY options. The issue exists because of the absence of FILE privilege check for the user. FIX: ==== A FILE privilege check has been introduced for resolving the above scenario. --- sql/sql_alter.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 6247d581830..660efe2d177 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2018, 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 @@ -18,6 +18,8 @@ // mysql_exchange_partition #include "sql_alter.h" +bool has_external_data_or_index_dir(partition_info &pi); + bool Alter_table_statement::execute(THD *thd) { LEX *lex= thd->lex; @@ -42,6 +44,16 @@ bool Alter_table_statement::execute(THD *thd) if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */ DBUG_RETURN(TRUE); + +#ifdef WITH_PARTITION_STORAGE_ENGINE + { + partition_info *part_info= thd->lex->part_info; + if (part_info != NULL && has_external_data_or_index_dir(*part_info) && + check_access(thd, FILE_ACL, any_db, NULL, NULL, FALSE, FALSE)) + + DBUG_RETURN(TRUE); + } +#endif /* We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well as for RENAME TO, as being done by SQLCOM_RENAME_TABLE -- cgit v1.2.1 From 3fb2f8db179c2ea9a15fcc2f142c5b98c5aab17a Mon Sep 17 00:00:00 2001 From: Joao Gramacho Date: Fri, 2 Feb 2018 11:45:56 +0000 Subject: BUG#24365972 BINLOG DECODING ISN'T RESILIENT TO CORRUPT BINLOG FILES Problem ======= When facing decoding of corrupt binary log files, server may misbehave without detecting the events corruption. This patch makes MySQL server more resilient to binary log decoding. Fixes for events de-serialization and apply =========================================== @sql/log_event.cc Query_log_event::Query_log_event: added a check to ensure query length is respecting event buffer limits. Query_log_event::do_apply_event: extended a debug print, added a check to character set to determine if it is "parseable" or not, verified if database name is valid for system collation. Start_log_event_v3::do_apply_event: report an error on applying a non-supported binary log version. Load_log_event::copy_log_event: added a check to table_name length. User_var_log_event::User_var_log_event: added checks to avoid reading out of buffer limits. User_var_log_event::do_apply_event: reported an sanity check error properly and added individual sanity checks for variable types that expect fixed (or minimum) amount of bytes to be read. Rows_log_event::Rows_log_event: added checks to avoid reading out of buffer limits. @sql/log_event_old.cc Old_rows_log_event::Old_rows_log_event: added a sanity check to avoid reading out of buffer limits. @sql/sql_priv.h Added a sanity check to available_buffer() function. --- sql/log_event.cc | 126 ++++++++++++++++++++++++++++++++++++++++++++++++--- sql/log_event_old.cc | 11 ++++- sql/sql_priv.h | 7 ++- 3 files changed, 136 insertions(+), 8 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 5dbeb1eb4b9..ac1e105be8c 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2018, 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 @@ -3024,6 +3024,25 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, db= (char *)start; query= (char *)(start + db_len + 1); q_len= data_len - db_len -1; + + if (data_len && (data_len < db_len || + data_len < q_len || + data_len != (db_len + q_len + 1))) + { + q_len= 0; + query= NULL; + DBUG_VOID_RETURN; + } + + unsigned int max_length; + max_length= (event_len - ((const char*)(end + db_len + 1) - + (buf - common_header_len))); + if (q_len != max_length) + { + q_len= 0; + query= NULL; + DBUG_VOID_RETURN; + } /** Append the db length at the end of the buffer. This will be used by Query_cache::send_result_to_client() in case the query cache is On. @@ -3278,6 +3297,26 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, you. */ thd->catalog= catalog_len ? (char *) catalog : (char *)""; + + size_t valid_len; + bool len_error; + bool is_invalid_db_name= validate_string(system_charset_info, db, db_len, + &valid_len, &len_error); + + DBUG_PRINT("debug",("is_invalid_db_name= %s, valid_len=%zu, len_error=%s", + is_invalid_db_name ? "true" : "false", + valid_len, + len_error ? "true" : "false")); + + if (is_invalid_db_name || len_error) + { + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER_THD(thd, ER_SLAVE_FATAL_ERROR), + "Invalid database name in Query event."); + thd->is_slave_error= true; + goto end; + } + new_db.length= db_len; new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length); thd->set_db(new_db.str, new_db.length); /* allocates a copy of 'db' */ @@ -3454,7 +3493,23 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, } else thd->variables.collation_database= thd->db_charset; - + + { + const CHARSET_INFO *cs= thd->charset(); + /* + We cannot ask for parsing a statement using a character set + without state_maps (parser internal data). + */ + if (!cs->state_map) + { + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER_THD(thd, ER_SLAVE_FATAL_ERROR), + "character_set cannot be parsed"); + thd->is_slave_error= true; + goto end; + } + } + thd->table_map_for_update= (table_map)table_map_for_update; thd->set_invoker(&user, &host); /* @@ -3898,7 +3953,13 @@ int Start_log_event_v3::do_apply_event(Relay_log_info const *rli) */ break; default: - /* this case is impossible */ + /* + This case is not expected. It can be either an event corruption or an + unsupported binary log version. + */ + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER_THD(thd, ER_SLAVE_FATAL_ERROR), + "Binlog version not supported"); DBUG_RETURN(1); } DBUG_RETURN(error); @@ -4724,6 +4785,9 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, fields = (char*)field_lens + num_fields; table_name = fields + field_block_len; + if (strlen(table_name) > NAME_LEN) + goto err; + db = table_name + table_name_len + 1; DBUG_EXECUTE_IF ("simulate_invalid_address", db_len = data_len;); @@ -5889,6 +5953,13 @@ User_var_log_event(const char* buf, uint event_len, buf+= description_event->common_header_len + description_event->post_header_len[USER_VAR_EVENT-1]; name_len= uint4korr(buf); + /* Avoid reading out of buffer */ + if ((buf - buf_start) + UV_NAME_LEN_SIZE + name_len > event_len) + { + error= true; + goto err; + } + name= (char *) buf + UV_NAME_LEN_SIZE; /* @@ -5948,8 +6019,11 @@ User_var_log_event(const char* buf, uint event_len, we keep the flags set to UNDEF_F. */ uint bytes_read= ((val + val_len) - start); - DBUG_ASSERT(bytes_read==data_written || - bytes_read==(data_written-1)); + if (bytes_read > event_len) + { + error= true; + goto err; + } if ((data_written - bytes_read) > 0) { flags= (uint) *(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + @@ -6165,7 +6239,12 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) } if (!(charset= get_charset(charset_number, MYF(MY_WME)))) + { + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER_THD(thd, ER_SLAVE_FATAL_ERROR), + "Invalid character set for User var event"); return 1; + } LEX_STRING user_var_name; user_var_name.str= name; user_var_name.length= name_len; @@ -6186,12 +6265,26 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) { switch (type) { case REAL_RESULT: + if (val_len != 8) + { + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER_THD(thd, ER_SLAVE_FATAL_ERROR), + "Invalid variable length at User var event"); + return 1; + } float8get(real_val, val); it= new Item_float(real_val, 0); val= (char*) &real_val; // Pointer to value in native format val_len= 8; break; case INT_RESULT: + if (val_len != 8) + { + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER_THD(thd, ER_SLAVE_FATAL_ERROR), + "Invalid variable length at User var event"); + return 1; + } int_val= (longlong) uint8korr(val); it= new Item_int(int_val); val= (char*) &int_val; // Pointer to value in native format @@ -6199,6 +6292,13 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) break; case DECIMAL_RESULT: { + if (val_len < 3) + { + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER_THD(thd, ER_SLAVE_FATAL_ERROR), + "Invalid variable length at User var event"); + return 1; + } Item_decimal *dec= new Item_decimal((uchar*) val+2, val[0], val[1]); it= dec; val= (char *)dec->val_decimal(NULL); @@ -7646,6 +7746,15 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, DBUG_PRINT("debug", ("Reading from %p", ptr_after_width)); m_width = net_field_length(&ptr_after_width); DBUG_PRINT("debug", ("m_width=%lu", m_width)); + /* Avoid reading out of buffer */ + if (static_cast((ptr_after_width + + (m_width + 7) / 8) - + (uchar*)buf) > event_len) + { + m_cols.bitmap= NULL; + DBUG_VOID_RETURN; + } + /* if bitmap_init fails, catched in is_valid() */ if (likely(!bitmap_init(&m_cols, m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL, @@ -7694,7 +7803,12 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, const uchar* const ptr_rows_data= (const uchar*) ptr_after_width; - size_t const data_size= event_len - (ptr_rows_data - (const uchar *) buf); + size_t const read_size= ptr_rows_data - (const unsigned char *) buf; + if (read_size > event_len) + { + DBUG_VOID_RETURN; + } + size_t const data_size= event_len - read_size; DBUG_PRINT("info",("m_table_id: %lu m_flags: %d m_width: %lu data_size: %lu", m_table_id, m_flags, m_width, (ulong) data_size)); diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index eb9678ddaa5..6be4e086925 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2007, 2018, 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 @@ -1357,6 +1357,15 @@ Old_rows_log_event::Old_rows_log_event(const char *buf, uint event_len, DBUG_PRINT("debug", ("Reading from %p", ptr_after_width)); m_width = net_field_length(&ptr_after_width); DBUG_PRINT("debug", ("m_width=%lu", m_width)); + /* Avoid reading out of buffer */ + if (static_cast(m_width + + (ptr_after_width - + (const uchar *)buf)) > event_len) + { + m_cols.bitmap= NULL; + DBUG_VOID_RETURN; + } + /* if bitmap_init fails, catched in is_valid() */ if (likely(!bitmap_init(&m_cols, m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL, diff --git a/sql/sql_priv.h b/sql/sql_priv.h index 523220b3c03..b12d22e3fc7 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2018, 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 @@ -191,6 +191,11 @@ template T available_buffer(const char* buf_start, const char* buf_current, T buf_len) { + /* Sanity check */ + if (buf_current < buf_start || + buf_len < static_cast(buf_current - buf_start)) + return static_cast(0); + return buf_len - (buf_current - buf_start); } -- cgit v1.2.1 From e585decb459740ec53b1ac1b85f332f7bd3c8ccf Mon Sep 17 00:00:00 2001 From: Pavan Naik Date: Mon, 5 Feb 2018 19:30:37 +0530 Subject: BUG#27448061: MYSQLD--DEFAULTS-FILE TEST FAILS FOR NDB RELEASES PREVIOUS TO MYSQL 8.0 Description : ------------- The mysqld--defaults-file test fails when the test suite is run from a non-canonical path, which happens when the current working directory when mysql-test-run.pl is started contains a symbolic link. The problem is that this test case uses --replace-result with $MYSQL_TEST_DIR. This variable is a potentially non-canonical path based on the current working directory when mtr is started. However, the path in the expected error message from mysqld contains a canonical path. This means it does not contain $MYSQL_TEST_DIR if mtr's working directory is not the canonical path of the working directory. Because other tests produce output that may contain non-canonical paths, making $MYSQL_TEST_DIR always canonical is not a fix. Fix : ----- Introduced a new environment variable '$ABS_MYSQL_TEST_DIR' which will contin the canonical path to the test directory and replaced $MYSQL_TEST_DIR with the new variable in main.mysqld--defaults-file test file. This is a back-port of BUG#24579973. Change-Id: I3b8df6f2d7ce2b04e188a896d76250cc1addbbc1 --- mysql-test/mysql-test-run.pl | 3 ++- mysql-test/t/mysqld--defaults-file.test | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 2ca5c83e3f4..99d3203fb51 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # -*- cperl -*- -# Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2018, 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 @@ -2344,6 +2344,7 @@ sub environment_setup { $ENV{'DEFAULT_MASTER_PORT'}= $mysqld_variables{'port'}; $ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir; $ENV{'MYSQLTEST_VARDIR'}= $opt_vardir; + $ENV{'MYSQL_TEST_DIR_ABS'}= getcwd(); $ENV{'MYSQL_BINDIR'}= "$bindir"; $ENV{'MYSQL_SHAREDIR'}= $path_language; $ENV{'MYSQL_CHARSETSDIR'}= $path_charsetsdir; diff --git a/mysql-test/t/mysqld--defaults-file.test b/mysql-test/t/mysqld--defaults-file.test index 3bfe0aa891f..e2d5b40adbc 100644 --- a/mysql-test/t/mysqld--defaults-file.test +++ b/mysql-test/t/mysqld--defaults-file.test @@ -13,19 +13,21 @@ exec $MYSQLD --defaults-file=/path/with/no/extension --print-defaults 2>&1; --error 1 exec $MYSQLD --defaults-file=/path/with.ext --print-defaults 2>&1; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +# Using $MYSQL_TEST_DIR_ABS which contains canonical path to the +# test directory since --print-default prints the absolute path. +--replace_result $MYSQL_TEST_DIR_ABS MYSQL_TEST_DIR --error 1 exec $MYSQLD --defaults-file=relative/path/with.ext --print-defaults 2>&1; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +--replace_result $MYSQL_TEST_DIR_ABS MYSQL_TEST_DIR --error 1 exec $MYSQLD --defaults-file=relative/path/without/extension --print-defaults 2>&1; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +--replace_result $MYSQL_TEST_DIR_ABS MYSQL_TEST_DIR --error 1 exec $MYSQLD --defaults-file=with.ext --print-defaults 2>&1; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +--replace_result $MYSQL_TEST_DIR_ABS MYSQL_TEST_DIR --error 1 exec $MYSQLD --defaults-file=no_extension --print-defaults 2>&1; -- cgit v1.2.1 From e4784703ee44d0a0a497a1a411dea20987d501ad Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Mon, 12 Feb 2018 15:19:43 +0530 Subject: Bug#25471090: MYSQL USE AFTER FREE Description:- Mysql client crashes when trying to connect to a fake server which is sending incorrect packets. Analysis:- Mysql client crashes when it tries to read server version details. Fix:- A check is added in "red_one_row()". --- include/mysql_com.h | 3 ++- sql-common/client.c | 16 +++++++++------- sql-common/pack.c | 37 +++++++++++++++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 5cd40915743..52e8a367e3d 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2018, 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,6 +561,7 @@ void my_thread_end(void); #ifdef _global_h ulong STDCALL net_field_length(uchar **packet); +ulong STDCALL net_field_length_checked(uchar **packet, ulong max_length); my_ulonglong net_field_length_ll(uchar **packet); uchar *net_store_length(uchar *pkg, ulonglong length); #endif diff --git a/sql-common/client.c b/sql-common/client.c index 759d95117cb..9972ca741f2 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2003, 2018, 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 @@ -1723,18 +1723,20 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) end_pos=pos+pkt_len; for (field=0 ; field < fields ; field++) { - if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH) + len=(ulong) net_field_length_checked(&pos, (ulong)(end_pos - pos)); + if (pos > end_pos) + { + set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate); + return -1; + } + + if (len == NULL_LENGTH) { /* null field */ row[field] = 0; *lengths++=0; } else { - if (len > (ulong) (end_pos - pos)) - { - set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate); - return -1; - } row[field] = (char*) pos; pos+=len; *lengths++=len; diff --git a/sql-common/pack.c b/sql-common/pack.c index 02e91b5c3e3..57ff55689a2 100644 --- a/sql-common/pack.c +++ b/sql-common/pack.c @@ -1,5 +1,4 @@ -/* Copyright (c) 2000-2003, 2007 MySQL AB - Use is subject to license terms +/* Copyright (c) 2000, 2018 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 @@ -46,6 +45,40 @@ ulong STDCALL net_field_length(uchar **packet) return (ulong) uint4korr(pos+1); } +/* The same as above but with max length check */ +ulong STDCALL net_field_length_checked(uchar **packet, ulong max_length) +{ + ulong len; + uchar *pos= (uchar *)*packet; + + if (*pos < 251) + { + (*packet)++; + len= (ulong) *pos; + return (len > max_length) ? max_length : len; + } + if (*pos == 251) + { + (*packet)++; + return NULL_LENGTH; + } + if (*pos == 252) + { + (*packet)+=3; + len= (ulong) uint2korr(pos+1); + return (len > max_length) ? max_length : len; + } + if (*pos == 253) + { + (*packet)+=4; + len= (ulong) uint3korr(pos+1); + return (len > max_length) ? max_length : len; + } + (*packet)+=9; /* Must be 254 when here */ + len= (ulong) uint4korr(pos+1); + return (len > max_length) ? max_length : len; +} + /* The same as above but returns longlong */ my_ulonglong net_field_length_ll(uchar **packet) { -- cgit v1.2.1 From ddaf0f14704be3fd3d6960f7a3e2fdd0125e2dfd Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Wed, 14 Feb 2018 09:35:18 +0530 Subject: --- storage/innobase/handler/ha_innodb.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 1c6763ef93a..0591987f4ae 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. @@ -9225,8 +9225,10 @@ ha_innobase::start_stmt( case SQLCOM_INSERT: case SQLCOM_UPDATE: case SQLCOM_DELETE: + case SQLCOM_REPLACE: init_table_handle_for_HANDLER(); prebuilt->select_lock_type = LOCK_X; + prebuilt->stored_select_lock_type = LOCK_X; error = row_lock_table_for_mysql(prebuilt, NULL, 1); if (error != DB_SUCCESS) { -- cgit v1.2.1 From 873f8c25b6de24d267cbdedc70de40dc4b5b83aa Mon Sep 17 00:00:00 2001 From: Lars Tangvald Date: Tue, 13 Feb 2018 13:58:43 +0100 Subject: Bug#27538614 DROP EXTRA CHANGELOG FILE FROM DEB/RPM PACKAGES Change the file to refer to published git repository directly --- Docs/ChangeLog | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Docs/ChangeLog diff --git a/Docs/ChangeLog b/Docs/ChangeLog new file mode 100644 index 00000000000..05c9065c3b9 --- /dev/null +++ b/Docs/ChangeLog @@ -0,0 +1,2 @@ +You can find a detailed list of changes at + to https://github.com/mysql/mysql-server/commits/5.5 -- cgit v1.2.1 From c0b4d74b52e7eec9b13af732193f7f8d7abe05de Mon Sep 17 00:00:00 2001 From: Nisha Gopalakrishnan Date: Mon, 26 Feb 2018 14:37:39 +0530 Subject: BUG#27216817: INNODB: FAILING ASSERTION: PREBUILT->TABLE->N_MYSQL_HANDLES_OPENED == 1 ANALYSIS: ========= Adding unique index to a InnoDB table which is locked as mutliple instances may trigger an InnoDB assert. When we add a primary key or an unique index, we need to drop the original table and rebuild all indexes. InnoDB expects that only the instance of the table that is being rebuilt, is open during the process. In the current scenario we have opened multiple instances of the table. This triggers an assert during table rebuild. 'Locked_tables_list' encapsulates a list of all instances of tables locked by LOCK TABLES statement. FIX: === We are now temporarily closing all the instances of the table except the one which is being altered and later reopen them via Locked_tables_list::reopen_tables(). --- sql/sql_admin.cc | 4 ++-- sql/sql_base.cc | 18 +++++++++++++----- sql/sql_base.h | 5 +++-- sql/sql_partition.cc | 6 +++--- sql/sql_table.cc | 22 ++++++++++++++++++---- sql/sql_trigger.cc | 4 ++-- sql/sql_truncate.cc | 4 ++-- 7 files changed, 43 insertions(+), 20 deletions(-) diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index efdb67d01c4..bfe4edb67c4 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights +/* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify @@ -168,7 +168,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, */ if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) goto end; - close_all_tables_for_name(thd, table_list->table->s, FALSE); + close_all_tables_for_name(thd, table_list->table->s, FALSE, NULL); table_list->table= 0; } /* diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 27dcbee7b8f..e9ce652cdb1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2018, 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 @@ -1096,7 +1096,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, result= TRUE; goto err_with_reopen; } - close_all_tables_for_name(thd, table->s, FALSE); + close_all_tables_for_name(thd, table->s, FALSE, NULL); } } @@ -1367,13 +1367,16 @@ static void close_open_tables(THD *thd) In that case the documented behaviour is to implicitly remove the table from LOCK TABLES list. + @param[in] skip_table + TABLE instance that should be kept open. @pre Must be called with an X MDL lock on the table. */ void close_all_tables_for_name(THD *thd, TABLE_SHARE *share, - bool remove_from_locked_tables) + bool remove_from_locked_tables, + TABLE *skip_table) { char key[MAX_DBKEY_LENGTH]; uint key_length= share->table_cache_key.length; @@ -1388,7 +1391,8 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, TABLE *table= *prev; if (table->s->table_cache_key.length == key_length && - !memcmp(table->s->table_cache_key.str, key, key_length)) + !memcmp(table->s->table_cache_key.str, key, key_length) && + table != skip_table) { thd->locked_tables_list.unlink_from_list(thd, table->pos_in_locked_tables, @@ -1401,7 +1405,8 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, mysql_lock_remove(thd, thd->lock, table); /* Inform handler that table will be dropped after close */ - if (table->db_stat) /* Not true for partitioned tables. */ + if (table->db_stat && /* Not true for partitioned tables. */ + skip_table == NULL) table->file->extra(HA_EXTRA_PREPARE_FOR_DROP); close_thread_table(thd, prev); } @@ -1411,9 +1416,12 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, prev= &table->next; } } + + if (skip_table == NULL) { /* Remove the table share from the cache. */ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db, table_name, FALSE); + } } diff --git a/sql/sql_base.h b/sql/sql_base.h index b118c93ac28..28568acc081 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2018, 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 @@ -306,7 +306,8 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool wait_for_refresh, ulong timeout); bool close_cached_connection_tables(THD *thd, LEX_STRING *connect_string); void close_all_tables_for_name(THD *thd, TABLE_SHARE *share, - bool remove_from_locked_tables); + bool remove_from_locked_tables, + TABLE *skip_table); OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild); void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type, const char *db, const char *table_name, diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 65d4da0f2f6..bd76a92dc68 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2005, 2018, 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 @@ -6512,7 +6512,7 @@ static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt) THD *thd= lpt->thd; if (lpt->old_table) - close_all_tables_for_name(thd, lpt->old_table->s, FALSE); + close_all_tables_for_name(thd, lpt->old_table->s, FALSE, NULL); if (lpt->table) { /* @@ -6549,7 +6549,7 @@ static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt, bool close_old) } if (close_old && lpt->old_table) { - close_all_tables_for_name(lpt->thd, lpt->old_table->s, FALSE); + close_all_tables_for_name(lpt->thd, lpt->old_table->s, FALSE, NULL); lpt->old_table= 0; } DBUG_RETURN(0); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 58bcf5ca1d4..6d02140cfcb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2018, 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 @@ -2165,7 +2165,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, error= -1; goto err; } - close_all_tables_for_name(thd, table->table->s, TRUE); + close_all_tables_for_name(thd, table->table->s, TRUE, NULL); table->table= 0; } @@ -6168,7 +6168,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, */ if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) goto err; - close_all_tables_for_name(thd, table->s, TRUE); + close_all_tables_for_name(thd, table->s, TRUE, NULL); /* Then, we want check once again that target table does not exist. Actually the order of these two steps does not matter since @@ -6305,6 +6305,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, changes only" means also that the handler for the table does not change. The table is open and locked. The handler can be accessed. */ + if (need_copy_table == ALTER_TABLE_INDEX_CHANGED) { int pk_changed= 0; @@ -6606,6 +6607,19 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields thd->cuted_fields=0L; copied=deleted=0; + + if (thd->locked_tables_mode == LTM_LOCK_TABLES || + thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) + { + /* + Temporarily close the TABLE instances belonging to this + thread except the one to be used for ALTER TABLE. + + This is mostly needed to satisfy InnoDB assumptions/asserts. + */ + close_all_tables_for_name(thd, table->s, false, table); + } + /* We do not copy data for MERGE tables. Only the children have data. MERGE tables have HA_NO_COPY_ON_ALTER set. @@ -6877,7 +6891,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } close_all_tables_for_name(thd, table->s, - new_name != table_name || new_db != db); + new_name != table_name || new_db != db, NULL); error=0; table_list->table= table= 0; /* Safety */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 0a4f549a052..fe1131c4164 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2004, 2018, 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 @@ -568,7 +568,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) if (result) goto end; - close_all_tables_for_name(thd, table->s, FALSE); + close_all_tables_for_name(thd, table->s, FALSE, NULL); /* Reopen the table if we were under LOCK TABLES. Ignore the return value for now. It's better to diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 4f250e6e7a0..d8a0205a495 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2018, 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 @@ -394,7 +394,7 @@ bool Truncate_statement::lock_table(THD *thd, TABLE_LIST *table_ref, m_ticket_downgrade= table->mdl_ticket; /* Close if table is going to be recreated. */ if (*hton_can_recreate) - close_all_tables_for_name(thd, table->s, FALSE); + close_all_tables_for_name(thd, table->s, FALSE, NULL); } else { -- cgit v1.2.1 From 6beb08c7b67ed7610e95c0350f9f93005db1e055 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 4 Apr 2018 09:12:14 +0400 Subject: MDEV-15624 Changing the default character set to utf8mb4 changes query evaluation in a very surprising way --- mysql-test/r/ctype_ucs.result | 31 +++++++++++++++++++++++++++++++ mysql-test/r/ctype_utf8mb4.result | 23 +++++++++++++++++++++++ mysql-test/t/ctype_ucs.test | 22 ++++++++++++++++++++++ mysql-test/t/ctype_utf8mb4.test | 19 +++++++++++++++++++ sql/item_func.h | 2 ++ sql/item_strfunc.h | 1 + 6 files changed, 98 insertions(+) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 1bbd3af4af7..1c9e31d3a06 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -4397,5 +4397,36 @@ Field Type Null Key Default Extra c1 mediumtext YES NULL DROP TABLE t1; # +# MDEV-15624 Changing the default character set to utf8mb4 changes query evaluation in a very surprising way +# +SET NAMES utf8; +CREATE TABLE t1 (id INT); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT COUNT(DISTINCT c) FROM (SELECT id, REPLACE(uuid_short(), '0', CAST('o' AS CHAR CHARACTER SET ucs2)) AS c FROM t1) AS d1; +COUNT(DISTINCT c) +3 +SELECT DISTINCT REPLACE(uuid_short(), '0', CAST('o' AS CHAR CHARACTER SET ucs2)) AS c FROM t1; +c +xxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxx +SELECT COUNT(DISTINCT c) FROM (SELECT id, INSERT(uuid_short(), 1, 1, CAST('0' AS CHAR CHARACTER SET ucs2)) AS c FROM t1) AS d1; +COUNT(DISTINCT c) +3 +SELECT DISTINCT INSERT(uuid_short(), 1, 1, CAST('0' AS CHAR CHARACTER SET ucs2)) AS c FROM t1; +c +xxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxx +SELECT COUNT(DISTINCT c) FROM (SELECT id, CONCAT(uuid_short(), CAST('0' AS CHAR CHARACTER SET ucs2)) AS c FROM t1) AS d1; +COUNT(DISTINCT c) +3 +SELECT DISTINCT CONCAT(uuid_short(), CAST('0' AS CHAR CHARACTER SET ucs2)) AS c FROM t1; +c +xxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxx +DROP TABLE t1; +# # End of 5.5 tests # diff --git a/mysql-test/r/ctype_utf8mb4.result b/mysql-test/r/ctype_utf8mb4.result index 17a1a2f787e..2c0bdfb2307 100644 --- a/mysql-test/r/ctype_utf8mb4.result +++ b/mysql-test/r/ctype_utf8mb4.result @@ -2656,6 +2656,29 @@ SELECT LENGTH(data) AS len FROM (SELECT REPEAT('☃', 65536) AS data ) AS sub; len 196608 # +# MDEV-15624 Changing the default character set to utf8mb4 changes query evaluation in a very surprising way +# +SET NAMES utf8mb4; +CREATE TABLE t1 (id INT); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT COUNT(DISTINCT c) FROM (SELECT id, REPLACE(UUID(), "-", "") AS c FROM t1) AS d1; +COUNT(DISTINCT c) +3 +SELECT DISTINCT INSERT(uuid(), 9, 1, "X") AS c FROM t1; +c +xxxxxxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx +xxxxxxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx +xxxxxxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx +SELECT COUNT(DISTINCT c) FROM (SELECT id, INSERT(UUID(), 9, 1, "X") AS c FROM t1) AS d1; +COUNT(DISTINCT c) +3 +SELECT DISTINCT INSERT(UUID(), 9, 1, "X") AS c FROM t1; +c +xxxxxxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx +xxxxxxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx +xxxxxxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx +DROP TABLE t1; +# # End of 5.5 tests # # diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index b3d0be4432f..6f846eae771 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -885,6 +885,28 @@ DESCRIBE t1; DROP TABLE t1; +--echo # +--echo # MDEV-15624 Changing the default character set to utf8mb4 changes query evaluation in a very surprising way +--echo # + +SET NAMES utf8; +CREATE TABLE t1 (id INT); +INSERT INTO t1 VALUES (1),(2),(3); + +SELECT COUNT(DISTINCT c) FROM (SELECT id, REPLACE(uuid_short(), '0', CAST('o' AS CHAR CHARACTER SET ucs2)) AS c FROM t1) AS d1; +--replace_column 1 xxxxxxxxxxxxxxxxx +SELECT DISTINCT REPLACE(uuid_short(), '0', CAST('o' AS CHAR CHARACTER SET ucs2)) AS c FROM t1; + +SELECT COUNT(DISTINCT c) FROM (SELECT id, INSERT(uuid_short(), 1, 1, CAST('0' AS CHAR CHARACTER SET ucs2)) AS c FROM t1) AS d1; +--replace_column 1 xxxxxxxxxxxxxxxxx +SELECT DISTINCT INSERT(uuid_short(), 1, 1, CAST('0' AS CHAR CHARACTER SET ucs2)) AS c FROM t1; + +SELECT COUNT(DISTINCT c) FROM (SELECT id, CONCAT(uuid_short(), CAST('0' AS CHAR CHARACTER SET ucs2)) AS c FROM t1) AS d1; +--replace_column 1 xxxxxxxxxxxxxxxxx +SELECT DISTINCT CONCAT(uuid_short(), CAST('0' AS CHAR CHARACTER SET ucs2)) AS c FROM t1; +DROP TABLE t1; + + --echo # --echo # End of 5.5 tests --echo # diff --git a/mysql-test/t/ctype_utf8mb4.test b/mysql-test/t/ctype_utf8mb4.test index c240f261af4..551a570c0fc 100644 --- a/mysql-test/t/ctype_utf8mb4.test +++ b/mysql-test/t/ctype_utf8mb4.test @@ -1858,6 +1858,25 @@ SELECT LENGTH(data) AS len FROM (SELECT REPEAT('☃', 21846) AS data ) AS sub; SELECT LENGTH(data) AS len FROM (SELECT REPEAT('☃', 65535) AS data ) AS sub; SELECT LENGTH(data) AS len FROM (SELECT REPEAT('☃', 65536) AS data ) AS sub; +--echo # +--echo # MDEV-15624 Changing the default character set to utf8mb4 changes query evaluation in a very surprising way +--echo # + +SET NAMES utf8mb4; +CREATE TABLE t1 (id INT); +INSERT INTO t1 VALUES (1),(2),(3); + +SELECT COUNT(DISTINCT c) FROM (SELECT id, REPLACE(UUID(), "-", "") AS c FROM t1) AS d1; +--replace_column 1 xxxxxxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx +SELECT DISTINCT INSERT(uuid(), 9, 1, "X") AS c FROM t1; + +SELECT COUNT(DISTINCT c) FROM (SELECT id, INSERT(UUID(), 9, 1, "X") AS c FROM t1) AS d1; +--replace_column 1 xxxxxxxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx +SELECT DISTINCT INSERT(UUID(), 9, 1, "X") AS c FROM t1; + +DROP TABLE t1; + + --echo # --echo # End of 5.5 tests --echo # diff --git a/sql/item_func.h b/sql/item_func.h index 60122f03e0b..57818228b98 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2133,6 +2133,8 @@ public: Item_func_uuid_short() :Item_int_func() {} const char *func_name() const { return "uuid_short"; } longlong val_int(); + bool const_item() const { return false; } + table_map used_tables() const { return RAND_TABLE_BIT; } void fix_length_and_dec() { max_length= 21; unsigned_flag=1; } bool check_vcol_func_processor(uchar *int_arg) diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 006b1b90081..c1138c2a930 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -997,6 +997,7 @@ public: DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); fix_char_length(MY_UUID_STRING_LENGTH); } + bool const_item() const { return false; } table_map used_tables() const { return RAND_TABLE_BIT; } const char *func_name() const{ return "uuid"; } String *val_str(String *); -- cgit v1.2.1 From d6f3a0064be73cd134fd474e5ddc63646e09938a Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sat, 7 Apr 2018 21:51:15 +0400 Subject: MDEV-14185 CREATE TEMPORARY TABLE AS SELECT causes error 1290 with read_only and InnoDB. handler::ha_create_handler_files shouldn't call the mark_trx_read_write() for the temporary table. --- mysql-test/r/read_only_innodb.result | 8 ++++++++ mysql-test/t/read_only_innodb.test | 9 +++++++++ sql/handler.cc | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/read_only_innodb.result b/mysql-test/r/read_only_innodb.result index 1e041395d3c..2af72d30851 100644 --- a/mysql-test/r/read_only_innodb.result +++ b/mysql-test/r/read_only_innodb.result @@ -221,6 +221,14 @@ a a 5 10 DROP TABLE temp1, temp2; +# MDEV-14185 CREATE TEMPORARY TABLE AS SELECT causes error 1290 with read_only and InnoDB. + +CREATE TEMPORARY TABLE temp1 ENGINE=INNODB AS SELECT a FROM t1; +SELECT * FROM temp1; +a +1 +DROP TABLE temp1; + # Disconnect and cleanup SET GLOBAL READ_ONLY = OFF; diff --git a/mysql-test/t/read_only_innodb.test b/mysql-test/t/read_only_innodb.test index de237fecbb6..f89cf745973 100644 --- a/mysql-test/t/read_only_innodb.test +++ b/mysql-test/t/read_only_innodb.test @@ -243,6 +243,15 @@ UPDATE temp1,temp2 SET temp1.a = 5, temp2.a = 10; SELECT * FROM temp1, temp2; DROP TABLE temp1, temp2; +--echo +--echo # MDEV-14185 CREATE TEMPORARY TABLE AS SELECT causes error 1290 with read_only and InnoDB. +--echo + +CREATE TEMPORARY TABLE temp1 ENGINE=INNODB AS SELECT a FROM t1; +SELECT * FROM temp1; +DROP TABLE temp1; + + --echo --echo # Disconnect and cleanup --echo diff --git a/sql/handler.cc b/sql/handler.cc index dc40e34bc3d..d8a9ac6b05a 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3770,7 +3770,8 @@ int handler::ha_create_handler_files(const char *name, const char *old_name, int action_flag, HA_CREATE_INFO *info) { - mark_trx_read_write(); + if (!info || !(info->options & HA_LEX_CREATE_TMP_TABLE)) + mark_trx_read_write(); return create_handler_files(name, old_name, action_flag, info); } -- cgit v1.2.1 From 3eb2a265eac53050089bc5d563e65161717a2983 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sun, 8 Apr 2018 09:05:00 +0400 Subject: MDEV-14185 CREATE TEMPORARY TABLE AS SELECT causes error 1290 with read_only and InnoDB. condition fixed. --- sql/handler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/handler.cc b/sql/handler.cc index d8a9ac6b05a..ab4d9fd37c9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3770,7 +3770,7 @@ int handler::ha_create_handler_files(const char *name, const char *old_name, int action_flag, HA_CREATE_INFO *info) { - if (!info || !(info->options & HA_LEX_CREATE_TMP_TABLE)) + if (!opt_readonly || !info || !(info->options & HA_LEX_CREATE_TMP_TABLE)) mark_trx_read_write(); return create_handler_files(name, old_name, action_flag, info); -- cgit v1.2.1 From 88ac368fea2182447284d6bacff4d93ef1acb865 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sat, 13 Jan 2018 14:05:14 +1100 Subject: defaults-group-suffix in print_defaults Also clarify which --{no-,}default* options, must be first. Sample output: $ client/mysql --help client/mysql Ver 15.1 Distrib 5.5.59-MariaDB, for Linux (x86_64) using readline 5.1 Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others. Usage: client/mysql [OPTIONS] [database] Default options are read from the following files in the given order: /etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf The following groups are read: mysql client client-server client-mariadb The following options may be given as the first argument: --print-defaults Print the program argument list and exit. --no-defaults Don't read default options from any option file. The following specify which files/groups are read (specified before other options): --defaults-file=# Only read default options from the given file #. --defaults-extra-file=# Read this file after the global files are read. --defaults-group-suffix=# Additionally read default groups with # appended as a suffix. tests running from build directory: TEST: print defaults ignored as not first $ sql/mysqld --no-defaults --print-defaults --lc-messages-dir=${PWD}/sql/share TEST: no startup occurs as --print-defaults specified $ sql/mysqld --print-defaults --lc-messages-dir=${PWD}/sql/share sql/mysqld would have been started with the following arguments: --lc-messages-dir=/home/dan/repos/build-mariadb-5.5/sql/share TEST: default args can't be anywhere $ client/mysql --user=bob --defaults-file=/etc/my.cnf client/mysql: unknown variable 'defaults-file=/etc/my.cnf' $ client/mysql --user=bob --defaults-group-suffix=.group client/mysql: unknown variable 'defaults-group-suffix=.group' /etc/my.cnf: [client-server.group] socket=/var/lib/mysql-multi/group/mysqld.sock user=bob /etc/my.other.cnf: socket=/var/lib/mysql-other/mysqld.sock TEST: defaults file read and suffix also applied $ client/mysql --defaults-file=/etc/my.other.cnf --defaults-group-suffix=.group ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql-other/mysqld.sock' (2) TEST: defaults extra file $ client/mysql --defaults-extra-file=/etc/my.other.cnf --defaults-group-suffix=.group ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql-other/mysqld.sock' (2) --- mysql-test/r/mysqld--help.result | 2 ++ mysys/default.c | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index ef68c064dd4..825c7e786a3 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1,8 +1,10 @@ The following options may be given as the first argument: --print-defaults Print the program argument list and exit. --no-defaults Don't read default options from any option file. +The following specify which files/extra groups are read (specified before remaining options): --defaults-file=# Only read default options from the given file #. --defaults-extra-file=# Read this file after the global files are read. +--defaults-group-suffix=# Additionally read default groups with # appended as a suffix. --allow-suspicious-udfs Allows use of UDFs consisting of only one symbol xxx() diff --git a/mysys/default.c b/mysys/default.c index 93a1eff37cb..e901fb0b593 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -1102,10 +1102,12 @@ void print_defaults(const char *conf_file, const char **groups) } } puts("\nThe following options may be given as the first argument:\n\ ---print-defaults Print the program argument list and exit.\n\ ---no-defaults Don't read default options from any option file.\n\ ---defaults-file=# Only read default options from the given file #.\n\ ---defaults-extra-file=# Read this file after the global files are read."); +--print-defaults Print the program argument list and exit.\n\ +--no-defaults Don't read default options from any option file.\n\ +The following specify which files/extra groups are read (specified before remaining options):\n\ +--defaults-file=# Only read default options from the given file #.\n\ +--defaults-extra-file=# Read this file after the global files are read.\n\ +--defaults-group-suffix=# Additionally read default groups with # appended as a suffix."); } -- cgit v1.2.1 From 5e61e1716e763315009318081fba5994b8910242 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Mon, 16 Apr 2018 16:59:19 -0700 Subject: MDEV-14515 ifnull result depends on number of rows in joined table Any expensive WHERE condition for a table-less query with implicit aggregation was lost. As a result the used aggregate functions were calculated over a non-empty set of rows even in the case when the condition was false. --- mysql-test/r/subselect4.result | 24 ++++++++++++++++++++++-- mysql-test/t/subselect4.test | 23 +++++++++++++++++++++++ sql/opt_subselect.cc | 1 + 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index c20c048b919..6accc23d18a 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -1056,7 +1056,7 @@ EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT min(f3)+f3, min(f4)+f3+max(f4) FROM t2 WHERE f3 > 10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No matching min/max row +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT min(f3)+f3, min(f4)+f3+max(f4) FROM t2 WHERE f3 > 10); f1 f2 SET @@optimizer_switch = 'materialization=off,in_to_exists=on,semijoin=off'; @@ -1147,7 +1147,7 @@ EXPLAIN SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT min(f3)+f3, min(f4)+f3+max(f4) FROM t2 WHERE f3 > 10); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE -2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No matching min/max row +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT min(f3)+f3, min(f4)+f3+max(f4) FROM t2 WHERE f3 > 10); f1 f2 set @@optimizer_switch=@save_optimizer_switch; @@ -2511,3 +2511,23 @@ SELECT 2 IN (SELECT 2 from DUAL WHERE 1 != 1); 0 SET optimizer_switch= @@global.optimizer_switch; set @@tmp_table_size= @@global.tmp_table_size; +# +# mfrv-14515: Wrong results for tableless query with subquery in WHERE +# and implicit aggregation +# +create table t1 (i1 int, i2 int); +insert into t1 values (1314, 1084),(1330, 1084),(1401, 1084),(580, 1084); +create table t2 (cd int); +insert into t2 values +(1330), (1330), (1330), (1330), (1330), (1330), (1330), (1330), +(1330), (1330), (1330), (1330), (1330), (1330), (1330), (1330); +select max(10) from dual +where exists (select 1 from t2 join t1 on t1.i1 = t2.cd and t1.i2 = 345); +max(10) +NULL +insert into t2 select * from t2; +select max(10) from dual +where exists (select 1 from t2 join t1 on t1.i1 = t2.cd and t1.i2 = 345); +max(10) +NULL +DROP TABLE t1,t2; diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index 673dc9be0b4..2b53b55b735 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -2045,3 +2045,26 @@ SELECT 2 IN (SELECT 2 from DUAL WHERE 1 != 1); SET optimizer_switch= @@global.optimizer_switch; set @@tmp_table_size= @@global.tmp_table_size; + +--echo # +--echo # mfrv-14515: Wrong results for tableless query with subquery in WHERE +--echo # and implicit aggregation +--echo # + +create table t1 (i1 int, i2 int); +insert into t1 values (1314, 1084),(1330, 1084),(1401, 1084),(580, 1084); + +create table t2 (cd int); +insert into t2 values + (1330), (1330), (1330), (1330), (1330), (1330), (1330), (1330), + (1330), (1330), (1330), (1330), (1330), (1330), (1330), (1330); + +select max(10) from dual + where exists (select 1 from t2 join t1 on t1.i1 = t2.cd and t1.i2 = 345); + +insert into t2 select * from t2; + +select max(10) from dual + where exists (select 1 from t2 join t1 on t1.i1 = t2.cd and t1.i2 = 345); + +DROP TABLE t1,t2; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index c21541c4b97..1bda84bacd7 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -5903,5 +5903,6 @@ bool JOIN::choose_tableless_subquery_plan() tmp_having= having; } } + exec_const_cond= conds; return FALSE; } -- cgit v1.2.1 From f1258e7cd2c57886e5eb4cf51b4ab3a9c030cbab Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 19 Apr 2018 22:32:27 +0200 Subject: BUG#26881798: SERVER EXITS WHEN PRIMARY KEY IN MYSQL.PROC IS DROPPED test case --- mysql-test/r/sp-destruct.result | 6 ++++++ mysql-test/t/sp-destruct.test | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/mysql-test/r/sp-destruct.result b/mysql-test/r/sp-destruct.result index 2dac0270ce1..b8f9a516d1e 100644 --- a/mysql-test/r/sp-destruct.result +++ b/mysql-test/r/sp-destruct.result @@ -174,3 +174,9 @@ create database mysqltest1; create procedure mysqltest1.foo() select "foo"; update mysql.proc set name='' where db='mysqltest1'; drop database mysqltest1; +create procedure p1() set @foo = 10; +alter table mysql.proc drop primary key; +drop procedure p1; +ERROR HY000: Cannot load from mysql.proc. The table is probably corrupted +alter table mysql.proc add primary key (db,name,type); +drop procedure p1; diff --git a/mysql-test/t/sp-destruct.test b/mysql-test/t/sp-destruct.test index 3a2e9259938..e5314f89fd5 100644 --- a/mysql-test/t/sp-destruct.test +++ b/mysql-test/t/sp-destruct.test @@ -289,3 +289,13 @@ create database mysqltest1; create procedure mysqltest1.foo() select "foo"; update mysql.proc set name='' where db='mysqltest1'; drop database mysqltest1; + +# +# BUG#26881798: SERVER EXITS WHEN PRIMARY KEY IN MYSQL.PROC IS DROPPED +# +create procedure p1() set @foo = 10; +alter table mysql.proc drop primary key; +--error ER_CANNOT_LOAD_FROM_TABLE +drop procedure p1; +alter table mysql.proc add primary key (db,name,type); +drop procedure p1; -- cgit v1.2.1 From 149c993b2cdf4b6ccdce6f8bbbd28a38fc7404ee Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 19 Apr 2018 22:36:46 +0200 Subject: BUG#27216817: INNODB: FAILING ASSERTION: PREBUILT->TABLE->N_MYSQL_HANDLES_OPENED == 1 disable online alter add primary key for innodb, if the table is opened/locked more than once in the current connection (see assert in ha_innobase::add_index()) --- .../suite/innodb/r/innodb_bug27216817.result | 24 +++++++++++++++++++ mysql-test/suite/innodb/t/innodb_bug27216817.test | 28 ++++++++++++++++++++++ storage/innobase/handler/ha_innodb.cc | 11 +++++++++ storage/innobase/handler/ha_innodb.h | 1 + storage/xtradb/handler/ha_innodb.cc | 11 +++++++++ storage/xtradb/handler/ha_innodb.h | 1 + 6 files changed, 76 insertions(+) create mode 100644 mysql-test/suite/innodb/r/innodb_bug27216817.result create mode 100644 mysql-test/suite/innodb/t/innodb_bug27216817.test diff --git a/mysql-test/suite/innodb/r/innodb_bug27216817.result b/mysql-test/suite/innodb/r/innodb_bug27216817.result new file mode 100644 index 00000000000..f930171ff23 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug27216817.result @@ -0,0 +1,24 @@ +create table t1 (a int not null, b int not null) engine=innodb; +insert t1 values (1,2),(3,4); +lock table t1 write, t1 tr read; +flush status; +alter table t1 add primary key (b); +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 3 +unlock tables; +alter table t1 drop primary key; +lock table t1 write; +flush status; +alter table t1 add primary key (b); +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +unlock tables; +alter table t1 drop primary key; +flush status; +alter table t1 add primary key (b); +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +drop table t1; diff --git a/mysql-test/suite/innodb/t/innodb_bug27216817.test b/mysql-test/suite/innodb/t/innodb_bug27216817.test new file mode 100644 index 00000000000..a93932b4a04 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug27216817.test @@ -0,0 +1,28 @@ +# +# BUG#27216817: INNODB: FAILING ASSERTION: +# PREBUILT->TABLE->N_MYSQL_HANDLES_OPENED == 1 +# + +source include/have_innodb.inc; +create table t1 (a int not null, b int not null) engine=innodb; +insert t1 values (1,2),(3,4); + +lock table t1 write, t1 tr read; +flush status; +alter table t1 add primary key (b); +show status like 'Handler_read_rnd_next'; +unlock tables; +alter table t1 drop primary key; + +lock table t1 write; +flush status; +alter table t1 add primary key (b); +show status like 'Handler_read_rnd_next'; +unlock tables; +alter table t1 drop primary key; + +flush status; +alter table t1 add primary key (b); +show status like 'Handler_read_rnd_next'; + +drop table t1; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c3bacee91ff..8da89918b84 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -11147,6 +11147,17 @@ ha_innobase::check_if_incompatible_data( return(COMPATIBLE_DATA_YES); } +UNIV_INTERN +uint +ha_innobase::alter_table_flags(uint flags) +{ + uint mask = 0; + if (prebuilt->table->n_mysql_handles_opened > 1) { + mask = HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE; + } + return innobase_alter_table_flags(flags) & ~mask; +} + /************************************************************//** Validate the file format name and return its corresponding id. @return valid file format id */ diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 42aae4dc20e..f80330d6128 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -228,6 +228,7 @@ class ha_innobase: public handler /** @} */ bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes); + uint alter_table_flags(uint flags); }; /* Some accessor functions which the InnoDB plugin needs, but which diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index a17ab44f49d..94e49d4897a 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -12480,6 +12480,17 @@ ha_innobase::check_if_incompatible_data( DBUG_RETURN(COMPATIBLE_DATA_YES); } +UNIV_INTERN +uint +ha_innobase::alter_table_flags(uint flags) +{ + uint mask = 0; + if (prebuilt->table->n_mysql_handles_opened > 1) { + mask = HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE; + } + return innobase_alter_table_flags(flags) & ~mask; +} + /************************************************************//** Validate the file format name and return its corresponding id. @return valid file format id */ diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h index 914055a9271..2c3011b0bbb 100644 --- a/storage/xtradb/handler/ha_innodb.h +++ b/storage/xtradb/handler/ha_innodb.h @@ -230,6 +230,7 @@ class ha_innobase: public handler /** @} */ bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes); + uint alter_table_flags(uint flags); bool check_if_supported_virtual_columns(void) { return TRUE; } private: -- cgit v1.2.1 From 7828ba0df488de8c793e41e4bd3de79e06c2537f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 19 Apr 2018 22:39:24 +0200 Subject: Bug#25471090: MYSQL USE AFTER FREE in a specially crafted invalid packet, one can get end_pos < pos here --- sql-common/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql-common/client.c b/sql-common/client.c index fc591e21616..bb7bdb1ff7d 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1708,7 +1708,7 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) } else { - if (len > (ulong) (end_pos - pos)) + if (pos + len > end_pos) { set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate); return -1; -- cgit v1.2.1 From 4fd1c7e453eac90928df1c74f443a6237fa792b8 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 20 Apr 2018 01:01:56 +0200 Subject: 5.5.59-38.11 --- storage/xtradb/include/univ.i | 2 +- storage/xtradb/trx/trx0purge.c | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i index 9591df0cfc8..64a2bfa70fe 100644 --- a/storage/xtradb/include/univ.i +++ b/storage/xtradb/include/univ.i @@ -64,7 +64,7 @@ component, i.e. we show M.N.P as M.N */ (INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR) #ifndef PERCONA_INNODB_VERSION -#define PERCONA_INNODB_VERSION 38.10 +#define PERCONA_INNODB_VERSION 38.11 #endif #define INNODB_VERSION_STR MYSQL_SERVER_VERSION diff --git a/storage/xtradb/trx/trx0purge.c b/storage/xtradb/trx/trx0purge.c index d343a73c9d8..1b87c8543f2 100644 --- a/storage/xtradb/trx/trx0purge.c +++ b/storage/xtradb/trx/trx0purge.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -729,6 +729,7 @@ trx_purge_rseg_get_next_history_log( mutex_exit(&(rseg->mutex)); mtr_commit(&mtr); +#ifdef UNIV_DEBUG mutex_enter(&kernel_mutex); /* Add debug code to track history list corruption reported @@ -742,18 +743,20 @@ trx_purge_rseg_get_next_history_log( if (trx_sys->rseg_history_len > 2000000) { ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: Warning: purge reached the" + " InnoDB: Warning: purge reached the" " head of the history list,\n" "InnoDB: but its length is still" - " reported as %lu! Make a detailed bug\n" - "InnoDB: report, and submit it" - " to http://bugs.mysql.com\n", + " reported as %lu!." + " This can happen becasue a long" + " running transaction is withholding" + " purging of undo logs or a read" + " view is open. Please try to commit" + " the long running transaction.", (ulong) trx_sys->rseg_history_len); - ut_ad(0); } mutex_exit(&kernel_mutex); - +#endif return; } -- cgit v1.2.1