diff options
author | Nikita Malyavin <nikitamalyavin@gmail.com> | 2021-03-24 01:02:26 +0300 |
---|---|---|
committer | Nikita Malyavin <nikitamalyavin@gmail.com> | 2021-04-08 17:56:31 +0300 |
commit | 365cc8e5fd86d522b620436359793bea62c7567e (patch) | |
tree | 061830eceec4b85d89c1d8eee309ce3c7135e73a | |
parent | 6e7e772d780b23066307c307c45c552f5bf3d5dd (diff) | |
download | mariadb-git-bb-10.2-purge-debug-sync.tar.gz |
MDEV-24583 SELECT aborts after failed REPLACE into table with vcolbb-10.2-purge-debug-sync
table->move_fields wasn't undone in case of error.
1. move_fields is unconditionally undone even when error is occurred
2. cherry-pick an assertion in `ptr_in_record`, which is already in 10.5
-rw-r--r-- | mysql-test/suite/gcol/r/gcol_bugfixes.result | 30 | ||||
-rw-r--r-- | mysql-test/suite/gcol/t/gcol_bugfixes.test | 31 | ||||
-rw-r--r-- | sql/field.h | 5 | ||||
-rw-r--r-- | sql/sql_insert.cc | 5 |
4 files changed, 67 insertions, 4 deletions
diff --git a/mysql-test/suite/gcol/r/gcol_bugfixes.result b/mysql-test/suite/gcol/r/gcol_bugfixes.result index 8eb7a9372b5..d4887a0e653 100644 --- a/mysql-test/suite/gcol/r/gcol_bugfixes.result +++ b/mysql-test/suite/gcol/r/gcol_bugfixes.result @@ -669,3 +669,33 @@ PRIMARY KEY (number) REPLACE t2(number) VALUES('1'); REPLACE t2(number) VALUES('1'); DROP TABLE t2; +CREATE TABLE t1 (pk INT, a VARCHAR(3), v VARCHAR(3) AS (CONCAT('x-',a)), +PRIMARY KEY(pk)) ENGINE=MyISAM; +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (pk, a) VALUES (1,'foo'); +SET sql_mode=CONCAT(@@sql_mode,',STRICT_ALL_TABLES'); +REPLACE INTO t1 (pk,a) VALUES (1,'qux'); +SELECT * FROM v1; +pk a v +1 foo x-f +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 ( +pk INT, +a VARCHAR(1), +v VARCHAR(1) AS (CONCAT('virt-',a)) VIRTUAL, +PRIMARY KEY (pk) +) ENGINE=InnoDB; +INSERT INTO t1 (pk,a) VALUES +(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f'); +REPLACE INTO t1 (pk) VALUES (1); +ERROR 22001: Data too long for column 'v' at row 1 +SELECT * FROM t1 ORDER BY a; +pk a v +1 a v +2 b v +3 c v +4 d v +5 e v +6 f v +DROP TABLE t1; diff --git a/mysql-test/suite/gcol/t/gcol_bugfixes.test b/mysql-test/suite/gcol/t/gcol_bugfixes.test index 033c430853d..66c5a7c93a4 100644 --- a/mysql-test/suite/gcol/t/gcol_bugfixes.test +++ b/mysql-test/suite/gcol/t/gcol_bugfixes.test @@ -634,3 +634,34 @@ REPLACE t2(number) VALUES('1'); REPLACE t2(number) VALUES('1'); DROP TABLE t2; + +CREATE TABLE t1 (pk INT, a VARCHAR(3), v VARCHAR(3) AS (CONCAT('x-',a)), + PRIMARY KEY(pk)) ENGINE=MyISAM; +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (pk, a) VALUES (1,'foo'); +SET sql_mode=CONCAT(@@sql_mode,',STRICT_ALL_TABLES'); +--error 0,ER_DATA_TOO_LONG +REPLACE INTO t1 (pk,a) VALUES (1,'qux'); +SELECT * FROM v1; + +# Cleanup +DROP VIEW v1; +DROP TABLE t1; + +CREATE TABLE t1 ( + pk INT, + a VARCHAR(1), + v VARCHAR(1) AS (CONCAT('virt-',a)) VIRTUAL, + PRIMARY KEY (pk) +) ENGINE=InnoDB; + +INSERT INTO t1 (pk,a) VALUES +(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f'); + + --error ER_DATA_TOO_LONG +REPLACE INTO t1 (pk) VALUES (1); +SELECT * FROM t1 ORDER BY a; + +DROP TABLE t1; + + diff --git a/sql/field.h b/sql/field.h index 18e44f1d9d4..f63fb670211 100644 --- a/sql/field.h +++ b/sql/field.h @@ -972,8 +972,9 @@ public: virtual void reset_fields() {} const uchar *ptr_in_record(const uchar *record) const { - my_ptrdiff_t l_offset= (my_ptrdiff_t) (record - table->record[0]); - return ptr + l_offset; + my_ptrdiff_t l_offset= (my_ptrdiff_t) (ptr - table->record[0]); + DBUG_ASSERT(l_offset >= 0 && table->s->rec_buff_length - l_offset > 0); + return record + l_offset; } virtual int set_default(); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ec79ff6d688..90cf8782d48 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1753,9 +1753,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) in handler methods for the just read row in record[1]. */ table->move_fields(table->field, table->record[1], table->record[0]); - if (table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE)) - goto err; + int verr = table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE); table->move_fields(table->field, table->record[0], table->record[1]); + if (verr) + goto err; } if (info->handle_duplicates == DUP_UPDATE) { |