mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
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. sql/item.h: Fix bug#9728 decreased functionality in "on duplicate key update". sql/item.cc: Fix bug#9728 decreased functionality in "on duplicate key update" sql/sql_parse.cc: Fix bug#9728 decreased functionality in "on duplicate key update" sql/sql_base.cc: Fix bug#9728 decreased functionality in "on duplicate key update". sql/sql_yacc.yy: Fix bug#9728 decreased functionality in "on duplicate key update" mysql-test/t/insert_select.test: Test case for bug#9728 Decreased functionality in "on duplicate key update". mysql-test/r/insert_select.result: Test case for bug#9728 Decreased functionality in "on duplicate key update".
This commit is contained in:
parent
d785fc60ab
commit
a6c7fb455a
7 changed files with 66 additions and 9 deletions
|
@ -634,3 +634,18 @@ ff1 ff2
|
|||
1 2
|
||||
2 1
|
||||
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);
|
|||
insert into t2(ff1) select f1 from t1 on duplicate key update ff2=ff2+1;
|
||||
select * from 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():
|
|||
place == IN_HAVING)
|
||||
thd->lex->current_select->select_n_having_items++;
|
||||
}
|
||||
item_flags= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -83,7 +84,8 @@ Item::Item(THD *thd, Item *item):
|
|||
unsigned_flag(item->unsigned_flag),
|
||||
with_sum_func(item->with_sum_func),
|
||||
fixed(item->fixed),
|
||||
collation(item->collation)
|
||||
collation(item->collation),
|
||||
item_flags(item->item_flags)
|
||||
{
|
||||
next= thd->free_list; // Put in free list
|
||||
thd->free_list= this;
|
||||
|
|
11
sql/item.h
11
sql/item.h
|
@ -107,6 +107,11 @@ public:
|
|||
|
||||
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 {
|
||||
Item(const Item &); /* Prevent use of these */
|
||||
void operator=(Item &);
|
||||
|
@ -142,6 +147,7 @@ public:
|
|||
my_bool with_sum_func;
|
||||
my_bool fixed; /* If item fixed with fix_fields */
|
||||
DTCollation collation;
|
||||
uint8 item_flags; /* Flags on how item should be processed */
|
||||
|
||||
// alloc & destruct is done as start of select using sql_alloc
|
||||
Item();
|
||||
|
@ -327,6 +333,11 @@ public:
|
|||
cleanup();
|
||||
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,
|
|||
return (Field*) 0;
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
@ -2115,6 +2116,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
|||
return (Field*) 0;
|
||||
}
|
||||
found= field;
|
||||
if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
|
|
|
@ -2856,17 +2856,14 @@ unsent_create_error:
|
|||
if ((res= open_and_lock_tables(thd, tables)))
|
||||
break;
|
||||
|
||||
TABLE *table= tables->table;
|
||||
/* Skip first table, which is the table we are inserting in */
|
||||
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,
|
||||
table, lex->field_list, 0,
|
||||
tables->table, lex->field_list, 0,
|
||||
lex->update_list, lex->value_list,
|
||||
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->duplicates, lex->ignore)))
|
||||
{
|
||||
|
@ -2879,7 +2876,7 @@ unsent_create_error:
|
|||
/* revert changes for SP */
|
||||
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
|
||||
delete result;
|
||||
table->insert_values= 0;
|
||||
tables->table->insert_values= 0;
|
||||
if (thd->net.report_error)
|
||||
res= -1;
|
||||
}
|
||||
|
|
|
@ -4239,9 +4239,24 @@ insert_update_elem:
|
|||
simple_ident equal expr_or_default
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
uint8 tmp= MY_ITEM_PREFER_1ST_TABLE;
|
||||
if (lex->update_list.push_back($1) ||
|
||||
lex->value_list.push_back($3))
|
||||
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:
|
||||
|
|
Loading…
Reference in a new issue