1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-14551 Can't find record in table on multi-table update with ORDER BY

preserve positions if the multi-update join is using tmp table:

* store positions in the tmp table if needed
  JOIN::add_fields_for_current_rowid()

* take positions from the tmp table, not from file->position():
  multi_update::prepare2()
This commit is contained in:
Sergei Golubchik
2018-04-04 15:34:40 +02:00
parent e17e798599
commit 28dbdf3d79
12 changed files with 218 additions and 12 deletions

View File

@ -2198,10 +2198,66 @@ loop_end:
DBUG_RETURN(1);
tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
}
join->tmp_table_keep_current_rowid= TRUE;
DBUG_RETURN(0);
}
static TABLE *item_rowid_table(Item *item)
{
if (item->type() != Item::FUNC_ITEM)
return NULL;
Item_func *func= (Item_func *)item;
if (func->functype() != Item_func::TEMPTABLE_ROWID)
return NULL;
Item_temptable_rowid *itr= (Item_temptable_rowid *)func;
return itr->table;
}
/*
multi_update stores a rowid and new field values for every updated row in a
temporary table (one temporary table per updated table). These rowids are
obtained via Item_temptable_rowid's by calling handler::position(). But if
the join is resolved via a temp table, rowids cannot be obtained from
handler::position() in the multi_update::send_data(). So, they're stored in
the join's temp table (JOIN::add_fields_for_current_rowid()) and here we
replace Item_temptable_rowid's (that would've done handler::position()) with
Item_field's (that will simply take the corresponding field value from the
temp table).
*/
int multi_update::prepare2(JOIN *join)
{
if (!join->need_tmp || !join->tmp_table_keep_current_rowid)
return 0;
// there cannot be many tmp tables in multi-update
JOIN_TAB *tmptab= join->join_tab + join->exec_join_tab_cnt();
for (Item **it= tmptab->tmp_table_param->items_to_copy; *it ; it++)
{
TABLE *tbl= item_rowid_table(*it);
if (!tbl)
continue;
for (uint i= 0; i < table_count; i++)
{
for (Item **it2= tmp_table_param[i].items_to_copy; *it2; it2++)
{
if (item_rowid_table(*it2) != tbl)
continue;
Item *fld= new (thd->mem_root)
Item_field(thd, (*it)->get_tmp_table_field());
if (!fld)
return 1;
fld->set_result_field((*it2)->get_tmp_table_field());
*it2= fld;
}
}
}
return 0;
}
multi_update::~multi_update()
{
TABLE_LIST *table;