summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2019-09-02 14:10:20 +0200
committerSergei Golubchik <serg@mariadb.org>2019-09-03 20:34:30 +0200
commitc7c481f4d918aaf42cef083b77ab551d69cdae58 (patch)
tree8be0987072826c7a8f792cbba2be3dbc2cecb820
parent3789692d17625780b546bf2ec4a33acf5badae2c (diff)
downloadmariadb-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.result23
-rw-r--r--mysql-test/t/function_defaults.test27
-rw-r--r--sql/sql_base.cc10
-rw-r--r--sql/sql_update.cc19
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> &not_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)
{