Skip to content

Commit f06443c

Browse files
author
Sreeharsha Ramanavarapu
committed
Bug #26881946: INCORRECT BEHAVIOR WITH "VALUES"
Issue: ------ VALUES doesn't have a type() function and is considered a Item_field. Solution for 5.7: ----------------- Add a new type() function for Item_values_insert. On 8.0 and trunk it was fixed by Mithun's Bug#19601973. Solution for 5.6: ----------------- Additionally Bug#17458914 is backported. This will address the problem of using VALUES() in INSERT ... ON DUPLICATE KEY UPDATE. Create a field object only if it is in the UPDATE clause, else return a NULL item. This will also address the problems mentioned in Bug#14789787 and Bug#16756402. Solution for 5.5: ----------------- As mentioned above Bug#17458914 is backported. Additionally Bug#14786324 is also backported. When VALUES() is detected outside its meaningful place, it should be treated as NULL and is thus replaced with a Field_null object, with the same name as the original field. Fields with type NULL are generally not handled well inside the server (e.g Innodb will not accept them and it is impossible to create them in regular tables). So create a new const NULL item instead.
1 parent 02c1299 commit f06443c

File tree

6 files changed

+32
-20
lines changed

6 files changed

+32
-20
lines changed

mysql-test/r/insert_update.result

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ explain extended SELECT *, VALUES(a) FROM t1;
6060
id select_type table type possible_keys key key_len ref rows filtered Extra
6161
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00
6262
Warnings:
63-
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`
63+
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`
6464
explain extended select * from t1 where values(a);
6565
id select_type table type possible_keys key key_len ref rows filtered Extra
66-
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
66+
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
6767
Warnings:
68-
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`)
68+
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where 0
6969
DROP TABLE t1;
7070
create table t1(a int primary key, b int);
7171
insert into t1 values(1,1),(2,2),(3,3),(4,4),(5,5);

sql/item.cc

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7120,7 +7120,7 @@ Item *Item_default_value::transform(Item_transformer transformer, uchar *args)
71207120
bool Item_insert_value::eq(const Item *item, bool binary_cmp) const
71217121
{
71227122
return item->type() == INSERT_VALUE_ITEM &&
7123-
((Item_default_value *)item)->arg->eq(arg, binary_cmp);
7123+
((Item_insert_value *)item)->arg->eq(arg, binary_cmp);
71247124
}
71257125

71267126

@@ -7149,11 +7149,12 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
71497149

71507150
Item_field *field_arg= (Item_field *)arg;
71517151

7152-
if (field_arg->field->table->insert_values)
7152+
if (field_arg->field->table->insert_values &&
7153+
thd->lex->in_update_value_clause)
71537154
{
71547155
Field *def_field= (Field*) sql_alloc(field_arg->field->size_of());
71557156
if (!def_field)
7156-
return TRUE;
7157+
return true;
71577158
memcpy(def_field, field_arg->field, field_arg->field->size_of());
71587159
def_field->move_field_offset((my_ptrdiff_t)
71597160
(def_field->table->insert_values -
@@ -7162,17 +7163,17 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
71627163
}
71637164
else
71647165
{
7165-
Field *tmp_field= field_arg->field;
7166-
/* charset doesn't matter here, it's to avoid sigsegv only */
7167-
tmp_field= new Field_null(0, 0, Field::NONE, field_arg->field->field_name,
7168-
&my_charset_bin);
7169-
if (tmp_field)
7170-
{
7171-
tmp_field->init(field_arg->field->table);
7172-
set_field(tmp_field);
7173-
}
7166+
// VALUES() is used out-of-scope - its value is always NULL
7167+
Query_arena backup;
7168+
Query_arena *const arena= thd->activate_stmt_arena_if_needed(&backup);
7169+
Item *const item= new Item_null(this->name);
7170+
if (arena)
7171+
thd->restore_active_arena(arena, &backup);
7172+
if (!item)
7173+
return TRUE;
7174+
*items= item;
71747175
}
7175-
return FALSE;
7176+
return false;
71767177
}
71777178

71787179
void Item_insert_value::print(String *str, enum_query_type query_type)

sql/item.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3150,6 +3150,8 @@ class Item_insert_value : public Item_field
31503150
:Item_field(context_arg, (const char *)NULL, (const char *)NULL,
31513151
(const char *)NULL),
31523152
arg(a) {}
3153+
3154+
enum Type type() const { return INSERT_VALUE_ITEM; }
31533155
bool eq(const Item *item, bool binary_cmp) const;
31543156
bool fix_fields(THD *, Item **);
31553157
virtual void print(String *str, enum_query_type query_type);

sql/sql_insert.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
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,
13931393
thd->abort_on_warning= saved_abort_on_warning;
13941394
}
13951395

1396+
thd->lex->in_update_value_clause= true;
13961397
if (!res)
13971398
res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
13981399

1400+
thd->lex->in_update_value_clause= false;
1401+
13991402
if (!res && duplic == DUP_UPDATE)
14001403
{
14011404
select_lex->no_wrap_view_item= TRUE;
@@ -3263,8 +3266,11 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
32633266
table_list->next_name_resolution_table=
32643267
ctx_state.get_first_name_resolution_table();
32653268

3269+
thd->lex->in_update_value_clause= true;
32663270
res= res || setup_fields(thd, 0, *info.update_values,
32673271
MARK_COLUMNS_READ, 0, 0);
3272+
3273+
thd->lex->in_update_value_clause= false;
32683274
if (!res)
32693275
{
32703276
/*

sql/sql_lex.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
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()
23762376
*/
23772377

23782378
LEX::LEX()
2379-
:result(0), option_type(OPT_DEFAULT), is_lex_started(0)
2379+
:result(0), option_type(OPT_DEFAULT), is_lex_started(0),
2380+
in_update_value_clause(false)
23802381
{
23812382

23822383
my_init_dynamic_array2(&plugins, sizeof(plugin_ref),

sql/sql_lex.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -2491,6 +2491,8 @@ struct LEX: public Query_tables_list
24912491

24922492
bool escape_used;
24932493
bool is_lex_started; /* If lex_start() did run. For debugging. */
2494+
/// Set to true while resolving values in ON DUPLICATE KEY UPDATE clause
2495+
bool in_update_value_clause;
24942496

24952497
/*
24962498
The set of those tables whose fields are referenced in all subqueries

0 commit comments

Comments
 (0)