diff options
-rw-r--r-- | mysql-test/include/mix1.inc | 24 | ||||
-rw-r--r-- | mysql-test/r/innodb_mysql.result | 28 | ||||
-rw-r--r-- | sql/sql_insert.cc | 3 | ||||
-rw-r--r-- | sql/sql_update.cc | 11 |
4 files changed, 65 insertions, 1 deletions
diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index 11b0013fc38..f0900d1f8fa 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -961,5 +961,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 diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index cdea5c49594..fc8aaccceb9 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -959,4 +959,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 diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 11db88d8f5e..17335f4151d 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1421,7 +1421,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], diff --git a/sql/sql_update.cc b/sql/sql_update.cc index ef1f46bfdd2..6927835762b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -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(); |