Browse Source

MDEV-35475 Assertion `!rec_offs_nth_extern(offsets1, n)' failed in cmp_rec_rec_simple_field

Problem:
=======
InnoDB wrongly stores the primary key field in externally
stored off page during bulk insert operation. This leads
to assert failure.

Solution:
========
row_merge_buf_blob(): Should store the primary key fields
inline. Store the variable length field data externally
based on the row format of the table.
10.11-MDEV-34575
Thirunarayanan Balathandayuthapani 11 months ago
parent
commit
d93934d7bc
  1. 24
      mysql-test/suite/innodb/r/alter_copy_bulk.result
  2. 8
      mysql-test/suite/innodb/r/innodb-64k-crash,dynamic.rdiff
  3. 52
      mysql-test/suite/innodb/r/innodb-64k-crash,redundant.rdiff
  4. 50
      mysql-test/suite/innodb/r/innodb-64k-crash.result
  5. 8
      mysql-test/suite/innodb/r/insert_into_empty,32k.rdiff
  6. 34
      mysql-test/suite/innodb/r/insert_into_empty,4k.rdiff
  7. 8
      mysql-test/suite/innodb/r/insert_into_empty,64k.rdiff
  8. 38
      mysql-test/suite/innodb/r/insert_into_empty,8k.rdiff
  9. 23
      mysql-test/suite/innodb/r/insert_into_empty.result
  10. 25
      mysql-test/suite/innodb/t/alter_copy_bulk.test
  11. 1
      mysql-test/suite/innodb/t/innodb-64k-crash.opt
  12. 62
      mysql-test/suite/innodb/t/innodb-64k-crash.test
  13. 28
      mysql-test/suite/innodb/t/insert_into_empty.test
  14. 157
      storage/innobase/row/row0merge.cc

24
mysql-test/suite/innodb/r/alter_copy_bulk.result

@ -66,4 +66,28 @@ SELECT COUNT(*) FROM t;
COUNT(*)
2
DROP TABLE t1, t2, t;
#
# MDEV-35475 Assertion `!rec_offs_nth_extern(offsets1, n)'
# failed in cmp_rec_rec_simple_field
#
CREATE TABLE t1(a BLOB, b VARCHAR(2048), PRIMARY KEY (b)) ENGINE=InnoDB;
INSERT INTO t1 VALUES
(REPEAT('x',4805),'a'), (REPEAT('x',16111),'b'),
(REPEAT('x',65535),'c'), (REPEAT('x',11312),'d'),
(REPEAT('x',35177),'e'), (REPEAT('x',65535),'f'),
(REPEAT('x',1988),'g'), (NULL,REPEAT('x',2048)),
(REPEAT('x',2503),'h'), (REPEAT('x',33152),'i'),
(REPEAT('x',65535),'j'), (REPEAT('x',1988),'k'),
(REPEAT('x',65535),'l'), (REPEAT('x',65535),'m'),
(REPEAT('x',65535),'n'), (REPEAT('x',65535),'o'),
(REPEAT('x',1988),'p'), (REPEAT('x',2503),'q'),
(REPEAT('x',65535),'r'), (REPEAT('x',65535),'s'),
(REPEAT('x',65535),'t'), (REPEAT('x',3169),'u'),
(REPEAT('x',7071),'v'), (REPEAT('x',16111),'w'),
(REPEAT('x',2325),'x'), (REPEAT('x',33152),'y'),
(REPEAT('x',65535),'z'), (REPEAT('x',65535),'aa'),
(REPEAT('x',16111),'bb'), (REPEAT('x',4805),'cc'),
(REPEAT('x',65535),'dd');
ALTER TABLE t1 FORCE, ALGORITHM=COPY;
DROP TABLE t1;
SET GLOBAL innodb_stats_persistent=@default_stats_persistent;

8
mysql-test/suite/innodb/r/innodb-64k-crash,dynamic.rdiff

@ -0,0 +1,8 @@
--- innodb-64k-crash.result 2024-11-28 10:37:26.491384671 +0530
+++ innodb-64k-crash.reject 2024-11-28 11:05:46.461405444 +0530
@@ -334,5 +334,4 @@
REPEAT('s', 1024), REPEAT('t', 1024),
REPEAT('u', 1024), REPEAT('v', 1024),
REPEAT('w', 1024), REPEAT('x', 1024));
-ERROR 42000: Row size too large (> 16383). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
DROP TABLE t1;

52
mysql-test/suite/innodb/r/innodb-64k-crash,redundant.rdiff

@ -0,0 +1,52 @@
--- innodb-64k-crash.result 2024-11-28 10:37:26.491384671 +0530
+++ innodb-64k-crash.reject 2024-11-28 11:10:13.381250612 +0530
@@ -290,49 +290,3 @@
# MDEV-35475 Assertion `!rec_offs_nth_extern(offsets1, n)'
# failed in cmp_rec_rec_simple_field
#
-CREATE TABLE t1(f1 int not null, f2 text, f3 text, f4 text,
-f5 text, f6 text, f7 text, f8 text,
-f9 text, f10 text, f11 text, f12 text,
-f13 text, f14 text, f15 text, f16 text,
-f17 text, f18 text, f19 text, f20 text,
-f21 text, f22 text, f23 text, f24 text,
-f25 text, PRIMARY KEY(f1))ENGINE=InnoDB;
-SET STATEMENT unique_checks=0,foreign_key_checks=0 FOR
-INSERT INTO t1 VALUES(1, REPEAT('a', 1024), REPEAT('b', 1024),
-REPEAT('c', 1024), REPEAT('d', 1024),
-REPEAT('e', 1024), REPEAT('f', 1024),
-REPEAT('g', 4096), REPEAT('h', 1024),
-REPEAT('i', 1024), REPEAT('j', 1024),
-REPEAT('k', 1024), REPEAT('l', 1024),
-REPEAT('m', 1024), REPEAT('n', 1024),
-REPEAT('o', 1024), REPEAT('p', 1024),
-REPEAT('q', 1024), REPEAT('r', 1024),
-REPEAT('s', 1024), REPEAT('t', 1024),
-REPEAT('u', 1024), REPEAT('v', 1024),
-REPEAT('w', 1024), REPEAT('x', 1024)),
-(2, REPEAT('a', 1024), REPEAT('b', 1024),
-REPEAT('c', 1024), REPEAT('d', 1024),
-REPEAT('e', 1024), REPEAT('f', 1024),
-REPEAT('g', 4096), REPEAT('h', 1024),
-REPEAT('i', 1024), REPEAT('j', 1024),
-REPEAT('k', 1024), REPEAT('l', 1024),
-REPEAT('m', 1024), REPEAT('n', 1024),
-REPEAT('o', 1024), REPEAT('p', 1024),
-REPEAT('q', 1024), REPEAT('r', 1024),
-REPEAT('s', 1024), REPEAT('t', 1024),
-REPEAT('u', 1024), REPEAT('v', 1024),
-REPEAT('w', 1024), REPEAT('x', 1024)),
-(3, REPEAT('a', 1024), REPEAT('b', 1024),
-REPEAT('c', 1024), REPEAT('d', 1024),
-REPEAT('e', 1024), REPEAT('f', 1024),
-REPEAT('g', 4096), REPEAT('h', 1024),
-REPEAT('i', 1024), REPEAT('j', 1024),
-REPEAT('k', 1024), REPEAT('l', 1024),
-REPEAT('m', 1024), REPEAT('n', 1024),
-REPEAT('o', 1024), REPEAT('p', 1024),
-REPEAT('q', 1024), REPEAT('r', 1024),
-REPEAT('s', 1024), REPEAT('t', 1024),
-REPEAT('u', 1024), REPEAT('v', 1024),
-REPEAT('w', 1024), REPEAT('x', 1024));
-ERROR 42000: Row size too large (> 16383). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
-DROP TABLE t1;

50
mysql-test/suite/innodb/r/innodb-64k-crash.result

@ -286,3 +286,53 @@ Table Op Msg_type Msg_text
test.t1 check status OK
test.t2 check status OK
drop table t1,t2;
#
# MDEV-35475 Assertion `!rec_offs_nth_extern(offsets1, n)'
# failed in cmp_rec_rec_simple_field
#
CREATE TABLE t1(f1 int not null, f2 text, f3 text, f4 text,
f5 text, f6 text, f7 text, f8 text,
f9 text, f10 text, f11 text, f12 text,
f13 text, f14 text, f15 text, f16 text,
f17 text, f18 text, f19 text, f20 text,
f21 text, f22 text, f23 text, f24 text,
f25 text, PRIMARY KEY(f1))ENGINE=InnoDB;
SET STATEMENT unique_checks=0,foreign_key_checks=0 FOR
INSERT INTO t1 VALUES(1, REPEAT('a', 1024), REPEAT('b', 1024),
REPEAT('c', 1024), REPEAT('d', 1024),
REPEAT('e', 1024), REPEAT('f', 1024),
REPEAT('g', 4096), REPEAT('h', 1024),
REPEAT('i', 1024), REPEAT('j', 1024),
REPEAT('k', 1024), REPEAT('l', 1024),
REPEAT('m', 1024), REPEAT('n', 1024),
REPEAT('o', 1024), REPEAT('p', 1024),
REPEAT('q', 1024), REPEAT('r', 1024),
REPEAT('s', 1024), REPEAT('t', 1024),
REPEAT('u', 1024), REPEAT('v', 1024),
REPEAT('w', 1024), REPEAT('x', 1024)),
(2, REPEAT('a', 1024), REPEAT('b', 1024),
REPEAT('c', 1024), REPEAT('d', 1024),
REPEAT('e', 1024), REPEAT('f', 1024),
REPEAT('g', 4096), REPEAT('h', 1024),
REPEAT('i', 1024), REPEAT('j', 1024),
REPEAT('k', 1024), REPEAT('l', 1024),
REPEAT('m', 1024), REPEAT('n', 1024),
REPEAT('o', 1024), REPEAT('p', 1024),
REPEAT('q', 1024), REPEAT('r', 1024),
REPEAT('s', 1024), REPEAT('t', 1024),
REPEAT('u', 1024), REPEAT('v', 1024),
REPEAT('w', 1024), REPEAT('x', 1024)),
(3, REPEAT('a', 1024), REPEAT('b', 1024),
REPEAT('c', 1024), REPEAT('d', 1024),
REPEAT('e', 1024), REPEAT('f', 1024),
REPEAT('g', 4096), REPEAT('h', 1024),
REPEAT('i', 1024), REPEAT('j', 1024),
REPEAT('k', 1024), REPEAT('l', 1024),
REPEAT('m', 1024), REPEAT('n', 1024),
REPEAT('o', 1024), REPEAT('p', 1024),
REPEAT('q', 1024), REPEAT('r', 1024),
REPEAT('s', 1024), REPEAT('t', 1024),
REPEAT('u', 1024), REPEAT('v', 1024),
REPEAT('w', 1024), REPEAT('x', 1024));
ERROR 42000: Row size too large (> 16383). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
DROP TABLE t1;

8
mysql-test/suite/innodb/r/insert_into_empty,32k.rdiff

@ -1,4 +1,6 @@
@@ -377,8 +377,6 @@
--- insert_into_empty.result
+++ insert_into_empty,32k.result
@@ -446,12 +446,9 @@
c09 text, c10 text, c11 text, c12 text) ENGINE=InnoDB;
SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= COMPACT;
ALTER TABLE t1 FORCE;
@ -7,3 +9,7 @@
INSERT IGNORE INTO t1 VALUES
(1, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)),
(2, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107));
-ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK

34
mysql-test/suite/innodb/r/insert_into_empty,4k.rdiff

@ -1,10 +1,38 @@
--- a/mysql-test/suite/innodb/r/insert_into_empty.result
+++ b/mysql-test/suite/innodb/r/insert_into_empty.result
@@ -430,6 +430,7 @@
--- insert_into_empty.result
+++ insert_into_empty,4k.result
@@ -451,7 +451,7 @@
INSERT IGNORE INTO t1 VALUES
(1, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)),
(2, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107));
-ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
+ERROR 42000: Row size too large (> 1982). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
@@ -541,26 +541,4 @@
DELETE FROM t1;
commit;
DROP TABLE t1;
-#
-# MDEV-35475 Assertion `!rec_offs_nth_extern(offsets1, n)'
-# failed in cmp_rec_rec_simple_field
-#
-CREATE TABLE t1(a BLOB, b VARCHAR(2048), PRIMARY KEY (b)) ENGINE=InnoDB;
-INSERT INTO t1 VALUES (REPEAT('x',4805),'a'), (REPEAT('x',16111),'b'),
-(REPEAT('x',65535),'c'), (REPEAT('x',11312),'d'),
-(REPEAT('x',35177),'e'), (REPEAT('x',65535),'f'),
-(REPEAT('x',1988),'g'), (NULL,REPEAT('x',2048)),
-(REPEAT('x',2503),'h'), (REPEAT('x',33152),'i'),
-(REPEAT('x',65535),'j'), (REPEAT('x',1988),'k'),
-(REPEAT('x',65535),'l'), (REPEAT('x',65535),'m'),
-(REPEAT('x',65535),'n'), (REPEAT('x',65535),'o'),
-(REPEAT('x',1988),'p'), (REPEAT('x',2503),'q'),
-(REPEAT('x',65535),'r'), (REPEAT('x',65535),'s'),
-(REPEAT('x',65535),'t'), (REPEAT('x',3169),'u'),
-(REPEAT('x',7071),'v'), (REPEAT('x',16111),'w'),
-(REPEAT('x',2325),'x'), (REPEAT('x',33152),'y'),
-(REPEAT('x',65535),'z'), (REPEAT('x',65535),'aa'),
-(REPEAT('x',16111),'bb'), (REPEAT('x',4805),'cc'),
-(REPEAT('x',65535),'dd');
-DROP TABLE t1;
# End of 10.11 tests

8
mysql-test/suite/innodb/r/insert_into_empty,64k.rdiff

@ -1,4 +1,6 @@
@@ -377,8 +377,6 @@
--- insert_into_empty.result
+++ insert_into_empty,64k.result
@@ -446,12 +446,9 @@
c09 text, c10 text, c11 text, c12 text) ENGINE=InnoDB;
SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= COMPACT;
ALTER TABLE t1 FORCE;
@ -7,3 +9,7 @@
INSERT IGNORE INTO t1 VALUES
(1, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)),
(2, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107));
-ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK

38
mysql-test/suite/innodb/r/insert_into_empty,8k.rdiff

@ -0,0 +1,38 @@
--- insert_into_empty.result
+++ insert_into_empty,8k.result
@@ -451,7 +451,7 @@
INSERT IGNORE INTO t1 VALUES
(1, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)),
(2, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107));
-ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
+ERROR 42000: Row size too large (> 4030). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
@@ -541,26 +541,4 @@
DELETE FROM t1;
commit;
DROP TABLE t1;
-#
-# MDEV-35475 Assertion `!rec_offs_nth_extern(offsets1, n)'
-# failed in cmp_rec_rec_simple_field
-#
-CREATE TABLE t1(a BLOB, b VARCHAR(2048), PRIMARY KEY (b)) ENGINE=InnoDB;
-INSERT INTO t1 VALUES (REPEAT('x',4805),'a'), (REPEAT('x',16111),'b'),
-(REPEAT('x',65535),'c'), (REPEAT('x',11312),'d'),
-(REPEAT('x',35177),'e'), (REPEAT('x',65535),'f'),
-(REPEAT('x',1988),'g'), (NULL,REPEAT('x',2048)),
-(REPEAT('x',2503),'h'), (REPEAT('x',33152),'i'),
-(REPEAT('x',65535),'j'), (REPEAT('x',1988),'k'),
-(REPEAT('x',65535),'l'), (REPEAT('x',65535),'m'),
-(REPEAT('x',65535),'n'), (REPEAT('x',65535),'o'),
-(REPEAT('x',1988),'p'), (REPEAT('x',2503),'q'),
-(REPEAT('x',65535),'r'), (REPEAT('x',65535),'s'),
-(REPEAT('x',65535),'t'), (REPEAT('x',3169),'u'),
-(REPEAT('x',7071),'v'), (REPEAT('x',16111),'w'),
-(REPEAT('x',2325),'x'), (REPEAT('x',33152),'y'),
-(REPEAT('x',65535),'z'), (REPEAT('x',65535),'aa'),
-(REPEAT('x',16111),'bb'), (REPEAT('x',4805),'cc'),
-(REPEAT('x',65535),'dd');
-DROP TABLE t1;
# End of 10.11 tests

23
mysql-test/suite/innodb/r/insert_into_empty.result

@ -451,6 +451,7 @@ Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB o
INSERT IGNORE INTO t1 VALUES
(1, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)),
(2, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107));
ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
@ -540,4 +541,26 @@ INSERT INTO t1 VALUES(2,0);
DELETE FROM t1;
commit;
DROP TABLE t1;
#
# MDEV-35475 Assertion `!rec_offs_nth_extern(offsets1, n)'
# failed in cmp_rec_rec_simple_field
#
CREATE TABLE t1(a BLOB, b VARCHAR(2048), PRIMARY KEY (b)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (REPEAT('x',4805),'a'), (REPEAT('x',16111),'b'),
(REPEAT('x',65535),'c'), (REPEAT('x',11312),'d'),
(REPEAT('x',35177),'e'), (REPEAT('x',65535),'f'),
(REPEAT('x',1988),'g'), (NULL,REPEAT('x',2048)),
(REPEAT('x',2503),'h'), (REPEAT('x',33152),'i'),
(REPEAT('x',65535),'j'), (REPEAT('x',1988),'k'),
(REPEAT('x',65535),'l'), (REPEAT('x',65535),'m'),
(REPEAT('x',65535),'n'), (REPEAT('x',65535),'o'),
(REPEAT('x',1988),'p'), (REPEAT('x',2503),'q'),
(REPEAT('x',65535),'r'), (REPEAT('x',65535),'s'),
(REPEAT('x',65535),'t'), (REPEAT('x',3169),'u'),
(REPEAT('x',7071),'v'), (REPEAT('x',16111),'w'),
(REPEAT('x',2325),'x'), (REPEAT('x',33152),'y'),
(REPEAT('x',65535),'z'), (REPEAT('x',65535),'aa'),
(REPEAT('x',16111),'bb'), (REPEAT('x',4805),'cc'),
(REPEAT('x',65535),'dd');
DROP TABLE t1;
# End of 10.11 tests

25
mysql-test/suite/innodb/t/alter_copy_bulk.test

@ -83,4 +83,29 @@ CREATE TABLE t engine=innodb
SELECT t2.f2 FROM t2 JOIN t1 ON t1.f1 = t2.f1 AND t1.f3 = '' AND t1.f2=1 ;
SELECT COUNT(*) FROM t;
DROP TABLE t1, t2, t;
--echo #
--echo # MDEV-35475 Assertion `!rec_offs_nth_extern(offsets1, n)'
--echo # failed in cmp_rec_rec_simple_field
--echo #
CREATE TABLE t1(a BLOB, b VARCHAR(2048), PRIMARY KEY (b)) ENGINE=InnoDB;
INSERT INTO t1 VALUES
(REPEAT('x',4805),'a'), (REPEAT('x',16111),'b'),
(REPEAT('x',65535),'c'), (REPEAT('x',11312),'d'),
(REPEAT('x',35177),'e'), (REPEAT('x',65535),'f'),
(REPEAT('x',1988),'g'), (NULL,REPEAT('x',2048)),
(REPEAT('x',2503),'h'), (REPEAT('x',33152),'i'),
(REPEAT('x',65535),'j'), (REPEAT('x',1988),'k'),
(REPEAT('x',65535),'l'), (REPEAT('x',65535),'m'),
(REPEAT('x',65535),'n'), (REPEAT('x',65535),'o'),
(REPEAT('x',1988),'p'), (REPEAT('x',2503),'q'),
(REPEAT('x',65535),'r'), (REPEAT('x',65535),'s'),
(REPEAT('x',65535),'t'), (REPEAT('x',3169),'u'),
(REPEAT('x',7071),'v'), (REPEAT('x',16111),'w'),
(REPEAT('x',2325),'x'), (REPEAT('x',33152),'y'),
(REPEAT('x',65535),'z'), (REPEAT('x',65535),'aa'),
(REPEAT('x',16111),'bb'), (REPEAT('x',4805),'cc'),
(REPEAT('x',65535),'dd');
ALTER TABLE t1 FORCE, ALGORITHM=COPY;
DROP TABLE t1;
SET GLOBAL innodb_stats_persistent=@default_stats_persistent;

1
mysql-test/suite/innodb/t/innodb-64k-crash.opt

@ -0,0 +1 @@
--innodb_sort_buffer_size=65536

62
mysql-test/suite/innodb/t/innodb-64k-crash.test

@ -2,6 +2,7 @@
--source include/have_innodb_64k.inc
# Embedded server does not support restarting
--source include/not_embedded.inc
--source innodb_default_row_format.inc
let $MYSQLD_DATADIR= `select @@datadir`;
@ -314,3 +315,64 @@ connection default;
check table t1,t2;
drop table t1,t2;
--echo #
--echo # MDEV-35475 Assertion `!rec_offs_nth_extern(offsets1, n)'
--echo # failed in cmp_rec_rec_simple_field
--echo #
let $row_format= `select @@global.innodb_default_row_format`;
if ($row_format != "redundant")
{
CREATE TABLE t1(f1 int not null, f2 text, f3 text, f4 text,
f5 text, f6 text, f7 text, f8 text,
f9 text, f10 text, f11 text, f12 text,
f13 text, f14 text, f15 text, f16 text,
f17 text, f18 text, f19 text, f20 text,
f21 text, f22 text, f23 text, f24 text,
f25 text, PRIMARY KEY(f1))ENGINE=InnoDB;
let $error_code = ER_TOO_BIG_ROWSIZE;
if ($row_format == "dynamic")
{
let $error_code = 0;
}
--error $error_code
SET STATEMENT unique_checks=0,foreign_key_checks=0 FOR
INSERT INTO t1 VALUES(1, REPEAT('a', 1024), REPEAT('b', 1024),
REPEAT('c', 1024), REPEAT('d', 1024),
REPEAT('e', 1024), REPEAT('f', 1024),
REPEAT('g', 4096), REPEAT('h', 1024),
REPEAT('i', 1024), REPEAT('j', 1024),
REPEAT('k', 1024), REPEAT('l', 1024),
REPEAT('m', 1024), REPEAT('n', 1024),
REPEAT('o', 1024), REPEAT('p', 1024),
REPEAT('q', 1024), REPEAT('r', 1024),
REPEAT('s', 1024), REPEAT('t', 1024),
REPEAT('u', 1024), REPEAT('v', 1024),
REPEAT('w', 1024), REPEAT('x', 1024)),
(2, REPEAT('a', 1024), REPEAT('b', 1024),
REPEAT('c', 1024), REPEAT('d', 1024),
REPEAT('e', 1024), REPEAT('f', 1024),
REPEAT('g', 4096), REPEAT('h', 1024),
REPEAT('i', 1024), REPEAT('j', 1024),
REPEAT('k', 1024), REPEAT('l', 1024),
REPEAT('m', 1024), REPEAT('n', 1024),
REPEAT('o', 1024), REPEAT('p', 1024),
REPEAT('q', 1024), REPEAT('r', 1024),
REPEAT('s', 1024), REPEAT('t', 1024),
REPEAT('u', 1024), REPEAT('v', 1024),
REPEAT('w', 1024), REPEAT('x', 1024)),
(3, REPEAT('a', 1024), REPEAT('b', 1024),
REPEAT('c', 1024), REPEAT('d', 1024),
REPEAT('e', 1024), REPEAT('f', 1024),
REPEAT('g', 4096), REPEAT('h', 1024),
REPEAT('i', 1024), REPEAT('j', 1024),
REPEAT('k', 1024), REPEAT('l', 1024),
REPEAT('m', 1024), REPEAT('n', 1024),
REPEAT('o', 1024), REPEAT('p', 1024),
REPEAT('q', 1024), REPEAT('r', 1024),
REPEAT('s', 1024), REPEAT('t', 1024),
REPEAT('u', 1024), REPEAT('v', 1024),
REPEAT('w', 1024), REPEAT('x', 1024));
DROP TABLE t1;
}

28
mysql-test/suite/innodb/t/insert_into_empty.test

@ -484,7 +484,7 @@ ALTER TABLE t1 FORCE;
let $page_size= `SELECT @@innodb_page_size`;
let $error_code = 0;
if ($page_size == 4096) {
if ($page_size <= 16384) {
let $error_code = ER_TOO_BIG_ROWSIZE;
}
@ -593,4 +593,30 @@ INSERT INTO t1 VALUES(2,0);
DELETE FROM t1;
commit;
DROP TABLE t1;
if ($page_size >= 16384) {
--echo #
--echo # MDEV-35475 Assertion `!rec_offs_nth_extern(offsets1, n)'
--echo # failed in cmp_rec_rec_simple_field
--echo #
CREATE TABLE t1(a BLOB, b VARCHAR(2048), PRIMARY KEY (b)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (REPEAT('x',4805),'a'), (REPEAT('x',16111),'b'),
(REPEAT('x',65535),'c'), (REPEAT('x',11312),'d'),
(REPEAT('x',35177),'e'), (REPEAT('x',65535),'f'),
(REPEAT('x',1988),'g'), (NULL,REPEAT('x',2048)),
(REPEAT('x',2503),'h'), (REPEAT('x',33152),'i'),
(REPEAT('x',65535),'j'), (REPEAT('x',1988),'k'),
(REPEAT('x',65535),'l'), (REPEAT('x',65535),'m'),
(REPEAT('x',65535),'n'), (REPEAT('x',65535),'o'),
(REPEAT('x',1988),'p'), (REPEAT('x',2503),'q'),
(REPEAT('x',65535),'r'), (REPEAT('x',65535),'s'),
(REPEAT('x',65535),'t'), (REPEAT('x',3169),'u'),
(REPEAT('x',7071),'v'), (REPEAT('x',16111),'w'),
(REPEAT('x',2325),'x'), (REPEAT('x',33152),'y'),
(REPEAT('x',65535),'z'), (REPEAT('x',65535),'aa'),
(REPEAT('x',16111),'bb'), (REPEAT('x',4805),'cc'),
(REPEAT('x',65535),'dd');
DROP TABLE t1;
}
--echo # End of 10.11 tests

157
storage/innobase/row/row0merge.cc

@ -1051,7 +1051,8 @@ length in the field data
@param heap heap to store the blob offset and length
@return DB_SUCCESS if successful */
static dberr_t row_merge_write_blob_to_tmp_file(
dfield_t *field, merge_file_t *blob_file,mem_heap_t **heap)
dfield_t *field, uint32_t local_len,
merge_file_t *blob_file, mem_heap_t **heap)
{
if (blob_file->fd == OS_FILE_CLOSED)
{
@ -1060,83 +1061,75 @@ static dberr_t row_merge_write_blob_to_tmp_file(
return DB_OUT_OF_MEMORY;
}
uint64_t val= blob_file->offset;
uint32_t len= field->len;
dberr_t err= os_file_write(
IORequestWrite, "(bulk insert)", blob_file->fd,
field->data, blob_file->offset, len);
(byte*)field->data + local_len, blob_file->offset,
field->len - local_len);
if (err != DB_SUCCESS)
return err;
byte *data= static_cast<byte*>
(mem_heap_alloc(*heap, BTR_EXTERN_FIELD_REF_SIZE));
byte *data=
static_cast<byte*>(mem_heap_alloc(*heap,
local_len + BTR_EXTERN_FIELD_REF_SIZE));
memcpy(data, field->data, local_len);
/* Write zeroes for first 8 bytes */
memset(data, 0, 8);
memset(data + local_len, 0, 8);
/* Write offset for next 8 bytes */
mach_write_to_8(data + 8, val);
mach_write_to_8(data + local_len + 8, val);
/* Write length of the blob in 4 bytes */
mach_write_to_4(data + 16, len);
blob_file->offset+= field->len;
mach_write_to_4(data + local_len + 16, field->len - local_len);
blob_file->offset+= (field->len - local_len);
blob_file->n_rec++;
dfield_set_data(field, data, BTR_EXTERN_FIELD_REF_SIZE);
dfield_set_data(field, data,
local_len + BTR_EXTERN_FIELD_REF_SIZE);
dfield_set_ext(field);
return err;
}
/** This function is invoked when tuple size is greater than
innodb_sort_buffer_size. Basically it recreates the tuple
by writing the blob field to the temporary file.
@param entry index fields to be encode the blob
@param blob_file file to store the blob data
@param heap heap to store the blob offset and blob length
@return tuple which fits into sort_buffer_size */
static dtuple_t* row_merge_buf_large_tuple(const dtuple_t &entry,
merge_file_t *blob_file,
mem_heap_t **heap)
{
if (!*heap)
*heap= mem_heap_create(DTUPLE_EST_ALLOC(entry.n_fields));
dtuple_t *tuple= dtuple_copy(&entry, *heap);
for (ulint i= 0; i < tuple->n_fields; i++)
{
dfield_t *field= &tuple->fields[i];
if (dfield_is_null(field) || field->len <= 2000)
continue;
dberr_t err= row_merge_write_blob_to_tmp_file(field, blob_file, heap);
if (err != DB_SUCCESS)
return nullptr;
}
return tuple;
}
/** Write the field data whose length is more than 2000 bytes
into blob temporary file and write offset, length into the
tuple field
@param entry index fields to be encode the blob
/** Variable length field data or fixed length
character greater than 255 can be stored externally. Instead
of storing it externally, InnoDB should store it in temporary
file and write offset, length into the tuple field
@param fields index fields to be encode the blob
@param n_fields number of fields in the entry
@param blob_file file to store the blob data
@param index index for the tuple to be stored
@param heap heap to store the blob offset and blob length
@param blob_file file to store the blob data */
static dberr_t row_merge_buf_blob(const mtuple_t *entry, ulint n_fields,
mem_heap_t **heap, merge_file_t *blob_file)
@return error code */
static
dberr_t row_merge_buf_blob(dfield_t *fields, ulint n_fields,
merge_file_t *blob_file,
const dict_index_t *index,
mem_heap_t **heap)
{
if (!*heap)
*heap= mem_heap_create(100);
const uint blob_prefix= dict_table_has_atomic_blobs(index->table)
? 0
: REC_ANTELOPE_MAX_INDEX_COL_LEN;
const uint min_local_len = blob_prefix
? blob_prefix + FIELD_REF_SIZE
: 2 * FIELD_REF_SIZE;
for (ulint i= 0; i < n_fields; i++)
{
dfield_t *field= &entry->fields[i];
if (dfield_is_null(field) || field->len <= 2000)
dfield_t *field= &fields[i];
if (i < index->n_uniq || dfield_is_null(field))
continue;
dberr_t err= row_merge_write_blob_to_tmp_file(field, blob_file, heap);
if (err != DB_SUCCESS)
return err;
if (field->len > min_local_len &&
index->fields[i].fixed_len == 0 &&
DATA_BIG_COL(index->fields[i].col))
{
variable_len:
dberr_t err=
row_merge_write_blob_to_tmp_file(field, blob_prefix,
blob_file, heap);
if (err)
return err;
}
else if (index->fields[i].fixed_len > 255)
goto variable_len;
}
return DB_SUCCESS;
@ -1166,8 +1159,13 @@ dberr_t row_merge_buf_write(const row_merge_buf_t *buf,
if (blob_file) {
ut_ad(buf->index->is_primary());
err = row_merge_buf_blob(
entry, n_fields, &blob_heap, blob_file);
if (!blob_heap) {
blob_heap = mem_heap_create(100);
}
err = row_merge_buf_blob(entry->fields, n_fields,
blob_file, buf->index,
&blob_heap);
if (err != DB_SUCCESS) {
goto func_exit;
}
@ -1175,9 +1173,17 @@ dberr_t row_merge_buf_write(const row_merge_buf_t *buf,
ulint rec_size= row_merge_buf_encode(
&b, index, entry, n_fields);
if (blob_file && rec_size > srv_page_size) {
err = DB_TOO_BIG_RECORD;
goto func_exit;
if (blob_file) {
ulint rec_max_size =
(srv_page_size = UNIV_PAGE_SIZE_MAX)
? REDUNDANT_REC_MAX_DATA_SIZE
: page_get_free_space_of_empty(
dict_table_is_comp(
index->table)) / 2;
if (rec_size > rec_max_size) {
err = DB_TOO_BIG_RECORD;
goto func_exit;
}
}
ut_ad(b < &block[srv_sort_buf_size]);
@ -3549,9 +3555,14 @@ in field data for the tuple
@param tuple tuple to be inserted
@param heap heap to allocate the memory for the blob storage
@param blob_file file to handle blob data */
static dberr_t row_merge_copy_blob_from_file(dtuple_t *tuple, mem_heap_t *heap,
static dberr_t row_merge_copy_blob_from_file(dtuple_t *tuple,
dict_index_t *index,
mem_heap_t *heap,
merge_file_t *blob_file)
{
const uint blob_prefix= dict_table_has_atomic_blobs(index->table)
? 0
: REC_ANTELOPE_MAX_INDEX_COL_LEN;
for (ulint i = 0; i < dtuple_get_n_fields(tuple); i++)
{
dfield_t *field= dtuple_get_nth_field(tuple, i);
@ -3563,15 +3574,18 @@ static dberr_t row_merge_copy_blob_from_file(dtuple_t *tuple, mem_heap_t *heap,
ut_a(field_len >= BTR_EXTERN_FIELD_REF_SIZE);
ut_ad(!dfield_is_null(field));
field_data += blob_prefix;
ut_ad(mach_read_from_8(field_data) == 0);
uint64_t offset= mach_read_from_8(field_data + 8);
uint32_t len= mach_read_from_4(field_data + 16);
byte *data= (byte*) mem_heap_alloc(heap, len);
if (dberr_t err= os_file_read(IORequestRead, blob_file->fd, data,
byte *data= (byte*) mem_heap_alloc(heap, blob_prefix + len);
memcpy(data, field->data, blob_prefix);
if (dberr_t err= os_file_read(IORequestRead, blob_file->fd,
data + blob_prefix,
offset, len, nullptr))
return err;
dfield_set_data(field, data, len);
dfield_set_data(field, data, blob_prefix + len);
}
return DB_SUCCESS;
@ -3793,7 +3807,7 @@ row_merge_insert_index_tuples(
if (!dtuple_get_n_ext(dtuple)) {
} else if (blob_file) {
error = row_merge_copy_blob_from_file(
dtuple, tuple_heap, blob_file);
dtuple, index, tuple_heap, blob_file);
if (error != DB_SUCCESS) {
break;
}
@ -5185,8 +5199,17 @@ add_to_buf:
if (buf->n_tuples == 0)
{
/* Tuple data size is greater than srv_sort_buf_size */
dtuple_t *big_tuple= row_merge_buf_large_tuple(
row, &m_blob_file, &large_tuple_heap);
dtuple_t *big_tuple;
if (!large_tuple_heap)
large_tuple_heap= mem_heap_create(DTUPLE_EST_ALLOC(row.n_fields));
big_tuple= dtuple_copy(&row, large_tuple_heap);
err= row_merge_buf_blob(big_tuple->fields, big_tuple->n_fields,
&m_blob_file, &ind, &large_tuple_heap);
if (err)
goto func_exit;
if (row_merge_bulk_buf_add(buf, *ind.table, *big_tuple))
{
i++;

Loading…
Cancel
Save