Commit 2235ea95 authored by evgen@moonbone.local's avatar evgen@moonbone.local

Fix bug #9728 decreased functionality in "on duplicate key update"

Remove changes made by bug fix #8147. They strips list of insert_table_list to
only insert table, which results in error reported in bug #9728.
Added flag to Item to resolve ambigous fields reported in bug #8147.
parent a24336cd
...@@ -634,3 +634,18 @@ ff1 ff2 ...@@ -634,3 +634,18 @@ ff1 ff2
1 2 1 2
2 1 2 1
drop table t1, t2; drop table t1, t2;
create table t1 (a int unique);
create table t2 (a int, b int);
insert into t1 values (1),(2);
insert into t2 values (1,2);
select * from t1;
a
1
2
insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b;
select * from t1;
a
2
3
drop table t1;
drop table t2;
...@@ -175,3 +175,17 @@ insert into t1 values (1),(1),(2); ...@@ -175,3 +175,17 @@ insert into t1 values (1),(1),(2);
insert into t2(ff1) select f1 from t1 on duplicate key update ff2=ff2+1; insert into t2(ff1) select f1 from t1 on duplicate key update ff2=ff2+1;
select * from t2; select * from t2;
drop table t1, t2; drop table t1, t2;
#
# BUGS #9728 - 'Decreased functionality in "on duplicate key update"'
# #8147 - 'a column proclaimed ambigous in INSERT ... SELECT .. ON
# DUPLICATE'
#
create table t1 (a int unique);
create table t2 (a int, b int);
insert into t1 values (1),(2);
insert into t2 values (1,2);
select * from t1;
insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b;
select * from t1;
drop table t1;
drop table t2;
...@@ -65,6 +65,7 @@ Item::Item(): ...@@ -65,6 +65,7 @@ Item::Item():
place == IN_HAVING) place == IN_HAVING)
thd->lex->current_select->select_n_having_items++; thd->lex->current_select->select_n_having_items++;
} }
item_flags= 0;
} }
/* /*
...@@ -83,7 +84,8 @@ Item::Item(THD *thd, Item *item): ...@@ -83,7 +84,8 @@ Item::Item(THD *thd, Item *item):
unsigned_flag(item->unsigned_flag), unsigned_flag(item->unsigned_flag),
with_sum_func(item->with_sum_func), with_sum_func(item->with_sum_func),
fixed(item->fixed), fixed(item->fixed),
collation(item->collation) collation(item->collation),
item_flags(item->item_flags)
{ {
next= thd->free_list; // Put in free list next= thd->free_list; // Put in free list
thd->free_list= this; thd->free_list= this;
......
...@@ -107,6 +107,11 @@ class DTCollation { ...@@ -107,6 +107,11 @@ class DTCollation {
typedef bool (Item::*Item_processor)(byte *arg); typedef bool (Item::*Item_processor)(byte *arg);
/*
See comments for sql_yacc.yy: insert_update_elem rule
*/
#define MY_ITEM_PREFER_1ST_TABLE 1
class Item { class Item {
Item(const Item &); /* Prevent use of these */ Item(const Item &); /* Prevent use of these */
void operator=(Item &); void operator=(Item &);
...@@ -142,6 +147,7 @@ class Item { ...@@ -142,6 +147,7 @@ class Item {
my_bool with_sum_func; my_bool with_sum_func;
my_bool fixed; /* If item fixed with fix_fields */ my_bool fixed; /* If item fixed with fix_fields */
DTCollation collation; DTCollation collation;
uint8 item_flags; /* Flags on how item should be processed */
// alloc & destruct is done as start of select using sql_alloc // alloc & destruct is done as start of select using sql_alloc
Item(); Item();
...@@ -327,6 +333,11 @@ class Item { ...@@ -327,6 +333,11 @@ class Item {
cleanup(); cleanup();
delete this; delete this;
} }
virtual bool set_flags_processor(byte *args)
{
this->item_flags|= *((uint8*)args);
return true;
}
}; };
......
...@@ -2086,7 +2086,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, ...@@ -2086,7 +2086,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
return (Field*) 0; return (Field*) 0;
} }
bool allow_rowid= tables && !tables->next; // Only one table bool allow_rowid= tables && !tables->next; // Only one table
for (; tables ; tables=tables->next) uint table_idx= 0;
for (; tables ; tables=tables->next, table_idx++)
{ {
if (!tables->table) if (!tables->table)
{ {
...@@ -2114,7 +2115,9 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, ...@@ -2114,7 +2115,9 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
name,thd->where); name,thd->where);
return (Field*) 0; return (Field*) 0;
} }
found=field; found= field;
if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE)
break;
} }
} }
if (found) if (found)
......
...@@ -2856,17 +2856,14 @@ mysql_execute_command(THD *thd) ...@@ -2856,17 +2856,14 @@ mysql_execute_command(THD *thd)
if ((res= open_and_lock_tables(thd, tables))) if ((res= open_and_lock_tables(thd, tables)))
break; break;
TABLE *table= tables->table;
/* Skip first table, which is the table we are inserting in */ /* Skip first table, which is the table we are inserting in */
select_lex->table_list.first= (byte*) first_local_table->next; select_lex->table_list.first= (byte*) first_local_table->next;
tables= (TABLE_LIST *) select_lex->table_list.first;
first_local_table->next= 0;
if (!(res= mysql_prepare_insert(thd, tables, first_local_table, if (!(res= mysql_prepare_insert(thd, tables, first_local_table,
table, lex->field_list, 0, tables->table, lex->field_list, 0,
lex->update_list, lex->value_list, lex->update_list, lex->value_list,
lex->duplicates)) && lex->duplicates)) &&
(result= new select_insert(table, &lex->field_list, (result= new select_insert(tables->table, &lex->field_list,
&lex->update_list, &lex->value_list, &lex->update_list, &lex->value_list,
lex->duplicates, lex->ignore))) lex->duplicates, lex->ignore)))
{ {
...@@ -2879,7 +2876,7 @@ mysql_execute_command(THD *thd) ...@@ -2879,7 +2876,7 @@ mysql_execute_command(THD *thd)
/* revert changes for SP */ /* revert changes for SP */
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
delete result; delete result;
table->insert_values= 0; tables->table->insert_values= 0;
if (thd->net.report_error) if (thd->net.report_error)
res= -1; res= -1;
} }
......
...@@ -4239,9 +4239,24 @@ insert_update_elem: ...@@ -4239,9 +4239,24 @@ insert_update_elem:
simple_ident equal expr_or_default simple_ident equal expr_or_default
{ {
LEX *lex= Lex; LEX *lex= Lex;
uint8 tmp= MY_ITEM_PREFER_1ST_TABLE;
if (lex->update_list.push_back($1) || if (lex->update_list.push_back($1) ||
lex->value_list.push_back($3)) lex->value_list.push_back($3))
YYABORT; YYABORT;
/*
INSERT INTO a1(a) SELECT b1.a FROM b1 ON DUPLICATE KEY
UPDATE a= a + b1.b
Set MY_ITEM_PREFER_1ST_TABLE flag to $1 and $3 items
to prevent find_field_in_tables() doing further item searching
if it finds item occurence in first table in insert_table_list.
This allows to avoid ambiguity in resolving 'a' field in
example above.
*/
$1->walk(&Item::set_flags_processor,
(byte *) &tmp);
$3->walk(&Item::set_flags_processor,
(byte *) &tmp);
}; };
opt_low_priority: opt_low_priority:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment