mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
Bug#33222 - myisam-table drops rows when column is added
and a char-field > 128 exists CHECK TABLE (non-QUICK) and any form of repair table did wrongly rate records as corrupted under the following conditions: 1. The table has dynamic row format and 2. it has a CHAR like column > 127 bytes (but not VARCHAR) (for multi-byte character sets this could be less than 127 characters) and 3. it has records with > 127 bytes significant length in that column (a byte beyond byte position 127 must be non-space). Affected were the statements CHECK TABLE, REPAIR TABLE, OPTIMIZE TABLE, ALTER TABLE. CHECK TABLE reported and marked the table as crashed if any record was present that fulfilled condition 3. The other statements deleted these records. The problem was a signed/unsigned compare in MyISAM code. A char to uchar change became necessary after the big byte to uchar change. mysql-test/r/myisam.result: Bug#33222 - myisam-table drops rows when column is added and a char-field > 128 exists Added test result. mysql-test/t/myisam.test: Bug#33222 - myisam-table drops rows when column is added and a char-field > 128 exists Added test. storage/myisam/mi_dynrec.c: Bug#33222 - myisam-table drops rows when column is added and a char-field > 128 exists char -> uchar became necessary after big byte -> uchar change. Fixed some small coding style violations near the changes.
This commit is contained in:
parent
c7ee0f3e2c
commit
c3bf70215b
3 changed files with 349 additions and 15 deletions
|
@ -2001,4 +2001,166 @@ CHECK TABLE t1;
|
|||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(130),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
1
|
||||
CHECK TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
REPAIR TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
1
|
||||
CHECK TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(130),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
1
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
REPAIR TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
1
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(130),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
|
||||
INSERT INTO t1 VALUES('b', 'b');
|
||||
INSERT INTO t1 VALUES('c', 'b');
|
||||
DELETE FROM t1 WHERE c1='b';
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
2
|
||||
OPTIMIZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 optimize status OK
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
2
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(130),
|
||||
c2 VARCHAR(1),
|
||||
KEY (c1)
|
||||
) ENGINE=MyISAM;
|
||||
# Insert 100 rows. Query log disabled.
|
||||
UPDATE t1 SET c1=REPEAT("a",128) LIMIT 90;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
100
|
||||
ALTER TABLE t1 ENGINE=MyISAM;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
100
|
||||
CHECK TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(50),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET UTF8;
|
||||
INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
1
|
||||
CHECK TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
REPAIR TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
1
|
||||
CHECK TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(50),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET UTF8;
|
||||
INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
1
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
REPAIR TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
1
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(50),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET UTF8;
|
||||
INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
|
||||
INSERT INTO t1 VALUES('b', 'b');
|
||||
INSERT INTO t1 VALUES('c', 'b');
|
||||
DELETE FROM t1 WHERE c1='b';
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
2
|
||||
OPTIMIZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 optimize status OK
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
2
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(50),
|
||||
c2 VARCHAR(1),
|
||||
KEY (c1)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET UTF8;
|
||||
# Insert 100 rows. Query log disabled.
|
||||
UPDATE t1 SET c1=REPEAT(_utf8 x'e0ae85',43) LIMIT 90;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
100
|
||||
ALTER TABLE t1 ENGINE=MyISAM;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
100
|
||||
CHECK TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
End of 5.1 tests
|
||||
|
|
|
@ -1261,5 +1261,175 @@ DELETE FROM t1 WHERE c1 >= 10;
|
|||
CHECK TABLE t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Bug#33222 - myisam-table drops rows when column is added
|
||||
# and a char-field > 128 exists
|
||||
#
|
||||
# Test #1 - CHECK TABLE sees wrong record, REPAR TABLE deletes it.
|
||||
# Using a CHAR column that can have > 127 characters.
|
||||
# Using a VARCHAR to create a table with dynamic row format.
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(130),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
|
||||
SELECT COUNT(*) FROM t1;
|
||||
CHECK TABLE t1;
|
||||
REPAIR TABLE t1;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
CHECK TABLE t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Test #2 - same as test #1, but using EXTENDED.
|
||||
# Using a CHAR column that can have > 127 characters.
|
||||
# Using a VARCHAR to create a table with dynamic row format.
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(130),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
|
||||
SELECT COUNT(*) FROM t1;
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
REPAIR TABLE t1 EXTENDED;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Test #3 - same as test #1, but using OPTIMIZE TABLE.
|
||||
# Using a CHAR column that can have > 127 characters.
|
||||
# Using a VARCHAR to create a table with dynamic row format.
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(130),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
|
||||
# Insert more rows and delete one in the middle to force optimize.
|
||||
INSERT INTO t1 VALUES('b', 'b');
|
||||
INSERT INTO t1 VALUES('c', 'b');
|
||||
DELETE FROM t1 WHERE c1='b';
|
||||
SELECT COUNT(*) FROM t1;
|
||||
OPTIMIZE TABLE t1;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Test #4 - ALTER TABLE deletes rows.
|
||||
# Using a CHAR column that can have > 127 characters.
|
||||
# Using a VARCHAR to create a table with dynamic row format.
|
||||
# Using an index which can be disabled during bulk insert.
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(130),
|
||||
c2 VARCHAR(1),
|
||||
KEY (c1)
|
||||
) ENGINE=MyISAM;
|
||||
#
|
||||
# Insert 100 rows. This turns bulk insert on during the copy phase of
|
||||
# ALTER TABLE. Bulk insert disables keys before the insert and re-enables
|
||||
# them by repair after the insert.
|
||||
--disable_query_log
|
||||
let $count= 100;
|
||||
--echo # Insert $count rows. Query log disabled.
|
||||
while ($count)
|
||||
{
|
||||
INSERT INTO t1 VALUES ('a', 'b');
|
||||
dec $count;
|
||||
}
|
||||
--enable_query_log
|
||||
#
|
||||
# Change most of the rows into long character values with > 127 characters.
|
||||
UPDATE t1 SET c1=REPEAT("a",128) LIMIT 90;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
ALTER TABLE t1 ENGINE=MyISAM;
|
||||
#
|
||||
# With bug present, this shows that all long rows are gone.
|
||||
SELECT COUNT(*) FROM t1;
|
||||
CHECK TABLE t1;
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Test #5 - same as test #1 but UTF-8.
|
||||
# Using a CHAR column that can have > 127 characters.
|
||||
# Using a VARCHAR to create a table with dynamic row format.
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(50),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET UTF8;
|
||||
# Using Tamil Letter A, Unicode U+0B85
|
||||
INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
|
||||
SELECT COUNT(*) FROM t1;
|
||||
CHECK TABLE t1;
|
||||
REPAIR TABLE t1;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
CHECK TABLE t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Test #6 - same as test #2, but UTF-8.
|
||||
# Using a CHAR column that can have > 127 characters.
|
||||
# Using a VARCHAR to create a table with dynamic row format.
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(50),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET UTF8;
|
||||
# Using Tamil Letter A, Unicode U+0B85
|
||||
INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
|
||||
SELECT COUNT(*) FROM t1;
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
REPAIR TABLE t1 EXTENDED;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Test #7 - same as test #3, but UTF-8.
|
||||
# Using a CHAR column that can have > 127 characters.
|
||||
# Using a VARCHAR to create a table with dynamic row format.
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(50),
|
||||
c2 VARCHAR(1)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET UTF8;
|
||||
# Using Tamil Letter A, Unicode U+0B85
|
||||
INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
|
||||
# Insert more rows and delete one in the middle to force optimize.
|
||||
INSERT INTO t1 VALUES('b', 'b');
|
||||
INSERT INTO t1 VALUES('c', 'b');
|
||||
DELETE FROM t1 WHERE c1='b';
|
||||
SELECT COUNT(*) FROM t1;
|
||||
OPTIMIZE TABLE t1;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Test #8 - same as test #4, but UTF-8.
|
||||
# Using a CHAR column that can have > 42 UTF-8 characters.
|
||||
# Using a VARCHAR to create a table with dynamic row format.
|
||||
# Using an index which can be disabled during bulk insert.
|
||||
CREATE TABLE t1 (
|
||||
c1 CHAR(50),
|
||||
c2 VARCHAR(1),
|
||||
KEY (c1)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET UTF8;
|
||||
#
|
||||
# Insert 100 rows. This turns bulk insert on during the copy phase of
|
||||
# ALTER TABLE. Bulk insert disables keys before the insert and re-enables
|
||||
# them by repair after the insert.
|
||||
--disable_query_log
|
||||
let $count= 100;
|
||||
--echo # Insert $count rows. Query log disabled.
|
||||
while ($count)
|
||||
{
|
||||
INSERT INTO t1 VALUES ('a', 'b');
|
||||
dec $count;
|
||||
}
|
||||
--enable_query_log
|
||||
#
|
||||
# Change most of the rows into long character values with > 42 characters.
|
||||
# Using Tamil Letter A, Unicode U+0B85
|
||||
UPDATE t1 SET c1=REPEAT(_utf8 x'e0ae85',43) LIMIT 90;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
ALTER TABLE t1 ENGINE=MyISAM;
|
||||
#
|
||||
# With bug present, this shows that all long rows are gone.
|
||||
SELECT COUNT(*) FROM t1;
|
||||
CHECK TABLE t1;
|
||||
CHECK TABLE t1 EXTENDED;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
||||
|
|
|
@ -1006,12 +1006,12 @@ uint _mi_rec_pack(MI_INFO *info, register uchar *to,
|
|||
{
|
||||
if (rec->length > 255 && new_length > 127)
|
||||
{
|
||||
to[0]=(char) ((new_length & 127)+128);
|
||||
to[1]=(char) (new_length >> 7);
|
||||
to+=2;
|
||||
}
|
||||
else
|
||||
*to++= (char) new_length;
|
||||
to[0]= (uchar) ((new_length & 127) + 128);
|
||||
to[1]= (uchar) (new_length >> 7);
|
||||
to+=2;
|
||||
}
|
||||
else
|
||||
*to++= (uchar) new_length;
|
||||
memcpy((uchar*) to,pos,(size_t) new_length); to+=new_length;
|
||||
flag|=bit;
|
||||
}
|
||||
|
@ -1045,7 +1045,7 @@ uint _mi_rec_pack(MI_INFO *info, register uchar *to,
|
|||
}
|
||||
if ((bit= bit << 1) >= 256)
|
||||
{
|
||||
*packpos++ = (char) (uchar) flag;
|
||||
*packpos++= (uchar) flag;
|
||||
bit=1; flag=0;
|
||||
}
|
||||
}
|
||||
|
@ -1055,9 +1055,9 @@ uint _mi_rec_pack(MI_INFO *info, register uchar *to,
|
|||
}
|
||||
}
|
||||
if (bit != 1)
|
||||
*packpos= (char) (uchar) flag;
|
||||
*packpos= (uchar) flag;
|
||||
if (info->s->calc_checksum)
|
||||
*to++=(char) info->checksum;
|
||||
*to++= (uchar) info->checksum;
|
||||
DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
|
||||
DBUG_RETURN((uint) (to-startpos));
|
||||
} /* _mi_rec_pack */
|
||||
|
@ -1128,12 +1128,14 @@ my_bool _mi_rec_check(MI_INFO *info,const uchar *record, uchar *rec_buff,
|
|||
goto err;
|
||||
if (rec->length > 255 && new_length > 127)
|
||||
{
|
||||
if (to[0] != (char) ((new_length & 127)+128) ||
|
||||
to[1] != (char) (new_length >> 7))
|
||||
goto err;
|
||||
to+=2;
|
||||
}
|
||||
else if (*to++ != (char) new_length)
|
||||
/* purecov: begin inspected */
|
||||
if (to[0] != (uchar) ((new_length & 127) + 128) ||
|
||||
to[1] != (uchar) (new_length >> 7))
|
||||
goto err;
|
||||
to+=2;
|
||||
/* purecov: end */
|
||||
}
|
||||
else if (*to++ != (uchar) new_length)
|
||||
goto err;
|
||||
to+=new_length;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue