From e1d54fc7a852d5a985f7c6b2eb51a8872682e760 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 12 Aug 2010 15:59:02 +0500 Subject: [PATCH 01/17] Bug#55146 Assertion `m_part_spec.start_part == m_part_spec.end_part' in index_read_idx_map As we check for the impossible partitions earlier, it's possible that we don't find any suitable partitions at all. So this assertion just has to be corrected for this case. per-file comments: mysql-test/r/partition_innodb.result Bug#55146 Assertion `m_part_spec.start_part == m_part_spec.end_part' in index_read_idx_map test result updated. mysql-test/t/partition_innodb.test Bug#55146 Assertion `m_part_spec.start_part == m_part_spec.end_part' in index_read_idx_map test case added. sql/ha_partition.cc Bug#55146 Assertion `m_part_spec.start_part == m_part_spec.end_part' in index_read_idx_map Assertion changed to '>=' as the prune_partition_set() in the get_partition_set() can do start_part= end_part+1 if no possible partitions were found. --- mysql-test/r/partition_innodb.result | 6 ++++++ mysql-test/t/partition_innodb.test | 13 +++++++++++++ sql/ha_partition.cc | 8 ++++++-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result index 2a04aafe554..98104310227 100644 --- a/mysql-test/r/partition_innodb.result +++ b/mysql-test/r/partition_innodb.result @@ -387,3 +387,9 @@ a b 3 2003-03-03 COMMIT; DROP TABLE t1; +CREATE TABLE t1 (i1 int NOT NULL primary key, f1 int) ENGINE = InnoDB +PARTITION BY HASH(i1) PARTITIONS 2; +INSERT INTO t1 VALUES (1,1), (2,2); +SELECT * FROM t1 WHERE i1 = ( SELECT i1 FROM t1 WHERE f1=0 LIMIT 1 ); +i1 f1 +DROP TABLE t1; diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test index e1ac7b4c7eb..cef3540f9a7 100644 --- a/mysql-test/t/partition_innodb.test +++ b/mysql-test/t/partition_innodb.test @@ -401,3 +401,16 @@ connection default; SELECT * FROM t1; COMMIT; DROP TABLE t1; + +# +# Bug #55146 Assertion `m_part_spec.start_part == m_part_spec.end_part' in index_read_idx_map +# + +CREATE TABLE t1 (i1 int NOT NULL primary key, f1 int) ENGINE = InnoDB + PARTITION BY HASH(i1) PARTITIONS 2; + +INSERT INTO t1 VALUES (1,1), (2,2); + +SELECT * FROM t1 WHERE i1 = ( SELECT i1 FROM t1 WHERE f1=0 LIMIT 1 ); + +DROP TABLE t1; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index a87c7fbf7b8..dea889663d1 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4242,8 +4242,12 @@ int ha_partition::index_read_idx_map(uchar *buf, uint index, get_partition_set(table, buf, index, &m_start_key, &m_part_spec); - /* How can it be more than one partition with the current use? */ - DBUG_ASSERT(m_part_spec.start_part == m_part_spec.end_part); + /* + We have either found exactly 1 partition + (in which case start_part == end_part) + or no matching partitions (start_part > end_part) + */ + DBUG_ASSERT(m_part_spec.start_part >= m_part_spec.end_part); for (part= m_part_spec.start_part; part <= m_part_spec.end_part; part++) { From 1387f38969e95f6f88b148e8cdec695bda5a5456 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Thu, 16 Sep 2010 11:01:06 +0200 Subject: [PATCH 02/17] Bug#56287: mysql5.1.50 crash when using Partition datetime in sub in query When having a sub query in partitioned innodb one could make the partitioning engine to search for a 'index_next_same' on a partition that had not been initialized. Problem was that the subselect function looks at table->status which was not set in the partitioning handler when it skipped scanning due to no matching partitions found. Fixed by setting table->status = STATUS_NOT_FOUND when there was no partitions to scan. (If there are partitions to scan, it will be set in the partitions handler.) --- mysql-test/r/partition_innodb.result | 26 ++++++++++++++++++++++++++ mysql-test/t/partition_innodb.test | 24 ++++++++++++++++++++++++ sql/ha_partition.cc | 2 ++ 3 files changed, 52 insertions(+) diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result index 2a04aafe554..950eb5de3d8 100644 --- a/mysql-test/r/partition_innodb.result +++ b/mysql-test/r/partition_innodb.result @@ -1,5 +1,31 @@ drop table if exists t1, t2; # +# Bug#56287: crash when using Partition datetime in sub in query +# +CREATE TABLE t1 +(c1 bigint(20) unsigned NOT NULL AUTO_INCREMENT, +c2 varchar(40) not null default '', +c3 datetime not NULL, +PRIMARY KEY (c1,c3), +KEY partidx(c3)) +ENGINE=InnoDB +PARTITION BY RANGE (TO_DAYS(c3)) +(PARTITION p200912 VALUES LESS THAN (to_days('2010-01-01')), +PARTITION p201103 VALUES LESS THAN (to_days('2011-04-01')), +PARTITION p201912 VALUES LESS THAN MAXVALUE); +insert into t1(c2,c3) values ("Test row",'2010-01-01 00:00:00'); +SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'test'; +PARTITION_NAME TABLE_ROWS +p200912 0 +p201103 1 +p201912 0 +SELECT count(*) FROM t1 p where c3 in +(select c3 from t1 t where t.c3 < date '2011-04-26 19:19:44' + and t.c3 > date '2011-04-26 19:18:44') ; +count(*) +0 +DROP TABLE t1; +# # Bug#51830: Incorrect partition pruning on range partition (regression) # CREATE TABLE t1 (a INT NOT NULL) diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test index e1ac7b4c7eb..ca668d77199 100644 --- a/mysql-test/t/partition_innodb.test +++ b/mysql-test/t/partition_innodb.test @@ -7,6 +7,30 @@ drop table if exists t1, t2; let $MYSQLD_DATADIR= `SELECT @@datadir`; +--echo # +--echo # Bug#56287: crash when using Partition datetime in sub in query +--echo # +CREATE TABLE t1 +(c1 bigint(20) unsigned NOT NULL AUTO_INCREMENT, + c2 varchar(40) not null default '', + c3 datetime not NULL, + PRIMARY KEY (c1,c3), + KEY partidx(c3)) +ENGINE=InnoDB +PARTITION BY RANGE (TO_DAYS(c3)) +(PARTITION p200912 VALUES LESS THAN (to_days('2010-01-01')), + PARTITION p201103 VALUES LESS THAN (to_days('2011-04-01')), + PARTITION p201912 VALUES LESS THAN MAXVALUE); + +insert into t1(c2,c3) values ("Test row",'2010-01-01 00:00:00'); + +SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'test'; +SELECT count(*) FROM t1 p where c3 in +(select c3 from t1 t where t.c3 < date '2011-04-26 19:19:44' + and t.c3 > date '2011-04-26 19:18:44') ; + +DROP TABLE t1; + --echo # --echo # Bug#51830: Incorrect partition pruning on range partition (regression) --echo # diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 624ef1aff5b..d3846db42c2 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4483,6 +4483,7 @@ int ha_partition::partition_scan_set_up(uchar * buf, bool idx_read_flag) key not found. */ DBUG_PRINT("info", ("scan with no partition to scan")); + table->status= STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); } if (m_part_spec.start_part == m_part_spec.end_part) @@ -4507,6 +4508,7 @@ int ha_partition::partition_scan_set_up(uchar * buf, bool idx_read_flag) if (start_part == MY_BIT_NONE) { DBUG_PRINT("info", ("scan with no partition to scan")); + table->status= STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); } if (start_part > m_part_spec.start_part) From 085df749eab77609b5bfb6966ac97d33468d3dc9 Mon Sep 17 00:00:00 2001 From: "karen.langford@oracle.com" <> Date: Thu, 7 Oct 2010 15:25:14 +0200 Subject: [PATCH 03/17] Raise version number after cloning 5.1.52 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index c1672557bd1..7680a60226a 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.52], [], [mysql]) +AC_INIT([MySQL Server], [5.1.53], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From ff956907518366c0a0cff4aea34cccde94b5920f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 11 Oct 2010 11:01:47 +0300 Subject: [PATCH 04/17] Bug #56947 InnoDB leaks memory when failing to create a table No mysql-test case. Tested by creating a table, removing a *.frm file and attempting to create the table again. Code coverage tested by instrumentation. Tested with Valgrind. --- storage/innobase/row/row0mysql.c | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index c5a3a2da9e2..645260bce0f 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1981,6 +1981,7 @@ row_create_table_for_mysql( table already exists */ trx->error_state = DB_SUCCESS; + dict_mem_table_free(table); } que_graph_free((que_t*) que_node_get_parent(thr)); From 8b36ca25b1716c0a4e8c7217b4aa862a19b75d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 11 Oct 2010 11:18:00 +0300 Subject: [PATCH 05/17] Bug #56947 InnoDB leaks memory when failing to create a table row_create_table_for_mysql(): When the table creation fails, free the dict_table_t object. --- .../suite/innodb_plugin/r/innodb_bug56947.result | 6 ++++++ .../suite/innodb_plugin/t/innodb_bug56947.test | 11 +++++++++++ storage/innodb_plugin/ChangeLog | 13 ++++++++++--- storage/innodb_plugin/row/row0mysql.c | 14 ++++++++------ 4 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 mysql-test/suite/innodb_plugin/r/innodb_bug56947.result create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_bug56947.test diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug56947.result b/mysql-test/suite/innodb_plugin/r/innodb_bug56947.result new file mode 100644 index 00000000000..42101a46a5b --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug56947.result @@ -0,0 +1,6 @@ +create table bug56947(a int not null) engine = innodb; +CREATE TABLE `bug56947#1`(a int) ENGINE=InnoDB; +alter table bug56947 add unique index (a); +ERROR HY000: Table 'test.bug56947#1' already exists +drop table `bug56947#1`; +drop table bug56947; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug56947.test b/mysql-test/suite/innodb_plugin/t/innodb_bug56947.test new file mode 100644 index 00000000000..88544387567 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug56947.test @@ -0,0 +1,11 @@ +# +# Bug #56947 valgrind reports a memory leak in innodb-plugin.innodb-index +# +-- source include/have_innodb_plugin.inc + +create table bug56947(a int not null) engine = innodb; +CREATE TABLE `bug56947#1`(a int) ENGINE=InnoDB; +--error 156 +alter table bug56947 add unique index (a); +drop table `bug56947#1`; +drop table bug56947; diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 342e3e32bc1..ca7900549c2 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,13 +1,21 @@ +2010-10-11 The InnoDB Team + + * row/row0mysql.c, innodb_bug56947.result, innodb_bug56947.test: + Fix Bug #56947 InnoDB leaks memory when failing to create a table + 2010-10-06 The InnoDB Team + * row/row0mysql.c, innodb_bug57255.result, innodb_bug57255.test - Fix Bug #Cascade Delete results in "Got error -1 from storage engine" - + Fix Bug #57255 Cascade Delete results in "Got error -1 from + storage engine" + 2010-09-27 The InnoDB Team * row/row0sel.c, innodb_bug56716.result, innodb_bug56716.test: Fix Bug #56716 InnoDB locks a record gap without locking the table 2010-09-06 The InnoDB Team + * dict/dict0load.c, innodb_bug53756.test innodb_bug53756.result Fix Bug #53756 ALTER TABLE ADD PRIMARY KEY affects crash recovery @@ -40,7 +48,6 @@ * handler/ha_innodb.cc Fix Bug #55382 Assignment with SELECT expressions takes unexpected S locks in READ COMMITTED ->>>>>>> MERGE-SOURCE 2010-07-27 The InnoDB Team diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index 9cabea507fb..f27afc253ff 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -1879,15 +1879,13 @@ err_exit: err = trx->error_state; - if (UNIV_UNLIKELY(err != DB_SUCCESS)) { + switch (err) { + case DB_SUCCESS: + break; + case DB_OUT_OF_FILE_SPACE: trx->error_state = DB_SUCCESS; trx_general_rollback_for_mysql(trx, NULL); - /* TO DO: free table? The code below will dereference - table->name, though. */ - } - switch (err) { - case DB_OUT_OF_FILE_SPACE: ut_print_timestamp(stderr); fputs(" InnoDB: Warning: cannot create table ", stderr); @@ -1902,9 +1900,13 @@ err_exit: break; case DB_DUPLICATE_KEY: + default: /* We may also get err == DB_ERROR if the .ibd file for the table already exists */ + trx->error_state = DB_SUCCESS; + trx_general_rollback_for_mysql(trx, NULL); + dict_mem_table_free(table); break; } From 5a2a6c2c0dacd3509cacf89cae22c9657f19a7c7 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Tue, 12 Oct 2010 23:25:40 +0400 Subject: [PATCH 06/17] Fix for bug#57272: crash in rpad() when using utf8 Problem: if multibyte and binary string arguments passed to RPAD(), LPAD() or INSERT() functions, they might return wrong results or even lead to a server crash due to missed character set convertion. Fix: perform the convertion if necessary. --- mysql-test/r/ctype_utf8.result | 31 +++++++++++++++++++++++++ mysql-test/t/ctype_utf8.test | 20 ++++++++++++++++ sql/item_strfunc.cc | 42 ++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 4c21e66a39c..b491ce504bf 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -1898,3 +1898,34 @@ CONVERT(a, CHAR) CONVERT(b, CHAR) 70000 1092 DROP TABLE t1; End of 5.0 tests +SELECT LENGTH(RPAD(0.0115E88, 61297, _utf8'яэюя')); +LENGTH(RPAD(0.0115E88, 61297, _utf8'яэюя')) +61297 +SELECT LENGTH(RPAD(0.0115E88, 61297, _utf8'йцуя')); +LENGTH(RPAD(0.0115E88, 61297, _utf8'йцуя')) +61297 +SELECT HEX(RPAD(0x20, 2, _utf8 0xD18F)); +HEX(RPAD(0x20, 2, _utf8 0xD18F)) +20D1 +SELECT HEX(RPAD(0x20, 4, _utf8 0xD18F)); +HEX(RPAD(0x20, 4, _utf8 0xD18F)) +20D18FD1 +SELECT HEX(LPAD(0x20, 2, _utf8 0xD18F)); +HEX(LPAD(0x20, 2, _utf8 0xD18F)) +D120 +SELECT HEX(LPAD(0x20, 4, _utf8 0xD18F)); +HEX(LPAD(0x20, 4, _utf8 0xD18F)) +D18FD120 +SELECT HEX(RPAD(_utf8 0xD18F, 3, 0x20)); +HEX(RPAD(_utf8 0xD18F, 3, 0x20)) +D18F20 +SELECT HEX(LPAD(_utf8 0xD18F, 3, 0x20)); +HEX(LPAD(_utf8 0xD18F, 3, 0x20)) +20D18F +SELECT HEX(INSERT(_utf8 0xD18F, 2, 1, 0x20)); +HEX(INSERT(_utf8 0xD18F, 2, 1, 0x20)) +D120 +SELECT HEX(INSERT(_utf8 0xD18FD18E, 2, 1, 0x20)); +HEX(INSERT(_utf8 0xD18FD18E, 2, 1, 0x20)) +D120D18E +End of 5.1 tests diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 23c83310886..8e9f09d1e56 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -1466,3 +1466,23 @@ SELECT CONVERT(a, CHAR), CONVERT(b, CHAR) from t1 GROUP BY b; DROP TABLE t1; --echo End of 5.0 tests + + +# +# Bug #57272: crash in rpad() when using utf8 +# +SELECT LENGTH(RPAD(0.0115E88, 61297, _utf8'яэюя')); +SELECT LENGTH(RPAD(0.0115E88, 61297, _utf8'йцуя')); +SELECT HEX(RPAD(0x20, 2, _utf8 0xD18F)); +SELECT HEX(RPAD(0x20, 4, _utf8 0xD18F)); +SELECT HEX(LPAD(0x20, 2, _utf8 0xD18F)); +SELECT HEX(LPAD(0x20, 4, _utf8 0xD18F)); + +SELECT HEX(RPAD(_utf8 0xD18F, 3, 0x20)); +SELECT HEX(LPAD(_utf8 0xD18F, 3, 0x20)); + +SELECT HEX(INSERT(_utf8 0xD18F, 2, 1, 0x20)); +SELECT HEX(INSERT(_utf8 0xD18FD18E, 2, 1, 0x20)); + + +--echo End of 5.1 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 5d56b0a621a..9f06a4b5c9f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1013,6 +1013,20 @@ String *Item_func_insert::val_str(String *str) if ((length < 0) || (length > res->length())) length= res->length(); + /* + There is one exception not handled (intentionaly) by the character set + aggregation code. If one string is strong side and is binary, and + another one is weak side and is a multi-byte character string, + then we need to operate on the second string in terms on bytes when + calling ::numchars() and ::charpos(), rather than in terms of characters. + Lets substitute its character set to binary. + */ + if (collation.collation == &my_charset_bin) + { + res->set_charset(&my_charset_bin); + res2->set_charset(&my_charset_bin); + } + /* start and length are now sufficiently valid to pass to charpos function */ start= res->charpos((int) start); length= res->charpos((int) length, (uint32) start); @@ -2514,6 +2528,20 @@ String *Item_func_rpad::val_str(String *str) /* Set here so that rest of code sees out-of-bound value as such. */ if ((ulonglong) count > INT_MAX32) count= INT_MAX32; + /* + There is one exception not handled (intentionaly) by the character set + aggregation code. If one string is strong side and is binary, and + another one is weak side and is a multi-byte character string, + then we need to operate on the second string in terms on bytes when + calling ::numchars() and ::charpos(), rather than in terms of characters. + Lets substitute its character set to binary. + */ + if (collation.collation == &my_charset_bin) + { + res->set_charset(&my_charset_bin); + rpad->set_charset(&my_charset_bin); + } + if (count <= (res_char_length= res->numchars())) { // String to pad is big enough res->length(res->charpos((int) count)); // Shorten result if longer @@ -2616,6 +2644,20 @@ String *Item_func_lpad::val_str(String *str) if ((ulonglong) count > INT_MAX32) count= INT_MAX32; + /* + There is one exception not handled (intentionaly) by the character set + aggregation code. If one string is strong side and is binary, and + another one is weak side and is a multi-byte character string, + then we need to operate on the second string in terms on bytes when + calling ::numchars() and ::charpos(), rather than in terms of characters. + Lets substitute its character set to binary. + */ + if (collation.collation == &my_charset_bin) + { + res->set_charset(&my_charset_bin); + pad->set_charset(&my_charset_bin); + } + res_char_length= res->numchars(); if (count <= res_char_length) From 9ef7eac2c0a27cbacbd5c1499119f7c4b58a48fe Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Tue, 12 Oct 2010 23:28:03 +0400 Subject: [PATCH 07/17] Fix for bug#57283: inet_ntoa() crashes Problem: some call of INET_NTOA() function may lead to a crash due to missing its character set initialization. Fix: explicitly set the character set. --- mysql-test/r/func_misc.result | 6 ++++++ mysql-test/t/func_misc.test | 8 ++++++++ sql/item_strfunc.cc | 1 + 3 files changed, 15 insertions(+) diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index eee56ae7461..082b6eb50c2 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -351,4 +351,10 @@ GREATEST(a, (SELECT b FROM t1 LIMIT 1)) 3 1 DROP TABLE t1; +SELECT INET_NTOA(0); +INET_NTOA(0) +0.0.0.0 +SELECT '1' IN ('1', INET_NTOA(0)); +'1' IN ('1', INET_NTOA(0)) +1 End of tests diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index c6b5ffd5a3f..f47418fa773 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -479,4 +479,12 @@ SELECT DISTINCT GREATEST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1; DROP TABLE t1; + +# +# Bug #57283: inet_ntoa() crashes +# +SELECT INET_NTOA(0); +SELECT '1' IN ('1', INET_NTOA(0)); + + --echo End of tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 9f06a4b5c9f..8fda281bd9e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3135,6 +3135,7 @@ String* Item_func_inet_ntoa::val_str(String* str) if ((null_value= (args[0]->null_value || n > (ulonglong) LL(4294967295)))) return 0; // Null value + str->set_charset(collation.collation); str->length(0); int4store(buf,n); From 017b88f0de5711f876e0fe278a86e207b032ae12 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Sun, 17 Oct 2010 13:00:13 +0200 Subject: [PATCH 08/17] Bug#57359 Possible to circumvent secure_file_priv using '..' on Windows Where realpath(3) is used in Linux, mf_load_path is used for Windows. This function doesn't however correspond to the functionality of realpath. This patch attempts to do better by using the Windows function GetFullPathName() instead. --- mysys/my_symlink.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index 258e227bb7b..b57edd2179a 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -113,7 +113,6 @@ int my_is_symlink(const char *filename __attribute__((unused))) #endif } - /* Resolve all symbolic links in path 'to' may be equal to 'filename' @@ -146,8 +145,24 @@ int my_realpath(char *to, const char *filename, result= -1; } DBUG_RETURN(result); +#else +#ifdef _WIN32 + int ret= GetFullPathName(filename,FN_REFLEN, + to, + NULL); + if (ret == 0 || ret > FN_REFLEN) + { + if (ret > FN_REFLEN) + my_errno= ENAMETOOLONG; + else + my_errno= EACCES; + if (MyFlags & MY_WME) + my_error(EE_REALPATH, MYF(0), filename, my_errno); + return -1; + } #else my_load_path(to, filename, NullS); +#endif return 0; #endif } From 9a8f22fa2d9126cf7344cdd90e258f72dfa2e51e Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Mon, 18 Oct 2010 14:47:26 +0400 Subject: [PATCH 09/17] Bug#54484 explain + prepared statement: crash and Got error -1 from storage engine Subquery executes twice, at top level JOIN::optimize and ::execute stages. At first execution create_sort_index() function is called and FT_SELECT object is created and destroyed. HANDLER::ft_handler is cleaned up in the object destructor and at second execution FT_SELECT::get_next() method returns error. The fix is to reinit HANDLER::ft_handler field before re-execution of subquery. --- mysql-test/r/fulltext.result | 36 ++++++++++++++++++++++++++++++++++++ mysql-test/t/fulltext.test | 36 ++++++++++++++++++++++++++++++++++++ sql/item_func.cc | 10 ++++++++++ sql/item_func.h | 2 +- sql/sql_select.cc | 3 +++ 5 files changed, 86 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 806675edc5a..4f406f5032c 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -644,4 +644,40 @@ Table Op Msg_type Msg_text test.t1 repair status OK SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; DROP TABLE t1; +# +# Bug#54484 explain + prepared statement: crash and Got error -1 from storage engine +# +CREATE TABLE t1(f1 VARCHAR(6) NOT NULL, FULLTEXT KEY(f1), UNIQUE(f1)); +INSERT INTO t1 VALUES ('test'); +SELECT 1 FROM t1 WHERE 1 > +ALL((SELECT 1 FROM t1 JOIN t1 a +ON (MATCH(t1.f1) against ("")) +WHERE t1.f1 GROUP BY t1.f1)) xor f1; +1 +1 +PREPARE stmt FROM +'SELECT 1 FROM t1 WHERE 1 > + ALL((SELECT 1 FROM t1 RIGHT OUTER JOIN t1 a + ON (MATCH(t1.f1) against ("")) + WHERE t1.f1 GROUP BY t1.f1)) xor f1'; +EXECUTE stmt; +1 +1 +EXECUTE stmt; +1 +1 +DEALLOCATE PREPARE stmt; +PREPARE stmt FROM +'SELECT 1 FROM t1 WHERE 1 > + ALL((SELECT 1 FROM t1 JOIN t1 a + ON (MATCH(t1.f1) against ("")) + WHERE t1.f1 GROUP BY t1.f1))'; +EXECUTE stmt; +1 +1 +EXECUTE stmt; +1 +1 +DEALLOCATE PREPARE stmt; +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index ec64728a8c9..6de8b87197c 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -585,4 +585,40 @@ REPAIR TABLE t1; SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; DROP TABLE t1; +--echo # +--echo # Bug#54484 explain + prepared statement: crash and Got error -1 from storage engine +--echo # + +CREATE TABLE t1(f1 VARCHAR(6) NOT NULL, FULLTEXT KEY(f1), UNIQUE(f1)); +INSERT INTO t1 VALUES ('test'); + +SELECT 1 FROM t1 WHERE 1 > + ALL((SELECT 1 FROM t1 JOIN t1 a + ON (MATCH(t1.f1) against ("")) + WHERE t1.f1 GROUP BY t1.f1)) xor f1; + +PREPARE stmt FROM +'SELECT 1 FROM t1 WHERE 1 > + ALL((SELECT 1 FROM t1 RIGHT OUTER JOIN t1 a + ON (MATCH(t1.f1) against ("")) + WHERE t1.f1 GROUP BY t1.f1)) xor f1'; + +EXECUTE stmt; +EXECUTE stmt; + +DEALLOCATE PREPARE stmt; + +PREPARE stmt FROM +'SELECT 1 FROM t1 WHERE 1 > + ALL((SELECT 1 FROM t1 JOIN t1 a + ON (MATCH(t1.f1) against ("")) + WHERE t1.f1 GROUP BY t1.f1))'; + +EXECUTE stmt; +EXECUTE stmt; + +DEALLOCATE PREPARE stmt; + +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index eaf6a1b6d14..30d5d844f7c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5297,7 +5297,17 @@ void Item_func_match::init_search(bool no_order) /* Check if init_search() has been called before */ if (ft_handler) + { + /* + We should reset ft_handler as it is cleaned up + on destruction of FT_SELECT object + (necessary in case of re-execution of subquery). + TODO: FT_SELECT should not clean up ft_handler. + */ + if (join_key) + table->file->ft_handler= ft_handler; DBUG_VOID_RETURN; + } if (key == NO_SUCH_KEY) { diff --git a/sql/item_func.h b/sql/item_func.h index 256348eee08..26a7e033692 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1531,7 +1531,7 @@ public: join_key(0), ft_handler(0), table(0), master(0), concat_ws(0) { } void cleanup() { - DBUG_ENTER("Item_func_match"); + DBUG_ENTER("Item_func_match::cleanup"); Item_real_func::cleanup(); if (!master && ft_handler) ft_handler->please->close_search(ft_handler); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 08bd0c28738..a260b78f131 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1713,6 +1713,9 @@ JOIN::reinit() func->clear(); } + if (!(select_options & SELECT_DESCRIBE)) + init_ftfuncs(thd, select_lex, test(order)); + DBUG_RETURN(0); } From e6472e8fed46f1f3418b9cf3fba17be9254bdd1e Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Mon, 18 Oct 2010 16:12:27 +0400 Subject: [PATCH 10/17] Bug#56814 Explain + subselect + fulltext crashes server create_sort_index() function overwrites original JOIN_TAB::type field. At re-execution of subquery overwritten JOIN_TAB::type(JT_ALL) is used instead of JT_FT. It misleads test_if_skip_sort_order() and the function tries to find suitable key for the order that should not be allowed for FULLTEXT(JT_FT) table. The fix is to restore JOIN_TAB strucures for subselect on re-execution for EXPLAIN. Additional fix: Update TABLE::maybe_null field which affects list_contains_unique_index() behaviour as it could have the value(maybe_null==TRUE) based on the assumption that this join is outer (see setup_table_map() func). --- mysql-test/r/explain.result | 46 +++++++++++++++++++++++++++++++++++++ mysql-test/t/explain.test | 36 +++++++++++++++++++++++++++++ sql/item_subselect.cc | 15 ++++++++---- sql/sql_select.cc | 14 +++++++++++ 4 files changed, 106 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index f46fe8daaad..4bc6c0409f3 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -251,4 +251,50 @@ EXPLAIN SELECT c1 FROM t1 WHERE c2 = 1 AND c4 = 1 AND c5 = 1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref c2,c2_2 c2 10 const,const 3 Using where DROP TABLE t1; +# +# Bug#56814 Explain + subselect + fulltext crashes server +# +CREATE TABLE t1(f1 VARCHAR(6) NOT NULL, +FULLTEXT KEY(f1),UNIQUE(f1)); +INSERT INTO t1 VALUES ('test'); +EXPLAIN SELECT 1 FROM t1 +WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST ("")) +WHERE t1.f1 GROUP BY t1.f1)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 +2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort +2 SUBQUERY t1 fulltext f1 f1 0 1 Using where +PREPARE stmt FROM +'EXPLAIN SELECT 1 FROM t1 + WHERE 1 > ALL((SELECT 1 FROM t1 RIGHT OUTER JOIN t1 a + ON (MATCH(t1.f1) AGAINST ("")) + WHERE t1.f1 GROUP BY t1.f1))'; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 +2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort +2 SUBQUERY t1 fulltext f1 f1 0 1 Using where +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 +2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort +2 SUBQUERY t1 fulltext f1 f1 0 1 Using where +DEALLOCATE PREPARE stmt; +PREPARE stmt FROM +'EXPLAIN SELECT 1 FROM t1 + WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a + ON (MATCH(t1.f1) AGAINST ("")) + WHERE t1.f1 GROUP BY t1.f1))'; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 +2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort +2 SUBQUERY t1 fulltext f1 f1 0 1 Using where +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 +2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort +2 SUBQUERY t1 fulltext f1 f1 0 1 Using where +DEALLOCATE PREPARE stmt; +DROP TABLE t1; End of 5.1 tests. diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index b635a1b2968..c6c30b58341 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -228,4 +228,40 @@ EXPLAIN SELECT c1 FROM t1 WHERE c2 = 1 AND c4 = 1 AND c5 = 1; DROP TABLE t1; +--echo # +--echo # Bug#56814 Explain + subselect + fulltext crashes server +--echo # + +CREATE TABLE t1(f1 VARCHAR(6) NOT NULL, +FULLTEXT KEY(f1),UNIQUE(f1)); +INSERT INTO t1 VALUES ('test'); + +EXPLAIN SELECT 1 FROM t1 +WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST ("")) +WHERE t1.f1 GROUP BY t1.f1)); + +PREPARE stmt FROM +'EXPLAIN SELECT 1 FROM t1 + WHERE 1 > ALL((SELECT 1 FROM t1 RIGHT OUTER JOIN t1 a + ON (MATCH(t1.f1) AGAINST ("")) + WHERE t1.f1 GROUP BY t1.f1))'; + +EXECUTE stmt; +EXECUTE stmt; + +DEALLOCATE PREPARE stmt; + +PREPARE stmt FROM +'EXPLAIN SELECT 1 FROM t1 + WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a + ON (MATCH(t1.f1) AGAINST ("")) + WHERE t1.f1 GROUP BY t1.f1))'; + +EXECUTE stmt; +EXECUTE stmt; + +DEALLOCATE PREPARE stmt; + +DROP TABLE t1; + --echo End of 5.1 tests. diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 1ed36ce7656..d521ad0b4e8 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1906,21 +1906,26 @@ int subselect_single_select_engine::exec() DBUG_RETURN(join->error ? join->error : 1); } if (!select_lex->uncacheable && thd->lex->describe && - !(join->select_options & SELECT_DESCRIBE) && - join->need_tmp) + !(join->select_options & SELECT_DESCRIBE)) { item->update_used_tables(); if (item->const_item()) { + /* + It's necessary to keep original JOIN table because + create_sort_index() function may overwrite original + JOIN_TAB::type and wrong optimization method can be + selected on re-execution. + */ + select_lex->uncacheable|= UNCACHEABLE_EXPLAIN; + select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN; /* Force join->join_tmp creation, because this subquery will be replaced by a simple select from the materialization temp table by optimize() called by EXPLAIN and we need to preserve the initial query structure so we can display it. */ - select_lex->uncacheable|= UNCACHEABLE_EXPLAIN; - select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN; - if (join->init_save_join_tab()) + if (join->need_tmp && join->init_save_join_tab()) DBUG_RETURN(1); /* purecov: inspected */ } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a260b78f131..11acd0685a8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2490,6 +2490,13 @@ mysql_select(THD *thd, Item ***rref_pointer_array, { DBUG_RETURN(TRUE); } + /* + Original join tabs might be overwritten at first + subselect execution. So we need to restore them. + */ + Item_subselect *subselect= select_lex->master_unit()->item; + if (subselect && subselect->is_uncacheable() && join->reinit()) + DBUG_RETURN(TRUE); } else { @@ -8825,6 +8832,13 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) that reject nulls => the outer join can be replaced by an inner join. */ table->outer_join= 0; + /* + Update TABLE::maybe_null field as it could have + the value(maybe_null==TRUE) based on the assumption + that this join is outer(see setup_table_map() func). + */ + if (table->table) + table->table->maybe_null= FALSE; if (table->on_expr) { /* Add on expression to the where condition. */ From 56c308377676fc4ebed8ef2a4174d89dbd7ba9d9 Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Wed, 20 Oct 2010 19:14:25 -0700 Subject: [PATCH 11/17] Fix bug #57616 Sig 11 in dict_load_table() when failed to load index or foreign key Fix approved by Sunny Bains --- storage/innobase/dict/dict0load.c | 4 ++-- storage/innodb_plugin/ChangeLog | 6 ++++++ storage/innodb_plugin/dict/dict0load.c | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 625956600c0..c505bfbd6c4 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -878,13 +878,13 @@ err_exit: if (err != DB_SUCCESS) { dict_table_remove_from_cache(table); table = NULL; + } else { + table->fk_max_recusive_level = 0; } } else if (!srv_force_recovery) { dict_table_remove_from_cache(table); table = NULL; } - - table->fk_max_recusive_level = 0; #if 0 if (err != DB_SUCCESS && table != NULL) { diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index f0dfe1ff6cc..3e1e4fc7a99 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,9 @@ +2010-10-20 The InnoDB Team + + * dict/dict0load.c + Fix Bug #57616 Sig 11 in dict_load_table() when failed to load + index or foreign key + 2010-10-11 The InnoDB Team * row/row0sel.c diff --git a/storage/innodb_plugin/dict/dict0load.c b/storage/innodb_plugin/dict/dict0load.c index b046fb32b0b..3dcee46b92c 100644 --- a/storage/innodb_plugin/dict/dict0load.c +++ b/storage/innodb_plugin/dict/dict0load.c @@ -1023,13 +1023,13 @@ err_exit: if (err != DB_SUCCESS) { dict_table_remove_from_cache(table); table = NULL; + } else { + table->fk_max_recusive_level = 0; } } else if (!srv_force_recovery) { dict_table_remove_from_cache(table); table = NULL; } - - table->fk_max_recusive_level = 0; #if 0 if (err != DB_SUCCESS && table != NULL) { From c163b89247cd8c985c07ff7d824bfdc861b63d9c Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Sun, 24 Oct 2010 20:31:51 -0700 Subject: [PATCH 12/17] Fix bug #57700 Latching order violation in row_truncate_table_for_mysql(). Approved by Sunny Bains --- storage/innodb_plugin/ChangeLog | 6 ++++++ storage/innodb_plugin/row/row0mysql.c | 23 ++++++++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 3e1e4fc7a99..20d0fc86d00 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,9 @@ +2010-10-24 The InnoDB Team + + * row/row0mysql.c + Fix Bug #57700 Latching order violation in + row_truncate_table_for_mysql() + 2010-10-20 The InnoDB Team * dict/dict0load.c diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index f27afc253ff..24b7a983878 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -2782,15 +2782,6 @@ row_truncate_table_for_mysql( trx->table_id = table->id; - /* Lock all index trees for this table, as we will - truncate the table/index and possibly change their metadata. - All DML/DDL are blocked by table level lock, with - a few exceptions such as queries into information schema - about the table, MySQL could try to access index stats - for this kind of query, we need to use index locks to - sync up */ - dict_table_x_lock_indexes(table); - if (table->space && !table->dir_path_of_temp_table) { /* Discard and create the single-table tablespace. */ ulint space = table->space; @@ -2803,6 +2794,11 @@ row_truncate_table_for_mysql( dict_hdr_get_new_id(NULL, NULL, &space); + /* Lock all index trees for this table. We must + do so after dict_hdr_get_new_id() to preserve + the latch order */ + dict_table_x_lock_indexes(table); + if (space == ULINT_UNDEFINED || fil_create_new_single_table_tablespace( space, table->name, FALSE, flags, @@ -2836,6 +2832,15 @@ row_truncate_table_for_mysql( FIL_IBD_FILE_INITIAL_SIZE, &mtr); mtr_commit(&mtr); } + } else { + /* Lock all index trees for this table, as we will + truncate the table/index and possibly change their metadata. + All DML/DDL are blocked by table level lock, with + a few exceptions such as queries into information schema + about the table, MySQL could try to access index stats + for this kind of query, we need to use index locks to + sync up */ + dict_table_x_lock_indexes(table); } /* scan SYS_INDEXES for all indexes of the table */ From 5bf148fccdc1a05ae044757262d6db3beb2d80e8 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 27 Oct 2010 18:12:10 +0400 Subject: [PATCH 13/17] Bug#57477 SIGFPE when dividing a huge number a negative number The problem is dividing by const value when the result is out of supported range. The fix: -return LONGLONG_MIN if the result is out of supported range for DIV operator. -return 0 if divisor is -1 for MOD operator. --- mysql-test/r/func_math.result | 16 ++++++++++++++++ mysql-test/t/func_math.test | 6 ++++++ sql/item_func.cc | 16 ++++++++++------ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index fd7ef72409e..649232e0b05 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -482,4 +482,20 @@ RAND(i) 0.155220427694936 DROP TABLE t1; # +# Bug#57477 SIGFPE when dividing a huge number a negative number +# +SELECT -9999999999999999991 DIV -1; +-9999999999999999991 DIV -1 +-9223372036854775808 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +SELECT -9223372036854775808 DIV -1; +-9223372036854775808 DIV -1 +-9223372036854775808 +SELECT -9223372036854775808 MOD -1; +-9223372036854775808 MOD -1 +0 +SELECT -9223372036854775808999 MOD -1; +-9223372036854775808999 MOD -1 +0 End of 5.1 tests diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index 91fdce8addb..b0c92c9d6ab 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -308,5 +308,11 @@ SELECT RAND(i) FROM t1; DROP TABLE t1; --echo # +--echo # Bug#57477 SIGFPE when dividing a huge number a negative number +--echo # +SELECT -9999999999999999991 DIV -1; +SELECT -9223372036854775808 DIV -1; +SELECT -9223372036854775808 MOD -1; +SELECT -9223372036854775808999 MOD -1; --echo End of 5.1 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index 30d5d844f7c..3dbff43bb67 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1356,9 +1356,13 @@ longlong Item_func_int_div::val_int() signal_divide_by_null(); return 0; } - return (unsigned_flag ? - (ulonglong) value / (ulonglong) val2 : - value / val2); + + if (unsigned_flag) + return ((ulonglong) value / (ulonglong) val2); + else if (value == LONGLONG_MIN && val2 == -1) + return LONGLONG_MIN; + else + return value / val2; } @@ -1392,9 +1396,9 @@ longlong Item_func_mod::int_op() if (args[0]->unsigned_flag) result= args[1]->unsigned_flag ? ((ulonglong) value) % ((ulonglong) val2) : ((ulonglong) value) % val2; - else - result= args[1]->unsigned_flag ? - value % ((ulonglong) val2) : value % val2; + else result= args[1]->unsigned_flag ? + value % ((ulonglong) val2) : + (val2 == -1) ? 0 : value % val2; return result; } From 3a61843a1fda3c242a734b2e9094a00664d69867 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 29 Oct 2010 11:44:32 +0400 Subject: [PATCH 14/17] Bug#57194 group_concat cause crash and/or invalid memory reads with type errors The problem is caused by bug49487 fix and became visible after after bug56679 fix. Items are cleaned up and set to unfixed state after filling derived table. So we can not rely on item::fixed state in Item_func_group_concat::print and we can not use 'args' array as items there may be cleaned up. The fix is always to use orig_args array of items as it always should contain the correct data. --- mysql-test/r/func_gconcat.result | 8 ++++++++ mysql-test/t/func_gconcat.test | 10 ++++++++++ sql/item_sum.cc | 6 ++---- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index ae48eb1e0ff..de592ece285 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -1029,4 +1029,12 @@ GROUP_CONCAT(t1.a ORDER BY t1.a) 1,1,2,2 DEALLOCATE PREPARE stmt; DROP TABLE t1; +# +# Bug#57194 group_concat cause crash and/or invalid memory reads with type errors +# +CREATE TABLE t1(f1 int); +INSERT INTO t1 values (0),(0); +SELECT POLYGON((SELECT 1 FROM (SELECT 1 IN (GROUP_CONCAT(t1.f1)) FROM t1, t1 t GROUP BY t.f1 ) d)); +ERROR 22007: Illegal non geometric '(select 1 from (select (1 = group_concat(`test`.`t1`.`f1` separator ',')) AS `1 IN (GROUP_CONCAT(t1.f1))` from `test`.`t1` join `test`.`t1` `t` group by `t`.`f1`) `d`)' value found during parsing +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 926c1f92855..29fc8a9dc3c 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -734,4 +734,14 @@ EXECUTE stmt; DEALLOCATE PREPARE stmt; DROP TABLE t1; +--echo # +--echo # Bug#57194 group_concat cause crash and/or invalid memory reads with type errors +--echo # + +CREATE TABLE t1(f1 int); +INSERT INTO t1 values (0),(0); +--error ER_ILLEGAL_VALUE_FOR_TYPE +SELECT POLYGON((SELECT 1 FROM (SELECT 1 IN (GROUP_CONCAT(t1.f1)) FROM t1, t1 t GROUP BY t.f1 ) d)); +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/sql/item_sum.cc b/sql/item_sum.cc index ae9e46e2abf..65f8222d38b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3401,8 +3401,6 @@ String* Item_func_group_concat::val_str(String* str) void Item_func_group_concat::print(String *str, enum_query_type query_type) { - /* orig_args is not filled with valid values until fix_fields() */ - Item **pargs= fixed ? orig_args : args; str->append(STRING_WITH_LEN("group_concat(")); if (distinct) str->append(STRING_WITH_LEN("distinct ")); @@ -3410,7 +3408,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type) { if (i) str->append(','); - pargs[i]->print(str, query_type); + orig_args[i]->print(str, query_type); } if (arg_count_order) { @@ -3419,7 +3417,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type) { if (i) str->append(','); - pargs[i + arg_count_field]->print(str, query_type); + orig_args[i + arg_count_field]->print(str, query_type); if (order[i]->asc) str->append(STRING_WITH_LEN(" ASC")); else From e3917c3d43471725a79f89aae12eabbdc5dc55a4 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 29 Oct 2010 12:23:06 +0400 Subject: [PATCH 15/17] Bug#57688 Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field Lines below which were added in the patch for Bug#56814 cause this crash: + if (table->table) + table->table->maybe_null= FALSE; Consider following test case: -- CREATE TABLE t1(f1 INT NOT NULL); INSERT INTO t1 VALUES (16777214),(0); SELECT COUNT(*) FROM t1 LEFT JOIN t1 t2 ON 1 WHERE t2.f1 > 1 GROUP BY t2.f1; DROP TABLE t1; -- We set TABLE::maybe_null to FALSE for t2 table and in create_tmp_field() we create appropriate tmp table field using create_tmp_field_from_item() function instead of create_tmp_field_from_field. As a result we have LONGLONG field. As we have GROUP BY clause we calculate group buffer length, see calc_group_buffer(). Item from group list which is used for calculation refer to the field from real tables and have LONG type. So group buffer length become insufficient for storing of LONGLONG value. It leads to overwriting of wrong memory area in do_field_int() function which is called from end_update(). After some investigation I found out that create_tmp_field_from_item() is used only for OLAP grouping and can not be used for common grouping as it could be an incompatibility between tmp table fields and group buffer length. We can not remove create_tmp_field_from_item() call from create_tmp_field as OLAP needs it and we can not use this function for common grouping. So we should remove setting TABLE::maybe_null to FALSE from simplify_joins(). In this case we'll get wrong behaviour of list_contains_unique_index() back. To fix it we could use Field::real_maybe_null() check instead of Field::maybe_null() and add addition check of TABLE_LIST::outer_join. --- mysql-test/r/group_by.result | 10 ++++++++++ mysql-test/r/join_outer.result | 30 ++++++++++++++++++++++++++++++ mysql-test/t/group_by.test | 11 +++++++++++ mysql-test/t/join_outer.test | 29 +++++++++++++++++++++++++++++ sql/sql_select.cc | 11 +++-------- 5 files changed, 83 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index f74584f6bcf..83f1f220023 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1845,4 +1845,14 @@ SELECT SUBSTRING(a,1,10), LENGTH(a) FROM t1 GROUP BY a; SUBSTRING(a,1,10) LENGTH(a) 1111111111 1300 DROP TABLE t1; +# +# Bug#57688 Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field +# +CREATE TABLE t1(f1 INT NOT NULL); +INSERT INTO t1 VALUES (16777214),(0); +SELECT COUNT(*) FROM t1 LEFT JOIN t1 t2 +ON 1 WHERE t2.f1 > 1 GROUP BY t2.f1; +COUNT(*) +2 +DROP TABLE t1; # End of 5.1 tests diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 8e438934b23..d9c4ac5478e 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1397,4 +1397,34 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select straight_join `test`.`jt1`.`f1` AS `f1` from `test`.`t1` `jt6` left join (`test`.`t1` `jt3` join `test`.`t1` `jt4` left join `test`.`t1` `jt5` on(1) left join `test`.`t1` `jt2` on(1)) on((`test`.`jt6`.`f1` and 1)) left join `test`.`t1` `jt1` on(1) where 1 DROP TABLE t1; +# +# Bug#57688 Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field +# +CREATE TABLE t1 (f1 INT NOT NULL, PRIMARY KEY (f1)); +CREATE TABLE t2 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY (f1, f2)); +INSERT INTO t1 VALUES (4); +INSERT INTO t2 VALUES (3, 3); +INSERT INTO t2 VALUES (7, 7); +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 +GROUP BY t2.f1, t2.f2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system PRIMARY NULL NULL NULL 1 Using temporary; Using filesort +1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using index +SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 +GROUP BY t2.f1, t2.f2; +f1 f1 f2 +4 NULL NULL +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL +GROUP BY t2.f1, t2.f2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system PRIMARY NULL NULL NULL 1 Using filesort +1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using where; Using index +SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL +GROUP BY t2.f1, t2.f2; +f1 f1 f2 +DROP TABLE t1,t2; End of 5.1 tests diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 75ec1d82b02..580c2e5091c 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -1235,5 +1235,16 @@ SELECT SUBSTRING(a,1,10), LENGTH(a) FROM t1 GROUP BY a; SELECT SUBSTRING(a,1,10), LENGTH(a) FROM t1 GROUP BY a; DROP TABLE t1; +--echo # +--echo # Bug#57688 Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field +--echo # + +CREATE TABLE t1(f1 INT NOT NULL); +INSERT INTO t1 VALUES (16777214),(0); + +SELECT COUNT(*) FROM t1 LEFT JOIN t1 t2 +ON 1 WHERE t2.f1 > 1 GROUP BY t2.f1; + +DROP TABLE t1; --echo # End of 5.1 tests diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index cf881e6aaa2..3251ff292b6 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -981,4 +981,33 @@ EXPLAIN EXTENDED SELECT STRAIGHT_JOIN jt1.f1 FROM t1 AS jt1 DROP TABLE t1; +--echo # +--echo # Bug#57688 Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field +--echo # + +CREATE TABLE t1 (f1 INT NOT NULL, PRIMARY KEY (f1)); +CREATE TABLE t2 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY (f1, f2)); + +INSERT INTO t1 VALUES (4); +INSERT INTO t2 VALUES (3, 3); +INSERT INTO t2 VALUES (7, 7); + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 +GROUP BY t2.f1, t2.f2; + +SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 +GROUP BY t2.f1, t2.f2; + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL +GROUP BY t2.f1, t2.f2; + +SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 +WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL +GROUP BY t2.f1, t2.f2; + +DROP TABLE t1,t2; + --echo End of 5.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 11acd0685a8..9767839b5bf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8832,13 +8832,6 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) that reject nulls => the outer join can be replaced by an inner join. */ table->outer_join= 0; - /* - Update TABLE::maybe_null field as it could have - the value(maybe_null==TRUE) based on the assumption - that this join is outer(see setup_table_map() func). - */ - if (table->table) - table->table->maybe_null= FALSE; if (table->on_expr) { /* Add on expression to the where condition. */ @@ -13219,6 +13212,8 @@ static bool list_contains_unique_index(TABLE *table, bool (*find_func) (Field *, void *), void *data) { + if (table->pos_in_table_list->outer_join) + return 0; for (uint keynr= 0; keynr < table->s->keys; keynr++) { if (keynr == table->s->primary_key || @@ -13232,7 +13227,7 @@ list_contains_unique_index(TABLE *table, key_part < key_part_end; key_part++) { - if (key_part->field->maybe_null() || + if (key_part->field->real_maybe_null() || !find_func(key_part->field, data)) break; } From 942f71b2e0d76a15d5c0c3100bc8e7d257a1cea2 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Mon, 1 Nov 2010 09:47:57 +0300 Subject: [PATCH 16/17] test case fix --- mysql-test/t/func_gconcat.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 29fc8a9dc3c..a7072362759 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -740,8 +740,10 @@ DROP TABLE t1; CREATE TABLE t1(f1 int); INSERT INTO t1 values (0),(0); +--disable_ps_protocol --error ER_ILLEGAL_VALUE_FOR_TYPE SELECT POLYGON((SELECT 1 FROM (SELECT 1 IN (GROUP_CONCAT(t1.f1)) FROM t1, t1 t GROUP BY t.f1 ) d)); +--enable_ps_protocol DROP TABLE t1; --echo End of 5.1 tests From dce374bb663c0450546a6836cea763e8c3eca8dd Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 26 Nov 2010 12:24:05 +0200 Subject: [PATCH 17/17] bumped up the version string. --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 7fd581af009..9cfe342a7c5 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.54], [], [mysql]) +AC_INIT([MySQL Server], [5.1.55], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM