diff options
author | Daniel Fischer <df@sun.com> | 2009-04-30 12:36:18 +0200 |
---|---|---|
committer | Daniel Fischer <df@sun.com> | 2009-04-30 12:36:18 +0200 |
commit | 4c60b1d4b74798ae55da9e2f49493e058df67b38 (patch) | |
tree | 067efd4f9fd87d52c9e3b88472c890ac8644fca0 | |
parent | 8c1bb95156851b142750b61203e760042646d166 (diff) | |
download | mariadb-git-4c60b1d4b74798ae55da9e2f49493e058df67b38.tar.gz |
backport #42419, commits 66925, 66999
-rw-r--r-- | mysql-test/r/innodb_mysql.result | 32 | ||||
-rw-r--r-- | mysql-test/t/innodb_mysql.test | 69 | ||||
-rw-r--r-- | sql/sql_select.cc | 36 |
3 files changed, 125 insertions, 12 deletions
diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 682cc2e82e2..0cf0d0f5536 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1267,4 +1267,36 @@ CREATE INDEX i1 on t1 (a(3)); SELECT * FROM t1 WHERE a = 'abcde'; a DROP TABLE t1; +CREATE DATABASE systest1; +USE systest1; +CREATE TABLE tb1_eng1 ( +i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1), +f1 INT +) ENGINE = InnoDB; +INSERT INTO systest1.tb1_eng1 VALUES (1,1),(2,2),(3,3); +COMMIT; +SET AUTOCOMMIT = 0; +CREATE TEMPORARY TABLE systest1.t1_tmp ( f1 INT ); +INSERT INTO systest1.t1_tmp (f1) +SELECT f1 FROM systest1.tb1_eng1 WHERE i1 = 3; +INSERT INTO systest1.t1_tmp (f1) +SELECT f1 FROM systest1.tb1_eng1 WHERE i1 = 2; +SET AUTOCOMMIT = 0; +USE systest1; +CREATE TEMPORARY TABLE systest1.t2_tmp ( i1 int, new_i1 int ); +INSERT INTO systest1.t2_tmp VALUES +(1,51),(2,52),(3,53); +UPDATE systest1.tb1_eng1 target +SET i1 = (SELECT new_i1 FROM systest1.t2_tmp source WHERE source.i1 = target.i1) +WHERE i1 = 1; +UPDATE systest1.tb1_eng1 target +SET i1 = (SELECT new_i1 FROM systest1.t2_tmp source WHERE source.i1 = target.i1) +WHERE i1 = 2; +INSERT INTO systest1.t1_tmp (f1) +SELECT f1 FROM systest1.tb1_eng1 WHERE i1 = 1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +UPDATE systest1.tb1_eng1 target +SET i1 = (SELECT new_i1 FROM systest1.t2_tmp source WHERE source.i1 = target.i1) +WHERE i1 = 3; +drop database systest1; End of 5.0 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index b4fc425cb7c..f830399b919 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -1025,4 +1025,73 @@ CREATE INDEX i1 on t1 (a(3)); SELECT * FROM t1 WHERE a = 'abcde'; DROP TABLE t1; +# +# Bug #42419: Server crash with "Pure virtual method called" on two +# concurrent connections +# + +connect (c1, localhost, root,,); +connect (c2, localhost, root,,); + +CREATE DATABASE systest1; +USE systest1; + +CREATE TABLE tb1_eng1 ( + i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1), + f1 INT +) ENGINE = InnoDB; + +INSERT INTO systest1.tb1_eng1 VALUES (1,1),(2,2),(3,3); +COMMIT; + +connection c1; + +SET AUTOCOMMIT = 0; + +CREATE TEMPORARY TABLE systest1.t1_tmp ( f1 INT ); + +INSERT INTO systest1.t1_tmp (f1) + SELECT f1 FROM systest1.tb1_eng1 WHERE i1 = 3; +INSERT INTO systest1.t1_tmp (f1) + SELECT f1 FROM systest1.tb1_eng1 WHERE i1 = 2; + + +connection c2; + +SET AUTOCOMMIT = 0; +USE systest1; + +CREATE TEMPORARY TABLE systest1.t2_tmp ( i1 int, new_i1 int ); +INSERT INTO systest1.t2_tmp VALUES +(1,51),(2,52),(3,53); + +UPDATE systest1.tb1_eng1 target +SET i1 = (SELECT new_i1 FROM systest1.t2_tmp source WHERE source.i1 = target.i1) + WHERE i1 = 1; + +--send +UPDATE systest1.tb1_eng1 target +SET i1 = (SELECT new_i1 FROM systest1.t2_tmp source WHERE source.i1 = target.i1) + WHERE i1 = 2; + +--sleep 2 + +connection c1; + +--error ER_LOCK_DEADLOCK +INSERT INTO systest1.t1_tmp (f1) + SELECT f1 FROM systest1.tb1_eng1 WHERE i1 = 1; + +connection c2; + +--reap +UPDATE systest1.tb1_eng1 target +SET i1 = (SELECT new_i1 FROM systest1.t2_tmp source WHERE source.i1 = target.i1) + WHERE i1 = 3; + +connection default; +disconnect c1; +disconnect c2; +drop database systest1; + --echo End of 5.0 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2ac33c4e07f..f78991073bb 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2366,11 +2366,12 @@ typedef struct st_sargable_param */ static bool -make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, +make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, DYNAMIC_ARRAY *keyuse_array) { int error; TABLE *table; + TABLE_LIST *tables= tables_arg; uint i,table_count,const_count,key; table_map found_const_table_map, all_table_map, found_ref, refs; key_map const_ref, eq_part; @@ -2408,10 +2409,10 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, table_vector[i]=s->table=table=tables->table; table->pos_in_table_list= tables; error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); - if(error) + if (error) { - table->file->print_error(error, MYF(0)); - DBUG_RETURN(1); + table->file->print_error(error, MYF(0)); + goto error; } table->quick_keys.clear_all(); table->reginfo.join_tab=s; @@ -2496,7 +2497,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, { join->tables=0; // Don't use join->table my_message(ER_WRONG_OUTER_JOIN, ER(ER_WRONG_OUTER_JOIN), MYF(0)); - DBUG_RETURN(1); + goto error; } s->key_dependent= s->dependent; } @@ -2506,7 +2507,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables, conds, join->cond_equal, ~outer_join, join->select_lex, &sargables)) - DBUG_RETURN(1); + goto error; /* Read tables with 0 or 1 rows (system tables) */ join->const_table_map= 0; @@ -2522,7 +2523,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if ((tmp=join_read_const_table(s, p_pos))) { if (tmp > 0) - DBUG_RETURN(1); // Fatal error + goto error; // Fatal error } else found_const_table_map|= s->table->map; @@ -2594,7 +2595,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if ((tmp= join_read_const_table(s, join->positions+const_count-1))) { if (tmp > 0) - DBUG_RETURN(1); // Fatal error + goto error; // Fatal error } else found_const_table_map|= table->map; @@ -2643,12 +2644,12 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, set_position(join,const_count++,s,start_keyuse); if (create_ref_for_key(join, s, start_keyuse, found_const_table_map)) - DBUG_RETURN(1); + goto error; if ((tmp=join_read_const_table(s, join->positions+const_count-1))) { if (tmp > 0) - DBUG_RETURN(1); // Fatal error + goto error; // Fatal error } else found_const_table_map|= table->map; @@ -2725,7 +2726,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, *s->on_expr_ref ? *s->on_expr_ref : conds, 1, &error); if (!select) - DBUG_RETURN(1); + goto error; records= get_quick_record_count(join->thd, select, s->table, &s->const_keys, join->row_limit); s->quick=select->quick; @@ -2771,7 +2772,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, { optimize_keyuse(join, keyuse_array); if (choose_plan(join, all_table_map & ~join->const_table_map)) - DBUG_RETURN(TRUE); + goto error; } else { @@ -2781,6 +2782,17 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, } /* Generate an execution plan from the found optimal join order. */ DBUG_RETURN(join->thd->killed || get_best_combination(join)); + +error: + /* + Need to clean up join_tab from TABLEs in case of error. + They won't get cleaned up by JOIN::cleanup() because JOIN::join_tab + may not be assigned yet by this function (which is building join_tab). + Dangling TABLE::reginfo.join_tab may cause part_of_refkey to choke. + */ + for (tables= tables_arg; tables; tables= tables->next_leaf) + tables->table->reginfo.join_tab= NULL; + DBUG_RETURN (1); } |