Loading mysql-test/r/lock_multi.result +16 −0 Original line number Diff line number Diff line Loading @@ -99,3 +99,19 @@ kill query ERROR 70100: Query execution was interrupted unlock tables; drop table t1; CREATE TABLE t1 ( a int(11) unsigned default NULL, b varchar(255) default NULL, UNIQUE KEY a (a), KEY b (b) ); INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); CREATE TABLE t2 SELECT * FROM t1; CREATE TABLE t3 SELECT * FROM t1; # test altering of columns that multiupdate doesn't use # normal mode # PS mode # test altering of columns that multiupdate uses # normal mode # PS mode DROP TABLE t1, t2, t3; mysql-test/t/lock_multi.test +119 −0 Original line number Diff line number Diff line Loading @@ -281,4 +281,123 @@ unlock tables; connection default; drop table t1; # # Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while # ``FLUSH TABLES WITH READ LOCK'' # --connection default CREATE TABLE t1 ( a int(11) unsigned default NULL, b varchar(255) default NULL, UNIQUE KEY a (a), KEY b (b) ); INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); CREATE TABLE t2 SELECT * FROM t1; CREATE TABLE t3 SELECT * FROM t1; --echo # test altering of columns that multiupdate doesn't use --echo # normal mode --disable_query_log let $i = 100; while ($i) { --dec $i --connection writer send UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) SET a = NULL WHERE t1.b <> t2.b; --connection locker ALTER TABLE t2 ADD COLUMN (c INT); ALTER TABLE t2 DROP COLUMN c; --connection writer --reap } --echo # PS mode --connection writer PREPARE stmt FROM 'UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) SET a = NULL WHERE t1.b <> t2.b'; let $i = 100; while ($i) { --dec $i --connection writer --send EXECUTE stmt --connection locker ALTER TABLE t2 ADD COLUMN (c INT); ALTER TABLE t2 DROP COLUMN c; --connection writer --reap } --enable_query_log --echo # test altering of columns that multiupdate uses --echo # normal mode --connection default --disable_query_log let $i = 100; while ($i) { dec $i; --connection locker --error 0,1060 ALTER TABLE t2 ADD COLUMN a int(11) unsigned default NULL; UPDATE t2 SET a=b; --connection writer --send UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) SET a = NULL WHERE t1.b <> t2.b --connection locker --error 0,1091 ALTER TABLE t2 DROP COLUMN a; --connection writer --error 0,1054 --reap } --enable_query_log --echo # PS mode --disable_query_log let $i = 100; while ($i) { dec $i; --connection locker --error 0,1060 ALTER TABLE t2 ADD COLUMN a int(11) unsigned default NULL; UPDATE t2 SET a=b; --connection writer PREPARE stmt FROM 'UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) SET a = NULL WHERE t1.b <> t2.b'; --send EXECUTE stmt --connection locker --error 0,1091 ALTER TABLE t2 DROP COLUMN a; --connection writer --error 0,1054 --reap } --enable_query_log --connection default DROP TABLE t1, t2, t3; # End of 5.0 tests sql/item.cc +6 −4 Original line number Diff line number Diff line Loading @@ -1758,13 +1758,15 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, We need to copy db_name, table_name and field_name because they must be allocated in the statement memory, not in table memory (the table structure can go away and pop up again between subsequent executions of a prepared statement). of a prepared statement or after the close_tables_for_reopen() call in mysql_multi_update_prepare()). */ if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) { if (db_name) orig_db_name= thd->strdup(db_name); if (table_name) orig_table_name= thd->strdup(table_name); if (field_name) orig_field_name= thd->strdup(field_name); /* We don't restore 'name' in cleanup because it's not changed Loading sql/sql_base.cc +28 −6 Original line number Diff line number Diff line Loading @@ -3617,8 +3617,21 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, { /* This is a base table. */ DBUG_ASSERT(nj_col->view_field == NULL); DBUG_ASSERT(nj_col->table_ref->table == nj_col->table_field->table); found_field= nj_col->table_field; /* This fix_fields is not necessary (initially this item is fixed by the Item_field constructor; after reopen_tables the Item_func_eq calls fix_fields on that item), it's just a check during table reopening for columns that was dropped by the concurrent connection. */ if (!nj_col->table_field->fixed && nj_col->table_field->fix_fields(thd, (Item **)&nj_col->table_field)) { DBUG_PRINT("info", ("column '%s' was dropped by the concurrent connection", nj_col->table_field->name)); DBUG_RETURN(NULL); } DBUG_ASSERT(nj_col->table_ref->table == nj_col->table_field->field->table); found_field= nj_col->table_field->field; update_field_dependencies(thd, found_field, nj_col->table_ref->table); } Loading Loading @@ -4450,7 +4463,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, const char *field_name_1; /* true if field_name_1 is a member of using_fields */ bool is_using_column_1; if (!(nj_col_1= it_1.get_or_create_column_ref(leaf_1))) if (!(nj_col_1= it_1.get_or_create_column_ref(thd, leaf_1))) goto err; field_name_1= nj_col_1->name(); is_using_column_1= using_fields && Loading @@ -4471,7 +4484,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, { Natural_join_column *cur_nj_col_2; const char *cur_field_name_2; if (!(cur_nj_col_2= it_2.get_or_create_column_ref(leaf_2))) if (!(cur_nj_col_2= it_2.get_or_create_column_ref(thd, leaf_2))) goto err; cur_field_name_2= cur_nj_col_2->name(); DBUG_PRINT ("info", ("cur_field_name_2=%s.%s", Loading Loading @@ -4957,15 +4970,24 @@ static bool setup_natural_join_row_types(THD *thd, TABLE_LIST *left_neighbor; /* Table reference to the right of the current. */ TABLE_LIST *right_neighbor= NULL; bool save_first_natural_join_processing= context->select_lex->first_natural_join_processing; context->select_lex->first_natural_join_processing= FALSE; /* Note that tables in the list are in reversed order */ for (left_neighbor= table_ref_it++; left_neighbor ; ) { table_ref= left_neighbor; left_neighbor= table_ref_it++; /* For stored procedures do not redo work if already done. */ if (context->select_lex->first_execution) /* Do not redo work if already done: 1) for stored procedures, 2) for multitable update after lock failure and table reopening. */ if (save_first_natural_join_processing) { context->select_lex->first_natural_join_processing= FALSE; if (store_top_level_join_columns(thd, table_ref, left_neighbor, right_neighbor)) return TRUE; Loading sql/sql_lex.cc +1 −0 Original line number Diff line number Diff line Loading @@ -1205,6 +1205,7 @@ void st_select_lex::init_query() subquery_in_having= explicit_limit= 0; is_item_list_lookup= 0; first_execution= 1; first_natural_join_processing= 1; first_cond_optimization= 1; parsing_place= NO_MATTER; exclude_from_table_unique_test= no_wrap_view_item= FALSE; Loading Loading
mysql-test/r/lock_multi.result +16 −0 Original line number Diff line number Diff line Loading @@ -99,3 +99,19 @@ kill query ERROR 70100: Query execution was interrupted unlock tables; drop table t1; CREATE TABLE t1 ( a int(11) unsigned default NULL, b varchar(255) default NULL, UNIQUE KEY a (a), KEY b (b) ); INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); CREATE TABLE t2 SELECT * FROM t1; CREATE TABLE t3 SELECT * FROM t1; # test altering of columns that multiupdate doesn't use # normal mode # PS mode # test altering of columns that multiupdate uses # normal mode # PS mode DROP TABLE t1, t2, t3;
mysql-test/t/lock_multi.test +119 −0 Original line number Diff line number Diff line Loading @@ -281,4 +281,123 @@ unlock tables; connection default; drop table t1; # # Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while # ``FLUSH TABLES WITH READ LOCK'' # --connection default CREATE TABLE t1 ( a int(11) unsigned default NULL, b varchar(255) default NULL, UNIQUE KEY a (a), KEY b (b) ); INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); CREATE TABLE t2 SELECT * FROM t1; CREATE TABLE t3 SELECT * FROM t1; --echo # test altering of columns that multiupdate doesn't use --echo # normal mode --disable_query_log let $i = 100; while ($i) { --dec $i --connection writer send UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) SET a = NULL WHERE t1.b <> t2.b; --connection locker ALTER TABLE t2 ADD COLUMN (c INT); ALTER TABLE t2 DROP COLUMN c; --connection writer --reap } --echo # PS mode --connection writer PREPARE stmt FROM 'UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) SET a = NULL WHERE t1.b <> t2.b'; let $i = 100; while ($i) { --dec $i --connection writer --send EXECUTE stmt --connection locker ALTER TABLE t2 ADD COLUMN (c INT); ALTER TABLE t2 DROP COLUMN c; --connection writer --reap } --enable_query_log --echo # test altering of columns that multiupdate uses --echo # normal mode --connection default --disable_query_log let $i = 100; while ($i) { dec $i; --connection locker --error 0,1060 ALTER TABLE t2 ADD COLUMN a int(11) unsigned default NULL; UPDATE t2 SET a=b; --connection writer --send UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) SET a = NULL WHERE t1.b <> t2.b --connection locker --error 0,1091 ALTER TABLE t2 DROP COLUMN a; --connection writer --error 0,1054 --reap } --enable_query_log --echo # PS mode --disable_query_log let $i = 100; while ($i) { dec $i; --connection locker --error 0,1060 ALTER TABLE t2 ADD COLUMN a int(11) unsigned default NULL; UPDATE t2 SET a=b; --connection writer PREPARE stmt FROM 'UPDATE t2 INNER JOIN (t1 JOIN t3 USING(a)) USING(a) SET a = NULL WHERE t1.b <> t2.b'; --send EXECUTE stmt --connection locker --error 0,1091 ALTER TABLE t2 DROP COLUMN a; --connection writer --error 0,1054 --reap } --enable_query_log --connection default DROP TABLE t1, t2, t3; # End of 5.0 tests
sql/item.cc +6 −4 Original line number Diff line number Diff line Loading @@ -1758,13 +1758,15 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, We need to copy db_name, table_name and field_name because they must be allocated in the statement memory, not in table memory (the table structure can go away and pop up again between subsequent executions of a prepared statement). of a prepared statement or after the close_tables_for_reopen() call in mysql_multi_update_prepare()). */ if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) { if (db_name) orig_db_name= thd->strdup(db_name); if (table_name) orig_table_name= thd->strdup(table_name); if (field_name) orig_field_name= thd->strdup(field_name); /* We don't restore 'name' in cleanup because it's not changed Loading
sql/sql_base.cc +28 −6 Original line number Diff line number Diff line Loading @@ -3617,8 +3617,21 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, { /* This is a base table. */ DBUG_ASSERT(nj_col->view_field == NULL); DBUG_ASSERT(nj_col->table_ref->table == nj_col->table_field->table); found_field= nj_col->table_field; /* This fix_fields is not necessary (initially this item is fixed by the Item_field constructor; after reopen_tables the Item_func_eq calls fix_fields on that item), it's just a check during table reopening for columns that was dropped by the concurrent connection. */ if (!nj_col->table_field->fixed && nj_col->table_field->fix_fields(thd, (Item **)&nj_col->table_field)) { DBUG_PRINT("info", ("column '%s' was dropped by the concurrent connection", nj_col->table_field->name)); DBUG_RETURN(NULL); } DBUG_ASSERT(nj_col->table_ref->table == nj_col->table_field->field->table); found_field= nj_col->table_field->field; update_field_dependencies(thd, found_field, nj_col->table_ref->table); } Loading Loading @@ -4450,7 +4463,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, const char *field_name_1; /* true if field_name_1 is a member of using_fields */ bool is_using_column_1; if (!(nj_col_1= it_1.get_or_create_column_ref(leaf_1))) if (!(nj_col_1= it_1.get_or_create_column_ref(thd, leaf_1))) goto err; field_name_1= nj_col_1->name(); is_using_column_1= using_fields && Loading @@ -4471,7 +4484,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, { Natural_join_column *cur_nj_col_2; const char *cur_field_name_2; if (!(cur_nj_col_2= it_2.get_or_create_column_ref(leaf_2))) if (!(cur_nj_col_2= it_2.get_or_create_column_ref(thd, leaf_2))) goto err; cur_field_name_2= cur_nj_col_2->name(); DBUG_PRINT ("info", ("cur_field_name_2=%s.%s", Loading Loading @@ -4957,15 +4970,24 @@ static bool setup_natural_join_row_types(THD *thd, TABLE_LIST *left_neighbor; /* Table reference to the right of the current. */ TABLE_LIST *right_neighbor= NULL; bool save_first_natural_join_processing= context->select_lex->first_natural_join_processing; context->select_lex->first_natural_join_processing= FALSE; /* Note that tables in the list are in reversed order */ for (left_neighbor= table_ref_it++; left_neighbor ; ) { table_ref= left_neighbor; left_neighbor= table_ref_it++; /* For stored procedures do not redo work if already done. */ if (context->select_lex->first_execution) /* Do not redo work if already done: 1) for stored procedures, 2) for multitable update after lock failure and table reopening. */ if (save_first_natural_join_processing) { context->select_lex->first_natural_join_processing= FALSE; if (store_top_level_join_columns(thd, table_ref, left_neighbor, right_neighbor)) return TRUE; Loading
sql/sql_lex.cc +1 −0 Original line number Diff line number Diff line Loading @@ -1205,6 +1205,7 @@ void st_select_lex::init_query() subquery_in_having= explicit_limit= 0; is_item_list_lookup= 0; first_execution= 1; first_natural_join_processing= 1; first_cond_optimization= 1; parsing_place= NO_MATTER; exclude_from_table_unique_test= no_wrap_view_item= FALSE; Loading