diff options
author | Sergei Golubchik <serg@mariadb.org> | 2019-09-02 14:10:20 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2019-09-03 20:34:30 +0200 |
commit | c7c481f4d918aaf42cef083b77ab551d69cdae58 (patch) | |
tree | 8be0987072826c7a8f792cbba2be3dbc2cecb820 | |
parent | 3789692d17625780b546bf2ec4a33acf5badae2c (diff) | |
download | mariadb-git-c7c481f4d918aaf42cef083b77ab551d69cdae58.tar.gz |
MDEV-20403 Assertion `0' or Assertion `btr_validate_index(index, 0)' failed in row_upd_sec_index_entry or error code 126: Index is corrupted upon UPDATE with TIMESTAMP..ON UPDATE
Three issues here:
* ON UPDATE DEFAULT NOW columns were updated after generated columns
were computed - this broke indexed virtual columns
* ON UPDATE DEFAULT NOW columns were updated after BEFORE triggers,
so triggers didn't see the correct NEW value
* in case of a multi-update generated columns were also updated
after BEFORE triggers
-rw-r--r-- | mysql-test/r/function_defaults.result | 23 | ||||
-rw-r--r-- | mysql-test/t/function_defaults.test | 27 | ||||
-rw-r--r-- | sql/sql_base.cc | 10 | ||||
-rw-r--r-- | sql/sql_update.cc | 19 |
4 files changed, 65 insertions, 14 deletions
diff --git a/mysql-test/r/function_defaults.result b/mysql-test/r/function_defaults.result index 62422752e17..1c63ae17a5d 100644 --- a/mysql-test/r/function_defaults.result +++ b/mysql-test/r/function_defaults.result @@ -3093,3 +3093,26 @@ a b 1999-12-01 11:22:33.000000 1999-12-01 11:22:33.000000 2001-09-09 04:46:40.000000 2001-09-09 04:46:40.000000 DROP TABLE t1; +create table t1 (t timestamp, i int, v timestamp as (t) virtual, key(v)); +insert t1 (t,i) values ('2006-03-01 23:59:59',1); +update t1 set i = 2; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +create table t1 (t timestamp, i int); +create trigger tr1 before update on t1 for each row set @new:=new.t; +insert t1 (t,i) values ('2006-03-01 23:59:59', 1); +update t1 set i = 2; +select if(@new = t, 'correct', 'wrong') from t1; +if(@new = t, 'correct', 'wrong') +correct +drop table t1; +create table t1 (i int, j int as (i)); +create trigger tr1 before update on t1 for each row set @new:=new.j; +insert t1 (i) values (1); +update t1, t1 as t2 set t1.i = 2; +select if(@new = j, 'correct', 'wrong') from t1; +if(@new = j, 'correct', 'wrong') +correct +drop table t1; diff --git a/mysql-test/t/function_defaults.test b/mysql-test/t/function_defaults.test index f8b23d0eda8..1e3e86599e3 100644 --- a/mysql-test/t/function_defaults.test +++ b/mysql-test/t/function_defaults.test @@ -19,3 +19,30 @@ let $now=NOW(6); let $timestamp=TIMESTAMP(6); let $datetime=DATETIME(6); source 'include/function_defaults.inc'; + +# +# MDEV-20403 Assertion `0' or Assertion `btr_validate_index(index, 0)' failed in row_upd_sec_index_entry or error code 126: Index is corrupted upon UPDATE with TIMESTAMP..ON UPDATE +# + +# ON UPDATE DEFAULT NOW and indexed virtual columns +create table t1 (t timestamp, i int, v timestamp as (t) virtual, key(v)); +insert t1 (t,i) values ('2006-03-01 23:59:59',1); +update t1 set i = 2; +check table t1; +drop table t1; + +# ON UPDATE DEFAULT NOW and triggers +create table t1 (t timestamp, i int); +create trigger tr1 before update on t1 for each row set @new:=new.t; +insert t1 (t,i) values ('2006-03-01 23:59:59', 1); +update t1 set i = 2; +select if(@new = t, 'correct', 'wrong') from t1; +drop table t1; + +# triggers, virtual columns, multi-update +create table t1 (i int, j int as (i)); +create trigger tr1 before update on t1 for each row set @new:=new.j; +insert t1 (i) values (1); +update t1, t1 as t2 set t1.i = 2; +select if(@new = j, 'correct', 'wrong') from t1; +drop table t1; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 14740274b87..f7f7d50bc85 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8071,9 +8071,13 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values, rfield->set_explicit_default(value); } - if (!update && table_arg->default_field && - table_arg->update_default_fields(ignore_errors)) - goto err; + if (update) + table_arg->evaluate_update_default_function(); + else + if (table_arg->default_field && + table_arg->update_default_fields(ignore_errors)) + goto err; + /* Update virtual fields */ if (table_arg->vfield && table_arg->update_virtual_fields(table_arg->file, VCOL_UPDATE_FOR_WRITE)) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 0d55fa58bde..65a828147ae 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -66,12 +66,15 @@ bool compare_record(const TABLE *table) { DBUG_ASSERT(records_are_comparable(table)); - if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) != 0) + if (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ || + table->s->has_update_default_function) { /* Storage engine may not have read all columns of the record. Fields (including NULL bits) not in the write_set may not have been read and can therefore not be compared. + Or ON UPDATE DEFAULT NOW() could've changed field values, including + NULL bits. */ for (Field **ptr= table->field ; *ptr != NULL; ptr++) { @@ -762,8 +765,6 @@ int mysql_update(THD *thd, if (!can_compare_record || compare_record(table)) { - if (table->default_field) - table->evaluate_update_default_function(); if ((res= table_list->view_check_option(thd, ignore)) != VIEW_CHECK_OK) { @@ -2154,9 +2155,6 @@ int multi_update::send_data(List<Item> ¬_used_values) { int error; - if (table->default_field) - table->evaluate_update_default_function(); - if ((error= cur_table->view_check_option(thd, ignore)) != VIEW_CHECK_OK) { @@ -2472,6 +2470,10 @@ int multi_update::do_updates() copy_field_ptr->to_field->set_has_explicit_value(); } + table->evaluate_update_default_function(); + if (table->vfield && + table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE)) + goto err2; if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)) @@ -2480,11 +2482,6 @@ int multi_update::do_updates() if (!can_compare_record || compare_record(table)) { int error; - if (table->default_field) - table->evaluate_update_default_function(); - if (table->vfield && - table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE)) - goto err2; if ((error= cur_table->view_check_option(thd, ignore)) != VIEW_CHECK_OK) { |