diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 353d66b1ad5..62220de0496 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -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 diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index cadab8b3b70..334ecfd02d3 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -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 diff --git a/storage/myisam/mi_dynrec.c b/storage/myisam/mi_dynrec.c index 9940cf62204..22fa3d18802 100644 --- a/storage/myisam/mi_dynrec.c +++ b/storage/myisam/mi_dynrec.c @@ -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; }