summaryrefslogtreecommitdiff
path: root/sql/sql_update.cc
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2018-04-04 15:34:40 +0200
committerSergei Golubchik <serg@mariadb.org>2018-05-17 15:13:47 +0200
commit28dbdf3d79cfd39ffa2e1d087662ac82c9281d1d (patch)
tree7b93934b2e32c08e870351783f8933c62881cefa /sql/sql_update.cc
parente17e7985999b10c602ba72258e9a4b6e5fb91ed5 (diff)
downloadmariadb-git-28dbdf3d79cfd39ffa2e1d087662ac82c9281d1d.tar.gz
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()
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r--sql/sql_update.cc56
1 files changed, 56 insertions, 0 deletions
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 829bfa546ce..a8b86448d5e 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -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;