summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/versioning/r/update.result29
-rw-r--r--mysql-test/suite/versioning/t/update.test25
-rw-r--r--sql/sql_update.cc69
-rw-r--r--storage/innobase/handler/ha_innodb.cc14
4 files changed, 105 insertions, 32 deletions
diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result
index 0b239423834..fbb9f541b06 100644
--- a/mysql-test/suite/versioning/r/update.result
+++ b/mysql-test/suite/versioning/r/update.result
@@ -370,3 +370,32 @@ insert into t1 (a) values (1), (2);
update ignore t1 set a= 3;
delete history from t1;
drop table t1;
+#
+# MDEV-23446 UPDATE does not insert history row if the row is not changed
+#
+create table t1 (
+a int,
+row_start SYS_DATATYPE as row start invisible,
+row_end SYS_DATATYPE as row end invisible,
+period for system_time (row_start, row_end)) with system versioning;
+insert into t1 values (1);
+update t1 set a= 1;
+select *, check_row(row_start, row_end) from t1 for system_time all order by row_end;
+a check_row(row_start, row_end)
+1 HISTORICAL ROW
+1 CURRENT ROW
+# multi-update
+create or replace table t2 like t1;
+create or replace table t3 like t1;
+insert into t2 values (1);
+insert into t3 values (1);
+update t2, t3 set t2.a= 1, t3.a= 1 where t2.a = t3.a;
+select *, check_row(row_start, row_end) from t2 for system_time all order by row_end;
+a check_row(row_start, row_end)
+1 HISTORICAL ROW
+1 CURRENT ROW
+select *, check_row(row_start, row_end) from t2 for system_time all order by row_end;
+a check_row(row_start, row_end)
+1 HISTORICAL ROW
+1 CURRENT ROW
+drop tables t1, t2, t3;
diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test
index f64dcfd0e5c..7f99e307942 100644
--- a/mysql-test/suite/versioning/t/update.test
+++ b/mysql-test/suite/versioning/t/update.test
@@ -301,4 +301,29 @@ delete history from t1;
# cleanup
drop table t1;
+--echo #
+--echo # MDEV-23446 UPDATE does not insert history row if the row is not changed
+--echo #
+replace_result $sys_datatype_expl SYS_DATATYPE;
+eval create table t1 (
+ a int,
+ row_start $sys_datatype_expl as row start invisible,
+ row_end $sys_datatype_expl as row end invisible,
+ period for system_time (row_start, row_end)) with system versioning;
+insert into t1 values (1);
+update t1 set a= 1;
+select *, check_row(row_start, row_end) from t1 for system_time all order by row_end;
+
+--echo # multi-update
+create or replace table t2 like t1;
+create or replace table t3 like t1;
+insert into t2 values (1);
+insert into t3 values (1);
+update t2, t3 set t2.a= 1, t3.a= 1 where t2.a = t3.a;
+select *, check_row(row_start, row_end) from t2 for system_time all order by row_end;
+select *, check_row(row_start, row_end) from t2 for system_time all order by row_end;
+
+# cleanup
+drop tables t1, t2, t3;
+
source suite/versioning/common_finish.inc;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 318ab8e7f69..314256cd8c5 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -52,8 +52,9 @@
compare_record(TABLE*).
*/
bool records_are_comparable(const TABLE *table) {
- return ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) == 0) ||
- bitmap_is_subset(table->write_set, table->read_set);
+ return !table->versioned(VERS_TRX_ID) &&
+ (((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) == 0) ||
+ bitmap_is_subset(table->write_set, table->read_set));
}
@@ -960,25 +961,27 @@ update_begin:
}
else if (likely(!error))
{
- if (has_vers_fields && table->versioned())
- {
- if (table->versioned(VERS_TIMESTAMP))
- {
- store_record(table, record[2]);
- table->mark_columns_per_binlog_row_image();
- error= vers_insert_history_row(table);
- restore_record(table, record[2]);
- }
- if (likely(!error))
- updated_sys_ver++;
- }
- if (likely(!error))
- updated++;
+ if (has_vers_fields && table->versioned(VERS_TRX_ID))
+ updated_sys_ver++;
+ updated++;
}
if (unlikely(error) &&
(!ignore || table->file->is_fatal_error(error, HA_CHECK_ALL)))
{
+ goto error;
+ }
+ }
+
+ if (likely(!error) && has_vers_fields && table->versioned(VERS_TIMESTAMP))
+ {
+ store_record(table, record[2]);
+ table->mark_columns_per_binlog_row_image();
+ error= vers_insert_history_row(table);
+ restore_record(table, record[2]);
+ if (unlikely(error))
+ {
+error:
/*
If (ignore && error is ignorable) we don't have to
do anything; otherwise...
@@ -989,10 +992,11 @@ update_begin:
flags|= ME_FATALERROR; /* Other handler errors are fatal */
prepare_record_for_error_message(error, table);
- table->file->print_error(error,MYF(flags));
- error= 1;
- break;
- }
+ table->file->print_error(error,MYF(flags));
+ error= 1;
+ break;
+ }
+ updated_sys_ver++;
}
if (table->triggers &&
@@ -2410,6 +2414,7 @@ int multi_update::send_data(List<Item> &not_used_values)
if (!ignore ||
table->file->is_fatal_error(error, HA_CHECK_ALL))
{
+error:
/*
If (ignore && error == is ignorable) we don't have to
do anything; otherwise...
@@ -2431,19 +2436,8 @@ int multi_update::send_data(List<Item> &not_used_values)
error= 0;
updated--;
}
- else if (has_vers_fields && table->versioned())
+ else if (has_vers_fields && table->versioned(VERS_TRX_ID))
{
- if (table->versioned(VERS_TIMESTAMP))
- {
- store_record(table, record[2]);
- if (vers_insert_history_row(table))
- {
- restore_record(table, record[2]);
- error= 1;
- break;
- }
- restore_record(table, record[2]);
- }
updated_sys_ver++;
}
/* non-transactional or transactional table got modified */
@@ -2457,6 +2451,17 @@ int multi_update::send_data(List<Item> &not_used_values)
}
}
}
+ if (has_vers_fields && table->versioned(VERS_TIMESTAMP))
+ {
+ store_record(table, record[2]);
+ if (vers_insert_history_row(table))
+ {
+ restore_record(table, record[2]);
+ goto error;
+ }
+ restore_record(table, record[2]);
+ updated_sys_ver++;
+ }
if (table->triggers &&
unlikely(table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER, TRUE)))
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index d1f155eecff..e66a340a7f0 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -8799,6 +8799,20 @@ ha_innobase::update_row(
MySQL that the row is not really updated and it
should not increase the count of updated rows.
This is fix for http://bugs.mysql.com/29157 */
+ if (m_prebuilt->versioned_write
+ && thd_sql_command(m_user_thd) != SQLCOM_ALTER_TABLE
+ /* Multiple UPDATE of same rows in single transaction create
+ historical rows only once. */
+ && trx->id != table->vers_start_id()) {
+ error = row_insert_for_mysql((byte*) old_row,
+ m_prebuilt,
+ ROW_INS_HISTORICAL);
+ if (error != DB_SUCCESS) {
+ goto func_exit;
+ }
+ innobase_srv_conc_exit_innodb(m_prebuilt);
+ innobase_active_small();
+ }
DBUG_RETURN(HA_ERR_RECORD_IS_THE_SAME);
} else {
const bool vers_set_fields = m_prebuilt->versioned_write