mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-41667 InnoDB: Failing assertion: buf <= (byte*) original_upd_buff + buff_len
Problem: ======= An UPDATE on an InnoDB table with several indexed virtual columns could corrupt the heap in calc_row_difference() because the write pointer went past the end of the update buffer. ha_innobase::update_row() sized the buffer from the row length, the maximum key length and fixed padding. That did not allow for the extra packed values calc_row_difference() stores for indexed virtual columns for both the new value and the old value. Solution: ======== When allocating the update buffer in ha_innobase::update_row(), add pack_length() of every virtual column. The row length already counts each virtual column once, so the buffer can now hold both the new and old packed values. All virtual columns are counted, not only the indexed ones, because the buffer is reused and a column may become indexed after it is allocated. Based on mysql/mysql-server@1265514061
This commit is contained in:
@@ -364,5 +364,21 @@ disconnect con1;
|
||||
connection default;
|
||||
drop table t;
|
||||
#
|
||||
# MDEV-41667 InnoDB: Failing assertion: buf <= (byte*)
|
||||
# original_upd_buff + buff_len
|
||||
#
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b BIGINT NOT NULL , v1 BIGINT AS (b+1) VIRTUAL, KEY(v1), v2 BIGINT AS (b+2) VIRTUAL, KEY(v2), v3 BIGINT AS (b+3) VIRTUAL, KEY(v3), v4 BIGINT AS (b+4) VIRTUAL, KEY(v4), v5 BIGINT AS (b+5) VIRTUAL, KEY(v5), v6 BIGINT AS (b+6) VIRTUAL, KEY(v6), v7 BIGINT AS (b+7) VIRTUAL, KEY(v7), v8 BIGINT AS (b+8) VIRTUAL, KEY(v8), v9 BIGINT AS (b+9) VIRTUAL, KEY(v9), v10 BIGINT AS (b+10) VIRTUAL, KEY(v10), v11 BIGINT AS (b+11) VIRTUAL, KEY(v11), v12 BIGINT AS (b+12) VIRTUAL, KEY(v12), v13 BIGINT AS (b+13) VIRTUAL, KEY(v13), v14 BIGINT AS (b+14) VIRTUAL, KEY(v14), v15 BIGINT AS (b+15) VIRTUAL, KEY(v15), v16 BIGINT AS (b+16) VIRTUAL, KEY(v16), v17 BIGINT AS (b+17) VIRTUAL, KEY(v17), v18 BIGINT AS (b+18) VIRTUAL, KEY(v18), v19 BIGINT AS (b+19) VIRTUAL, KEY(v19), v20 BIGINT AS (b+20) VIRTUAL, KEY(v20), v21 BIGINT AS (b+21) VIRTUAL, KEY(v21), v22 BIGINT AS (b+22) VIRTUAL, KEY(v22), v23 BIGINT AS (b+23) VIRTUAL, KEY(v23), v24 BIGINT AS (b+24) VIRTUAL, KEY(v24), v25 BIGINT AS (b+25) VIRTUAL, KEY(v25), v26 BIGINT AS (b+26) VIRTUAL, KEY(v26), v27 BIGINT AS (b+27) VIRTUAL, KEY(v27), v28 BIGINT AS (b+28) VIRTUAL, KEY(v28), v29 BIGINT AS (b+29) VIRTUAL, KEY(v29), v30 BIGINT AS (b+30) VIRTUAL, KEY(v30), v31 BIGINT AS (b+31) VIRTUAL, KEY(v31), v32 BIGINT AS (b+32) VIRTUAL, KEY(v32)) ENGINE=InnoDB;
|
||||
INSERT INTO t1 (a,b) VALUES (1,10),(2,20);
|
||||
UPDATE t1 SET b=11 WHERE a=1;
|
||||
UPDATE t1 SET b=b+100;
|
||||
SELECT a, b, v1, v32 FROM t1;
|
||||
a b v1 v32
|
||||
1 111 112 143
|
||||
2 120 121 152
|
||||
CHECK TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# End of 10.11 tests
|
||||
#
|
||||
|
||||
@@ -197,6 +197,26 @@ disconnect con1;
|
||||
connection default;
|
||||
drop table t;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-41667 InnoDB: Failing assertion: buf <= (byte*)
|
||||
--echo # original_upd_buff + buff_len
|
||||
--echo #
|
||||
let $n= 32;
|
||||
let $cols= ;
|
||||
let $i= 1;
|
||||
while ($i <= $n)
|
||||
{
|
||||
let $cols= $cols, v$i BIGINT AS (b+$i) VIRTUAL, KEY(v$i);
|
||||
inc $i;
|
||||
}
|
||||
eval CREATE TABLE t1 (a INT PRIMARY KEY, b BIGINT NOT NULL $cols) ENGINE=InnoDB;
|
||||
INSERT INTO t1 (a,b) VALUES (1,10),(2,20);
|
||||
UPDATE t1 SET b=11 WHERE a=1;
|
||||
UPDATE t1 SET b=b+100;
|
||||
SELECT a, b, v1, v32 FROM t1;
|
||||
CHECK TABLE t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.11 tests
|
||||
--echo #
|
||||
|
||||
@@ -8266,7 +8266,7 @@ calc_row_difference(
|
||||
const uchar* new_row,
|
||||
TABLE* table,
|
||||
uchar* upd_buff,
|
||||
ulint buff_len,
|
||||
size_t buff_len,
|
||||
row_prebuilt_t* prebuilt,
|
||||
ib_uint64_t& auto_inc)
|
||||
{
|
||||
@@ -8799,6 +8799,21 @@ ha_innobase::update_row(
|
||||
m_upd_buf_size = table->s->reclength + table->s->max_key_length
|
||||
+ MAX_REF_PARTS * 3;
|
||||
|
||||
/* Reserve an extra packed value for every
|
||||
virtual column. calc_row_difference() may retain
|
||||
both new and old values for indexed virtual
|
||||
columns, including columns indexed by an online
|
||||
rebuild.
|
||||
The buffer is reused, so its capacity must also
|
||||
cover virtual columns that become indexed
|
||||
after the initial allocation. */
|
||||
for (uint i = 0; i < table->s->fields; i++) {
|
||||
Field *field = table->field[i];
|
||||
if (!field->stored_in_db()) {
|
||||
m_upd_buf_size += field->pack_length();
|
||||
}
|
||||
}
|
||||
|
||||
m_upd_buf = reinterpret_cast<uchar*>(
|
||||
my_malloc(PSI_INSTRUMENT_ME,
|
||||
m_upd_buf_size,
|
||||
|
||||
@@ -518,7 +518,7 @@ protected:
|
||||
uchar* m_upd_buf;
|
||||
|
||||
/** the size of upd_buf in bytes */
|
||||
ulint m_upd_buf_size;
|
||||
size_t m_upd_buf_size;
|
||||
|
||||
/** Flags that specificy the handler instance (table) capability. */
|
||||
Table_flags m_int_table_flags;
|
||||
|
||||
Reference in New Issue
Block a user