From b7aafca7b708b40cdfbeeff3798e2074722ece7e Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Mon, 26 Feb 2018 15:55:16 +0530 Subject: [PATCH 01/71] Raise version number after cloning 5.5.60 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 44f719ca097..23e938e60e1 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=60 +MYSQL_VERSION_PATCH=61 MYSQL_VERSION_EXTRA= From d4e94739231be30cbda7f910eb1d76cfba2e549b Mon Sep 17 00:00:00 2001 From: Faustin Lammler Date: Tue, 3 Apr 2018 10:33:11 -0300 Subject: [PATCH 02/71] Package dependency case problem --- debian/control | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index 862cd4f3cea..79ccf8c8fd4 100644 --- a/debian/control +++ b/debian/control @@ -373,10 +373,10 @@ Description: MariaDB database regression test suite (metapackage depending on th Package: mariadb-connect-engine-10.0 Section: database Architecture: any -Depends: libxml2, mariadb-server-10.0|mariadb-galera-server-10.0, unixODBC +Depends: libxml2, mariadb-server-10.0|mariadb-galera-server-10.0, unixodbc Build-depends: libxml2-dev, mariadb-server-10.0|mariadb-galera-server-10.0, - unixODBC-dev + unixodbc-dev Description: Connect storage engine for MariaDB Connect engine supports a number of file formats (dbf, xml, txt, bin, etc), connections to ODBC tables and remote MySQL tables, as well as a number of From d982e717aba67227ec40761a21a4211db91aa0e2 Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Mon, 9 Apr 2018 11:18:12 +0530 Subject: [PATCH 03/71] Bug#27510150: MYSQLDUMP FAILS FOR SPECIFIC --WHERE CLAUSES Description: Mysqldump utility fails for specific clauses used with the option, 'where'. Analysis:- Method, "fix_identifier_with_newline()" that prefixes all occurrences of newline char ('\n') in incoming buffer does not verify the size of the buffer. The buffer in which the incoming buffer is copied is limited to 2048 bytes and the method does not try to allocate additional memory for larger incoming buffers. Fix:- Method, "fix_identifier_with_newline()" is modified to fix this issue. --- client/mysqldump.c | 182 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 142 insertions(+), 40 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 2775769fe52..34037337091 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1,5 +1,5 @@ /* - 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 @@ -549,7 +549,8 @@ static int dump_tablespaces_for_databases(char** databases); static int dump_tablespaces(char* ts_where); static void print_comment(FILE *sql_file, my_bool is_error, const char *format, ...); -static const char* fix_identifier_with_newline(char*); +static char const* fix_identifier_with_newline(char const* object_name, + my_bool* freemem); /* @@ -644,13 +645,19 @@ static void write_header(FILE *sql_file, char *db_name) } else if (!opt_compact) { + my_bool freemem= FALSE; + char const* text= fix_identifier_with_newline(db_name, &freemem); + print_comment(sql_file, 0, "-- MySQL dump %s Distrib %s, for %s (%s)\n--\n", DUMP_VERSION, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); print_comment(sql_file, 0, "-- Host: %s Database: %s\n", current_host ? current_host : "localhost", - db_name ? fix_identifier_with_newline(db_name) : ""); + text); + if (freemem) + my_free((void*)text); + print_comment(sql_file, 0, "-- ------------------------------------------------------\n" ); @@ -1982,31 +1989,84 @@ static void print_comment(FILE *sql_file, my_bool is_error, const char *format, print_xml_comment(sql_file, strlen(comment_buff), comment_buff); } -/* - This function accepts object names and prefixes -- wherever \n - character is found. - @param[in] object_name +/** + @brief Accepts object names and prefixes them with "-- " wherever + end-of-line character ('\n') is found. - @return - @retval fixed object name. + @param[in] object_name object name list (concatenated string) + @param[out] freemem should buffer be released after usage + + @return + @retval pointer to a string with prefixed objects */ - -static const char* fix_identifier_with_newline(char* object_name) +static char const* fix_identifier_with_newline(char const* object_name, my_bool* freemem) { - static char buff[COMMENT_LENGTH]= {0}; - char *ptr= buff; - memset(buff, 0, 255); - while(*object_name) + const size_t PREFIX_LENGTH= 3; // strlen ("-- ") + + // static buffer for replacement procedure + static char storage[NAME_LEN + 1]; + static char* buffer= storage; + static size_t buffer_size= sizeof(storage) - 1; + size_t index= 0; + size_t required_size= 0; + + // we presume memory allocation won't be needed + *freemem= FALSE; + + // traverse and reformat objects + while (object_name && *object_name) { - *ptr++ = *object_name; + ++required_size; if (*object_name == '\n') - ptr= strmov(ptr, "-- "); - object_name++; + required_size+= PREFIX_LENGTH; + + // do we need dynamic (re)allocation + if (required_size > buffer_size) + { + // new alloc size increased in COMMENT_LENGTH multiple + buffer_size= COMMENT_LENGTH * (1 + required_size/COMMENT_LENGTH); + + // is our buffer already dynamically allocated + if (*freemem) + { + // just realloc + buffer= (char*)my_realloc(buffer, buffer_size + 1, MYF(MY_WME)); + if (!buffer) + exit(1); + } + else + { + // dynamic allocation + copy from static buffer + buffer= (char*)my_malloc(buffer_size + 1, MYF(MY_WME)); + if (!buffer) + exit(1); + + strncpy(buffer, storage, index); + *freemem= TRUE; + } + } + + // copy a character + buffer[index]= *object_name; + ++index; + + // prefix new lines with double dash + if (*object_name == '\n') + { + strcpy(buffer + index, "-- "); + index += PREFIX_LENGTH; + } + + ++object_name; } - return buff; + + // don't forget null termination + buffer[index]= '\0'; + return buffer; } + /* create_delimiter Generate a new (null-terminated) string that does not exist in query @@ -2066,6 +2126,8 @@ static uint dump_events_for_db(char *db) char db_cl_name[MY_CS_NAME_SIZE]; int db_cl_altered= FALSE; + my_bool freemem= FALSE; + char const *text= fix_identifier_with_newline(db, &freemem); DBUG_ENTER("dump_events_for_db"); DBUG_PRINT("enter", ("db: '%s'", db)); @@ -2075,7 +2137,9 @@ static uint dump_events_for_db(char *db) /* nice comments */ print_comment(sql_file, 0, "\n--\n-- Dumping events for database '%s'\n--\n", - fix_identifier_with_newline(db)); + text); + if (freemem) + my_free((void*)text); /* not using "mysql_query_with_error_report" because we may have not @@ -2284,6 +2348,8 @@ static uint dump_routines_for_db(char *db) char db_cl_name[MY_CS_NAME_SIZE]; int db_cl_altered= FALSE; + my_bool freemem= FALSE; + char const *text= fix_identifier_with_newline(db, &freemem); DBUG_ENTER("dump_routines_for_db"); DBUG_PRINT("enter", ("db: '%s'", db)); @@ -2292,8 +2358,10 @@ static uint dump_routines_for_db(char *db) /* nice comments */ print_comment(sql_file, 0, - "\n--\n-- Dumping routines for database '%s'\n--\n", - fix_identifier_with_newline(db)); + "\n--\n-- Dumping routines for database '%s'\n--\n", text); + + if (freemem) + my_free((void*)text); /* not using "mysql_query_with_error_report" because we may have not @@ -2348,11 +2416,17 @@ static uint dump_routines_for_db(char *db) row[2] ? strlen(row[2]) : 0)); if (row[2] == NULL) { + my_bool freemem= FALSE; + char const* text= fix_identifier_with_newline(current_user, &freemem); + print_comment(sql_file, 1, "\n-- insufficient privileges to %s\n", query_buff); print_comment(sql_file, 1, "-- does %s have permissions on mysql.proc?\n\n", - fix_identifier_with_newline(current_user)); + text); + if (freemem) + my_free((void*)text); + maybe_die(EX_MYSQLERR,"%s has insufficent privileges to %s!", current_user, query_buff); } else if (strlen(row[2])) @@ -2547,6 +2621,8 @@ static uint get_table_structure(char *table, char *db, char *table_type, /* Make an sql-file, if path was given iow. option -T was given */ char buff[20+FN_REFLEN]; MYSQL_FIELD *field; + my_bool freemem= FALSE; + char const *text; my_snprintf(buff, sizeof(buff), "show create table %s", result_table); @@ -2563,14 +2639,17 @@ static uint get_table_structure(char *table, char *db, char *table_type, write_header(sql_file, db); } + text= fix_identifier_with_newline(result_table, &freemem); if (strcmp (table_type, "VIEW") == 0) /* view */ print_comment(sql_file, 0, "\n--\n-- Temporary table structure for view %s\n--\n\n", - fix_identifier_with_newline(result_table)); + text); else print_comment(sql_file, 0, - "\n--\n-- Table structure for table %s\n--\n\n", - fix_identifier_with_newline(result_table)); + "\n--\n-- Table structure for table %s\n--\n\n", text); + + if (freemem) + my_free((void*)text); if (opt_drop) { @@ -2803,6 +2882,9 @@ static uint get_table_structure(char *table, char *db, char *table_type, /* Make an sql-file, if path was given iow. option -T was given */ if (!opt_no_create_info) { + my_bool freemem= FALSE; + char const *text; + if (path) { if (!(sql_file= open_sql_file_for_table(table, O_WRONLY))) @@ -2810,9 +2892,13 @@ static uint get_table_structure(char *table, char *db, char *table_type, write_header(sql_file, db); } + text= fix_identifier_with_newline(result_table, &freemem); print_comment(sql_file, 0, "\n--\n-- Table structure for table %s\n--\n\n", - fix_identifier_with_newline(result_table)); + text); + if (freemem) + my_free((void*)text); + if (opt_drop) fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table); if (!opt_xml) @@ -3515,25 +3601,34 @@ static void dump_table(char *table, char *db) } else { - print_comment(md_result_file, 0, - "\n--\n-- Dumping data for table %s\n--\n", - fix_identifier_with_newline(result_table)); - + my_bool freemem= FALSE; + char const* text= fix_identifier_with_newline(result_table, &freemem); + print_comment(md_result_file, 0, "\n--\n-- Dumping data for table %s\n--\n", + text); + if (freemem) + my_free((void*)text); + dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * FROM "); dynstr_append_checked(&query_string, result_table); if (where) { - print_comment(md_result_file, 0, "-- WHERE: %s\n", - fix_identifier_with_newline(where)); + freemem= FALSE; + text= fix_identifier_with_newline(where, &freemem); + print_comment(md_result_file, 0, "-- WHERE: %s\n", text); + if (freemem) + my_free((void*)text); dynstr_append_checked(&query_string, " WHERE "); dynstr_append_checked(&query_string, where); } if (order_by) { - print_comment(md_result_file, 0, "-- ORDER BY: %s\n", - fix_identifier_with_newline(order_by)); + freemem= FALSE; + text= fix_identifier_with_newline(order_by, &freemem); + print_comment(md_result_file, 0, "-- ORDER BY: %s\n", text); + if (freemem) + my_free((void*)text); dynstr_append_checked(&query_string, " ORDER BY "); dynstr_append_checked(&query_string, order_by); @@ -4302,10 +4397,13 @@ static int init_dumping(char *database, int init_func(char*)) */ char quoted_database_buf[NAME_LEN*2+3]; char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted); + my_bool freemem= FALSE; + char const* text= fix_identifier_with_newline(qdatabase, &freemem); - print_comment(md_result_file, 0, - "\n--\n-- Current Database: %s\n--\n", - fix_identifier_with_newline(qdatabase)); + print_comment(md_result_file, 0, "\n--\n-- Current Database: %s\n--\n", + text); + if (freemem) + my_free((void*)text); /* Call the view or table specific function */ init_func(qdatabase); @@ -5265,6 +5363,8 @@ static my_bool get_view_structure(char *table, char* db) char table_buff2[NAME_LEN*2+3]; char query[QUERY_LENGTH]; FILE *sql_file= md_result_file; + my_bool freemem= FALSE; + char const *text; DBUG_ENTER("get_view_structure"); if (opt_no_create_info) /* Don't write table creation info */ @@ -5309,9 +5409,11 @@ static my_bool get_view_structure(char *table, char* db) write_header(sql_file, db); } + text= fix_identifier_with_newline(result_table, &freemem); print_comment(sql_file, 0, - "\n--\n-- Final view structure for view %s\n--\n\n", - fix_identifier_with_newline(result_table)); + "\n--\n-- Final view structure for view %s\n--\n\n", text); + if (freemem) + my_free((void*)text); /* Table might not exist if this view was dumped with --tab. */ fprintf(sql_file, "/*!50001 DROP TABLE IF EXISTS %s*/;\n", opt_quoted_table); From 940b88b686bcf037a36f6e81be4017a07fcf782a Mon Sep 17 00:00:00 2001 From: Ajo Robert Date: Tue, 10 Apr 2018 00:30:59 +0530 Subject: [PATCH 04/71] Bug#27197235 USER VARIABLE + UINON + DECIMAL COLUMN RETURNS WRONG VALUES User variables will have the default session collation associated with it. And a select which uses it as part of a union may infer the collation while type merging. This leads to problems when the result is of DECIMAL type. Setting the appropriate collation of DECIMAL result type is missing in 5.7 code base. Added code to set appropriate collation when the result is of DECIMAL type during Item_type_holder::join_types(). --- mysql-test/r/union.result | 16 ++++++++++++++++ mysql-test/t/union.test | 14 ++++++++++++++ sql/item.cc | 3 ++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 97c1a8b4d49..c0b364d0fde 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -1860,3 +1860,19 @@ DROP TABLE t17059925, t2, t3; SET @@long_query_time= @old_long_query_time; SET @@global.log_output= @old_log_output; SET @@global.slow_query_log= @old_slow_query_log; +# +# Bug#27197235 USER VARIABLE + UINON + DECIMAL COLUMN RETURNS +# WRONG VALUES +# +SET NAMES utf8; +SET @advertAcctId = 1000003; +select @advertAcctId as a from dual union all select 1.0 from dual; +a +1000003.0 +1.0 +SET NAMES latin1; +SET @advertAcctId = 1000003; +select @advertAcctId as a from dual union all select 1.0 from dual; +a +1000003.0 +1.0 diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 147c1d3834b..d7e362558e3 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -1256,3 +1256,17 @@ SET @@long_query_time= @old_long_query_time; SET @@global.log_output= @old_log_output; SET @@global.slow_query_log= @old_slow_query_log; +--echo # +--echo # Bug#27197235 USER VARIABLE + UINON + DECIMAL COLUMN RETURNS +--echo # WRONG VALUES +--echo # + +let $old_charset= `SELECT @@character_set_client`; + +SET NAMES utf8; +SET @advertAcctId = 1000003; +select @advertAcctId as a from dual union all select 1.0 from dual; + +eval SET NAMES $old_charset; +SET @advertAcctId = 1000003; +select @advertAcctId as a from dual union all select 1.0 from dual; diff --git a/sql/item.cc b/sql/item.cc index a37a61453e8..07d64881eeb 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1,5 +1,5 @@ /* - 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 @@ -8266,6 +8266,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) } if (Field::result_merge_type(fld_type) == DECIMAL_RESULT) { + collation.set_numeric(); decimals= min(max(decimals, item->decimals), DECIMAL_MAX_SCALE); int item_int_part= item->decimal_int_part(); int item_prec = max(prev_decimal_int_part, item_int_part) + decimals; From a08508abf83d953f11e4823798398d9229ba0237 Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Tue, 24 Apr 2018 10:02:04 +0530 Subject: [PATCH 05/71] Bug#27407480: AUTOMATIC_SP_PRIVILEGES REQUIRES NEED THE INSERT PRIVILEGES FOR MYSQL.USER TABLE Description:- Incorrect granting of EXECUTE and ALTER ROUTINE privileges when the 'automatic_sp_privileges' variable is set. Fix:- EXECUTE and ALTER ROUTINE privileges are correctly granted to the creator of the procedure when the 'automatic_sp_privileges' is SET. --- mysql-test/r/grant.result | 3 +-- sql/sql_acl.cc | 15 ++++----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 7603e4b1b1c..e524bb5cac2 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1780,8 +1780,6 @@ BEGIN SET @x = 0; REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT; END ;|| -Warnings: -Warning 1404 Failed to grant EXECUTE and ALTER ROUTINE privileges SHOW GRANTS FOR 'user1'@'localhost'; Grants for user1@localhost GRANT USAGE ON *.* TO 'user1'@'localhost' @@ -1791,6 +1789,7 @@ SHOW GRANTS FOR 'user2'; Grants for user2@% GRANT USAGE ON *.* TO 'user2'@'%' GRANT CREATE, CREATE ROUTINE ON `db1`.* TO 'user2'@'%' +GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `db1`.`proc2` TO 'user2'@'%' DROP PROCEDURE db1.proc1; DROP PROCEDURE db1.proc2; REVOKE ALL ON db1.* FROM 'user1'@'localhost'; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 385484f2b01..705b4792a37 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -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 @@ -7670,19 +7670,12 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) DBUG_RETURN(TRUE); - combo->user.str= sctx->user; + combo->user.str= (char *) sctx->priv_user; mysql_mutex_lock(&acl_cache->lock); - if ((au= find_acl_user(combo->host.str=(char*)sctx->host_or_ip,combo->user.str,FALSE))) - goto found_acl; - if ((au= find_acl_user(combo->host.str=(char*)sctx->get_host()->ptr(), - combo->user.str,FALSE))) - goto found_acl; - if ((au= find_acl_user(combo->host.str=(char*)sctx->get_ip()->ptr(), - combo->user.str,FALSE))) - goto found_acl; - if((au= find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE))) + if ((au= find_acl_user(combo->host.str= (char *) sctx->priv_host, + combo->user.str, FALSE))) goto found_acl; mysql_mutex_unlock(&acl_cache->lock); From 6d570d729682039edd6c490187a0434e7d75d486 Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Thu, 10 May 2018 10:14:30 +0530 Subject: [PATCH 06/71] Bug#27230925: HANDLE_FATAL_SIGNAL (SIG=11) IN SHOW_ROUTINE_GRANTS Description :- Server crashes in show_routine_grants(). Analysis :- When "grant_reload_procs_priv" encounters an error, the grant structures (structures with column, function and procedure privileges) are freed. Server crashes when trying to access these structures later. Fix :- Grant structures are retained even when "grant_reload_procs_priv()" encounters an error while reloading column, function and procedure privileges. --- mysql-test/r/grant.result | 1 + mysql-test/t/grant.test | 3 ++ sql/sql_acl.cc | 92 ++++++++++++++++++++++++++------------- 3 files changed, 65 insertions(+), 31 deletions(-) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index e524bb5cac2..d151b58e9ce 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1692,6 +1692,7 @@ revoke create, insert on mysqltest.t6 from mysqltest@localhost; drop user mysqltest@localhost; drop database mysqltest; use test; +call mtr.add_suppression("Can't open and lock privilege tables"); FLUSH PRIVILEGES without procs_priv table. RENAME TABLE mysql.procs_priv TO mysql.procs_gone; FLUSH PRIVILEGES; diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index 1e1cb6c24dc..2a1a8e34efb 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -1667,6 +1667,9 @@ use test; # # Bug#16470 crash on grant if old grant tables # + +call mtr.add_suppression("Can't open and lock privilege tables"); + --echo FLUSH PRIVILEGES without procs_priv table. RENAME TABLE mysql.procs_priv TO mysql.procs_gone; --error ER_NO_SUCH_TABLE diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 705b4792a37..64888f7308a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -4871,6 +4871,7 @@ end_index_init: exists. @param thd A pointer to the thread handler object. + @param table A pointer to the table list. @see grant_reload @@ -4879,31 +4880,22 @@ end_index_init: @retval TRUE An error has occurred. */ -static my_bool grant_reload_procs_priv(THD *thd) +static my_bool grant_reload_procs_priv(THD *thd, TABLE_LIST *table) { HASH old_proc_priv_hash, old_func_priv_hash; - TABLE_LIST table; my_bool return_val= FALSE; DBUG_ENTER("grant_reload_procs_priv"); - table.init_one_table("mysql", 5, "procs_priv", - strlen("procs_priv"), "procs_priv", - TL_READ); - table.open_type= OT_BASE_ONLY; - - if (open_and_lock_tables(thd, &table, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) - DBUG_RETURN(TRUE); - - mysql_rwlock_wrlock(&LOCK_grant); /* Save a copy of the current hash if we need to undo the grant load */ old_proc_priv_hash= proc_priv_hash; old_func_priv_hash= func_priv_hash; - if ((return_val= grant_load_procs_priv(table.table))) + if ((return_val= grant_load_procs_priv(table->table))) { /* Error; Reverting to old hash */ DBUG_PRINT("error",("Reverting to old privileges")); - grant_free(); + my_hash_free(&proc_priv_hash); + my_hash_free(&func_priv_hash); proc_priv_hash= old_proc_priv_hash; func_priv_hash= old_func_priv_hash; } @@ -4912,9 +4904,7 @@ static my_bool grant_reload_procs_priv(THD *thd) my_hash_free(&old_proc_priv_hash); my_hash_free(&old_func_priv_hash); } - mysql_rwlock_unlock(&LOCK_grant); - close_mysql_tables(thd); DBUG_RETURN(return_val); } @@ -4936,7 +4926,7 @@ static my_bool grant_reload_procs_priv(THD *thd) my_bool grant_reload(THD *thd) { - TABLE_LIST tables[2]; + TABLE_LIST tables[3]; HASH old_column_priv_hash; MEM_ROOT old_mem; my_bool return_val= 1; @@ -4952,15 +4942,57 @@ my_bool grant_reload(THD *thd) tables[1].init_one_table(C_STRING_WITH_LEN("mysql"), C_STRING_WITH_LEN("columns_priv"), "columns_priv", TL_READ); + tables[2].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("procs_priv"), + "procs_priv", TL_READ); + tables[0].next_local= tables[0].next_global= tables+1; - tables[0].open_type= tables[1].open_type= OT_BASE_ONLY; + tables[1].next_local= tables[1].next_global= tables+2; + tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY; + + /* + Reload will work in the following manner:- + + proc_priv_hash structure + / \ + not initialized initialized + / \ | + mysql.procs_priv table Server Startup | + is missing \ | + | open_and_lock_tables() + Assume we are working on /success \failure + pre 4.1 system tables. Normal Scenario. An error is thrown. + A warning is printed Reload column privilege. Retain the old hash. + and continue with Reload function and + reloading the column procedure privileges, + privileges. if available. + */ + + if (!(my_hash_inited(&proc_priv_hash))) + tables[2].open_strategy= TABLE_LIST::OPEN_IF_EXISTS; /* To avoid deadlocks we should obtain table locks before obtaining LOCK_grant rwlock. */ if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) + { + if (thd->stmt_da->is_error()) + { + sql_print_error("Fatal error: Can't open and lock privilege tables: %s", + thd->stmt_da->message()); + } goto end; + } + + if (tables[2].table == NULL) + { + sql_print_warning("Table 'mysql.procs_priv' does not exist. " + "Please run mysql_upgrade."); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NO_SUCH_TABLE, + ER(ER_NO_SUCH_TABLE), tables[2].db, + tables[2].table_name); + } mysql_rwlock_wrlock(&LOCK_grant); old_column_priv_hash= column_priv_hash; @@ -4972,10 +5004,18 @@ my_bool grant_reload(THD *thd) old_mem= memex; init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); - if ((return_val= grant_load(thd, tables))) + /* + tables[2].table i.e. procs_priv can be null if we are working with + pre 4.1 privilage tables + */ + if ((return_val= (grant_load(thd, tables) || + (tables[2].table != NULL && + grant_reload_procs_priv(thd, &tables[2]))) + )) { // Error. Revert to old hash DBUG_PRINT("error",("Reverting to old privileges")); - grant_free(); /* purecov: deadcode */ + my_hash_free(&column_priv_hash); + free_root(&memex,MYF(0)); column_priv_hash= old_column_priv_hash; /* purecov: deadcode */ memex= old_mem; /* purecov: deadcode */ } @@ -4983,22 +5023,12 @@ my_bool grant_reload(THD *thd) { my_hash_free(&old_column_priv_hash); free_root(&old_mem,MYF(0)); + grant_version++; } mysql_rwlock_unlock(&LOCK_grant); - close_mysql_tables(thd); - - /* - It is OK failing to load procs_priv table because we may be - working with 4.1 privilege tables. - */ - if (grant_reload_procs_priv(thd)) - return_val= 1; - - mysql_rwlock_wrlock(&LOCK_grant); - grant_version++; - mysql_rwlock_unlock(&LOCK_grant); end: + close_mysql_tables(thd); DBUG_RETURN(return_val); } From bbc2e37fe4e0ca3a7cfa1437a763dc43829e98e2 Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Mon, 14 May 2018 11:28:13 +0530 Subject: [PATCH 07/71] Bug#27759871: BACKRONYM ISSUE IS STILL IN MYSQL 5.7 Description:- Client applications establishes connection to server, which does not support SSL, via TCP even when SSL is enforced via MYSQL_OPT_SSL_MODE or MYSQL_OPT_SSL_ENFORCE or MYSQL_OPT_SSL_VERIFY_SERVER_CERT. Analysis:- There exist no error handling for catching client applications which enforces SSL connection to connect to a server which does not support SSL. Fix:- Error handling is done to catch above mentioned scenarios. --- include/sql_common.h | 5 ++++- libmysqld/libmysqld.c | 5 ++++- sql-common/client.c | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/include/sql_common.h b/include/sql_common.h index 45e90d438fb..9571dff9778 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -1,7 +1,7 @@ #ifndef SQL_COMMON_INCLUDED #define SQL_COMMON_INCLUDED -/* 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 @@ -96,6 +96,9 @@ void set_stmt_error(MYSQL_STMT *stmt, int errcode, const char *sqlstate, void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate); void set_mysql_extended_error(MYSQL *mysql, int errcode, const char *sqlstate, const char *format, ...); +#ifdef EMBEDDED_LIBRARY +int embedded_ssl_check(MYSQL *mysql); +#endif /* client side of the pluggable authentication */ struct st_plugin_vio_info; diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index 6de1e3383d2..85ca0cf4bd8 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2001, 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 @@ -173,6 +173,9 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if (db) client_flag|=CLIENT_CONNECT_WITH_DB; + if (embedded_ssl_check(mysql)) + goto error; + mysql->info_buffer= my_malloc(MYSQL_ERRMSG_SIZE, MYF(0)); mysql->thd= create_embedded_thd(client_flag); diff --git a/sql-common/client.c b/sql-common/client.c index 9972ca741f2..3247fd8e339 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2020,6 +2020,34 @@ error: #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ +/** + Checks if any SSL option is set for libmysqld embedded server. + + @param mysql the connection handle + @retval 0 success + @retval 1 failure +*/ +#ifdef EMBEDDED_LIBRARY +int embedded_ssl_check(MYSQL *mysql) +{ + if (mysql->options.ssl_key || mysql->options.ssl_cert || + mysql->options.ssl_ca || mysql->options.ssl_capath || + mysql->options.ssl_cipher || + mysql->options.client_flag & CLIENT_SSL_VERIFY_SERVER_CERT || + (mysql->options.extension && + mysql->options.extension->ssl_mode == SSL_MODE_REQUIRED)) + { + set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate, + ER(CR_SSL_CONNECTION_ERROR), + "Embedded server libmysqld library doesn't support " + "SSL connections"); + return 1; + } + return 0; +} +#endif + + /* Note that the mysql argument must be initialized with mysql_init() before calling mysql_real_connect ! @@ -3592,6 +3620,11 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, mysql->client_flag= client_flag; +#ifdef EMBEDDED_LIBRARY + if (embedded_ssl_check(mysql)) + goto error; +#endif + /* Part 2: invoke the plugin to send the authentication data to the server */ @@ -4271,10 +4304,14 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) mysql->reconnect= *(my_bool *) arg; break; case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) if (*(my_bool*) arg) mysql->options.client_flag|= CLIENT_SSL_VERIFY_SERVER_CERT; else mysql->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT; +#elif defined(EMBEDDED_LIBRARY) + DBUG_RETURN(1); +#endif break; case MYSQL_PLUGIN_DIR: EXTENSION_SET_STRING(&mysql->options, plugin_dir, arg); @@ -4288,11 +4325,15 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) (*(my_bool*) arg) ? TRUE : FALSE; break; case MYSQL_OPT_SSL_MODE: +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) if (*(uint *) arg == SSL_MODE_REQUIRED) { ENSURE_EXTENSIONS_PRESENT(&mysql->options); mysql->options.extension->ssl_mode= SSL_MODE_REQUIRED; } +#elif defined(EMBEDDED_LIBRARY) + DBUG_RETURN(1); +#endif break; default: DBUG_RETURN(1); From bd5ca6acece65858591c2bf54f86ff34aeea2821 Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Mon, 21 May 2018 08:42:45 +0530 Subject: [PATCH 08/71] Bug#25541037: MYSQL BUG ON DELETE Description:- MyISAM table gets corrupted with concurrent executions of INSERT, DELETE statements in a particular sequence. Analysis:- Due to the inappropriate manipulation of w_lock and r_lock associated with a MyISAM table, there arises a scenario where the table's state information becomes invalid. Fix:- A lock is introduced to resolve this issue. --- storage/myisam/ha_myisam.cc | 6 +++++- storage/myisam/mi_check.c | 6 +++++- storage/myisam/mi_locking.c | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 21cbef32188..6eed1be1ba9 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.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 @@ -1172,10 +1172,14 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize) if (file->s->base.auto_key) update_auto_increment_key(¶m, file, 1); if (optimize_done) + { + mysql_mutex_lock(&share->intern_lock); error = update_state_info(¶m, file, UPDATE_TIME | UPDATE_OPEN_COUNT | (local_testflag & T_STATISTICS ? UPDATE_STAT : 0)); + mysql_mutex_unlock(&share->intern_lock); + } info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE | HA_STATUS_CONST); if (rows != file->state->records && ! (param.testflag & T_VERY_SILENT)) diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index fe0d4c9c30b..7134cfc265a 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -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 @@ -4474,6 +4474,10 @@ int update_state_info(MI_CHECK *param, MI_INFO *info,uint update) int error; uint r_locks=share->r_locks,w_locks=share->w_locks; share->r_locks= share->w_locks= share->tot_locks= 0; + + DBUG_EXECUTE_IF("simulate_incorrect_share_wlock_value", + DEBUG_SYNC_C("after_share_wlock_set_to_0");); + error=_mi_writeinfo(info,WRITEINFO_NO_UNLOCK); share->r_locks=r_locks; share->w_locks=w_locks; diff --git a/storage/myisam/mi_locking.c b/storage/myisam/mi_locking.c index 4a33e838fb9..dcfeaca5b8c 100644 --- a/storage/myisam/mi_locking.c +++ b/storage/myisam/mi_locking.c @@ -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 @@ -229,6 +229,10 @@ int mi_lock_database(MI_INFO *info, int lock_type) info->invalidator=info->s->invalidator; share->w_locks++; share->tot_locks++; + + DBUG_EXECUTE_IF("simulate_incorrect_share_wlock_value", + DEBUG_SYNC_C("after_share_wlock_increment");); + info->s->in_use= list_add(info->s->in_use, &info->in_use); break; default: From eee5bd9a2e2949ef468670f1ec4431a4ce54ada0 Mon Sep 17 00:00:00 2001 From: Faustin Lammler Date: Tue, 3 Apr 2018 10:33:11 -0300 Subject: [PATCH 09/71] Package dependency case problem dummy commit, add carriage return rollback and add travis build remove travis CI config --- debian/control | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index 862cd4f3cea..79ccf8c8fd4 100644 --- a/debian/control +++ b/debian/control @@ -373,10 +373,10 @@ Description: MariaDB database regression test suite (metapackage depending on th Package: mariadb-connect-engine-10.0 Section: database Architecture: any -Depends: libxml2, mariadb-server-10.0|mariadb-galera-server-10.0, unixODBC +Depends: libxml2, mariadb-server-10.0|mariadb-galera-server-10.0, unixodbc Build-depends: libxml2-dev, mariadb-server-10.0|mariadb-galera-server-10.0, - unixODBC-dev + unixodbc-dev Description: Connect storage engine for MariaDB Connect engine supports a number of file formats (dbf, xml, txt, bin, etc), connections to ODBC tables and remote MySQL tables, as well as a number of From 15c6d6a94a20053ded2e115d21e7d285b583c9ef Mon Sep 17 00:00:00 2001 From: sjaakola Date: Thu, 7 Jun 2018 17:12:38 +0300 Subject: [PATCH 10/71] MDEV-14612 wsrep_sst_mariabackup unnecessarily converts address to host name SST script for mariabackup (wsrep_sst_mariabackup.sh) does reverse DNS to convert the joiner's IP address to domain name, and this is not always a wanted feature. It is not understood why this remote host DNS conversion is in the script, in the first place, but conversion was originally added by commit: commit 3d8aacba861044843417b710fff208b8bd6a53c4 Author: Nirbhay Choubey Date: Wed Feb 22 15:58:45 2017 -0500 In this commit, REMOTEHOST variable is removed and replaced by REMOTEIP. All references to joiner is therefore by IP address only. --- scripts/wsrep_sst_mariabackup.sh | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 549161aa8f3..8bc5954e45a 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -33,7 +33,6 @@ ssystag="" XTRABACKUP_PID="" SST_PORT="" REMOTEIP="" -REMOTEHOST="" tcert="" tpem="" tkey="" @@ -225,7 +224,7 @@ get_transfer() tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=${tpem},cafile=${tcert}${sockopt} stdio" else wsrep_log_info "Encrypting with cert=${tpem}, cafile=${tcert}" - tcmd="socat -u stdio openssl-connect:${REMOTEHOST}:${TSST_PORT},cert=${tpem},cafile=${tcert}${sockopt}" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=${tpem},cafile=${tcert}${sockopt}" fi elif [[ $encrypt -eq 3 ]];then wsrep_log_info "Using openssl based encryption with socat: with key and crt" @@ -248,7 +247,7 @@ get_transfer() tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=${tpem},key=${tkey},verify=0${sockopt}" else wsrep_log_info "Encrypting with cert=${tpem}, key=${tkey}, cafile=${tcert}" - tcmd="socat -u stdio openssl-connect:${REMOTEHOST}:${TSST_PORT},cert=${tpem},key=${tkey},cafile=${tcert}${sockopt}" + tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=${tpem},key=${tkey},cafile=${tcert}${sockopt}" fi fi @@ -518,10 +517,6 @@ setup_ports() if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') - REMOTEHOST=$(getent hosts $REMOTEIP | awk '{ print $2 }') - if [[ -z $REMOTEHOST ]];then - REMOTEHOST=$REMOTEIP - fi lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') sst_ver=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $5 }') else From e48d775c6f066add457fa8cfb2ebc4d5ff0c7613 Mon Sep 17 00:00:00 2001 From: Ivo Roylev Date: Thu, 14 Jun 2018 17:27:54 +0300 Subject: [PATCH 11/71] Bug#27980823: HEAP OVERFLOW VULNERABILITIES IN MYSQL CLIENT LIBRARY (cherry picked from commit b5b986b2cbd9a7848dc3f48e5c42b6d4e1e5fb22) --- sql-common/client.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sql-common/client.c b/sql-common/client.c index 3247fd8e339..7938403db59 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1505,7 +1505,8 @@ unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, { uchar *pos; /* fields count may be wrong */ - DBUG_ASSERT((uint) (field - result) < fields); + if (field < result || (uint) (field - result) >= fields) + DBUG_RETURN(NULL); cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7); field->catalog= strmake_root(alloc,(char*) row->data[0], lengths[0]); field->db= strmake_root(alloc,(char*) row->data[1], lengths[1]); @@ -1612,6 +1613,7 @@ MYSQL_DATA *cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, if ((pkt_len= cli_safe_read(mysql)) == packet_error) DBUG_RETURN(0); + if (pkt_len == 0) DBUG_RETURN(0); if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), MYF(MY_WME | MY_ZEROFILL)))) { From e5c6580178a8d660c03fe9fab09c539cedf6fb34 Mon Sep 17 00:00:00 2001 From: mkaruza Date: Tue, 19 Jun 2018 16:09:31 +0200 Subject: [PATCH 12/71] MDEV-15442 xtrabackup-v2 SST donor stuck in DONOR/DESYNCED state when joiner is killed Monitor mysqld process and if it is terminated during sst stream kill xtrabackup-v2 script and children --- scripts/wsrep_sst_xtrabackup-v2.sh | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/scripts/wsrep_sst_xtrabackup-v2.sh b/scripts/wsrep_sst_xtrabackup-v2.sh index 00efdaeebcf..99bbabbe9be 100644 --- a/scripts/wsrep_sst_xtrabackup-v2.sh +++ b/scripts/wsrep_sst_xtrabackup-v2.sh @@ -801,6 +801,27 @@ check_for_version() fi } +monitor_process() +{ + local sst_stream_pid=$1 + + while true ; do + + if ! ps --pid "${WSREP_SST_OPT_PARENT}" &>/dev/null; then + wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." + kill -- -"${WSREP_SST_OPT_PARENT}" + exit 32 + fi + + if ! ps --pid "${sst_stream_pid}" &>/dev/null; then + break + fi + + sleep 0.1 + + done +} + if [[ ! -x `which $INNOBACKUPEX_BIN` ]];then wsrep_log_error "innobackupex not in path: $PATH" @@ -1102,7 +1123,7 @@ then MAGIC_FILE="${DATA}/${INFO_FILE}" wsrep_log_info "Waiting for SST streaming to complete!" - wait $jpid + monitor_process $jpid get_proc From 7a7a61998c60b8114994b29d5f649637be8139e0 Mon Sep 17 00:00:00 2001 From: mkaruza Date: Wed, 20 Jun 2018 13:16:34 +0200 Subject: [PATCH 13/71] MDEV-15442 xtrabackup-v2 SST donor stuck in DONOR/DESYNCED state when joiner is killed SST transfer scripts rsync and maribackup now monitor parent process and will cleanup if process dies --- scripts/wsrep_sst_mariabackup.sh | 23 ++++++++++++++++++++++- scripts/wsrep_sst_rsync.sh | 2 ++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 549161aa8f3..ea0a6fc0d51 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -644,6 +644,27 @@ send_donor() } +monitor_process() +{ + local sst_stream_pid=$1 + + while true ; do + + if ! ps --pid "${WSREP_SST_OPT_PARENT}" &>/dev/null; then + wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." + kill -- -"${WSREP_SST_OPT_PARENT}" + exit 32 + fi + + if ! ps --pid "${sst_stream_pid}" &>/dev/null; then + break + fi + + sleep 0.1 + + done +} + if [[ ! -x `which $INNOBACKUPEX_BIN` ]];then wsrep_log_error "${INNOBACKUPEX_BIN} not in path: $PATH" exit 2 @@ -932,7 +953,7 @@ then MAGIC_FILE="${DATA}/${INFO_FILE}" wsrep_log_info "Waiting for SST streaming to complete!" - wait $jpid + monitor_process $jpid get_proc diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 3d76d1780e2..81120b66d5a 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -329,6 +329,8 @@ EOF then wsrep_log_error \ "Parent mysqld process (PID:$MYSQLD_PID) terminated unexpectedly." + kill -- -"${MYSQLD_PID}" + sleep 1 exit 32 fi From 90e608c6acd150e727cb0002f36767d0866aa633 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 26 Jun 2018 11:42:02 +0400 Subject: [PATCH 14/71] A test cleanup for MDEV-15834: fixing failure in "mtr --embedded" --- mysql-test/suite/vcol/t/vcol_misc.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/suite/vcol/t/vcol_misc.test b/mysql-test/suite/vcol/t/vcol_misc.test index a123d21d574..fab705eaaa6 100644 --- a/mysql-test/suite/vcol/t/vcol_misc.test +++ b/mysql-test/suite/vcol/t/vcol_misc.test @@ -327,8 +327,10 @@ SET sql_mode=DEFAULT; --copy_file std_data/frm/t1.frm $MYSQLD_DATADIR/test/t1.frm SHOW TABLES; +--replace_result $MYSQLD_DATADIR ./ --error ER_NOT_FORM_FILE SHOW CREATE TABLE t1; +--replace_result $MYSQLD_DATADIR ./ --error ER_NOT_FORM_FILE ALTER TABLE t1; --remove_file $MYSQLD_DATADIR/test/t1.frm From 1f6a89a8fdf88029518584f3e906d0e55bc1889a Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 27 Jun 2018 13:18:03 +0300 Subject: [PATCH 15/71] Added valgrind suppression for OpenSuse 42.2 --- mysql-test/valgrind.supp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 71e6836365e..c9c06c2634a 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -608,6 +608,19 @@ fun:dlopen* } +# +# Warning caused by small memory leak in _dl_init +# + +{ + dl_init memory leak + Memcheck:Leak + fun:malloc + obj:*/libstdc++.so* + fun:call_init.part* + fun:_dl_init +} + # # In glibc (checked version 2.7), inet_ntoa allocates an 18-byte # per-thread static buffer for the return value. That memory is freed From faef2e6a44de8e1c1301104671d08dfc1deef1e0 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 27 Jun 2018 13:18:30 +0300 Subject: [PATCH 16/71] Added more help text in case mysql_install_db fails. --- scripts/mysql_install_db.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 2c5f8d7082d..a8f32526a7e 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -211,6 +211,11 @@ cannot_find_file() echo "If you compiled from source, you need to run 'make install' to" echo "copy the software into the correct location ready for operation." echo + echo "If you compiled from source, you need to either run 'make install' to" + echo "copy the software into the correct location ready for operation." + echo "If you don't want to do a full install, you can use the --srcdir" + echo "option to only install the mysql database and privilege tables" + echo echo "If you are using a binary release, you must either be at the top" echo "level of the extracted archive, or pass the --basedir option" echo "pointing to that location." From 937c19318819f63d72a66dac5a60c638386512d6 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 27 Jun 2018 13:17:18 +0300 Subject: [PATCH 17/71] Fixed MDEV-16512, crashing on re-execution of failing SP MDEV-16512 Server crashes in find_field_in_table_ref on 2nd execution of SP referring to non-existing field Problem was in the natural join code that it changed TABLE_LIST and Item_fields but didn't restore changed things if things goes wrong and was not able to re-execute after failure. Some of the problems could have been avoided if we would have run fix_fields before doing natural join transformations. Fixed by marking functions complete AFTER they had executed, instead at start. I had also to change some tests that checked if Item_fields are usable. This doesn't fix all known problems, but at least avoids some crashes. What should be done in the near future is to mark the statement in the SP as 'not re-executable' and force a reparse of it on next execution. Reviewer: Sergei Petrunia --- mysql-test/r/join.result | 40 +++++++++++++++++++++++++++++++ mysql-test/t/join.test | 52 ++++++++++++++++++++++++++++++++++++++++ sql/sql_base.cc | 12 ++++++---- sql/table.cc | 6 ++--- 4 files changed, 102 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 1e51d55f012..7b0e7807e39 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -1497,3 +1497,43 @@ Note 1003 select NULL AS `i1`,`v2`.`i2` AS `i2`,`v2`.`a` AS `a`,`v2`.`b` AS `b` DROP VIEW v2; DROP TABLE t1,t2; SET optimizer_switch=@save_optimizer_switch; +# +# MDEV-16512 +# Server crashes in find_field_in_table_ref on 2nd execution of SP referring to +# non-existing field +# +CREATE TABLE t (i INT); +CREATE PROCEDURE p() SELECT t1.f FROM t AS t1 JOIN t AS t2 USING (f); +CALL p; +ERROR 42S22: Unknown column 'f' in 'from clause' +CALL p; +ERROR 42S22: Unknown column 'f' in 'from clause' +FLUSH TABLES; +CALL p; +ERROR 42S22: Unknown column 'f' in 'from clause' +DROP TABLE t; +CREATE TABLE t (f INT); +CALL p; +ERROR 42S22: Unknown column 'f' in 'from clause' +DROP TABLE t; +CREATE TABLE t (i INT); +CALL p; +ERROR 42S22: Unknown column 'f' in 'from clause' +DROP PROCEDURE p; +DROP TABLE t; +CREATE TABLE t1 (a INT, b INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT, c INT); +CREATE TABLE t4 (a INT, c INT); +CREATE TABLE t5 (a INT, c INT); +CREATE PROCEDURE p1() SELECT c FROM t1 JOIN (t2 LEFT JOIN t3 USING (a) LEFT JOIN t4 USING (a) +LEFT JOIN t5 USING (a)) USING (a); +CALL p1; +ERROR 23000: Column 'c' in field list is ambiguous +CALL p1; +ERROR 23000: Column 'c' in field list is ambiguous +DROP PROCEDURE p1; +DROP TABLE t1,t2,t3,t4,t5; +# +# End of MariaDB 5.5 tests +# diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 203a7d377a5..feafac57a7e 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -1159,3 +1159,55 @@ DROP VIEW v2; DROP TABLE t1,t2; SET optimizer_switch=@save_optimizer_switch; + +--echo # +--echo # MDEV-16512 +--echo # Server crashes in find_field_in_table_ref on 2nd execution of SP referring to +--echo # non-existing field +--echo # + +CREATE TABLE t (i INT); +CREATE PROCEDURE p() SELECT t1.f FROM t AS t1 JOIN t AS t2 USING (f); +--error ER_BAD_FIELD_ERROR +CALL p; +--error ER_BAD_FIELD_ERROR +CALL p; +FLUSH TABLES; +--error ER_BAD_FIELD_ERROR +CALL p; +DROP TABLE t; + +# +# Fix the table definition to match the using +# + +CREATE TABLE t (f INT); +# +# The following shouldn't fail as the table is now matching the using +# +--error ER_BAD_FIELD_ERROR +CALL p; +DROP TABLE t; +CREATE TABLE t (i INT); +--error ER_BAD_FIELD_ERROR +CALL p; +DROP PROCEDURE p; +DROP TABLE t; + +CREATE TABLE t1 (a INT, b INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT, c INT); +CREATE TABLE t4 (a INT, c INT); +CREATE TABLE t5 (a INT, c INT); +CREATE PROCEDURE p1() SELECT c FROM t1 JOIN (t2 LEFT JOIN t3 USING (a) LEFT JOIN t4 USING (a) +LEFT JOIN t5 USING (a)) USING (a); +--error ER_NON_UNIQ_ERROR +CALL p1; +--error ER_NON_UNIQ_ERROR +CALL p1; +DROP PROCEDURE p1; +DROP TABLE t1,t2,t3,t4,t5; + +--echo # +--echo # End of MariaDB 5.5 tests +--echo # diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 71bbb538b5c..8ffb7bc118b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7687,6 +7687,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, Query_arena *arena, backup; bool result= TRUE; List *non_join_columns; + List *join_columns; DBUG_ENTER("store_natural_using_join_columns"); DBUG_ASSERT(!natural_using_join->join_columns); @@ -7694,7 +7695,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, arena= thd->activate_stmt_arena_if_needed(&backup); if (!(non_join_columns= new List) || - !(natural_using_join->join_columns= new List)) + !(join_columns= new List)) goto err; /* Append the columns of the first join operand. */ @@ -7703,7 +7704,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, nj_col_1= it_1.get_natural_column_ref(); if (nj_col_1->is_common) { - natural_using_join->join_columns->push_back(nj_col_1); + join_columns->push_back(nj_col_1); /* Reset the common columns for the next call to mark_common_columns. */ nj_col_1->is_common= FALSE; } @@ -7724,7 +7725,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, { const char *using_field_name_ptr= using_field_name->c_ptr(); List_iterator_fast - it(*(natural_using_join->join_columns)); + it(*join_columns); Natural_join_column *common_field; for (;;) @@ -7757,7 +7758,8 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, } if (non_join_columns->elements > 0) - natural_using_join->join_columns->concat(non_join_columns); + join_columns->concat(non_join_columns); + natural_using_join->join_columns= join_columns; natural_using_join->is_join_columns_complete= TRUE; result= FALSE; @@ -7989,7 +7991,6 @@ static bool setup_natural_join_row_types(THD *thd, DBUG_PRINT("info", ("using cached setup_natural_join_row_types")); DBUG_RETURN(false); } - context->select_lex->first_natural_join_processing= false; List_iterator_fast table_ref_it(*from_clause); TABLE_LIST *table_ref; /* Current table reference. */ @@ -8034,6 +8035,7 @@ static bool setup_natural_join_row_types(THD *thd, change on re-execution */ context->natural_join_first_table= context->first_name_resolution_table; + context->select_lex->first_natural_join_processing= false; DBUG_RETURN (false); } diff --git a/sql/table.cc b/sql/table.cc index 87a249defa0..48aa445e1aa 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5487,7 +5487,7 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, TABLE_LIST *parent_ nj_col= natural_join_it.column_ref(); DBUG_ASSERT(nj_col); } - DBUG_ASSERT(!nj_col->table_field || + DBUG_ASSERT(!nj_col->table_field || !nj_col->table_field->field || nj_col->table_ref->table == nj_col->table_field->field->table); /* @@ -5536,7 +5536,7 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, TABLE_LIST *parent_ RETURN # Pointer to a column of a natural join (or its operand) - NULL No memory to allocate the column + NULL We didn't originally have memory to allocate the column */ Natural_join_column * @@ -5552,7 +5552,7 @@ Field_iterator_table_ref::get_natural_column_ref() */ nj_col= natural_join_it.column_ref(); DBUG_ASSERT(nj_col && - (!nj_col->table_field || + (!nj_col->table_field || !nj_col->table_field->field || nj_col->table_ref->table == nj_col->table_field->field->table)); return nj_col; } From 9d41dd2f39f5a0c840d77e5fb7fc8d1396bf1a33 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 27 Jun 2018 15:34:11 +0400 Subject: [PATCH 18/71] MDEV-8540 - Crash on server shutdown since 10.0.16 For the purpose of reporting an error to error log, shutdown thread was attempting to access current_thd->variables.lc_messages->errmsgs->errmsgs. Whereas current_thd was NULL. We should log errors according to global lc_messages setting instead of session setting. --- sql/log.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index 5b4ba87ef52..2504b5e2d06 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2499,14 +2499,14 @@ void MYSQL_LOG::close(uint exiting) if (log_type == LOG_BIN && mysql_file_sync(log_file.file, MYF(MY_WME)) && ! write_error) { write_error= 1; - sql_print_error(ER_THD_OR_DEFAULT(current_thd, ER_ERROR_ON_WRITE), name, errno); + sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno); } if (!(exiting & LOG_CLOSE_DELAYED_CLOSE) && mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error) { write_error= 1; - sql_print_error(ER_THD_OR_DEFAULT(current_thd, ER_ERROR_ON_WRITE), name, errno); + sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno); } } @@ -2690,7 +2690,7 @@ err: if (!write_error) { write_error= 1; - sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); + sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno); } mysql_mutex_unlock(&LOCK_log); return TRUE; @@ -2866,7 +2866,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, if (! write_error) { write_error= 1; - sql_print_error(ER(ER_ERROR_ON_WRITE), name, tmp_errno); + sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, tmp_errno); } } } @@ -6385,7 +6385,7 @@ void MYSQL_BIN_LOG::close(uint exiting) if (mysql_file_close(index_file.file, MYF(0)) < 0 && ! write_error) { write_error= 1; - sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno); + sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), index_file_name, errno); } } log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED; From f46acd4a3a74c57a31226b11186746bce6c98813 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 29 Jun 2018 14:00:00 +0300 Subject: [PATCH 19/71] Adopt Debian's fix-FTBFS-on-GNU-Hurd.patch. - Took the original patch by Ondrej Sury; - Applied a fix for a known problem in the patch: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=882062 - Fixed a few other issues --- cmake/dtrace.cmake | 4 ++ cmake/package_name.cmake | 3 ++ extra/mariabackup/backup_copy.cc | 34 +++++++++----- sql/wsrep_binlog.cc | 45 ++++++++++++++----- storage/mroonga/vendor/groonga/config.h.cmake | 1 + 5 files changed, 67 insertions(+), 20 deletions(-) diff --git a/cmake/dtrace.cmake b/cmake/dtrace.cmake index d7ab0f31991..bb45eaf865b 100644 --- a/cmake/dtrace.cmake +++ b/cmake/dtrace.cmake @@ -46,6 +46,10 @@ MACRO(CHECK_DTRACE) AND NOT CMAKE_SYSTEM_NAME MATCHES "SunOS") SET(ENABLE_DTRACE ON CACHE BOOL "Enable dtrace") ENDIF() + # On GNU/Hurd, dtrace is not supported + IF(DTRACE AND CMAKE_SYSTEM_NAME MATCHES "GNU") + SET(ENABLE_DTRACE OFF CACHE BOOL "Disable dtrace") + ENDIF() SET(HAVE_DTRACE ${ENABLE_DTRACE}) IF(CMAKE_SYSTEM_NAME MATCHES "SunOS") IF(CMAKE_SIZEOF_VOID_P EQUAL 4) diff --git a/cmake/package_name.cmake b/cmake/package_name.cmake index 4930a6bf40a..a8bd1596f47 100644 --- a/cmake/package_name.cmake +++ b/cmake/package_name.cmake @@ -77,6 +77,9 @@ IF(NOT VERSION) SET(DEFAULT_MACHINE "i386") ENDIF() ENDIF() + ELSEIF(CMAKE_SYSTEM_NAME MATCHES "GNU") + SET(DEFAULT_PLATFORM "GNU") + SET(DEFAULT_MACHINE "i386") ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Darwin") IF(CMAKE_OSX_DEPLOYMENT_TARGET) SET(DEFAULT_PLATFORM "osx${CMAKE_OSX_DEPLOYMENT_TARGET}") diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index d3253348d72..7cdc6b8e3a6 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -623,11 +623,14 @@ static int mkdirp(const char *pathname, int Flags, myf MyFlags) { - char parent[PATH_MAX], *p; + char *parent, *p; + int len = strlen(pathname) + 1; /* make a parent directory path */ - strncpy(parent, pathname, sizeof(parent)); - parent[sizeof(parent) - 1] = 0; + if (!(parent= (char *)malloc(len))) + return(-1); + strncpy(parent, pathname, len); + parent[len-1]= 0; for (p = parent + strlen(parent); !is_path_separator(*p) && p != parent; p--); @@ -636,19 +639,23 @@ mkdirp(const char *pathname, int Flags, myf MyFlags) /* try to make parent directory */ if (p != parent && mkdirp(parent, Flags, MyFlags) != 0) { + free(parent); return(-1); } /* make this one if parent has been made */ if (my_mkdir(pathname, Flags, MyFlags) == 0) { + free(parent); return(0); } /* if it already exists that is fine */ if (errno == EEXIST) { + free(parent); return(0); } + free(parent); return(-1); } @@ -658,17 +665,24 @@ bool equal_paths(const char *first, const char *second) { #ifdef HAVE_REALPATH - char real_first[PATH_MAX]; - char real_second[PATH_MAX]; + char *real_first, *real_second; + int result; - if (realpath(first, real_first) == NULL) { - return false; - } - if (realpath(second, real_second) == NULL) { + real_first = realpath(first, 0); + if (real_first == NULL) { return false; } - return (strcmp(real_first, real_second) == 0); + real_second = realpath(second, 0); + if (real_second == NULL) { + free(real_first); + return false; + } + + result = strcmp(real_first, real_second); + free(real_first); + free(real_second); + return result == 0; #else return strcmp(first, second) == 0; #endif diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc index 998f4e72157..52934ff10cd 100644 --- a/sql/wsrep_binlog.cc +++ b/sql/wsrep_binlog.cc @@ -318,13 +318,23 @@ int wsrep_write_cache(wsrep_t* const wsrep, void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len) { - char filename[PATH_MAX]= {0}; - int len= snprintf(filename, PATH_MAX, "%s/GRA_%ld_%lld.log", + int len= snprintf(NULL, 0, "%s/GRA_%ld_%lld.log", wsrep_data_home_dir, thd->thread_id, (long long)wsrep_thd_trx_seqno(thd)); - if (len >= PATH_MAX) + if (len < 0) { - WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len); + WSREP_ERROR("snprintf error: %d, skipping dump.", len); + DBUG_VOID_RETURN; + } + + char *filename= (char *)malloc(len++); + int len1= snprintf(filename, len, "%s/GRA_%ld_%lld.log", + wsrep_data_home_dir, thd->thread_id, + (long long)wsrep_thd_trx_seqno(thd)); + if (len >= len1) + { + WSREP_ERROR("RBR dump path truncated: %d, skipping dump.", len); + free(filename); return; } @@ -343,6 +353,7 @@ void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len) WSREP_ERROR("Failed to open file '%s': %d (%s)", filename, errno, strerror(errno)); } + free(filename); } /* @@ -448,19 +459,32 @@ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf, { DBUG_ENTER("wsrep_dump_rbr_buf_with_header"); - char filename[PATH_MAX]= {0}; File file; IO_CACHE cache; Log_event_writer writer(&cache); Format_description_log_event *ev=NULL; - int len= my_snprintf(filename, PATH_MAX, "%s/GRA_%ld_%lld_v2.log", - wsrep_data_home_dir, thd->thread_id, - (long long) wsrep_thd_trx_seqno(thd)); + longlong thd_trx_seqno= (long long)wsrep_thd_trx_seqno(thd); - if (len >= PATH_MAX) + int len= my_snprintf(NULL, 0, "%s/GRA_%ld_%lld_v2.log", + wsrep_data_home_dir, thd->thread_id, + thd_trx_seqno); + + char *filename; + if (len < 0 || !(filename= (char*)malloc(len++))) { - WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len); + WSREP_ERROR("snprintf error: %d, skipping dump.", len); + DBUG_VOID_RETURN; + } + + int len1= my_snprintf(filename, len, "%s/GRA_%ld_%lld_v2.log", + wsrep_data_home_dir, thd->thread_id, + thd_trx_seqno); + + if (len >= len1) + { + WSREP_ERROR("RBR dump path truncated: %d, skipping dump.", len); + free(filename); DBUG_VOID_RETURN; } @@ -501,6 +525,7 @@ cleanup2: end_io_cache(&cache); cleanup1: + free(filename); mysql_file_close(file, MYF(MY_WME)); if (!thd->wsrep_applier) delete ev; diff --git a/storage/mroonga/vendor/groonga/config.h.cmake b/storage/mroonga/vendor/groonga/config.h.cmake index bfd0cbdc012..ec67c5eea23 100644 --- a/storage/mroonga/vendor/groonga/config.h.cmake +++ b/storage/mroonga/vendor/groonga/config.h.cmake @@ -107,6 +107,7 @@ #cmakedefine HAVE_SIGNAL_H #cmakedefine HAVE_SYS_MMAN_H #cmakedefine HAVE_SYS_PARAM_H +#cmakedefine HAVE_SYS_POLL_H #cmakedefine HAVE_SYS_RESOURCE_H #cmakedefine HAVE_SYS_SELECT_H #cmakedefine HAVE_SYS_SOCKET_H From 83bf267e0d386c35497f34c6ad7bd802c1c8de6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Fri, 29 Jun 2018 12:09:38 +0300 Subject: [PATCH 20/71] Fix Internal Compiler Error GCC-6.3.0 Change the float comparison function to use a negated version when comparing for equality. This actually produces less code when compiling with optimizations (O3) on. --- storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c index 44378cfae25..a3d838c327f 100644 --- a/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c +++ b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c @@ -562,7 +562,7 @@ inline static grn_ts_bool grn_ts_op_not_equal_float(grn_ts_float lhs, grn_ts_float rhs) { /* To suppress warnings, "lhs != rhs" is not used. */ - return (lhs < rhs) || (lhs > rhs); + return !grn_ts_op_equal_float(lhs, rhs); } /* grn_ts_op_not_equal_time() returns lhs != rhs. */ From 36ea82617c1506532e863cb241296acc8b657243 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 29 Jun 2018 18:16:56 +0300 Subject: [PATCH 21/71] Fix a typo a in the commit before the last one in the "Adopt Debian's fix-FTBFS-on-GNU-Hurd.patch", DBUG_VOID_RETURN has been used instead of "return" --- sql/wsrep_binlog.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc index 52934ff10cd..f8553d015aa 100644 --- a/sql/wsrep_binlog.cc +++ b/sql/wsrep_binlog.cc @@ -324,7 +324,7 @@ void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len) if (len < 0) { WSREP_ERROR("snprintf error: %d, skipping dump.", len); - DBUG_VOID_RETURN; + return; } char *filename= (char *)malloc(len++); From 90cb7212742e9ae3a63bd183e171c95bd12d559f Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 29 Jun 2018 22:46:38 -0700 Subject: [PATCH 22/71] MDEV-16603 Crash with set join_cache_level=4 When the definition of the index used for hash join was created in create_hj_key_for_table() it could cause memory overwrite due to a bug that led to an underestimation of the number of the index component. --- mysql-test/r/join_cache.result | 33 +++++++++++++++++++++++++++++++++ mysql-test/t/join_cache.test | 31 +++++++++++++++++++++++++++++++ sql/sql_select.cc | 4 ++-- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index 386f7119bc8..f1e6fb577c8 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5871,4 +5871,37 @@ SET join_buffer_size = default; SET join_buffer_space_limit= default; set optimizer_switch=@save_optimizer_switch; DROP TABLE t1,t4,t5,t2; +# +# MDEV-16603: BNLH for query with materialized semi-join +# +set join_cache_level=4; +CREATE TABLE t1 ( i1 int, v1 varchar(1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (7,'x'); +CREATE TABLE t2 (i1 int, v1 varchar(1), KEY v1 (v1,i1)) ENGINE=InnoDB; +INSERT INTO t2 VALUES +(NULL,'x'),(1,'x'),(3,'x'),(5,'x'),(8,'x'),(48,'x'), +(228,'x'),(3,'y'),(1,'z'),(9,'z'); +CREATE TABLE temp +SELECT t1.i1 AS f1, t1.v1 AS f2 FROM (t2 JOIN t1 ON (t1.v1 = t2.v1)); +SELECT * FROM temp +WHERE (f1,f2) IN (SELECT t1.i1, t1.v1 FROM (t2 JOIN t1 ON (t1.v1 = t2.v1))); +f1 f2 +7 x +7 x +7 x +7 x +7 x +7 x +7 x +EXPLAIN EXTENDED SELECT * FROM temp +WHERE (f1,f2) IN (SELECT t1.i1, t1.v1 FROM (t2 JOIN t1 ON (t1.v1 = t2.v1))); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 1 100.00 +1 PRIMARY temp hash_ALL NULL #hash#$hj 9 test.t1.i1,test.t1.v1 7 100.00 Using where; Using join buffer (flat, BNLH join) +2 MATERIALIZED t1 ALL NULL NULL NULL NULL 1 100.00 Using where +2 MATERIALIZED t2 hash_index v1 #hash#v1:v1 4:9 test.t1.v1 10 10.00 Using join buffer (flat, BNLH join) +Warnings: +Note 1003 select `test`.`temp`.`f1` AS `f1`,`test`.`temp`.`f2` AS `f2` from `test`.`temp` semi join (`test`.`t2` join `test`.`t1`) where ((`test`.`temp`.`f1` = `test`.`t1`.`i1`) and (`test`.`t2`.`v1` = `test`.`t1`.`v1`) and (`test`.`temp`.`f2` = `test`.`t1`.`v1`)) +DROP TABLE t1,t2,temp; +SET join_cache_level = default; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index 58a7b885356..d82b4fa6030 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3836,5 +3836,36 @@ set optimizer_switch=@save_optimizer_switch; DROP TABLE t1,t4,t5,t2; +--echo # +--echo # MDEV-16603: BNLH for query with materialized semi-join +--echo # + +--source include/have_innodb.inc + +set join_cache_level=4; + +CREATE TABLE t1 ( i1 int, v1 varchar(1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (7,'x'); + +CREATE TABLE t2 (i1 int, v1 varchar(1), KEY v1 (v1,i1)) ENGINE=InnoDB; + +INSERT INTO t2 VALUES + (NULL,'x'),(1,'x'),(3,'x'),(5,'x'),(8,'x'),(48,'x'), + (228,'x'),(3,'y'),(1,'z'),(9,'z'); + +CREATE TABLE temp +SELECT t1.i1 AS f1, t1.v1 AS f2 FROM (t2 JOIN t1 ON (t1.v1 = t2.v1)); + +let $q = +SELECT * FROM temp +WHERE (f1,f2) IN (SELECT t1.i1, t1.v1 FROM (t2 JOIN t1 ON (t1.v1 = t2.v1))); + +eval $q; +eval EXPLAIN EXTENDED $q; + +DROP TABLE t1,t2,temp; + +SET join_cache_level = default; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b79431ae2f6..700b7b37928 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7994,7 +7994,6 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, if (first_keyuse) { key_parts++; - first_keyuse= FALSE; } else { @@ -8004,7 +8003,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, if (curr->keypart == keyuse->keypart && !(~used_tables & curr->used_tables) && join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, - keyuse) && + curr) && are_tables_local(join_tab, curr->used_tables)) break; } @@ -8012,6 +8011,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, key_parts++; } } + first_keyuse= FALSE; keyuse++; } while (keyuse->table == table && keyuse->is_for_hash_join()); if (!key_parts) From 1d10c9afe0f2f4fba73892e6c12ea6efe90d5931 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Mon, 2 Jul 2018 15:29:22 +0300 Subject: [PATCH 23/71] Post-fix to "Adopt Debian's fix-FTBFS-on-GNU-Hurd.patch", part #2. "my_snprintf(NULL, 0, ...)" does not follow what snprintf does. Change the call in wsrep_dump_rbr_buf_with_header to use snprintf (note that wsrep_dump_rbr_buf was using snprintf all the way). Fix an off-by-one error in comparison so it actually prints the output --- sql/wsrep_binlog.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc index f8553d015aa..902190d4772 100644 --- a/sql/wsrep_binlog.cc +++ b/sql/wsrep_binlog.cc @@ -327,11 +327,11 @@ void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len) return; } - char *filename= (char *)malloc(len++); + char *filename= (char *)malloc(len+1); int len1= snprintf(filename, len, "%s/GRA_%ld_%lld.log", wsrep_data_home_dir, thd->thread_id, (long long)wsrep_thd_trx_seqno(thd)); - if (len >= len1) + if (len > len1) { WSREP_ERROR("RBR dump path truncated: %d, skipping dump.", len); free(filename); @@ -466,22 +466,22 @@ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf, longlong thd_trx_seqno= (long long)wsrep_thd_trx_seqno(thd); - int len= my_snprintf(NULL, 0, "%s/GRA_%ld_%lld_v2.log", - wsrep_data_home_dir, thd->thread_id, - thd_trx_seqno); + int len= snprintf(NULL, 0, "%s/GRA_%ld_%lld_v2.log", + wsrep_data_home_dir, thd->thread_id, + thd_trx_seqno); char *filename; - if (len < 0 || !(filename= (char*)malloc(len++))) + if (len < 0 || !(filename= (char*)malloc(len+1))) { WSREP_ERROR("snprintf error: %d, skipping dump.", len); DBUG_VOID_RETURN; } - int len1= my_snprintf(filename, len, "%s/GRA_%ld_%lld_v2.log", - wsrep_data_home_dir, thd->thread_id, - thd_trx_seqno); + int len1= snprintf(filename, len, "%s/GRA_%ld_%lld_v2.log", + wsrep_data_home_dir, thd->thread_id, + thd_trx_seqno); - if (len >= len1) + if (len > len1) { WSREP_ERROR("RBR dump path truncated: %d, skipping dump.", len); free(filename); From 0897a25c0f0b9b86590fd581795aa64b3fbef009 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 2 Jul 2018 15:02:31 +0100 Subject: [PATCH 24/71] MDEV-16596 : Windows - redo log does not work on native 4K sector disks. Disks with native 4K sectors need 4K alignment and size for unbuffered IO (i.e for files opened with FILE_FLAG_NO_BUFFERING) Innodb opens redo log with FILE_FLAG_NO_BUFFERING, however it always does 512byte IOs. Thus, the IO on 4K native sectors will fail, rendering Innodb non-functional. The fix is to check whether OS_FILE_LOG_BLOCK_SIZE is multiple of logical sector size, and if it is not, reopen the redo log without FILE_FLAG_NO_BUFFERING flag. --- cmake/os/Windows.cmake | 2 +- storage/xtradb/os/os0file.cc | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index e4221227d91..b69ae9bebf8 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -51,7 +51,7 @@ IF(CMAKE_C_COMPILER MATCHES "icl") ENDIF() ADD_DEFINITIONS(-D_WINDOWS -D__WIN__ -D_CRT_SECURE_NO_DEPRECATE) -ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) +ADD_DEFINITIONS(-D_WIN32_WINNT=0x0A00) # We do not want the windows.h macros min/max ADD_DEFINITIONS(-DNOMINMAX) # Speed up build process excluding unused header files diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index 9df42470e5a..bf9db50b7f7 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -1691,6 +1691,31 @@ os_file_set_atomic_writes( #endif } +/** Check that IO of specific size is possible for the file +opened with FILE_FLAG_NO_BUFFERING. + +The requirement is that IO is multiple of the disk sector size. + +@param[in] file file handle +@param[in] io_size expected io size +@return true - unbuffered io of requested size is possible, false otherwise. + +@note: this function only works correctly with Windows 8 or later, +(GetFileInformationByHandleEx with FileStorageInfo is only supported there). +It will return true on earlier Windows version. +*/ +static bool unbuffered_io_possible(HANDLE file, size_t io_size) +{ + FILE_STORAGE_INFO info; + if (GetFileInformationByHandleEx( + file, FileStorageInfo, &info, sizeof(info))) { + ULONG sector_size = info.LogicalBytesPerSector; + if (sector_size) + return io_size % sector_size == 0; + } + return true; +} + /****************************************************************//** NOTE! Use the corresponding macro os_file_create(), not directly this function! @@ -1851,6 +1876,18 @@ os_file_create_func( (LPCTSTR) name, access, share_mode, NULL, create_flag, attributes, NULL); + /* If FILE_FLAG_NO_BUFFERING was set, check if this can work at all, + for expected IO sizes. Reopen without the unbuffered flag, if it is won't work*/ + if ((file.m_file != INVALID_HANDLE_VALUE) + && (attributes & FILE_FLAG_NO_BUFFERING) + && (type == OS_LOG_FILE) + && !unbuffered_io_possible(file.m_file, OS_FILE_LOG_BLOCK_SIZE)) { + ut_a(CloseHandle(file.m_file)); + attributes &= ~FILE_FLAG_NO_BUFFERING; + create_flag = OPEN_ALWAYS; + continue; + } + if (file.m_file == INVALID_HANDLE_VALUE) { const char* operation; From 8c5d64dafb3051749f3762cbad88553568abbb16 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 2 Jul 2018 15:22:52 +0100 Subject: [PATCH 25/71] Post-fix after MDEV-8540 - do not close stdin on Windows. It is not open. --- sql/mysqld.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d760986a303..75d6cca7fda 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5149,8 +5149,10 @@ int win_main(int argc, char **argv) int mysqld_main(int argc, char **argv) #endif { +#ifndef _WIN32 /* We can't close stdin just now, because it may be booststrap mode. */ bool please_close_stdin= fcntl(STDIN_FILENO, F_GETFD) >= 0; +#endif /* Perform basic thread library and malloc initialization, @@ -5495,9 +5497,12 @@ int mysqld_main(int argc, char **argv) (char*) "" : mysqld_unix_port), mysqld_port, MYSQL_COMPILATION_COMMENT); +#ifndef _WIN32 /* Only close stdin if it was open initinally. */ if (please_close_stdin) fclose(stdin); +#endif + #if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) Service.SetRunning(); #endif From a2c0376e08d80d7b7dad8713d1df334b2b81eff9 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 2 Jul 2018 17:45:19 +0100 Subject: [PATCH 26/71] Fix build on non-Windows, broken by 0897a25c0f0b9b865 --- storage/xtradb/os/os0file.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index bf9db50b7f7..4246bfbff70 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -1691,6 +1691,7 @@ os_file_set_atomic_writes( #endif } +#ifdef _WIN32 /** Check that IO of specific size is possible for the file opened with FILE_FLAG_NO_BUFFERING. @@ -1715,6 +1716,7 @@ static bool unbuffered_io_possible(HANDLE file, size_t io_size) } return true; } +#endif /****************************************************************//** NOTE! Use the corresponding macro os_file_create(), not directly From 24a0a74f5d92a861989fcea17a0c62c1ee7b1299 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Tue, 10 Jul 2018 13:54:04 +0530 Subject: [PATCH 27/71] MDEV-16307: Incorrect results when using BNLH join instead of BNL join with views In this issue we are using derived_with_keys optimization and we are using these keys to do a hash join which is incorrect. We cannot create keys for dervied tables whose keyparts have types are of BLOB or TEXT type. TEXT or BLOB columns can only be indexed over a specified length. --- mysql-test/r/derived.result | 33 +++++++++++++++++++++++++++++++++ mysql-test/t/derived.test | 21 +++++++++++++++++++++ sql/table.cc | 13 +++++++++++-- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index 54c78dc9f6f..5debfaed5e3 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -1023,6 +1023,7 @@ INSERT INTO t2 VALUES (NULL),(NULL); CREATE TABLE t3 (c VARCHAR(1024) CHARACTER SET utf8, d INT) ENGINE=MyISAM; CREATE OR REPLACE ALGORITHM=TEMPTABLE VIEW v3 AS SELECT * FROM t3; INSERT INTO t3 VALUES ('abc',NULL),('def',4); +set @save_join_cache_level= @@join_cache_level; SET join_cache_level= 8; explain SELECT * FROM v1, t2, v3 WHERE a = c AND b = d; @@ -1052,4 +1053,36 @@ i drop procedure pr; drop view v1; drop table t1; +set @@join_cache_level= @save_join_cache_level; +# +# MDEV-16307: Incorrect results when using BNLH join instead of BNL join with views +# +CREATE TABLE t1 (c1 text, c2 int); +INSERT INTO t1 VALUES ('a',1), ('c',3), ('g',7), ('d',4), ('c',3); +CREATE TABLE t2 (c1 text, c2 int); +INSERT INTO t2 VALUES ('b',2), ('c',3); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +explain SELECT v1.c1, v1.c2, t2.c1, t2.c2 FROM v1, t2 WHERE v1.c1=t2.c1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join) +2 DERIVED t1 ALL NULL NULL NULL NULL 5 +SELECT v1.c1, v1.c2, t2.c1, t2.c2 FROM v1, t2 WHERE v1.c1=t2.c1; +c1 c2 c1 c2 +c 3 c 3 +c 3 c 3 +set @save_join_cache_level= @@join_cache_level; +set @@join_cache_level=4; +explain SELECT v1.c1, v1.c2, t2.c1, t2.c2 FROM v1, t2 WHERE v1.c1=t2.c1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY hash_ALL NULL #hash#$hj 3 test.t2.c1 5 Using where; Using join buffer (flat, BNLH join) +2 DERIVED t1 ALL NULL NULL NULL NULL 5 +SELECT v1.c1, v1.c2, t2.c1, t2.c2 FROM v1, t2 WHERE v1.c1=t2.c1; +c1 c2 c1 c2 +c 3 c 3 +c 3 c 3 +drop table t1,t2; +drop view v1; +set @@join_cache_level= @save_join_cache_level; # end of 5.5 diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index c5b792c8d4d..217203422e0 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -880,6 +880,7 @@ CREATE TABLE t3 (c VARCHAR(1024) CHARACTER SET utf8, d INT) ENGINE=MyISAM; CREATE OR REPLACE ALGORITHM=TEMPTABLE VIEW v3 AS SELECT * FROM t3; INSERT INTO t3 VALUES ('abc',NULL),('def',4); +set @save_join_cache_level= @@join_cache_level; SET join_cache_level= 8; explain SELECT * FROM v1, t2, v3 WHERE a = c AND b = d; @@ -902,5 +903,25 @@ call pr(2); drop procedure pr; drop view v1; drop table t1; +set @@join_cache_level= @save_join_cache_level; +--echo # +--echo # MDEV-16307: Incorrect results when using BNLH join instead of BNL join with views +--echo # + +CREATE TABLE t1 (c1 text, c2 int); +INSERT INTO t1 VALUES ('a',1), ('c',3), ('g',7), ('d',4), ('c',3); +CREATE TABLE t2 (c1 text, c2 int); +INSERT INTO t2 VALUES ('b',2), ('c',3); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; + +explain SELECT v1.c1, v1.c2, t2.c1, t2.c2 FROM v1, t2 WHERE v1.c1=t2.c1; +SELECT v1.c1, v1.c2, t2.c1, t2.c2 FROM v1, t2 WHERE v1.c1=t2.c1; +set @save_join_cache_level= @@join_cache_level; +set @@join_cache_level=4; +explain SELECT v1.c1, v1.c2, t2.c1, t2.c2 FROM v1, t2 WHERE v1.c1=t2.c1; +SELECT v1.c1, v1.c2, t2.c1, t2.c2 FROM v1, t2 WHERE v1.c1=t2.c1; +drop table t1,t2; +drop view v1; +set @@join_cache_level= @save_join_cache_level; --echo # end of 5.5 diff --git a/sql/table.cc b/sql/table.cc index 48aa445e1aa..f6152a36eef 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6060,6 +6060,14 @@ void TABLE::create_key_part_by_field(KEY_PART_INFO *key_part_info, The function checks whether a possible key satisfies the constraints imposed on the keys of any temporary table. + We need to filter out BLOB columns here, because ref access optimizer creates + KEYUSE objects for equalities for non-key columns for two puproses: + 1. To discover possible keys for derived_with_keys optimization + 2. To do hash joins + For the purpose of #1, KEYUSE objects are not created for "blob_column=..." . + However, they might be created for #2. In order to catch that case, we filter + them out here. + @return TRUE if the key is valid @return FALSE otherwise */ @@ -6075,11 +6083,12 @@ bool TABLE::check_tmp_key(uint key, uint key_parts, { uint fld_idx= next_field_no(arg); reg_field= field + fld_idx; + if ((*reg_field)->type() == MYSQL_TYPE_BLOB) + return FALSE; uint fld_store_len= (uint16) (*reg_field)->key_length(); if ((*reg_field)->real_maybe_null()) fld_store_len+= HA_KEY_NULL_LENGTH; - if ((*reg_field)->type() == MYSQL_TYPE_BLOB || - (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR || + if ((*reg_field)->real_type() == MYSQL_TYPE_VARCHAR || (*reg_field)->type() == MYSQL_TYPE_GEOMETRY) fld_store_len+= HA_KEY_BLOB_LENGTH; key_len+= fld_store_len; From 2fbf2277ffec86d69f793534da7043b6dd540780 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 11 Jul 2018 10:43:38 +0300 Subject: [PATCH 28/71] MDEV-15982: Incorrect results when subquery is materialized fix_semijoin_strategies_for_picked_join_order() should set join->sjm_lookup_tables to be a bitmap of tables inside SJ-Materialization-Lookup nests. --- mysql-test/r/subselect_sj2_mat.result | 51 +++++++++++++++++++++++++++ mysql-test/t/subselect_sj2_mat.test | 49 +++++++++++++++++++++++++ sql/opt_subselect.cc | 3 +- 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect_sj2_mat.result b/mysql-test/r/subselect_sj2_mat.result index 19aa3bd3f02..7f97e1aabee 100644 --- a/mysql-test/r/subselect_sj2_mat.result +++ b/mysql-test/r/subselect_sj2_mat.result @@ -1658,3 +1658,54 @@ id 12 13 drop table t1; +# +# MDEV-15982: Incorrect results when subquery is materialized +# +CREATE TABLE `t1` (`id` int(32) NOT NULL primary key); +INSERT INTO `t1` VALUES +(45), (46), (47), (48), (49), (50), (51), (52), (53), (54), (55), (56), (57), (58), (59), (60), (61), (62), +(63), (64), (65), (66), (67), (68), (69), (70), (71), (72), (73), (74), (75), (76), (77), (78), (79), (80), +(81), (82), (83), (84), (85), (86), (87), (88), (89), (90), (91), (92),(93),(94),(95),(96), (97), (98), +(99), (100), (101), (102), (103), (104), (105), (106), (107), (108), (109), (110), (111), (112), (113), +(114), (115), (116), (117), (118), (119), (120), (121), (122), (123), (124), (125), (126), (127), (128), +(129), (130), (131), (132), (133), (134), (135), (136), (137), (138), (139), (140), (141), (142), (143), (144), (145), (146), +(147), (148), (149), (150), (151), (152), (153), (154), (155), (156), (157), (158), (159), (160), (161), +(162), (163), (164), (165), (166), (167), (168), (169), (170), (171), (172), (173), +(174), (175), (176), (177), (178), (179), (180), (181), (182), (183), (2), (3), (4), (5), (6), (19), (35), +(7), (20), (8), (36), (219), (22), (10), (23), (37), (11), (24); +CREATE TABLE `t2` (`type` int , `id` int(32) NOT NULL primary key); +INSERT INTO `t2` VALUES +(2,2),(2,3),(1,4),(2,5),(1,6),(1,19),(5,7),(1,20),(1,8),(1,21),(1,9), +(1,22),(2,10),(1,23),(2,11),(1,24),(1,12),(1,25),(2,13),(2,26),(2,14), +(2,27),(1,15),(1,28),(3,16),(1,29),(2,17),(1,30),(5,18),(2,1); +CREATE TABLE `t3` (`ref_id` int(32) unsigned ,`type` varchar(80),`id` int(32) NOT NULL ); +INSERT INTO `t3` VALUES +(1,'incident',31),(2,'faux pas',32), +(5,'oopsies',33),(3,'deniable',34), +(11,'wasntme',35),(10,'wasntme',36), +(17,'faux pas',37),(13,'unlikely',38), +(13,'improbable',39),(14,'incident',40), +(26,'problem',41),(14,'problem',42), +(26,'incident',43),(27,'incident',44); +explain +SELECT t2.id FROM t2,t1 +WHERE t2.id IN (SELECT t3.ref_id FROM t3,t1 where t3.id = t1.id) and t2.id = t1.id; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 30 Using index +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 Using where +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 test.t2.id 1 Using index +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 14 +2 MATERIALIZED t1 eq_ref PRIMARY PRIMARY 4 test.t3.id 1 Using index +SELECT t2.id FROM t2,t1 +WHERE t2.id IN (SELECT t3.ref_id FROM t3,t1 where t3.id = t1.id) and t2.id = t1.id; +id +10 +11 +set optimizer_switch='materialization=off'; +SELECT t2.id FROM t2,t1 +WHERE t2.id IN (SELECT t3.ref_id FROM t3,t1 where t3.id = t1.id) and t2.id = t1.id; +id +11 +10 +set optimizer_switch='materialization=on'; +DROP TABLE t1,t2,t3; diff --git a/mysql-test/t/subselect_sj2_mat.test b/mysql-test/t/subselect_sj2_mat.test index 0665cdf68fe..43b63459928 100644 --- a/mysql-test/t/subselect_sj2_mat.test +++ b/mysql-test/t/subselect_sj2_mat.test @@ -345,3 +345,52 @@ WHERE ( (t.id IN (0,4,12,13,1,10,3,11)) ); drop table t1; +--echo # +--echo # MDEV-15982: Incorrect results when subquery is materialized +--echo # + +CREATE TABLE `t1` (`id` int(32) NOT NULL primary key); +INSERT INTO `t1` VALUES +(45), (46), (47), (48), (49), (50), (51), (52), (53), (54), (55), (56), (57), (58), (59), (60), (61), (62), +(63), (64), (65), (66), (67), (68), (69), (70), (71), (72), (73), (74), (75), (76), (77), (78), (79), (80), +(81), (82), (83), (84), (85), (86), (87), (88), (89), (90), (91), (92),(93),(94),(95),(96), (97), (98), +(99), (100), (101), (102), (103), (104), (105), (106), (107), (108), (109), (110), (111), (112), (113), +(114), (115), (116), (117), (118), (119), (120), (121), (122), (123), (124), (125), (126), (127), (128), +(129), (130), (131), (132), (133), (134), (135), (136), (137), (138), (139), (140), (141), (142), (143), (144), (145), (146), +(147), (148), (149), (150), (151), (152), (153), (154), (155), (156), (157), (158), (159), (160), (161), +(162), (163), (164), (165), (166), (167), (168), (169), (170), (171), (172), (173), +(174), (175), (176), (177), (178), (179), (180), (181), (182), (183), (2), (3), (4), (5), (6), (19), (35), +(7), (20), (8), (36), (219), (22), (10), (23), (37), (11), (24); + +CREATE TABLE `t2` (`type` int , `id` int(32) NOT NULL primary key); +INSERT INTO `t2` VALUES +(2,2),(2,3),(1,4),(2,5),(1,6),(1,19),(5,7),(1,20),(1,8),(1,21),(1,9), +(1,22),(2,10),(1,23),(2,11),(1,24),(1,12),(1,25),(2,13),(2,26),(2,14), +(2,27),(1,15),(1,28),(3,16),(1,29),(2,17),(1,30),(5,18),(2,1); + +CREATE TABLE `t3` (`ref_id` int(32) unsigned ,`type` varchar(80),`id` int(32) NOT NULL ); +INSERT INTO `t3` VALUES +(1,'incident',31),(2,'faux pas',32), +(5,'oopsies',33),(3,'deniable',34), +(11,'wasntme',35),(10,'wasntme',36), +(17,'faux pas',37),(13,'unlikely',38), +(13,'improbable',39),(14,'incident',40), +(26,'problem',41),(14,'problem',42), +(26,'incident',43),(27,'incident',44); + +explain +SELECT t2.id FROM t2,t1 + WHERE t2.id IN (SELECT t3.ref_id FROM t3,t1 where t3.id = t1.id) and t2.id = t1.id; + +SELECT t2.id FROM t2,t1 + WHERE t2.id IN (SELECT t3.ref_id FROM t3,t1 where t3.id = t1.id) and t2.id = t1.id; + +set optimizer_switch='materialization=off'; + +SELECT t2.id FROM t2,t1 + WHERE t2.id IN (SELECT t3.ref_id FROM t3,t1 where t3.id = t1.id) and t2.id = t1.id; +set optimizer_switch='materialization=on'; + +DROP TABLE t1,t2,t3; + + diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index ec7b10f20c8..14b2aaee591 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -3532,7 +3532,8 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) first= tablenr - sjm->tables + 1; join->best_positions[first].n_sj_tables= sjm->tables; join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE; - join->sjm_lookup_tables|= s->table->map; + for (uint i= first; i < first+ sjm->tables; i++) + join->sjm_lookup_tables |= join->best_positions[i].table->table->map; } else if (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN) { From ad9d1e8c3f5a8e1b3e222921e825247aa47c4d23 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Wed, 11 Jul 2018 02:28:42 +0530 Subject: [PATCH 29/71] MDEV-16552: [10.0] ASAN global-buffer-overflow in is_stat_table / statistics_for_tables_is_needed Backport the fix f214d365121 to 10.0 Author: Sergei Golubchik Date: Tue Apr 17 00:44:34 2018 +0200 ASAN error in is_stat_table() don't memcmp beyond the first argument's end Also: use my_strcasecmp(table_alias_charset), like elsewhere, not memcmp --- mysql-test/r/stat_tables.result | 7 +++++++ mysql-test/r/stat_tables_innodb.result | 7 +++++++ mysql-test/t/stat_tables.test | 6 ++++++ sql/sql_statistics.cc | 4 ++-- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index fcced761283..4a608089d7d 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -516,4 +516,11 @@ use test; drop database db1; drop database db2; drop table t1; +# +# MDEV-16552: [10.0] ASAN global-buffer-overflow in is_stat_table / statistics_for_tables_is_needed +# +SET use_stat_tables = PREFERABLY; +SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ); +CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ) +NULL set use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result index 0e866755532..87049b228e5 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -543,6 +543,13 @@ use test; drop database db1; drop database db2; drop table t1; +# +# MDEV-16552: [10.0] ASAN global-buffer-overflow in is_stat_table / statistics_for_tables_is_needed +# +SET use_stat_tables = PREFERABLY; +SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ); +CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ) +NULL set use_stat_tables=@save_use_stat_tables; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; SET SESSION STORAGE_ENGINE=DEFAULT; diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test index 4cbaa9e27c8..9f94cf1b5a7 100644 --- a/mysql-test/t/stat_tables.test +++ b/mysql-test/t/stat_tables.test @@ -305,4 +305,10 @@ drop database db1; drop database db2; drop table t1; +--echo # +--echo # MDEV-16552: [10.0] ASAN global-buffer-overflow in is_stat_table / statistics_for_tables_is_needed +--echo # + +SET use_stat_tables = PREFERABLY; +SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ); set use_stat_tables=@save_use_stat_tables; diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 1febc02b903..be4547a69df 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -3858,11 +3858,11 @@ bool is_stat_table(const char *db, const char *table) { DBUG_ASSERT(db && table); - if (!memcmp(db, stat_tables_db_name.str, stat_tables_db_name.length)) + if (!my_strcasecmp(table_alias_charset, db, stat_tables_db_name.str)) { for (uint i= 0; i < STATISTICS_TABLES; i ++) { - if (!memcmp(table, stat_table_name[i].str, stat_table_name[i].length)) + if (!my_strcasecmp(table_alias_charset, table, stat_table_name[i].str)) return true; } } From c89bb15c31f98d2d368414c7366ce61955b70b44 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 13 Jul 2018 17:48:30 -0700 Subject: [PATCH 30/71] MDEV-16757 Memory leak after adding manually min/max statistical data for blob column ANALYZE TABLE does not collect statistical data on min/max values for BLOB columns of
. However these values can be added into mysql.column_stats manually by executing proper statements. Unfortunately this led to a memory leak because the memory allocated for these values was never freed. This patch provides the server with a function to free memory allocated for min/max statistical values of BLOB types. --- mysql-test/r/stat_tables.result | 28 ++++++++++++++++++++++ mysql-test/r/stat_tables_innodb.result | 28 ++++++++++++++++++++++ mysql-test/t/stat_tables.test | 24 +++++++++++++++++++ sql/sql_statistics.cc | 33 ++++++++++++++++++++++++++ sql/sql_statistics.h | 1 + sql/table_cache.cc | 2 ++ 6 files changed, 116 insertions(+) diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index 4a608089d7d..e6b675060a5 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -524,3 +524,31 @@ SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ); CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ) NULL set use_stat_tables=@save_use_stat_tables; +# +# MDEV-16757: manual addition of min/max statistics for BLOB +# +SET use_stat_tables= PREFERABLY; +CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +test t1 t NULL NULL 0.0000 3.0000 NULL NULL NULL NULL +DELETE FROM mysql.column_stats +WHERE db_name='test' AND table_name='t1' AND column_name='t'; +INSERT INTO mysql.column_stats VALUES +('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL); +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL +SELECT pk FROM t1; +pk +1 +2 +DROP TABLE t1; +set use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result index 87049b228e5..04d73868cfb 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -551,5 +551,33 @@ SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ); CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ) NULL set use_stat_tables=@save_use_stat_tables; +# +# MDEV-16757: manual addition of min/max statistics for BLOB +# +SET use_stat_tables= PREFERABLY; +CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +test t1 t NULL NULL 0.0000 3.0000 NULL NULL NULL NULL +DELETE FROM mysql.column_stats +WHERE db_name='test' AND table_name='t1' AND column_name='t'; +INSERT INTO mysql.column_stats VALUES +('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL); +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL +SELECT pk FROM t1; +pk +1 +2 +DROP TABLE t1; +set use_stat_tables=@save_use_stat_tables; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; SET SESSION STORAGE_ENGINE=DEFAULT; diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test index 9f94cf1b5a7..843e6f8aa0b 100644 --- a/mysql-test/t/stat_tables.test +++ b/mysql-test/t/stat_tables.test @@ -312,3 +312,27 @@ drop table t1; SET use_stat_tables = PREFERABLY; SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ); set use_stat_tables=@save_use_stat_tables; + +--echo # +--echo # MDEV-16757: manual addition of min/max statistics for BLOB +--echo # + +SET use_stat_tables= PREFERABLY; + +CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +--sorted_result +SELECT * FROM mysql.column_stats; +DELETE FROM mysql.column_stats + WHERE db_name='test' AND table_name='t1' AND column_name='t'; +INSERT INTO mysql.column_stats VALUES + ('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL); +--sorted_result +SELECT * FROM mysql.column_stats; + +SELECT pk FROM t1; + +DROP TABLE t1; + +set use_stat_tables=@save_use_stat_tables; diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index be4547a69df..537ede91710 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -2916,6 +2916,39 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) } +/** + @breif + Cleanup of min/max statistical values for table share +*/ + +void delete_stat_values_for_table_share(TABLE_SHARE *table_share) +{ + TABLE_STATISTICS_CB *stats_cb= &table_share->stats_cb; + Table_statistics *table_stats= stats_cb->table_stats; + if (!table_stats) + return; + Column_statistics *column_stats= table_stats->column_stats; + if (!column_stats) + return; + + for (Field **field_ptr= table_share->field; + *field_ptr; + field_ptr++, column_stats++) + { + if (column_stats->min_value) + { + delete column_stats->min_value; + column_stats->min_value= NULL; + } + if (column_stats->max_value) + { + delete column_stats->max_value; + column_stats->max_value= NULL; + } + } +} + + /** @brief Check whether any statistics is to be read for tables from a table list diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h index 20b2eb66449..6a43e42ab96 100644 --- a/sql/sql_statistics.h +++ b/sql/sql_statistics.h @@ -89,6 +89,7 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables); int collect_statistics_for_table(THD *thd, TABLE *table); int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *share, bool is_safe); +void delete_stat_values_for_table_share(TABLE_SHARE *table_share); int alloc_statistics_for_table(THD *thd, TABLE *table); int update_statistics_for_table(THD *thd, TABLE *table); int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab); diff --git a/sql/table_cache.cc b/sql/table_cache.cc index bdb7914c32b..a31068c9bc3 100644 --- a/sql/table_cache.cc +++ b/sql/table_cache.cc @@ -52,6 +52,7 @@ #include "hash.h" #include "table.h" #include "sql_base.h" +#include "sql_statistics.h" /** Configuration. */ ulong tdc_size; /**< Table definition cache threshold for LRU eviction. */ @@ -869,6 +870,7 @@ void tdc_release_share(TABLE_SHARE *share) mysql_mutex_lock(&share->tdc.LOCK_table_share); if (share->tdc.flushed) { + delete_stat_values_for_table_share(share); mysql_mutex_unlock(&share->tdc.LOCK_table_share); mysql_mutex_unlock(&LOCK_unused_shares); tdc_delete_share_from_hash(share); From 1fd84f9129f2ed98706f6e225b06b16a13d0ebd0 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 13 Jul 2018 23:03:57 -0700 Subject: [PATCH 31/71] MDEV-16760 CREATE OR REPLACE TABLE never updates statistical tables If the command CREATE OR REPLACE TABLE really replaces a table then it should remove all data on this table from all statistical tables. --- mysql-test/r/stat_tables.result | 25 +++++++++++++++++++++++++ mysql-test/r/stat_tables_innodb.result | 25 +++++++++++++++++++++++++ mysql-test/t/stat_tables.test | 20 ++++++++++++++++++++ sql/sql_table.cc | 4 ++++ 4 files changed, 74 insertions(+) diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index e6b675060a5..c1457d5e91a 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -552,3 +552,28 @@ pk 2 DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-16760: CREATE OR REPLACE TABLE after ANALYZE TABLE +# +SET use_stat_tables= PREFERABLY; +CREATE TABLE t1 (pk int PRIMARY KEY, c varchar(32)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +SELECT * FROM t1; +pk c +1 foo +2 bar +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +test t1 c bar foo 0.0000 3.0000 1.0000 0 NULL NULL +CREATE OR REPLACE TABLE t1 (pk int PRIMARY KEY, a char(7)); +SELECT * FROM t1; +pk a +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +DROP TABLE t1; +set use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result index 04d73868cfb..2ac868e9341 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -579,5 +579,30 @@ pk 2 DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-16760: CREATE OR REPLACE TABLE after ANALYZE TABLE +# +SET use_stat_tables= PREFERABLY; +CREATE TABLE t1 (pk int PRIMARY KEY, c varchar(32)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +SELECT * FROM t1; +pk c +1 foo +2 bar +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +test t1 c bar foo 0.0000 3.0000 1.0000 0 NULL NULL +CREATE OR REPLACE TABLE t1 (pk int PRIMARY KEY, a char(7)); +SELECT * FROM t1; +pk a +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +DROP TABLE t1; +set use_stat_tables=@save_use_stat_tables; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; SET SESSION STORAGE_ENGINE=DEFAULT; diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test index 843e6f8aa0b..d69b00618ea 100644 --- a/mysql-test/t/stat_tables.test +++ b/mysql-test/t/stat_tables.test @@ -336,3 +336,23 @@ SELECT pk FROM t1; DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; + +--echo # +--echo # MDEV-16760: CREATE OR REPLACE TABLE after ANALYZE TABLE +--echo # + +SET use_stat_tables= PREFERABLY; + +CREATE TABLE t1 (pk int PRIMARY KEY, c varchar(32)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +SELECT * FROM t1; +SELECT * FROM mysql.column_stats; + +CREATE OR REPLACE TABLE t1 (pk int PRIMARY KEY, a char(7)); +SELECT * FROM t1; +SELECT * FROM mysql.column_stats; + +DROP TABLE t1; + +set use_stat_tables=@save_use_stat_tables; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6c71067d51b..ee02b5fc7aa 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4762,6 +4762,10 @@ int create_table_impl(THD *thd, { if (create_info->options & HA_LEX_CREATE_REPLACE) { + LEX_STRING db_name= {(char *) db, strlen(db)}; + LEX_STRING tab_name= {(char *) table_name, strlen(table_name)}; + (void) delete_statistics_for_table(thd, &db_name, &tab_name); + TABLE_LIST table_list; table_list.init_one_table(db, strlen(db), table_name, strlen(table_name), table_name, From 095dc81158902380b8618338efabb5ce480dbd79 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sun, 15 Jul 2018 16:24:24 -0700 Subject: [PATCH 32/71] MDEV-16757 Memory leak after adding manually min/max statistical data for blob column ANALYZE TABLE
does not collect statistical data on min/max values for BLOB columns of
. However these values can be added into mysql.column_stats manually by executing proper statements. Unfortunately this led to a memory leak because the memory allocated for these values was never freed. This patch provides the server with a function to free memory allocated for min/max statistical values of BLOB types. Temporarily changed the test case until MDEV-16711 is fixed as without this fix the test case for MDEV-16757 did not fail only for 10.0. --- mysql-test/r/stat_tables.result | 24 +++++++++++++++++++ mysql-test/r/stat_tables_innodb.result | 24 +++++++++++++++++++ mysql-test/t/stat_tables.test | 24 +++++++++++++++++++ sql/sql_statistics.cc | 33 ++++++++++++++++++++++++++ sql/sql_statistics.h | 1 + sql/table_cache.cc | 2 ++ 6 files changed, 108 insertions(+) diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index fcced761283..f299603f8f1 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -517,3 +517,27 @@ drop database db1; drop database db2; drop table t1; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-16757: manual addition of min/max statistics for BLOB +# +SET use_stat_tables= PREFERABLY; +CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze Warning Engine-independent statistics are not collected for column 't' +test.t1 analyze status OK +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +DELETE FROM mysql.column_stats +WHERE db_name='test' AND table_name='t1' AND column_name='t'; +INSERT INTO mysql.column_stats VALUES +('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL); +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL +DROP TABLE t1; +set use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result index 0e866755532..d2d92966d2b 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -544,5 +544,29 @@ drop database db1; drop database db2; drop table t1; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-16757: manual addition of min/max statistics for BLOB +# +SET use_stat_tables= PREFERABLY; +CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze Warning Engine-independent statistics are not collected for column 't' +test.t1 analyze status OK +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +DELETE FROM mysql.column_stats +WHERE db_name='test' AND table_name='t1' AND column_name='t'; +INSERT INTO mysql.column_stats VALUES +('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL); +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL +DROP TABLE t1; +set use_stat_tables=@save_use_stat_tables; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; SET SESSION STORAGE_ENGINE=DEFAULT; diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test index 4cbaa9e27c8..5bbd8cadfbb 100644 --- a/mysql-test/t/stat_tables.test +++ b/mysql-test/t/stat_tables.test @@ -306,3 +306,27 @@ drop database db2; drop table t1; set use_stat_tables=@save_use_stat_tables; + +--echo # +--echo # MDEV-16757: manual addition of min/max statistics for BLOB +--echo # + +SET use_stat_tables= PREFERABLY; + +CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +--sorted_result +SELECT * FROM mysql.column_stats; +DELETE FROM mysql.column_stats + WHERE db_name='test' AND table_name='t1' AND column_name='t'; +INSERT INTO mysql.column_stats VALUES + ('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL); +--sorted_result +SELECT * FROM mysql.column_stats; + +# SELECT pk FROM t1; + +DROP TABLE t1; + +set use_stat_tables=@save_use_stat_tables; diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index abf3975dd9c..a1c21421c59 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -3055,6 +3055,39 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) } +/** + @breif + Cleanup of min/max statistical values for table share +*/ + +void delete_stat_values_for_table_share(TABLE_SHARE *table_share) +{ + TABLE_STATISTICS_CB *stats_cb= &table_share->stats_cb; + Table_statistics *table_stats= stats_cb->table_stats; + if (!table_stats) + return; + Column_statistics *column_stats= table_stats->column_stats; + if (!column_stats) + return; + + for (Field **field_ptr= table_share->field; + *field_ptr; + field_ptr++, column_stats++) + { + if (column_stats->min_value) + { + delete column_stats->min_value; + column_stats->min_value= NULL; + } + if (column_stats->max_value) + { + delete column_stats->max_value; + column_stats->max_value= NULL; + } + } +} + + /** @brief Check whether any statistics is to be read for tables from a table list diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h index f46583839d1..0611c021e88 100644 --- a/sql/sql_statistics.h +++ b/sql/sql_statistics.h @@ -92,6 +92,7 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables); int collect_statistics_for_table(THD *thd, TABLE *table); int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *share, bool is_safe); +void delete_stat_values_for_table_share(TABLE_SHARE *table_share); int alloc_statistics_for_table(THD *thd, TABLE *table); int update_statistics_for_table(THD *thd, TABLE *table); int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab); diff --git a/sql/table_cache.cc b/sql/table_cache.cc index 16a47b37417..b911252019f 100644 --- a/sql/table_cache.cc +++ b/sql/table_cache.cc @@ -52,6 +52,7 @@ #include "lf.h" #include "table.h" #include "sql_base.h" +#include "sql_statistics.h" /** Configuration. */ @@ -786,6 +787,7 @@ void tdc_release_share(TABLE_SHARE *share) } if (share->tdc->flushed || tdc_records() > tdc_size) { + delete_stat_values_for_table_share(share); mysql_mutex_unlock(&LOCK_unused_shares); tdc_delete_share_from_hash(share->tdc); DBUG_VOID_RETURN; From ae0eb507bda858a13475faef4476dd496c4dbc01 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 13 Jul 2018 23:03:57 -0700 Subject: [PATCH 33/71] MDEV-16760 CREATE OR REPLACE TABLE never updates statistical tables If the command CREATE OR REPLACE TABLE really replaces a table then it should remove all data on this table from all statistical tables. --- mysql-test/r/stat_tables.result | 25 +++++++++++++++++++++++++ mysql-test/r/stat_tables_innodb.result | 25 +++++++++++++++++++++++++ mysql-test/t/stat_tables.test | 20 ++++++++++++++++++++ sql/sql_table.cc | 4 ++++ 4 files changed, 74 insertions(+) diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index f299603f8f1..1f1cad10c23 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -541,3 +541,28 @@ test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-16760: CREATE OR REPLACE TABLE after ANALYZE TABLE +# +SET use_stat_tables= PREFERABLY; +CREATE TABLE t1 (pk int PRIMARY KEY, c varchar(32)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +SELECT * FROM t1; +pk c +1 foo +2 bar +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +test t1 c bar foo 0.0000 3.0000 1.0000 0 NULL NULL +CREATE OR REPLACE TABLE t1 (pk int PRIMARY KEY, a char(7)); +SELECT * FROM t1; +pk a +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +DROP TABLE t1; +set use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result index d2d92966d2b..fc1ecdf66c4 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -568,5 +568,30 @@ test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-16760: CREATE OR REPLACE TABLE after ANALYZE TABLE +# +SET use_stat_tables= PREFERABLY; +CREATE TABLE t1 (pk int PRIMARY KEY, c varchar(32)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +SELECT * FROM t1; +pk c +1 foo +2 bar +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL +test t1 c bar foo 0.0000 3.0000 1.0000 0 NULL NULL +CREATE OR REPLACE TABLE t1 (pk int PRIMARY KEY, a char(7)); +SELECT * FROM t1; +pk a +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram +DROP TABLE t1; +set use_stat_tables=@save_use_stat_tables; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; SET SESSION STORAGE_ENGINE=DEFAULT; diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test index 5bbd8cadfbb..b98ca641dc0 100644 --- a/mysql-test/t/stat_tables.test +++ b/mysql-test/t/stat_tables.test @@ -330,3 +330,23 @@ SELECT * FROM mysql.column_stats; DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; + +--echo # +--echo # MDEV-16760: CREATE OR REPLACE TABLE after ANALYZE TABLE +--echo # + +SET use_stat_tables= PREFERABLY; + +CREATE TABLE t1 (pk int PRIMARY KEY, c varchar(32)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +SELECT * FROM t1; +SELECT * FROM mysql.column_stats; + +CREATE OR REPLACE TABLE t1 (pk int PRIMARY KEY, a char(7)); +SELECT * FROM t1; +SELECT * FROM mysql.column_stats; + +DROP TABLE t1; + +set use_stat_tables=@save_use_stat_tables; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3c9146354d6..9a8c737cd82 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4770,6 +4770,10 @@ int create_table_impl(THD *thd, { if (options.or_replace()) { + LEX_STRING db_name= {(char *) db, strlen(db)}; + LEX_STRING tab_name= {(char *) table_name, strlen(table_name)}; + (void) delete_statistics_for_table(thd, &db_name, &tab_name); + TABLE_LIST table_list; table_list.init_one_table(db, strlen(db), table_name, strlen(table_name), table_name, From b75d819604bbb6c461e6363e331bd6bd1ba7a787 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sun, 15 Jul 2018 18:40:25 -0700 Subject: [PATCH 34/71] MDEV-16711 Crash in Field_blob::store() while reading statistics for the small InnoDB table This bug was introduced by the patch 6c414fcf89510215d6d3466eb9992d444eadae89. The patch has not taken into account that some objects of the Field_* types are created only for TABLE_SHARE and the field 'table' is set to NULL for them. In particular such are objects created to store statistical min/max values for columns. --- mysql-test/r/stat_tables.result | 20 ++++++++++++++++++++ mysql-test/r/stat_tables_innodb.result | 20 ++++++++++++++++++++ mysql-test/t/stat_tables.test | 20 +++++++++++++++++++- sql/field.cc | 8 +++++++- 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index 1f1cad10c23..279c09ff44f 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -539,6 +539,10 @@ SELECT * FROM mysql.column_stats; db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL +SELECT pk FROM t1; +pk +1 +2 DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; # @@ -566,3 +570,19 @@ SELECT * FROM mysql.column_stats; db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-16711:CREATE OR REPLACE TABLE introducing BLOB column +# +SET use_stat_tables= PREFERABLY; +CREATE TABLE t1 (pk INT PRIMARY KEY, t CHAR(60)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +CREATE OR REPLACE TABLE t1 (pk INT PRIMARY KEY, t TEXT); +SELECT MAX(pk) FROM t1; +MAX(pk) +NULL +DROP TABLE t1; +set use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result index fc1ecdf66c4..1604c413743 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -566,6 +566,10 @@ SELECT * FROM mysql.column_stats; db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL +SELECT pk FROM t1; +pk +1 +2 DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; # @@ -593,5 +597,21 @@ SELECT * FROM mysql.column_stats; db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-16711:CREATE OR REPLACE TABLE introducing BLOB column +# +SET use_stat_tables= PREFERABLY; +CREATE TABLE t1 (pk INT PRIMARY KEY, t CHAR(60)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +CREATE OR REPLACE TABLE t1 (pk INT PRIMARY KEY, t TEXT); +SELECT MAX(pk) FROM t1; +MAX(pk) +NULL +DROP TABLE t1; +set use_stat_tables=@save_use_stat_tables; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; SET SESSION STORAGE_ENGINE=DEFAULT; diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test index b98ca641dc0..51c9995b6fa 100644 --- a/mysql-test/t/stat_tables.test +++ b/mysql-test/t/stat_tables.test @@ -325,7 +325,7 @@ INSERT INTO mysql.column_stats VALUES --sorted_result SELECT * FROM mysql.column_stats; -# SELECT pk FROM t1; +SELECT pk FROM t1; DROP TABLE t1; @@ -350,3 +350,21 @@ SELECT * FROM mysql.column_stats; DROP TABLE t1; set use_stat_tables=@save_use_stat_tables; + + +--echo # +--echo # MDEV-16711:CREATE OR REPLACE TABLE introducing BLOB column +--echo # + +SET use_stat_tables= PREFERABLY; + +CREATE TABLE t1 (pk INT PRIMARY KEY, t CHAR(60)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +ANALYZE TABLE t1; +CREATE OR REPLACE TABLE t1 (pk INT PRIMARY KEY, t TEXT); + +SELECT MAX(pk) FROM t1; + +DROP TABLE t1; + +set use_stat_tables=@save_use_stat_tables; diff --git a/sql/field.cc b/sql/field.cc index 64c51677c0f..71fc5684d92 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7942,7 +7942,13 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) return 0; } - if (table->blob_storage) // GROUP_CONCAT with ORDER BY | DISTINCT + /* + For min/max fields of statistical data 'table' is set to NULL. + It could not be otherwise as this data is shared by many instances + of the same base table. + */ + + if (table && table->blob_storage) // GROUP_CONCAT with ORDER BY | DISTINCT { DBUG_ASSERT(!f_is_hex_escape(flags)); DBUG_ASSERT(field_charset == cs); From fe9f2f4bb63b379a532016c28c3771510061a47d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 6 Jun 2018 14:19:14 +0300 Subject: [PATCH 35/71] MDEV-16401: Apply review comments to MDEV-16005 Do not hold LOCK_thd_data during my_error or WSREP_DEBUG. Similarly, release LOCK_thd_data before close_thread_tables() call. --- sql/sql_parse.cc | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 89b5adff60c..7e72c1a9397 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1271,9 +1271,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (thd->wsrep_conflict_state == ABORTED && command != COM_STMT_CLOSE && command != COM_QUIT) { + mysql_mutex_unlock(&thd->LOCK_thd_data); my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); WSREP_DEBUG("Deadlock error for: %s", thd->query()); - mysql_mutex_unlock(&thd->LOCK_thd_data); thd->reset_killed(); thd->mysys_var->abort = 0; thd->wsrep_conflict_state = NO_CONFLICT; @@ -7290,34 +7290,44 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, thd->lex->sql_command != SQLCOM_SELECT && (thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit)) { - WSREP_DEBUG("wsrep retrying AC query: %s", + mysql_mutex_unlock(&thd->LOCK_thd_data); + WSREP_DEBUG("wsrep retrying AC query: %s", (thd->query()) ? thd->query() : "void"); /* Performance Schema Interface instrumentation, end */ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); thd->m_statement_psi= NULL; thd->m_digest= NULL; + // Released thd->LOCK_thd_data above as below could end up + // close_thread_tables()/close_open_tables()/close_thread_table()/mysql_mutex_lock(&thd->LOCK_thd_data) close_thread_tables(thd); + mysql_mutex_lock(&thd->LOCK_thd_data); thd->wsrep_conflict_state= RETRY_AUTOCOMMIT; thd->wsrep_retry_counter++; // grow wsrep_copy_query(thd); thd->set_time(); parser_state->reset(rawbuf, length); + mysql_mutex_unlock(&thd->LOCK_thd_data); } else { - WSREP_DEBUG("%s, thd: %lu is_AC: %d, retry: %lu - %lu SQL: %s", - (thd->wsrep_conflict_state == ABORTED) ? + mysql_mutex_unlock(&thd->LOCK_thd_data); + // This does dirty read to wsrep variables but it is only a debug code + WSREP_DEBUG("%s, thd: %lu is_AC: %d, retry: %lu - %lu SQL: %s", + (thd->wsrep_conflict_state == ABORTED) ? "BF Aborted" : "cert failure", - thd->thread_id, is_autocommit, thd->wsrep_retry_counter, + thd->thread_id, is_autocommit, thd->wsrep_retry_counter, thd->variables.wsrep_retry_autocommit, thd->query()); my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + + mysql_mutex_lock(&thd->LOCK_thd_data); thd->wsrep_conflict_state= NO_CONFLICT; if (thd->wsrep_conflict_state != REPLAYING) thd->wsrep_retry_counter= 0; // reset + mysql_mutex_unlock(&thd->LOCK_thd_data); } - mysql_mutex_unlock(&thd->LOCK_thd_data); + thd->reset_killed(); } else @@ -7353,6 +7363,7 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, #endif /* WITH_WSREP */ } + /* When you modify mysql_parse(), you may need to modify mysql_test_parse_for_slave() in this same file. From 8c45eb3ea51e80b429c789713fa85ef380cecdd3 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sat, 13 Jan 2018 12:27:28 +1100 Subject: [PATCH 36/71] MDEV-15050 scripts: mysql_install_db.{sh|pl}, mysqld_multi - mysqld is in @sbindir@ Closes #551 --- scripts/mysql_install_db.pl.in | 2 +- scripts/mysql_install_db.sh | 2 +- scripts/mysqld_multi.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mysql_install_db.pl.in b/scripts/mysql_install_db.pl.in index c6714f66bff..2a65dc94ba8 100644 --- a/scripts/mysql_install_db.pl.in +++ b/scripts/mysql_install_db.pl.in @@ -326,7 +326,7 @@ else $opt->{basedir} = '@prefix@'; $bindir = '@bindir@'; $extra_bindir = $bindir; - $mysqld = '@libexecdir@/mysqld'; + $mysqld = '@sbindir@/mysqld'; $pkgdatadir = '@pkgdatadir@'; $scriptdir = '@scriptdir@'; } diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index a8f32526a7e..0272a19931f 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -311,7 +311,7 @@ else basedir="@prefix@" bindir="@bindir@" resolveip="$bindir/resolveip" - mysqld="@libexecdir@/mysqld" + mysqld="@sbindir@/mysqld" pkgdatadir="@pkgdatadir@" fi diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index e96d12e3f89..8f5adfe4842 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -30,7 +30,7 @@ $opt_example = 0; $opt_help = 0; $opt_log = undef(); $opt_mysqladmin = "@bindir@/mysqladmin"; -$opt_mysqld = "@libexecdir@/mysqld"; +$opt_mysqld = "@sbindir@/mysqld"; $opt_no_log = 0; $opt_password = undef(); $opt_tcp_ip = 0; From ada54101a7185782657813c553907f61f2a35faf Mon Sep 17 00:00:00 2001 From: sachin Date: Wed, 30 May 2018 16:25:44 +0530 Subject: [PATCH 37/71] MDEV-9266 Creating index on temporaray table breaks replication Problem:- Create/drop index was logged into binlog. Goal:- Operation on temporary table should not be binlog when binlog format is row. Solution:- We should add CF_FORCE_ORIGINAL_BINLOG_FORMAT when there is ddl on temp table. For optimize, analyze, repair we wont change anything ,Then will be logged in binlog , But they also dont throw any error if operation fails Since slave wont be having any temp table , but these operation on tmp table will be processed without breaking replication. For rename we need a different logic MDEV-16728 will solve it. --- .../binlog/include/check_binlog_size.inc | 31 +++++++++++++++++++ .../binlog/r/binlog_tmp_table_row.result | 7 +++++ .../suite/binlog/t/binlog_tmp_table_row.test | 30 ++++++++++++++++++ sql/sql_parse.cc | 3 ++ 4 files changed, 71 insertions(+) create mode 100644 mysql-test/suite/binlog/include/check_binlog_size.inc create mode 100644 mysql-test/suite/binlog/r/binlog_tmp_table_row.result create mode 100644 mysql-test/suite/binlog/t/binlog_tmp_table_row.test diff --git a/mysql-test/suite/binlog/include/check_binlog_size.inc b/mysql-test/suite/binlog/include/check_binlog_size.inc new file mode 100644 index 00000000000..9df161ec843 --- /dev/null +++ b/mysql-test/suite/binlog/include/check_binlog_size.inc @@ -0,0 +1,31 @@ +# This file runs the query and checks +# whether the size of binlog is increased or not +# If size is changed it issue die command +# Parameters +# $sql_query = query to run + +#Only last row of show binlog events matter +--let $tmp= 0 +--let $counter= 1 +while ($tmp != "No such row") +{ + --let $initial_binlog_size= $tmp + --let $tmp= query_get_value(show binary logs, File_size, $counter) + --inc $counter +} + +--eval $sql_query + +--let $tmp= 0 +--let $counter= 1 +while ($tmp != "No such row") +{ + --let $current_binlog_size= $tmp + --let $tmp= query_get_value(show binary logs, File_size, $counter) + --inc $counter +} + +if ($initial_binlog_size != $current_binlog_size) +{ + die "Binlog size changed"; +} diff --git a/mysql-test/suite/binlog/r/binlog_tmp_table_row.result b/mysql-test/suite/binlog/r/binlog_tmp_table_row.result new file mode 100644 index 00000000000..71bd75d89cb --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_tmp_table_row.result @@ -0,0 +1,7 @@ +RESET MASTER; +#Create table test +create temporary table t1(a int, b int); +#Add index test +create index index_a on t1(a); +#drop index test +drop index index_a on t1; diff --git a/mysql-test/suite/binlog/t/binlog_tmp_table_row.test b/mysql-test/suite/binlog/t/binlog_tmp_table_row.test new file mode 100644 index 00000000000..ce11c880679 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_tmp_table_row.test @@ -0,0 +1,30 @@ +# ==== Purpose ==== +# +# Test if statements used temporary tables are not binlogged in the case of +# binlog_format=row +# +# ==== Method ==== +# +# We will see if binlog file size is increased or not, It should be constant for the +# entire period of test. +# +# ==== Related bugs ==== +# +# Mdev-9266 +# +source include/have_log_bin.inc; +source include/have_binlog_format_row.inc; + +RESET MASTER; + +--echo #Create table test +--let $sql_query= create temporary table t1(a int, b int) +--source suite/binlog/include/check_binlog_size.inc + +--echo #Add index test +--let $sql_query= create index index_a on t1(a) +--source suite/binlog/include/check_binlog_size.inc + +--echo #drop index test +--let $sql_query= drop index index_a on t1 +--source suite/binlog/include/check_binlog_size.inc diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 28d11ef2e5c..a9849c7248d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -457,6 +457,9 @@ void init_update_queries(void) sql_command_flags[SQLCOM_TRUNCATE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; /* We don't want to replicate DROP for temp tables in row format */ sql_command_flags[SQLCOM_DROP_TABLE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; + /* We don't want to replicate CREATE/DROP INDEX for temp tables in row format */ + sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; + sql_command_flags[SQLCOM_DROP_INDEX]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; /* One can change replication mode with SET */ sql_command_flags[SQLCOM_SET_OPTION]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; From 4d06b7e1bd3b825da32c9200e6f5ca609add0e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 18 Jul 2018 11:22:17 +0300 Subject: [PATCH 38/71] MDEV-16769: Notes "WSREP: Waiting for SST to complete" flood the error log Used wrong initialization for condition timeout, should have used set_timespec. --- sql/wsrep_sst.cc | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 60683bf740c..155051bfe84 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -204,8 +204,7 @@ void wsrep_sst_grab () // Wait for end of SST bool wsrep_sst_wait () { - struct timespec wtime = {WSREP_TIMEDWAIT_SECONDS, 0}; - uint32 total_wtime = 0; + double total_wtime = 0; if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort(); @@ -214,14 +213,18 @@ bool wsrep_sst_wait () while (!sst_complete) { + struct timespec wtime; + set_timespec(wtime, WSREP_TIMEDWAIT_SECONDS); + time_t start_time = time(NULL); mysql_cond_timedwait (&COND_wsrep_sst, &LOCK_wsrep_sst, &wtime); + time_t end_time = time(NULL); if (!sst_complete) { - total_wtime += wtime.tv_sec; - WSREP_DEBUG("Waiting for SST to complete. waited %u secs.", total_wtime); + total_wtime += difftime(end_time, start_time); + WSREP_DEBUG("Waiting for SST to complete. current seqno: %ld waited %f secs.", local_seqno, total_wtime); service_manager_extend_timeout(WSREP_EXTEND_TIMEOUT_INTERVAL, - "WSREP state transfer ongoing, current seqno: %ld", local_seqno); + "WSREP state transfer ongoing, current seqno: %ld waited %f secs", local_seqno, total_wtime); } } @@ -1319,19 +1322,22 @@ void wsrep_SE_init_grab() void wsrep_SE_init_wait() { - struct timespec wtime = {WSREP_TIMEDWAIT_SECONDS, 0}; - uint32 total_wtime=0; + double total_wtime=0; while (SE_initialized == false) { + struct timespec wtime; + set_timespec(wtime, WSREP_TIMEDWAIT_SECONDS); + time_t start_time = time(NULL); mysql_cond_timedwait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init, &wtime); + time_t end_time = time(NULL); if (!SE_initialized) { - total_wtime += wtime.tv_sec; - WSREP_DEBUG("Waiting for SST to complete. waited %u secs.", total_wtime); + total_wtime += difftime(end_time, start_time); + WSREP_DEBUG("Waiting for SST to complete. current seqno: %ld waited %f secs.", local_seqno, total_wtime); service_manager_extend_timeout(WSREP_EXTEND_TIMEOUT_INTERVAL, - "WSREP SE initialization ongoing."); + "WSREP state transfer ongoing, current seqno: %ld waited %f secs", local_seqno, total_wtime); } } From ab58493db22d870cb6a470d6b0551cfc70dd09f3 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 19 Jul 2018 09:55:19 +0400 Subject: [PATCH 39/71] MDEV-13118 Wrong results with LOWER and UPPER and subquery This problem is similar to MDEV-10306. 1. Fixing Item_str_conv::val_str(String *str) to return the result in "str", and to use tmp_value only as a temporary buffer for args[0]->val_str(). The new code version now guarantees that the result is always returned in "str". The trick with copy_if_not_alloced() is not used any more. 2. The change #1 revealed the same problem in SUBSTRING_INDEX(), so some tests with combinations of UPPER()/LOWER() and SUBSTRING_INDEX() started to fail. Fixing Item_func_substr_index::val_str() the same way, to return the result in "str" and use tmp_value as a temporary buffer for args[0]->val_str(). --- mysql-test/include/ctype_mdev13118.inc | 15 ++++ mysql-test/r/ctype_binary.result | 23 ++++++ mysql-test/r/ctype_eucjpms.result | 23 ++++++ mysql-test/r/ctype_euckr.result | 29 +++++++ mysql-test/r/ctype_gbk.result | 23 ++++++ mysql-test/r/ctype_latin1.result | 23 ++++++ mysql-test/r/ctype_ucs.result | 23 ++++++ mysql-test/r/ctype_ujis.result | 23 ++++++ mysql-test/r/ctype_utf16.result | 23 ++++++ mysql-test/r/ctype_utf16le.result | 29 +++++++ mysql-test/r/ctype_utf32.result | 23 ++++++ mysql-test/r/ctype_utf8.result | 23 ++++++ mysql-test/r/ctype_utf8mb4.result | 23 ++++++ mysql-test/t/ctype_binary.test | 3 + mysql-test/t/ctype_eucjpms.test | 2 + mysql-test/t/ctype_euckr.test | 11 +++ mysql-test/t/ctype_gbk.test | 3 + mysql-test/t/ctype_latin1.test | 3 + mysql-test/t/ctype_ucs.test | 4 + mysql-test/t/ctype_ujis.test | 4 + mysql-test/t/ctype_utf16.test | 5 ++ mysql-test/t/ctype_utf16le.test | 13 +++ mysql-test/t/ctype_utf32.test | 8 ++ mysql-test/t/ctype_utf8.test | 7 ++ mysql-test/t/ctype_utf8mb4.test | 8 ++ sql/item_strfunc.cc | 107 ++++++++++++++----------- 26 files changed, 433 insertions(+), 48 deletions(-) create mode 100644 mysql-test/include/ctype_mdev13118.inc diff --git a/mysql-test/include/ctype_mdev13118.inc b/mysql-test/include/ctype_mdev13118.inc new file mode 100644 index 00000000000..efcb57299df --- /dev/null +++ b/mysql-test/include/ctype_mdev13118.inc @@ -0,0 +1,15 @@ +--echo # +--echo # MDEV-13118 Wrong results with LOWER and UPPER and subquery +--echo # + +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +--sorted_result +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +--sorted_result +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/ctype_binary.result b/mysql-test/r/ctype_binary.result index 48b481883ca..b28d9040547 100644 --- a/mysql-test/r/ctype_binary.result +++ b/mysql-test/r/ctype_binary.result @@ -3022,6 +3022,29 @@ DROP TABLE t1; SELECT _binary 0x7E, _binary X'7E', _binary B'01111110'; _binary 0x7E _binary X'7E' _binary B'01111110' ~ ~ ~ +SET NAMES utf8, character_set_connection=binary; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varbinary(10) NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +abcdefghi-abcdefghi +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; # # End of 10.0 tests # diff --git a/mysql-test/r/ctype_eucjpms.result b/mysql-test/r/ctype_eucjpms.result index a1232c115e9..1e2312638c9 100644 --- a/mysql-test/r/ctype_eucjpms.result +++ b/mysql-test/r/ctype_eucjpms.result @@ -33636,6 +33636,29 @@ HEX(a) CHAR_LENGTH(a) DROP TABLE t1; SELECT _eucjpms 0x8EA0; ERROR HY000: Invalid eucjpms character string: '8EA0' +SET NAMES eucjpms; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) CHARACTER SET eucjpms NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; # # End of 10.0 tests # diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result index dcb68cfe60b..cea93b0c808 100644 --- a/mysql-test/r/ctype_euckr.result +++ b/mysql-test/r/ctype_euckr.result @@ -25274,3 +25274,32 @@ A1A1A1A1A1A120202020202020202020202020202020202020 # # End of 5.6 tests # +# +# Start of 10.0 tests +# +SET NAMES utf8, character_set_connection=euckr; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) CHARACTER SET euckr NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; +# +# End of 10.0 tests +# diff --git a/mysql-test/r/ctype_gbk.result b/mysql-test/r/ctype_gbk.result index 2d31a15bb62..15f9bc6bfea 100644 --- a/mysql-test/r/ctype_gbk.result +++ b/mysql-test/r/ctype_gbk.result @@ -4943,6 +4943,29 @@ E05C5B E05B DROP TABLE t1; # Start of ctype_E05C.inc +SET NAMES utf8, character_set_connection=gbk; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) CHARACTER SET gbk NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; # # MDEV-9886 Illegal mix of collations with a view comparing a field to a binary constant # diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result index cf48aaab09b..8913c8082c8 100644 --- a/mysql-test/r/ctype_latin1.result +++ b/mysql-test/r/ctype_latin1.result @@ -7939,6 +7939,29 @@ a 0 DROP VIEW v1; DROP TABLE t1; +SET NAMES latin1; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; # # End of 10.0 tests # diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 59d88414cab..58fd308c7e2 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -5629,6 +5629,29 @@ c2 YWJjZGVmZ2hp-YWJjZGVmZ2hp DROP TABLE t1; SET optimizer_switch=@save_optimizer_switch; +SET NAMES utf8, character_set_connection=ucs2; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) CHARACTER SET ucs2 NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; # # End of 10.0 tests # diff --git a/mysql-test/r/ctype_ujis.result b/mysql-test/r/ctype_ujis.result index 413ab4efe31..d4589f62ae5 100644 --- a/mysql-test/r/ctype_ujis.result +++ b/mysql-test/r/ctype_ujis.result @@ -25942,6 +25942,29 @@ HEX(a) CHAR_LENGTH(a) DROP TABLE t1; SELECT _ujis 0x8EA0; ERROR HY000: Invalid ujis character string: '8EA0' +SET NAMES ujis; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) CHARACTER SET ujis NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; # # End of 10.0 tests # diff --git a/mysql-test/r/ctype_utf16.result b/mysql-test/r/ctype_utf16.result index 958ade902df..e182432faec 100644 --- a/mysql-test/r/ctype_utf16.result +++ b/mysql-test/r/ctype_utf16.result @@ -2134,6 +2134,29 @@ EXECUTE stmt USING @arg00; CONCAT(_utf16'a' COLLATE utf16_unicode_ci, ?) aÿ DEALLOCATE PREPARE stmt; +SET NAMES utf8, character_set_connection=utf16; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) CHARACTER SET utf16 NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; # # End of 10.0 tests # diff --git a/mysql-test/r/ctype_utf16le.result b/mysql-test/r/ctype_utf16le.result index 8098b0d1666..f6a4d351ad4 100644 --- a/mysql-test/r/ctype_utf16le.result +++ b/mysql-test/r/ctype_utf16le.result @@ -2319,3 +2319,32 @@ DFFFFFDFFFFF9CFFFF9DFFFF9EFFFF # # End of 5.6 tests # +# +# Start of 10.0 tests +# +SET NAMES utf8, character_set_connection=utf16le; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) CHARACTER SET utf16le NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; +# +# Start of 10.0 tests +# diff --git a/mysql-test/r/ctype_utf32.result b/mysql-test/r/ctype_utf32.result index 1f3e519a525..91277cd5108 100644 --- a/mysql-test/r/ctype_utf32.result +++ b/mysql-test/r/ctype_utf32.result @@ -2231,6 +2231,29 @@ EXECUTE stmt USING @arg00; CONCAT(_utf32'a' COLLATE utf32_unicode_ci, ?) aÿ DEALLOCATE PREPARE stmt; +SET NAMEs utf8, character_set_connection=utf32; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) CHARACTER SET utf32 NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; # # End of 10.0 tests # diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 7a3ff3732c3..6a4001597c4 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -10127,6 +10127,29 @@ SELECT * FROM v1; c ß DROP VIEW v1; +SET NAMES utf8; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) CHARACTER SET utf8 NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; # # End of 10.0 tests # diff --git a/mysql-test/r/ctype_utf8mb4.result b/mysql-test/r/ctype_utf8mb4.result index f31b7a6781e..4d91c42cf51 100644 --- a/mysql-test/r/ctype_utf8mb4.result +++ b/mysql-test/r/ctype_utf8mb4.result @@ -3427,6 +3427,29 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; SET NAMES default; +SET NAMES utf8mb4; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET @save_optimizer_switch=@@optimizer_switch; +SET optimizer_switch=_latin1'derived_merge=on'; +CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(10) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI'); +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub; +c2 +abcdefghi-abcdefghi +abcdefghi-abcdefghi +SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub; +c2 +ABCDEFGHI-ABCDEFGHI +ABCDEFGHI-ABCDEFGHI +DROP TABLE t1; +SET optimizer_switch=@save_optimizer_switch; # End of 10.0 tests # # End of tests diff --git a/mysql-test/t/ctype_binary.test b/mysql-test/t/ctype_binary.test index 3d3f90b444b..801e1328892 100644 --- a/mysql-test/t/ctype_binary.test +++ b/mysql-test/t/ctype_binary.test @@ -24,6 +24,9 @@ SET NAMES binary; --echo # SELECT _binary 0x7E, _binary X'7E', _binary B'01111110'; +SET NAMES utf8, character_set_connection=binary; +--source include/ctype_mdev13118.inc + --echo # --echo # End of 10.0 tests --echo # diff --git a/mysql-test/t/ctype_eucjpms.test b/mysql-test/t/ctype_eucjpms.test index 49ca81850ed..590f2ca9950 100644 --- a/mysql-test/t/ctype_eucjpms.test +++ b/mysql-test/t/ctype_eucjpms.test @@ -536,6 +536,8 @@ DROP TABLE t1; --error ER_INVALID_CHARACTER_STRING SELECT _eucjpms 0x8EA0; +SET NAMES eucjpms; +--source include/ctype_mdev13118.inc --echo # --echo # End of 10.0 tests diff --git a/mysql-test/t/ctype_euckr.test b/mysql-test/t/ctype_euckr.test index 155b8ebed00..d81ba2a8bdf 100644 --- a/mysql-test/t/ctype_euckr.test +++ b/mysql-test/t/ctype_euckr.test @@ -197,3 +197,14 @@ set collation_connection=euckr_bin; --echo # End of 5.6 tests --echo # + +--echo # +--echo # Start of 10.0 tests +--echo # + +SET NAMES utf8, character_set_connection=euckr; +--source include/ctype_mdev13118.inc + +--echo # +--echo # End of 10.0 tests +--echo # diff --git a/mysql-test/t/ctype_gbk.test b/mysql-test/t/ctype_gbk.test index 454377d98a7..bcdcc09b473 100644 --- a/mysql-test/t/ctype_gbk.test +++ b/mysql-test/t/ctype_gbk.test @@ -199,6 +199,9 @@ let $ctype_unescape_combinations=selected; SET NAMES gbk; --source include/ctype_E05C.inc +SET NAMES utf8, character_set_connection=gbk; +--source include/ctype_mdev13118.inc + --echo # --echo # MDEV-9886 Illegal mix of collations with a view comparing a field to a binary constant --echo # diff --git a/mysql-test/t/ctype_latin1.test b/mysql-test/t/ctype_latin1.test index 8a188b71e24..da4d76ee2cf 100644 --- a/mysql-test/t/ctype_latin1.test +++ b/mysql-test/t/ctype_latin1.test @@ -260,6 +260,9 @@ SELECT * FROM v1; DROP VIEW v1; DROP TABLE t1; +SET NAMES latin1; +--source include/ctype_mdev13118.inc + --echo # --echo # End of 10.0 tests diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index d78977a3d1c..050e199e5b7 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -984,6 +984,10 @@ DROP TABLE t1; SET optimizer_switch=@save_optimizer_switch; +SET NAMES utf8, character_set_connection=ucs2; +--source include/ctype_mdev13118.inc + + --echo # --echo # End of 10.0 tests --echo # diff --git a/mysql-test/t/ctype_ujis.test b/mysql-test/t/ctype_ujis.test index 48dc0e63058..8d55819acf7 100644 --- a/mysql-test/t/ctype_ujis.test +++ b/mysql-test/t/ctype_ujis.test @@ -1366,6 +1366,10 @@ DROP TABLE t1; SELECT _ujis 0x8EA0; +SET NAMES ujis; +--source include/ctype_mdev13118.inc + + --echo # --echo # End of 10.0 tests --echo # diff --git a/mysql-test/t/ctype_utf16.test b/mysql-test/t/ctype_utf16.test index cda85239512..b562b15eeeb 100644 --- a/mysql-test/t/ctype_utf16.test +++ b/mysql-test/t/ctype_utf16.test @@ -866,6 +866,11 @@ SET @arg00=_binary 0x00FF; EXECUTE stmt USING @arg00; DEALLOCATE PREPARE stmt; + +SET NAMES utf8, character_set_connection=utf16; +--source include/ctype_mdev13118.inc + + --echo # --echo # End of 10.0 tests --echo # diff --git a/mysql-test/t/ctype_utf16le.test b/mysql-test/t/ctype_utf16le.test index a8326900847..f5b89aa9dc4 100644 --- a/mysql-test/t/ctype_utf16le.test +++ b/mysql-test/t/ctype_utf16le.test @@ -744,3 +744,16 @@ SET NAMES utf8, collation_connection=utf16le_bin; --echo # --echo # End of 5.6 tests --echo # + + +--echo # +--echo # Start of 10.0 tests +--echo # + + +SET NAMES utf8, character_set_connection=utf16le; +--source include/ctype_mdev13118.inc + +--echo # +--echo # Start of 10.0 tests +--echo # diff --git a/mysql-test/t/ctype_utf32.test b/mysql-test/t/ctype_utf32.test index c747abb8b08..1a4c9fd28ee 100644 --- a/mysql-test/t/ctype_utf32.test +++ b/mysql-test/t/ctype_utf32.test @@ -979,6 +979,14 @@ SET @arg00=_binary 0x00FF; EXECUTE stmt USING @arg00; DEALLOCATE PREPARE stmt; + +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET NAMEs utf8, character_set_connection=utf32; +--source include/ctype_mdev13118.inc + + --echo # --echo # End of 10.0 tests --echo # diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 2524daffa9e..11dfef67765 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -1880,6 +1880,13 @@ SELECT * FROM v1; DROP VIEW v1; +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET NAMES utf8; +--source include/ctype_mdev13118.inc + + --echo # --echo # End of 10.0 tests --echo # diff --git a/mysql-test/t/ctype_utf8mb4.test b/mysql-test/t/ctype_utf8mb4.test index f68cfd57e2a..89007546492 100644 --- a/mysql-test/t/ctype_utf8mb4.test +++ b/mysql-test/t/ctype_utf8mb4.test @@ -1913,6 +1913,14 @@ DROP TABLE t1; SET NAMES default; + +# +# MDEV-13118 Wrong results with LOWER and UPPER and subquery +# +SET NAMES utf8mb4; +--source include/ctype_mdev13118.inc + + --echo # End of 10.0 tests --echo # diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index e0bd3cc2195..160e740a9f7 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1566,32 +1566,27 @@ String *Item_str_conv::val_str(String *str) { DBUG_ASSERT(fixed == 1); String *res; - if (!(res=args[0]->val_str(str))) - { - null_value=1; /* purecov: inspected */ - return 0; /* purecov: inspected */ - } - null_value=0; + uint alloced_length, len; + + if ((null_value= (!(res= args[0]->val_str(&tmp_value)) || + str->alloc((alloced_length= res->length() * multiply))))) + return 0; + if (multiply == 1) { - uint len; - res= copy_if_not_alloced(&tmp_value, res, res->length()); - len= converter(collation.collation, (char*) res->ptr(), res->length(), - (char*) res->ptr(), res->length()); - DBUG_ASSERT(len <= res->length()); - res->length(len); + str->copy(*res); // Should not fail (it was alloced above) + len= converter(collation.collation, (char*) str->ptr(), str->length(), + (char*) str->ptr(), alloced_length); } else { - uint len= res->length() * multiply; - tmp_value.alloc(len); - tmp_value.set_charset(collation.collation); len= converter(collation.collation, (char*) res->ptr(), res->length(), - (char*) tmp_value.ptr(), len); - tmp_value.length(len); - res= &tmp_value; + (char*) str->ptr(), alloced_length); + str->set_charset(collation.collation); } - return res; + DBUG_ASSERT(len <= alloced_length); + str->length(len); + return str; } @@ -1783,7 +1778,7 @@ String *Item_func_substr_index::val_str(String *str) DBUG_ASSERT(fixed == 1); char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),system_charset_info); - String *res= args[0]->val_str(str); + String *res= args[0]->val_str(&tmp_value); String *delimiter= args[1]->val_str(&tmp); int32 count= (int32) args[2]->val_int(); uint offset; @@ -1832,20 +1827,31 @@ String *Item_func_substr_index::val_str(String *str) if (pass == 0) /* count<0 */ { c+=n+1; - if (c<=0) return res; /* not found, return original string */ + if (c<=0) + { + str->copy(res->ptr(), res->length(), collation.collation); + return str; // not found, return the original string + } ptr=res->ptr(); } else { - if (c) return res; /* Not found, return original string */ + if (c) + { + str->copy(res->ptr(), res->length(), collation.collation); + return str; // not found, return the original string + } if (count>0) /* return left part */ { - tmp_value.set(*res,0,(ulong) (ptr-res->ptr())); + str->copy(res->ptr(), (uint32) (ptr-res->ptr()), collation.collation); + return str; } else /* return right part */ { - ptr+= delimiter_length; - tmp_value.set(*res,(ulong) (ptr-res->ptr()), (ulong) (strend-ptr)); + ptr+= delimiter_length; + str->copy(res->ptr() + (ptr-res->ptr()), (uint32) (strend - ptr), + collation.collation); + return str; } } } @@ -1857,13 +1863,16 @@ String *Item_func_substr_index::val_str(String *str) { // start counting from the beginning for (offset=0; ; offset+= delimiter_length) { - if ((int) (offset= res->strstr(*delimiter, offset)) < 0) - return res; // Didn't find, return org string - if (!--count) - { - tmp_value.set(*res,0,offset); - break; - } + if ((int) (offset= res->strstr(*delimiter, offset)) < 0) + { + str->copy(res->ptr(), res->length(), collation.collation); + return str; // not found, return the original string + } + if (!--count) + { + str->copy(res->ptr(), offset, collation.collation); + return str; + } } } else @@ -1878,30 +1887,32 @@ String *Item_func_substr_index::val_str(String *str) address space less than where the found substring is located in res */ - if ((int) (offset= res->strrstr(*delimiter, offset)) < 0) - return res; // Didn't find, return org string + if ((int) (offset= res->strrstr(*delimiter, offset)) < 0) + { + str->copy(res->ptr(), res->length(), collation.collation); + return str; // not found, return the original string + } /* At this point, we've searched for the substring the number of times as supplied by the index value */ - if (!++count) - { - offset+= delimiter_length; - tmp_value.set(*res,offset,res->length()- offset); - break; - } + if (!++count) + { + offset+= delimiter_length; + str->copy(res->ptr() + offset, res->length() - offset, + collation.collation); + return str; + } } if (count) - return res; // Didn't find, return org string + { + str->copy(res->ptr(), res->length(), collation.collation); + return str; // not found, return the original string + } } } - /* - We always mark tmp_value as const so that if val_str() is called again - on this object, we don't disrupt the contents of tmp_value when it was - derived from another String. - */ - tmp_value.mark_as_const(); - return (&tmp_value); + DBUG_ASSERT(0); + return NULL; } /* From e2ac4098ed507957ba6dac9b408d31054a8e6b6d Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 19 Jul 2018 13:02:14 +0400 Subject: [PATCH 40/71] Simplify caseup() and casedn() in charsets After the MDEV-13118 fix there's no code in the server that wants caseup/casedn to change the argument in place for simple charsets. Let's remove this logic and always return the result in a new string for all charsets, both simple and complex. 1. Removing the optimization that *some* character sets used in casedn() and caseup(), which allowed (and required) to change the case in-place, overwriting the string passed as the "src" argument. Now all CHARSET_INFO's work in the same way: non of them change the source string in-place, all of them now convert case from the source string to the destination string, leaving the source string untouched. 2. Adding "const" qualifier to the "char *src" parameter to caseup() and casedn(). 3. Removing duplicate implementations in ctype-mb.c. Now both caseup() and casedn() implementations for all CJK character sets use internally the same function my_casefold_mb() (the former my_casefold_mb_varlen()). 4. Removing the "unused" attribute from parameters of some my_case{up|dn}_xxx() implementations, as the affected parameters are now *used* in the code. Previously these parameters were used only in DBUG_ASSERT(). --- include/m_ctype.h | 28 ++++++------ sql/item_strfunc.cc | 15 ++----- strings/ctype-bin.c | 8 ++-- strings/ctype-euc_kr.c | 4 +- strings/ctype-mb.c | 100 ++++++----------------------------------- strings/ctype-simple.c | 22 +++++---- strings/ctype-ucs2.c | 78 +++++++++++++++++--------------- strings/ctype-ujis.c | 8 ++-- strings/ctype-utf8.c | 20 +++++---- 9 files changed, 106 insertions(+), 177 deletions(-) diff --git a/include/m_ctype.h b/include/m_ctype.h index 8d9838fdde2..eb2d760359b 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -365,7 +365,7 @@ typedef int (*my_charset_conv_mb_wc)(CHARSET_INFO *, my_wc_t *, typedef int (*my_charset_conv_wc_mb)(CHARSET_INFO *, my_wc_t, uchar *, uchar *); typedef size_t (*my_charset_conv_case)(CHARSET_INFO *, - char *, size_t, char *, size_t); + const char *, size_t, char *, size_t); /* See strings/CHARSET_INFO.txt about information on this structure */ @@ -565,9 +565,11 @@ extern uint my_instr_simple(CHARSET_INFO *, /* Functions for 8bit */ extern size_t my_caseup_str_8bit(CHARSET_INFO *, char *); extern size_t my_casedn_str_8bit(CHARSET_INFO *, char *); -extern size_t my_caseup_8bit(CHARSET_INFO *, char *src, size_t srclen, +extern size_t my_caseup_8bit(CHARSET_INFO *, + const char *src, size_t srclen, char *dst, size_t dstlen); -extern size_t my_casedn_8bit(CHARSET_INFO *, char *src, size_t srclen, +extern size_t my_casedn_8bit(CHARSET_INFO *, + const char *src, size_t srclen, char *dst, size_t dstlen); extern int my_strcasecmp_8bit(CHARSET_INFO * cs, const char *, const char *); @@ -658,17 +660,17 @@ uint my_mbcharlen_8bit(CHARSET_INFO *, uint c); /* Functions for multibyte charsets */ extern size_t my_caseup_str_mb(CHARSET_INFO *, char *); extern size_t my_casedn_str_mb(CHARSET_INFO *, char *); -extern size_t my_caseup_mb(CHARSET_INFO *, char *src, size_t srclen, - char *dst, size_t dstlen); -extern size_t my_casedn_mb(CHARSET_INFO *, char *src, size_t srclen, - char *dst, size_t dstlen); -extern size_t my_caseup_mb_varlen(CHARSET_INFO *, char *src, size_t srclen, - char *dst, size_t dstlen); -extern size_t my_casedn_mb_varlen(CHARSET_INFO *, char *src, size_t srclen, - char *dst, size_t dstlen); -extern size_t my_caseup_ujis(CHARSET_INFO *, char *src, size_t srclen, +extern size_t my_caseup_mb(CHARSET_INFO *, + const char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_mb(CHARSET_INFO *, + const char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_caseup_ujis(CHARSET_INFO *, + const char *src, size_t srclen, char *dst, size_t dstlen); -extern size_t my_casedn_ujis(CHARSET_INFO *, char *src, size_t srclen, +extern size_t my_casedn_ujis(CHARSET_INFO *, + const char *src, size_t srclen, char *dst, size_t dstlen); extern int my_strcasecmp_mb(CHARSET_INFO * cs,const char *, const char *); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 160e740a9f7..ba9f14fb63f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1572,19 +1572,10 @@ String *Item_str_conv::val_str(String *str) str->alloc((alloced_length= res->length() * multiply))))) return 0; - if (multiply == 1) - { - str->copy(*res); // Should not fail (it was alloced above) - len= converter(collation.collation, (char*) str->ptr(), str->length(), - (char*) str->ptr(), alloced_length); - } - else - { - len= converter(collation.collation, (char*) res->ptr(), res->length(), - (char*) str->ptr(), alloced_length); - str->set_charset(collation.collation); - } + len= converter(collation.collation, (char*) res->ptr(), res->length(), + (char*) str->ptr(), alloced_length); DBUG_ASSERT(len <= alloced_length); + str->set_charset(collation.collation); str->length(len); return str; } diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 2e699db0bd3..53a0e850b54 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -220,11 +220,11 @@ static size_t my_case_str_bin(CHARSET_INFO *cs __attribute__((unused)), static size_t my_case_bin(CHARSET_INFO *cs __attribute__((unused)), - char *src __attribute__((unused)), - size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) + const char *src, size_t srclen, + char *dst, size_t dstlen) { + DBUG_ASSERT(srclen <= dstlen); + memcpy(dst, src, srclen); return srclen; } diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index b7065369258..f35c3f07c79 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -9994,8 +9994,8 @@ static MY_CHARSET_HANDLER my_charset_handler= my_mb_ctype_mb, my_caseup_str_mb, my_casedn_str_mb, - my_caseup_mb_varlen, /* UPPER() can reduce length: Turkish DOTLESS i -> I */ - my_casedn_mb, /* LOWER() does not change length, use simple version*/ + my_caseup_mb, /* UPPER() can reduce length: Turkish DOTLESS i -> I */ + my_casedn_mb, /* LOWER() does not change length */ my_snprintf_8bit, my_long10_to_str_8bit, my_longlong10_to_str_8bit, diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index 02a9a91ca6a..318e581792a 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -71,81 +71,8 @@ get_case_info_for_ch(const CHARSET_INFO *cs, uint page, uint offs) /* - For character sets which don't change octet length in case conversion. -*/ -size_t my_caseup_mb(CHARSET_INFO * cs, char *src, size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) -{ - register uint32 l; - register char *srcend= src + srclen; - register const uchar *map= cs->to_upper; - - DBUG_ASSERT(cs->caseup_multiply == 1); - DBUG_ASSERT(src == dst && srclen == dstlen); - DBUG_ASSERT(cs->mbmaxlen == 2); - - while (src < srcend) - { - if ((l=my_ismbchar(cs, src, srcend))) - { - MY_UNICASE_CHARACTER *ch; - if ((ch= get_case_info_for_ch(cs, (uchar) src[0], (uchar) src[1]))) - { - *src++= ch->toupper >> 8; - *src++= ch->toupper & 0xFF; - } - else - src+= l; - } - else - { - *src=(char) map[(uchar) *src]; - src++; - } - } - return srclen; -} - - -size_t my_casedn_mb(CHARSET_INFO * cs, char *src, size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) -{ - register uint32 l; - register char *srcend= src + srclen; - register const uchar *map=cs->to_lower; - - DBUG_ASSERT(cs->casedn_multiply == 1); - DBUG_ASSERT(src == dst && srclen == dstlen); - DBUG_ASSERT(cs->mbmaxlen == 2); - - while (src < srcend) - { - if ((l= my_ismbchar(cs, src, srcend))) - { - MY_UNICASE_CHARACTER *ch; - if ((ch= get_case_info_for_ch(cs, (uchar) src[0], (uchar) src[1]))) - { - *src++= ch->tolower >> 8; - *src++= ch->tolower & 0xFF; - } - else - src+= l; - } - else - { - *src= (char) map[(uchar)*src]; - src++; - } - } - return srclen; -} - - -/* - Case folding functions for character set - where case conversion can change string octet length. + Case folding functions for CJK character set. + Case conversion can optionally reduce string octet length. For example, in EUCKR, _euckr 0xA9A5 == "LATIN LETTER DOTLESS I" (Turkish letter) is upper-cased to to @@ -153,13 +80,14 @@ size_t my_casedn_mb(CHARSET_INFO * cs, char *src, size_t srclen, Length is reduced in this example from two bytes to one byte. */ static size_t -my_casefold_mb_varlen(CHARSET_INFO *cs, - char *src, size_t srclen, - char *dst, size_t dstlen __attribute__((unused)), - const uchar *map, - size_t is_upper) +my_casefold_mb(CHARSET_INFO *cs, + const char *src, size_t srclen, + char *dst, size_t dstlen __attribute__((unused)), + const uchar *map, + size_t is_upper) { - char *srcend= src + srclen, *dst0= dst; + const char *srcend= src + srclen; + char *dst0= dst; DBUG_ASSERT(cs->mbmaxlen == 2); @@ -193,22 +121,22 @@ my_casefold_mb_varlen(CHARSET_INFO *cs, size_t -my_casedn_mb_varlen(CHARSET_INFO * cs, char *src, size_t srclen, +my_casedn_mb(CHARSET_INFO * cs, const char *src, size_t srclen, char *dst, size_t dstlen) { DBUG_ASSERT(dstlen >= srclen * cs->casedn_multiply); DBUG_ASSERT(src != dst || cs->casedn_multiply == 1); - return my_casefold_mb_varlen(cs, src, srclen, dst, dstlen, cs->to_lower, 0); + return my_casefold_mb(cs, src, srclen, dst, dstlen, cs->to_lower, 0); } size_t -my_caseup_mb_varlen(CHARSET_INFO * cs, char *src, size_t srclen, - char *dst, size_t dstlen) +my_caseup_mb(CHARSET_INFO * cs, const char *src, size_t srclen, + char *dst, size_t dstlen) { DBUG_ASSERT(dstlen >= srclen * cs->caseup_multiply); DBUG_ASSERT(src != dst || cs->caseup_multiply == 1); - return my_casefold_mb_varlen(cs, src, srclen, dst, dstlen, cs->to_upper, 1); + return my_casefold_mb(cs, src, srclen, dst, dstlen, cs->to_upper, 1); } diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 7f13cef4474..61b14b84820 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -214,28 +214,26 @@ size_t my_casedn_str_8bit(CHARSET_INFO * cs,char *str) } -size_t my_caseup_8bit(CHARSET_INFO * cs, char *src, size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) +size_t my_caseup_8bit(CHARSET_INFO * cs, const char *src, size_t srclen, + char *dst, size_t dstlen) { - char *end= src + srclen; + const char *end= src + srclen; register const uchar *map= cs->to_upper; - DBUG_ASSERT(src == dst && srclen == dstlen); + DBUG_ASSERT(srclen <= dstlen); for ( ; src != end ; src++) - *src= (char) map[(uchar) *src]; + *dst++= (char) map[(uchar) *src]; return srclen; } -size_t my_casedn_8bit(CHARSET_INFO * cs, char *src, size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) +size_t my_casedn_8bit(CHARSET_INFO * cs, const char *src, size_t srclen, + char *dst, size_t dstlen) { - char *end= src + srclen; + const char *end= src + srclen; register const uchar *map=cs->to_lower; - DBUG_ASSERT(src == dst && srclen == dstlen); + DBUG_ASSERT(srclen <= dstlen); for ( ; src != end ; src++) - *src= (char) map[(uchar) *src]; + *dst++= (char) map[(uchar) *src]; return srclen; } diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index 318c248f742..724e69872de 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1196,25 +1196,26 @@ my_tosort_utf16(MY_UNICASE_INFO *uni_plane, my_wc_t *wc) static size_t -my_caseup_utf16(CHARSET_INFO *cs, char *src, size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) +my_caseup_utf16(CHARSET_INFO *cs, const char *src, size_t srclen, + char *dst, size_t dstlen) { my_wc_t wc; my_charset_conv_mb_wc mb_wc= cs->cset->mb_wc; my_charset_conv_wc_mb wc_mb= cs->cset->wc_mb; int res; - char *srcend= src + srclen; + const char *srcend= src + srclen; + char *dstend= dst + dstlen; MY_UNICASE_INFO *uni_plane= cs->caseinfo; - DBUG_ASSERT(src == dst && srclen == dstlen); + DBUG_ASSERT(srclen <= dstlen); while ((src < srcend) && (res= mb_wc(cs, &wc, (uchar *) src, (uchar *) srcend)) > 0) { my_toupper_utf16(uni_plane, &wc); - if (res != wc_mb(cs, wc, (uchar *) src, (uchar *) srcend)) + if (res != wc_mb(cs, wc, (uchar *) dst, (uchar *) dstend)) break; src+= res; + dst+= res; } return srclen; } @@ -1243,25 +1244,26 @@ my_hash_sort_utf16(CHARSET_INFO *cs, const uchar *s, size_t slen, static size_t -my_casedn_utf16(CHARSET_INFO *cs, char *src, size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) +my_casedn_utf16(CHARSET_INFO *cs, const char *src, size_t srclen, + char *dst, size_t dstlen) { my_wc_t wc; my_charset_conv_mb_wc mb_wc= cs->cset->mb_wc; my_charset_conv_wc_mb wc_mb= cs->cset->wc_mb; int res; - char *srcend= src + srclen; + const char *srcend= src + srclen; + char *dstend= dst + dstlen; MY_UNICASE_INFO *uni_plane= cs->caseinfo; - DBUG_ASSERT(src == dst && srclen == dstlen); + DBUG_ASSERT(srclen <= dstlen); while ((src < srcend) && (res= mb_wc(cs, &wc, (uchar *) src, (uchar *) srcend)) > 0) { my_tolower_utf16(uni_plane, &wc); - if (res != wc_mb(cs, wc, (uchar *) src, (uchar *) srcend)) + if (res != wc_mb(cs, wc, (uchar *) dst, (uchar *) dstend)) break; src+= res; + dst+= res; } return srclen; } @@ -1987,23 +1989,24 @@ my_tosort_utf32(MY_UNICASE_INFO *uni_plane, my_wc_t *wc) static size_t -my_caseup_utf32(CHARSET_INFO *cs, char *src, size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) +my_caseup_utf32(CHARSET_INFO *cs, const char *src, size_t srclen, + char *dst, size_t dstlen) { my_wc_t wc; int res; - char *srcend= src + srclen; + const char *srcend= src + srclen; + char *dstend= dst + dstlen; MY_UNICASE_INFO *uni_plane= cs->caseinfo; - DBUG_ASSERT(src == dst && srclen == dstlen); + DBUG_ASSERT(srclen <= dstlen); while ((src < srcend) && (res= my_utf32_uni(cs, &wc, (uchar *)src, (uchar*) srcend)) > 0) { my_toupper_utf32(uni_plane, &wc); - if (res != my_uni_utf32(cs, wc, (uchar*) src, (uchar*) srcend)) + if (res != my_uni_utf32(cs, wc, (uchar*) dst, (uchar*) dstend)) break; src+= res; + dst+= res; } return srclen; } @@ -2038,22 +2041,23 @@ my_hash_sort_utf32(CHARSET_INFO *cs, const uchar *s, size_t slen, static size_t -my_casedn_utf32(CHARSET_INFO *cs, char *src, size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) +my_casedn_utf32(CHARSET_INFO *cs, const char *src, size_t srclen, + char *dst, size_t dstlen) { my_wc_t wc; int res; - char *srcend= src + srclen; + const char *srcend= src + srclen; + char *dstend= dst + dstlen; MY_UNICASE_INFO *uni_plane= cs->caseinfo; - DBUG_ASSERT(src == dst && srclen == dstlen); + DBUG_ASSERT(srclen <= dstlen); while ((res= my_utf32_uni(cs, &wc, (uchar*) src, (uchar*) srcend)) > 0) { my_tolower_utf32(uni_plane,&wc); - if (res != my_uni_utf32(cs, wc, (uchar*) src, (uchar*) srcend)) + if (res != my_uni_utf32(cs, wc, (uchar*) dst, (uchar*) dstend)) break; src+= res; + dst+= res; } return srclen; } @@ -2950,23 +2954,24 @@ my_tosort_ucs2(MY_UNICASE_INFO *uni_plane, my_wc_t *wc) *wc= page[*wc & 0xFF].sort; } -static size_t my_caseup_ucs2(CHARSET_INFO *cs, char *src, size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) +static size_t my_caseup_ucs2(CHARSET_INFO *cs, const char *src, size_t srclen, + char *dst, size_t dstlen) { my_wc_t wc; int res; - char *srcend= src + srclen; + const char *srcend= src + srclen; + char *dstend= dst + dstlen; MY_UNICASE_INFO *uni_plane= cs->caseinfo; - DBUG_ASSERT(src == dst && srclen == dstlen); + DBUG_ASSERT(srclen <= dstlen); while ((src < srcend) && (res= my_ucs2_uni(cs, &wc, (uchar *)src, (uchar*) srcend)) > 0) { my_toupper_ucs2(uni_plane, &wc); - if (res != my_uni_ucs2(cs, wc, (uchar*) src, (uchar*) srcend)) + if (res != my_uni_ucs2(cs, wc, (uchar*) dst, (uchar*) dstend)) break; src+= res; + dst+= res; } return srclen; } @@ -2995,23 +3000,24 @@ static void my_hash_sort_ucs2(CHARSET_INFO *cs, const uchar *s, size_t slen, } -static size_t my_casedn_ucs2(CHARSET_INFO *cs, char *src, size_t srclen, - char *dst __attribute__((unused)), - size_t dstlen __attribute__((unused))) +static size_t my_casedn_ucs2(CHARSET_INFO *cs, const char *src, size_t srclen, + char *dst, size_t dstlen) { my_wc_t wc; int res; - char *srcend= src + srclen; + const char *srcend= src + srclen; + char *dstend= dst + dstlen; MY_UNICASE_INFO *uni_plane= cs->caseinfo; - DBUG_ASSERT(src == dst && srclen == dstlen); + DBUG_ASSERT(srclen <= dstlen); while ((src < srcend) && (res= my_ucs2_uni(cs, &wc, (uchar*) src, (uchar*) srcend)) > 0) { my_tolower_ucs2(uni_plane, &wc); - if (res != my_uni_ucs2(cs, wc, (uchar*) src, (uchar*) srcend)) + if (res != my_uni_ucs2(cs, wc, (uchar*) dst, (uchar*) dstend)) break; src+= res; + dst+= res; } return srclen; } diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c index e7dbefe6c1d..25f8881d819 100644 --- a/strings/ctype-ujis.c +++ b/strings/ctype-ujis.c @@ -67179,12 +67179,12 @@ get_case_info_for_ch(CHARSET_INFO *cs, uint plane, uint page, uint offs) */ static size_t my_casefold_ujis(CHARSET_INFO *cs, - char *src, size_t srclen, + const char *src, size_t srclen, char *dst, size_t dstlen __attribute__((unused)), const uchar * const map, size_t is_upper) { - char *srcend= src + srclen, *dst0= dst; + const char *srcend= src + srclen, *dst0= dst; while (src < srcend) { @@ -67226,7 +67226,7 @@ my_casefold_ujis(CHARSET_INFO *cs, LOWER() */ size_t -my_casedn_ujis(CHARSET_INFO * cs, char *src, size_t srclen, +my_casedn_ujis(CHARSET_INFO * cs, const char *src, size_t srclen, char *dst, size_t dstlen) { DBUG_ASSERT(dstlen >= srclen * cs->casedn_multiply); @@ -67239,7 +67239,7 @@ my_casedn_ujis(CHARSET_INFO * cs, char *src, size_t srclen, UPPER() */ size_t -my_caseup_ujis(CHARSET_INFO * cs, char *src, size_t srclen, +my_caseup_ujis(CHARSET_INFO * cs, const char *src, size_t srclen, char *dst, size_t dstlen) { DBUG_ASSERT(dstlen >= srclen * cs->caseup_multiply); diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index cd4e82a107c..7d7e61ce511 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -5065,12 +5065,13 @@ my_tosort_utf8mb3(MY_UNICASE_INFO *uni_plane, my_wc_t *wc) *wc= page[*wc & 0xFF].sort; } -static size_t my_caseup_utf8(CHARSET_INFO *cs, char *src, size_t srclen, +static size_t my_caseup_utf8(CHARSET_INFO *cs, const char *src, size_t srclen, char *dst, size_t dstlen) { my_wc_t wc; int srcres, dstres; - char *srcend= src + srclen, *dstend= dst + dstlen, *dst0= dst; + const char *srcend= src + srclen; + char *dstend= dst + dstlen, *dst0= dst; MY_UNICASE_INFO *uni_plane= cs->caseinfo; DBUG_ASSERT(src != dst || cs->caseup_multiply == 1); @@ -5136,12 +5137,13 @@ static size_t my_caseup_str_utf8(CHARSET_INFO *cs, char *src) } -static size_t my_casedn_utf8(CHARSET_INFO *cs, char *src, size_t srclen, +static size_t my_casedn_utf8(CHARSET_INFO *cs, const char *src, size_t srclen, char *dst, size_t dstlen) { my_wc_t wc; int srcres, dstres; - char *srcend= src + srclen, *dstend= dst + dstlen, *dst0= dst; + const char *srcend= src + srclen; + char *dstend= dst + dstlen, *dst0= dst; MY_UNICASE_INFO *uni_plane= cs->caseinfo; DBUG_ASSERT(src != dst || cs->casedn_multiply == 1); @@ -7579,12 +7581,13 @@ my_toupper_utf8mb4(MY_UNICASE_INFO *uni_plane, my_wc_t *wc) static size_t -my_caseup_utf8mb4(CHARSET_INFO *cs, char *src, size_t srclen, +my_caseup_utf8mb4(CHARSET_INFO *cs, const char *src, size_t srclen, char *dst, size_t dstlen) { my_wc_t wc; int srcres, dstres; - char *srcend= src + srclen, *dstend= dst + dstlen, *dst0= dst; + const char *srcend= src + srclen; + char *dstend= dst + dstlen, *dst0= dst; MY_UNICASE_INFO *uni_plane= cs->caseinfo; DBUG_ASSERT(src != dst || cs->caseup_multiply == 1); @@ -7666,12 +7669,13 @@ my_caseup_str_utf8mb4(CHARSET_INFO *cs, char *src) static size_t my_casedn_utf8mb4(CHARSET_INFO *cs, - char *src, size_t srclen, + const char *src, size_t srclen, char *dst, size_t dstlen) { my_wc_t wc; int srcres, dstres; - char *srcend= src + srclen, *dstend= dst + dstlen, *dst0= dst; + const char *srcend= src + srclen; + char *dstend= dst + dstlen, *dst0= dst; MY_UNICASE_INFO *uni_plane= cs->caseinfo; DBUG_ASSERT(src != dst || cs->casedn_multiply == 1); From 09f147659f36a30d7075885d88392c9a41244505 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 19 Jul 2018 12:07:07 +0300 Subject: [PATCH 41/71] MDEV-16777: galera.galera_gra_log fails with File ...GRA_*.log not found error snprintf returns the number of bytes it wrote (or would have written) NOT counting the \0 terminal character. The buffer size it accepts as argument DOES COUNT the \0 character. Pass the right parameter value. --- sql/wsrep_binlog.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc index 902190d4772..c7674cd0169 100644 --- a/sql/wsrep_binlog.cc +++ b/sql/wsrep_binlog.cc @@ -326,11 +326,16 @@ void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len) WSREP_ERROR("snprintf error: %d, skipping dump.", len); return; } + /* + len doesn't count the \0 end-of-string. Use len+1 below + to alloc and pass as an argument to snprintf. + */ char *filename= (char *)malloc(len+1); - int len1= snprintf(filename, len, "%s/GRA_%ld_%lld.log", + int len1= snprintf(filename, len+1, "%s/GRA_%ld_%lld.log", wsrep_data_home_dir, thd->thread_id, (long long)wsrep_thd_trx_seqno(thd)); + if (len > len1) { WSREP_ERROR("RBR dump path truncated: %d, skipping dump.", len); @@ -469,7 +474,10 @@ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf, int len= snprintf(NULL, 0, "%s/GRA_%ld_%lld_v2.log", wsrep_data_home_dir, thd->thread_id, thd_trx_seqno); - + /* + len doesn't count the \0 end-of-string. Use len+1 below + to alloc and pass as an argument to snprintf. + */ char *filename; if (len < 0 || !(filename= (char*)malloc(len+1))) { @@ -477,7 +485,7 @@ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf, DBUG_VOID_RETURN; } - int len1= snprintf(filename, len, "%s/GRA_%ld_%lld_v2.log", + int len1= snprintf(filename, len+1, "%s/GRA_%ld_%lld_v2.log", wsrep_data_home_dir, thd->thread_id, thd_trx_seqno); From 0b3e28a4cd3f8000eedb8ba190c0ea461544651a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 12 Jul 2018 21:58:11 +0200 Subject: [PATCH 42/71] MDEV-8941 Compile on Solaris (SPARC) fails with errors in filamvct.cpp remove unnecessary declaration --- storage/connect/filamvct.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/storage/connect/filamvct.cpp b/storage/connect/filamvct.cpp index 244acfdc5c8..dd827d084fa 100755 --- a/storage/connect/filamvct.cpp +++ b/storage/connect/filamvct.cpp @@ -65,11 +65,6 @@ extern int num_read, num_there; // Statistics static int num_write; -#if defined(UNIX) -// Add dummy strerror (NGC) -char *strerror(int num); -#endif // UNIX - /***********************************************************************/ /* Header containing block info for not split VEC tables. */ /* Block and last values can be calculated from NumRec and Nrec. */ From bd5cf02bbe7bce029b0275be1b15d2108806d5e9 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 13 Jul 2018 16:54:47 +0200 Subject: [PATCH 43/71] MDEV-11741 handler::ha_reset(): Assertion `bitmap_is_set_all(&table->s->all_set)' failed or server crash in mi_reset or buffer overrun or unexpected ER_CANT_REMOVE_ALL_FIELDS MEMORY table could be renamed into a non-extistent database. rename() is documented to return ENOENT when the source file does not exist OR when the target directory not exist. Nonexistent source .frm file is ok (table can still exist in the engine), nonexistent target directory is not. Make my_rename to use ENOTDIR for the latter case. Make RENAME TABLE issue an appropriate error ("unknown database" instead of "unknown table") --- mysql-test/r/rename.result | 4 ++++ mysql-test/t/rename.test | 7 +++++++ mysys/my_rename.c | 5 ++++- sql/sql_table.cc | 2 ++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/rename.result b/mysql-test/r/rename.result index c90aaf24e9b..f019527c951 100644 --- a/mysql-test/r/rename.result +++ b/mysql-test/r/rename.result @@ -133,3 +133,7 @@ select * from t2; a 1 drop table tmp,t2; +create table t1 (a int) engine=memory; +rename table t1 to non_existent.t2; +ERROR 42000: Unknown database 'non_existent' +drop table t1; diff --git a/mysql-test/t/rename.test b/mysql-test/t/rename.test index 67732d5b5b9..215ecbcbb18 100644 --- a/mysql-test/t/rename.test +++ b/mysql-test/t/rename.test @@ -141,3 +141,10 @@ select * from tmp; select * from t2; drop table tmp,t2; +# +# MDEV-11741 handler::ha_reset(): Assertion `bitmap_is_set_all(&table->s->all_set)' failed or server crash in mi_reset or buffer overrun or unexpected ER_CANT_REMOVE_ALL_FIELDS +# +create table t1 (a int) engine=memory; +--error ER_BAD_DB_ERROR +rename table t1 to non_existent.t2; +drop table t1; diff --git a/mysys/my_rename.c b/mysys/my_rename.c index 09e7eafa980..17f693629a8 100644 --- a/mysys/my_rename.c +++ b/mysys/my_rename.c @@ -39,7 +39,10 @@ int my_rename(const char *from, const char *to, myf MyFlags) if (link(from, to) || unlink(from)) { #endif - my_errno=errno; + if (errno == ENOENT && !access(from, F_OK)) + my_errno= ENOTDIR; + else + my_errno= errno; error = -1; if (MyFlags & (MY_FAE+MY_WME)) my_error(EE_LINK, MYF(ME_BELL+ME_WAITTANG),from,to,my_errno); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ee02b5fc7aa..9a2b4901d4e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5257,6 +5257,8 @@ mysql_rename_table(handlerton *base, const char *old_db, delete file; if (error == HA_ERR_WRONG_COMMAND) my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE"); + else if (error == ENOTDIR) + my_error(ER_BAD_DB_ERROR, MYF(0), new_db); else if (error) my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error); else if (!(flags & FN_IS_TMP)) From 33eccb577657a127a877cea53ee4dc41cb4604c2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 13 Jul 2018 21:37:22 +0200 Subject: [PATCH 44/71] MDEV-11790 WITHOUT_SERVER installs mysqld_safe_helper Don't install server files if WITHOUT_SERVER is specified. "Server files" are defined as files going into the MariaDB-Server RPM, that is files in the components Server, ManPagesServer, Server_Scripts, IniFiles, SuportFiles, and Readme. --- CMakeLists.txt | 6 ++++++ cmake/install_macros.cmake | 8 ++++++++ cmake/mysql_add_executable.cmake | 3 +++ scripts/CMakeLists.txt | 2 ++ sql/share/CMakeLists.txt | 12 +++++++----- support-files/CMakeLists.txt | 2 ++ 6 files changed, 28 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11874650d18..5a9ec265de0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,6 +165,12 @@ ENDIF() OPTION (WITH_UNIT_TESTS "Compile MySQL with unit tests" ON) MARK_AS_ADVANCED(CYBOZU BACKUP_TEST WITHOUT_SERVER DISABLE_SHARED) +IF (WITHOUT_SERVER) + SET (SKIP_COMPONENTS "Server|IniFiles|SuportFiles|Readme") +ELSE() + SET (SKIP_COMPONENTS "N-O-N-E") +ENDIF() + OPTION(NOT_FOR_DISTRIBUTION "Allow linking with GPLv2-incompatible system libraries. Only set it you never plan to distribute the resulting binaries" OFF) include(CheckCSourceCompiles) diff --git a/cmake/install_macros.cmake b/cmake/install_macros.cmake index 7da8edd22eb..ff4ba593415 100644 --- a/cmake/install_macros.cmake +++ b/cmake/install_macros.cmake @@ -115,6 +115,10 @@ FUNCTION(INSTALL_SCRIPT) SET(COMP) ENDIF() + IF (COMP MATCHES ${SKIP_COMPONENTS}) + RETURN() + ENDIF() + INSTALL(FILES ${script} DESTINATION ${ARG_DESTINATION} @@ -138,6 +142,10 @@ FUNCTION(INSTALL_DOCUMENTATION) SET(destination ${INSTALL_DOCDIR}) ENDIF() + IF (ARG_COMPONENT MATCHES ${SKIP_COMPONENTS}) + RETURN() + ENDIF() + STRING(TOUPPER ${ARG_COMPONENT} COMPUP) IF(CPACK_COMPONENT_${COMPUP}_GROUP) SET(group ${CPACK_COMPONENT_${COMPUP}_GROUP}) diff --git a/cmake/mysql_add_executable.cmake b/cmake/mysql_add_executable.cmake index 45575bdd536..c8a2e522d66 100644 --- a/cmake/mysql_add_executable.cmake +++ b/cmake/mysql_add_executable.cmake @@ -59,6 +59,9 @@ FUNCTION (MYSQL_ADD_EXECUTABLE) ELSE() SET(COMP COMPONENT Client) ENDIF() + IF (COMP MATCHES ${SKIP_COMPONENTS}) + RETURN() + ENDIF() MYSQL_INSTALL_TARGETS(${target} DESTINATION ${ARG_DESTINATION} ${COMP}) ENDIF() ENDFUNCTION() diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 40273b1a1c2..24b48e1920e 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -74,6 +74,7 @@ IF(UNIX) ) ENDIF() +IF (NOT WITHOUT_SERVER) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/mysql_system_tables.sql ${CMAKE_CURRENT_SOURCE_DIR}/mysql_system_tables_data.sql @@ -83,6 +84,7 @@ INSTALL(FILES ${FIX_PRIVILEGES_SQL} DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server ) +ENDIF() # TCMalloc hacks IF(MALLOC_LIB) diff --git a/sql/share/CMakeLists.txt b/sql/share/CMakeLists.txt index e0d5fb6c1a7..4293c0b528c 100644 --- a/sql/share/CMakeLists.txt +++ b/sql/share/CMakeLists.txt @@ -44,12 +44,14 @@ SET(files errmsg-utf8.txt ) -FOREACH (dir ${dirs}) - INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${dir} - DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server) -ENDFOREACH() INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/charsets DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Common PATTERN "languages.html" EXCLUDE ) -INSTALL(FILES ${files} DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server) +IF (NOT WITHOUT_SERVER) + FOREACH (dir ${dirs}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${dir} + DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server) + ENDFOREACH() + INSTALL(FILES ${files} DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server) +ENDIF() diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 5e9fd081a09..cc9eed6c7be 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -41,12 +41,14 @@ ELSE() SET(inst_location ${INSTALL_SUPPORTFILESDIR}) ENDIF() +IF (NOT WITHOUT_SERVER) FOREACH(inifile my-huge my-innodb-heavy-4G my-large my-medium my-small) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${inifile}.cnf.sh ${CMAKE_CURRENT_BINARY_DIR}/${inifile}.${ini_file_extension} @ONLY) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${inifile}.${ini_file_extension} DESTINATION ${inst_location} COMPONENT IniFiles) ENDFOREACH() +ENDIF() IF(UNIX) SET(prefix ${CMAKE_INSTALL_PREFIX}) From 40f29ecbf1c8bf36be443c40382fe8cdc8a7f413 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 14 Jul 2018 00:51:23 +0200 Subject: [PATCH 45/71] MDEV-13397 MariaDB upgrade fail when using default_time_zone don't try to set default time zone in --bootstrap, this generally cannot be done, as timezone tables aren't loaded. and bootstrap scripts don't need it anyway. --- mysql-test/t/bootstrap.test | 9 +++++++++ sql/tztime.cc | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/bootstrap.test b/mysql-test/t/bootstrap.test index 5ab736cee15..3df3919220e 100644 --- a/mysql-test/t/bootstrap.test +++ b/mysql-test/t/bootstrap.test @@ -105,3 +105,12 @@ use test; EOF --exec $MYSQLD_BOOTSTRAP_CMD --ignore-db-dirs='some_dir' --ignore-db-dirs='some_dir' < $MYSQLTEST_VARDIR/tmp/bootstrap_9969.sql >> $MYSQLTEST_VARDIR/tmp/bootstrap.log 2>&1 --remove_file $MYSQLTEST_VARDIR/tmp/bootstrap_9969.sql + +# +# MDEV-13397 MariaDB upgrade fail when using default_time_zone +# +--write_file $MYSQLTEST_VARDIR/tmp/bootstrap_9969.sql +use test; +EOF +--exec $MYSQLD_BOOTSTRAP_CMD --default-time-zone=Europe/Moscow < $MYSQLTEST_VARDIR/tmp/bootstrap_9969.sql >> $MYSQLTEST_VARDIR/tmp/bootstrap.log 2>&1 +--remove_file $MYSQLTEST_VARDIR/tmp/bootstrap_9969.sql diff --git a/sql/tztime.cc b/sql/tztime.cc index 75b732f4436..9933c1e6364 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1663,7 +1663,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) { /* If we are in bootstrap mode we should not load time zone tables */ return_val= time_zone_tables_exist= 0; - goto end_with_setting_default_tz; + goto end_with_cleanup; } /* From 5c744bb5350acbf2d3abce28d01fc829c4f2375c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 14 Jul 2018 13:48:50 +0200 Subject: [PATCH 46/71] MDEV-14882 mysql_upgrade performs unnecessary conversions back and forth avoid round-robin conversions, if the column is MODIFY-ed, it should always be modified to its final definition, not to some intermediate state. also avoid other unconditional changes, like ALTER TABLE event DROP PRIMARY KEY; ALTER TABLE event ADD PRIMARY KEY(db, name); --- scripts/mysql_system_tables_fix.sql | 50 +++++++++++++++++------------ 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql index 1bb601ef5f9..194b1615c2b 100644 --- a/scripts/mysql_system_tables_fix.sql +++ b/scripts/mysql_system_tables_fix.sql @@ -1,5 +1,5 @@ -- Copyright (C) 2003, 2013 Oracle and/or its affiliates. --- Copyright (C) 2010, 2014 SkySQL Ab. +-- Copyright (C) 2010, 2018 MariaDB Corporation -- -- 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 @@ -27,15 +27,24 @@ set sql_mode=''; set storage_engine=MyISAM; -ALTER TABLE user add File_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL; +ALTER TABLE user add File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; # Detect whether or not we had the Grant_priv column SET @hadGrantPriv:=0; SELECT @hadGrantPriv:=1 FROM user WHERE Grant_priv LIKE '%'; -ALTER TABLE user add Grant_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add References_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add Index_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add Alter_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL; -ALTER TABLE host add Grant_priv enum('N','Y') NOT NULL,add References_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add Index_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add Alter_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL; -ALTER TABLE db add Grant_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add References_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add Index_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add Alter_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL; +ALTER TABLE user add Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + add References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + add Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + add Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; +ALTER TABLE host add Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + add References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + add Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + add Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; +ALTER TABLE db add Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + add References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + add Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + add Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; # Fix privileges for old tables UPDATE user SET Grant_priv=File_priv,References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv WHERE @hadGrantPriv = 0; @@ -47,11 +56,11 @@ UPDATE host SET References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Cr # Adding columns needed by GRANT .. REQUIRE (openssl) ALTER TABLE user -ADD ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci NOT NULL, +ADD ssl_type enum('','ANY','X509', 'SPECIFIED') DEFAULT '' NOT NULL, ADD ssl_cipher BLOB NOT NULL, ADD x509_issuer BLOB NOT NULL, ADD x509_subject BLOB NOT NULL; -ALTER TABLE user MODIFY ssl_type enum('','ANY','X509', 'SPECIFIED') NOT NULL; +ALTER TABLE user MODIFY ssl_type enum('','ANY','X509', 'SPECIFIED') DEFAULT '' NOT NULL; # # tables_priv @@ -62,9 +71,9 @@ ALTER TABLE tables_priv ALTER TABLE tables_priv MODIFY Host char(60) NOT NULL default '', MODIFY Db char(64) NOT NULL default '', - MODIFY User char(80) NOT NULL default '', + MODIFY User char(80) binary NOT NULL default '', MODIFY Table_name char(64) NOT NULL default '', - MODIFY Grantor char(141) NOT NULL default '', + MODIFY Grantor char(141) COLLATE utf8_bin NOT NULL default '', ENGINE=MyISAM, CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin; @@ -90,7 +99,7 @@ ALTER TABLE columns_priv ALTER TABLE columns_priv MODIFY Host char(60) NOT NULL default '', MODIFY Db char(64) NOT NULL default '', - MODIFY User char(80) NOT NULL default '', + MODIFY User char(80) binary NOT NULL default '', MODIFY Table_name char(64) NOT NULL default '', MODIFY Column_name char(64) NOT NULL default '', ENGINE=MyISAM, @@ -161,7 +170,7 @@ alter table func comment='User defined functions'; # and reset all char columns to correct width ALTER TABLE user MODIFY Host char(60) NOT NULL default '', - MODIFY User char(80) NOT NULL default '', + MODIFY User char(80) binary NOT NULL default '', ENGINE=MyISAM, CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin; ALTER TABLE user MODIFY Password char(41) character set latin1 collate latin1_bin NOT NULL default '', @@ -191,7 +200,7 @@ ALTER TABLE user ALTER TABLE db MODIFY Host char(60) NOT NULL default '', MODIFY Db char(64) NOT NULL default '', - MODIFY User char(80) NOT NULL default '', + MODIFY User char(80) binary NOT NULL default '', ENGINE=MyISAM, CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin; ALTER TABLE db MODIFY Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, @@ -451,7 +460,7 @@ ALTER TABLE proc MODIFY db MODIFY definer char(141) collate utf8_bin DEFAULT '' NOT NULL, MODIFY comment - char(64) collate utf8_bin DEFAULT '' NOT NULL; + text collate utf8_bin NOT NULL; ALTER TABLE proc ADD character_set_client char(32) collate utf8_bin DEFAULT NULL @@ -515,19 +524,18 @@ ALTER TABLE proc MODIFY comment SET @hadEventPriv := 0; SELECT @hadEventPriv :=1 FROM user WHERE Event_priv LIKE '%'; -ALTER TABLE user add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL AFTER Create_user_priv; +ALTER TABLE user ADD Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL AFTER Create_user_priv; ALTER TABLE user MODIFY Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL AFTER Create_user_priv; UPDATE user SET Event_priv=Super_priv WHERE @hadEventPriv = 0; -ALTER TABLE db add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL; +ALTER TABLE db ADD Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL; ALTER TABLE db MODIFY Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL; # # EVENT table # -ALTER TABLE event DROP PRIMARY KEY; -ALTER TABLE event ADD PRIMARY KEY(db, name); +ALTER TABLE event DROP PRIMARY KEY, ADD PRIMARY KEY(db, name); # Add sql_mode column just in case. ALTER TABLE event ADD sql_mode set ('IGNORE_BAD_TABLE_OPTIONS') AFTER on_completion; # Update list of sql_mode values. @@ -567,8 +575,8 @@ ALTER TABLE event MODIFY sql_mode ) DEFAULT '' NOT NULL AFTER on_completion; ALTER TABLE event MODIFY name char(64) CHARACTER SET utf8 NOT NULL default ''; -ALTER TABLE event MODIFY COLUMN originator INT UNSIGNED NOT NULL; ALTER TABLE event ADD COLUMN originator INT UNSIGNED NOT NULL AFTER comment; +ALTER TABLE event MODIFY COLUMN originator INT UNSIGNED NOT NULL; ALTER TABLE event MODIFY COLUMN status ENUM('ENABLED','DISABLED','SLAVESIDE_DISABLED') NOT NULL default 'ENABLED'; @@ -630,10 +638,12 @@ ALTER TABLE user MODIFY Create_tablespace_priv enum('N','Y') COLLATE utf8_genera UPDATE user SET Create_tablespace_priv = Super_priv WHERE @hadCreateTablespacePriv = 0; -ALTER TABLE user ADD plugin char(64) DEFAULT '', ADD authentication_string TEXT; +ALTER TABLE user ADD plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL, + ADD authentication_string TEXT NOT NULL; +ALTER TABLE user MODIFY plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL, + MODIFY authentication_string TEXT NOT NULL; ALTER TABLE user ADD password_expired ENUM('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; ALTER TABLE user ADD is_role enum('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; -ALTER TABLE user MODIFY plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL, MODIFY authentication_string TEXT NOT NULL; -- Somewhere above, we ran ALTER TABLE user .... CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin. -- we want password_expired column to have collation utf8_general_ci. ALTER TABLE user MODIFY password_expired ENUM('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; From d57ddaa1904d3c2f08460c539c72652f0c78c09a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 16 Jul 2018 15:12:38 +0200 Subject: [PATCH 47/71] MDEV-15551 Server hangs or assertion `strcmp(share->unique_file_name,filename) || share->last_version' fails in test_if_reopen or unexpected ER_LOCK_DEADLOCK only use HA_EXTRA_PREPARE_FOR_DROP when the table is going to be dropped --- mysql-test/suite/parts/r/truncate_locked.result | 7 +++++++ mysql-test/suite/parts/t/truncate_locked.test | 10 ++++++++++ sql/sql_truncate.cc | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/parts/r/truncate_locked.result create mode 100644 mysql-test/suite/parts/t/truncate_locked.test diff --git a/mysql-test/suite/parts/r/truncate_locked.result b/mysql-test/suite/parts/r/truncate_locked.result new file mode 100644 index 00000000000..54a3722938e --- /dev/null +++ b/mysql-test/suite/parts/r/truncate_locked.result @@ -0,0 +1,7 @@ +create table t1 (i int) engine=myisam partition by hash(i) partitions 2 ; +lock table t1 write; +truncate table t1; +desc t1; +Field Type Null Key Default Extra +i int(11) YES NULL +drop table t1; diff --git a/mysql-test/suite/parts/t/truncate_locked.test b/mysql-test/suite/parts/t/truncate_locked.test new file mode 100644 index 00000000000..4ff1016fb05 --- /dev/null +++ b/mysql-test/suite/parts/t/truncate_locked.test @@ -0,0 +1,10 @@ +# +# MDEV-15551 Server hangs or assertion `strcmp(share->unique_file_name,filename) || share->last_version' fails in test_if_reopen or unexpected ER_LOCK_DEADLOCK +# +--source include/have_partition.inc +create table t1 (i int) engine=myisam partition by hash(i) partitions 2 ; +lock table t1 write; +truncate table t1; +desc t1; +drop table t1; + diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 75a0678928b..f5161c09b2c 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -400,7 +400,8 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref, { DEBUG_SYNC(thd, "upgrade_lock_for_truncate"); /* To remove the table from the cache we need an exclusive lock. */ - if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_DROP)) + if (wait_while_table_is_used(thd, table, + *hton_can_recreate ? HA_EXTRA_PREPARE_FOR_DROP : HA_EXTRA_NOT_USED)) DBUG_RETURN(TRUE); m_ticket_downgrade= table->mdl_ticket; /* Close if table is going to be recreated. */ From 323f269d4099b4a47530f0574af63292dfd89b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 19 Jul 2018 15:13:31 +0300 Subject: [PATCH 48/71] MDEV-10564: Galera `wsrep_debug` patch logs MySQL user credentials Restricted output for CREATE USER, GRANT, REVOKE and SET PASSWORD so that it shows only above keywords but not rest of query i.e. not user or password. --- sql/wsrep_mysqld.cc | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index b127d3a8f00..a88713652ed 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1450,6 +1450,25 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, } } +static const char* wsrep_get_query_or_msg(const THD* thd) +{ + switch(thd->lex->sql_command) + { + case SQLCOM_CREATE_USER: + return "CREATE USER"; + case SQLCOM_GRANT: + return "GRANT"; + case SQLCOM_REVOKE: + return "REVOKE"; + case SQLCOM_SET_OPTION: + if (thd->lex->definer) + return "SET PASSWORD"; + /* fallthrough */ + default: + return thd->query(); + } +} + /* returns: 0: statement was replicated as TOI @@ -1472,7 +1491,8 @@ static int wsrep_TOI_begin(THD *thd, char *db_, char *table_, } WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), - thd->wsrep_exec_mode, thd->query() ); + thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd)); + switch (thd->lex->sql_command) { case SQLCOM_CREATE_VIEW: @@ -1546,8 +1566,8 @@ static void wsrep_TOI_end(THD *thd) { wsrep_status_t ret; wsrep_to_isolation--; - WSREP_DEBUG("TO END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), - thd->wsrep_exec_mode, (thd->query()) ? thd->query() : "void"); + WSREP_DEBUG("TO END: %lld, %d: %s", (long long)wsrep_thd_trx_seqno(thd), + thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd)); wsrep_set_SE_checkpoint(thd->wsrep_trx_meta.gtid.uuid, thd->wsrep_trx_meta.gtid.seqno); From 9cea4ccf12cb6e8746b9b440d9c62408a9ef04af Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 19 Jul 2018 15:31:30 -0700 Subject: [PATCH 49/71] MDEV-16726 Assertion `tab->type == JT_REF || tab->type == JT_EQ_REF' failed Due to a legacy bug in the code of make_join_statistics() detecting so-called constant tables could miss some of them in rare queries that used RIGHT JOIN. As a result these queries had execution plans different from the execution plans of the equivalent queries with LEFT JOIN. Besides starting from 10.2 this could trigger an assertion failure. --- mysql-test/r/join_outer.result | 50 +++++++++++++++++++++ mysql-test/r/join_outer_jcl6.result | 50 +++++++++++++++++++++ mysql-test/r/subselect_mat_cost_bugs.result | 2 +- mysql-test/t/join_outer.test | 48 ++++++++++++++++++++ sql/sql_select.cc | 4 +- 5 files changed, 151 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 67b22ca86b2..d55f11cc2f2 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -2368,5 +2368,55 @@ id sid id 1 NULL NULL 2 NULL NULL drop table t1, t2; +# +# MDEV-16726: SELECT with STRAGHT JOIN containing NESTED RIGHT JOIN +# converted to INNER JOIN with first constant inner table +# +CREATE TABLE t1 ( +pk int PRIMARY KEY, i1 int, v1 varchar(1), v2 varchar(1), KEY v1 (v1,i1) +) engine=MyISAM; +INSERT INTO t1 VALUES +(8,3,'c','c'),(9,4,'z','z'),(10,3,'i','i'),(11,186,'x','x'), +(14,226,'m','m'),(15,133,'p','p'); +CREATE TABLE t2 ( +pk int PRIMARY KEY, i1 int, v1 varchar(1), v2 varchar(1) +) engine=MyISAM; +INSERT INTO t2 VALUES (10,6,'p','p'); +EXPLAIN EXTENDED +SELECT STRAIGHT_JOIN t2.v2 +FROM +(t1 as tb1 LEFT JOIN t1 AS tb2 ON tb2.v1 = tb1.v2) +RIGHT JOIN +(t2,t1) +ON t1.pk = t2.pk AND t2.v2 = tb1.v1 +WHERE tb1.pk = 40 +ORDER BY tb1.i1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select straight_join 'p' AS `v2` from `test`.`t1` join `test`.`t1` `tb1` left join `test`.`t1` `tb2` on(multiple equal(`test`.`tb2`.`v1`, NULL)) where 0 order by NULL +EXPLAIN EXTENDED +SELECT STRAIGHT_JOIN t2.v2 +FROM +(t2,t1) +LEFT JOIN +(t1 as tb1 LEFT JOIN t1 AS tb2 ON tb2.v1 = tb1.v2) +ON t1.pk = t2.pk AND t2.v2 = tb1.v1 +WHERE tb1.pk = 40 +ORDER BY tb1.i1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select straight_join 'p' AS `v2` from `test`.`t1` join `test`.`t1` `tb1` left join `test`.`t1` `tb2` on(multiple equal(`test`.`tb2`.`v1`, NULL)) where 0 order by NULL +SELECT STRAIGHT_JOIN DISTINCT t2.v2 +FROM +(t1 as tb1 LEFT JOIN t1 AS tb2 ON tb2.v1 = tb1.v2) +RIGHT JOIN +(t2,t1) +ON t1.pk = t2.pk AND t2.v2 = tb1.v1 +WHERE tb1.pk = 40 +ORDER BY tb1.i1; +v2 +DROP TABLE t1,t2; # end of 5.5 tests SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/join_outer_jcl6.result b/mysql-test/r/join_outer_jcl6.result index c019da6197b..8a9b395edff 100644 --- a/mysql-test/r/join_outer_jcl6.result +++ b/mysql-test/r/join_outer_jcl6.result @@ -2379,6 +2379,56 @@ id sid id 1 NULL NULL 2 NULL NULL drop table t1, t2; +# +# MDEV-16726: SELECT with STRAGHT JOIN containing NESTED RIGHT JOIN +# converted to INNER JOIN with first constant inner table +# +CREATE TABLE t1 ( +pk int PRIMARY KEY, i1 int, v1 varchar(1), v2 varchar(1), KEY v1 (v1,i1) +) engine=MyISAM; +INSERT INTO t1 VALUES +(8,3,'c','c'),(9,4,'z','z'),(10,3,'i','i'),(11,186,'x','x'), +(14,226,'m','m'),(15,133,'p','p'); +CREATE TABLE t2 ( +pk int PRIMARY KEY, i1 int, v1 varchar(1), v2 varchar(1) +) engine=MyISAM; +INSERT INTO t2 VALUES (10,6,'p','p'); +EXPLAIN EXTENDED +SELECT STRAIGHT_JOIN t2.v2 +FROM +(t1 as tb1 LEFT JOIN t1 AS tb2 ON tb2.v1 = tb1.v2) +RIGHT JOIN +(t2,t1) +ON t1.pk = t2.pk AND t2.v2 = tb1.v1 +WHERE tb1.pk = 40 +ORDER BY tb1.i1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select straight_join 'p' AS `v2` from `test`.`t1` join `test`.`t1` `tb1` left join `test`.`t1` `tb2` on(multiple equal(`test`.`tb2`.`v1`, NULL)) where 0 order by NULL +EXPLAIN EXTENDED +SELECT STRAIGHT_JOIN t2.v2 +FROM +(t2,t1) +LEFT JOIN +(t1 as tb1 LEFT JOIN t1 AS tb2 ON tb2.v1 = tb1.v2) +ON t1.pk = t2.pk AND t2.v2 = tb1.v1 +WHERE tb1.pk = 40 +ORDER BY tb1.i1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select straight_join 'p' AS `v2` from `test`.`t1` join `test`.`t1` `tb1` left join `test`.`t1` `tb2` on(multiple equal(`test`.`tb2`.`v1`, NULL)) where 0 order by NULL +SELECT STRAIGHT_JOIN DISTINCT t2.v2 +FROM +(t1 as tb1 LEFT JOIN t1 AS tb2 ON tb2.v1 = tb1.v2) +RIGHT JOIN +(t2,t1) +ON t1.pk = t2.pk AND t2.v2 = tb1.v1 +WHERE tb1.pk = 40 +ORDER BY tb1.i1; +v2 +DROP TABLE t1,t2; # end of 5.5 tests SET optimizer_switch=@save_optimizer_switch; set join_cache_level=default; diff --git a/mysql-test/r/subselect_mat_cost_bugs.result b/mysql-test/r/subselect_mat_cost_bugs.result index d33f1488e4d..03f4b3e1903 100644 --- a/mysql-test/r/subselect_mat_cost_bugs.result +++ b/mysql-test/r/subselect_mat_cost_bugs.result @@ -442,7 +442,7 @@ SELECT i2 FROM t2 RIGHT JOIN t3 ON (c3 = c2) WHERE pk3 = i1 id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 2 DEPENDENT SUBQUERY t3 const PRIMARY PRIMARY 4 const 1 -2 DEPENDENT SUBQUERY t2 index NULL i2 11 NULL 2 Using where; Using index +2 DEPENDENT SUBQUERY t2 index i2 i2 11 NULL 2 Using where; Using index DROP TABLE t1,t2,t3; # # MDEV-7599: in-to-exists chosen after min/max optimization diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 2769aea9969..305421c10d5 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -1911,6 +1911,54 @@ select * from t1 t on t.id=r.id ; drop table t1, t2; +--echo # +--echo # MDEV-16726: SELECT with STRAGHT JOIN containing NESTED RIGHT JOIN +--echo # converted to INNER JOIN with first constant inner table +--echo # + +CREATE TABLE t1 ( + pk int PRIMARY KEY, i1 int, v1 varchar(1), v2 varchar(1), KEY v1 (v1,i1) +) engine=MyISAM; +INSERT INTO t1 VALUES + (8,3,'c','c'),(9,4,'z','z'),(10,3,'i','i'),(11,186,'x','x'), + (14,226,'m','m'),(15,133,'p','p'); + +CREATE TABLE t2 ( + pk int PRIMARY KEY, i1 int, v1 varchar(1), v2 varchar(1) +) engine=MyISAM; +INSERT INTO t2 VALUES (10,6,'p','p'); + +EXPLAIN EXTENDED +SELECT STRAIGHT_JOIN t2.v2 +FROM + (t1 as tb1 LEFT JOIN t1 AS tb2 ON tb2.v1 = tb1.v2) + RIGHT JOIN + (t2,t1) + ON t1.pk = t2.pk AND t2.v2 = tb1.v1 +WHERE tb1.pk = 40 +ORDER BY tb1.i1; + +EXPLAIN EXTENDED +SELECT STRAIGHT_JOIN t2.v2 +FROM + (t2,t1) + LEFT JOIN + (t1 as tb1 LEFT JOIN t1 AS tb2 ON tb2.v1 = tb1.v2) + ON t1.pk = t2.pk AND t2.v2 = tb1.v1 +WHERE tb1.pk = 40 +ORDER BY tb1.i1; + +SELECT STRAIGHT_JOIN DISTINCT t2.v2 +FROM + (t1 as tb1 LEFT JOIN t1 AS tb2 ON tb2.v1 = tb1.v2) + RIGHT JOIN + (t2,t1) + ON t1.pk = t2.pk AND t2.v2 = tb1.v1 +WHERE tb1.pk = 40 +ORDER BY tb1.i1; + +DROP TABLE t1,t2; + --echo # end of 5.5 tests SET optimizer_switch=@save_optimizer_switch; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 700b7b37928..6a64a0e9952 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3456,8 +3456,8 @@ make_join_statistics(JOIN *join, List &tables_list, int ref_changed; do { - more_const_tables_found: ref_changed = 0; + more_const_tables_found: found_ref=0; /* @@ -3622,7 +3622,7 @@ make_join_statistics(JOIN *join, List &tables_list, } } } - } while (join->const_table_map & found_ref && ref_changed); + } while (ref_changed); join->sort_by_table= get_sort_by_table(join->order, join->group_list, join->select_lex->leaf_tables, From a0d33dc6ef6f380fb5a2d166e75ed6fed2dfce9d Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Fri, 20 Jul 2018 13:35:58 +0200 Subject: [PATCH 50/71] MDEV-16689: core-file should become a real server variable Mysql Bug#56124 bug analog fix using Sys_var_bit. --- client/mysqlbinlog.cc | 2 +- .../sys_vars/r/sysvars_server_embedded.result | 14 ++++++++++++++ .../sys_vars/r/sysvars_server_notembedded.result | 14 ++++++++++++++ sql/mysqld.cc | 3 ++- sql/mysqld.h | 3 ++- sql/sys_vars.cc | 6 ++++++ 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 9753125dd67..bc13aa6c2cc 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -71,7 +71,7 @@ ulong bytes_sent = 0L, bytes_received = 0L; ulong mysqld_net_retry_count = 10L; ulong open_files_limit; ulong opt_binlog_rows_event_max_size; -uint test_flags = 0; +ulonglong test_flags = 0; static uint opt_protocol= 0; static FILE *result_file; static char *result_file_name= 0; diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 7f046a188cc..2b3ecc36772 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -471,6 +471,20 @@ NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME CORE_FILE +SESSION_VALUE NULL +GLOBAL_VALUE ON +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE NULL +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BOOLEAN +VARIABLE_COMMENT write a core-file on crashes +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST OFF,ON +READ_ONLY YES +COMMAND_LINE_ARGUMENT NULL VARIABLE_NAME DATADIR SESSION_VALUE NULL GLOBAL_VALUE PATH diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 72550ffb3af..8df07cdefbd 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -471,6 +471,20 @@ NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME CORE_FILE +SESSION_VALUE NULL +GLOBAL_VALUE ON +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE NULL +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BOOLEAN +VARIABLE_COMMENT write a core-file on crashes +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST OFF,ON +READ_ONLY YES +COMMAND_LINE_ARGUMENT NULL VARIABLE_NAME DATADIR SESSION_VALUE NULL GLOBAL_VALUE PATH diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0f5147c8cf1..1e6e144ccff 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -482,7 +482,7 @@ my_bool opt_master_verify_checksum= 0; my_bool opt_slave_sql_verify_checksum= 1; const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS}; volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */ -uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; +uint mysqld_port, select_errors, dropping_tables, ha_open_options; uint mysqld_extra_port; uint mysqld_port_timeout; ulong delay_key_write_options; @@ -509,6 +509,7 @@ ulonglong max_binlog_cache_size=0; ulong slave_max_allowed_packet= 0; ulonglong binlog_stmt_cache_size=0; ulonglong max_binlog_stmt_cache_size=0; +ulonglong test_flags; ulonglong query_cache_size=0; ulong query_cache_limit=0; ulong executed_events=0; diff --git a/sql/mysqld.h b/sql/mysqld.h index 97ecf889787..0a3266abfb5 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -159,7 +159,8 @@ extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size; extern ulong tc_log_page_waits; extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb; extern my_bool relay_log_recovery; -extern uint test_flags,select_errors,ha_open_options; +extern uint select_errors,ha_open_options; +extern ulonglong test_flags; extern uint protocol_version, mysqld_port, dropping_tables; extern ulong delay_key_write_options; extern char *opt_logname, *opt_slow_logname, *opt_bin_logname, diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 5470acc7892..f941794f89e 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -440,6 +440,12 @@ bool check_has_super(sys_var *self, THD *thd, set_var *var) #endif return false; } + +static Sys_var_bit Sys_core_file("core_file", "write a core-file on crashes", + READ_ONLY GLOBAL_VAR(test_flags), NO_CMD_LINE, + TEST_CORE_ON_SIGNAL, DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, + 0,0,0); + static bool binlog_format_check(sys_var *self, THD *thd, set_var *var) { if (check_has_super(self, thd, var)) From e0139c2b92ba1f8819a3ed75d020d9665545e2bf Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 24 Jul 2018 18:16:41 +0200 Subject: [PATCH 51/71] fix plugins.processlist make it not to fail when `show engine innodb status` output contains a double quote --- mysql-test/suite/plugins/t/processlist.test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/plugins/t/processlist.test b/mysql-test/suite/plugins/t/processlist.test index 5aacef317b9..e8f03aacb10 100644 --- a/mysql-test/suite/plugins/t/processlist.test +++ b/mysql-test/suite/plugins/t/processlist.test @@ -8,7 +8,8 @@ start transaction; insert t1 values (1); let id=`select connection_id()`; connect con2,localhost,root; -let s=query_get_value(show engine innodb status,Status,1); +replace_regex /\"/-/; #" +let s=`show engine innodb status`; disable_query_log; eval select regexp_replace("$s", '(?s)^.*MySQL thread id $id,.*root([^\n]*)\n.*', '\\\\1') as `state from show engine innodb status`; eval select state as `state from show processlist` from information_schema.processlist where id = $id; From 9fbe360e9f7d41d169eb5abed22dc15f26f6c749 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 24 Jul 2018 18:24:21 +0200 Subject: [PATCH 52/71] make plugins.processlist more robust --- mysql-test/suite/plugins/r/processlist.result | 4 +--- mysql-test/suite/plugins/t/processlist.test | 5 +++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/plugins/r/processlist.result b/mysql-test/suite/plugins/r/processlist.result index d08ea9d3523..9200c865533 100644 --- a/mysql-test/suite/plugins/r/processlist.result +++ b/mysql-test/suite/plugins/r/processlist.result @@ -1,8 +1,6 @@ create table t1 (a int) engine=innodb; start transaction; insert t1 values (1); -state from show engine innodb status +state from show engine innodb status, must be empty -state from show processlist - drop table t1; diff --git a/mysql-test/suite/plugins/t/processlist.test b/mysql-test/suite/plugins/t/processlist.test index e8f03aacb10..39b715b867b 100644 --- a/mysql-test/suite/plugins/t/processlist.test +++ b/mysql-test/suite/plugins/t/processlist.test @@ -8,11 +8,12 @@ start transaction; insert t1 values (1); let id=`select connection_id()`; connect con2,localhost,root; +let $wait_condition=select state='' from information_schema.processlist where id = $id; +--source include/wait_condition.inc replace_regex /\"/-/; #" let s=`show engine innodb status`; disable_query_log; -eval select regexp_replace("$s", '(?s)^.*MySQL thread id $id,.*root([^\n]*)\n.*', '\\\\1') as `state from show engine innodb status`; -eval select state as `state from show processlist` from information_schema.processlist where id = $id; +eval select regexp_replace("$s", '(?s)^.*MySQL thread id $id,.*root([^\n]*)\n.*', '\\\\1') as `state from show engine innodb status, must be empty`; enable_query_log; disconnect con2; connection default; From 1bda5e3a8f21d14b4af416259f293a92c49daebb Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Tue, 24 Jul 2018 20:09:42 +0300 Subject: [PATCH 53/71] List of unstable tests for 10.0.36 release --- mysql-test/unstable-tests | 174 +++++++++++++++++++++----------------- 1 file changed, 98 insertions(+), 76 deletions(-) diff --git a/mysql-test/unstable-tests b/mysql-test/unstable-tests index d50a9acc92e..5fa6f6653c3 100644 --- a/mysql-test/unstable-tests +++ b/mysql-test/unstable-tests @@ -23,59 +23,79 @@ # ############################################################################## -# Based on 10.0 48636f09720af45454e5db1183b62a1991db8faf +# Based on 10.0 5e67567b158db5d294b11b310ff35a454f58d034 +main.alter_table : Modified in 10.0.36 +main.assign_key_cache : Added in 10.0.36 +main.assign_key_cache_debug : Added in 10.0.36 +main.auto_increment : Modified in 10.0.36 +main.bootstrap : Modified in 10.0.36 +main.connect_debug : Added in 10.0.36 main.count_distinct2 : MDEV-11768 - timeout main.create_delayed : MDEV-10605 - failed with timeout -main.ctype_ucs : Modified in 10.0.35 -main.ctype_utf8mb4 : Modified in 10.0.35 +main.create_or_replace : Modified in 10.0.36 +ctype_binary : Modified in 10.0.36 +ctype_eucjpms : Modified in 10.0.36 +ctype_euckr : Modified in 10.0.36 +ctype_gbk : Modified in 10.0.36 +ctype_latin1 : Modified in 10.0.36 +ctype_ucs : Modified in 10.0.36 +ctype_ujis : Modified in 10.0.36 +ctype_utf16le : Modified in 10.0.36 +ctype_utf16 : Modified in 10.0.36 +ctype_utf32 : Modified in 10.0.36 +ctype_utf8mb4 : Modified in 10.0.36 +ctype_utf8 : Modified in 10.0.36 main.debug_sync : MDEV-10607 - internal error +main.derived : Modified in 10.0.36 main.derived_opt : MDEV-11768 - timeout -main.dyncol : Modified in 10.0.35 main.events_slowlog : MDEV-12821 - wrong result -main.func_concat : Modified in 10.0.35 -main.func_misc : Modified in 10.0.35 -main.func_str : Modified in 10.0.35 -main.func_time : Modified in 10.0.35 -main.having : Modified in 10.0.35 main.gis : MDEV-13411 - wrong result on P8 +main.grant : Modified in 10.0.36 +main.grant2 : Modified in 10.0.36 +main.grant_not_windows : Added in 10.0.36 +main.having : Modified in 10.0.36 main.host_cache_size_functionality : MDEV-10606 - sporadic failure on shutdown main.index_intersect_innodb : MDEV-10643 - failed with timeout main.index_merge_innodb : MDEV-7142 - wrong result main.innodb_mysql_lock : MDEV-7861 - sporadic lock detection failure -main.join_outer : Modified in 10.0.35 +main.insert_select : Modified in 10.0.36 +main.join : Modified in 10.0.36 +main.join_cache : Modified in 10.0.36 +main.join_outer : Modified in 10.0.36 main.kill_processlist-6619 : MDEV-10793 - wrong result +main.limit : Modified in 10.0.36 main.log_tables-big : MDEV-13408 - wrong result main.mdev-504 : MDEV-10607 - sporadic "can't connect" main.mdev375 : MDEV-10607 - sporadic "can't connect" main.merge : MDEV-10607 - sporadic "can't connect" +main.myisam : Modified in 10.0.36 +main.mysql : Modified in 10.0.36 +main.mysql_cp932 : Modified in 10.0.36 +main.mysqldump : Modified in 10.0.36 main.mysqlhotcopy_myisam : MDEV-10995 - test hangs on debug build +main.mysqlslap : Modified in 10.0.36 main.mysqltest : MDEV-9269 - fails on Alpha main.mysql_client_test_nonblock : MDEV-15096 - exec failed -main.parser : Modified in 10.0.35 -main.partition : Modified in 10.0.35 main.ps : MDEV-11017 - sporadic wrong Prepared_stmt_count -main.ps_qc_innodb : Added in 10.0.35 +main.rename : Modified in 10.0.36 main.query_cache_debug : MDEV-15281 - resize or similar command in progress -main.read_only_innodb : Modified in 10.0.35 +main.selectivity : Modified in 10.0.36 main.show_explain : MDEV-10674 - wrong result -main.sp-destruct : Modified in 10.0.35 +main.sp-innodb : Modified in 10.0.36 main.sp_notembedded : MDEV-10607 - internal error main.sp-security : MDEV-10607 - sporadic "can't connect" +main.statistics : Modified in 10.0.36 +main.statistics_close : Added in 10.0.36 +main.stat_tables : Modified in 10.0.36 main.stat_tables_par_innodb : MDEV-14155 - wrong rounding -main.statistics : Modified in 10.0.35 main.subselect_innodb : MDEV-10614 - sporadic wrong results -main.subselect_mat : Modified in 10.0.35 -main.subselect4 : Modified in 10.0.35 -main.symlink-aria-11902 : MDEV-15098 - error 40 from storage engine -main.symlink-myisam-11902 : MDEV-15098 - error 40 from storage engine +main.subselect_sj : Modified in 10.0.36 +main.subselect_sj2_mat : Modified in 10.0.36 +main.subselect4 : Modified in 10.0.36 main.tc_heuristic_recover : MDEV-15200 - wrong error on mysqld_stub_cmd main.type_datetime : MDEV-14322 - wrong result -main.type_time_6065 : Modified in 10.0.35 -main.update_innodb : Modified in 10.0.35 -main.view : Modified in 10.0.35 main.xa : MDEV-11769 - lock wait timeout -main.xml : Modified in 10.0.35 #---------------------------------------------------------------- @@ -84,27 +104,16 @@ archive.archive_symlink : MDEV-12170 - unexpected error on rmdir archive.discover : MDEV-10510 - table is marked as crashed archive.mysqlhotcopy_archive : MDEV-10995 - test hangs on debug build, MDEV-14726 - table is marked as crashed +archive-test_sql_discovery.discover : MDEV-16817 - Table marked as crashed + #---------------------------------------------------------------- binlog.binlog_commit_wait : MDEV-10150 - Error: too much time elapsed +binlog.binlog_tmp_table_row : Added in 10.0.36 binlog.binlog_xa_recover : MDEV-8517 - Extra checkpoint #---------------------------------------------------------------- -connect.jdbc : Included file modified in 10.0.35 -connect.jdbc_new : Included file modified in 10.0.35 -connect.jdbc_oracle : Included file modified in 10.0.35 -connect.jdbc_postgresql : Modified in 10.0.35 -connect.json_java_2 : Included file modified in 10.0.35 -connect.json_java_3 : Included file modified in 10.0.35 -connect.json_mongo_c : Included file modified in 10.0.35 -connect.json_udf : Modified in 10.0.35 -connect.mongo_c : Included file modified in 10.0.35 -connect.mongo_java_2 : Included file modified in 10.0.35 -connect.mongo_java_3 : Included file modified in 10.0.35 -connect.mongo_test : Modified in 10.0.35 -connect.tbl_thread : Modified in 10.0.35 -connect.vcol : Added in 10.0.35 connect.zip : MDEV-13884 - wrong result #---------------------------------------------------------------- @@ -113,14 +122,16 @@ engines/rr_trx.* : MDEV-10998 - tests not maintained #---------------------------------------------------------------- -federated.federatedx : MDEV-10617 - Wrong checksum, timeouts +federated.assisted_discovery : Include file modified in 10.0.36 +federated.federatedx : MDEV-10617 - Wrong checksum, timeouts; include file modified in 10.0.36 federated.federated_bug_35333 : MDEV-13410 - Wrong result federated.federated_innodb : MDEV-10617, MDEV-10417 - Wrong checksum, timeouts, fails on Mips -federated.federated_partition : MDEV-10417 - Fails on Mips -federated.federated_transactions : MDEV-10617, MDEV-10417 - Wrong checksum, timeouts, fails on Mips +federated.federated_partition : MDEV-10417 - Fails on Mips; include file modified in 10.0.36 +federated.federated_transactions : MDEV-10617, MDEV-10417 - Wrong checksum, timeouts, fails on Mips; include file modified in 10.0.36 #---------------------------------------------------------------- +funcs_1.is_engines_federated : Include file modified in 10.0.36 funcs_1.memory_views : MDEV-11773 - timeout funcs_1.processlist_val_ps : MDEV-12175 - Wrong result funcs_1.processlist_val_no_prot : MDEV-11223 - Wrong result @@ -129,34 +140,40 @@ funcs_2/charset.* : MDEV-10999 - test not maintained #---------------------------------------------------------------- -innodb.binlog_consistent : MDEV-10618 - Server fails to start -innodb.group_commit_crash : MDEV-11770 - checksum mismatch -innodb.group_commit_crash_no_optimize_thread : MDEV-11770 - checksum mismatch -innodb.innodb-alter-nullable : Modified in 10.0.35 -innodb.innodb-alter-table : MDEV-10619 - Testcase timeout -innodb.innodb_bug11754376 : Modified in 10.0.35 -innodb.innodb_bug27216817 : Added in 10.0.35 -innodb.innodb_bug30423 : MDEV-7311 - Wrong number of rows in the plan -innodb.innodb_bug48024 : MDEV-14352 - Assertion failure -innodb.innodb_bug56947 : Modified in 10.0.35 -innodb.innodb_corrupt_bit : Modified in 10.0.35 -innodb.innodb_monitor : MDEV-10939 - Testcase timeout -innodb.innodb-replace-debug : Modified in 10.0.35 -innodb.log_file_size : MDEV-15668 - Not found pattern; modified in 10.0.35 -innodb.mvcc : Added in 10.0.35 -innodb.read_only_recover_committed : Added in 10.0.35 -innodb.recovery_shutdown : MDEV-15671 - Warning: database page corruption; modified in 10.0.35 -innodb.xa_recovery : MDEV-15279 - mysqld got exception - -innodb_fts.innobase_drop_fts_index_table : Modified in 10.0.35 -innodb_fts.innodb-fts-fic : MDEV-14154 - Assertion failure -innodb_fts.innodb_fts_misc_debug : MDEV-14156 - Unexpected warning; modified in 10.0.35 -innodb_fts.innodb_fts_result_cache_limit : Modified in 10.0.35 +handler.ps : Added in 10.0.36 #---------------------------------------------------------------- -maria.dynamic : Added in 10.0.35 -maria.maria : MDEV-14430 - Wrong result +heap.heap_auto_increment : Modified in 10.0.36 + +#---------------------------------------------------------------- + +innodb.alter_partitioned_xa : Added in 10.0.36 +innodb.binlog_consistent : MDEV-10618 - Server fails to start +innodb.group_commit_crash : MDEV-11770 - checksum mismatch +innodb.group_commit_crash_no_optimize_thread : MDEV-11770 - checksum mismatch +innodb.innodb-alter : Modified in 10.0.36 +innodb.innodb-alter-table : MDEV-10619 - Testcase timeout +innodb.innodb_bug30423 : MDEV-7311 - Wrong number of rows in the plan +innodb.innodb_bug48024 : MDEV-14352 - Assertion failure +innodb.innodb_bug54044 : Modified in 10.0.36 +innodb.innodb-mdev7046 : Modified in 10.0.36 +innodb.innodb_monitor : MDEV-10939 - Testcase timeout +innodb.log_file_size : MDEV-15668 - Not found pattern +innodb.recovery_shutdown : MDEV-15671 - Warning: database page corruption +innodb.rename_table : Added in 10.0.36 +innodb.table_definition_cache_debug : MDEV-14206 - Unexpected warning +innodb.xa_recovery : MDEV-15279 - mysqld got exception + +innodb_fts.basic : Added in 10.0.36 +innodb_fts.innodb-fts-fic : MDEV-14154 - Assertion failure +innodb_fts.innodb_fts_misc_debug : MDEV-14156 - Unexpected warning + +#---------------------------------------------------------------- + +maria.alter : Modified in 10.0.36 +maria.lock : Modified in 10.0.36 +maria.maria : MDEV-14430 - Wrong result; modified in 10.0.36 #---------------------------------------------------------------- @@ -178,12 +195,11 @@ multi_source.status_vars : MDEV-4632 - failed while waiting for Slave_received_h #---------------------------------------------------------------- -parts.partition_alter_innodb : Include file modified in 10.0.35 -parts.partition_alter_maria : Modified in 10.0.35 -parts.partition_alter_myisam : Include file modified in 10.0.35 -parts.partition_auto_increment_maria : MDEV-14430 - wrong result -parts.partition_debug_innodb : MDEV-15095 - table does not exist -parts.partition_exch_qa_10 : MDEV-11765 - wrong result +parts.alter_data_directory_innodb : Added in 10.0.36 +parts.partition_auto_increment_archive : MDEV-16491 - Table marked as crashed +parts.partition_auto_increment_maria : MDEV-14430 - wrong result +parts.partition_exch_qa_10 : MDEV-11765 - wrong result +parts.truncate_locked : Added in 10.0.36 #---------------------------------------------------------------- @@ -198,7 +214,8 @@ perfschema_stress.* : MDEV-10996 - tests not maintained #---------------------------------------------------------------- plugins.feedback_plugin_send : MDEV-7932 - ssl failed for url, MDEV-11118 - wrong result -plugins.server_audit : MDEV-9562 - crashes on sol10-sparc; modified in 10.0.35 +plugins.processlist : MDEV-16818 - Syntax error; added in 10.0.36 +plugins.server_audit : MDEV-9562 - crashes on sol10-sparc; modified in 10.0.36 plugins.thread_pool_server_audit : MDEV-9562 - crashes on sol10-sparc, MDEV-14295 - wrong result #---------------------------------------------------------------- @@ -208,6 +225,7 @@ roles.create_and_grant_role : MDEV-11772 - wrong result #---------------------------------------------------------------- rpl.last_insert_id : MDEV-10625 - warnings in error log +rpl.rename : Added in 10.0.36 rpl.rpl_auto_increment : MDEV-10417 - Fails on Mips rpl.rpl_auto_increment_bug45679 : MDEV-10417 - Fails on Mips rpl.rpl_auto_increment_update_failure : MDEV-10625 - warnings in error log @@ -219,14 +237,17 @@ rpl.rpl_gtid_until : MDEV-10625 - warnings in error log rpl.rpl_innodb_bug30888 : MDEV-10417 - Fails on Mips rpl.rpl_insert : MDEV-9329 - Fails on Ubuntu/s390x rpl.rpl_insert_delayed : MDEV-9329 - Fails on Ubuntu/s390x +rpl.rpl_insert_id_pk : MDEV-16567 - Assertion failure rpl.rpl_invoked_features : MDEV-10417 - Fails on Mips -rpl.rpl_mdev6020 : MDEV-10630, MDEV-10417 - Timeouts, fails on Mips +rpl.rpl_mdev6020 : MDEV-10417 - Timeouts, fails on Mips +rpl.rpl_mixed_implicit_commit_binlog : Included file modified in 10.0.36 rpl.rpl_parallel : MDEV-10653 - Timeouts rpl.rpl_parallel_mdev6589 : MDEV-12979 - Assertion failure rpl.rpl_parallel_multilevel2 : MDEV-14723 - Timeout rpl.rpl_parallel_temptable : MDEV-10356 - Crash in close_thread_tables rpl.rpl_partition_innodb : MDEV-10417 - Fails on Mips rpl.rpl_row_basic_11bugs : MDEV-12171 - Server failed to start +rpl.rpl_row_implicit_commit_binlog : Included file modified in 10.0.36 rpl.rpl_row_index_choice : MDEV-13409 - Server crash rpl.rpl_row_sp001 : MDEV-9329 - Fails on Ubuntu/s390x rpl.rpl_semi_sync : MDEV-11220 - Wrong result @@ -234,6 +255,7 @@ rpl.rpl_semi_sync_uninstall_plugin : MDEV-7140 - Wrong plugin status rpl.rpl_show_slave_hosts : MDEV-12171 - Server failed to start rpl.rpl_skip_replication : MDEV-9268 - Fails with timeout in sync_slave_with_master on Alpha rpl.rpl_slave_grp_exec : MDEV-10514 - Unexpected deadlock +rpl.rpl_stm_implicit_commit_binlog : Included file modified in 10.0.36 rpl.rpl_sync : MDEV-10633 - Database page corruption rpl.rpl_temporary_error2 : MDEV-10634 - Wrong number of retries @@ -247,7 +269,7 @@ spider/bg.direct_aggregate : MDEV-7098 - Trying to unlock mutex that wasn't spider/bg.direct_aggregate_part : MDEV-7098 - Trying to unlock mutex that wasn't locked spider/bg.spider3_fixes : MDEV-7098 - Trying to unlock mutex that wasn't locked spider/bg.spider_fixes_part : MDEV-7098 - Trying to unlock mutex that wasn't locked -spider/bg.ha : MDEV-7914 (fixed in 10.3), MDEV-9329 - Crash, failures on s390x +spider/bg.ha : MDEV-7914 (fixed in 10.1), MDEV-9329 - Crash, failures on s390x spider/bg.ha_part : MDEV-9329 - Fails on Ubuntu/s390x spider/bg.spider_fixes : MDEV-7098, MDEV-9329 - Mutex problem, failures on s390x spider/bg.vp_fixes : MDEV-9329 - Fails on Ubuntu/s390x @@ -267,7 +289,6 @@ stress.ddl_innodb : MDEV-10635 - Testcase timeout #---------------------------------------------------------------- sys_vars.autocommit_func2 : MDEV-9329 - Fails on Ubuntu/s390x -sys_vars.max_prepared_stmt_count_basic : Modified in 10.0.35 sys_vars.thread_cache_size_func : MDEV-11775 - wrong result #---------------------------------------------------------------- @@ -310,5 +331,6 @@ unit.my_atomic : MDEV-15670 - Signal 11 thrown vcol.not_supported : MDEV-10639 - Testcase timeout vcol.vcol_keys_innodb : MDEV-10639 - Testcase timeout +vcol.vcol_misc : MDEV-16651 - Wrong error message; modified in 10.0.36 #---------------------------------------------------------------- From d567f1611e27a17427380e9aae67939792f68ad1 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 24 Jul 2018 20:00:28 -0700 Subject: [PATCH 54/71] MDEV-16820 Lost 'Impossible where' from query with inexpensive subquery This patch fixes another problem introduced by the patch for mdev-4817. The latter changed Item_cond::fix_fields() in such a way that it could call the virtual method is_expensive(). With the first its call the method saves the result in Item::is_expensive_cache. For all next calls the method returns the result from this cache. So if the item once was determined as expensive the method always returns true. For subqueries it's not good, because non-optimized subqueries always is considered as expensive. It means that the cache should be invalidated after the call of optimize_constant_subqueries(). --- mysql-test/r/subselect.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_mat.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_opts.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_scache.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_semijoin.result | 16 ++++++++++++++++ mysql-test/t/subselect.test | 15 +++++++++++++++ sql/item.h | 5 +++++ sql/sql_select.cc | 7 +++++++ 8 files changed, 107 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index e2f2b6521c8..cdedc02f825 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -7171,4 +7171,20 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 25ef4a76962..a7291297e7c 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -7168,6 +7168,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests set optimizer_switch=default; select @@optimizer_switch like '%materialization=on%'; diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 074874fbd5b..c41fa1be47b 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -7166,5 +7166,21 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests set @optimizer_switch_for_subselect_test=null; diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index de49585b562..1c181357050 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -7177,6 +7177,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests set optimizer_switch=default; select @@optimizer_switch like '%subquery_cache=on%'; diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 46a46c91ddc..89c671252ff 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -7166,6 +7166,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests set @optimizer_switch_for_subselect_test=null; set @join_cache_level_for_subselect_test=NULL; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index e6233e9de78..4e35032a789 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -6060,4 +6060,19 @@ and t1.a in (select `test`.`t3`.`c` from `test`.`t3`); SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +--echo # +--echo # MDEV-16820: impossible where with inexpensive subquery +--echo # + +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); + +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); + +explain select * from t1 where (select max(b) from t2) = 10; +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; + +drop table t1,t2; + --echo End of 5.5 tests diff --git a/sql/item.h b/sql/item.h index d756cf8301b..1bded7377ee 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1234,6 +1234,11 @@ public: { return FALSE; } + bool cleanup_is_expensive_cache_processor(uchar *arg) + { + is_expensive_cache= (int8)(-1); + return 0; + } /* To call bool function for all arguments */ struct bool_func_call_args diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6a64a0e9952..5228dd4f439 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1098,6 +1098,13 @@ JOIN::optimize() if (optimize_constant_subqueries()) DBUG_RETURN(1); + if (conds && conds->has_subquery()) + (void) conds->walk(&Item::cleanup_is_expensive_cache_processor, + 0, (uchar*)0); + if (having && having->has_subquery()) + (void) having->walk(&Item::cleanup_is_expensive_cache_processor, + 0, (uchar*)0); + if (setup_jtbm_semi_joins(this, join_list, &conds)) DBUG_RETURN(1); From 57cde8ccd19675dc98e3cbacf0ef5c72cb188e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 25 Jul 2018 08:21:25 +0300 Subject: [PATCH 55/71] MDEV-15822: WSREP: BF lock wait long for trx In Galera BF (brute force) transactions may not wait for lock requests and normally BF-transaction would select transaction holding conflicting locks as a victim for rollback. However, background statistic calculation transaction is InnoDB internal transaction and it has no thd i.e. it can't be selected as a victim. If background statistics calculation transaction holds conflicting locks to statistics tables it will cause BF lock wait long error message. Correct way to handle background statistics calculation is to acquire thd for transaction but that change is too big for GA-releases and there are other reported problems on background statistics calculation. This fix avoids adding a table to background statistics calculation if --- .../r/galera_bf_background_statistics.result | 95 +++++++++++++++++++ .../t/galera_bf_background_statistics.opt | 1 + .../t/galera_bf_background_statistics.test | 49 ++++++++++ storage/innobase/row/row0mysql.cc | 25 ++++- 4 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 mysql-test/suite/galera/r/galera_bf_background_statistics.result create mode 100644 mysql-test/suite/galera/t/galera_bf_background_statistics.opt create mode 100644 mysql-test/suite/galera/t/galera_bf_background_statistics.test diff --git a/mysql-test/suite/galera/r/galera_bf_background_statistics.result b/mysql-test/suite/galera/r/galera_bf_background_statistics.result new file mode 100644 index 00000000000..dc367b065f6 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_bf_background_statistics.result @@ -0,0 +1,95 @@ +SELECT @@innodb_stats_persistent; +@@innodb_stats_persistent +1 +CREATE TABLE t1 (f1 INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, f2 INTEGER DEFAULT NULL) ENGINE=InnoDB; +INSERT INTO t1(f1) values (NULL); +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +SELECT count(1) from t1; +count(1) +16384 +SET AUTOCOMMIT=OFF; +INSERT INTO t1 VALUES (9999999,NULL); +SELECT SLEEP(1000);; +ALTER TABLE t1 CHANGE f2 f2 INTEGER NOT NULL DEFAULT 1; +Warnings: +Warning 1265 Data truncated for column 'f2' at row 1 +Warning 1265 Data truncated for column 'f2' at row 2 +Warning 1265 Data truncated for column 'f2' at row 3 +Warning 1265 Data truncated for column 'f2' at row 4 +Warning 1265 Data truncated for column 'f2' at row 5 +Warning 1265 Data truncated for column 'f2' at row 6 +Warning 1265 Data truncated for column 'f2' at row 7 +Warning 1265 Data truncated for column 'f2' at row 8 +Warning 1265 Data truncated for column 'f2' at row 9 +Warning 1265 Data truncated for column 'f2' at row 10 +Warning 1265 Data truncated for column 'f2' at row 11 +Warning 1265 Data truncated for column 'f2' at row 12 +Warning 1265 Data truncated for column 'f2' at row 13 +Warning 1265 Data truncated for column 'f2' at row 14 +Warning 1265 Data truncated for column 'f2' at row 15 +Warning 1265 Data truncated for column 'f2' at row 16 +Warning 1265 Data truncated for column 'f2' at row 17 +Warning 1265 Data truncated for column 'f2' at row 18 +Warning 1265 Data truncated for column 'f2' at row 19 +Warning 1265 Data truncated for column 'f2' at row 20 +Warning 1265 Data truncated for column 'f2' at row 21 +Warning 1265 Data truncated for column 'f2' at row 22 +Warning 1265 Data truncated for column 'f2' at row 23 +Warning 1265 Data truncated for column 'f2' at row 24 +Warning 1265 Data truncated for column 'f2' at row 25 +Warning 1265 Data truncated for column 'f2' at row 26 +Warning 1265 Data truncated for column 'f2' at row 27 +Warning 1265 Data truncated for column 'f2' at row 28 +Warning 1265 Data truncated for column 'f2' at row 29 +Warning 1265 Data truncated for column 'f2' at row 30 +Warning 1265 Data truncated for column 'f2' at row 31 +Warning 1265 Data truncated for column 'f2' at row 32 +Warning 1265 Data truncated for column 'f2' at row 33 +Warning 1265 Data truncated for column 'f2' at row 34 +Warning 1265 Data truncated for column 'f2' at row 35 +Warning 1265 Data truncated for column 'f2' at row 36 +Warning 1265 Data truncated for column 'f2' at row 37 +Warning 1265 Data truncated for column 'f2' at row 38 +Warning 1265 Data truncated for column 'f2' at row 39 +Warning 1265 Data truncated for column 'f2' at row 40 +Warning 1265 Data truncated for column 'f2' at row 41 +Warning 1265 Data truncated for column 'f2' at row 42 +Warning 1265 Data truncated for column 'f2' at row 43 +Warning 1265 Data truncated for column 'f2' at row 44 +Warning 1265 Data truncated for column 'f2' at row 45 +Warning 1265 Data truncated for column 'f2' at row 46 +Warning 1265 Data truncated for column 'f2' at row 47 +Warning 1265 Data truncated for column 'f2' at row 48 +Warning 1265 Data truncated for column 'f2' at row 49 +Warning 1265 Data truncated for column 'f2' at row 50 +Warning 1265 Data truncated for column 'f2' at row 51 +Warning 1265 Data truncated for column 'f2' at row 52 +Warning 1265 Data truncated for column 'f2' at row 53 +Warning 1265 Data truncated for column 'f2' at row 54 +Warning 1265 Data truncated for column 'f2' at row 55 +Warning 1265 Data truncated for column 'f2' at row 56 +Warning 1265 Data truncated for column 'f2' at row 57 +Warning 1265 Data truncated for column 'f2' at row 58 +Warning 1265 Data truncated for column 'f2' at row 59 +Warning 1265 Data truncated for column 'f2' at row 60 +Warning 1265 Data truncated for column 'f2' at row 61 +Warning 1265 Data truncated for column 'f2' at row 62 +Warning 1265 Data truncated for column 'f2' at row 63 +Warning 1265 Data truncated for column 'f2' at row 64 +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +wsrep_local_aborts_increment +1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_bf_background_statistics.opt b/mysql-test/suite/galera/t/galera_bf_background_statistics.opt new file mode 100644 index 00000000000..f9b1414a974 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_background_statistics.opt @@ -0,0 +1 @@ +--innodb_stats_persistent=ON diff --git a/mysql-test/suite/galera/t/galera_bf_background_statistics.test b/mysql-test/suite/galera/t/galera_bf_background_statistics.test new file mode 100644 index 00000000000..1030e8d4154 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_background_statistics.test @@ -0,0 +1,49 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +# +# Test a local transaction being aborted by a slave one while it is running a SLEEP() +# + +SELECT @@innodb_stats_persistent; + +CREATE TABLE t1 (f1 INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, f2 INTEGER DEFAULT NULL) ENGINE=InnoDB; +INSERT INTO t1(f1) values (NULL); +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +INSERT INTO t1(f1) select NULL from t1; +SELECT count(1) from t1; + +--connection node_2 +SET AUTOCOMMIT=OFF; +--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` +INSERT INTO t1 VALUES (9999999,NULL); +--send SELECT SLEEP(1000); + +--connection node_1 +ALTER TABLE t1 CHANGE f2 f2 INTEGER NOT NULL DEFAULT 1; + +--connection node_2 +--error ER_LOCK_DEADLOCK +--reap + +--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` + +# Check that wsrep_local_bf_aborts has been incremented by exactly 1 +--disable_query_log +--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment; +--enable_query_log + +DROP TABLE t1; + diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 6a971a973f5..963d939380c 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -70,6 +70,13 @@ Created 9/17/2000 Heikki Tuuri #include "ha_prototypes.h" #include +#ifdef WITH_WSREP +#include "mysql/service_wsrep.h" +#include "wsrep.h" +#include "log.h" +#include "wsrep_mysqld.h" +#endif + /** Provide optional 4.x backwards compatibility for 5.0 and above */ UNIV_INTERN ibool row_rollback_on_timeout = FALSE; @@ -1093,6 +1100,7 @@ UNIV_INLINE void row_update_statistics_if_needed( /*============================*/ + trx_t* trx, dict_table_t* table) /*!< in: table */ { ib_uint64_t counter; @@ -1114,6 +1122,16 @@ row_update_statistics_if_needed( if (counter > n_rows / 10 /* 10% */ && dict_stats_auto_recalc_is_enabled(table)) { +#ifdef WITH_WSREP + if (wsrep_on(trx->mysql_thd) && + wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + WSREP_DEBUG("Avoiding background statistics" + " calculation for table %s", + table->name); + return; + } +#endif /* WITH_WSREP */ + dict_stats_recalc_pool_add(table); table->stat_modified_counter = 0; } @@ -1537,7 +1555,8 @@ error_exit: ut_memcpy(prebuilt->row_id, node->row_id_buf, DATA_ROW_ID_LEN); } - row_update_statistics_if_needed(table); + row_update_statistics_if_needed(trx, table); + trx->op_info = ""; return(err); @@ -1921,7 +1940,7 @@ run_again: that changes indexed columns, UPDATEs that change only non-indexed columns would not affect statistics. */ if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { - row_update_statistics_if_needed(prebuilt->table); + row_update_statistics_if_needed(trx, prebuilt->table); } else { /* Update the table modification counter even when non-indexed columns change if statistics is initialized. */ @@ -2158,7 +2177,7 @@ run_again: } } - row_update_statistics_if_needed(table); + row_update_statistics_if_needed(trx, table); return(err); } From c631060713a2af2890284feb7aea96c0cf4ba49f Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 24 Jul 2018 23:45:55 -0700 Subject: [PATCH 56/71] MDEV-16820 Lost 'Impossible where' from query with inexpensive subquery This patch fixes another problem introduced by the patch for mdev-4817. The latter changed Item_cond::fix_fields() in such a way that it could call the virtual method is_expensive(). With the first its call the method saves the result in Item::is_expensive_cache. For all next calls the method returns the result from this cache. So if the item once was determined as expensive the method always returns true. For subqueries it's not good, because non-optimized subqueries always is considered as expensive. It means that the cache should be invalidated after the call of optimize_constant_subqueries(). --- mysql-test/r/subselect.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_exists_to_in.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_mat.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_opts.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_scache.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_semijoin.result | 16 ++++++++++++++++ mysql-test/t/subselect.test | 15 +++++++++++++++ sql/item.h | 5 +++++ sql/sql_select.cc | 7 +++++++ 9 files changed, 123 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 79b2810d529..b074fb371a5 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -7211,4 +7211,20 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests diff --git a/mysql-test/r/subselect_no_exists_to_in.result b/mysql-test/r/subselect_no_exists_to_in.result index 7b2054f4a67..d5aa16a2ce9 100644 --- a/mysql-test/r/subselect_no_exists_to_in.result +++ b/mysql-test/r/subselect_no_exists_to_in.result @@ -7211,6 +7211,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests set optimizer_switch=default; select @@optimizer_switch like '%exists_to_in=off%'; diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 51c5263ad8a..aff68bd6729 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -7204,6 +7204,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests set optimizer_switch=default; select @@optimizer_switch like '%materialization=on%'; diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 574af7b4d1f..f1181785a5c 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -7202,5 +7202,21 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests set @optimizer_switch_for_subselect_test=null; diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 03285cf2968..6cefce21c20 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -7217,6 +7217,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests set optimizer_switch=default; select @@optimizer_switch like '%subquery_cache=on%'; diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 6669c27ede7..884374a74b1 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -7202,6 +7202,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests set @optimizer_switch_for_subselect_test=null; set @join_cache_level_for_subselect_test=NULL; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 8c9a4893be2..390d36361b2 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -6096,4 +6096,19 @@ and t1.a in (select `test`.`t3`.`c` from `test`.`t3`); SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +--echo # +--echo # MDEV-16820: impossible where with inexpensive subquery +--echo # + +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); + +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); + +explain select * from t1 where (select max(b) from t2) = 10; +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; + +drop table t1,t2; + --echo End of 5.5 tests diff --git a/sql/item.h b/sql/item.h index b111d74057c..7c95239b242 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1275,6 +1275,11 @@ public: virtual bool exists2in_processor(uchar *opt_arg) { return 0; } virtual bool find_selective_predicates_list_processor(uchar *opt_arg) { return 0; } + bool cleanup_is_expensive_cache_processor(uchar *arg) + { + is_expensive_cache= (int8)(-1); + return 0; + } /* To call bool function for all arguments */ struct bool_func_call_args diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 43b8d2b8636..19a727f696b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1207,6 +1207,13 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S if (optimize_constant_subqueries()) DBUG_RETURN(1); + if (conds && conds->has_subquery()) + (void) conds->walk(&Item::cleanup_is_expensive_cache_processor, + 0, (uchar*)0); + if (having && having->has_subquery()) + (void) having->walk(&Item::cleanup_is_expensive_cache_processor, + 0, (uchar*)0); + if (setup_jtbm_semi_joins(this, join_list, &conds)) DBUG_RETURN(1); From 1fde449f1d4e8ebe12e989754bfdc84b123cf0b2 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 24 Jul 2018 23:45:55 -0700 Subject: [PATCH 57/71] MDEV-16820 Lost 'Impossible where' from query with inexpensive subquery This patch fixes another problem introduced by the patch for mdev-4817. The latter changed Item_cond::fix_fields() in such a way that it could call the virtual method is_expensive(). With the first its call the method saves the result in Item::is_expensive_cache. For all next calls the method returns the result from this cache. So if the item once was determined as expensive the method always returns true. For subqueries it's not good, because non-optimized subqueries always is considered as expensive. It means that the cache should be invalidated after the call of optimize_constant_subqueries(). --- mysql-test/r/subselect.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_exists_to_in.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_mat.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_opts.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_scache.result | 16 ++++++++++++++++ mysql-test/r/subselect_no_semijoin.result | 16 ++++++++++++++++ mysql-test/t/subselect.test | 15 +++++++++++++++ sql/item.h | 5 +++++ sql/sql_select.cc | 7 +++++++ 9 files changed, 123 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 40f936fb3b4..69db0959373 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -7235,6 +7235,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests # End of 10.0 tests # diff --git a/mysql-test/r/subselect_no_exists_to_in.result b/mysql-test/r/subselect_no_exists_to_in.result index a23820820ef..ef3bf7ef692 100644 --- a/mysql-test/r/subselect_no_exists_to_in.result +++ b/mysql-test/r/subselect_no_exists_to_in.result @@ -7235,6 +7235,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests # End of 10.0 tests # diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index baa74307f89..703572e0ef8 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -7228,6 +7228,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests # End of 10.0 tests # diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 039f2fe1a9e..39a098b754b 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -7226,6 +7226,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests # End of 10.0 tests # diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 0ce77bbb376..b9a59bf3952 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -7241,6 +7241,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests # End of 10.0 tests # diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 574e78122f1..f1df85fed6e 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -7226,6 +7226,22 @@ a 5 SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +# +# MDEV-16820: impossible where with inexpensive subquery +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); +explain select * from t1 where (select max(b) from t2) = 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 Select tables optimized away +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; +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 Select tables optimized away +drop table t1,t2; End of 5.5 tests # End of 10.0 tests # diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 717871db61d..a4c4c21610e 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -6098,6 +6098,21 @@ and t1.a in (select `test`.`t3`.`c` from `test`.`t3`); SET @@optimizer_switch= @optimiser_switch_save; DROP TABLE t1, t2, t3; +--echo # +--echo # MDEV-16820: impossible where with inexpensive subquery +--echo # + +create table t1 (a int) engine=myisam; +insert into t1 values (3), (1), (7); + +create table t2 (b int, index idx(b)); +insert into t2 values (2), (5), (3), (2); + +explain select * from t1 where (select max(b) from t2) = 10; +explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3; + +drop table t1,t2; + --echo End of 5.5 tests --echo # End of 10.0 tests diff --git a/sql/item.h b/sql/item.h index 139ce40b25b..dcd773ffc59 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1449,6 +1449,11 @@ public: virtual bool exists2in_processor(uchar *opt_arg) { return 0; } virtual bool find_selective_predicates_list_processor(uchar *opt_arg) { return 0; } + bool cleanup_is_expensive_cache_processor(uchar *arg) + { + is_expensive_cache= (int8)(-1); + return 0; + } /* To call bool function for all arguments */ struct bool_func_call_args diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e3b725ce1f6..460a64e1a7a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1212,6 +1212,13 @@ JOIN::optimize_inner() if (optimize_constant_subqueries()) DBUG_RETURN(1); + if (conds && conds->has_subquery()) + (void) conds->walk(&Item::cleanup_is_expensive_cache_processor, + 0, (uchar*)0); + if (having && having->has_subquery()) + (void) having->walk(&Item::cleanup_is_expensive_cache_processor, + 0, (uchar*)0); + if (setup_jtbm_semi_joins(this, join_list, &conds)) DBUG_RETURN(1); From f9b43c2565284feefe94e4feaa4c02bf25a6f921 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Wed, 25 Jul 2018 14:20:16 +0530 Subject: [PATCH 58/71] MDEV-16751: Server crashes in st_join_table::cleanup or TABLE_LIST::is_with_table_recursive_reference with join_cache_level>2 During muliple equality propagation for a query in which we have an IN subquery, the items in the select list of the subquery may not be part of the multiple equality because there might be another occurence of the same field in the where clause of the subquery. So we keyuse_is_valid_for_access_in_chosen_plan function which expects the items in the select list of the subquery to be same to the ones in the multiple equality (through these multiple equalities we create keyuse array). The solution would be that we expect the same field not the same Item because when we have SEMI JOIN MATERIALIZATION SCAN, we use copy back technique to copies back the materialised table fields to the original fields of the base tables. --- mysql-test/r/subselect_mat.result | 35 ++++++++++++++++++++++++++++ mysql-test/r/subselect_sj_mat.result | 35 ++++++++++++++++++++++++++++ mysql-test/t/subselect_sj_mat.test | 25 ++++++++++++++++++++ sql/opt_subselect.cc | 3 +++ sql/sql_select.cc | 9 +++++-- 5 files changed, 105 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 00448ac4f91..a56d076d528 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -2360,6 +2360,41 @@ ec70316637232000158bbfc8bcbe5d60 ebb4620037332000158bbfc8bcbe5d89 DROP TABLE t1,t2,t3; set optimizer_switch=@save_optimizer_switch; +# +# MDEV-16751: Server crashes in st_join_table::cleanup or +# TABLE_LIST::is_with_table_recursive_reference with join_cache_level>2 +# +set @save_join_cache_level= @@join_cache_level; +set join_cache_level=4; +CREATE TABLE t1 ( id int NOT NULL); +INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19); +CREATE TABLE t2 (i1 int NOT NULL, i2 int NOT NULL) ; +INSERT INTO t2 VALUES (11,11),(12,12),(13,13); +explain +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 3 +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t2.i1 9 Using where; Using join buffer (flat, BNLH join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); +1 +1 +1 +1 +set @@join_cache_level= @save_join_cache_level; +alter table t1 add key(id); +explain +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 3 +1 PRIMARY t1 ref id id 4 test.t2.i1 2 Using index +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); +1 +1 +1 +1 +drop table t1,t2; # End of 5.5 tests set @subselect_mat_test_optimizer_switch_value=null; set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off'; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index cb5012a91c9..fa62259e3d6 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -2400,4 +2400,39 @@ ec70316637232000158bbfc8bcbe5d60 ebb4620037332000158bbfc8bcbe5d89 DROP TABLE t1,t2,t3; set optimizer_switch=@save_optimizer_switch; +# +# MDEV-16751: Server crashes in st_join_table::cleanup or +# TABLE_LIST::is_with_table_recursive_reference with join_cache_level>2 +# +set @save_join_cache_level= @@join_cache_level; +set join_cache_level=4; +CREATE TABLE t1 ( id int NOT NULL); +INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19); +CREATE TABLE t2 (i1 int NOT NULL, i2 int NOT NULL) ; +INSERT INTO t2 VALUES (11,11),(12,12),(13,13); +explain +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 3 +1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t2.i1 9 Using where; Using join buffer (flat, BNLH join) +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); +1 +1 +1 +1 +set @@join_cache_level= @save_join_cache_level; +alter table t1 add key(id); +explain +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 3 +1 PRIMARY t1 ref id id 4 test.t2.i1 2 Using index +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); +1 +1 +1 +1 +drop table t1,t2; # End of 5.5 tests diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index 90f63bea561..f1b64337702 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -2151,4 +2151,29 @@ eval $q; DROP TABLE t1,t2,t3; set optimizer_switch=@save_optimizer_switch; +--echo # +--echo # MDEV-16751: Server crashes in st_join_table::cleanup or +--echo # TABLE_LIST::is_with_table_recursive_reference with join_cache_level>2 +--echo # + +set @save_join_cache_level= @@join_cache_level; +set join_cache_level=4; +CREATE TABLE t1 ( id int NOT NULL); +INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19); + +CREATE TABLE t2 (i1 int NOT NULL, i2 int NOT NULL) ; +INSERT INTO t2 VALUES (11,11),(12,12),(13,13); + +explain +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); + +set @@join_cache_level= @save_join_cache_level; +alter table t1 add key(id); + +explain +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); +SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); + +drop table t1,t2; --echo # End of 5.5 tests diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 14b2aaee591..783e3d4d22f 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -815,6 +815,9 @@ int check_and_do_in_subquery_rewrites(JOIN *join) details) * require that compared columns have exactly the same type. This is a temporary measure to avoid BUG#36752-type problems. + + JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan expects that for Semi Join Materialization + Scan all the items in the select list of the IN Subquery are of the type Item::FIELD_ITEM. */ static diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5228dd4f439..45a1372988b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7445,8 +7445,13 @@ bool JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan(JOIN *join, st_select_lex *sjm_sel= emb_sj_nest->sj_subq_pred->unit->first_select(); for (uint i= 0; i < sjm_sel->item_list.elements; i++) { - if (sjm_sel->ref_pointer_array[i] == keyuse->val) - return true; + DBUG_ASSERT(sjm_sel->ref_pointer_array[i]->type() == Item::FIELD_ITEM); + if (keyuse->val->type() == Item::FIELD_ITEM) + { + Field *field = ((Item_field*)sjm_sel->ref_pointer_array[i])->field; + if (field->eq(((Item_field*)keyuse->val)->field)) + return true; + } } return false; } From 37dee22d27c55c14f0be7005c3e5bdbb09e1fc92 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Wed, 25 Jul 2018 21:17:50 +0530 Subject: [PATCH 59/71] MDEV-15454: Nested SELECT IN returns wrong results In this case we are setting the field Item_func_eq::in_eqaulity_no for the semi-join equalities. This helps us to remove these equalites as the inner tables are not available during parent select execution while the outer tables are not available during materialization phase. We only have it set for the equalites for the fields involved with the IN subquery and reset it for the equalities which do not belong to the IN subquery. For example in case of nested IN subqueries: SELECT t1.a FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2 where t2.b IN (select t3.b from t3 where t3.c=27 )) there are two equalites involving the fields of the IN subquery 1) t2.b = t3.b : the field Item_func_eq::in_eqaulity_no is set when we merge the grandchild select into the child select 2) t1.a = t2.a : the field Item_func_eq::in_eqaulity_no is set when we merge the child select into the parent select But when we perform case 2) we should ensure that we reset the equalities in the child's WHERE clause. --- mysql-test/r/subselect_mat.result | 41 ++++++++++++++++++ mysql-test/r/subselect_sj_mat.result | 41 ++++++++++++++++++ mysql-test/t/subselect_sj_mat.test | 45 ++++++++++++++++++++ sql/opt_subselect.cc | 63 ++++++++++++++++++++++++++++ 4 files changed, 190 insertions(+) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index a56d076d528..7f39f1fb788 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -2395,6 +2395,47 @@ SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); 1 1 drop table t1,t2; +# +# MDEV-15454: Nested SELECT IN returns wrong results +# +CREATE TABLE t1 ( a int NOT NULL PRIMARY KEY); +CREATE TABLE t2 ( a int, b int ); +INSERT INTO t2 VALUES (7878, 96),(3465, 96),(1403, 96),(4189, 96),(8732, 96), (5,96); +CREATE TABLE t3 (c int unsigned NOT NULL, b int unsigned NOT NULL, PRIMARY KEY (c,b)); +INSERT INTO t3 (c, b) VALUES (27, 96); +CREATE PROCEDURE prepare_data() +BEGIN +DECLARE i INT DEFAULT 1; +WHILE i < 1000 DO +INSERT INTO t1 (a) VALUES (i); +INSERT INTO t2 (a,b) VALUES (i,56); +INSERT INTO t3 (c,b) VALUES (i,i); +SET i = i + 1; +END WHILE; +END$$ +CALL prepare_data(); +SELECT t2.a FROM t2 WHERE t2.b IN (SELECT t3.b FROM t3 WHERE t3.c= 27); +a +7878 +3465 +1403 +4189 +8732 +5 +set @save_optimizer_switch= @@optimizer_switch; +SET optimizer_switch='materialization=off'; +SELECT t1.a FROM t1 +WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.b IN (SELECT t3.b FROM t3 WHERE t3.c= 27)) LIMIT 5; +a +5 +SET optimizer_switch='materialization=on'; +SELECT t1.a FROM t1 +WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.b IN (SELECT t3.b FROM t3 WHERE t3.c= 27)) LIMIT 5; +a +5 +drop procedure prepare_data; +set @@optimizer_switch= @save_optimizer_switch; +drop table t1,t2,t3; # End of 5.5 tests set @subselect_mat_test_optimizer_switch_value=null; set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off'; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index fa62259e3d6..44006eadfc6 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -2435,4 +2435,45 @@ SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); 1 1 drop table t1,t2; +# +# MDEV-15454: Nested SELECT IN returns wrong results +# +CREATE TABLE t1 ( a int NOT NULL PRIMARY KEY); +CREATE TABLE t2 ( a int, b int ); +INSERT INTO t2 VALUES (7878, 96),(3465, 96),(1403, 96),(4189, 96),(8732, 96), (5,96); +CREATE TABLE t3 (c int unsigned NOT NULL, b int unsigned NOT NULL, PRIMARY KEY (c,b)); +INSERT INTO t3 (c, b) VALUES (27, 96); +CREATE PROCEDURE prepare_data() +BEGIN +DECLARE i INT DEFAULT 1; +WHILE i < 1000 DO +INSERT INTO t1 (a) VALUES (i); +INSERT INTO t2 (a,b) VALUES (i,56); +INSERT INTO t3 (c,b) VALUES (i,i); +SET i = i + 1; +END WHILE; +END$$ +CALL prepare_data(); +SELECT t2.a FROM t2 WHERE t2.b IN (SELECT t3.b FROM t3 WHERE t3.c= 27); +a +7878 +3465 +1403 +4189 +8732 +5 +set @save_optimizer_switch= @@optimizer_switch; +SET optimizer_switch='materialization=off'; +SELECT t1.a FROM t1 +WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.b IN (SELECT t3.b FROM t3 WHERE t3.c= 27)) LIMIT 5; +a +5 +SET optimizer_switch='materialization=on'; +SELECT t1.a FROM t1 +WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.b IN (SELECT t3.b FROM t3 WHERE t3.c= 27)) LIMIT 5; +a +5 +drop procedure prepare_data; +set @@optimizer_switch= @save_optimizer_switch; +drop table t1,t2,t3; # End of 5.5 tests diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index f1b64337702..794545b53a7 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -2176,4 +2176,49 @@ SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2); drop table t1,t2; + +--echo # +--echo # MDEV-15454: Nested SELECT IN returns wrong results +--echo # + +CREATE TABLE t1 ( a int NOT NULL PRIMARY KEY); + +CREATE TABLE t2 ( a int, b int ); +INSERT INTO t2 VALUES (7878, 96),(3465, 96),(1403, 96),(4189, 96),(8732, 96), (5,96); + +CREATE TABLE t3 (c int unsigned NOT NULL, b int unsigned NOT NULL, PRIMARY KEY (c,b)); +INSERT INTO t3 (c, b) VALUES (27, 96); + +DELIMITER $$; +CREATE PROCEDURE prepare_data() +BEGIN + DECLARE i INT DEFAULT 1; + WHILE i < 1000 DO + INSERT INTO t1 (a) VALUES (i); + INSERT INTO t2 (a,b) VALUES (i,56); + INSERT INTO t3 (c,b) VALUES (i,i); + SET i = i + 1; + END WHILE; +END$$ +DELIMITER ;$$ + +CALL prepare_data(); + +SELECT t2.a FROM t2 WHERE t2.b IN (SELECT t3.b FROM t3 WHERE t3.c= 27); + +set @save_optimizer_switch= @@optimizer_switch; +SET optimizer_switch='materialization=off'; + +SELECT t1.a FROM t1 +WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.b IN (SELECT t3.b FROM t3 WHERE t3.c= 27)) LIMIT 5; + +SET optimizer_switch='materialization=on'; + +SELECT t1.a FROM t1 +WHERE t1.a IN (SELECT t2.a FROM t2 WHERE t2.b IN (SELECT t3.b FROM t3 WHERE t3.c= 27)) LIMIT 5; + +drop procedure prepare_data; +set @@optimizer_switch= @save_optimizer_switch; +drop table t1,t2,t3; + --echo # End of 5.5 tests diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 783e3d4d22f..f472cf16710 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -440,6 +440,7 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs); static bool replace_where_subcondition(JOIN *, Item **, Item *, Item *, bool); static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2, void *arg); +static void reset_equality_number_for_subq_conds(Item * cond); static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred); static bool convert_subq_to_jtbm(JOIN *parent_join, Item_in_subselect *subq_pred, bool *remove); @@ -1456,6 +1457,67 @@ static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2, } +/** + @brief + reset the value of the field in_eqaulity_no for all Item_func_eq + items in the where clause of the subquery. + + Look for in_equality_no description in Item_func_eq class + + DESCRIPTION + Lets have an example: + SELECT t1.a FROM t1 WHERE t1.a IN + (SELECT t2.a FROM t2 where t2.b IN + (select t3.b from t3 where t3.c=27 )) + + So for such a query we have the parent, child and + grandchild select. + + So for the equality t2.b = t3.b we set the value for in_equality_no to + 0 according to its description. Wewe do the same for t1.a = t2.a. + But when we look at the child select (with the grandchild select merged), + the query would be + + SELECT t1.a FROM t1 WHERE t1.a IN + (SELECT t2.a FROM t2 where t2.b = t3.b and t3.c=27) + + and then when the child select is merged into the parent select the query + would look like + + SELECT t1.a FROM t1, semi-join-nest(t2,t3) + WHERE t1.a =t2.a and t2.b = t3.b and t3.c=27 + + Still we would have in_equality_no set for t2.b = t3.b + though it does not take part in the semi-join equality for the parent select, + so we should reset its value to UINT_MAX. + + @param cond WHERE clause of the subquery +*/ + +static void reset_equality_number_for_subq_conds(Item * cond) +{ + if (!cond) + return; + if (cond->type() == Item::COND_ITEM) + { + List_iterator li(*((Item_cond*) cond)->argument_list()); + Item *item; + while ((item=li++)) + { + if (item->type() == Item::FUNC_ITEM && + ((Item_func*)item)->functype()== Item_func::EQ_FUNC) + ((Item_func_eq*)item)->in_equality_no= UINT_MAX; + } + } + else + { + if (cond->type() == Item::FUNC_ITEM && + ((Item_func*)cond)->functype()== Item_func::EQ_FUNC) + ((Item_func_eq*)cond)->in_equality_no= UINT_MAX; + } + return; +} + /* Convert a subquery predicate into a TABLE_LIST semi-join nest @@ -1713,6 +1775,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) */ sj_nest->sj_in_exprs= subq_pred->left_expr->cols(); sj_nest->nested_join->sj_outer_expr_list.empty(); + reset_equality_number_for_subq_conds(sj_nest->sj_on_expr); if (subq_pred->left_expr->cols() == 1) { From bd0b368119b48ffbb1e5ab3cd2887270c5c6840e Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Fri, 27 Jul 2018 11:34:34 +0530 Subject: [PATCH 60/71] Fix added along with a test for a case missed in the patch for MDEV-16751 --- mysql-test/r/subselect_mat.result | 17 +++++++++++++++++ mysql-test/r/subselect_sj_mat.result | 17 +++++++++++++++++ mysql-test/t/subselect_sj_mat.test | 9 +++++++++ sql/sql_select.cc | 8 ++++---- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 7f39f1fb788..eca3b760b65 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -2436,6 +2436,23 @@ a drop procedure prepare_data; set @@optimizer_switch= @save_optimizer_switch; drop table t1,t2,t3; +CREATE TABLE t1 ( id int NOT NULL, key(id)); +INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19); +CREATE TABLE t2 (i1 int NOT NULL, i2 int NOT NULL); +INSERT INTO t2 VALUES (11,11),(12,12),(13,13); +CREATE VIEW v1 AS SELECT t2.i1 FROM t2 where t2.i1 = t2.i2; +explain SELECT 1 FROM t1 where t1.id IN (SELECT v1.i1 from v1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 3 +1 PRIMARY t1 ref id id 4 test.t2.i1 2 Using index +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where +SELECT 1 FROM t1 where t1.id IN (SELECT v1.i1 from v1); +1 +1 +1 +1 +drop table t1,t2; +drop view v1; # End of 5.5 tests set @subselect_mat_test_optimizer_switch_value=null; set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off'; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 44006eadfc6..180c182a51a 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -2476,4 +2476,21 @@ a drop procedure prepare_data; set @@optimizer_switch= @save_optimizer_switch; drop table t1,t2,t3; +CREATE TABLE t1 ( id int NOT NULL, key(id)); +INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19); +CREATE TABLE t2 (i1 int NOT NULL, i2 int NOT NULL); +INSERT INTO t2 VALUES (11,11),(12,12),(13,13); +CREATE VIEW v1 AS SELECT t2.i1 FROM t2 where t2.i1 = t2.i2; +explain SELECT 1 FROM t1 where t1.id IN (SELECT v1.i1 from v1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 3 +1 PRIMARY t1 ref id id 4 test.t2.i1 2 Using index +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where +SELECT 1 FROM t1 where t1.id IN (SELECT v1.i1 from v1); +1 +1 +1 +1 +drop table t1,t2; +drop view v1; # End of 5.5 tests diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index 794545b53a7..c82c1e7acec 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -2221,4 +2221,13 @@ drop procedure prepare_data; set @@optimizer_switch= @save_optimizer_switch; drop table t1,t2,t3; +CREATE TABLE t1 ( id int NOT NULL, key(id)); +INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19); +CREATE TABLE t2 (i1 int NOT NULL, i2 int NOT NULL); +INSERT INTO t2 VALUES (11,11),(12,12),(13,13); +CREATE VIEW v1 AS SELECT t2.i1 FROM t2 where t2.i1 = t2.i2; +explain SELECT 1 FROM t1 where t1.id IN (SELECT v1.i1 from v1); +SELECT 1 FROM t1 where t1.id IN (SELECT v1.i1 from v1); +drop table t1,t2; +drop view v1; --echo # End of 5.5 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 45a1372988b..b2b2bcde80c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7445,11 +7445,11 @@ bool JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan(JOIN *join, st_select_lex *sjm_sel= emb_sj_nest->sj_subq_pred->unit->first_select(); for (uint i= 0; i < sjm_sel->item_list.elements; i++) { - DBUG_ASSERT(sjm_sel->ref_pointer_array[i]->type() == Item::FIELD_ITEM); - if (keyuse->val->type() == Item::FIELD_ITEM) + DBUG_ASSERT(sjm_sel->ref_pointer_array[i]->real_item()->type() == Item::FIELD_ITEM); + if (keyuse->val->real_item()->type() == Item::FIELD_ITEM) { - Field *field = ((Item_field*)sjm_sel->ref_pointer_array[i])->field; - if (field->eq(((Item_field*)keyuse->val)->field)) + Field *field = ((Item_field*)sjm_sel->ref_pointer_array[i]->real_item())->field; + if (field->eq(((Item_field*)keyuse->val->real_item())->field)) return true; } } From 14306bcbec0b6a999985008f3d33602c08058006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 27 Jul 2018 10:05:26 +0300 Subject: [PATCH 61/71] MDEV-16831: Galera test failure on galera_sst_mysqldump_with_key Test case was not written correctly. --- .../r/galera_sst_mysqldump_with_key.result | 95 ++++++++++++++++++- .../t/galera_sst_mysqldump_with_key.test | 7 +- 2 files changed, 97 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_sst_mysqldump_with_key.result b/mysql-test/suite/galera/r/galera_sst_mysqldump_with_key.result index 074481afc2d..bdf3844f2c5 100644 --- a/mysql-test/suite/galera/r/galera_sst_mysqldump_with_key.result +++ b/mysql-test/suite/galera/r/galera_sst_mysqldump_with_key.result @@ -9,7 +9,7 @@ CREATE USER sslsst; GRANT ALL PRIVILEGES ON *.* TO sslsst; GRANT USAGE ON *.* TO sslsst REQUIRE SSL; SET GLOBAL wsrep_sst_auth = 'sslsst:'; -Performing State Transfer on a server that has been temporarily disconnected +Performing State Transfer on a server that has been shut down cleanly and restarted CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -27,8 +27,7 @@ INSERT INTO t1 VALUES ('node2_committed_before'); INSERT INTO t1 VALUES ('node2_committed_before'); INSERT INTO t1 VALUES ('node2_committed_before'); COMMIT; -Unloading wsrep provider ... -SET GLOBAL wsrep_provider = 'none'; +Shutting down server ... SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_committed_during'); @@ -50,7 +49,95 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); -Loading wsrep provider ... +Starting server ... +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +COMMIT; +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +COMMIT; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +COMMIT; +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +ROLLBACK; +SELECT COUNT(*) = 35 FROM t1; +COUNT(*) = 35 +1 +SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; +COUNT(*) = 0 +1 +COMMIT; +SET AUTOCOMMIT=ON; +SELECT COUNT(*) = 35 FROM t1; +COUNT(*) = 35 +1 +SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; +COUNT(*) = 0 +1 +DROP TABLE t1; +COMMIT; +SET AUTOCOMMIT=ON; +Performing State Transfer on a server that has been killed and restarted +CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +COMMIT; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +COMMIT; +Killing server ... +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +COMMIT; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +Performing --wsrep-recover ... +Starting server ... +Using --wsrep-start-position when starting mysqld ... SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node2_committed_after'); diff --git a/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test index 0dbc63b531c..57244cb50c7 100644 --- a/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test +++ b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test @@ -19,7 +19,12 @@ GRANT USAGE ON *.* TO sslsst REQUIRE SSL; SET GLOBAL wsrep_sst_auth = 'sslsst:'; ---source suite/galera/include/galera_st_disconnect_slave.inc +# We set the required mysqldump SST options here so that they are used every time the server is restarted during the test +--let $start_mysqld_params = --wsrep_sst_auth=sst:'sslsst:' --wsrep_sst_method=mysqldump --wsrep-sst-receive-address=127.0.0.1:$NODE_MYPORT_2 --skip-grant-tables + +--source suite/galera/include/galera_st_shutdown_slave.inc +--source suite/galera/include/galera_st_kill_slave.inc +--source suite/galera/include/galera_st_kill_slave_ddl.inc --source include/auto_increment_offset_restore.inc --source suite/galera/include/galera_sst_restore.inc From 340963351c5fb9dbeb03d6c887b18d328073ed79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 30 Jul 2018 10:39:42 +0300 Subject: [PATCH 62/71] Use a more precise argument for memset() --- storage/innobase/buf/buf0buddy.cc | 2 +- storage/xtradb/buf/buf0buddy.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/innobase/buf/buf0buddy.cc b/storage/innobase/buf/buf0buddy.cc index 7a441b4239a..c8c39e0caaf 100644 --- a/storage/innobase/buf/buf0buddy.cc +++ b/storage/innobase/buf/buf0buddy.cc @@ -132,7 +132,7 @@ buf_buddy_stamp_free( buf_buddy_free_t* buf, /*!< in/out: block to stamp */ ulint i) /*!< in: block size */ { - ut_d(memset(buf, static_cast(i), BUF_BUDDY_LOW << i)); + ut_d(memset(&buf->stamp.bytes, int(i), BUF_BUDDY_LOW << i)); buf_buddy_mem_invalid(buf, i); mach_write_to_4(buf->stamp.bytes + BUF_BUDDY_STAMP_OFFSET, BUF_BUDDY_STAMP_FREE); diff --git a/storage/xtradb/buf/buf0buddy.cc b/storage/xtradb/buf/buf0buddy.cc index 1c50e71e687..ee687efc9ec 100644 --- a/storage/xtradb/buf/buf0buddy.cc +++ b/storage/xtradb/buf/buf0buddy.cc @@ -132,7 +132,7 @@ buf_buddy_stamp_free( buf_buddy_free_t* buf, /*!< in/out: block to stamp */ ulint i) /*!< in: block size */ { - ut_d(memset(buf, static_cast(i), BUF_BUDDY_LOW << i)); + ut_d(memset(&buf->stamp.bytes, int(i), BUF_BUDDY_LOW << i)); buf_buddy_mem_invalid(buf, i); mach_write_to_4(buf->stamp.bytes + BUF_BUDDY_STAMP_OFFSET, BUF_BUDDY_STAMP_FREE); From 8bdd125067851a201348ae24cac7f9097d494d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 30 Jul 2018 13:13:43 +0300 Subject: [PATCH 63/71] MDEV-16851 On schema mismatch in IMPORT TABLESPACE, display ROW_FORMAT in clear text This is motivated by Oracle MySQL Bug #27542720 SCHEMA MISMATCH - TABLE FLAGS DON'T MATCH, BUT FLAGS ARE NUMBERS but using a different approach. row_import::match_schema(): In case of a mismatch, display the ROW_FORMAT and optionally KEY_BLOCK_SIZE of the .cfg file. --- .../suite/innodb/r/innodb-wl5522.result | 263 +++++++++++++++++- mysql-test/suite/innodb/t/innodb-wl5522.test | 258 ++++++++++++++++- storage/innobase/row/row0import.cc | 59 +++- storage/xtradb/row/row0import.cc | 52 +++- 4 files changed, 608 insertions(+), 24 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-wl5522.result b/mysql-test/suite/innodb/r/innodb-wl5522.result index 2116dfbf3fa..fb80580f797 100644 --- a/mysql-test/suite/innodb/r/innodb-wl5522.result +++ b/mysql-test/suite/innodb/r/innodb-wl5522.result @@ -1,4 +1,3 @@ -DROP TABLE IF EXISTS t1; SET GLOBAL innodb_file_per_table = 1; SELECT @@innodb_file_per_table; @@innodb_file_per_table @@ -580,7 +579,7 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x1 and the meta-data file has 0x0) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x1 and the meta-data file has 0x0; .cfg file uses ROW_FORMAT=REDUNDANT) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -592,7 +591,19 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x21 and the meta-data file has 0x0) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x21 and the meta-data file has 0x0; .cfg file uses ROW_FORMAT=REDUNDANT) +unlink: t1.ibd +unlink: t1.cfg +DROP TABLE t1; +CREATE TABLE t1( +c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +ALTER TABLE t1 DISCARD TABLESPACE; +SELECT * FROM t1; +ERROR HY000: Tablespace has been discarded for table 't1' +restore: t1 .ibd and .cfg files +ALTER TABLE t1 IMPORT TABLESPACE; +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x29 and the meta-data file has 0x0; .cfg file uses ROW_FORMAT=REDUNDANT) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -766,7 +777,7 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x0 and the meta-data file has 0x1) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x0 and the meta-data file has 0x1; .cfg file uses ROW_FORMAT=COMPACT) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -778,7 +789,19 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x21 and the meta-data file has 0x1) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x21 and the meta-data file has 0x1; .cfg file uses ROW_FORMAT=COMPACT) +unlink: t1.ibd +unlink: t1.cfg +DROP TABLE t1; +CREATE TABLE t1( +c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +ALTER TABLE t1 DISCARD TABLESPACE; +SELECT * FROM t1; +ERROR HY000: Tablespace has been discarded for table 't1' +restore: t1 .ibd and .cfg files +ALTER TABLE t1 IMPORT TABLESPACE; +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x29 and the meta-data file has 0x1; .cfg file uses ROW_FORMAT=COMPACT) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -955,7 +978,7 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x1 and the meta-data file has 0x21) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x1 and the meta-data file has 0x21; .cfg file uses ROW_FORMAT=DYNAMIC) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -967,7 +990,19 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x0 and the meta-data file has 0x21) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x0 and the meta-data file has 0x21; .cfg file uses ROW_FORMAT=DYNAMIC) +unlink: t1.ibd +unlink: t1.cfg +DROP TABLE t1; +CREATE TABLE t1( +c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +ALTER TABLE t1 DISCARD TABLESPACE; +SELECT * FROM t1; +ERROR HY000: Tablespace has been discarded for table 't1' +restore: t1 .ibd and .cfg files +ALTER TABLE t1 IMPORT TABLESPACE; +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x29 and the meta-data file has 0x21; .cfg file uses ROW_FORMAT=DYNAMIC) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -1026,6 +1061,220 @@ c1 c2 42 1 43 1 DROP TABLE t1; +CREATE TABLE t1( +c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +INSERT INTO t1(c2) VALUES(1); +INSERT INTO t1(c2) SELECT c2 FROM t1; +INSERT INTO t1(c2) SELECT c2 FROM t1; +INSERT INTO t1(c2) SELECT c2 FROM t1; +INSERT INTO t1(c2) SELECT c2 FROM t1; +INSERT INTO t1(c2) SELECT c2 FROM t1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + `c2` int(11) DEFAULT NULL, + PRIMARY KEY (`c1`), + KEY `idx` (`c2`) +) ENGINE=InnoDB AUTO_INCREMENT=59 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED +SELECT * FROM t1; +c1 c2 +1 1 +2 1 +3 1 +4 1 +6 1 +7 1 +8 1 +9 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +28 1 +29 1 +30 1 +31 1 +32 1 +33 1 +34 1 +35 1 +36 1 +37 1 +38 1 +39 1 +40 1 +41 1 +42 1 +43 1 +FLUSH TABLES t1 FOR EXPORT; +backup: t1 +UNLOCK TABLES; +DROP TABLE t1; +CREATE TABLE t1( +c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +ALTER TABLE t1 DISCARD TABLESPACE; +SELECT * FROM t1; +ERROR HY000: Tablespace has been discarded for table 't1' +restore: t1 .ibd and .cfg files +ALTER TABLE t1 IMPORT TABLESPACE; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +unlink: t1.cfg +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + `c2` int(11) DEFAULT NULL, + PRIMARY KEY (`c1`), + KEY `idx` (`c2`) +) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED +SELECT * FROM t1; +c1 c2 +1 1 +2 1 +3 1 +4 1 +6 1 +7 1 +8 1 +9 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +28 1 +29 1 +30 1 +31 1 +32 1 +33 1 +34 1 +35 1 +36 1 +37 1 +38 1 +39 1 +40 1 +41 1 +42 1 +43 1 +DROP TABLE t1; +CREATE TABLE t1( +c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=REDUNDANT; +ALTER TABLE t1 DISCARD TABLESPACE; +SELECT * FROM t1; +ERROR HY000: Tablespace has been discarded for table 't1' +restore: t1 .ibd and .cfg files +ALTER TABLE t1 IMPORT TABLESPACE; +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x0 and the meta-data file has 0x29; .cfg file uses ROW_FORMAT=COMPRESSED) +unlink: t1.ibd +unlink: t1.cfg +DROP TABLE t1; +CREATE TABLE t1( +c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPACT; +ALTER TABLE t1 DISCARD TABLESPACE; +SELECT * FROM t1; +ERROR HY000: Tablespace has been discarded for table 't1' +restore: t1 .ibd and .cfg files +ALTER TABLE t1 IMPORT TABLESPACE; +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x1 and the meta-data file has 0x29; .cfg file uses ROW_FORMAT=COMPRESSED) +unlink: t1.ibd +unlink: t1.cfg +DROP TABLE t1; +CREATE TABLE t1( +c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +ALTER TABLE t1 DISCARD TABLESPACE; +SELECT * FROM t1; +ERROR HY000: Tablespace has been discarded for table 't1' +restore: t1 .ibd and .cfg files +ALTER TABLE t1 IMPORT TABLESPACE; +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x21 and the meta-data file has 0x29; .cfg file uses ROW_FORMAT=COMPRESSED) +unlink: t1.ibd +unlink: t1.cfg +DROP TABLE t1; +CREATE TABLE t1( +c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +c2 INT, INDEX idx(c2)) ENGINE=InnoDB +ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +ALTER TABLE t1 DISCARD TABLESPACE; +SELECT * FROM t1; +ERROR HY000: Tablespace has been discarded for table 't1' +restore: t1 .ibd and .cfg files +ALTER TABLE t1 IMPORT TABLESPACE; +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x23 and the meta-data file has 0x29; .cfg file uses ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8) +unlink: t1.ibd +unlink: t1.cfg +DROP TABLE t1; +CREATE TABLE t1( +c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +ALTER TABLE t1 DISCARD TABLESPACE; +SELECT * FROM t1; +ERROR HY000: Tablespace has been discarded for table 't1' +restore: t1 .ibd and .cfg files +ALTER TABLE t1 IMPORT TABLESPACE; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +unlink: t1.cfg +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + `c2` int(11) DEFAULT NULL, + PRIMARY KEY (`c1`), + KEY `idx` (`c2`) +) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED +SELECT * FROM t1; +c1 c2 +1 1 +2 1 +3 1 +4 1 +6 1 +7 1 +8 1 +9 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +28 1 +29 1 +30 1 +31 1 +32 1 +33 1 +34 1 +35 1 +36 1 +37 1 +38 1 +39 1 +40 1 +41 1 +42 1 +43 1 +DROP TABLE t1; call mtr.add_suppression("Got error -1 when reading table '.*'"); call mtr.add_suppression("InnoDB: Error: tablespace id and flags in file '.*'.*"); call mtr.add_suppression("InnoDB: The table .* doesn't have a corresponding tablespace, it was discarded"); diff --git a/mysql-test/suite/innodb/t/innodb-wl5522.test b/mysql-test/suite/innodb/t/innodb-wl5522.test index c9e7748cb47..d50032c3be7 100644 --- a/mysql-test/suite/innodb/t/innodb-wl5522.test +++ b/mysql-test/suite/innodb/t/innodb-wl5522.test @@ -3,10 +3,6 @@ -- source include/have_innodb.inc ---disable_warnings -DROP TABLE IF EXISTS t1; ---enable_warnings - let $innodb_file_per_table = `SELECT @@innodb_file_per_table`; let $innodb_file_format = `SELECT @@innodb_file_format`; @@ -481,7 +477,7 @@ SELECT * FROM t1; DROP TABLE t1; # -# Row format tests [EXPORT REDUNDANT - IMPORT COMPACT & DYNAMIC] +# EXPORT ROW_FORMAT=REDUNDANT # CREATE TABLE t1( c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -583,6 +579,29 @@ EOF DROP TABLE t1; +CREATE TABLE t1( + c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +ALTER TABLE t1 DISCARD TABLESPACE; +--error ER_TABLESPACE_DISCARDED +SELECT * FROM t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_discard_tablespaces("test", "t1"); +ib_restore_tablespaces("test", "t1"); +EOF + +--error ER_TABLE_SCHEMA_MISMATCH +ALTER TABLE t1 IMPORT TABLESPACE; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_unlink_tablespace("test", "t1"); +EOF + +DROP TABLE t1; + # This should be OK. CREATE TABLE t1( c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -611,7 +630,7 @@ SELECT * FROM t1; DROP TABLE t1; # -# Row format tests [EXPORT COMPACT - IMPORT REDUNDANT & DYNAMIC] +# EXPORT ROW_FORMAT=COMPACT # CREATE TABLE t1( c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -713,6 +732,29 @@ EOF DROP TABLE t1; +CREATE TABLE t1( + c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +ALTER TABLE t1 DISCARD TABLESPACE; +--error ER_TABLESPACE_DISCARDED +SELECT * FROM t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_discard_tablespaces("test", "t1"); +ib_restore_tablespaces("test", "t1"); +EOF + +--error ER_TABLE_SCHEMA_MISMATCH +ALTER TABLE t1 IMPORT TABLESPACE; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_unlink_tablespace("test", "t1"); +EOF + +DROP TABLE t1; + # This should be OK. CREATE TABLE t1( c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -742,7 +784,7 @@ SELECT * FROM t1; DROP TABLE t1; # -# Row format tests [EXPORT DYNAMIC- IMPORT REDUNDANT & DYNAMIC] +# EXPORT ROW_FORMAT=DYNAMIC # CREATE TABLE t1( c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -844,6 +886,29 @@ EOF DROP TABLE t1; +CREATE TABLE t1( + c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +ALTER TABLE t1 DISCARD TABLESPACE; +--error ER_TABLESPACE_DISCARDED +SELECT * FROM t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_discard_tablespaces("test", "t1"); +ib_restore_tablespaces("test", "t1"); +EOF + +--error ER_TABLE_SCHEMA_MISMATCH +ALTER TABLE t1 IMPORT TABLESPACE; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_unlink_tablespace("test", "t1"); +EOF + +DROP TABLE t1; + # This should be OK. CREATE TABLE t1( c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -872,6 +937,185 @@ SELECT * FROM t1; DROP TABLE t1; +# +# EXPORT ROW_FORMAT=COMPRESSED +# +CREATE TABLE t1( + c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; + +INSERT INTO t1(c2) VALUES(1); +INSERT INTO t1(c2) SELECT c2 FROM t1; +INSERT INTO t1(c2) SELECT c2 FROM t1; +INSERT INTO t1(c2) SELECT c2 FROM t1; +INSERT INTO t1(c2) SELECT c2 FROM t1; +INSERT INTO t1(c2) SELECT c2 FROM t1; + +SHOW CREATE TABLE t1; +SELECT * FROM t1; + +FLUSH TABLES t1 FOR EXPORT; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_backup_tablespaces("test", "t1"); +EOF + +UNLOCK TABLES; + +DROP TABLE t1; + +CREATE TABLE t1( + c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; + +ALTER TABLE t1 DISCARD TABLESPACE; +--error ER_TABLESPACE_DISCARDED +SELECT * FROM t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_discard_tablespaces("test", "t1"); +ib_restore_tablespaces("test", "t1"); +EOF + +ALTER TABLE t1 IMPORT TABLESPACE; +CHECK TABLE t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_cleanup("test", "t1"); +EOF + +SHOW CREATE TABLE t1; +SELECT * FROM t1; + +DROP TABLE t1; + +CREATE TABLE t1( + c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=REDUNDANT; + +ALTER TABLE t1 DISCARD TABLESPACE; +--error ER_TABLESPACE_DISCARDED +SELECT * FROM t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_discard_tablespaces("test", "t1"); +ib_restore_tablespaces("test", "t1"); +EOF + +--error ER_TABLE_SCHEMA_MISMATCH +ALTER TABLE t1 IMPORT TABLESPACE; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_unlink_tablespace("test", "t1"); +EOF + +DROP TABLE t1; + +CREATE TABLE t1( + c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPACT; + +ALTER TABLE t1 DISCARD TABLESPACE; +--error ER_TABLESPACE_DISCARDED +SELECT * FROM t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_discard_tablespaces("test", "t1"); +ib_restore_tablespaces("test", "t1"); +EOF + +--error ER_TABLE_SCHEMA_MISMATCH +ALTER TABLE t1 IMPORT TABLESPACE; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_unlink_tablespace("test", "t1"); +EOF + +DROP TABLE t1; + +CREATE TABLE t1( + c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +ALTER TABLE t1 DISCARD TABLESPACE; +--error ER_TABLESPACE_DISCARDED +SELECT * FROM t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_discard_tablespaces("test", "t1"); +ib_restore_tablespaces("test", "t1"); +EOF + +--error ER_TABLE_SCHEMA_MISMATCH +ALTER TABLE t1 IMPORT TABLESPACE; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_unlink_tablespace("test", "t1"); +EOF + +DROP TABLE t1; + + +CREATE TABLE t1( + c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + c2 INT, INDEX idx(c2)) ENGINE=InnoDB + ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +ALTER TABLE t1 DISCARD TABLESPACE; +--error ER_TABLESPACE_DISCARDED +SELECT * FROM t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_discard_tablespaces("test", "t1"); +ib_restore_tablespaces("test", "t1"); +EOF + +--error ER_TABLE_SCHEMA_MISMATCH +ALTER TABLE t1 IMPORT TABLESPACE; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_unlink_tablespace("test", "t1"); +EOF + +DROP TABLE t1; + +# This should be OK. +CREATE TABLE t1( + c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + c2 INT, INDEX idx(c2)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; + +ALTER TABLE t1 DISCARD TABLESPACE; +--error ER_TABLESPACE_DISCARDED +SELECT * FROM t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_discard_tablespaces("test", "t1"); +ib_restore_tablespaces("test", "t1"); +EOF + +ALTER TABLE t1 IMPORT TABLESPACE; +CHECK TABLE t1; + +perl; +do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; +ib_cleanup("test", "t1"); +EOF + +SHOW CREATE TABLE t1; +SELECT * FROM t1; + +DROP TABLE t1; + call mtr.add_suppression("Got error -1 when reading table '.*'"); call mtr.add_suppression("InnoDB: Error: tablespace id and flags in file '.*'.*"); call mtr.add_suppression("InnoDB: The table .* doesn't have a corresponding tablespace, it was discarded"); diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index f93d004d8f9..127f1df8df5 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2012, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2015, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -1333,17 +1333,63 @@ row_import::match_schema( { /* Do some simple checks. */ - if ((m_table->flags ^ m_flags) & ~DICT_TF_MASK_DATA_DIR) { + if (ulint mismatch = (m_table->flags ^ m_flags) + & ~DICT_TF_MASK_DATA_DIR) { + const char* msg; + if (mismatch & DICT_TF_MASK_ZIP_SSIZE) { + if ((m_table->flags & DICT_TF_MASK_ZIP_SSIZE) + && (m_flags & DICT_TF_MASK_ZIP_SSIZE)) { + switch (m_flags & DICT_TF_MASK_ZIP_SSIZE) { + case 0U << DICT_TF_POS_ZIP_SSIZE: + goto uncompressed; + case 1U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=1"; + break; + case 2U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=2"; + break; + case 3U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=4"; + break; + case 4U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=8"; + break; + case 5U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=16"; + break; + default: + msg = "strange KEY_BLOCK_SIZE"; + } + } else if (m_flags & DICT_TF_MASK_ZIP_SSIZE) { + msg = "ROW_FORMAT=COMPRESSED"; + } else { + goto uncompressed; + } + } else { +uncompressed: + msg = (m_flags & DICT_TF_MASK_ATOMIC_BLOBS) + ? "ROW_FORMAT=DYNAMIC" + : (m_flags & DICT_TF_MASK_COMPACT) + ? "ROW_FORMAT=COMPACT" + : "ROW_FORMAT=REDUNDANT"; + } + ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH, "Table flags don't match, server table has 0x%x" - " and the meta-data file has 0x%lx", - m_table->flags, ulong(m_flags)); + " and the meta-data file has 0x%lx;" + " .cfg file uses %s", + m_table->flags, ulong(m_flags), msg); return(DB_ERROR); } else if (m_table->n_cols != m_n_cols) { ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH, - "Number of columns don't match, table has %u" - " columns but the tablespace meta-data file has " + "Number of columns don't match, table has %u " + "columns but the tablespace meta-data file has " ULINTPF " columns", m_table->n_cols, m_n_cols); @@ -1822,7 +1868,6 @@ PageConverter::update_records( while (!m_rec_iter.end()) { rec_t* rec = m_rec_iter.current(); - ibool deleted = rec_get_deleted_flag(rec, comp); /* For the clustered index we have to adjust the BLOB diff --git a/storage/xtradb/row/row0import.cc b/storage/xtradb/row/row0import.cc index 39e450bd7c5..127f1df8df5 100644 --- a/storage/xtradb/row/row0import.cc +++ b/storage/xtradb/row/row0import.cc @@ -1333,11 +1333,57 @@ row_import::match_schema( { /* Do some simple checks. */ - if ((m_table->flags ^ m_flags) & ~DICT_TF_MASK_DATA_DIR) { + if (ulint mismatch = (m_table->flags ^ m_flags) + & ~DICT_TF_MASK_DATA_DIR) { + const char* msg; + if (mismatch & DICT_TF_MASK_ZIP_SSIZE) { + if ((m_table->flags & DICT_TF_MASK_ZIP_SSIZE) + && (m_flags & DICT_TF_MASK_ZIP_SSIZE)) { + switch (m_flags & DICT_TF_MASK_ZIP_SSIZE) { + case 0U << DICT_TF_POS_ZIP_SSIZE: + goto uncompressed; + case 1U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=1"; + break; + case 2U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=2"; + break; + case 3U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=4"; + break; + case 4U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=8"; + break; + case 5U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=16"; + break; + default: + msg = "strange KEY_BLOCK_SIZE"; + } + } else if (m_flags & DICT_TF_MASK_ZIP_SSIZE) { + msg = "ROW_FORMAT=COMPRESSED"; + } else { + goto uncompressed; + } + } else { +uncompressed: + msg = (m_flags & DICT_TF_MASK_ATOMIC_BLOBS) + ? "ROW_FORMAT=DYNAMIC" + : (m_flags & DICT_TF_MASK_COMPACT) + ? "ROW_FORMAT=COMPACT" + : "ROW_FORMAT=REDUNDANT"; + } + ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH, "Table flags don't match, server table has 0x%x" - " and the meta-data file has 0x%lx", - m_table->flags, ulong(m_flags)); + " and the meta-data file has 0x%lx;" + " .cfg file uses %s", + m_table->flags, ulong(m_flags), msg); return(DB_ERROR); } else if (m_table->n_cols != m_n_cols) { From d17e9a02c4a08da9ac1b8f4c653f29f067d75a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 30 Jul 2018 14:05:24 +0300 Subject: [PATCH 64/71] Fix InnoDB/XtraDB warnings by GCC 8.2.0 --- storage/innobase/buf/buf0dump.cc | 2 +- storage/innobase/handler/i_s.cc | 19 ++++++++----------- storage/innobase/row/row0import.cc | 26 ++++++++++++-------------- storage/innobase/trx/trx0trx.cc | 4 ++-- storage/innobase/trx/trx0undo.cc | 3 +-- storage/xtradb/buf/buf0dump.cc | 2 +- storage/xtradb/handler/i_s.cc | 19 ++++++++----------- storage/xtradb/row/row0import.cc | 26 ++++++++++++-------------- storage/xtradb/trx/trx0trx.cc | 4 ++-- storage/xtradb/trx/trx0undo.cc | 3 +-- 10 files changed, 48 insertions(+), 60 deletions(-) diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc index b2b8733c8ce..9642fc86018 100644 --- a/storage/innobase/buf/buf0dump.cc +++ b/storage/innobase/buf/buf0dump.cc @@ -203,7 +203,7 @@ buf_dump( #define SHOULD_QUIT() (SHUTTING_DOWN() && obey_shutdown) char full_filename[OS_FILE_MAX_PATH]; - char tmp_filename[OS_FILE_MAX_PATH]; + char tmp_filename[OS_FILE_MAX_PATH + sizeof "incomplete"]; char now[32]; FILE* f; ulint i; diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index f8aa3bd4637..de164e42273 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -1452,19 +1452,16 @@ i_s_cmp_fill_low( clear it. We could introduce mutex protection, but it could cause a measureable performance hit in page0zip.cc. */ - table->field[1]->store( - static_cast(zip_stat->compressed)); - table->field[2]->store( - static_cast(zip_stat->compressed_ok)); - table->field[3]->store( - static_cast(zip_stat->compressed_usec / 1000000)); - table->field[4]->store( - static_cast(zip_stat->decompressed)); - table->field[5]->store( - static_cast(zip_stat->decompressed_usec / 1000000)); + table->field[1]->store(zip_stat->compressed, true); + table->field[2]->store(zip_stat->compressed_ok, true); + table->field[3]->store(zip_stat->compressed_usec / 1000000, + true); + table->field[4]->store(zip_stat->decompressed, true); + table->field[5]->store(zip_stat->decompressed_usec / 1000000, + true); if (reset) { - memset(zip_stat, 0, sizeof *zip_stat); + new (zip_stat) page_zip_stat_t(); } if (schema_table_store_record(thd, table)) { diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 127f1df8df5..dad55205bc2 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -105,18 +105,18 @@ struct row_index_t { struct row_import { row_import() UNIV_NOTHROW : - m_table(), - m_version(), - m_hostname(), - m_table_name(), - m_autoinc(), - m_page_size(), - m_flags(), - m_n_cols(), - m_cols(), - m_col_names(), - m_n_indexes(), - m_indexes(), + m_table(NULL), + m_version(0), + m_hostname(NULL), + m_table_name(NULL), + m_autoinc(0), + m_page_size(0), + m_flags(0), + m_n_cols(0), + m_cols(NULL), + m_col_names(NULL), + m_n_indexes(0), + m_indexes(NULL), m_missing(true) { } ~row_import() UNIV_NOTHROW; @@ -3558,8 +3558,6 @@ row_import_for_mysql( row_import cfg; - memset(&cfg, 0x0, sizeof(cfg)); - err = row_import_read_cfg(table, trx->mysql_thd, cfg); /* Check if the table column definitions match the contents diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 4a332d22cbc..2401783648a 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -2145,6 +2145,7 @@ trx_get_trx_by_xid_low( if (trx->is_recovered && trx_state_eq(trx, TRX_STATE_PREPARED) + && !trx->xid.is_null() && xid->gtrid_length == trx->xid.gtrid_length && xid->bqual_length == trx->xid.bqual_length && memcmp(xid->data, trx->xid.data, @@ -2152,8 +2153,7 @@ trx_get_trx_by_xid_low( /* Invalidate the XID, so that subsequent calls will not find it. */ - memset(&trx->xid, 0, sizeof(trx->xid)); - trx->xid.formatID = -1; + trx->xid.null(); break; } } diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index 370b3f181a1..b137c461ec3 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -1314,8 +1314,7 @@ trx_undo_mem_create_at_db_start( /* Read X/Open XA transaction identification if it exists, or set it to NULL. */ - memset(&xid, 0, sizeof(xid)); - xid.formatID = -1; + xid.null(); if (xid_exists == TRUE) { trx_undo_read_xid(undo_header, &xid); diff --git a/storage/xtradb/buf/buf0dump.cc b/storage/xtradb/buf/buf0dump.cc index 51c41cc1b78..d5f07250f05 100644 --- a/storage/xtradb/buf/buf0dump.cc +++ b/storage/xtradb/buf/buf0dump.cc @@ -203,7 +203,7 @@ buf_dump( #define SHOULD_QUIT() (SHUTTING_DOWN() && obey_shutdown) char full_filename[OS_FILE_MAX_PATH]; - char tmp_filename[OS_FILE_MAX_PATH]; + char tmp_filename[OS_FILE_MAX_PATH + sizeof "incomplete"]; char now[32]; FILE* f; ulint i; diff --git a/storage/xtradb/handler/i_s.cc b/storage/xtradb/handler/i_s.cc index 834bae399fb..b864830657e 100644 --- a/storage/xtradb/handler/i_s.cc +++ b/storage/xtradb/handler/i_s.cc @@ -1458,19 +1458,16 @@ i_s_cmp_fill_low( clear it. We could introduce mutex protection, but it could cause a measureable performance hit in page0zip.cc. */ - table->field[1]->store( - static_cast(zip_stat->compressed)); - table->field[2]->store( - static_cast(zip_stat->compressed_ok)); - table->field[3]->store( - static_cast(zip_stat->compressed_usec / 1000000)); - table->field[4]->store( - static_cast(zip_stat->decompressed)); - table->field[5]->store( - static_cast(zip_stat->decompressed_usec / 1000000)); + table->field[1]->store(zip_stat->compressed, true); + table->field[2]->store(zip_stat->compressed_ok, true); + table->field[3]->store(zip_stat->compressed_usec / 1000000, + true); + table->field[4]->store(zip_stat->decompressed, true); + table->field[5]->store(zip_stat->decompressed_usec / 1000000, + true); if (reset) { - memset(zip_stat, 0, sizeof *zip_stat); + new (zip_stat) page_zip_stat_t(); } if (schema_table_store_record(thd, table)) { diff --git a/storage/xtradb/row/row0import.cc b/storage/xtradb/row/row0import.cc index 127f1df8df5..dad55205bc2 100644 --- a/storage/xtradb/row/row0import.cc +++ b/storage/xtradb/row/row0import.cc @@ -105,18 +105,18 @@ struct row_index_t { struct row_import { row_import() UNIV_NOTHROW : - m_table(), - m_version(), - m_hostname(), - m_table_name(), - m_autoinc(), - m_page_size(), - m_flags(), - m_n_cols(), - m_cols(), - m_col_names(), - m_n_indexes(), - m_indexes(), + m_table(NULL), + m_version(0), + m_hostname(NULL), + m_table_name(NULL), + m_autoinc(0), + m_page_size(0), + m_flags(0), + m_n_cols(0), + m_cols(NULL), + m_col_names(NULL), + m_n_indexes(0), + m_indexes(NULL), m_missing(true) { } ~row_import() UNIV_NOTHROW; @@ -3558,8 +3558,6 @@ row_import_for_mysql( row_import cfg; - memset(&cfg, 0x0, sizeof(cfg)); - err = row_import_read_cfg(table, trx->mysql_thd, cfg); /* Check if the table column definitions match the contents diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index 701ac3ed72d..8e62a7dba46 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -2421,6 +2421,7 @@ trx_get_trx_by_xid_low( if (trx->is_recovered && trx_state_eq(trx, TRX_STATE_PREPARED) + && !trx->xid.is_null() && xid->gtrid_length == trx->xid.gtrid_length && xid->bqual_length == trx->xid.bqual_length && memcmp(xid->data, trx->xid.data, @@ -2428,8 +2429,7 @@ trx_get_trx_by_xid_low( /* Invalidate the XID, so that subsequent calls will not find it. */ - memset(&trx->xid, 0, sizeof(trx->xid)); - trx->xid.formatID = -1; + trx->xid.null(); break; } } diff --git a/storage/xtradb/trx/trx0undo.cc b/storage/xtradb/trx/trx0undo.cc index 370b3f181a1..b137c461ec3 100644 --- a/storage/xtradb/trx/trx0undo.cc +++ b/storage/xtradb/trx/trx0undo.cc @@ -1314,8 +1314,7 @@ trx_undo_mem_create_at_db_start( /* Read X/Open XA transaction identification if it exists, or set it to NULL. */ - memset(&xid, 0, sizeof(xid)); - xid.formatID = -1; + xid.null(); if (xid_exists == TRUE) { trx_undo_read_xid(undo_header, &xid); From 29ddc6e9e37cbb74193b55e85a1b9cc3f47f28b6 Mon Sep 17 00:00:00 2001 From: Sachin Agarwal Date: Thu, 17 May 2018 16:53:30 +0530 Subject: [PATCH 65/71] Bug #27326796 - MYSQL CRASH WITH INNODB ASSERTION FAILURE IN FILE PARS0PARS.CC Problem: As part of bug #24938374 fix, dict_operation_lock was not taken by fts_optimize_thread while syncing fts cache. Due to this change, alter query is able to update SYS_TABLE rows simultaneously. Now when fts_optimizer_thread goes open index table, It doesn't open index table if the record corresponding to that table is set to REC_INFO_DELETED_FLAG in SYS_TABLES and hits an assert. Fix: If fts sync is already in progress, Alter query would wait for sync to complete before renaming table. RB: #19604 Reviewed by : Jimmy.Yang@oracle.com --- storage/innobase/fts/fts0fts.cc | 57 +++++++++++---------------- storage/innobase/handler/ha_innodb.cc | 37 ++++++++++++++++- storage/xtradb/fts/fts0fts.cc | 57 +++++++++++---------------- storage/xtradb/handler/ha_innodb.cc | 37 ++++++++++++++++- 4 files changed, 116 insertions(+), 72 deletions(-) diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 8ccc8afe7b4..86dd76bbf49 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2016, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -869,37 +869,28 @@ fts_drop_index( err = fts_drop_index_tables(trx, index); - for(;;) { - bool retry = false; - if (index->index_fts_syncing) { - retry = true; - } - if (!retry){ - fts_free(table); - break; - } + while (index->index_fts_syncing + && !trx_is_interrupted(trx)) { DICT_BG_YIELD(trx); } + + fts_free(table); + return(err); } - for(;;) { - bool retry = false; - if (index->index_fts_syncing) { - retry = true; - } - if (!retry){ - current_doc_id = table->fts->cache->next_doc_id; - first_doc_id = table->fts->cache->first_doc_id; - fts_cache_clear(table->fts->cache); - fts_cache_destroy(table->fts->cache); - table->fts->cache = fts_cache_create(table); - table->fts->cache->next_doc_id = current_doc_id; - table->fts->cache->first_doc_id = first_doc_id; - break; - } + while (index->index_fts_syncing + && !trx_is_interrupted(trx)) { DICT_BG_YIELD(trx); } + + current_doc_id = table->fts->cache->next_doc_id; + first_doc_id = table->fts->cache->first_doc_id; + fts_cache_clear(table->fts->cache); + fts_cache_destroy(table->fts->cache); + table->fts->cache = fts_cache_create(table); + table->fts->cache->next_doc_id = current_doc_id; + table->fts->cache->first_doc_id = first_doc_id; } else { fts_cache_t* cache = table->fts->cache; fts_index_cache_t* index_cache; @@ -909,18 +900,14 @@ fts_drop_index( index_cache = fts_find_index_cache(cache, index); if (index_cache != NULL) { - for(;;) { - bool retry = false; - if (index->index_fts_syncing) { - retry = true; - } - if (!retry && index_cache->words) { - fts_words_free(index_cache->words); - rbt_free(index_cache->words); - break; - } + while (index->index_fts_syncing + && !trx_is_interrupted(trx)) { DICT_BG_YIELD(trx); } + if (index_cache->words) { + fts_words_free(index_cache->words); + rbt_free(index_cache->words); + } ib_vector_remove(cache->indexes, *(void**) index_cache); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index b35eeb432fc..3959b49b600 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -10877,6 +10877,7 @@ static MY_ATTRIBUTE((nonnull, warn_unused_result)) dberr_t innobase_rename_table( /*==================*/ + THD* thd, /*!< Connection thread handle */ trx_t* trx, /*!< in: transaction */ const char* from, /*!< in: old name of the table */ const char* to) /*!< in: new name of the table */ @@ -10902,6 +10903,36 @@ innobase_rename_table( row_mysql_lock_data_dictionary(trx); + dict_table_t* table = dict_table_open_on_name(norm_from, TRUE, FALSE, + DICT_ERR_IGNORE_NONE); + + /* Since DICT_BG_YIELD has sleep for 250 milliseconds, + Convert lock_wait_timeout unit from second to 250 milliseconds */ + long int lock_wait_timeout = thd_lock_wait_timeout(thd) * 4; + if (table != NULL) { + for (dict_index_t* index = dict_table_get_first_index(table); + index != NULL; + index = dict_table_get_next_index(index)) { + + if (index->type & DICT_FTS) { + /* Found */ + while (index->index_fts_syncing + && !trx_is_interrupted(trx) + && (lock_wait_timeout--) > 0) { + DICT_BG_YIELD(trx); + } + } + } + dict_table_close(table, TRUE, FALSE); + } + + /* FTS sync is in progress. We shall timeout this operation */ + if (lock_wait_timeout < 0) { + error = DB_LOCK_WAIT_TIMEOUT; + row_mysql_unlock_data_dictionary(trx); + DBUG_RETURN(error); + } + /* Transaction must be flagged as a locking transaction or it hasn't been started yet. */ @@ -11011,7 +11042,7 @@ ha_innobase::rename_table( ++trx->will_lock; trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); - error = innobase_rename_table(trx, from, to); + error = innobase_rename_table(thd, trx, from, to); DEBUG_SYNC(thd, "after_innobase_rename_table"); @@ -11055,6 +11086,10 @@ ha_innobase::rename_table( my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to); error = DB_ERROR; + } else if (error == DB_LOCK_WAIT_TIMEOUT) { + my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0), to); + + error = DB_LOCK_WAIT; } DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); diff --git a/storage/xtradb/fts/fts0fts.cc b/storage/xtradb/fts/fts0fts.cc index d2c20405e6a..36a1d234bf4 100644 --- a/storage/xtradb/fts/fts0fts.cc +++ b/storage/xtradb/fts/fts0fts.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2016, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -869,37 +869,28 @@ fts_drop_index( err = fts_drop_index_tables(trx, index); - for(;;) { - bool retry = false; - if (index->index_fts_syncing) { - retry = true; - } - if (!retry){ - fts_free(table); - break; - } + while (index->index_fts_syncing + && !trx_is_interrupted(trx)) { DICT_BG_YIELD(trx); } + + fts_free(table); + return(err); } - for(;;) { - bool retry = false; - if (index->index_fts_syncing) { - retry = true; - } - if (!retry){ - current_doc_id = table->fts->cache->next_doc_id; - first_doc_id = table->fts->cache->first_doc_id; - fts_cache_clear(table->fts->cache); - fts_cache_destroy(table->fts->cache); - table->fts->cache = fts_cache_create(table); - table->fts->cache->next_doc_id = current_doc_id; - table->fts->cache->first_doc_id = first_doc_id; - break; - } + while (index->index_fts_syncing + && !trx_is_interrupted(trx)) { DICT_BG_YIELD(trx); } + + current_doc_id = table->fts->cache->next_doc_id; + first_doc_id = table->fts->cache->first_doc_id; + fts_cache_clear(table->fts->cache); + fts_cache_destroy(table->fts->cache); + table->fts->cache = fts_cache_create(table); + table->fts->cache->next_doc_id = current_doc_id; + table->fts->cache->first_doc_id = first_doc_id; } else { fts_cache_t* cache = table->fts->cache; fts_index_cache_t* index_cache; @@ -909,18 +900,14 @@ fts_drop_index( index_cache = fts_find_index_cache(cache, index); if (index_cache != NULL) { - for(;;) { - bool retry = false; - if (index->index_fts_syncing) { - retry = true; - } - if (!retry && index_cache->words) { - fts_words_free(index_cache->words); - rbt_free(index_cache->words); - break; - } + while (index->index_fts_syncing + && !trx_is_interrupted(trx)) { DICT_BG_YIELD(trx); } + if (index_cache->words) { + fts_words_free(index_cache->words); + rbt_free(index_cache->words); + } ib_vector_remove(cache->indexes, *(void**) index_cache); } diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 89f4b9cb7b5..f153b6e28ae 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -11695,6 +11695,7 @@ static MY_ATTRIBUTE((nonnull, warn_unused_result)) dberr_t innobase_rename_table( /*==================*/ + THD* thd, /*!< Connection thread handle */ trx_t* trx, /*!< in: transaction */ const char* from, /*!< in: old name of the table */ const char* to) /*!< in: new name of the table */ @@ -11720,6 +11721,36 @@ innobase_rename_table( row_mysql_lock_data_dictionary(trx); + dict_table_t* table = dict_table_open_on_name(norm_from, TRUE, FALSE, + DICT_ERR_IGNORE_NONE); + + /* Since DICT_BG_YIELD has sleep for 250 milliseconds, + Convert lock_wait_timeout unit from second to 250 milliseconds */ + long int lock_wait_timeout = thd_lock_wait_timeout(thd) * 4; + if (table != NULL) { + for (dict_index_t* index = dict_table_get_first_index(table); + index != NULL; + index = dict_table_get_next_index(index)) { + + if (index->type & DICT_FTS) { + /* Found */ + while (index->index_fts_syncing + && !trx_is_interrupted(trx) + && (lock_wait_timeout--) > 0) { + DICT_BG_YIELD(trx); + } + } + } + dict_table_close(table, TRUE, FALSE); + } + + /* FTS sync is in progress. We shall timeout this operation */ + if (lock_wait_timeout < 0) { + error = DB_LOCK_WAIT_TIMEOUT; + row_mysql_unlock_data_dictionary(trx); + DBUG_RETURN(error); + } + /* Transaction must be flagged as a locking transaction or it hasn't been started yet. */ @@ -11834,7 +11865,7 @@ ha_innobase::rename_table( ++trx->will_lock; trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); - error = innobase_rename_table(trx, from, to); + error = innobase_rename_table(thd, trx, from, to); DEBUG_SYNC(thd, "after_innobase_rename_table"); @@ -11878,6 +11909,10 @@ ha_innobase::rename_table( my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to); error = DB_ERROR; + } else if (error == DB_LOCK_WAIT_TIMEOUT) { + my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0), to); + + error = DB_LOCK_WAIT; } DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); From a49ec980422e04ce1a37344be09aa6254f16fa2a Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Wed, 14 Feb 2018 09:35:18 +0530 Subject: [PATCH 66/71] --- storage/xtradb/handler/ha_innodb.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 94e49d4897a..1fe93f0ff9d 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/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. @@ -10689,8 +10689,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) { From 5ed2da9587c0dd6dcf9cfcb19f5e434488d79e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 30 Jul 2018 16:28:20 +0300 Subject: [PATCH 67/71] Apply the 5.6.40 security fixes to XtraDB We did not merge Percona XtraDB 5.6.40-84.0 yet. The changes in it are mostly cosmetic, except for 2 bug fixes from Oracle MySQL 5.6.40, which could be security bugs. This was achieved by taking the applicable parts of an earlier InnoDB commit to XtraDB: git diff 15ec8c2f28f08517ecbffb959d756b4bdd53ab45{~,} storage/innobase| sed -e s+/innobase/+/xtradb/+|patch -p1 --- storage/xtradb/handler/handler0alter.cc | 51 ++++++++++++++++--------- storage/xtradb/row/row0log.cc | 12 +++++- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index 755c07848e1..151c3237b2b 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2005, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2017, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -4782,13 +4782,15 @@ processed_field: } /** Get the auto-increment value of the table on commit. -@param ha_alter_info Data used during in-place alter -@param ctx In-place ALTER TABLE context -@param altered_table MySQL table that is being altered -@param old_table MySQL table as it is before the ALTER operation -@return the next auto-increment value (0 if not present) */ +@param[in] ha_alter_info Data used during in-place alter +@param[in,out] ctx In-place ALTER TABLE context + return autoinc value in ctx->max_autoinc +@param altered_table[in] MySQL table that is being altered +@param old_table[in] MySQL table as it is before the ALTER operation +retval true Failure +@retval false Success*/ static MY_ATTRIBUTE((nonnull, warn_unused_result)) -ulonglong +bool commit_get_autoinc( /*===============*/ Alter_inplace_info* ha_alter_info, @@ -4796,23 +4798,28 @@ commit_get_autoinc( const TABLE* altered_table, const TABLE* old_table) { - ulonglong max_autoinc; DBUG_ENTER("commit_get_autoinc"); if (!altered_table->found_next_number_field) { /* There is no AUTO_INCREMENT column in the table after the ALTER operation. */ - max_autoinc = 0; + ctx->max_autoinc = 0; } else if (ctx->add_autoinc != ULINT_UNDEFINED) { /* An AUTO_INCREMENT column was added. Get the last value from the sequence, which may be based on a supplied AUTO_INCREMENT value. */ - max_autoinc = ctx->sequence.last(); + ctx->max_autoinc = ctx->sequence.last(); } else if ((ha_alter_info->handler_flags & Alter_inplace_info::CHANGE_CREATE_OPTION) && (ha_alter_info->create_info->used_fields & HA_CREATE_USED_AUTO)) { + + /* Check if the table is discarded */ + if(dict_table_is_discarded(ctx->old_table)) { + DBUG_RETURN(true); + } + /* An AUTO_INCREMENT value was supplied, but the table was not rebuilt. Get the user-supplied value or the last value from the sequence. */ @@ -4827,7 +4834,8 @@ commit_get_autoinc( dict_index_t* index = dict_table_get_index_on_name( ctx->old_table, autoinc_key->name); - max_autoinc = ha_alter_info->create_info->auto_increment_value; + ctx->max_autoinc = + ha_alter_info->create_info->auto_increment_value; dict_table_autoinc_lock(ctx->old_table); @@ -4836,8 +4844,8 @@ commit_get_autoinc( if (err != DB_SUCCESS) { ut_ad(0); - max_autoinc = 0; - } else if (max_autoinc <= max_value_table) { + ctx->max_autoinc = 0; + } else if (ctx->max_autoinc <= max_value_table) { ulonglong col_max_value; ulonglong offset; @@ -4845,7 +4853,7 @@ commit_get_autoinc( old_table->found_next_number_field); offset = ctx->prebuilt->autoinc_offset; - max_autoinc = innobase_next_autoinc( + ctx->max_autoinc = innobase_next_autoinc( max_value_table, 1, 1, offset, col_max_value); } @@ -4855,11 +4863,11 @@ commit_get_autoinc( Read the old counter value from the table. */ ut_ad(old_table->found_next_number_field); dict_table_autoinc_lock(ctx->old_table); - max_autoinc = ctx->old_table->autoinc; + ctx->max_autoinc = ctx->old_table->autoinc; dict_table_autoinc_unlock(ctx->old_table); } - DBUG_RETURN(max_autoinc); + DBUG_RETURN(false); } /** Add or drop foreign key constraints to the data dictionary tables, @@ -5828,8 +5836,13 @@ ha_innobase::commit_inplace_alter_table( DBUG_ASSERT(new_clustered == ctx->need_rebuild()); - ctx->max_autoinc = commit_get_autoinc( - ha_alter_info, ctx, altered_table, table); + if (commit_get_autoinc(ha_alter_info, ctx, altered_table, + table)) { + fail = true; + my_error(ER_TABLESPACE_DISCARDED, MYF(0), + table->s->table_name.str); + goto rollback_trx; + } if (ctx->need_rebuild()) { ctx->tmp_name = dict_mem_create_temporary_tablename( @@ -5861,6 +5874,8 @@ ha_innobase::commit_inplace_alter_table( #endif } +rollback_trx: + /* Commit or roll back the changes to the data dictionary. */ if (fail) { diff --git a/storage/xtradb/row/row0log.cc b/storage/xtradb/row/row0log.cc index c239722e4f7..7cab4cbbebb 100644 --- a/storage/xtradb/row/row0log.cc +++ b/storage/xtradb/row/row0log.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2017, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -2631,7 +2631,15 @@ all_done: while (!trx_is_interrupted(trx)) { mrec = next_mrec; - ut_ad(mrec < mrec_end); + ut_ad(mrec <= mrec_end); + + if (mrec == mrec_end) { + /* We are at the end of the log. + Mark the replay all_done. */ + if (has_index_lock) { + goto all_done; + } + } if (!has_index_lock) { /* We are applying operations from a different From e52315a4a2c7e752e786f9fcf63b0b5685b0d474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 30 Jul 2018 18:06:30 +0300 Subject: [PATCH 68/71] MDEV-16855 Fix fts_sync_synchronization in InnoDB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a backport of the following fix from MySQL 5.7.23. Some code refactoring has been omitted, and the test case has been adapted to MariaDB. commit 7a689acaa65e9d602575f7aa53fe36a64a07460f Author: Krzysztof Kapuścik Date: Tue Mar 13 12:34:03 2018 +0100 Bug#27082268 Invalid FTS sync synchronization The fix closes two issues: Bug #27082268 - INNODB: FAILING ASSERTION: SYM_NODE->TABLE != NULL DURING FTS SYNC Bug #27095935 - DEADLOCK BETWEEN FTS_DROP_INDEX AND FTS_OPTIMIZE_SYNC_TABLE Both issues were related to a FTS cache sync being done during operations that perfomed DDL actions on internal FTS tables (ALTER TABLE, TRUNCATE). In some cases the FTS tables and/or internal cache structures could get removed while still being used to perform FTS synchronization leading to crashes. In other the sync operations could not get finishes as it was waiting for dict lock which was taken by thread waiting for the background sync to be finished. The changes done includes: - Stopping background operations during ALTER TABLE and TRUNCATE. - Removal of unused code in FTS. - Cleanup of FTS sync related code to make it more readable and easier to maintain. RB#18262 --- mysql-test/suite/innodb_fts/r/sync_ddl.result | 117 ++++++++++++ mysql-test/suite/innodb_fts/t/sync_ddl.test | 177 ++++++++++++++++++ storage/innobase/fts/fts0fts.cc | 19 +- storage/innobase/fts/fts0opt.cc | 175 ++--------------- storage/innobase/handler/handler0alter.cc | 66 +++---- storage/innobase/include/fts0fts.h | 8 +- storage/innobase/include/fts0priv.h | 18 +- storage/innobase/row/row0mysql.cc | 12 ++ storage/xtradb/fts/fts0fts.cc | 19 +- storage/xtradb/fts/fts0opt.cc | 175 ++--------------- storage/xtradb/handler/handler0alter.cc | 66 +++---- storage/xtradb/include/fts0fts.h | 8 +- storage/xtradb/include/fts0priv.h | 18 +- storage/xtradb/row/row0mysql.cc | 12 ++ 14 files changed, 450 insertions(+), 440 deletions(-) create mode 100644 mysql-test/suite/innodb_fts/r/sync_ddl.result create mode 100644 mysql-test/suite/innodb_fts/t/sync_ddl.test diff --git a/mysql-test/suite/innodb_fts/r/sync_ddl.result b/mysql-test/suite/innodb_fts/r/sync_ddl.result new file mode 100644 index 00000000000..1e98594b28e --- /dev/null +++ b/mysql-test/suite/innodb_fts/r/sync_ddl.result @@ -0,0 +1,117 @@ +CREATE TABLE t1 ( +id INT AUTO_INCREMENT NOT NULL PRIMARY KEY, +value VARCHAR(1024) +) ENGINE=InnoDB; +CREATE FULLTEXT INDEX idx1 ON t1(value); +Warnings: +Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID +SET @save_debug = @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_sync_before_syncing,ib_trunc_sleep_before_fts_cache_clear'; +INSERT INTO t1 (value) VALUES +('By default or with the IN NATURAL LANGUAGE MODE modifier') +; +TRUNCATE TABLE t1; +DROP TABLE t1; +SET GLOBAL debug_dbug = @save_debug; +CREATE TABLE t1 ( +id INT AUTO_INCREMENT NOT NULL PRIMARY KEY, +value VARCHAR(1024) +) ENGINE=InnoDB; +CREATE FULLTEXT INDEX idx1 ON t1(value); +Warnings: +Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_write_words_before_select_index,ib_trunc_sleep_before_fts_cache_clear'; +INSERT INTO t1 (value) VALUES +('By default or with the IN NATURAL LANGUAGE MODE modifier'), +('performs a natural language search for a string'), +('collection is a set of one or more columns included'), +('returns a relevance value; that is, a similarity measure'), +('and the text in that row in the columns named in'), +('By default, the search is performed in case-insensitive'), +('sensitive full-text search, use a binary collation '), +('example, a column that uses the latin1 character'), +('collation of latin1_bin to make it case sensitive') +; +TRUNCATE TABLE t1; +DROP TABLE t1; +SET GLOBAL debug_dbug = @save_debug; +CREATE TABLE t1 ( +value VARCHAR(1024) +) ENGINE=InnoDB; +CREATE FULLTEXT INDEX idx1 ON t1(value); +Warnings: +Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_msg_sync_sleep'; +INSERT INTO t1 (value) VALUES +('By default or with the IN NATURAL LANGUAGE MODE modifier'), +('performs a natural language search for a string'), +('collection is a set of one or more columns included'), +('returns a relevance value; that is, a similarity measure'), +('and the text in that row in the columns named in'), +('By default, the search is performed in case-insensitive'), +('sensitive full-text search, use a binary collation '), +('example, a column that uses the latin1 character'), +('collation of latin1_bin to make it case sensitive') +; +DROP INDEX idx1 ON t1; +DROP TABLE t1; +SET GLOBAL debug_dbug = @save_debug; +CREATE TABLE t1 ( +value VARCHAR(1024) +) ENGINE=InnoDB; +CREATE FULLTEXT INDEX idx1 ON t1(value); +Warnings: +Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_msg_sync_sleep'; +INSERT INTO t1 (value) VALUES +('By default or with the IN NATURAL LANGUAGE MODE modifier'), +('performs a natural language search for a string'), +('collection is a set of one or more columns included'), +('returns a relevance value; that is, a similarity measure'), +('and the text in that row in the columns named in'), +('By default, the search is performed in case-insensitive'), +('sensitive full-text search, use a binary collation '), +('example, a column that uses the latin1 character'), +('collation of latin1_bin to make it case sensitive') +; +ALTER TABLE t1 +DROP INDEX idx1, +ALGORITHM=INPLACE; +DROP TABLE t1; +SET GLOBAL debug_dbug = @save_debug; +CREATE TABLE t1 ( +value VARCHAR(1024) +) ENGINE=InnoDB; +CREATE FULLTEXT INDEX idx1 ON t1(value); +Warnings: +Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_msg_sync_sleep'; +INSERT INTO t1 (value) VALUES +('example, a column that uses the latin1 character'), +('collation of latin1_bin to make it case sensitive') +; +ALTER TABLE t1 +DROP INDEX idx1, +ALGORITHM=COPY; +DROP TABLE t1; +SET GLOBAL debug_dbug = @save_debug; +CREATE TABLE t1 ( +id1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +value VARCHAR(1024) +) ENGINE=InnoDB; +CREATE FULLTEXT INDEX idx1 ON t1(value); +Warnings: +Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_msg_sync_sleep'; +INSERT INTO t1 (value) VALUES +('example, a column that uses the latin1 character'), +('collation of latin1_bin to make it case sensitive') +; +ALTER TABLE t1 +DROP COLUMN id1, +ADD COLUMN id2 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +DROP INDEX idx1, +ADD FULLTEXT INDEX idx2(value), +ALGORITHM=INPLACE; +DROP TABLE t1; +SET GLOBAL debug_dbug = @save_debug; diff --git a/mysql-test/suite/innodb_fts/t/sync_ddl.test b/mysql-test/suite/innodb_fts/t/sync_ddl.test new file mode 100644 index 00000000000..2950297d5bb --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/sync_ddl.test @@ -0,0 +1,177 @@ +# +# BUG#27082268 FTS synchronization issues +# + +--source include/have_innodb.inc +--source include/have_debug.inc + +#-------------------------------------- +# Check FTS_sync vs TRUNCATE (1) +#-------------------------------------- + +CREATE TABLE t1 ( + id INT AUTO_INCREMENT NOT NULL PRIMARY KEY, + value VARCHAR(1024) + ) ENGINE=InnoDB; + +CREATE FULLTEXT INDEX idx1 ON t1(value); + +SET @save_debug = @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_sync_before_syncing,ib_trunc_sleep_before_fts_cache_clear'; + +INSERT INTO t1 (value) VALUES + ('By default or with the IN NATURAL LANGUAGE MODE modifier') + ; + +TRUNCATE TABLE t1; + +DROP TABLE t1; + +SET GLOBAL debug_dbug = @save_debug; + +#-------------------------------------- +# Check FTS sync vs DROP INDEX (2) +#-------------------------------------- + +CREATE TABLE t1 ( + id INT AUTO_INCREMENT NOT NULL PRIMARY KEY, + value VARCHAR(1024) + ) ENGINE=InnoDB; + +CREATE FULLTEXT INDEX idx1 ON t1(value); + +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_write_words_before_select_index,ib_trunc_sleep_before_fts_cache_clear'; + +INSERT INTO t1 (value) VALUES + ('By default or with the IN NATURAL LANGUAGE MODE modifier'), + ('performs a natural language search for a string'), + ('collection is a set of one or more columns included'), + ('returns a relevance value; that is, a similarity measure'), + ('and the text in that row in the columns named in'), + ('By default, the search is performed in case-insensitive'), + ('sensitive full-text search, use a binary collation '), + ('example, a column that uses the latin1 character'), + ('collation of latin1_bin to make it case sensitive') + ; + +TRUNCATE TABLE t1; + +DROP TABLE t1; + +SET GLOBAL debug_dbug = @save_debug; + +#-------------------------------------- +# Check FTS sync vs DROP INDEX +#-------------------------------------- + +CREATE TABLE t1 ( + value VARCHAR(1024) + ) ENGINE=InnoDB; + +CREATE FULLTEXT INDEX idx1 ON t1(value); + +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_msg_sync_sleep'; + +INSERT INTO t1 (value) VALUES + ('By default or with the IN NATURAL LANGUAGE MODE modifier'), + ('performs a natural language search for a string'), + ('collection is a set of one or more columns included'), + ('returns a relevance value; that is, a similarity measure'), + ('and the text in that row in the columns named in'), + ('By default, the search is performed in case-insensitive'), + ('sensitive full-text search, use a binary collation '), + ('example, a column that uses the latin1 character'), + ('collation of latin1_bin to make it case sensitive') + ; + +DROP INDEX idx1 ON t1; + +DROP TABLE t1; + +SET GLOBAL debug_dbug = @save_debug; + +#-------------------------------------- +# Check FTS sync vs ALTER TABLE DROP INDEX (INPLACE) +#-------------------------------------- + +CREATE TABLE t1 ( + value VARCHAR(1024) + ) ENGINE=InnoDB; + +CREATE FULLTEXT INDEX idx1 ON t1(value); + +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_msg_sync_sleep'; + +INSERT INTO t1 (value) VALUES + ('By default or with the IN NATURAL LANGUAGE MODE modifier'), + ('performs a natural language search for a string'), + ('collection is a set of one or more columns included'), + ('returns a relevance value; that is, a similarity measure'), + ('and the text in that row in the columns named in'), + ('By default, the search is performed in case-insensitive'), + ('sensitive full-text search, use a binary collation '), + ('example, a column that uses the latin1 character'), + ('collation of latin1_bin to make it case sensitive') + ; + +ALTER TABLE t1 + DROP INDEX idx1, + ALGORITHM=INPLACE; + +DROP TABLE t1; + +SET GLOBAL debug_dbug = @save_debug; + +#-------------------------------------- +# Check FTS sync vs ALTER TABLE DROP INDEX (COPY) +#-------------------------------------- + +CREATE TABLE t1 ( + value VARCHAR(1024) + ) ENGINE=InnoDB; + +CREATE FULLTEXT INDEX idx1 ON t1(value); + +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_msg_sync_sleep'; + +INSERT INTO t1 (value) VALUES + ('example, a column that uses the latin1 character'), + ('collation of latin1_bin to make it case sensitive') + ; + +ALTER TABLE t1 + DROP INDEX idx1, + ALGORITHM=COPY; + +DROP TABLE t1; + +SET GLOBAL debug_dbug = @save_debug; + +#-------------------------------------- +# Check FTS sync vs ALTER TABLE (INPLACE, new cluster) +#-------------------------------------- + +CREATE TABLE t1 ( + id1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + value VARCHAR(1024) + ) ENGINE=InnoDB; + +CREATE FULLTEXT INDEX idx1 ON t1(value); + +SET GLOBAL debug_dbug = '+d,fts_instrument_sync_request,fts_instrument_msg_sync_sleep'; + +INSERT INTO t1 (value) VALUES + ('example, a column that uses the latin1 character'), + ('collation of latin1_bin to make it case sensitive') + ; + +ALTER TABLE t1 + DROP COLUMN id1, + ADD COLUMN id2 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + DROP INDEX idx1, + ADD FULLTEXT INDEX idx2(value), + ALGORITHM=INPLACE; + +DROP TABLE t1; + +SET GLOBAL debug_dbug = @save_debug; diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 86dd76bbf49..6044abd8e79 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -268,7 +268,7 @@ FTS auxiliary INDEX table and clear the cache at the end. @param[in,out] sync sync state @param[in] unlock_cache whether unlock cache lock when write node @param[in] wait whether wait when a sync is in progress -@param[in] has_dict whether has dict operation lock +@param[in] has_dict whether has dict operation lock @return DB_SUCCESS if all OK */ static dberr_t @@ -3961,6 +3961,9 @@ fts_sync_write_words( word = rbt_value(fts_tokenizer_word_t, rbt_node); + DBUG_EXECUTE_IF("fts_instrument_write_words_before_select_index", + os_thread_sleep(300000);); + selected = fts_select_index( index_cache->charset, word->text.f_str, word->text.f_len); @@ -4525,7 +4528,7 @@ FTS auxiliary INDEX table and clear the cache at the end. @param[in,out] sync sync state @param[in] unlock_cache whether unlock cache lock when write node @param[in] wait whether wait when a sync is in progress -@param[in] has_dict whether has dict operation lock +@param[in] has_dict whether has dict operation lock @return DB_SUCCESS if all OK */ static dberr_t @@ -4587,15 +4590,13 @@ begin_sync: continue; } + DBUG_EXECUTE_IF("fts_instrument_sync_before_syncing", + os_thread_sleep(300000);); index_cache->index->index_fts_syncing = true; - DBUG_EXECUTE_IF("fts_instrument_sync_sleep_drop_waits", - os_thread_sleep(10000000); - ); error = fts_sync_index(sync, index_cache); - if (error != DB_SUCCESS && !sync->interrupted) { - + if (error != DB_SUCCESS) { goto end_sync; } } @@ -4630,8 +4631,8 @@ end_sync: } rw_lock_x_lock(&cache->lock); - /* Clear fts syncing flags of any indexes incase sync is - interrupeted */ + /* Clear fts syncing flags of any indexes in case sync is + interrupted */ for (i = 0; i < ib_vector_size(cache->indexes); ++i) { static_cast( ib_vector_get(cache->indexes, i)) diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index d9f96948000..77293bc867a 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2016, MariaDB Corporation. All Rights reserved. This program is free software; you can redistribute it and/or modify it under @@ -58,12 +58,6 @@ static const ulint FTS_WORD_NODES_INIT_SIZE = 64; /** Last time we did check whether system need a sync */ static ib_time_t last_check_sync_time; -#if 0 -/** Check each table in round robin to see whether they'd -need to be "optimized" */ -static ulint fts_optimize_sync_iterator = 0; -#endif - /** State of a table within the optimization sub system. */ enum fts_state_t { FTS_STATE_LOADED, @@ -75,17 +69,11 @@ enum fts_state_t { /** FTS optimize thread message types. */ enum fts_msg_type_t { - FTS_MSG_START, /*!< Start optimizing thread */ - - FTS_MSG_PAUSE, /*!< Pause optimizing thread */ - FTS_MSG_STOP, /*!< Stop optimizing and exit thread */ FTS_MSG_ADD_TABLE, /*!< Add table to the optimize thread's work queue */ - FTS_MSG_OPTIMIZE_TABLE, /*!< Optimize a table */ - FTS_MSG_DEL_TABLE, /*!< Remove a table from the optimize threads work queue */ FTS_MSG_SYNC_TABLE /*!< Sync fts cache of a table */ @@ -235,7 +223,7 @@ struct fts_msg_t { /** The number of words to read and optimize in a single pass. */ UNIV_INTERN ulong fts_num_word_optimize; -// FIXME +/** Whether to enable additional FTS diagnostic printout. */ UNIV_INTERN char fts_enable_diag_print; /** ZLib compressed block size.*/ @@ -2560,13 +2548,9 @@ fts_optimize_create_msg( return(msg); } -/**********************************************************************//** -Add the table to add to the OPTIMIZER's list. */ -UNIV_INTERN -void -fts_optimize_add_table( -/*===================*/ - dict_table_t* table) /*!< in: table to add */ +/** Add the table to add to the OPTIMIZER's list. +@param[in] table table to add */ +UNIV_INTERN void fts_optimize_add_table(dict_table_t* table) { fts_msg_t* msg; @@ -2584,26 +2568,6 @@ fts_optimize_add_table( ib_wqueue_add(fts_optimize_wq, msg, msg->heap); } -/**********************************************************************//** -Optimize a table. */ -UNIV_INTERN -void -fts_optimize_do_table( -/*==================*/ - dict_table_t* table) /*!< in: table to optimize */ -{ - fts_msg_t* msg; - - /* Optimizer thread could be shutdown */ - if (!fts_optimize_wq) { - return; - } - - msg = fts_optimize_create_msg(FTS_MSG_OPTIMIZE_TABLE, table); - - ib_wqueue_add(fts_optimize_wq, msg, msg->heap); -} - /**********************************************************************//** Remove the table from the OPTIMIZER's list. We do wait for acknowledgement from the consumer of the message. */ @@ -2618,7 +2582,7 @@ fts_optimize_remove_table( fts_msg_del_t* remove; /* if the optimize system not yet initialized, return */ - if (!fts_optimize_wq) { + if (!fts_optimize_is_init()) { return; } @@ -2660,7 +2624,7 @@ fts_optimize_request_sync_table( table_id_t* table_id; /* if the optimize system not yet initialized, return */ - if (!fts_optimize_wq) { + if (!fts_optimize_is_init()) { return; } @@ -2682,54 +2646,6 @@ fts_optimize_request_sync_table( ib_wqueue_add(fts_optimize_wq, msg, msg->heap); } -/**********************************************************************//** -Find the slot for a particular table. -@return slot if found else NULL. */ -static -fts_slot_t* -fts_optimize_find_slot( -/*===================*/ - ib_vector_t* tables, /*!< in: vector of tables */ - const dict_table_t* table) /*!< in: table to add */ -{ - ulint i; - - for (i = 0; i < ib_vector_size(tables); ++i) { - fts_slot_t* slot; - - slot = static_cast(ib_vector_get(tables, i)); - - if (slot->table->id == table->id) { - return(slot); - } - } - - return(NULL); -} - -/**********************************************************************//** -Start optimizing table. */ -static -void -fts_optimize_start_table( -/*=====================*/ - ib_vector_t* tables, /*!< in/out: vector of tables */ - dict_table_t* table) /*!< in: table to optimize */ -{ - fts_slot_t* slot; - - slot = fts_optimize_find_slot(tables, table); - - if (slot == NULL) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error: table %s not registered " - "with the optimize thread.\n", table->name); - } else { - slot->last_run = 0; - slot->completed = 0; - } -} - /**********************************************************************//** Add the table to the vector if it doesn't already exist. */ static @@ -2912,57 +2828,6 @@ fts_is_sync_needed( return(false); } -#if 0 -/*********************************************************************//** -Check whether a table needs to be optimized. */ -static -void -fts_optimize_need_sync( -/*===================*/ - ib_vector_t* tables) /*!< in: list of tables */ -{ - dict_table_t* table = NULL; - fts_slot_t* slot; - ulint num_table = ib_vector_size(tables); - - if (!num_table) { - return; - } - - if (fts_optimize_sync_iterator >= num_table) { - fts_optimize_sync_iterator = 0; - } - - slot = ib_vector_get(tables, fts_optimize_sync_iterator); - table = slot->table; - - if (!table) { - return; - } - - ut_ad(table->fts); - - if (table->fts->cache) { - ulint deleted = table->fts->cache->deleted; - - if (table->fts->cache->added - >= fts_optimize_add_threshold) { - fts_sync_table(table); - } else if (deleted >= fts_optimize_delete_threshold) { - fts_optimize_do_table(table); - - mutex_enter(&table->fts->cache->deleted_lock); - table->fts->cache->deleted -= deleted; - mutex_exit(&table->fts->cache->deleted_lock); - } - } - - fts_optimize_sync_iterator++; - - return; -} -#endif - /** Sync fts cache of a table @param[in] table_id table id */ void @@ -2975,7 +2840,7 @@ fts_optimize_sync_table( if (table) { if (dict_table_has_fts_index(table) && table->fts->cache) { - fts_sync_table(table, true, false, true); + fts_sync_table(table, true, false, false); } dict_table_close(table, FALSE, FALSE); @@ -3047,8 +2912,7 @@ fts_optimize_thread( fts_msg_t* msg; msg = static_cast( - ib_wqueue_timedwait(wq, - FTS_QUEUE_WAIT_IN_USECS)); + ib_wqueue_timedwait(wq, FTS_QUEUE_WAIT_IN_USECS)); /* Timeout ? */ if (msg == NULL) { @@ -3060,12 +2924,6 @@ fts_optimize_thread( } switch (msg->type) { - case FTS_MSG_START: - break; - - case FTS_MSG_PAUSE: - break; - case FTS_MSG_STOP: done = TRUE; exit_event = (os_event_t) msg->ptr; @@ -3081,15 +2939,6 @@ fts_optimize_thread( } break; - case FTS_MSG_OPTIMIZE_TABLE: - if (!done) { - fts_optimize_start_table( - tables, - static_cast( - msg->ptr)); - } - break; - case FTS_MSG_DEL_TABLE: if (fts_optimize_del_table( tables, static_cast( @@ -3104,6 +2953,10 @@ fts_optimize_thread( break; case FTS_MSG_SYNC_TABLE: + DBUG_EXECUTE_IF( + "fts_instrument_msg_sync_sleep", + os_thread_sleep(300000);); + fts_optimize_sync_table( *static_cast(msg->ptr)); break; @@ -3163,7 +3016,7 @@ fts_optimize_init(void) ut_ad(!srv_read_only_mode); /* For now we only support one optimize thread. */ - ut_a(fts_optimize_wq == NULL); + ut_a(!fts_optimize_is_init()); fts_optimize_wq = ib_wqueue_create(); ut_a(fts_optimize_wq != NULL); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 3de46ed4f80..6a3e9575eb1 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -5710,24 +5710,24 @@ ha_innobase::commit_inplace_alter_table( trx_t* trx = ctx0->trx; bool fail = false; - if (new_clustered) { - for (inplace_alter_handler_ctx** pctx = ctx_array; - *pctx; pctx++) { - ha_innobase_inplace_ctx* ctx - = static_cast(*pctx); - DBUG_ASSERT(ctx->need_rebuild()); + /* Stop background FTS operations. */ + for (inplace_alter_handler_ctx** pctx = ctx_array; + *pctx; pctx++) { + ha_innobase_inplace_ctx* ctx + = static_cast(*pctx); + DBUG_ASSERT(new_clustered == ctx->need_rebuild()); + + if (new_clustered) { if (ctx->old_table->fts) { ut_ad(!ctx->old_table->fts->add_wq); - fts_optimize_remove_table( - ctx->old_table); + fts_optimize_remove_table(ctx->old_table); } + } - if (ctx->new_table->fts) { - ut_ad(!ctx->new_table->fts->add_wq); - fts_optimize_remove_table( - ctx->new_table); - } + if (ctx->new_table->fts) { + ut_ad(!ctx->new_table->fts->add_wq); + fts_optimize_remove_table(ctx->new_table); } } @@ -5772,41 +5772,40 @@ ha_innobase::commit_inplace_alter_table( /* Make a concurrent Drop fts Index to wait until sync of that fts index is happening in the background */ - for (;;) { + for (int retry_count = 0;;) { bool retry = false; for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx; pctx++) { - int count =0; ha_innobase_inplace_ctx* ctx = static_cast(*pctx); DBUG_ASSERT(new_clustered == ctx->need_rebuild()); if (dict_fts_index_syncing(ctx->old_table)) { - count++; - if (count == 100) { - fprintf(stderr, - "Drop index waiting for background sync" - "to finish\n"); - } retry = true; + break; } if (new_clustered && dict_fts_index_syncing(ctx->new_table)) { - count++; - if (count == 100) { - fprintf(stderr, - "Drop index waiting for background sync" - "to finish\n"); - } retry = true; + break; } } - if (!retry) { + if (!retry) { break; } + /* Print a message if waiting for a long time. */ + if (retry_count < 100) { + retry_count++; + } else { + ib_logf(IB_LOG_LEVEL_INFO, + "Drop index waiting for background sync" + " to finish"); + retry_count = 0; + } + DICT_BG_YIELD(trx); } @@ -6070,6 +6069,11 @@ foreign_fail: ut_a(fts_check_cached_index(ctx->old_table)); DBUG_INJECT_CRASH("ib_commit_inplace_crash_fail", crash_fail_inject_count++); + + /* Restart the FTS background operations. */ + if (ctx->old_table->fts) { + fts_optimize_add_table(ctx->old_table); + } } row_mysql_unlock_data_dictionary(trx); @@ -6118,8 +6122,6 @@ foreign_fail: dict_table_autoinc_unlock(t); } - bool add_fts = false; - /* Publish the created fulltext index, if any. Note that a fulltext index can be created without creating the clustered index, if there already exists @@ -6134,14 +6136,14 @@ foreign_fail: is left unset when a drop proceeds the add. */ DICT_TF2_FLAG_SET(ctx->new_table, DICT_TF2_FTS); fts_add_index(index, ctx->new_table); - add_fts = true; } } ut_d(dict_table_check_for_dup_indexes( ctx->new_table, CHECK_ALL_COMPLETE)); - if (add_fts) { + /* Start/Restart the FTS background operations. */ + if (ctx->new_table->fts) { fts_optimize_add_table(ctx->new_table); } diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index cd94956dc55..4c2d247e0a6 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2016, 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -705,6 +705,12 @@ fts_drop_index_tables( dict_index_t* index) /*!< in: Index to drop */ MY_ATTRIBUTE((nonnull, warn_unused_result)); +/** Add the table to add to the OPTIMIZER's list. +@param[in] table table to add */ +void +fts_optimize_add_table( + dict_table_t* table); + /******************************************************************//** Remove the table from the OPTIMIZER's list. We do wait for acknowledgement from the consumer of the message. */ diff --git a/storage/innobase/include/fts0priv.h b/storage/innobase/include/fts0priv.h index 2d4e9d88fd1..a3936f54a48 100644 --- a/storage/innobase/include/fts0priv.h +++ b/storage/innobase/include/fts0priv.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 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 the Free Software @@ -598,22 +598,6 @@ fts_get_table_id( long */ MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** -Add the table to add to the OPTIMIZER's list. */ -UNIV_INTERN -void -fts_optimize_add_table( -/*===================*/ - dict_table_t* table) /*!< in: table to add */ - MY_ATTRIBUTE((nonnull)); -/******************************************************************//** -Optimize a table. */ -UNIV_INTERN -void -fts_optimize_do_table( -/*==================*/ - dict_table_t* table) /*!< in: table to optimize */ - MY_ATTRIBUTE((nonnull)); -/******************************************************************//** Construct the prefix name of an FTS table. @return own: table name, must be freed with mem_free() */ UNIV_INTERN diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index bb1a27be4ba..87d40ee2ba4 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3309,6 +3309,10 @@ row_truncate_table_for_mysql( return(DB_TABLESPACE_NOT_FOUND); } + if (table->fts) { + fts_optimize_remove_table(table); + } + trx_start_for_ddl(trx, TRX_DICT_OP_TABLE); trx->op_info = "truncating table"; @@ -3709,6 +3713,9 @@ next_rec: /* Reset the Doc ID in cache to 0 */ if (has_internal_doc_id && table->fts->cache) { + DBUG_EXECUTE_IF("ib_trunc_sleep_before_fts_cache_clear", + os_thread_sleep(10000000);); + table->fts->fts_status |= TABLE_DICT_LOCKED; fts_update_next_doc_id(trx, table, NULL, 0); fts_cache_clear(table->fts->cache); @@ -3732,6 +3739,11 @@ funct_exit: table->memcached_sync_count = 0; } + /* Add the table back to FTS optimize background thread. */ + if (table->fts) { + fts_optimize_add_table(table); + } + row_mysql_unlock_data_dictionary(trx); dict_stats_update(table, DICT_STATS_EMPTY_TABLE); diff --git a/storage/xtradb/fts/fts0fts.cc b/storage/xtradb/fts/fts0fts.cc index 36a1d234bf4..2f9e331219b 100644 --- a/storage/xtradb/fts/fts0fts.cc +++ b/storage/xtradb/fts/fts0fts.cc @@ -268,7 +268,7 @@ FTS auxiliary INDEX table and clear the cache at the end. @param[in,out] sync sync state @param[in] unlock_cache whether unlock cache lock when write node @param[in] wait whether wait when a sync is in progress -@param[in] has_dict whether has dict operation lock +@param[in] has_dict whether has dict operation lock @return DB_SUCCESS if all OK */ static dberr_t @@ -3961,6 +3961,9 @@ fts_sync_write_words( word = rbt_value(fts_tokenizer_word_t, rbt_node); + DBUG_EXECUTE_IF("fts_instrument_write_words_before_select_index", + os_thread_sleep(300000);); + selected = fts_select_index( index_cache->charset, word->text.f_str, word->text.f_len); @@ -4525,7 +4528,7 @@ FTS auxiliary INDEX table and clear the cache at the end. @param[in,out] sync sync state @param[in] unlock_cache whether unlock cache lock when write node @param[in] wait whether wait when a sync is in progress -@param[in] has_dict whether has dict operation lock +@param[in] has_dict whether has dict operation lock @return DB_SUCCESS if all OK */ static dberr_t @@ -4587,15 +4590,13 @@ begin_sync: continue; } + DBUG_EXECUTE_IF("fts_instrument_sync_before_syncing", + os_thread_sleep(300000);); index_cache->index->index_fts_syncing = true; - DBUG_EXECUTE_IF("fts_instrument_sync_sleep_drop_waits", - os_thread_sleep(10000000); - ); error = fts_sync_index(sync, index_cache); - if (error != DB_SUCCESS && !sync->interrupted) { - + if (error != DB_SUCCESS) { goto end_sync; } } @@ -4630,8 +4631,8 @@ end_sync: } rw_lock_x_lock(&cache->lock); - /* Clear fts syncing flags of any indexes incase sync is - interrupeted */ + /* Clear fts syncing flags of any indexes in case sync is + interrupted */ for (i = 0; i < ib_vector_size(cache->indexes); ++i) { static_cast( ib_vector_get(cache->indexes, i)) diff --git a/storage/xtradb/fts/fts0opt.cc b/storage/xtradb/fts/fts0opt.cc index d9f96948000..77293bc867a 100644 --- a/storage/xtradb/fts/fts0opt.cc +++ b/storage/xtradb/fts/fts0opt.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2016, MariaDB Corporation. All Rights reserved. This program is free software; you can redistribute it and/or modify it under @@ -58,12 +58,6 @@ static const ulint FTS_WORD_NODES_INIT_SIZE = 64; /** Last time we did check whether system need a sync */ static ib_time_t last_check_sync_time; -#if 0 -/** Check each table in round robin to see whether they'd -need to be "optimized" */ -static ulint fts_optimize_sync_iterator = 0; -#endif - /** State of a table within the optimization sub system. */ enum fts_state_t { FTS_STATE_LOADED, @@ -75,17 +69,11 @@ enum fts_state_t { /** FTS optimize thread message types. */ enum fts_msg_type_t { - FTS_MSG_START, /*!< Start optimizing thread */ - - FTS_MSG_PAUSE, /*!< Pause optimizing thread */ - FTS_MSG_STOP, /*!< Stop optimizing and exit thread */ FTS_MSG_ADD_TABLE, /*!< Add table to the optimize thread's work queue */ - FTS_MSG_OPTIMIZE_TABLE, /*!< Optimize a table */ - FTS_MSG_DEL_TABLE, /*!< Remove a table from the optimize threads work queue */ FTS_MSG_SYNC_TABLE /*!< Sync fts cache of a table */ @@ -235,7 +223,7 @@ struct fts_msg_t { /** The number of words to read and optimize in a single pass. */ UNIV_INTERN ulong fts_num_word_optimize; -// FIXME +/** Whether to enable additional FTS diagnostic printout. */ UNIV_INTERN char fts_enable_diag_print; /** ZLib compressed block size.*/ @@ -2560,13 +2548,9 @@ fts_optimize_create_msg( return(msg); } -/**********************************************************************//** -Add the table to add to the OPTIMIZER's list. */ -UNIV_INTERN -void -fts_optimize_add_table( -/*===================*/ - dict_table_t* table) /*!< in: table to add */ +/** Add the table to add to the OPTIMIZER's list. +@param[in] table table to add */ +UNIV_INTERN void fts_optimize_add_table(dict_table_t* table) { fts_msg_t* msg; @@ -2584,26 +2568,6 @@ fts_optimize_add_table( ib_wqueue_add(fts_optimize_wq, msg, msg->heap); } -/**********************************************************************//** -Optimize a table. */ -UNIV_INTERN -void -fts_optimize_do_table( -/*==================*/ - dict_table_t* table) /*!< in: table to optimize */ -{ - fts_msg_t* msg; - - /* Optimizer thread could be shutdown */ - if (!fts_optimize_wq) { - return; - } - - msg = fts_optimize_create_msg(FTS_MSG_OPTIMIZE_TABLE, table); - - ib_wqueue_add(fts_optimize_wq, msg, msg->heap); -} - /**********************************************************************//** Remove the table from the OPTIMIZER's list. We do wait for acknowledgement from the consumer of the message. */ @@ -2618,7 +2582,7 @@ fts_optimize_remove_table( fts_msg_del_t* remove; /* if the optimize system not yet initialized, return */ - if (!fts_optimize_wq) { + if (!fts_optimize_is_init()) { return; } @@ -2660,7 +2624,7 @@ fts_optimize_request_sync_table( table_id_t* table_id; /* if the optimize system not yet initialized, return */ - if (!fts_optimize_wq) { + if (!fts_optimize_is_init()) { return; } @@ -2682,54 +2646,6 @@ fts_optimize_request_sync_table( ib_wqueue_add(fts_optimize_wq, msg, msg->heap); } -/**********************************************************************//** -Find the slot for a particular table. -@return slot if found else NULL. */ -static -fts_slot_t* -fts_optimize_find_slot( -/*===================*/ - ib_vector_t* tables, /*!< in: vector of tables */ - const dict_table_t* table) /*!< in: table to add */ -{ - ulint i; - - for (i = 0; i < ib_vector_size(tables); ++i) { - fts_slot_t* slot; - - slot = static_cast(ib_vector_get(tables, i)); - - if (slot->table->id == table->id) { - return(slot); - } - } - - return(NULL); -} - -/**********************************************************************//** -Start optimizing table. */ -static -void -fts_optimize_start_table( -/*=====================*/ - ib_vector_t* tables, /*!< in/out: vector of tables */ - dict_table_t* table) /*!< in: table to optimize */ -{ - fts_slot_t* slot; - - slot = fts_optimize_find_slot(tables, table); - - if (slot == NULL) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error: table %s not registered " - "with the optimize thread.\n", table->name); - } else { - slot->last_run = 0; - slot->completed = 0; - } -} - /**********************************************************************//** Add the table to the vector if it doesn't already exist. */ static @@ -2912,57 +2828,6 @@ fts_is_sync_needed( return(false); } -#if 0 -/*********************************************************************//** -Check whether a table needs to be optimized. */ -static -void -fts_optimize_need_sync( -/*===================*/ - ib_vector_t* tables) /*!< in: list of tables */ -{ - dict_table_t* table = NULL; - fts_slot_t* slot; - ulint num_table = ib_vector_size(tables); - - if (!num_table) { - return; - } - - if (fts_optimize_sync_iterator >= num_table) { - fts_optimize_sync_iterator = 0; - } - - slot = ib_vector_get(tables, fts_optimize_sync_iterator); - table = slot->table; - - if (!table) { - return; - } - - ut_ad(table->fts); - - if (table->fts->cache) { - ulint deleted = table->fts->cache->deleted; - - if (table->fts->cache->added - >= fts_optimize_add_threshold) { - fts_sync_table(table); - } else if (deleted >= fts_optimize_delete_threshold) { - fts_optimize_do_table(table); - - mutex_enter(&table->fts->cache->deleted_lock); - table->fts->cache->deleted -= deleted; - mutex_exit(&table->fts->cache->deleted_lock); - } - } - - fts_optimize_sync_iterator++; - - return; -} -#endif - /** Sync fts cache of a table @param[in] table_id table id */ void @@ -2975,7 +2840,7 @@ fts_optimize_sync_table( if (table) { if (dict_table_has_fts_index(table) && table->fts->cache) { - fts_sync_table(table, true, false, true); + fts_sync_table(table, true, false, false); } dict_table_close(table, FALSE, FALSE); @@ -3047,8 +2912,7 @@ fts_optimize_thread( fts_msg_t* msg; msg = static_cast( - ib_wqueue_timedwait(wq, - FTS_QUEUE_WAIT_IN_USECS)); + ib_wqueue_timedwait(wq, FTS_QUEUE_WAIT_IN_USECS)); /* Timeout ? */ if (msg == NULL) { @@ -3060,12 +2924,6 @@ fts_optimize_thread( } switch (msg->type) { - case FTS_MSG_START: - break; - - case FTS_MSG_PAUSE: - break; - case FTS_MSG_STOP: done = TRUE; exit_event = (os_event_t) msg->ptr; @@ -3081,15 +2939,6 @@ fts_optimize_thread( } break; - case FTS_MSG_OPTIMIZE_TABLE: - if (!done) { - fts_optimize_start_table( - tables, - static_cast( - msg->ptr)); - } - break; - case FTS_MSG_DEL_TABLE: if (fts_optimize_del_table( tables, static_cast( @@ -3104,6 +2953,10 @@ fts_optimize_thread( break; case FTS_MSG_SYNC_TABLE: + DBUG_EXECUTE_IF( + "fts_instrument_msg_sync_sleep", + os_thread_sleep(300000);); + fts_optimize_sync_table( *static_cast(msg->ptr)); break; @@ -3163,7 +3016,7 @@ fts_optimize_init(void) ut_ad(!srv_read_only_mode); /* For now we only support one optimize thread. */ - ut_a(fts_optimize_wq == NULL); + ut_a(!fts_optimize_is_init()); fts_optimize_wq = ib_wqueue_create(); ut_a(fts_optimize_wq != NULL); diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index 151c3237b2b..bc6a6dd68d4 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -5726,24 +5726,24 @@ ha_innobase::commit_inplace_alter_table( trx_t* trx = ctx0->trx; bool fail = false; - if (new_clustered) { - for (inplace_alter_handler_ctx** pctx = ctx_array; - *pctx; pctx++) { - ha_innobase_inplace_ctx* ctx - = static_cast(*pctx); - DBUG_ASSERT(ctx->need_rebuild()); + /* Stop background FTS operations. */ + for (inplace_alter_handler_ctx** pctx = ctx_array; + *pctx; pctx++) { + ha_innobase_inplace_ctx* ctx + = static_cast(*pctx); + DBUG_ASSERT(new_clustered == ctx->need_rebuild()); + + if (new_clustered) { if (ctx->old_table->fts) { ut_ad(!ctx->old_table->fts->add_wq); - fts_optimize_remove_table( - ctx->old_table); + fts_optimize_remove_table(ctx->old_table); } + } - if (ctx->new_table->fts) { - ut_ad(!ctx->new_table->fts->add_wq); - fts_optimize_remove_table( - ctx->new_table); - } + if (ctx->new_table->fts) { + ut_ad(!ctx->new_table->fts->add_wq); + fts_optimize_remove_table(ctx->new_table); } } @@ -5788,41 +5788,40 @@ ha_innobase::commit_inplace_alter_table( /* Make a concurrent Drop fts Index to wait until sync of that fts index is happening in the background */ - for (;;) { + for (int retry_count = 0;;) { bool retry = false; for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx; pctx++) { - int count =0; ha_innobase_inplace_ctx* ctx = static_cast(*pctx); DBUG_ASSERT(new_clustered == ctx->need_rebuild()); if (dict_fts_index_syncing(ctx->old_table)) { - count++; - if (count == 100) { - fprintf(stderr, - "Drop index waiting for background sync" - "to finish\n"); - } retry = true; + break; } if (new_clustered && dict_fts_index_syncing(ctx->new_table)) { - count++; - if (count == 100) { - fprintf(stderr, - "Drop index waiting for background sync" - "to finish\n"); - } retry = true; + break; } } - if (!retry) { + if (!retry) { break; } + /* Print a message if waiting for a long time. */ + if (retry_count < 100) { + retry_count++; + } else { + ib_logf(IB_LOG_LEVEL_INFO, + "Drop index waiting for background sync" + " to finish"); + retry_count = 0; + } + DICT_BG_YIELD(trx); } @@ -6086,6 +6085,11 @@ foreign_fail: ut_a(fts_check_cached_index(ctx->old_table)); DBUG_INJECT_CRASH("ib_commit_inplace_crash_fail", crash_fail_inject_count++); + + /* Restart the FTS background operations. */ + if (ctx->old_table->fts) { + fts_optimize_add_table(ctx->old_table); + } } row_mysql_unlock_data_dictionary(trx); @@ -6134,8 +6138,6 @@ foreign_fail: dict_table_autoinc_unlock(t); } - bool add_fts = false; - /* Publish the created fulltext index, if any. Note that a fulltext index can be created without creating the clustered index, if there already exists @@ -6150,14 +6152,14 @@ foreign_fail: is left unset when a drop proceeds the add. */ DICT_TF2_FLAG_SET(ctx->new_table, DICT_TF2_FTS); fts_add_index(index, ctx->new_table); - add_fts = true; } } ut_d(dict_table_check_for_dup_indexes( ctx->new_table, CHECK_ALL_COMPLETE)); - if (add_fts) { + /* Start/Restart the FTS background operations. */ + if (ctx->new_table->fts) { fts_optimize_add_table(ctx->new_table); } diff --git a/storage/xtradb/include/fts0fts.h b/storage/xtradb/include/fts0fts.h index cd94956dc55..4c2d247e0a6 100644 --- a/storage/xtradb/include/fts0fts.h +++ b/storage/xtradb/include/fts0fts.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2016, 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -705,6 +705,12 @@ fts_drop_index_tables( dict_index_t* index) /*!< in: Index to drop */ MY_ATTRIBUTE((nonnull, warn_unused_result)); +/** Add the table to add to the OPTIMIZER's list. +@param[in] table table to add */ +void +fts_optimize_add_table( + dict_table_t* table); + /******************************************************************//** Remove the table from the OPTIMIZER's list. We do wait for acknowledgement from the consumer of the message. */ diff --git a/storage/xtradb/include/fts0priv.h b/storage/xtradb/include/fts0priv.h index 2d4e9d88fd1..a3936f54a48 100644 --- a/storage/xtradb/include/fts0priv.h +++ b/storage/xtradb/include/fts0priv.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 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 the Free Software @@ -598,22 +598,6 @@ fts_get_table_id( long */ MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** -Add the table to add to the OPTIMIZER's list. */ -UNIV_INTERN -void -fts_optimize_add_table( -/*===================*/ - dict_table_t* table) /*!< in: table to add */ - MY_ATTRIBUTE((nonnull)); -/******************************************************************//** -Optimize a table. */ -UNIV_INTERN -void -fts_optimize_do_table( -/*==================*/ - dict_table_t* table) /*!< in: table to optimize */ - MY_ATTRIBUTE((nonnull)); -/******************************************************************//** Construct the prefix name of an FTS table. @return own: table name, must be freed with mem_free() */ UNIV_INTERN diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc index cb496965f01..44e358aab89 100644 --- a/storage/xtradb/row/row0mysql.cc +++ b/storage/xtradb/row/row0mysql.cc @@ -3328,6 +3328,10 @@ row_truncate_table_for_mysql( return(DB_TABLESPACE_NOT_FOUND); } + if (table->fts) { + fts_optimize_remove_table(table); + } + trx_start_for_ddl(trx, TRX_DICT_OP_TABLE); trx->op_info = "truncating table"; @@ -3734,6 +3738,9 @@ next_rec: /* Reset the Doc ID in cache to 0 */ if (has_internal_doc_id && table->fts->cache) { + DBUG_EXECUTE_IF("ib_trunc_sleep_before_fts_cache_clear", + os_thread_sleep(10000000);); + table->fts->fts_status |= TABLE_DICT_LOCKED; fts_update_next_doc_id(trx, table, NULL, 0); fts_cache_clear(table->fts->cache); @@ -3757,6 +3764,11 @@ funct_exit: table->memcached_sync_count = 0; } + /* Add the table back to FTS optimize background thread. */ + if (table->fts) { + fts_optimize_add_table(table); + } + row_mysql_unlock_data_dictionary(trx); dict_stats_update(table, DICT_STATS_EMPTY_TABLE); From e023f9a4d5a620b54d7f7132567150d80b630692 Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Tue, 31 Jul 2018 15:19:01 +0300 Subject: [PATCH 69/71] Unstable tests for 10.0.36 release, latest additions --- mysql-test/unstable-tests | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mysql-test/unstable-tests b/mysql-test/unstable-tests index 5fa6f6653c3..e8bb02f51e0 100644 --- a/mysql-test/unstable-tests +++ b/mysql-test/unstable-tests @@ -23,7 +23,7 @@ # ############################################################################## -# Based on 10.0 5e67567b158db5d294b11b310ff35a454f58d034 +# Based on 10.0 e52315a4a2c7e752e786f9fcf63b0b5685b0d474 main.alter_table : Modified in 10.0.36 main.assign_key_cache : Added in 10.0.36 @@ -89,12 +89,15 @@ main.statistics : Modified in 10.0.36 main.statistics_close : Added in 10.0.36 main.stat_tables : Modified in 10.0.36 main.stat_tables_par_innodb : MDEV-14155 - wrong rounding +main.subselect : Modified in 10.0.36 main.subselect_innodb : MDEV-10614 - sporadic wrong results main.subselect_sj : Modified in 10.0.36 +main.subselect_sj_mat : Modified in 10.0.36 main.subselect_sj2_mat : Modified in 10.0.36 main.subselect4 : Modified in 10.0.36 main.tc_heuristic_recover : MDEV-15200 - wrong error on mysqld_stub_cmd main.type_datetime : MDEV-14322 - wrong result +main.union : Modified in 10.0.36 main.xa : MDEV-11769 - lock wait timeout #---------------------------------------------------------------- @@ -159,6 +162,7 @@ innodb.innodb_bug48024 : MDEV-14352 - Assertion failure innodb.innodb_bug54044 : Modified in 10.0.36 innodb.innodb-mdev7046 : Modified in 10.0.36 innodb.innodb_monitor : MDEV-10939 - Testcase timeout +innodb.innodb-wl5522 : Modified in 10.0.36 innodb.log_file_size : MDEV-15668 - Not found pattern innodb.recovery_shutdown : MDEV-15671 - Warning: database page corruption innodb.rename_table : Added in 10.0.36 @@ -168,6 +172,7 @@ innodb.xa_recovery : MDEV-15279 - mysqld got exception innodb_fts.basic : Added in 10.0.36 innodb_fts.innodb-fts-fic : MDEV-14154 - Assertion failure innodb_fts.innodb_fts_misc_debug : MDEV-14156 - Unexpected warning +innodb_fts.sync_ddl : Added in 10.0.36 #---------------------------------------------------------------- @@ -214,7 +219,7 @@ perfschema_stress.* : MDEV-10996 - tests not maintained #---------------------------------------------------------------- plugins.feedback_plugin_send : MDEV-7932 - ssl failed for url, MDEV-11118 - wrong result -plugins.processlist : MDEV-16818 - Syntax error; added in 10.0.36 +plugins.processlist : MDEV-16818 - Added in 10.0.36 plugins.server_audit : MDEV-9562 - crashes on sol10-sparc; modified in 10.0.36 plugins.thread_pool_server_audit : MDEV-9562 - crashes on sol10-sparc, MDEV-14295 - wrong result From b3e95086e1188dc86e67e44d0fe5a68ea2feca99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 31 Jul 2018 14:29:05 +0300 Subject: [PATCH 70/71] Fix function pointer type mismatch --- storage/innobase/fts/fts0pars.cc | 16 ++++++++-------- storage/innobase/fts/fts0pars.y | 16 ++++++++-------- storage/xtradb/fts/fts0pars.cc | 16 ++++++++-------- storage/xtradb/fts/fts0pars.y | 16 ++++++++-------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/storage/innobase/fts/fts0pars.cc b/storage/innobase/fts/fts0pars.cc index 7f0ba4e0c1b..19917ccd26a 100644 --- a/storage/innobase/fts/fts0pars.cc +++ b/storage/innobase/fts/fts0pars.cc @@ -87,7 +87,7 @@ extern int fts_lexer(YYSTYPE*, fts_lexer_t*); extern int fts_blexer(YYSTYPE*, yyscan_t); extern int fts_tlexer(YYSTYPE*, yyscan_t); -typedef int (*fts_scan)(); + extern int ftserror(const char* p); @@ -102,8 +102,8 @@ extern int ftserror(const char* p); #define YYTOKENFREE(token) fts_ast_string_free((token)) -typedef int (*fts_scanner_alt)(YYSTYPE* val, yyscan_t yyscanner); -typedef int (*fts_scanner)(); + +typedef int (*fts_scanner)(YYSTYPE* val, yyscan_t yyscanner); struct fts_lexer_t { fts_scanner scanner; @@ -1950,7 +1950,7 @@ fts_lexer_create( reinterpret_cast(query), static_cast(query_len), fts_lexer->yyscanner); - fts_lexer->scanner = reinterpret_cast(fts_blexer); + fts_lexer->scanner = fts_blexer; /* FIXME: Debugging */ /* fts0bset_debug(1 , fts_lexer->yyscanner); */ } else { @@ -1959,7 +1959,7 @@ fts_lexer_create( reinterpret_cast(query), static_cast(query_len), fts_lexer->yyscanner); - fts_lexer->scanner = reinterpret_cast(fts_tlexer); + fts_lexer->scanner = fts_tlexer; } return(fts_lexer); @@ -1973,7 +1973,7 @@ fts_lexer_free( /*===========*/ fts_lexer_t* fts_lexer) { - if (fts_lexer->scanner == (fts_scan) fts_blexer) { + if (fts_lexer->scanner == fts_blexer) { fts0blex_destroy(fts_lexer->yyscanner); } else { fts0tlex_destroy(fts_lexer->yyscanner); @@ -1991,9 +1991,9 @@ fts_lexer( YYSTYPE* val, fts_lexer_t* fts_lexer) { - fts_scanner_alt func_ptr; + fts_scanner func_ptr; - func_ptr = (fts_scanner_alt) fts_lexer->scanner; + func_ptr = fts_lexer->scanner; return(func_ptr(val, fts_lexer->yyscanner)); } diff --git a/storage/innobase/fts/fts0pars.y b/storage/innobase/fts/fts0pars.y index e48036e82fe..65c4189eece 100644 --- a/storage/innobase/fts/fts0pars.y +++ b/storage/innobase/fts/fts0pars.y @@ -35,7 +35,7 @@ extern int fts_lexer(YYSTYPE*, fts_lexer_t*); extern int fts_blexer(YYSTYPE*, yyscan_t); extern int fts_tlexer(YYSTYPE*, yyscan_t); -typedef int (*fts_scan)(); + extern int ftserror(const char* p); @@ -48,8 +48,8 @@ extern int ftserror(const char* p); #define YYPARSE_PARAM state #define YYLEX_PARAM ((fts_ast_state_t*) state)->lexer -typedef int (*fts_scanner_alt)(YYSTYPE* val, yyscan_t yyscanner); -typedef int (*fts_scanner)(); + +typedef int (*fts_scanner)(YYSTYPE* val, yyscan_t yyscanner); struct fts_lexer_struct { fts_scanner scanner; @@ -238,13 +238,13 @@ fts_lexer_create( if (boolean_mode) { fts0blex_init(&fts_lexer->yyscanner); fts0b_scan_bytes((char*) query, query_len, fts_lexer->yyscanner); - fts_lexer->scanner = (fts_scan) fts_blexer; + fts_lexer->scanner = fts_blexer; /* FIXME: Debugging */ /* fts0bset_debug(1 , fts_lexer->yyscanner); */ } else { fts0tlex_init(&fts_lexer->yyscanner); fts0t_scan_bytes((char*) query, query_len, fts_lexer->yyscanner); - fts_lexer->scanner = (fts_scan) fts_tlexer; + fts_lexer->scanner = fts_tlexer; } return(fts_lexer); @@ -258,7 +258,7 @@ fts_lexer_free( /*===========*/ fts_lexer_t* fts_lexer) { - if (fts_lexer->scanner == (fts_scan) fts_blexer) { + if (fts_lexer->scanner == fts_blexer) { fts0blex_destroy(fts_lexer->yyscanner); } else { fts0tlex_destroy(fts_lexer->yyscanner); @@ -276,9 +276,9 @@ fts_lexer( YYSTYPE* val, fts_lexer_t* fts_lexer) { - fts_scanner_alt func_ptr; + fts_scanner func_ptr; - func_ptr = (fts_scanner_alt) fts_lexer->scanner; + func_ptr = fts_lexer->scanner; return(func_ptr(val, fts_lexer->yyscanner)); } diff --git a/storage/xtradb/fts/fts0pars.cc b/storage/xtradb/fts/fts0pars.cc index 7f0ba4e0c1b..19917ccd26a 100644 --- a/storage/xtradb/fts/fts0pars.cc +++ b/storage/xtradb/fts/fts0pars.cc @@ -87,7 +87,7 @@ extern int fts_lexer(YYSTYPE*, fts_lexer_t*); extern int fts_blexer(YYSTYPE*, yyscan_t); extern int fts_tlexer(YYSTYPE*, yyscan_t); -typedef int (*fts_scan)(); + extern int ftserror(const char* p); @@ -102,8 +102,8 @@ extern int ftserror(const char* p); #define YYTOKENFREE(token) fts_ast_string_free((token)) -typedef int (*fts_scanner_alt)(YYSTYPE* val, yyscan_t yyscanner); -typedef int (*fts_scanner)(); + +typedef int (*fts_scanner)(YYSTYPE* val, yyscan_t yyscanner); struct fts_lexer_t { fts_scanner scanner; @@ -1950,7 +1950,7 @@ fts_lexer_create( reinterpret_cast(query), static_cast(query_len), fts_lexer->yyscanner); - fts_lexer->scanner = reinterpret_cast(fts_blexer); + fts_lexer->scanner = fts_blexer; /* FIXME: Debugging */ /* fts0bset_debug(1 , fts_lexer->yyscanner); */ } else { @@ -1959,7 +1959,7 @@ fts_lexer_create( reinterpret_cast(query), static_cast(query_len), fts_lexer->yyscanner); - fts_lexer->scanner = reinterpret_cast(fts_tlexer); + fts_lexer->scanner = fts_tlexer; } return(fts_lexer); @@ -1973,7 +1973,7 @@ fts_lexer_free( /*===========*/ fts_lexer_t* fts_lexer) { - if (fts_lexer->scanner == (fts_scan) fts_blexer) { + if (fts_lexer->scanner == fts_blexer) { fts0blex_destroy(fts_lexer->yyscanner); } else { fts0tlex_destroy(fts_lexer->yyscanner); @@ -1991,9 +1991,9 @@ fts_lexer( YYSTYPE* val, fts_lexer_t* fts_lexer) { - fts_scanner_alt func_ptr; + fts_scanner func_ptr; - func_ptr = (fts_scanner_alt) fts_lexer->scanner; + func_ptr = fts_lexer->scanner; return(func_ptr(val, fts_lexer->yyscanner)); } diff --git a/storage/xtradb/fts/fts0pars.y b/storage/xtradb/fts/fts0pars.y index e48036e82fe..65c4189eece 100644 --- a/storage/xtradb/fts/fts0pars.y +++ b/storage/xtradb/fts/fts0pars.y @@ -35,7 +35,7 @@ extern int fts_lexer(YYSTYPE*, fts_lexer_t*); extern int fts_blexer(YYSTYPE*, yyscan_t); extern int fts_tlexer(YYSTYPE*, yyscan_t); -typedef int (*fts_scan)(); + extern int ftserror(const char* p); @@ -48,8 +48,8 @@ extern int ftserror(const char* p); #define YYPARSE_PARAM state #define YYLEX_PARAM ((fts_ast_state_t*) state)->lexer -typedef int (*fts_scanner_alt)(YYSTYPE* val, yyscan_t yyscanner); -typedef int (*fts_scanner)(); + +typedef int (*fts_scanner)(YYSTYPE* val, yyscan_t yyscanner); struct fts_lexer_struct { fts_scanner scanner; @@ -238,13 +238,13 @@ fts_lexer_create( if (boolean_mode) { fts0blex_init(&fts_lexer->yyscanner); fts0b_scan_bytes((char*) query, query_len, fts_lexer->yyscanner); - fts_lexer->scanner = (fts_scan) fts_blexer; + fts_lexer->scanner = fts_blexer; /* FIXME: Debugging */ /* fts0bset_debug(1 , fts_lexer->yyscanner); */ } else { fts0tlex_init(&fts_lexer->yyscanner); fts0t_scan_bytes((char*) query, query_len, fts_lexer->yyscanner); - fts_lexer->scanner = (fts_scan) fts_tlexer; + fts_lexer->scanner = fts_tlexer; } return(fts_lexer); @@ -258,7 +258,7 @@ fts_lexer_free( /*===========*/ fts_lexer_t* fts_lexer) { - if (fts_lexer->scanner == (fts_scan) fts_blexer) { + if (fts_lexer->scanner == fts_blexer) { fts0blex_destroy(fts_lexer->yyscanner); } else { fts0tlex_destroy(fts_lexer->yyscanner); @@ -276,9 +276,9 @@ fts_lexer( YYSTYPE* val, fts_lexer_t* fts_lexer) { - fts_scanner_alt func_ptr; + fts_scanner func_ptr; - func_ptr = (fts_scanner_alt) fts_lexer->scanner; + func_ptr = fts_lexer->scanner; return(func_ptr(val, fts_lexer->yyscanner)); } From a7f84f09bfec22e26b3bd54505a9c8e1d0faff40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 31 Jul 2018 16:12:38 +0300 Subject: [PATCH 71/71] MDEV-16865 InnoDB fts_query() ignores KILL The functions fts_ast_visit() and fts_query() inside InnoDB FULLTEXT INDEX query processing are not checking for THD::killed (trx_is_interrupted()), like anything that potentially takes a long time should do. This is a port of the following change from MySQL 5.7.23, with a completely rewritten test case. commit c58c6f8f66ddd0357ecd0c99646aa6bf1dae49c8 Author: Aakanksha Verma Date: Fri May 4 15:53:13 2018 +0530 Bug #27155294 MAX_EXECUTION_TIME NOT INTERUPTED WITH FULLTEXT SEARCH USING MECAB --- .../suite/innodb_fts/r/fts_kill_query.result | 6 ++++ .../suite/innodb_fts/t/fts_kill_query.test | 30 +++++++++++++++++++ storage/innobase/fts/fts0ast.cc | 9 +++++- storage/innobase/fts/fts0que.cc | 17 ++++++++++- storage/innobase/include/fts0ast.h | 5 +++- storage/xtradb/fts/fts0ast.cc | 9 +++++- storage/xtradb/fts/fts0que.cc | 17 ++++++++++- storage/xtradb/include/fts0ast.h | 5 +++- 8 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 mysql-test/suite/innodb_fts/r/fts_kill_query.result create mode 100644 mysql-test/suite/innodb_fts/t/fts_kill_query.test diff --git a/mysql-test/suite/innodb_fts/r/fts_kill_query.result b/mysql-test/suite/innodb_fts/r/fts_kill_query.result new file mode 100644 index 00000000000..45623f96ab0 --- /dev/null +++ b/mysql-test/suite/innodb_fts/r/fts_kill_query.result @@ -0,0 +1,6 @@ +CREATE TABLE t1 (a VARCHAR(7), b text, FULLTEXT KEY idx (a,b)) ENGINE=InnoDB; +COMMIT; +SELECT COUNT(*) FROM t1 +WHERE MATCH (a,b) AGAINST ('foo bar' IN BOOLEAN MODE); +KILL QUERY @id; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/t/fts_kill_query.test b/mysql-test/suite/innodb_fts/t/fts_kill_query.test new file mode 100644 index 00000000000..3dda29a3876 --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/fts_kill_query.test @@ -0,0 +1,30 @@ +--source include/have_innodb.inc + +CREATE TABLE t1 (a VARCHAR(7), b text, FULLTEXT KEY idx (a,b)) ENGINE=InnoDB; + +--disable_query_log +BEGIN; +let $n=1000; +while ($n) { +INSERT INTO t1 VALUES('foo bar','boo far'); +dec $n; +} +--enable_query_log +COMMIT; + +let $id = `SELECT CONNECTION_ID()`; +send SELECT COUNT(*) FROM t1 +WHERE MATCH (a,b) AGAINST ('foo bar' IN BOOLEAN MODE); + +connect (con1,localhost,root,,); +let $ignore= `SELECT @id := $ID`; +KILL QUERY @id; +disconnect con1; + +connection default; +# The following would return a result set if the KILL was not fast enough. +--disable_result_log +--error 0,ER_QUERY_INTERRUPTED,HA_ERR_ABORTED_BY_USER +reap; +--enable_result_log +DROP TABLE t1; diff --git a/storage/innobase/fts/fts0ast.cc b/storage/innobase/fts/fts0ast.cc index 030b972440f..4b36152cf62 100644 --- a/storage/innobase/fts/fts0ast.cc +++ b/storage/innobase/fts/fts0ast.cc @@ -1,6 +1,7 @@ /***************************************************************************** -Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2018, MariaDB Corporation. 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 @@ -27,6 +28,7 @@ Created 2007/3/16 Sunny Bains. #include "fts0ast.h" #include "fts0pars.h" #include "fts0fts.h" +#include "row0sel.h" /* The FTS ast visit pass. */ enum fts_ast_visit_pass_t { @@ -498,6 +500,7 @@ fts_ast_visit( bool revisit = false; bool will_be_ignored = false; fts_ast_visit_pass_t visit_pass = FTS_PASS_FIRST; + const trx_t* trx = node->trx; start_node = node->list.head; @@ -596,6 +599,10 @@ fts_ast_visit( } } + if (trx_is_interrupted(trx)) { + return DB_INTERRUPTED; + } + if (revisit) { /* Exist pass processes the skipped FTS_EXIST operation. */ for (node = start_node; diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index 3a543836837..7d4cd7a3646 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -3970,6 +3970,7 @@ fts_query( /* Parse the input query string. */ if (fts_query_parse(&query, lc_query_str, result_len)) { fts_ast_node_t* ast = query.root; + ast->trx = trx; /* Optimize query to check if it's a single term */ fts_query_can_optimize(&query, flags); @@ -3983,6 +3984,11 @@ fts_query( query.error = fts_ast_visit( FTS_NONE, ast, fts_query_visitor, &query, &will_be_ignored); + if (query.error == DB_INTERRUPTED) { + error = DB_INTERRUPTED; + ut_free(lc_query_str); + goto func_exit; + } /* If query expansion is requested, extend the search with first search pass result */ @@ -4010,6 +4016,15 @@ fts_query( memset(*result, 0, sizeof(**result)); } + if (trx_is_interrupted(trx)) { + error = DB_INTERRUPTED; + ut_free(lc_query_str); + if (result != NULL) { + fts_query_free_result(*result); + } + goto func_exit; + } + ut_free(lc_query_str); if (fts_enable_diag_print && (*result)) { diff --git a/storage/innobase/include/fts0ast.h b/storage/innobase/include/fts0ast.h index 50f62063893..25df2dd9156 100644 --- a/storage/innobase/include/fts0ast.h +++ b/storage/innobase/include/fts0ast.h @@ -1,6 +1,7 @@ /***************************************************************************** -Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2018, MariaDB Corporation. 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 @@ -314,6 +315,8 @@ struct fts_ast_node_t { fts_ast_node_t* next_alloc; /*!< For tracking allocations */ bool visited; /*!< whether this node is already processed */ + /** current transaction */ + const trx_t* trx; }; /* To track state during parsing */ diff --git a/storage/xtradb/fts/fts0ast.cc b/storage/xtradb/fts/fts0ast.cc index 030b972440f..4b36152cf62 100644 --- a/storage/xtradb/fts/fts0ast.cc +++ b/storage/xtradb/fts/fts0ast.cc @@ -1,6 +1,7 @@ /***************************************************************************** -Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2018, MariaDB Corporation. 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 @@ -27,6 +28,7 @@ Created 2007/3/16 Sunny Bains. #include "fts0ast.h" #include "fts0pars.h" #include "fts0fts.h" +#include "row0sel.h" /* The FTS ast visit pass. */ enum fts_ast_visit_pass_t { @@ -498,6 +500,7 @@ fts_ast_visit( bool revisit = false; bool will_be_ignored = false; fts_ast_visit_pass_t visit_pass = FTS_PASS_FIRST; + const trx_t* trx = node->trx; start_node = node->list.head; @@ -596,6 +599,10 @@ fts_ast_visit( } } + if (trx_is_interrupted(trx)) { + return DB_INTERRUPTED; + } + if (revisit) { /* Exist pass processes the skipped FTS_EXIST operation. */ for (node = start_node; diff --git a/storage/xtradb/fts/fts0que.cc b/storage/xtradb/fts/fts0que.cc index 100dbcd70ca..50f198401f9 100644 --- a/storage/xtradb/fts/fts0que.cc +++ b/storage/xtradb/fts/fts0que.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -3989,6 +3989,7 @@ fts_query( /* Parse the input query string. */ if (fts_query_parse(&query, lc_query_str, result_len)) { fts_ast_node_t* ast = query.root; + ast->trx = trx; /* Optimize query to check if it's a single term */ fts_query_can_optimize(&query, flags); @@ -4002,6 +4003,11 @@ fts_query( query.error = fts_ast_visit( FTS_NONE, ast, fts_query_visitor, &query, &will_be_ignored); + if (query.error == DB_INTERRUPTED) { + error = DB_INTERRUPTED; + ut_free(lc_query_str); + goto func_exit; + } /* If query expansion is requested, extend the search with first search pass result */ @@ -4029,6 +4035,15 @@ fts_query( memset(*result, 0, sizeof(**result)); } + if (trx_is_interrupted(trx)) { + error = DB_INTERRUPTED; + ut_free(lc_query_str); + if (result != NULL) { + fts_query_free_result(*result); + } + goto func_exit; + } + ut_free(lc_query_str); if (fts_enable_diag_print && (*result)) { diff --git a/storage/xtradb/include/fts0ast.h b/storage/xtradb/include/fts0ast.h index 50f62063893..25df2dd9156 100644 --- a/storage/xtradb/include/fts0ast.h +++ b/storage/xtradb/include/fts0ast.h @@ -1,6 +1,7 @@ /***************************************************************************** -Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2018, MariaDB Corporation. 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 @@ -314,6 +315,8 @@ struct fts_ast_node_t { fts_ast_node_t* next_alloc; /*!< For tracking allocations */ bool visited; /*!< whether this node is already processed */ + /** current transaction */ + const trx_t* trx; }; /* To track state during parsing */