Commit 42d1e3c4 authored by evgen@moonbone.local's avatar evgen@moonbone.local

Bug#29310: An InnoDB table was updated when the data wasn't actually changed.

When a table is being updated it has two set of fields - fields required for
checks of conditions and fields to be updated. A storage engine is allowed
not to retrieve columns marked for update. Due to this fact records can't
be compared to see whether the data has been changed or not. This makes the
server always update records independently of data change.

Now when an auto-updatable timestamp field is present and server sees that
a table handle isn't going to retrieve write-only fields then all of such
fields are marked as to be read to force the handler to retrieve them.
parent 23a30b0c
......@@ -948,5 +948,29 @@ unlock tables;
select * from t1;
drop tables t1;
#
# Bug#29310: An InnoDB table was updated when the data wasn't actually changed.
#
create table t1(f1 varchar(5) unique, f2 timestamp NOT NULL DEFAULT
CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);
insert into t1(f1) values(1);
--replace_column 1 #
select @a:=f2 from t1;
--sleep 5
update t1 set f1=1;
--replace_column 1 #
select @b:=f2 from t1;
select if(@a=@b,"ok","wrong");
--sleep 5
insert into t1(f1) values (1) on duplicate key update f1="1";
--replace_column 1 #
select @b:=f2 from t1;
select if(@a=@b,"ok","wrong");
--sleep 5
insert into t1(f1) select f1 from t1 on duplicate key update f1="1";
--replace_column 1 #
select @b:=f2 from t1;
select if(@a=@b,"ok","wrong");
drop table t1;
--echo End of 5.1 tests
......@@ -951,4 +951,32 @@ NULL
1
Two
drop tables t1;
create table t1(f1 varchar(5) unique, f2 timestamp NOT NULL DEFAULT
CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);
insert into t1(f1) values(1);
select @a:=f2 from t1;
@a:=f2
#
update t1 set f1=1;
select @b:=f2 from t1;
@b:=f2
#
select if(@a=@b,"ok","wrong");
if(@a=@b,"ok","wrong")
ok
insert into t1(f1) values (1) on duplicate key update f1="1";
select @b:=f2 from t1;
@b:=f2
#
select if(@a=@b,"ok","wrong");
if(@a=@b,"ok","wrong")
ok
insert into t1(f1) select f1 from t1 on duplicate key update f1="1";
select @b:=f2 from t1;
@b:=f2
#
select if(@a=@b,"ok","wrong");
if(@a=@b,"ok","wrong")
ok
drop table t1;
End of 5.1 tests
......@@ -1419,7 +1419,8 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
goto before_trg_err;
table->file->restore_auto_increment(prev_insert_id);
if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) ||
if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ &&
!bitmap_is_subset(table->write_set, table->read_set)) ||
compare_record(table))
{
if ((error=table->file->ha_update_row(table->record[1],
......
......@@ -231,6 +231,17 @@ int mysql_update(THD *thd,
if (cond_value == Item::COND_FALSE)
limit= 0; // Impossible WHERE
}
/*
If a timestamp field settable on UPDATE is present then to avoid wrong
update force the table handler to retrieve write-only fields to be able
to compare records and detect data change.
*/
if (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ &&
table->timestamp_field &&
(table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_UPDATE ||
table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH))
bitmap_union(table->read_set, table->write_set);
// Don't count on usage of 'only index' when calculating which key to use
table->covering_keys.clear_all();
......
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