Commit 43e879c7 authored by Nikita Malyavin's avatar Nikita Malyavin

MDEV-24583 SELECT aborts after failed REPLACE into table with vcol

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
parent f85afa51
...@@ -669,3 +669,77 @@ PRIMARY KEY (number) ...@@ -669,3 +669,77 @@ PRIMARY KEY (number)
REPLACE t2(number) VALUES('1'); REPLACE t2(number) VALUES('1');
REPLACE t2(number) VALUES('1'); REPLACE t2(number) VALUES('1');
DROP TABLE t2; DROP TABLE t2;
# MDEV-24583 SELECT aborts after failed REPLACE into table with vcol
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
SET SQL_MODE=DEFAULT;
DROP TABLE t1;
# (duplicate) MDEV-24656
# [FATAL] InnoDB: Data field type 0, len 0, ASAN heap-buffer-overflow
# upon LOAD DATA with virtual columns
CREATE TABLE t1 (id INT PRIMARY KEY, a VARCHAR(2333),
va VARCHAR(171) AS (a)) ENGINE=InnoDB;
INSERT INTO t1 (id,a) VALUES (1,REPEAT('x',200));
SELECT id, va INTO OUTFILE 'load_t1' FROM t1;
LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id,va);
ERROR 22001: Data too long for column 'va' at row 1
SELECT * FROM t1;
id a va
1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
LOAD DATA INFILE 'load_t1' IGNORE INTO TABLE t1 (id,va);
Warnings:
Warning 1062 Duplicate entry '1' for key 'PRIMARY'
DROP TABLE t1;
CREATE TABLE t1 (id BIGINT PRIMARY KEY, a VARCHAR(2333),
va VARCHAR(171) AS (a)) ENGINE=InnoDB;
INSERT INTO t1 (id,a) VALUES (1,REPEAT('x',200));
SELECT id, va INTO OUTFILE 'load_t1' FROM t1;
LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id,va);
ERROR 22001: Data too long for column 'va' at row 1
SELECT * FROM t1;
id a va
1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
LOAD DATA INFILE 'load_t1' IGNORE INTO TABLE t1 (id,va);
Warnings:
Warning 1062 Duplicate entry '1' for key 'PRIMARY'
DROP TABLE t1;
# (duplicate) MDEV-24665
# ASAN errors, assertion failures, corrupt values after failed
# LOAD DATA into table with virtual/stored column
CREATE TABLE t1 (id INT PRIMARY KEY,
ts TIMESTAMP DEFAULT '1971-01-01 00:00:00',
c VARBINARY(8) DEFAULT '', vc VARCHAR(3) AS (c) STORED);
INSERT IGNORE INTO t1 (id,c) VALUES (1,'foobar');
Warnings:
Warning 1265 Data truncated for column 'vc' at row 1
SELECT id, ts, vc INTO OUTFILE 'load_t1' FROM t1;
LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id, ts, vc);
INSERT IGNORE INTO t1 (id) VALUES (2);
DROP TABLE t1;
...@@ -634,3 +634,87 @@ REPLACE t2(number) VALUES('1'); ...@@ -634,3 +634,87 @@ REPLACE t2(number) VALUES('1');
REPLACE t2(number) VALUES('1'); REPLACE t2(number) VALUES('1');
DROP TABLE t2; DROP TABLE t2;
--echo # MDEV-24583 SELECT aborts after failed REPLACE into table with vcol
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;
SET SQL_MODE=DEFAULT;
DROP TABLE t1;
--echo # (duplicate) MDEV-24656
--echo # [FATAL] InnoDB: Data field type 0, len 0, ASAN heap-buffer-overflow
--echo # upon LOAD DATA with virtual columns
CREATE TABLE t1 (id INT PRIMARY KEY, a VARCHAR(2333),
va VARCHAR(171) AS (a)) ENGINE=InnoDB;
INSERT INTO t1 (id,a) VALUES (1,REPEAT('x',200));
SELECT id, va INTO OUTFILE 'load_t1' FROM t1;
--error ER_DATA_TOO_LONG
LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id,va);
SELECT * FROM t1;
LOAD DATA INFILE 'load_t1' IGNORE INTO TABLE t1 (id,va);
DROP TABLE t1;
--let $datadir= `select @@datadir`
--remove_file $datadir/test/load_t1
CREATE TABLE t1 (id BIGINT PRIMARY KEY, a VARCHAR(2333),
va VARCHAR(171) AS (a)) ENGINE=InnoDB;
INSERT INTO t1 (id,a) VALUES (1,REPEAT('x',200));
SELECT id, va INTO OUTFILE 'load_t1' FROM t1;
--error ER_DATA_TOO_LONG
LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id,va);
SELECT * FROM t1;
LOAD DATA INFILE 'load_t1' IGNORE INTO TABLE t1 (id,va);
# Cleanup
DROP TABLE t1;
--let $datadir= `select @@datadir`
--remove_file $datadir/test/load_t1
--echo # (duplicate) MDEV-24665
--echo # ASAN errors, assertion failures, corrupt values after failed
--echo # LOAD DATA into table with virtual/stored column
CREATE TABLE t1 (id INT PRIMARY KEY,
ts TIMESTAMP DEFAULT '1971-01-01 00:00:00',
c VARBINARY(8) DEFAULT '', vc VARCHAR(3) AS (c) STORED);
INSERT IGNORE INTO t1 (id,c) VALUES (1,'foobar');
SELECT id, ts, vc INTO OUTFILE 'load_t1' FROM t1;
--error 0,ER_DATA_TOO_LONG
LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id, ts, vc);
INSERT IGNORE INTO t1 (id) VALUES (2);
# Cleanup
DROP TABLE t1;
--let $datadir= `select @@datadir`
--remove_file $datadir/test/load_t1
...@@ -67,4 +67,17 @@ connection master; ...@@ -67,4 +67,17 @@ connection master;
DROP VIEW v1; DROP VIEW v1;
set @@binlog_row_image=default; set @@binlog_row_image=default;
DROP TABLE t1; DROP TABLE t1;
SET SQL_MODE=default;
CREATE TABLE t1 (pk INT, a VARCHAR(3), b VARCHAR(1) AS (a) VIRTUAL, PRIMARY KEY (pk));
INSERT IGNORE INTO t1 (pk, a) VALUES (1,'foo'),(2,'bar');
Warnings:
Warning 1265 Data truncated for column 'b' at row 1
Warning 1265 Data truncated for column 'b' at row 2
REPLACE INTO t1 (pk) VALUES (2);
ERROR 22001: Data too long for column 'b' at row 1
UPDATE IGNORE t1 SET a = NULL;
Warnings:
Warning 1265 Data truncated for column 'b' at row 1
Warning 1265 Data truncated for column 'b' at row 2
DROP TABLE t1;
include/rpl_end.inc include/rpl_end.inc
...@@ -51,5 +51,19 @@ DROP VIEW v1; ...@@ -51,5 +51,19 @@ DROP VIEW v1;
set @@binlog_row_image=default; set @@binlog_row_image=default;
DROP TABLE t1; DROP TABLE t1;
SET SQL_MODE=default;
# MDEV-24782
# ASAN use-after-poison in Field::pack_int / THD::binlog_update_row
CREATE TABLE t1 (pk INT, a VARCHAR(3), b VARCHAR(1) AS (a) VIRTUAL, PRIMARY KEY (pk));
INSERT IGNORE INTO t1 (pk, a) VALUES (1,'foo'),(2,'bar');
--error ER_DATA_TOO_LONG
REPLACE INTO t1 (pk) VALUES (2);
UPDATE IGNORE t1 SET a = NULL;
# Cleanup
DROP TABLE t1;
--source include/rpl_end.inc --source include/rpl_end.inc
...@@ -972,8 +972,9 @@ class Field: public Value_source ...@@ -972,8 +972,9 @@ class Field: public Value_source
virtual void reset_fields() {} virtual void reset_fields() {}
const uchar *ptr_in_record(const uchar *record) const const uchar *ptr_in_record(const uchar *record) const
{ {
my_ptrdiff_t l_offset= (my_ptrdiff_t) (record - table->record[0]); my_ptrdiff_t l_offset= (my_ptrdiff_t) (ptr - table->record[0]);
return ptr + l_offset; DBUG_ASSERT(l_offset >= 0 && table->s->rec_buff_length - l_offset > 0);
return record + l_offset;
} }
virtual int set_default(); virtual int set_default();
......
...@@ -1753,9 +1753,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) ...@@ -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]. in handler methods for the just read row in record[1].
*/ */
table->move_fields(table->field, table->record[1], table->record[0]); table->move_fields(table->field, table->record[1], table->record[0]);
if (table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE)) int verr = table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE);
goto err;
table->move_fields(table->field, table->record[0], table->record[1]); table->move_fields(table->field, table->record[0], table->record[1]);
if (verr)
goto err;
} }
if (info->handle_duplicates == DUP_UPDATE) if (info->handle_duplicates == DUP_UPDATE)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment