summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Malyavin <nikitamalyavin@gmail.com>2021-03-24 01:02:26 +0300
committerNikita Malyavin <nikitamalyavin@gmail.com>2021-04-08 17:56:31 +0300
commit365cc8e5fd86d522b620436359793bea62c7567e (patch)
tree061830eceec4b85d89c1d8eee309ce3c7135e73a
parent6e7e772d780b23066307c307c45c552f5bf3d5dd (diff)
downloadmariadb-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.result30
-rw-r--r--mysql-test/suite/gcol/t/gcol_bugfixes.test31
-rw-r--r--sql/field.h5
-rw-r--r--sql/sql_insert.cc5
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)
{