From e93574e9d16efc747a88875325469e2b029e5eb8 Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/hfmain.(none)" <> Date: Tue, 30 Oct 2007 12:35:03 +0400 Subject: [PATCH 1/3] Bug #31758 inet_ntoa, oct crashes server with null+filesort Item_func_inet_ntoa and Item_func_conv inherit 'maybe_null' flag from an argument, which is wrong. Both can be NULL with notnull arguments, so that's fixed. --- mysql-test/r/func_str.result | 18 +++++++++++++++--- mysql-test/t/func_str.test | 13 +++++++++++++ sql/item_strfunc.h | 3 ++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index af6a4d20cff..3a429765c98 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -711,9 +711,9 @@ Warning 1265 Data truncated for column 'format(130,10)' at row 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `bin(130)` char(64) NOT NULL default '', - `oct(130)` char(64) NOT NULL default '', - `conv(130,16,10)` char(64) NOT NULL default '', + `bin(130)` char(64) default NULL, + `oct(130)` char(64) default NULL, + `conv(130,16,10)` char(64) default NULL, `hex(130)` char(6) NOT NULL default '', `char(130)` char(1) NOT NULL default '', `format(130,10)` char(4) NOT NULL default '', @@ -1075,5 +1075,17 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found Warnings: Note 1003 select decode(test.t1.f1,'zxcv') AS `enc` from test.t1 +drop table t1; +create table t1 (a bigint not null)engine=myisam; +insert into t1 set a = 1024*1024*1024*4; +delete from t1 order by (inet_ntoa(a)) desc limit 10; +drop table t1; +create table t1 (a char(36) not null)engine=myisam; +insert ignore into t1 set a = ' '; +insert ignore into t1 set a = ' '; +select * from t1 order by (oct(a)); +a + + drop table t1; End of 4.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 5897674d1d4..f2991cc3b1d 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -721,4 +721,17 @@ explain extended select encode(f1,'zxcv') as 'enc' from t1; explain extended select decode(f1,'zxcv') as 'enc' from t1; drop table t1; +# +# Bug #31758 inet_ntoa, oct, crashes server with null + filesort +# +create table t1 (a bigint not null)engine=myisam; +insert into t1 set a = 1024*1024*1024*4; +delete from t1 order by (inet_ntoa(a)) desc limit 10; +drop table t1; +create table t1 (a char(36) not null)engine=myisam; +insert ignore into t1 set a = ' '; +insert ignore into t1 set a = ' '; +select * from t1 order by (oct(a)); +drop table t1; + --echo End of 4.1 tests diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 4bd8574ff04..b438ac81763 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -531,6 +531,7 @@ public: { collation.set(default_charset()); decimals=0; max_length=64; + maybe_null= 1; } }; @@ -623,7 +624,7 @@ public: } String* val_str(String* str); const char *func_name() const { return "inet_ntoa"; } - void fix_length_and_dec() { decimals = 0; max_length=3*8+7; } + void fix_length_and_dec() { decimals = 0; max_length=3*8+7; maybe_null=1;} }; class Item_func_quote :public Item_str_func From f1a3c36403fb0a566a6d9da1c6b9fb74e4c8681a Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Wed, 7 Nov 2007 18:45:04 +0300 Subject: [PATCH 2/3] Fix for bug #32103: optimizer crash when join on int and mediumint with variable in where clause. Problem: the new_item() method of Item_uint used an incorrect constructor. "new Item_uint(name, max_length)" calls Item_uint::Item_uint(const char *str_arg, uint length) which assumes the first argument to be the string representation of the value, not the item's name. This could result in either a server crash or incorrect results depending on usage scenarios. Fixed by using the correct constructor in new_item(): Item_uint::Item_uint(const char *str_arg, longlong i, uint length). --- mysql-test/r/select.result | 8 ++++++++ mysql-test/t/select.test | 21 +++++++++++++++++++++ sql/item.h | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 6dc971a953c..53ab13fe084 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2835,4 +2835,12 @@ FFFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF 8FFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF drop table t1; +CREATE TABLE t1 (c0 int); +CREATE TABLE t2 (c0 int); +INSERT INTO t1 VALUES(@@connect_timeout); +INSERT INTO t2 VALUES(@@connect_timeout); +SELECT * FROM t1 JOIN t2 ON t1.c0 = t2.c0 WHERE (t1.c0 <=> @@connect_timeout); +c0 c0 +X X +DROP TABLE t1, t2; End of 4.1 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 0dc179e9b4b..b41deed65d2 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2353,4 +2353,25 @@ insert into t1 values (0xfffffffffffffffff, 0xfffffffffffffffff), select hex(a), hex(b) from t1; drop table t1; +# +# Bug #32103: optimizer crash when join on int and mediumint with variable in +# where clause +# + +CREATE TABLE t1 (c0 int); +CREATE TABLE t2 (c0 int); + +# We need any variable that: +# 1. has integer type, +# 2. can be used with the "@@name" syntax +# 3. available in every server build +INSERT INTO t1 VALUES(@@connect_timeout); +INSERT INTO t2 VALUES(@@connect_timeout); + +# We only need to ensure 1 row is returned to validate the results +--replace_column 1 X 2 X +SELECT * FROM t1 JOIN t2 ON t1.c0 = t2.c0 WHERE (t1.c0 <=> @@connect_timeout); + +DROP TABLE t1, t2; + --echo End of 4.1 tests diff --git a/sql/item.h b/sql/item.h index f2136c4997a..7a073b7165c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -690,7 +690,7 @@ public: double val() { DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); } String *val_str(String*); - Item *new_item() { return new Item_uint(name,max_length); } + Item *new_item() { return new Item_uint(name, value, max_length); } int save_in_field(Field *field, bool no_conversions); void print(String *str); Item_num *neg (); From 91e2f91897af45189a1611a47ac248a331b8db5f Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/hfmain.(none)" <> Date: Mon, 12 Nov 2007 13:00:22 +0400 Subject: [PATCH 3/3] Bug #31305 myisam tables crash when they are near capacity. When we insert a record into MYISAM table which is almost 'full', we first write record data in the free space inside a file, and then check if we have enough space after the end of the file. So if we don't have the space, table will left corrupted. Similar error also happens when we updata MYISAM tables. Fixed by modifying write_dynamic_record and update_dynamic_record functions to check for free space before writing parts of a record --- .bzrignore | 2 + myisam/mi_dynrec.c | 68 +++++++++++++++++++++++++++++++++ mysql-test/r/almost_full.result | 29 ++++++++++++++ mysql-test/t/almost_full.test | 41 ++++++++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 mysql-test/r/almost_full.result create mode 100644 mysql-test/t/almost_full.test diff --git a/.bzrignore b/.bzrignore index 0c666cc3ae0..27ad9519e18 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1068,3 +1068,5 @@ include/check_abi include/mysql_h.ic mysql-test/r/blackhole.log mysql-test/lib/init_db.sql +libmysql_r/client_settings.h +libmysqld/ha_blackhole.cc diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index 260f461685e..ad76296a66e 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -145,6 +145,29 @@ static int write_dynamic_record(MI_INFO *info, const byte *record, DBUG_ENTER("write_dynamic_record"); flag=0; + + /* + Check if we have enough room for the new record. + First we do simplified check to make usual case faster. + Then we do more precise check for the space left. + Though it still is not absolutely precise, as + we always use MI_MAX_DYN_BLOCK_HEADER while it can be + less in the most of the cases. + */ + + if (unlikely(info->s->base.max_data_file_length - + info->state->data_file_length < + reclength + MI_MAX_DYN_BLOCK_HEADER)) + { + if (info->s->base.max_data_file_length - info->state->data_file_length + + info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER < + reclength + MI_MAX_DYN_BLOCK_HEADER) + { + my_errno=HA_ERR_RECORD_FILE_FULL; + DBUG_RETURN(1); + } + } + do { if (_mi_find_writepos(info,reclength,&filepos,&length)) @@ -577,6 +600,51 @@ static int update_dynamic_record(MI_INFO *info, my_off_t filepos, byte *record, DBUG_ENTER("update_dynamic_record"); flag=block_info.second_read=0; + /* + Check if we have enough room for the record. + First we do simplified check to make usual case faster. + Then we do more precise check for the space left. + Though it still is not absolutely precise, as + we always use MI_MAX_DYN_BLOCK_HEADER while it can be + less in the most of the cases. + */ + + /* + compare with just the reclength as we're going + to get some space from the old replaced record + */ + if (unlikely(info->s->base.max_data_file_length - + info->state->data_file_length < reclength)) + { + /* + let's read the old record's block to find out the length of the + old record + */ + if ((error=_mi_get_block_info(&block_info,info->dfile,filepos)) + & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR)) + { + DBUG_PRINT("error",("Got wrong block info")); + if (!(error & BLOCK_FATAL_ERROR)) + my_errno=HA_ERR_WRONG_IN_RECORD; + goto err; + } + + /* + if new record isn't longer, we can go on safely + */ + if (block_info.rec_len < reclength) + { + if (info->s->base.max_data_file_length - info->state->data_file_length + + info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER < + reclength - block_info.rec_len + MI_MAX_DYN_BLOCK_HEADER) + { + my_errno=HA_ERR_RECORD_FILE_FULL; + goto err; + } + } + block_info.second_read=0; + } + while (reclength > 0) { if (filepos != info->s->state.dellink) diff --git a/mysql-test/r/almost_full.result b/mysql-test/r/almost_full.result new file mode 100644 index 00000000000..eb28f12fa51 --- /dev/null +++ b/mysql-test/r/almost_full.result @@ -0,0 +1,29 @@ +drop table if exists t1; +set global myisam_data_pointer_size=2; +CREATE TABLE t1 (a int auto_increment primary key not null, b longtext) ENGINE=MyISAM; +DELETE FROM t1 WHERE a=1 or a=5; +INSERT INTO t1 SET b=repeat('a',600); +ERROR HY000: The table 't1' is full +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check warning Datafile is almost full, 65448 of 65534 used +test.t1 check status OK +UPDATE t1 SET b=repeat('a', 800) where a=10; +ERROR HY000: The table 't1' is full +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check warning Datafile is almost full, 65448 of 65534 used +test.t1 check status OK +INSERT INTO t1 SET b=repeat('a',400); +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check warning Datafile is almost full, 65448 of 65534 used +test.t1 check status OK +DELETE FROM t1 WHERE a=2 or a=6; +UPDATE t1 SET b=repeat('a', 600) where a=11; +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check warning Datafile is almost full, 65448 of 65534 used +test.t1 check status OK +drop table t1; +set global myisam_data_pointer_size=default; diff --git a/mysql-test/t/almost_full.test b/mysql-test/t/almost_full.test new file mode 100644 index 00000000000..5c67ab3c088 --- /dev/null +++ b/mysql-test/t/almost_full.test @@ -0,0 +1,41 @@ +# +# Some special cases with empty tables +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +set global myisam_data_pointer_size=2; +CREATE TABLE t1 (a int auto_increment primary key not null, b longtext) ENGINE=MyISAM; + +--disable_query_log +let $1= 303; +while ($1) +{ + INSERT INTO t1 SET b=repeat('a',200); + dec $1; +} +--enable_query_log + +DELETE FROM t1 WHERE a=1 or a=5; + +--error 1114 +INSERT INTO t1 SET b=repeat('a',600); +CHECK TABLE t1 EXTENDED; + +--error 1114 +UPDATE t1 SET b=repeat('a', 800) where a=10; +CHECK TABLE t1 EXTENDED; + +INSERT INTO t1 SET b=repeat('a',400); +CHECK TABLE t1 EXTENDED; + +DELETE FROM t1 WHERE a=2 or a=6; +UPDATE t1 SET b=repeat('a', 600) where a=11; +CHECK TABLE t1 EXTENDED; +drop table t1; + +set global myisam_data_pointer_size=default; + +# End of 4.1 tests