mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 12:32:27 +01:00
Merge epotemkin@bk-internal.mysql.com:/home/bk/mysql-5.0-opt
into moonbone.local:/mnt/gentoo64/work/16630-bug-5.0-opt-mysql sql/item.cc: Auto merged sql/sql_select.cc: Auto merged
This commit is contained in:
commit
98f87d9702
6 changed files with 94 additions and 3 deletions
|
@ -731,3 +731,16 @@ select @@identity;
|
|||
@@identity
|
||||
0
|
||||
drop table t1;
|
||||
CREATE TABLE t1 (f1 INT, f2 INT );
|
||||
CREATE TABLE t2 (f1 INT PRIMARY KEY, f2 INT);
|
||||
INSERT INTO t1 VALUES (1,1),(2,2),(10,10);
|
||||
INSERT INTO t2 (f1, f2) SELECT f1, f2 FROM t1;
|
||||
INSERT INTO t2 (f1, f2)
|
||||
SELECT f1, f1 FROM t2 src WHERE f1 < 2
|
||||
ON DUPLICATE KEY UPDATE f1 = 100 + src.f1;
|
||||
SELECT * FROM t2;
|
||||
f1 f2
|
||||
101 1
|
||||
2 2
|
||||
10 10
|
||||
DROP TABLE t1, t2;
|
||||
|
|
|
@ -292,3 +292,18 @@ select @@identity;
|
|||
insert ignore t1(f2) select 1;
|
||||
select @@identity;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug#16630: wrong result, when INSERT t1 SELECT ... FROM t1 ON DUPLICATE
|
||||
#
|
||||
CREATE TABLE t1 (f1 INT, f2 INT );
|
||||
CREATE TABLE t2 (f1 INT PRIMARY KEY, f2 INT);
|
||||
INSERT INTO t1 VALUES (1,1),(2,2),(10,10);
|
||||
INSERT INTO t2 (f1, f2) SELECT f1, f2 FROM t1;
|
||||
INSERT INTO t2 (f1, f2)
|
||||
SELECT f1, f1 FROM t2 src WHERE f1 < 2
|
||||
ON DUPLICATE KEY UPDATE f1 = 100 + src.f1;
|
||||
SELECT * FROM t2;
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
|
||||
|
|
45
sql/item.cc
45
sql/item.cc
|
@ -4809,6 +4809,51 @@ void Item_field::update_null_value()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Add the field to the select list and substitute it for the reference to
|
||||
the field.
|
||||
|
||||
SYNOPSIS
|
||||
Item_field::update_value_transformer()
|
||||
select_arg current select
|
||||
|
||||
DESCRIPTION
|
||||
If the field doesn't belong to the table being inserted into then it is
|
||||
added to the select list, pointer to it is stored in the ref_pointer_array
|
||||
of the select and the field itself is substituted for the Item_ref object.
|
||||
This is done in order to get correct values from update fields that
|
||||
belongs to the SELECT part in the INSERT .. SELECT .. ON DUPLICATE KEY
|
||||
UPDATE statement.
|
||||
|
||||
RETURN
|
||||
0 if error occured
|
||||
ref if all conditions are met
|
||||
this field otherwise
|
||||
*/
|
||||
|
||||
Item *Item_field::update_value_transformer(byte *select_arg)
|
||||
{
|
||||
SELECT_LEX *select= (SELECT_LEX*)select_arg;
|
||||
DBUG_ASSERT(fixed);
|
||||
|
||||
if (field->table != select->context.table_list->table &&
|
||||
type() != Item::TRIGGER_FIELD_ITEM)
|
||||
{
|
||||
List<Item> *all_fields= &select->join->all_fields;
|
||||
Item **ref_pointer_array= select->ref_pointer_array;
|
||||
int el= all_fields->elements;
|
||||
Item_ref *ref;
|
||||
|
||||
ref_pointer_array[el]= (Item*)this;
|
||||
all_fields->push_front((Item*)this);
|
||||
ref= new Item_ref(&select->context, ref_pointer_array + el,
|
||||
table_name, field_name);
|
||||
return ref;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
Item_ref::Item_ref(Name_resolution_context *context_arg,
|
||||
Item **item, const char *table_name_arg,
|
||||
const char *field_name_arg)
|
||||
|
|
|
@ -817,6 +817,7 @@ public:
|
|||
virtual Item_field *filed_for_view_update() { return 0; }
|
||||
|
||||
virtual Item *neg_transformer(THD *thd) { return NULL; }
|
||||
virtual Item *update_value_transformer(byte *select_arg) { return this; }
|
||||
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
|
||||
void delete_self()
|
||||
{
|
||||
|
@ -1295,6 +1296,7 @@ public:
|
|||
Item_field *filed_for_view_update() { return this; }
|
||||
Item *safe_charset_converter(CHARSET_INFO *tocs);
|
||||
int fix_outer_field(THD *thd, Field **field, Item **reference);
|
||||
virtual Item *update_value_transformer(byte *select_arg);
|
||||
friend class Item_default_value;
|
||||
friend class Item_insert_value;
|
||||
friend class st_select_lex_unit;
|
||||
|
|
|
@ -2388,7 +2388,23 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
|||
next_name_resolution_table= ctx_state.save_next_local;
|
||||
}
|
||||
res= res || setup_fields(thd, 0, *info.update_values, 1, 0, 0);
|
||||
if (!res)
|
||||
{
|
||||
/*
|
||||
Traverse the update values list and substitute fields from the
|
||||
select for references (Item_ref objects) to them. This is done in
|
||||
order to get correct values from those fields when the select
|
||||
employs a temporary table.
|
||||
*/
|
||||
List_iterator<Item> li(*info.update_values);
|
||||
Item *item;
|
||||
|
||||
while ((item= li++))
|
||||
{
|
||||
item->transform(&Item::update_value_transformer,
|
||||
(byte*)lex->current_select);
|
||||
}
|
||||
}
|
||||
/* Restore the current context. */
|
||||
ctx_state.restore_state(context, table_list);
|
||||
}
|
||||
|
|
|
@ -482,6 +482,9 @@ JOIN::prepare(Item ***rref_pointer_array,
|
|||
}
|
||||
}
|
||||
|
||||
if (!procedure && result && result->prepare(fields_list, unit_arg))
|
||||
goto err; /* purecov: inspected */
|
||||
|
||||
/* Init join struct */
|
||||
count_field_types(&tmp_table_param, all_fields, 0);
|
||||
ref_pointer_array_size= all_fields.elements*sizeof(Item*);
|
||||
|
@ -495,9 +498,6 @@ JOIN::prepare(Item ***rref_pointer_array,
|
|||
goto err;
|
||||
}
|
||||
#endif
|
||||
if (!procedure && result && result->prepare(fields_list, unit_arg))
|
||||
goto err; /* purecov: inspected */
|
||||
|
||||
if (select_lex->olap == ROLLUP_TYPE && rollup_init())
|
||||
goto err;
|
||||
if (alloc_func_list())
|
||||
|
|
Loading…
Reference in a new issue