diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index a285810b78b..31e7b253267 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -60,12 +60,12 @@ explain extended SELECT *, VALUES(a) FROM t1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c`,values(`test`.`t1`.`a`) AS `VALUES(a)` from `test`.`t1` +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c`,NULL AS `VALUES(a)` from `test`.`t1` explain extended select * from t1 where values(a); id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where values(`test`.`t1`.`a`) +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where 0 DROP TABLE t1; create table t1(a int primary key, b int); insert into t1 values(1,1),(2,2),(3,3),(4,4),(5,5); diff --git a/sql/item.cc b/sql/item.cc index 6f1fdaae398..a37a61453e8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7120,7 +7120,7 @@ Item *Item_default_value::transform(Item_transformer transformer, uchar *args) bool Item_insert_value::eq(const Item *item, bool binary_cmp) const { return item->type() == INSERT_VALUE_ITEM && - ((Item_default_value *)item)->arg->eq(arg, binary_cmp); + ((Item_insert_value *)item)->arg->eq(arg, binary_cmp); } @@ -7149,11 +7149,12 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) Item_field *field_arg= (Item_field *)arg; - if (field_arg->field->table->insert_values) + if (field_arg->field->table->insert_values && + thd->lex->in_update_value_clause) { Field *def_field= (Field*) sql_alloc(field_arg->field->size_of()); if (!def_field) - return TRUE; + return true; memcpy(def_field, field_arg->field, field_arg->field->size_of()); def_field->move_field_offset((my_ptrdiff_t) (def_field->table->insert_values - @@ -7162,17 +7163,17 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) } else { - Field *tmp_field= field_arg->field; - /* charset doesn't matter here, it's to avoid sigsegv only */ - tmp_field= new Field_null(0, 0, Field::NONE, field_arg->field->field_name, - &my_charset_bin); - if (tmp_field) - { - tmp_field->init(field_arg->field->table); - set_field(tmp_field); - } + // VALUES() is used out-of-scope - its value is always NULL + Query_arena backup; + Query_arena *const arena= thd->activate_stmt_arena_if_needed(&backup); + Item *const item= new Item_null(this->name); + if (arena) + thd->restore_active_arena(arena, &backup); + if (!item) + return TRUE; + *items= item; } - return FALSE; + return false; } void Item_insert_value::print(String *str, enum_query_type query_type) diff --git a/sql/item.h b/sql/item.h index 9f4e1d24424..3556a58ff82 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3150,6 +3150,8 @@ public: :Item_field(context_arg, (const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + + enum Type type() const { return INSERT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, Item **); virtual void print(String *str, enum_query_type query_type); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index dc7cb698476..5d1905bf4ba 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1393,9 +1393,12 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, thd->abort_on_warning= saved_abort_on_warning; } + thd->lex->in_update_value_clause= true; if (!res) res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0); + thd->lex->in_update_value_clause= false; + if (!res && duplic == DUP_UPDATE) { select_lex->no_wrap_view_item= TRUE; @@ -3263,8 +3266,11 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) table_list->next_name_resolution_table= ctx_state.get_first_name_resolution_table(); + thd->lex->in_update_value_clause= true; res= res || setup_fields(thd, 0, *info.update_values, MARK_COLUMNS_READ, 0, 0); + + thd->lex->in_update_value_clause= false; if (!res) { /* diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 50cdabe341a..f7e9fd8570d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2376,7 +2376,8 @@ void Query_tables_list::destroy_query_tables_list() */ LEX::LEX() - :result(0), option_type(OPT_DEFAULT), is_lex_started(0) + :result(0), option_type(OPT_DEFAULT), is_lex_started(0), + in_update_value_clause(false) { my_init_dynamic_array2(&plugins, sizeof(plugin_ref), diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 867997feb39..3c950ebe117 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2491,6 +2491,8 @@ struct LEX: public Query_tables_list bool escape_used; bool is_lex_started; /* If lex_start() did run. For debugging. */ + /// Set to true while resolving values in ON DUPLICATE KEY UPDATE clause + bool in_update_value_clause; /* The set of those tables whose fields are referenced in all subqueries