mirror of
https://github.com/MariaDB/server.git
synced 2025-03-26 08:58:40 +01:00
MDEV-30469 (refactoring) Support ORDER BY and LIMIT for multi-table DELETE...
This patch includes a few changes to make the code easier to maintain: - Renamed SQL_I_List::link_in_list to SQL_I_List::insert. link_in_list was ambiguous as it could refer to a link or it could refer to a node - Remove field_name local variable in multi_update::initialize_tables because it is not used when creating the temporary tables - multi_update changes: - Move temp table callocs to init, a more natural location for them, and moved tables_to_update to const member variable so we don't recompute it. - Filter out jtbm tables and tables not in the update map, pushing those that will be updated into an update_targets container. This simplifies checks and loops in initialize_tables.
This commit is contained in:
parent
dfdbec1636
commit
02dc8615f2
12 changed files with 108 additions and 100 deletions
|
@ -7160,7 +7160,7 @@ bool subselect_single_column_match_engine::partial_match()
|
|||
|
||||
void Item_subselect::register_as_with_rec_ref(With_element *with_elem)
|
||||
{
|
||||
with_elem->sq_with_rec_ref.link_in_list(this, &this->next_with_rec_ref);
|
||||
with_elem->sq_with_rec_ref.insert(this, &this->next_with_rec_ref);
|
||||
with_recursive_reference= true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2415,7 +2415,7 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
|
|||
MDL_REQUEST_INIT_BY_KEY(&rn->mdl_request, key, MDL_SHARED, MDL_TRANSACTION);
|
||||
if (my_hash_insert(&prelocking_ctx->sroutines, (uchar *)rn))
|
||||
return FALSE;
|
||||
prelocking_ctx->sroutines_list.link_in_list(rn, &rn->next);
|
||||
prelocking_ctx->sroutines_list.insert(rn, &rn->next);
|
||||
rn->belong_to_view= belong_to_view;
|
||||
rn->m_handler= handler;
|
||||
rn->m_sp_cache_version= 0;
|
||||
|
|
|
@ -3166,7 +3166,7 @@ int sp_head::add_instr(sp_instr *instr)
|
|||
if (instr_trig_fld_list)
|
||||
{
|
||||
m_cur_instr_trig_field_items.save_and_clear(instr_trig_fld_list);
|
||||
m_trg_table_fields.link_in_list(
|
||||
m_trg_table_fields.insert(
|
||||
instr_trig_fld_list,
|
||||
&instr_trig_fld_list->first->next_trig_field_list);
|
||||
}
|
||||
|
|
|
@ -1386,7 +1386,7 @@ bool sp_instr_set_trigger_field::on_after_expr_parsing(THD *thd)
|
|||
if (!val || !trigger_field)
|
||||
return true;
|
||||
|
||||
thd->spcont->m_sp->m_cur_instr_trig_field_items.link_in_list(
|
||||
thd->spcont->m_sp->m_cur_instr_trig_field_items.insert(
|
||||
trigger_field, &trigger_field->next_trg_field);
|
||||
|
||||
value= val;
|
||||
|
|
|
@ -7601,7 +7601,8 @@ class multi_update :public select_result_interceptor
|
|||
{
|
||||
TABLE_LIST *all_tables; /* query/update command tables */
|
||||
List<TABLE_LIST> *leaves; /* list of leaves of join table tree */
|
||||
List<TABLE_LIST> updated_leaves; /* list of of updated leaves */
|
||||
List<TABLE_LIST> updated_leaves; /* a superset of tables which will be updated */
|
||||
List<TABLE_LIST> update_targets; /* the tables that will be UPDATE'd */
|
||||
TABLE_LIST *update_tables;
|
||||
TABLE **tmp_tables, *main_table, *table_to_update;
|
||||
TMP_TABLE_PARAM *tmp_table_param;
|
||||
|
@ -7633,6 +7634,7 @@ class multi_update :public select_result_interceptor
|
|||
ha_rows updated_sys_ver;
|
||||
|
||||
bool has_vers_fields;
|
||||
const table_map tables_to_update;
|
||||
|
||||
public:
|
||||
multi_update(THD *thd_arg, TABLE_LIST *ut, List<TABLE_LIST> *leaves_list,
|
||||
|
|
|
@ -51,7 +51,7 @@ bool With_clause::add_with_element(With_element *elem)
|
|||
elem->owner= this;
|
||||
elem->number= with_list.elements;
|
||||
elem->spec->with_element= elem;
|
||||
with_list.link_in_list(elem, &elem->next);
|
||||
with_list.insert(elem, &elem->next);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1112,7 +1112,7 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived)
|
|||
|
||||
void TABLE_LIST::register_as_derived_with_rec_ref(With_element *rec_elem)
|
||||
{
|
||||
rec_elem->derived_with_rec_ref.link_in_list(this, &this->next_with_rec_ref);
|
||||
rec_elem->derived_with_rec_ref.insert(this, &this->next_with_rec_ref);
|
||||
is_derived_with_recursive_reference= true;
|
||||
get_unit()->uncacheable|= UNCACHEABLE_DEPENDENT;
|
||||
}
|
||||
|
|
|
@ -242,7 +242,7 @@ bool LEX::set_trigger_new_row(const LEX_CSTRING *name, Item *val,
|
|||
Let us add this item to list of all Item_trigger_field
|
||||
objects in trigger.
|
||||
*/
|
||||
sphead->m_cur_instr_trig_field_items.link_in_list(trg_fld,
|
||||
sphead->m_cur_instr_trig_field_items.insert(trg_fld,
|
||||
&trg_fld->next_trg_field);
|
||||
|
||||
return sphead->add_instr(sp_fld);
|
||||
|
@ -8263,7 +8263,7 @@ Item *LEX::create_and_link_Item_trigger_field(THD *thd,
|
|||
in trigger.
|
||||
*/
|
||||
if (likely(trg_fld))
|
||||
sphead->m_cur_instr_trig_field_items.link_in_list(trg_fld,
|
||||
sphead->m_cur_instr_trig_field_items.insert(trg_fld,
|
||||
&trg_fld->next_trg_field);
|
||||
|
||||
return trg_fld;
|
||||
|
|
|
@ -61,7 +61,7 @@ public:
|
|||
next= &first;
|
||||
}
|
||||
|
||||
inline void link_in_list(T *element, T **next_ptr)
|
||||
inline void insert(T *element, T **next_ptr)
|
||||
{
|
||||
elements++;
|
||||
(*next)= element;
|
||||
|
|
|
@ -2065,7 +2065,7 @@ dispatch_command_return dispatch_command(enum enum_server_command command, THD *
|
|||
*/
|
||||
table_list.select_lex= thd->lex->first_select_lex();
|
||||
thd->lex->
|
||||
first_select_lex()->table_list.link_in_list(&table_list,
|
||||
first_select_lex()->table_list.insert(&table_list,
|
||||
&table_list.next_local);
|
||||
thd->lex->add_to_query_tables(&table_list);
|
||||
|
||||
|
@ -8003,7 +8003,7 @@ add_proc_to_list(THD* thd, Item *item)
|
|||
item_ptr = (Item**) (order+1);
|
||||
*item_ptr= item;
|
||||
order->item=item_ptr;
|
||||
thd->lex->proc_list.link_in_list(order, &order->next);
|
||||
thd->lex->proc_list.insert(order, &order->next);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -8024,7 +8024,7 @@ bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc)
|
|||
order->used=0;
|
||||
order->counter_used= 0;
|
||||
order->fast_field_copier_setup= 0;
|
||||
list.link_in_list(order, &order->next);
|
||||
list.insert(order, &order->next);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@ -8202,7 +8202,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
|||
and SELECT.
|
||||
*/
|
||||
if (likely(!ptr->sequence))
|
||||
table_list.link_in_list(ptr, &ptr->next_local);
|
||||
table_list.insert(ptr, &ptr->next_local);
|
||||
ptr->next_name_resolution_table= NULL;
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
ptr->partition_names= partition_names;
|
||||
|
|
|
@ -1056,7 +1056,7 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg,
|
|||
bool first_execution)
|
||||
{
|
||||
thd_arg->lex->current_select= fake_select_lex;
|
||||
fake_select_lex->table_list.link_in_list(&result_table_list,
|
||||
fake_select_lex->table_list.insert(&result_table_list,
|
||||
&result_table_list.next_local);
|
||||
fake_select_lex->context.table_list=
|
||||
fake_select_lex->context.first_name_resolution_table=
|
||||
|
|
|
@ -1782,25 +1782,47 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd)
|
|||
}
|
||||
|
||||
|
||||
multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
|
||||
multi_update::multi_update(THD *thd_arg,
|
||||
TABLE_LIST *table_list,
|
||||
List<TABLE_LIST> *leaves_list,
|
||||
List<Item> *field_list, List<Item> *value_list,
|
||||
enum enum_duplicates handle_duplicates_arg,
|
||||
bool ignore_arg):
|
||||
select_result_interceptor(thd_arg),
|
||||
all_tables(table_list), leaves(leaves_list), update_tables(0),
|
||||
tmp_tables(0), updated(0), found(0), fields(field_list),
|
||||
values(value_list), table_count(0), copy_field(0),
|
||||
handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1),
|
||||
transactional_tables(0), ignore(ignore_arg), error_handled(0), prepared(0),
|
||||
updated_sys_ver(0)
|
||||
List<Item> *field_list,
|
||||
List<Item> *value_list,
|
||||
enum enum_duplicates handle_duplicates_arg,
|
||||
bool ignore_arg)
|
||||
: select_result_interceptor(thd_arg),
|
||||
all_tables(table_list),
|
||||
leaves(leaves_list),
|
||||
update_tables(0),
|
||||
tmp_tables(0),
|
||||
updated(0),
|
||||
found(0),
|
||||
fields(field_list),
|
||||
values(value_list),
|
||||
table_count(0),
|
||||
copy_field(0),
|
||||
handle_duplicates(handle_duplicates_arg),
|
||||
do_update(1),
|
||||
trans_safe(1),
|
||||
transactional_tables(0),
|
||||
ignore(ignore_arg),
|
||||
error_handled(0),
|
||||
prepared(0),
|
||||
updated_sys_ver(0),
|
||||
tables_to_update(get_table_map(fields))
|
||||
{
|
||||
// Defer error reporting to multi_update::init whne tables_to_update is zero
|
||||
// because we don't have exceptions and we can't return values from a constructor.
|
||||
}
|
||||
|
||||
|
||||
bool multi_update::init(THD *thd)
|
||||
{
|
||||
table_map tables_to_update= get_table_map(fields);
|
||||
if (!tables_to_update)
|
||||
{
|
||||
my_message(ER_NO_TABLES_USED, ER_THD(thd, ER_NO_TABLES_USED), MYF(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
List_iterator_fast<TABLE_LIST> li(*leaves);
|
||||
TABLE_LIST *tbl;
|
||||
while ((tbl =li++))
|
||||
|
@ -1812,6 +1834,24 @@ bool multi_update::init(THD *thd)
|
|||
if (updated_leaves.push_back(tbl, thd->mem_root))
|
||||
return true;
|
||||
}
|
||||
|
||||
List_iterator<TABLE_LIST> updated_leaves_iter(updated_leaves);
|
||||
TABLE_LIST *table_ref;
|
||||
while ((table_ref= updated_leaves_iter++))
|
||||
{
|
||||
/* TODO: add support of view of join support */
|
||||
if (table_ref->is_jtbm())
|
||||
continue;
|
||||
|
||||
TABLE *table= table_ref->table;
|
||||
if (tables_to_update & table->map)
|
||||
update_targets.push_back(table_ref);
|
||||
}
|
||||
table_count= update_targets.elements;
|
||||
tmp_tables = thd->calloc<TABLE*>(table_count);
|
||||
tmp_table_param = thd->calloc<TMP_TABLE_PARAM>(table_count);
|
||||
fields_for_table= thd->alloc<List_item*>(table_count);
|
||||
values_for_table= thd->alloc<List_item*>(table_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1838,14 +1878,13 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
|||
|
||||
{
|
||||
TABLE_LIST *table_ref;
|
||||
SQL_I_List<TABLE_LIST> update;
|
||||
table_map tables_to_update;
|
||||
SQL_I_List<TABLE_LIST> update_list;
|
||||
Item_field *item;
|
||||
List_iterator_fast<Item> field_it(*fields);
|
||||
List_iterator_fast<Item> value_it(*values);
|
||||
uint i, max_fields;
|
||||
uint leaf_table_count= 0;
|
||||
List_iterator<TABLE_LIST> ti(updated_leaves);
|
||||
List_iterator<TABLE_LIST> update_targets_iter(update_targets);
|
||||
DBUG_ENTER("multi_update::prepare");
|
||||
|
||||
if (prepared)
|
||||
|
@ -1856,98 +1895,69 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
|||
thd->cuted_fields=0L;
|
||||
THD_STAGE_INFO(thd, stage_updating_main_table);
|
||||
|
||||
tables_to_update= get_table_map(fields);
|
||||
|
||||
if (!tables_to_update)
|
||||
{
|
||||
my_message(ER_NO_TABLES_USED, ER_THD(thd, ER_NO_TABLES_USED), MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
We gather the set of columns read during evaluation of SET expression in
|
||||
TABLE::tmp_set by pointing TABLE::read_set to it and then restore it after
|
||||
setup_fields().
|
||||
*/
|
||||
while ((table_ref= ti++))
|
||||
while ((table_ref= update_targets_iter++))
|
||||
{
|
||||
if (table_ref->is_jtbm())
|
||||
continue;
|
||||
|
||||
TABLE *table= table_ref->table;
|
||||
if (tables_to_update & table->map)
|
||||
{
|
||||
DBUG_ASSERT(table->read_set == &table->def_read_set);
|
||||
table->read_set= &table->tmp_set;
|
||||
bitmap_clear_all(table->read_set);
|
||||
}
|
||||
DBUG_ASSERT(table->read_set == &table->def_read_set);
|
||||
table->read_set= &table->tmp_set;
|
||||
bitmap_clear_all(table->read_set);
|
||||
}
|
||||
|
||||
/*
|
||||
We have to check values after setup_tables to get covering_keys right in
|
||||
reference tables
|
||||
*/
|
||||
|
||||
int error= setup_fields(thd, Ref_ptr_array(),
|
||||
*values, MARK_COLUMNS_READ, 0, NULL, 0) ||
|
||||
TABLE::check_assignability_explicit_fields(*fields, *values,
|
||||
ignore);
|
||||
|
||||
ti.rewind();
|
||||
while ((table_ref= ti++))
|
||||
/*
|
||||
Restore TABLE::tmp_set as we promised just before setup_tables.
|
||||
*/
|
||||
update_targets_iter.rewind();
|
||||
while ((table_ref= update_targets_iter++))
|
||||
{
|
||||
if (table_ref->is_jtbm())
|
||||
continue;
|
||||
|
||||
TABLE *table= table_ref->table;
|
||||
if (tables_to_update & table->map)
|
||||
{
|
||||
table->read_set= &table->def_read_set;
|
||||
bitmap_union(table->read_set, &table->tmp_set);
|
||||
if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_PREPARE))
|
||||
table->file->prepare_for_modify(true, true);
|
||||
}
|
||||
table->read_set= &table->def_read_set;
|
||||
bitmap_union(table->read_set, &table->tmp_set);
|
||||
if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_PREPARE))
|
||||
table->file->prepare_for_modify(true, true);
|
||||
}
|
||||
if (unlikely(error))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
/*
|
||||
Save tables being updated in update_tables
|
||||
update_table->shared is position for table
|
||||
Don't use key read on tables that are updated
|
||||
Save tables that we will update into update_list.
|
||||
table_ref->shared links this table to its corresponding temporary table
|
||||
for collecting row ids.
|
||||
Don't use key read on tables that are updated.
|
||||
*/
|
||||
|
||||
update.empty();
|
||||
ti.rewind();
|
||||
while ((table_ref= ti++))
|
||||
update_list.empty();
|
||||
update_targets_iter.rewind();
|
||||
for (uint index= 0; (table_ref= update_targets_iter++);)
|
||||
{
|
||||
/* TODO: add support of view of join support */
|
||||
if (table_ref->is_jtbm())
|
||||
continue;
|
||||
TABLE *table=table_ref->table;
|
||||
leaf_table_count++;
|
||||
if (tables_to_update & table->map)
|
||||
{
|
||||
TABLE_LIST *tl= (TABLE_LIST*) thd->memdup(table_ref,
|
||||
sizeof(*tl));
|
||||
if (!tl)
|
||||
DBUG_RETURN(1);
|
||||
update.link_in_list(tl, &tl->next_local);
|
||||
table_ref->shared= tl->shared= table_count++;
|
||||
table->no_keyread=1;
|
||||
table->covering_keys.clear_all();
|
||||
table->prepare_triggers_for_update_stmt_or_event();
|
||||
table->reset_default_fields();
|
||||
}
|
||||
TABLE_LIST *tl= (TABLE_LIST*) thd->memdup(table_ref,
|
||||
sizeof(*tl));
|
||||
if (!tl)
|
||||
DBUG_RETURN(1);
|
||||
update_list.insert(tl, &tl->next_local);
|
||||
table_ref->shared= tl->shared= index++;
|
||||
table->no_keyread=1;
|
||||
table->covering_keys.clear_all();
|
||||
table->prepare_triggers_for_update_stmt_or_event();
|
||||
table->reset_default_fields();
|
||||
}
|
||||
|
||||
table_count= update.elements;
|
||||
update_tables= update.first;
|
||||
update_tables= update_list.first;
|
||||
|
||||
tmp_tables = thd->calloc<TABLE*>(table_count);
|
||||
tmp_table_param = thd->calloc<TMP_TABLE_PARAM>(table_count);
|
||||
fields_for_table= thd->alloc<List_item*>(table_count);
|
||||
values_for_table= thd->alloc<List_item*>(table_count);
|
||||
if (unlikely(thd->is_fatal_error))
|
||||
DBUG_RETURN(1);
|
||||
for (i=0 ; i < table_count ; i++)
|
||||
|
@ -2129,7 +2139,7 @@ multi_update::initialize_tables(JOIN *join)
|
|||
for (table_ref= update_tables; table_ref; table_ref= table_ref->next_local)
|
||||
{
|
||||
TABLE *table=table_ref->table;
|
||||
uint cnt= table_ref->shared;
|
||||
uint index= table_ref->shared;
|
||||
List<Item> temp_fields;
|
||||
ORDER group;
|
||||
TMP_TABLE_PARAM *tmp_param;
|
||||
|
@ -2191,8 +2201,6 @@ loop_end:
|
|||
}
|
||||
}
|
||||
|
||||
tmp_param= tmp_table_param+cnt;
|
||||
|
||||
/*
|
||||
Create a temporary table to store all fields that are changed for this
|
||||
table. The first field in the temporary table is a pointer to the
|
||||
|
@ -2205,9 +2213,6 @@ loop_end:
|
|||
TABLE *tbl= table;
|
||||
do
|
||||
{
|
||||
LEX_CSTRING field_name;
|
||||
field_name.str= tbl->alias.c_ptr();
|
||||
field_name.length= strlen(field_name.str);
|
||||
/*
|
||||
Signal each table (including tables referenced by WITH CHECK OPTION
|
||||
clause) for which we will store row position in the temporary table
|
||||
|
@ -2225,13 +2230,14 @@ loop_end:
|
|||
DBUG_RETURN(1);
|
||||
} while ((tbl= tbl_it++));
|
||||
|
||||
temp_fields.append(fields_for_table[cnt]);
|
||||
temp_fields.append(fields_for_table[index]);
|
||||
|
||||
/* Make an unique key over the first field to avoid duplicated updates */
|
||||
bzero((char*) &group, sizeof(group));
|
||||
group.direction= ORDER::ORDER_ASC;
|
||||
group.item= (Item**) temp_fields.head_ref();
|
||||
|
||||
tmp_param= &tmp_table_param[index];
|
||||
tmp_param->init();
|
||||
tmp_param->tmp_name="update";
|
||||
tmp_param->field_count= temp_fields.elements;
|
||||
|
@ -2240,13 +2246,13 @@ loop_end:
|
|||
/* small table, ignore @@big_tables */
|
||||
my_bool save_big_tables= thd->variables.big_tables;
|
||||
thd->variables.big_tables= FALSE;
|
||||
tmp_tables[cnt]=create_tmp_table(thd, tmp_param, temp_fields,
|
||||
tmp_tables[index]=create_tmp_table(thd, tmp_param, temp_fields,
|
||||
(ORDER*) &group, 0, 0,
|
||||
TMP_TABLE_ALL_COLUMNS, HA_POS_ERROR, &empty_clex_str);
|
||||
thd->variables.big_tables= save_big_tables;
|
||||
if (!tmp_tables[cnt])
|
||||
if (!tmp_tables[index])
|
||||
DBUG_RETURN(1);
|
||||
tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
tmp_tables[index]->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
}
|
||||
join->tmp_table_keep_current_rowid= TRUE;
|
||||
DBUG_RETURN(0);
|
||||
|
|
Loading…
Add table
Reference in a new issue