summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/include/mix1.inc24
-rw-r--r--mysql-test/r/innodb_mysql.result28
-rw-r--r--sql/sql_insert.cc3
-rw-r--r--sql/sql_update.cc11
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();