diff options
author | Gleb Shchepa <gshchepa@mysql.com> | 2008-10-08 02:34:00 +0500 |
---|---|---|
committer | Gleb Shchepa <gshchepa@mysql.com> | 2008-10-08 02:34:00 +0500 |
commit | f48b42e77657dd2e27380201631fd0f137863b85 (patch) | |
tree | 384f8d90fd9749658c189cb58badeb9a8114b295 /sql/sql_base.cc | |
parent | 1ce81aac15f0e7a89aef78f8e25ec7976f37972c (diff) | |
download | mariadb-git-f48b42e77657dd2e27380201631fd0f137863b85.tar.gz |
Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while
``FLUSH TABLES WITH READ LOCK''
Concurrent execution of 1) multitable update with a
NATURAL/USING join and 2) a such query as "FLUSH TABLES
WITH READ LOCK" or "ALTER TABLE" of updating table led
to a server crash.
The mysql_multi_update_prepare() function call is optimized
to lock updating tables only, so it postpones locking to
the last, and if locking fails, it does cleanup of modified
syntax structures and repeats a query analysis. However,
that cleanup procedure was incomplete for NATURAL/USING join
syntax data: 1) some Field_item items pointed into freed
table structures, and 2) the TABLE_LIST::join_columns fields
was not reset.
Major change:
short-living Field *Natural_join_column::table_field has
been replaced with long-living Item*.
mysql-test/r/lock_multi.result:
Added test case for bug #38691.
mysql-test/t/lock_multi.test:
Added test case for bug #38691.
sql/item.cc:
Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while
``FLUSH TABLES WITH READ LOCK''
The Item_field constructor has been modified to allocate
and copy original database/table/field names always (not
during PS preparation/1st execution only), because
an initialization of Item_field items with a pointer to
short-living Field structures is a common practice.
sql/sql_base.cc:
Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while
``FLUSH TABLES WITH READ LOCK''
1) Type adjustment for Natural_join_column::table_field
(Field to Item_field);
2) The setup_natural_join_row_types function has been
updated to take into account new
first_natural_join_processing flag to skip unnecessary
reinitialization of Natural_join_column::join_columns
during table reopening after lock_tables() failure
(like the 'first_execution' flag for PS).
sql/sql_lex.cc:
Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while
``FLUSH TABLES WITH READ LOCK''
Initialization of the new
st_select_lex::first_natural_join_processing flag has
been added.
sql/sql_lex.h:
Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while
``FLUSH TABLES WITH READ LOCK''
The st_select_lex::first_natural_join_processing flag
has been added to skip unnecessary rebuilding of
NATURAL/USING JOIN structures during table reopening
after lock_tables failure.
sql/sql_update.cc:
Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while
``FLUSH TABLES WITH READ LOCK''
Extra cleanup calls have been added to reset
Natural_join_column::table_field items.
sql/table.cc:
Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while
``FLUSH TABLES WITH READ LOCK''
Type adjustment for Natural_join_column::table_field
(Field to Item_field).
sql/table.h:
Bug #38691: segfault/abort in ``UPDATE ...JOIN'' while
``FLUSH TABLES WITH READ LOCK''
Type of the Natural_join_column::table_field field has
been changed from Field that points into short-living
TABLE memory to long-living Item_field that can be
linked to (fixed) reopened table.
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 34 |
1 files changed, 28 insertions, 6 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 533b0070fee..d969c837891 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -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); } @@ -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 && @@ -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", @@ -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; |