Commit 31366c6c authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-17548 Incorrect access to off-page column for indexed virtual column

row_build_index_entry_low(): ext does not contain virtual columns.

row_upd_store_v_row(): Copy virtual column values

This is based on the following fix in MySQL 5.7.24:

commit 4ec2158bec73f1582501c4b3e3de250fed9edc9a
Author: Sachin Agarwal <sachin.z.agarwal@oracle.com>
Date:   Fri Aug 24 14:44:13 2018 +0530

    Bug #27968952 INNODB CRASH/CORRUPTION WITH TEXT PREFIX INDEXES

    Problem:
    There are two problems:
      1. If there is one secondary index on extenally
    stored column and another seconday index on virtual column (whose
    base column is not externally stored). then while updating seconday
    index on vitrual column, virtual column data is replaced by
    externally stoared column.
      2. In row update operation, node->row contains
    shallow copy of virtual data fields. While building an update vector
    containing all the fields to be modified, compute virtual column.
    which may causes change in virtual data fields in node->row.

    In both the above cases, while updating seconday index on virtual
    column, couldn't find the row and hit an explicite assert inside
    ROW_NOT_FOUND.

    Fix:
    1. Added check if column is virtual then its ext flag should be ZERO
    and virtual column data will not be replaced by offset column data.
    2. Deep copy of virtual data fields for node->row.

    RB: #20382
    Reviewed by : Jimmy.Yang@oracle.com
parent e548d92b
......@@ -211,3 +211,35 @@ t1 CREATE TABLE `t1` (
KEY `n` (`col2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
DROP TABLE t1;
#
# Bug #27968952 INNODB CRASH/CORRUPTION WITH TEXT PREFIX INDEXES
#
CREATE TABLE t1(
a INT NOT NULL UNIQUE,
b INT NOT NULL,
c TEXT GENERATED ALWAYS AS (a <> b) VIRTUAL,
d TEXT NOT NULL,
UNIQUE KEY (c(1)), KEY(d(1))
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
SET @t = REPEAT('t',@@innodb_page_size);
INSERT INTO t1 (a,b,d) VALUES (1,0,@t), (0,0,@t);
UPDATE t1 SET b = a;
ERROR 23000: Duplicate entry '0' for key 'c'
REPLACE INTO t1 SET a = 0, b = 1, d = 'd';
SELECT * FROM t1;
a b c d
0 1 1 d
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
DROP TABLE t1;
CREATE TABLE t1(
a VARCHAR(1000) GENERATED ALWAYS AS ('1') VIRTUAL,
b VARCHAR(1000) NOT NULL,
c VARCHAR(1000) GENERATED ALWAYS AS (b) STORED,
KEY (b(1)),
KEY (a(1))
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
INSERT INTO t1(b) VALUES(REPEAT('b',1000));
DELETE FROM t1;
DROP TABLE t1;
......@@ -232,3 +232,34 @@ CREATE TABLE t1 (col1 int(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE t1 ADD col2 char(21) AS (col1 * col1), ADD INDEX n (col2);
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # Bug #27968952 INNODB CRASH/CORRUPTION WITH TEXT PREFIX INDEXES
--echo #
CREATE TABLE t1(
a INT NOT NULL UNIQUE,
b INT NOT NULL,
c TEXT GENERATED ALWAYS AS (a <> b) VIRTUAL,
d TEXT NOT NULL,
UNIQUE KEY (c(1)), KEY(d(1))
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
SET @t = REPEAT('t',@@innodb_page_size);
INSERT INTO t1 (a,b,d) VALUES (1,0,@t), (0,0,@t);
--error ER_DUP_ENTRY
UPDATE t1 SET b = a;
REPLACE INTO t1 SET a = 0, b = 1, d = 'd';
SELECT * FROM t1;
CHECK TABLE t1;
DROP TABLE t1;
CREATE TABLE t1(
a VARCHAR(1000) GENERATED ALWAYS AS ('1') VIRTUAL,
b VARCHAR(1000) NOT NULL,
c VARCHAR(1000) GENERATED ALWAYS AS (b) STORED,
KEY (b(1)),
KEY (a(1))
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
INSERT INTO t1(b) VALUES(REPEAT('b',1000));
DELETE FROM t1;
DROP TABLE t1;
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
......@@ -295,7 +295,7 @@ row_build_index_entry_low(
stored off-page. */
ut_ad(col->ord_part);
if (ext) {
if (ext && !col->is_virtual()) {
/* See if the column is stored externally. */
const byte* buf = row_ext_lookup(ext, col_no,
&len);
......
......@@ -2157,6 +2157,7 @@ row_upd_store_v_row(
}
dfield_copy_data(dfield, upd_field->old_v_val);
dfield_dup(dfield, node->heap);
break;
}
......@@ -2177,6 +2178,7 @@ row_upd_store_v_row(
update->old_vrow,
col_no);
dfield_copy_data(dfield, vfield);
dfield_dup(dfield, node->heap);
}
} else {
/* Need to compute, this happens when
......
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