mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-13417 UPDATE produces wrong values if an updated column is later used as an update source
Standard compatible behavior for UPDATE: all assignments in SET are executed "simultaneously", not left-to-right. And `SET a=b,b=a` will swap the values.
This commit is contained in:
committed by
Sergei Golubchik
parent
355ee6877b
commit
d943d7f712
@ -132,25 +132,50 @@ bool compare_record(const TABLE *table)
|
||||
FALSE Items are OK
|
||||
*/
|
||||
|
||||
static bool check_fields(THD *thd, List<Item> &items)
|
||||
static bool check_fields(THD *thd, List<Item> &items, bool update_view)
|
||||
{
|
||||
List_iterator<Item> it(items);
|
||||
Item *item;
|
||||
Item_field *field;
|
||||
|
||||
while ((item= it++))
|
||||
if (update_view)
|
||||
{
|
||||
if (!(field= item->field_for_view_update()))
|
||||
List_iterator<Item> it(items);
|
||||
Item_field *field;
|
||||
while ((item= it++))
|
||||
{
|
||||
/* item has name, because it comes from VIEW SELECT list */
|
||||
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str);
|
||||
return TRUE;
|
||||
if (!(field= item->field_for_view_update()))
|
||||
{
|
||||
/* item has name, because it comes from VIEW SELECT list */
|
||||
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str);
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
we make temporary copy of Item_field, to avoid influence of changing
|
||||
result_field on Item_ref which refer on this field
|
||||
*/
|
||||
thd->change_item_tree(it.ref(),
|
||||
new (thd->mem_root) Item_field(thd, field));
|
||||
}
|
||||
}
|
||||
|
||||
if (thd->variables.sql_mode & MODE_SIMULTANEOUS_ASSIGNMENT)
|
||||
{
|
||||
// Make sure that a column is updated only once
|
||||
List_iterator_fast<Item> it(items);
|
||||
while ((item= it++))
|
||||
{
|
||||
item->field_for_view_update()->field->clear_has_explicit_value();
|
||||
}
|
||||
it.rewind();
|
||||
while ((item= it++))
|
||||
{
|
||||
Field *f= item->field_for_view_update()->field;
|
||||
if (f->has_explicit_value())
|
||||
{
|
||||
my_error(ER_UPDATED_COLUMN_ONLY_ONCE, MYF(0),
|
||||
*(f->table_name), f->field_name.str);
|
||||
return TRUE;
|
||||
}
|
||||
f->set_has_explicit_value();
|
||||
}
|
||||
/*
|
||||
we make temporary copy of Item_field, to avoid influence of changing
|
||||
result_field on Item_ref which refer on this field
|
||||
*/
|
||||
thd->change_item_tree(it.ref(), new (thd->mem_root) Item_field(thd, field));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@ -373,7 +398,7 @@ int mysql_update(THD *thd,
|
||||
if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
|
||||
fields, MARK_COLUMNS_WRITE, 0, 0))
|
||||
DBUG_RETURN(1); /* purecov: inspected */
|
||||
if (table_list->view && check_fields(thd, fields))
|
||||
if (check_fields(thd, fields, table_list->view))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
@ -1534,6 +1559,7 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
//We need to merge for insert prior to prepare.
|
||||
if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (mysql_handle_derived(lex, DT_PREPARE))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
@ -1560,7 +1586,7 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
}
|
||||
}
|
||||
|
||||
if (update_view && check_fields(thd, *fields))
|
||||
if (check_fields(thd, *fields, update_view))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
Reference in New Issue
Block a user