Skip to content

Commit a5d0f86

Browse files
Bug #28652826 THE CONTINUATION OF BUG 27968952 .. CRASH &
CORRUPTION WITH GCOLS Problem: Wrong value of BLOB column is being updated into secondary index. Analysis: For REPLACE query, If INSERT operation finds same key value in cluster index, It converts INSERT into UPDATE operation. UPDATE operation build the update vector. For virtual generated columns, my_eval_gcolumn_expr() wrties the "old" BLOB column directly into Field_blob::value. If this UPDATE operation fails due to dup_key error in secondary index. We go back to the handler and fetch the key value which causes the error. If that key is defined on virtual BLOB column. Since the "old" value has over-written the "new" value. We get "old" BLOB value. Therefore we update wrong row and end up with data corruption. Solution: If INSERT operation returns DUP_KEY error to the handler. We recalculate data for generated columns before reading the key value. Change-Id: I8fd4526cac6b0c905fc6125e24ed85f524ae1343 Reviewed by : Sergey Glukhov<sergey.glukhov@oracle.com>
1 parent d433f6a commit a5d0f86

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

mysql-test/suite/gcol/r/gcol_bugfixes.result

+21
Original file line numberDiff line numberDiff line change
@@ -639,3 +639,24 @@ SELECT (SELECT MAX(c) FROM v);
639639
(SELECT MAX(c) FROM v)
640640
1
641641
DROP TABLE v;
642+
#
643+
# Bug #28652826 THE CONTINUATION OF BUG 27968952 .. CRASH & CORRUPTION
644+
# WITH GCOLS
645+
#
646+
CREATE TABLE t(
647+
a INT NOT NULL,
648+
b INT NOT NULL,
649+
c INT NOT NULL,
650+
g MEDIUMTEXT GENERATED ALWAYS AS((a <> b)) VIRTUAL,
651+
UNIQUE KEY i0000 (a),
652+
UNIQUE KEY i0001 (g(78))
653+
) ENGINE=INNODB;
654+
REPLACE INTO t(a, b, c) VALUES (1,8,9);
655+
REPLACE INTO t(a, b, c) VALUES (0,0,10);
656+
REPLACE INTO t(a, b, c) VALUES (4,4,11);
657+
REPLACE INTO t(a, b, c) VALUES (0,7,12);
658+
REPLACE INTO t(a, b, c) VALUES (0,0,13);
659+
SELECT * FROM t;
660+
a b c g
661+
0 0 13 0
662+
DROP TABLE t;

mysql-test/suite/gcol/t/gcol_bugfixes.test

+21
Original file line numberDiff line numberDiff line change
@@ -611,3 +611,24 @@ KEY(c,b(1))) charset utf8mb4;
611611
INSERT INTO v (a,c) VALUES (1,1);
612612
SELECT (SELECT MAX(c) FROM v);
613613
DROP TABLE v;
614+
615+
--echo #
616+
--echo # Bug #28652826 THE CONTINUATION OF BUG 27968952 .. CRASH & CORRUPTION
617+
--echo # WITH GCOLS
618+
--echo #
619+
620+
CREATE TABLE t(
621+
a INT NOT NULL,
622+
b INT NOT NULL,
623+
c INT NOT NULL,
624+
g MEDIUMTEXT GENERATED ALWAYS AS((a <> b)) VIRTUAL,
625+
UNIQUE KEY i0000 (a),
626+
UNIQUE KEY i0001 (g(78))
627+
) ENGINE=INNODB;
628+
REPLACE INTO t(a, b, c) VALUES (1,8,9);
629+
REPLACE INTO t(a, b, c) VALUES (0,0,10);
630+
REPLACE INTO t(a, b, c) VALUES (4,4,11);
631+
REPLACE INTO t(a, b, c) VALUES (0,7,12);
632+
REPLACE INTO t(a, b, c) VALUES (0,0,13);
633+
SELECT * FROM t;
634+
DROP TABLE t;

sql/sql_insert.cc

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -1623,6 +1623,14 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, COPY_INFO *update)
16231623
goto err;
16241624
}
16251625
}
1626+
/*
1627+
If we convert INSERT operation internally to an UPDATE.
1628+
An INSERT operation may update table->vfield for BLOB fields,
1629+
So here we recalculate data for generated columns.
1630+
*/
1631+
if (table->vfield) {
1632+
update_generated_write_fields(table->write_set, table);
1633+
}
16261634
key_copy((uchar*) key,table->record[0],table->key_info+key_nr,0);
16271635
if ((error=(table->file->ha_index_read_idx_map(table->record[1],key_nr,
16281636
(uchar*) key, HA_WHOLE_KEY,
@@ -1808,6 +1816,7 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, COPY_INFO *update)
18081816
we just should not expose this fact to users by invoking
18091817
ON UPDATE triggers.
18101818
*/
1819+
18111820
if (last_uniq_key(table,key_nr) &&
18121821
!table->file->referenced_by_foreign_key() &&
18131822
(!table->triggers || !table->triggers->has_delete_triggers()))

0 commit comments

Comments
 (0)