From c02d6164fbdd5effe758a61d9bb709c581fefef1 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 15 Jun 2019 14:46:25 +0300 Subject: [PATCH] MDEV-19771 REPLACE on table with virtual_field can cause crash Fixes also MDEV-17837 Problem was that we did not ignore warnings from virtual fields when updated virtual fields for to-be-replaced row. --- mysql-test/suite/vcol/r/vcol_misc.result | 38 +++++++++++++++++++++ mysql-test/suite/vcol/t/vcol_misc.test | 42 +++++++++++++++++++++--- sql/sql_insert.cc | 3 ++ 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/vcol/r/vcol_misc.result b/mysql-test/suite/vcol/r/vcol_misc.result index 291a954baf6..8716e39eb82 100644 --- a/mysql-test/suite/vcol/r/vcol_misc.result +++ b/mysql-test/suite/vcol/r/vcol_misc.result @@ -423,5 +423,43 @@ ERROR HY000: Incorrect information in file: './test/t1.frm' ALTER TABLE t1; ERROR HY000: Incorrect information in file: './test/t1.frm' # +# MDEV-19771 REPLACE on table with virtual_field can cause crash in set_ok_status() + +create or replace table t1 (pk int primary key, col_bit bit(15) default null, +vcol_bit bit(10) GENERATED ALWAYS AS (`col_bit`) VIRTUAL); +replace INTO `t1` (`pk`,col_bit) VALUES (99,1000); +select pk, col_bit+0, vcol_bit+0 from t1; +pk col_bit+0 vcol_bit+0 +99 1000 1000 +replace INTO `t1` (`pk`,col_bit) VALUES (99,10000); +select pk, col_bit+0, vcol_bit+0 from t1; +pk col_bit+0 vcol_bit+0 +99 10000 1023 +REPLACE LOW_PRIORITY INTO `t1` (`pk`) VALUES (99); +Warnings: +Warning 1264 Out of range value for column 'vcol_bit' at row 1 +drop table t1; +# +# MDEV-17837 REPLACE on table with virtual_field can cause crash in set_ok_status() +# +SET @old_sql_mode=@@sql_mode; +SET sql_mode= STRICT_ALL_TABLES; +CREATE TABLE t1 ( +pk INT, +i TINYINT, +vi TINYINT AS (i+1) PERSISTENT, +PRIMARY KEY(pk) +); +INSERT INTO t1 (pk,i) VALUES (1,1); +TRUNCATE TABLE t1; +INSERT IGNORE INTO t1 (pk,i) VALUES (1,127); +Warnings: +Warning 1264 Out of range value for column 'vi' at row 1 +REPLACE INTO t1 (pk,i) VALUES (1,2); +Warnings: +Warning 1264 Out of range value for column 'vi' at row 1 +DROP TABLE t1; +SET @sql_mode=@old_sql_mode; +# # End of 10.2 tests # diff --git a/mysql-test/suite/vcol/t/vcol_misc.test b/mysql-test/suite/vcol/t/vcol_misc.test index 255621845fb..1de2827efe6 100644 --- a/mysql-test/suite/vcol/t/vcol_misc.test +++ b/mysql-test/suite/vcol/t/vcol_misc.test @@ -215,12 +215,12 @@ drop table t1; create table t1 (a int, b int); insert into t1 values (3, 30), (4, 20), (1, 20); create table t2 (c int, d int, v int as (d+1), index idx(c)); -insert into t2(c,d) values +insert into t2(c,d) values (20, 100), (20, 300), (30, 100), (30, 200), (40, 500), - (70, 100), (40, 300), (60, 100), (40, 100), (70, 100); -insert into t2(c,d) values + (70, 100), (40, 300), (60, 100), (40, 100), (70, 100); +insert into t2(c,d) values (120, 100), (150, 300), (130, 100), (130, 200), (140, 500), - (170, 100), (180, 300), (160, 100), (40, 100), (170, 100); + (170, 100), (180, 300), (160, 100), (40, 100), (170, 100); set join_cache_level=6; explain @@ -391,6 +391,40 @@ SHOW CREATE TABLE t1; ALTER TABLE t1; --remove_file $MYSQLD_DATADIR/test/t1.frm +--echo # +--echo # MDEV-19771 REPLACE on table with virtual_field can cause crash in set_ok_status() +--echo + +create or replace table t1 (pk int primary key, col_bit bit(15) default null, + vcol_bit bit(10) GENERATED ALWAYS AS (`col_bit`) VIRTUAL); +replace INTO `t1` (`pk`,col_bit) VALUES (99,1000); +select pk, col_bit+0, vcol_bit+0 from t1; +replace INTO `t1` (`pk`,col_bit) VALUES (99,10000); +select pk, col_bit+0, vcol_bit+0 from t1; +REPLACE LOW_PRIORITY INTO `t1` (`pk`) VALUES (99); +drop table t1; + +--echo # +--echo # MDEV-17837 REPLACE on table with virtual_field can cause crash in set_ok_status() +--echo # + +SET @old_sql_mode=@@sql_mode; +SET sql_mode= STRICT_ALL_TABLES; + +CREATE TABLE t1 ( + pk INT, + i TINYINT, + vi TINYINT AS (i+1) PERSISTENT, + PRIMARY KEY(pk) +); + +INSERT INTO t1 (pk,i) VALUES (1,1); +TRUNCATE TABLE t1; +INSERT IGNORE INTO t1 (pk,i) VALUES (1,127); +REPLACE INTO t1 (pk,i) VALUES (1,2); +DROP TABLE t1; +SET @sql_mode=@old_sql_mode; + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2502be7e454..e2e7454803b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1747,12 +1747,15 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } if (table->vfield) { + my_bool abort_on_warning= thd->abort_on_warning; /* We have not yet called update_virtual_fields(VOL_UPDATE_FOR_READ) in handler methods for the just read row in record[1]. */ table->move_fields(table->field, table->record[1], table->record[0]); + thd->abort_on_warning= 0; table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE); + thd->abort_on_warning= abort_on_warning; table->move_fields(table->field, table->record[0], table->record[1]); } if (info->handle_duplicates == DUP_UPDATE)