Skip to content

Commit cf00393

Browse files
committed
Race condition in DEFAULT() with expressions
Item_default_value::calculate was updating table->s->default_values, but it is supposed to be read-only
1 parent cd4dd2b commit cf00393

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed

mysql-test/r/default_debug.result

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
create table t1 (a int, b int default (a+1));
2+
insert t1 values (1,10), (2,20), (3,30);
3+
connect con1, localhost, root;
4+
select a,b,default(b) from t1;
5+
a b default(b)
6+
1 10 2
7+
2 20 3
8+
3 30 4
9+
set debug_sync='after_Item_default_value_calculate WAIT_FOR go';
10+
select a,b,default(b) from t1;
11+
connection default;
12+
set debug_sync='ha_write_row_start SIGNAL go';
13+
insert t1 values (100,default(b));
14+
connection con1;
15+
a b default(b)
16+
1 10 2
17+
2 20 3
18+
3 30 4
19+
connection default;
20+
drop table t1;
21+
set debug_sync='RESET';

mysql-test/t/default_debug.test

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#
2+
# Race condition in DEFAULT() with expressions
3+
#
4+
5+
source include/have_debug_sync.inc;
6+
7+
create table t1 (a int, b int default (a+1));
8+
insert t1 values (1,10), (2,20), (3,30);
9+
connect (con1, localhost, root);
10+
select a,b,default(b) from t1;
11+
set debug_sync='after_Item_default_value_calculate WAIT_FOR go';
12+
send select a,b,default(b) from t1;
13+
connection default;
14+
set debug_sync='ha_write_row_start SIGNAL go';
15+
insert t1 values (100,default(b));
16+
connection con1;
17+
reap;
18+
connection default;
19+
drop table t1;
20+
set debug_sync='RESET';

sql/item.cc

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8758,17 +8758,22 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
87588758
goto error;
87598759
memcpy((void *)def_field, (void *)field_arg->field,
87608760
field_arg->field->size_of());
8761-
def_field->move_field_offset((my_ptrdiff_t)
8762-
(def_field->table->s->default_values -
8763-
def_field->table->record[0]));
8764-
set_field(def_field);
8765-
if (field->default_value)
8761+
IF_DBUG(def_field->is_stat_field=1,); // a hack to fool ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED
8762+
if (def_field->default_value && def_field->default_value->flags)
87668763
{
8767-
fix_session_vcol_expr_for_read(thd, field, field->default_value);
8764+
uchar *newptr= (uchar*) thd->alloc(1+def_field->pack_length());
8765+
if (!newptr)
8766+
goto error;
8767+
fix_session_vcol_expr_for_read(thd, def_field, def_field->default_value);
87688768
if (thd->mark_used_columns != MARK_COLUMNS_NONE)
8769-
field->default_value->expr->walk(&Item::register_field_in_read_map, 1, 0);
8770-
IF_DBUG(def_field->is_stat_field=1,); // a hack to fool ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED
8769+
def_field->default_value->expr->walk(&Item::register_field_in_read_map, 1, 0);
8770+
def_field->move_field(newptr+1, def_field->maybe_null() ? newptr : 0, 1);
87718771
}
8772+
else
8773+
def_field->move_field_offset((my_ptrdiff_t)
8774+
(def_field->table->s->default_values -
8775+
def_field->table->record[0]));
8776+
set_field(def_field);
87728777
return FALSE;
87738778

87748779
error:
@@ -8793,6 +8798,7 @@ void Item_default_value::calculate()
87938798
{
87948799
if (field->default_value)
87958800
field->set_default();
8801+
DEBUG_SYNC(field->table->in_use, "after_Item_default_value_calculate");
87968802
}
87978803

87988804
String *Item_default_value::val_str(String *str)

0 commit comments

Comments
 (0)