summaryrefslogtreecommitdiff
path: root/sql/sql_base.cc
diff options
context:
space:
mode:
authorGleb Shchepa <gshchepa@mysql.com>2008-10-08 02:34:00 +0500
committerGleb Shchepa <gshchepa@mysql.com>2008-10-08 02:34:00 +0500
commitf48b42e77657dd2e27380201631fd0f137863b85 (patch)
tree384f8d90fd9749658c189cb58badeb9a8114b295 /sql/sql_base.cc
parent1ce81aac15f0e7a89aef78f8e25ec7976f37972c (diff)
downloadmariadb-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.cc34
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;