From ef92aaf9ece92c873ae0f3448ab2274c958ba3fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 22 Jun 2016 22:37:28 +0300 Subject: MDEV-10083: Orphan ibd file when playing with foreign keys Analysis: row_drop_table_for_mysql did not allow dropping referenced table even in case when actual creating of the referenced table was not successfull if foreign_key_checks=1. Fix: Allow dropping referenced table even if foreign_key_checks=1 if actual table create returned error. --- mysql-test/suite/innodb/r/innodb-fkcheck.result | 87 ++++++++++++++++++ mysql-test/suite/innodb/t/innodb-fkcheck.test | 115 ++++++++++++++++++++++++ storage/innobase/dict/dict0crea.c | 8 +- storage/innobase/handler/ha_innodb.cc | 3 +- storage/innobase/include/row0mysql.h | 5 +- storage/innobase/row/row0merge.c | 2 +- storage/innobase/row/row0mysql.c | 23 +++-- storage/innobase/trx/trx0roll.c | 2 +- storage/xtradb/dict/dict0crea.c | 8 +- storage/xtradb/handler/ha_innodb.cc | 4 +- storage/xtradb/include/row0mysql.h | 5 +- storage/xtradb/row/row0merge.c | 2 +- storage/xtradb/row/row0mysql.c | 23 +++-- storage/xtradb/trx/trx0roll.c | 2 +- 14 files changed, 257 insertions(+), 32 deletions(-) create mode 100644 mysql-test/suite/innodb/r/innodb-fkcheck.result create mode 100644 mysql-test/suite/innodb/t/innodb-fkcheck.test diff --git a/mysql-test/suite/innodb/r/innodb-fkcheck.result b/mysql-test/suite/innodb/r/innodb-fkcheck.result new file mode 100644 index 00000000000..a6bbcc9024e --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb-fkcheck.result @@ -0,0 +1,87 @@ +set global innodb_file_per_table = 1; +drop table if exists b; +drop database if exists bug_fk; +create database bug_fk; +use bug_fk; +CREATE TABLE b ( +b int unsigned NOT NULL, +d1 datetime NOT NULL, +PRIMARY KEY (b,d1) +) ENGINE=InnoDB; +CREATE TABLE c ( +b int unsigned NOT NULL, +d1 datetime NOT NULL, +d2 datetime NOT NULL, +PRIMARY KEY (b,d1), +CONSTRAINT b_fk FOREIGN KEY (b) REFERENCES b (b) +) ENGINE=InnoDB; +show warnings; +Level Code Message +set foreign_key_checks = 0; +DROP TABLE IF EXISTS b; +show create table c; +Table Create Table +c CREATE TABLE `c` ( + `b` int(10) unsigned NOT NULL, + `d1` datetime NOT NULL, + `d2` datetime NOT NULL, + PRIMARY KEY (`b`,`d1`), + CONSTRAINT `b_fk` FOREIGN KEY (`b`) REFERENCES `b` (`b`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +CREATE TABLE b ( +b bigint unsigned NOT NULL, +d1 date NOT NULL, +PRIMARY KEY (b,d1) +) ENGINE=InnoDB; +ERROR HY000: Can't create table 'bug_fk.b' (errno: 150) +show warnings; +Level Code Message +Error 1005 Can't create table 'bug_fk.b' (errno: 150) +DROP TABLE IF EXISTS d; +Warnings: +Note 1051 Unknown table 'd' +CREATE TABLE d ( +b bigint unsigned NOT NULL, +d1 date NOT NULL, +PRIMARY KEY (b,d1), +CONSTRAINT bd_fk FOREIGN KEY (b) REFERENCES b (b) +) ENGINE=InnoDB; +show warnings; +Level Code Message +set foreign_key_checks = 1; +show create table c; +Table Create Table +c CREATE TABLE `c` ( + `b` int(10) unsigned NOT NULL, + `d1` datetime NOT NULL, + `d2` datetime NOT NULL, + PRIMARY KEY (`b`,`d1`), + CONSTRAINT `b_fk` FOREIGN KEY (`b`) REFERENCES `b` (`b`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +show create table d; +Table Create Table +d CREATE TABLE `d` ( + `b` bigint(20) unsigned NOT NULL, + `d1` date NOT NULL, + PRIMARY KEY (`b`,`d1`), + CONSTRAINT `bd_fk` FOREIGN KEY (`b`) REFERENCES `b` (`b`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +CREATE TABLE b ( +b bigint unsigned NOT NULL, +d1 date NOT NULL, +PRIMARY KEY (b,d1) +) ENGINE=InnoDB; +ERROR HY000: Can't create table 'bug_fk.b' (errno: 150) +show warnings; +Level Code Message +Error 1005 Can't create table 'bug_fk.b' (errno: 150) +set foreign_key_checks=0; +drop table c; +drop table d; +create table b(id int) engine=innodb; +show warnings; +Level Code Message +b.frm +b.ibd +drop table if exists b; +drop database if exists bug_fk; diff --git a/mysql-test/suite/innodb/t/innodb-fkcheck.test b/mysql-test/suite/innodb/t/innodb-fkcheck.test new file mode 100644 index 00000000000..51e36ae6984 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-fkcheck.test @@ -0,0 +1,115 @@ +--source include/have_innodb.inc + +# +# MDEV-10083: Orphan ibd file when playing with foreign keys +# +--disable_query_log +SET @start_global_fpt = @@global.innodb_file_per_table; +SET @start_global_fkc = @@global.foreign_key_checks; +--enable_query_log + +set global innodb_file_per_table = 1; + +--disable_warnings +drop table if exists b; +drop database if exists bug_fk; +--enable_warnings + +let $MYSQLD_DATADIR = `select @@datadir`; + +create database bug_fk; +use bug_fk; + +CREATE TABLE b ( + b int unsigned NOT NULL, + d1 datetime NOT NULL, + PRIMARY KEY (b,d1) +) ENGINE=InnoDB; + +CREATE TABLE c ( + b int unsigned NOT NULL, + d1 datetime NOT NULL, + d2 datetime NOT NULL, + PRIMARY KEY (b,d1), + CONSTRAINT b_fk FOREIGN KEY (b) REFERENCES b (b) +) ENGINE=InnoDB; + +show warnings; + +set foreign_key_checks = 0; + +DROP TABLE IF EXISTS b; + +show create table c; + +# +# Note that column b has different type in parent table +# +--error 1005 +CREATE TABLE b ( + b bigint unsigned NOT NULL, + d1 date NOT NULL, + PRIMARY KEY (b,d1) +) ENGINE=InnoDB; + +show warnings; + +DROP TABLE IF EXISTS d; + +CREATE TABLE d ( + b bigint unsigned NOT NULL, + d1 date NOT NULL, + PRIMARY KEY (b,d1), + CONSTRAINT bd_fk FOREIGN KEY (b) REFERENCES b (b) +) ENGINE=InnoDB; + +show warnings; + +set foreign_key_checks = 1; + +show create table c; +show create table d; + +# +# Table c column b used on foreign key has different type +# compared referenced column b in table b, but this +# create still produced b.ibd file. This is because +# we row_drop_table_for_mysql was called and referenced +# table is not allowed to be dropped even in case +# when actual create is not successfull. +# +--error 1005 +CREATE TABLE b ( + b bigint unsigned NOT NULL, + d1 date NOT NULL, + PRIMARY KEY (b,d1) +) ENGINE=InnoDB; + +show warnings; + +--list_files $MYSQLD_DATADIR/bug_fk b* + +set foreign_key_checks=0; + +drop table c; +drop table d; + +--list_files $MYSQLD_DATADIR/bug_fk b* + +create table b(id int) engine=innodb; +show warnings; + +--list_files $MYSQLD_DATADIR/bug_fk b* + +# +# Cleanup +# +--disable_query_log +SET @@global.innodb_file_per_table = @start_global_fpt; +SET @@global.foreign_key_checks = @start_global_fkc; +--enable_query_log + +--disable_warnings +drop table if exists b; +drop database if exists bug_fk; +--enable_warnings diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 8102f570175..f8bcc6f2d5f 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -1242,14 +1242,14 @@ dict_create_or_check_foreign_constraint_tables(void) fprintf(stderr, "InnoDB: dropping incompletely created" " SYS_FOREIGN table\n"); - row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE); + row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE); } if (table2) { fprintf(stderr, "InnoDB: dropping incompletely created" " SYS_FOREIGN_COLS table\n"); - row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE); + row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE); } fprintf(stderr, @@ -1298,8 +1298,8 @@ dict_create_or_check_foreign_constraint_tables(void) "InnoDB: dropping incompletely created" " SYS_FOREIGN tables\n"); - row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE); - row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE); + row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE); + row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE); error = DB_MUST_GET_MORE_FILE_SPACE; } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 734dbe1cafd..780f3a6f82f 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7644,7 +7644,8 @@ ha_innobase::delete_table( error = row_drop_table_for_mysql(norm_name, trx, thd_sql_command(thd) - == SQLCOM_DROP_DB); + == SQLCOM_DROP_DB, + FALSE); /* Flush the log to reduce probability that the .frm files and the InnoDB data dictionary get out-of-sync if the user runs diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 7abb0b67fff..0f66644d906 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -454,7 +454,10 @@ row_drop_table_for_mysql( /*=====================*/ const char* name, /*!< in: table name */ trx_t* trx, /*!< in: transaction handle */ - ibool drop_db);/*!< in: TRUE=dropping whole database */ + ibool drop_db,/*!< in: TRUE=dropping whole database */ + ibool create_failed);/*!n_mysql_handles_opened == 0); - return(row_drop_table_for_mysql(table->name, trx, FALSE)); + return(row_drop_table_for_mysql(table->name, trx, FALSE, FALSE)); } /*********************************************************************//** diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 1a11e398959..6206bef6b56 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1987,7 +1987,7 @@ err_exit: if (dict_table_get_low(table->name, DICT_ERR_IGNORE_NONE)) { - row_drop_table_for_mysql(table->name, trx, FALSE); + row_drop_table_for_mysql(table->name, trx, FALSE, TRUE); trx_commit_for_mysql(trx); } else { dict_mem_table_free(table); @@ -2117,7 +2117,7 @@ error_handling: trx_general_rollback_for_mysql(trx, NULL); - row_drop_table_for_mysql(table_name, trx, FALSE); + row_drop_table_for_mysql(table_name, trx, FALSE, TRUE); trx_commit_for_mysql(trx); @@ -2187,7 +2187,7 @@ row_table_add_foreign_constraints( trx_general_rollback_for_mysql(trx, NULL); - row_drop_table_for_mysql(name, trx, FALSE); + row_drop_table_for_mysql(name, trx, FALSE, TRUE); trx_commit_for_mysql(trx); @@ -2228,7 +2228,7 @@ row_drop_table_for_mysql_in_background( /* Try to drop the table in InnoDB */ - error = row_drop_table_for_mysql(name, trx, FALSE); + error = row_drop_table_for_mysql(name, trx, FALSE, FALSE); /* Flush the log to reduce probability that the .frm files and the InnoDB data dictionary get out-of-sync if the user runs @@ -3078,7 +3078,10 @@ row_drop_table_for_mysql( /*=====================*/ const char* name, /*!< in: table name */ trx_t* trx, /*!< in: transaction handle */ - ibool drop_db)/*!< in: TRUE=dropping whole database */ + ibool drop_db,/*!< in: TRUE=dropping whole database */ + ibool create_failed) /*!check_foreigns + /* We should allow dropping a referenced table if creating + that referenced table has failed for some reason. For example + if referenced table is created but it column types that are + referenced do not match. */ + if (foreign && trx->check_foreigns && !create_failed && !(drop_db && dict_tables_have_same_db( name, foreign->foreign_table_name_lookup))) { FILE* ef = dict_foreign_err_file; @@ -3578,7 +3585,7 @@ row_mysql_drop_temp_tables(void) table = dict_load_table(table_name, TRUE, DICT_ERR_IGNORE_NONE); if (table) { - row_drop_table_for_mysql(table_name, trx, FALSE); + row_drop_table_for_mysql(table_name, trx, FALSE, FALSE); trx_commit_for_mysql(trx); } @@ -3708,7 +3715,7 @@ loop: goto loop; } - err = row_drop_table_for_mysql(table_name, trx, TRUE); + err = row_drop_table_for_mysql(table_name, trx, TRUE, FALSE); trx_commit_for_mysql(trx); if (err != DB_SUCCESS) { diff --git a/storage/innobase/trx/trx0roll.c b/storage/innobase/trx/trx0roll.c index ffd7bb3d146..877a478e50a 100644 --- a/storage/innobase/trx/trx0roll.c +++ b/storage/innobase/trx/trx0roll.c @@ -504,7 +504,7 @@ trx_rollback_active( ut_print_name(stderr, trx, TRUE, table->name); fputs(" in recovery\n", stderr); - err = row_drop_table_for_mysql(table->name, trx, TRUE); + err = row_drop_table_for_mysql(table->name, trx, TRUE, FALSE); trx_commit_for_mysql(trx); ut_a(err == (int) DB_SUCCESS); diff --git a/storage/xtradb/dict/dict0crea.c b/storage/xtradb/dict/dict0crea.c index a77acf8b577..b44fdc1d2e4 100644 --- a/storage/xtradb/dict/dict0crea.c +++ b/storage/xtradb/dict/dict0crea.c @@ -1444,14 +1444,14 @@ dict_create_or_check_foreign_constraint_tables(void) fprintf(stderr, "InnoDB: dropping incompletely created" " SYS_FOREIGN table\n"); - row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE); + row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE); } if (table2) { fprintf(stderr, "InnoDB: dropping incompletely created" " SYS_FOREIGN_COLS table\n"); - row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE); + row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE); } fprintf(stderr, @@ -1500,8 +1500,8 @@ dict_create_or_check_foreign_constraint_tables(void) "InnoDB: dropping incompletely created" " SYS_FOREIGN tables\n"); - row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE); - row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE); + row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE); + row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE); error = DB_MUST_GET_MORE_FILE_SPACE; } diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 8148c3e1dd5..d5da3825ef0 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -8773,7 +8773,8 @@ ha_innobase::delete_table( error = row_drop_table_for_mysql(norm_name, trx, thd_sql_command(thd) - == SQLCOM_DROP_DB); + == SQLCOM_DROP_DB, + FALSE); /* Flush the log to reduce probability that the .frm files and the InnoDB data dictionary get out-of-sync if the user runs @@ -8858,6 +8859,7 @@ innobase_drop_database( trx_free_for_mysql(trx); return; /* ignore */ } + row_drop_database_for_mysql(namebuf, trx); my_free(namebuf); diff --git a/storage/xtradb/include/row0mysql.h b/storage/xtradb/include/row0mysql.h index 35378bf3302..e228289bdae 100644 --- a/storage/xtradb/include/row0mysql.h +++ b/storage/xtradb/include/row0mysql.h @@ -470,7 +470,10 @@ row_drop_table_for_mysql( /*=====================*/ const char* name, /*!< in: table name */ trx_t* trx, /*!< in: transaction handle */ - ibool drop_db);/*!< in: TRUE=dropping whole database */ + ibool drop_db,/*!< in: TRUE=dropping whole database */ + ibool create_failed);/*!n_mysql_handles_opened == 0); - return(row_drop_table_for_mysql(table->name, trx, FALSE)); + return(row_drop_table_for_mysql(table->name, trx, FALSE, FALSE)); } /*********************************************************************//** diff --git a/storage/xtradb/row/row0mysql.c b/storage/xtradb/row/row0mysql.c index e6ccf44b884..0182752132a 100644 --- a/storage/xtradb/row/row0mysql.c +++ b/storage/xtradb/row/row0mysql.c @@ -2013,7 +2013,7 @@ err_exit: if (dict_table_get_low(table->name, DICT_ERR_IGNORE_NONE)) { - row_drop_table_for_mysql(table->name, trx, FALSE); + row_drop_table_for_mysql(table->name, trx, FALSE, TRUE); trx_commit_for_mysql(trx); } else { dict_mem_table_free(table); @@ -2143,7 +2143,7 @@ error_handling: trx_general_rollback_for_mysql(trx, NULL); - row_drop_table_for_mysql(table_name, trx, FALSE); + row_drop_table_for_mysql(table_name, trx, FALSE, TRUE); trx_commit_for_mysql(trx); @@ -2278,7 +2278,7 @@ row_table_add_foreign_constraints( trx_general_rollback_for_mysql(trx, NULL); - row_drop_table_for_mysql(name, trx, FALSE); + row_drop_table_for_mysql(name, trx, FALSE, TRUE); trx_commit_for_mysql(trx); @@ -2319,7 +2319,7 @@ row_drop_table_for_mysql_in_background( /* Try to drop the table in InnoDB */ - error = row_drop_table_for_mysql(name, trx, FALSE); + error = row_drop_table_for_mysql(name, trx, FALSE, FALSE); /* Flush the log to reduce probability that the .frm files and the InnoDB data dictionary get out-of-sync if the user runs @@ -3216,7 +3216,10 @@ row_drop_table_for_mysql( /*=====================*/ const char* name, /*!< in: table name */ trx_t* trx, /*!< in: transaction handle */ - ibool drop_db)/*!< in: TRUE=dropping whole database */ + ibool drop_db,/*!< in: TRUE=dropping whole database */ + ibool create_failed) /*!check_foreigns + /* We should allow dropping a referenced table if creating + that referenced table has failed for some reason. For example + if referenced table is created but it column types that are + referenced do not match. */ + if (foreign && trx->check_foreigns && !create_failed && !(drop_db && dict_tables_have_same_db( name, foreign->foreign_table_name_lookup))) { FILE* ef = dict_foreign_err_file; @@ -3718,7 +3725,7 @@ row_mysql_drop_temp_tables(void) table = dict_table_get_low(table_name, DICT_ERR_IGNORE_ALL); if (table) { - row_drop_table_for_mysql(table_name, trx, FALSE); + row_drop_table_for_mysql(table_name, trx, FALSE, FALSE); trx_commit_for_mysql(trx); } @@ -3848,7 +3855,7 @@ loop: goto loop; } - err = row_drop_table_for_mysql(table_name, trx, TRUE); + err = row_drop_table_for_mysql(table_name, trx, TRUE, FALSE); trx_commit_for_mysql(trx); if (err != DB_SUCCESS) { diff --git a/storage/xtradb/trx/trx0roll.c b/storage/xtradb/trx/trx0roll.c index 25c1d5d4692..236eb88e7a4 100644 --- a/storage/xtradb/trx/trx0roll.c +++ b/storage/xtradb/trx/trx0roll.c @@ -504,7 +504,7 @@ trx_rollback_active( ut_print_name(stderr, trx, TRUE, table->name); fputs(" in recovery\n", stderr); - err = row_drop_table_for_mysql(table->name, trx, TRUE); + err = row_drop_table_for_mysql(table->name, trx, TRUE, FALSE); trx_commit_for_mysql(trx); ut_a(err == (int) DB_SUCCESS); -- cgit v1.2.1 From 79f852a069fb6ba5e18fd66ea2a24fa91c245c24 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 22 Jun 2016 14:17:06 +0200 Subject: MDEV-10050: Crash in subselect thd should not be taken earlier then fix_field and reset on fix_fields if it is needed. --- sql/item_subselect.cc | 58 +++++++++++++++++++++++++++++++-------------------- sql/item_subselect.h | 34 +++++++++++++----------------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index ba674743724..690318c610a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -79,7 +79,6 @@ void Item_subselect::init(st_select_lex *select_lex, DBUG_PRINT("enter", ("select_lex: 0x%lx this: 0x%lx", (ulong) select_lex, (ulong) this)); unit= select_lex->master_unit(); - thd= unit->thd; if (unit->item) { @@ -90,7 +89,7 @@ void Item_subselect::init(st_select_lex *select_lex, engine= unit->item->engine; own_engine= FALSE; parsing_place= unit->item->parsing_place; - thd->change_item_tree((Item**)&unit->item, this); + unit->thd->change_item_tree((Item**)&unit->item, this); engine->change_result(this, result, TRUE); } else @@ -104,9 +103,9 @@ void Item_subselect::init(st_select_lex *select_lex, NO_MATTER : outer_select->parsing_place); if (unit->is_union()) - engine= new subselect_union_engine(thd, unit, result, this); + engine= new subselect_union_engine(unit, result, this); else - engine= new subselect_single_select_engine(thd, select_lex, result, this); + engine= new subselect_single_select_engine(select_lex, result, this); } { SELECT_LEX *upper= unit->outer_select(); @@ -220,6 +219,10 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) uint8 uncacheable; bool res; + thd= thd_param; + + DBUG_ASSERT(unit->thd == thd); + status_var_increment(thd_param->status_var.feature_subquery); DBUG_ASSERT(fixed == 0); @@ -242,7 +245,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) return TRUE; - if (!(res= engine->prepare())) + if (!(res= engine->prepare(thd))) { // all transformation is done (used by prepared statements) changed= 1; @@ -2651,7 +2654,10 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) { uint outer_cols_num; List *inner_cols; - char const *save_where= thd->where; + char const *save_where= thd_arg->where; + + thd= thd_arg; + DBUG_ASSERT(unit->thd == thd); if (test_strategy(SUBS_SEMI_JOIN)) return !( (*ref)= new Item_int(1)); @@ -2769,7 +2775,8 @@ bool Item_in_subselect::setup_mat_engine() if (!(mat_engine= new subselect_hash_sj_engine(thd, this, select_engine))) DBUG_RETURN(TRUE); - if (mat_engine->init(&select_engine->join->fields_list, + if (mat_engine->prepare(thd) || + mat_engine->init(&select_engine->join->fields_list, engine->get_identifier())) DBUG_RETURN(TRUE); @@ -2885,10 +2892,10 @@ void subselect_engine::set_thd(THD *thd_arg) subselect_single_select_engine:: -subselect_single_select_engine(THD *thd_arg, st_select_lex *select, +subselect_single_select_engine(st_select_lex *select, select_result_interceptor *result_arg, Item_subselect *item_arg) - :subselect_engine(thd_arg, item_arg, result_arg), + :subselect_engine(item_arg, result_arg), prepared(0), executed(0), select_lex(select), join(0) { @@ -2966,10 +2973,10 @@ void subselect_uniquesubquery_engine::cleanup() } -subselect_union_engine::subselect_union_engine(THD *thd_arg, st_select_lex_unit *u, +subselect_union_engine::subselect_union_engine(st_select_lex_unit *u, select_result_interceptor *result_arg, Item_subselect *item_arg) - :subselect_engine(thd_arg, item_arg, result_arg) + :subselect_engine(item_arg, result_arg) { unit= u; unit->item= item_arg; @@ -3002,10 +3009,11 @@ subselect_union_engine::subselect_union_engine(THD *thd_arg, st_select_lex_unit @retval 1 if error */ -int subselect_single_select_engine::prepare() +int subselect_single_select_engine::prepare(THD *thd) { if (prepared) return 0; + set_thd(thd); if (select_lex->join) { select_lex->cleanup(); @@ -3034,12 +3042,13 @@ int subselect_single_select_engine::prepare() return 0; } -int subselect_union_engine::prepare() +int subselect_union_engine::prepare(THD *thd_arg) { + set_thd(thd_arg); return unit->prepare(thd, result, SELECT_NO_UNLOCK); } -int subselect_uniquesubquery_engine::prepare() +int subselect_uniquesubquery_engine::prepare(THD *) { /* Should never be called. */ DBUG_ASSERT(FALSE); @@ -4499,13 +4508,14 @@ subselect_hash_sj_engine::~subselect_hash_sj_engine() } -int subselect_hash_sj_engine::prepare() +int subselect_hash_sj_engine::prepare(THD *thd_arg) { /* Create and optimize the JOIN that will be used to materialize the subquery if not yet created. */ - return materialize_engine->prepare(); + set_thd(thd_arg); + return materialize_engine->prepare(thd); } @@ -4877,7 +4887,7 @@ int subselect_hash_sj_engine::exec() if (strategy == PARTIAL_MATCH_MERGE) { pm_engine= - new subselect_rowid_merge_engine(thd, (subselect_uniquesubquery_engine*) + new subselect_rowid_merge_engine((subselect_uniquesubquery_engine*) lookup_engine, tmp_table, count_pm_keys, has_covering_null_row, @@ -4886,6 +4896,7 @@ int subselect_hash_sj_engine::exec() item, result, semi_join_conds->argument_list()); if (!pm_engine || + pm_engine->prepare(thd) || ((subselect_rowid_merge_engine*) pm_engine)-> init(nn_key_parts, &partial_match_key_parts)) { @@ -4903,13 +4914,14 @@ int subselect_hash_sj_engine::exec() if (strategy == PARTIAL_MATCH_SCAN) { if (!(pm_engine= - new subselect_table_scan_engine(thd, (subselect_uniquesubquery_engine*) + new subselect_table_scan_engine((subselect_uniquesubquery_engine*) lookup_engine, tmp_table, item, result, semi_join_conds->argument_list(), has_covering_null_row, has_covering_null_columns, - count_columns_with_nulls))) + count_columns_with_nulls)) || + pm_engine->prepare(thd)) { /* This is an irrecoverable error. */ res= 1; @@ -5356,14 +5368,14 @@ void Ordered_key::print(String *str) subselect_partial_match_engine::subselect_partial_match_engine( - THD *thd_arg, subselect_uniquesubquery_engine *engine_arg, + subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg, bool has_covering_null_row_arg, bool has_covering_null_columns_arg, uint count_columns_with_nulls_arg) - :subselect_engine(thd_arg, item_arg, result_arg), + :subselect_engine(item_arg, result_arg), tmp_table(tmp_table_arg), lookup_engine(engine_arg), equi_join_conds(equi_join_conds_arg), has_covering_null_row(has_covering_null_row_arg), @@ -5976,7 +5988,7 @@ end: subselect_table_scan_engine::subselect_table_scan_engine( - THD *thd_arg, subselect_uniquesubquery_engine *engine_arg, + subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, @@ -5984,7 +5996,7 @@ subselect_table_scan_engine::subselect_table_scan_engine( bool has_covering_null_row_arg, bool has_covering_null_columns_arg, uint count_columns_with_nulls_arg) - :subselect_partial_match_engine(thd_arg, engine_arg, tmp_table_arg, item_arg, + :subselect_partial_match_engine(engine_arg, tmp_table_arg, item_arg, result_arg, equi_join_conds_arg, has_covering_null_row_arg, has_covering_null_columns_arg, diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 0ee5f73eb35..0abfe0d5abc 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -715,7 +715,7 @@ public: INDEXSUBQUERY_ENGINE, HASH_SJ_ENGINE, ROWID_MERGE_ENGINE, TABLE_SCAN_ENGINE}; - subselect_engine(THD *thd_arg, Item_subselect *si, + subselect_engine(Item_subselect *si, select_result_interceptor *res) { result= res; @@ -723,7 +723,6 @@ public: cmp_type= res_type= STRING_RESULT; res_field_type= MYSQL_TYPE_VAR_STRING; maybe_null= 0; - set_thd(thd_arg); } virtual ~subselect_engine() {}; // to satisfy compiler virtual void cleanup()= 0; @@ -734,7 +733,7 @@ public: */ void set_thd(THD *thd_arg); THD * get_thd() { return thd; } - virtual int prepare()= 0; + virtual int prepare(THD *)= 0; virtual void fix_length_and_dec(Item_cache** row)= 0; /* Execute the engine @@ -789,11 +788,11 @@ class subselect_single_select_engine: public subselect_engine st_select_lex *select_lex; /* corresponding select_lex */ JOIN * join; /* corresponding JOIN structure */ public: - subselect_single_select_engine(THD *thd_arg, st_select_lex *select, + subselect_single_select_engine(st_select_lex *select, select_result_interceptor *result, Item_subselect *item); void cleanup(); - int prepare(); + int prepare(THD *thd); void fix_length_and_dec(Item_cache** row); int exec(); uint cols(); @@ -823,11 +822,11 @@ class subselect_union_engine: public subselect_engine { st_select_lex_unit *unit; /* corresponding unit structure */ public: - subselect_union_engine(THD *thd_arg, st_select_lex_unit *u, + subselect_union_engine(st_select_lex_unit *u, select_result_interceptor *result, Item_subselect *item); void cleanup(); - int prepare(); + int prepare(THD *); void fix_length_and_dec(Item_cache** row); int exec(); uint cols(); @@ -880,11 +879,11 @@ public: // constructor can assign THD because it will be called after JOIN::prepare subselect_uniquesubquery_engine(THD *thd_arg, st_join_table *tab_arg, Item_subselect *subs, Item *where) - :subselect_engine(thd_arg, subs, 0), tab(tab_arg), cond(where) + :subselect_engine(subs, 0), tab(tab_arg), cond(where) {} ~subselect_uniquesubquery_engine(); void cleanup(); - int prepare(); + int prepare(THD *); void fix_length_and_dec(Item_cache** row); int exec(); uint cols() { return 1; } @@ -1012,7 +1011,7 @@ public: subselect_hash_sj_engine(THD *thd, Item_subselect *in_predicate, subselect_single_select_engine *old_engine) - : subselect_engine(thd, in_predicate, NULL), + : subselect_engine(in_predicate, NULL), tmp_table(NULL), is_materialized(FALSE), materialize_engine(old_engine), materialize_join(NULL), semi_join_conds(NULL), lookup_engine(NULL), count_partial_match_columns(0), count_null_only_columns(0), @@ -1022,7 +1021,7 @@ public: bool init(List *tmp_columns, uint subquery_id); void cleanup(); - int prepare(); + int prepare(THD *); int exec(); virtual void print(String *str, enum_query_type query_type); uint cols() @@ -1301,15 +1300,14 @@ protected: protected: virtual bool partial_match()= 0; public: - subselect_partial_match_engine(THD *thd_arg, - subselect_uniquesubquery_engine *engine_arg, + subselect_partial_match_engine(subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg, bool has_covering_null_row_arg, bool has_covering_null_columns_arg, uint count_columns_with_nulls_arg); - int prepare() { return 0; } + int prepare(THD *thd_arg) { set_thd(thd_arg); return 0; } int exec(); void fix_length_and_dec(Item_cache**) {} uint cols() { /* TODO: what is the correct value? */ return 1; } @@ -1396,8 +1394,7 @@ protected: bool exists_complementing_null_row(MY_BITMAP *keys_to_complement); bool partial_match(); public: - subselect_rowid_merge_engine(THD *thd_arg, - subselect_uniquesubquery_engine *engine_arg, + subselect_rowid_merge_engine(subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, uint merge_keys_count_arg, bool has_covering_null_row_arg, bool has_covering_null_columns_arg, @@ -1405,7 +1402,7 @@ public: Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg) - :subselect_partial_match_engine(thd_arg, engine_arg, tmp_table_arg, + :subselect_partial_match_engine(engine_arg, tmp_table_arg, item_arg, result_arg, equi_join_conds_arg, has_covering_null_row_arg, has_covering_null_columns_arg, @@ -1424,8 +1421,7 @@ class subselect_table_scan_engine: public subselect_partial_match_engine protected: bool partial_match(); public: - subselect_table_scan_engine(THD *thd_arg, - subselect_uniquesubquery_engine *engine_arg, + subselect_table_scan_engine(subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg, -- cgit v1.2.1 From a7814d44fc50ecb270bf9816de7b019a71405e46 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 30 Jun 2016 12:59:52 +0400 Subject: MDEV-10311 - funcs_1.processlist_priv_no_prot fails sporadically State column of SHOW PROCESSLIST can have NULL values for being initialized threads (between new connection was acknowledged and waiting for network data). Fixed test case to handle such cases by waiting for State to become empty string. --- mysql-test/suite/funcs_1/datadict/processlist_priv.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/funcs_1/datadict/processlist_priv.inc b/mysql-test/suite/funcs_1/datadict/processlist_priv.inc index b863b98d98a..38b9a3e309e 100644 --- a/mysql-test/suite/funcs_1/datadict/processlist_priv.inc +++ b/mysql-test/suite/funcs_1/datadict/processlist_priv.inc @@ -153,7 +153,7 @@ connection default; let $wait_timeout= 10; let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST -WHERE DB = 'information_schema' AND COMMAND = 'Sleep' AND USER = 'ddicttestuser1'; +WHERE DB = 'information_schema' AND COMMAND = 'Sleep' AND USER = 'ddicttestuser1' AND state=''; --source include/wait_condition.inc --replace_result ENGINE=MyISAM "" ENGINE=Aria "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" "" eval SHOW CREATE TABLE $table; -- cgit v1.2.1 From e81455bb1617e574faab93f0846a6339064968b3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 4 May 2015 08:32:05 +0200 Subject: MDEV-7973 bigint fail with gcc 5.0 -LONGLONG_MIN is the undefined behavior in C. longlong2decimal() used to do this: int longlong2decimal(longlong from, decimal_t *to) { if ((to->sign= from < 0)) return ull2dec(-from, to); return ull2dec(from, to); and later in ull2dec() (DIG_BASE is 1000000000): static int ull2dec(ulonglong from, decimal_t *to) { for (intg1=1; from >= DIG_BASE; intg1++, from/=DIG_BASE) {} this breaks in gcc-5 at -O3. Here ull2dec is inlined into longlong2decimal. And gcc-5 believes that 'from' in the inlined ull2dec is always a positive integer (indeed, if it was negative, then -from was used instead). So gcc-5 uses *signed* comparison with DIG_BASE. Fix: make a special case for LONGLONG_MIN, don't negate it --- strings/decimal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/strings/decimal.c b/strings/decimal.c index 8dbe1bd57f4..b0c57d3db0c 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1025,7 +1025,11 @@ int ulonglong2decimal(ulonglong from, decimal_t *to) int longlong2decimal(longlong from, decimal_t *to) { if ((to->sign= from < 0)) + { + if (from == LONGLONG_MIN) // avoid undefined behavior + return ull2dec((ulonglong)LONGLONG_MIN, to); return ull2dec(-from, to); + } return ull2dec(from, to); } -- cgit v1.2.1 From 97ded96a33abb98190537e10e94c7dadf5bd0a5f Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 11 Jul 2016 17:03:03 +0000 Subject: MDEV-10318 : Fix crash in embedded, in case prepared statement has parameter placeholders, but does not bind parameters --- libmysqld/lib_sql.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 3d6ca5a3810..623569c18de 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -341,6 +341,12 @@ static int emb_stmt_execute(MYSQL_STMT *stmt) THD *thd; my_bool res; + if (stmt->param_count && !stmt->bind_param_done) + { + set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate, NULL); + DBUG_RETURN(1); + } + int4store(header, stmt->stmt_id); header[4]= (uchar) stmt->flags; thd= (THD*)stmt->mysql->thd; -- cgit v1.2.1 From 4e19aa386493fcf0613049b47cbb9b151e2d3e8d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 12 Jul 2016 12:13:31 +0200 Subject: MDEV-10318 unset params in --ps --embedded add a test case --- mysql-test/r/ps_1general.result | 2 ++ mysql-test/t/ps_1general.test | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index 0a3d16cf48e..cc31944fd1f 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -788,3 +788,5 @@ execute stmt1; 1 drop prepare stmt1; drop table t1; +select ?+1; +Got one of the listed errors diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test index 812b1b5ff94..7b7b87ef851 100644 --- a/mysql-test/t/ps_1general.test +++ b/mysql-test/t/ps_1general.test @@ -936,3 +936,10 @@ drop table t1; # Matthias # End of 4.1 tests + +# +# MDEV-10318 unset params in --ps --embedded +# +--error ER_PARSE_ERROR,2031 +select ?+1; + -- cgit v1.2.1 From 5cf49cdf92bb57c2e20f72422a22768be8c7a8a8 Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Fri, 15 Jul 2016 23:51:30 +0300 Subject: MDEV-10248 Cannot Remove Test Tables While dropping the test database, use IF EXISTS to avoid bogus errors --- scripts/mysql_secure_installation.pl.in | 2 +- scripts/mysql_secure_installation.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mysql_secure_installation.pl.in b/scripts/mysql_secure_installation.pl.in index 188a6bd7104..32331c3d601 100644 --- a/scripts/mysql_secure_installation.pl.in +++ b/scripts/mysql_secure_installation.pl.in @@ -217,7 +217,7 @@ sub remove_remote_root { sub remove_test_database { print " - Dropping test database...\n"; - if (do_query("DROP DATABASE test;")) { + if (do_query("DROP DATABASE IF EXISTS test;")) { print " ... Success!\n"; } else { print " ... Failed! Not critical, keep moving...\n"; diff --git a/scripts/mysql_secure_installation.sh b/scripts/mysql_secure_installation.sh index 9e9bce9fa87..7fb8b73ef8f 100644 --- a/scripts/mysql_secure_installation.sh +++ b/scripts/mysql_secure_installation.sh @@ -324,7 +324,7 @@ remove_remote_root() { remove_test_database() { echo " - Dropping test database..." - do_query "DROP DATABASE test;" + do_query "DROP DATABASE IF EXISTS test;" if [ $? -eq 0 ]; then echo " ... Success!" else -- cgit v1.2.1 From 1b5da2ca49f69605ccfe4d98e9207e7b8551e21f Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 21 Jul 2016 15:32:28 +0400 Subject: MDEV-10316 - main.type_date fails around midnight sporadically A better fix for MySQL Bug#41776: use hard timestamp rather than unreliable sleep. --- mysql-test/r/type_date.result | 2 ++ mysql-test/t/type_date.test | 15 +++------------ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index ecbda1d13e6..ad7560fa3f8 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -165,6 +165,7 @@ str_to_date( '', a ) NULL DROP TABLE t1; CREATE TABLE t1 (a DATE, b INT, PRIMARY KEY (a,b)); +SET timestamp=UNIX_TIMESTAMP('2016-07-21 14:48:18'); INSERT INTO t1 VALUES (DATE(NOW()), 1); SELECT COUNT(*) FROM t1 WHERE a = NOW(); COUNT(*) @@ -192,6 +193,7 @@ COUNT(*) EXPLAIN SELECT COUNT(*) FROM t1 WHERE a = NOW(); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +SET timestamp=DEFAULT; DROP TABLE t1; CREATE TABLE t1 (a DATE); CREATE TABLE t2 (a DATE); diff --git a/mysql-test/t/type_date.test b/mysql-test/t/type_date.test index 8b0c5dcf330..832e72520ce 100644 --- a/mysql-test/t/type_date.test +++ b/mysql-test/t/type_date.test @@ -169,18 +169,8 @@ DROP TABLE t1; # CREATE TABLE t1 (a DATE, b INT, PRIMARY KEY (a,b)); -## The current sub test could fail (difference to expected result) if we -## have just reached midnight. -## (Bug#41776 type_date.test may fail if run around midnight) -## Therefore we sleep a bit if we are too close to midnight. -## The complete test itself needs in average less than 1 second. -## Therefore a time_distance to midnight of 5 seconds should be sufficient. -if (`SELECT CURTIME() > SEC_TO_TIME(24 * 3600 - 5)`) -{ - # We are here when CURTIME() is between '23:59:56' and '23:59:59'. - # So a sleep time of 5 seconds brings us between '00:00:01' and '00:00:04'. - --real_sleep 5 -} + +SET timestamp=UNIX_TIMESTAMP('2016-07-21 14:48:18'); INSERT INTO t1 VALUES (DATE(NOW()), 1); SELECT COUNT(*) FROM t1 WHERE a = NOW(); EXPLAIN SELECT COUNT(*) FROM t1 WHERE a = NOW(); @@ -192,6 +182,7 @@ EXPLAIN SELECT COUNT(*) FROM t1 WHERE a = NOW() AND b = 1; ALTER TABLE t1 DROP PRIMARY KEY; SELECT COUNT(*) FROM t1 WHERE a = NOW(); EXPLAIN SELECT COUNT(*) FROM t1 WHERE a = NOW(); +SET timestamp=DEFAULT; DROP TABLE t1; -- cgit v1.2.1 From 15ef38d2ea97575c71b83db6669ee20000c23a6b Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 27 Jul 2016 00:38:51 +0300 Subject: MDEV-10228: Delete missing rows with OR conditions Fix get_quick_keys(): When building range tree from a condition in form keypart1=const AND (keypart2 < 0 OR keypart2>=0) the SEL_ARG for keypart2 represents an interval (-inf, +inf). However, the logic that sets UNIQUE_RANGE flag fails to recognize this, and sets UNIQUE_RANGE flag if (keypart1, keypart2) covered a unique key. As a result, range access executor assumes the interval can have at most one row and only reads the first row from it. --- mysql-test/r/range.result | 31 +++++++++++++++++++++++++++++++ mysql-test/t/range.test | 29 +++++++++++++++++++++++++++++ sql/opt_range.cc | 2 ++ 3 files changed, 62 insertions(+) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index a19d906b645..630a692cef6 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -2113,3 +2113,34 @@ a b 0 0 1 1 drop table t2; +# +# MDEV-10228: Delete missing rows with OR conditions +# (The example uses UPDATE, because UPDATE allows to use index hints +# and so it's possible to make an example that works with any storage +# engine) +# +CREATE TABLE t1 ( +key1varchar varchar(14) NOT NULL, +key2int int(11) NOT NULL DEFAULT '0', +col1 int, +PRIMARY KEY (key1varchar,key2int), +KEY key1varchar (key1varchar), +KEY key2int (key2int) +) DEFAULT CHARSET=utf8; +insert into t1 values +('value1',0, 0), +('value1',1, 0), +('value1',1000685, 0), +('value1',1003560, 0), +('value1',1004807, 0); +update t1 force index (PRIMARY) set col1=12345 +where (key1varchar='value1' AND (key2int <=1 OR key2int > 1)); +# The following must show col1=12345 for all rows: +select * from t1; +key1varchar key2int col1 +value1 0 12345 +value1 1 12345 +value1 1000685 12345 +value1 1003560 12345 +value1 1004807 12345 +drop table t1; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index b73b09dffd5..393ca68e945 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1689,3 +1689,32 @@ insert into t2 values (0, 0, 0, 0), (1, 1, 1, 1); analyze table t2; select a, b from t2 where (a, b) in ((0, 0), (1, 1)); drop table t2; + +--echo # +--echo # MDEV-10228: Delete missing rows with OR conditions +--echo # (The example uses UPDATE, because UPDATE allows to use index hints +--echo # and so it's possible to make an example that works with any storage +--echo # engine) +--echo # + +CREATE TABLE t1 ( + key1varchar varchar(14) NOT NULL, + key2int int(11) NOT NULL DEFAULT '0', + col1 int, + PRIMARY KEY (key1varchar,key2int), + KEY key1varchar (key1varchar), + KEY key2int (key2int) +) DEFAULT CHARSET=utf8; + +insert into t1 values + ('value1',0, 0), + ('value1',1, 0), + ('value1',1000685, 0), + ('value1',1003560, 0), + ('value1',1004807, 0); + +update t1 force index (PRIMARY) set col1=12345 +where (key1varchar='value1' AND (key2int <=1 OR key2int > 1)); +--echo # The following must show col1=12345 for all rows: +select * from t1; +drop table t1; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index f4ac47fee96..a40363ff9ab 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -10409,8 +10409,10 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, KEY *table_key=quick->head->key_info+quick->index; flag=EQ_RANGE; if ((table_key->flags & HA_NOSAME) && + min_part == key_tree->part && key_tree->part == table_key->key_parts-1) { + DBUG_ASSERT(min_part == max_part); if ((table_key->flags & HA_NULL_PART_KEY) && null_part_in_key(key, param->min_key, -- cgit v1.2.1 From c6aaa2adbefa04463bb9b67264c09a04b9c4bfcd Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Sat, 30 Jul 2016 10:53:01 +0300 Subject: MDEV-10228: update test results --- mysql-test/r/range_mrr_icp.result | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/mysql-test/r/range_mrr_icp.result b/mysql-test/r/range_mrr_icp.result index 9a089106c76..3f5de5b0189 100644 --- a/mysql-test/r/range_mrr_icp.result +++ b/mysql-test/r/range_mrr_icp.result @@ -2115,4 +2115,35 @@ a b 0 0 1 1 drop table t2; +# +# MDEV-10228: Delete missing rows with OR conditions +# (The example uses UPDATE, because UPDATE allows to use index hints +# and so it's possible to make an example that works with any storage +# engine) +# +CREATE TABLE t1 ( +key1varchar varchar(14) NOT NULL, +key2int int(11) NOT NULL DEFAULT '0', +col1 int, +PRIMARY KEY (key1varchar,key2int), +KEY key1varchar (key1varchar), +KEY key2int (key2int) +) DEFAULT CHARSET=utf8; +insert into t1 values +('value1',0, 0), +('value1',1, 0), +('value1',1000685, 0), +('value1',1003560, 0), +('value1',1004807, 0); +update t1 force index (PRIMARY) set col1=12345 +where (key1varchar='value1' AND (key2int <=1 OR key2int > 1)); +# The following must show col1=12345 for all rows: +select * from t1; +key1varchar key2int col1 +value1 0 12345 +value1 1 12345 +value1 1000685 12345 +value1 1003560 12345 +value1 1004807 12345 +drop table t1; set optimizer_switch=@mrr_icp_extra_tmp; -- cgit v1.2.1 From 5fdb3cfcd432b85dc305a1a61c2d018a798a6ac3 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Fri, 29 Jul 2016 18:21:08 +0200 Subject: MDEV-10419: crash in mariadb 10.1.16-MariaDB-1~trusty Fixed initialization and usage of THD reference in subselect engines. --- mysql-test/r/view.result | 15 +++++++++++++++ mysql-test/t/view.test | 15 +++++++++++++++ sql/item_subselect.cc | 8 +++++--- sql/item_subselect.h | 5 +++-- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index dbfdf3f0f56..6848ba30245 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -5520,6 +5520,21 @@ test.v1 check Error 'test.v1' is not BASE TABLE test.v1 check status Operation failed drop view v1; drop table t1; +# +# MDEV-10419: crash in mariadb 10.1.16-MariaDB-1~trusty +# +CREATE TABLE t1 (c1 CHAR(13)); +CREATE TABLE t2 (c2 CHAR(13)); +CREATE FUNCTION f() RETURNS INT RETURN 0; +CREATE OR REPLACE VIEW v1 AS select f() from t1 where c1 in (select c2 from t2); +DROP FUNCTION f; +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `f`() AS `f()` from `t1` where `test`.`t1`.`c1` in (select `test`.`t2`.`c2` from `t2`) latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +drop view v1; +drop table t1,t2; # ----------------------------------------------------------------- # -- End of 5.5 tests. # ----------------------------------------------------------------- diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index a25a4d129aa..ebd68587a47 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -5490,6 +5490,21 @@ alter table v1 check partition p1; drop view v1; drop table t1; + +--echo # +--echo # MDEV-10419: crash in mariadb 10.1.16-MariaDB-1~trusty +--echo # +CREATE TABLE t1 (c1 CHAR(13)); +CREATE TABLE t2 (c2 CHAR(13)); + +CREATE FUNCTION f() RETURNS INT RETURN 0; +CREATE OR REPLACE VIEW v1 AS select f() from t1 where c1 in (select c2 from t2); +DROP FUNCTION f; + +SHOW CREATE VIEW v1; + +drop view v1; +drop table t1,t2; --echo # ----------------------------------------------------------------- --echo # -- End of 5.5 tests. --echo # ----------------------------------------------------------------- diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 690318c610a..3727711a395 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -3308,7 +3308,7 @@ int subselect_uniquesubquery_engine::scan_table() } table->file->extra_opt(HA_EXTRA_CACHE, - current_thd->variables.read_buff_size); + get_thd()->variables.read_buff_size); table->null_row= 0; for (;;) { @@ -3746,7 +3746,7 @@ table_map subselect_union_engine::upper_select_const_tables() void subselect_single_select_engine::print(String *str, enum_query_type query_type) { - select_lex->print(thd, str, query_type); + select_lex->print(get_thd(), str, query_type); } @@ -4276,6 +4276,7 @@ bitmap_init_memroot(MY_BITMAP *map, uint n_bits, MEM_ROOT *mem_root) bool subselect_hash_sj_engine::init(List *tmp_columns, uint subquery_id) { + THD *thd= get_thd(); select_union *result_sink; /* Options to create_tmp_table. */ ulonglong tmp_create_options= thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS; @@ -5500,6 +5501,7 @@ bool subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, MY_BITMAP *partial_match_key_parts) { + THD *thd= get_thd(); /* The length in bytes of the rowids (positions) of tmp_table. */ uint rowid_length= tmp_table->file->ref_length; ha_rows row_count= tmp_table->file->stats.records; @@ -6038,7 +6040,7 @@ bool subselect_table_scan_engine::partial_match() } tmp_table->file->extra_opt(HA_EXTRA_CACHE, - current_thd->variables.read_buff_size); + get_thd()->variables.read_buff_size); for (;;) { error= tmp_table->file->ha_rnd_next(tmp_table->record[0]); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 0abfe0d5abc..a44503b4471 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -716,7 +716,8 @@ public: ROWID_MERGE_ENGINE, TABLE_SCAN_ENGINE}; subselect_engine(Item_subselect *si, - select_result_interceptor *res) + select_result_interceptor *res): + thd(NULL) { result= res; item= si; @@ -732,7 +733,7 @@ public: Should be called before prepare(). */ void set_thd(THD *thd_arg); - THD * get_thd() { return thd; } + THD * get_thd() { return thd ? thd : current_thd; } virtual int prepare(THD *)= 0; virtual void fix_length_and_dec(Item_cache** row)= 0; /* -- cgit v1.2.1 From 6b71a6d2d935d997f43a658d45d1e518620cf0ad Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 2 Aug 2016 18:52:51 +0200 Subject: MDEV-10383 Named pipes : multiple servers can listen on the same pipename Use FILE_FLAG_FIRST_PIPE_INSTANCE with the first CreateNamedPipe() call to make sure the pipe does not already exist. --- mysql-test/t/named_pipe.test | 9 +++++++++ sql/mysqld.cc | 31 +++++++++++-------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/mysql-test/t/named_pipe.test b/mysql-test/t/named_pipe.test index 8dcab3329e4..af74c200e96 100644 --- a/mysql-test/t/named_pipe.test +++ b/mysql-test/t/named_pipe.test @@ -22,3 +22,12 @@ connect(pipe_con,localhost,root,,,,,PIPE); connection default; disconnect pipe_con; + +# MDEV-10383 : check that other server cannot 'bind' on the same pipe +let $MYSQLD_DATADIR= `select @@datadir`; +--error 1 +--exec $MYSQLD_CMD --enable-named-pipe --skip-networking --log-error=second-mysqld.err +let SEARCH_FILE=$MYSQLD_DATADIR/second-mysqld.err; +let SEARCH_RANGE= -50; +let SEARCH_PATTERN=\[ERROR\] Create named pipe failed; +source include/search_pattern_in_file.inc; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3450447ceb9..9b8f964629d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2316,26 +2316,17 @@ static void network_init(void) saPipeSecurity.lpSecurityDescriptor = &sdPipeDescriptor; saPipeSecurity.bInheritHandle = FALSE; if ((hPipe= CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE | - PIPE_READMODE_BYTE | - PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - (int) global_system_variables.net_buffer_length, - (int) global_system_variables.net_buffer_length, - NMPWAIT_USE_DEFAULT_WAIT, - &saPipeSecurity)) == INVALID_HANDLE_VALUE) - { - LPVOID lpMsgBuf; - int error=GetLastError(); - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, 0, NULL ); - sql_perror((char *)lpMsgBuf); - LocalFree(lpMsgBuf); - unireg_abort(1); - } + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + (int) global_system_variables.net_buffer_length, + (int) global_system_variables.net_buffer_length, + NMPWAIT_USE_DEFAULT_WAIT, + &saPipeSecurity)) == INVALID_HANDLE_VALUE) + { + sql_perror("Create named pipe failed"); + unireg_abort(1); + } } #endif -- cgit v1.2.1 From 39177d1f2beafb5d5ae1991c26ce57d42e1f9210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 3 Aug 2016 09:00:23 +0300 Subject: MDEV-10217: innodb.innodb_bug59641 fails sporadically in buildbot: InnoDB: Failing assertion: current_rec != insert_rec in file page0cur.c line 1052 Add instrumentation to get some idea why assertion is hit if it is hit. This is temporal commit, to test on P8. --- storage/innobase/page/page0cur.c | 17 +++++++++++++++++ storage/xtradb/page/page0cur.c | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/storage/innobase/page/page0cur.c b/storage/innobase/page/page0cur.c index a722f5b188d..0990f3891bf 100644 --- a/storage/innobase/page/page0cur.c +++ b/storage/innobase/page/page0cur.c @@ -1048,6 +1048,23 @@ use_heap: insert_rec = rec_copy(insert_buf, rec, offsets); rec_offs_make_valid(insert_rec, index, offsets); + if (UNIV_UNLIKELY(current_rec == insert_rec)) { + ulint extra_len, data_len; + extra_len = rec_offs_extra_size(offsets); + data_len = rec_offs_data_size(offsets); + + fprintf(stderr, "InnoDB: Error: current_rec == insert_rec " + " extra_len %lu data_len %lu insert_buf %p rec %p\n", + extra_len, data_len, insert_buf, rec); + fprintf(stderr, "InnoDB; Physical record: \n"); + rec_print(stderr, rec, index); + fprintf(stderr, "InnoDB: Inserted record: \n"); + rec_print(stderr, insert_rec, index); + fprintf(stderr, "InnoDB: Current record: \n"); + rec_print(stderr, current_rec,index); + ut_a(current_rec != insert_rec); + } + /* 4. Insert the record in the linked list of records */ ut_ad(current_rec != insert_rec); diff --git a/storage/xtradb/page/page0cur.c b/storage/xtradb/page/page0cur.c index a722f5b188d..0990f3891bf 100644 --- a/storage/xtradb/page/page0cur.c +++ b/storage/xtradb/page/page0cur.c @@ -1048,6 +1048,23 @@ use_heap: insert_rec = rec_copy(insert_buf, rec, offsets); rec_offs_make_valid(insert_rec, index, offsets); + if (UNIV_UNLIKELY(current_rec == insert_rec)) { + ulint extra_len, data_len; + extra_len = rec_offs_extra_size(offsets); + data_len = rec_offs_data_size(offsets); + + fprintf(stderr, "InnoDB: Error: current_rec == insert_rec " + " extra_len %lu data_len %lu insert_buf %p rec %p\n", + extra_len, data_len, insert_buf, rec); + fprintf(stderr, "InnoDB; Physical record: \n"); + rec_print(stderr, rec, index); + fprintf(stderr, "InnoDB: Inserted record: \n"); + rec_print(stderr, insert_rec, index); + fprintf(stderr, "InnoDB: Current record: \n"); + rec_print(stderr, current_rec,index); + ut_a(current_rec != insert_rec); + } + /* 4. Insert the record in the linked list of records */ ut_ad(current_rec != insert_rec); -- cgit v1.2.1