From 0304a13ee7140727786adf4feb5e1639e85e8138 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 6 Jun 2007 00:25:06 +0400 Subject: [PATCH 01/20] Bug#28778: Wrong result of BETWEEN when comparing a DATETIME field with an integer constants. This bug is introduced by the fix for bug#16377. Before the fix the Item_func_between::fix_length_and_dec method converted the second and third arguments to the type of the first argument if they were constant and the first argument is of the DATE/DATETIME type. That approach worked well for integer constants and sometimes produced bad result for string constants. The fix for the bug#16377 wrongly removed that code at all and as a result of this the comparison of a DATETIME field and an integer constant was carried out in a wrong way and sometimes led to wrong result sets. Now the Item_func_between::fix_length_and_dec method converts the second and third arguments to the type of the first argument if they are constant, the first argument is of the DATE/DATETIME type and the DATETIME comparator isn't applicable. sql/item_cmpfunc.cc: Bug#28778: Wrong result of BETWEEN when comparing a DATETIME field with an integer constants. Now the Item_func_between::fix_length_and_dec method converts the second and third arguments to the type of the first argument if they are constant, the first argument is of the DATE/DATETIME type and the DATETIME comparator isn't applicable. mysql-test/r/type_datetime.result: Added a test case for the bug#28778: Wrong result of BETWEEN when comparing a DATETIME field with an integer constants. mysql-test/t/type_datetime.test: Added a test case for the bug#28778: Wrong result of BETWEEN when comparing a DATETIME field with an integer constants. --- mysql-test/r/type_datetime.result | 16 ++++++++++++++++ mysql-test/t/type_datetime.test | 11 +++++++++++ sql/item_cmpfunc.cc | 17 +++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index ba02f19712a..9e47b5da2b6 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -411,3 +411,19 @@ if(@bug28261 = f1, '', @bug28261:= f1) 2001-01-01 2002-02-02 drop table t1; +create table t1(f1 datetime); +insert into t1 values('2001-01-01'),('2002-02-02'); +select * from t1 where f1 between 20020101 and 20070101000000; +f1 +2002-02-02 00:00:00 +select * from t1 where f1 between 2002010 and 20070101000000; +f1 +2001-01-01 00:00:00 +2002-02-02 00:00:00 +Warnings: +Warning 1292 Incorrect datetime value: '2002010' for column 'f1' at row 1 +select * from t1 where f1 between 20020101 and 2007010100000; +f1 +Warnings: +Warning 1292 Incorrect datetime value: '2007010100000' for column 'f1' at row 1 +drop table t1; diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index d420afbde37..ffda593f320 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -271,3 +271,14 @@ select if(@bug28261 = f1, '', @bug28261:= f1) from t1; select if(@bug28261 = f1, '', @bug28261:= f1) from t1; select if(@bug28261 = f1, '', @bug28261:= f1) from t1; drop table t1; + +# +# Bug#28778: Wrong result of BETWEEN when comparing a DATETIME field with an +# integer constants. +# +create table t1(f1 datetime); +insert into t1 values('2001-01-01'),('2002-02-02'); +select * from t1 where f1 between 20020101 and 20070101000000; +select * from t1 where f1 between 2002010 and 20070101000000; +select * from t1 where f1 between 20020101 and 2007010100000; +drop table t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 06c825334c2..919015140c1 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1755,6 +1755,23 @@ void Item_func_between::fix_length_and_dec() ge_cmp.set_datetime_cmp_func(args, args + 1); le_cmp.set_datetime_cmp_func(args, args + 2); } + else if (args[0]->real_item()->type() == FIELD_ITEM && + thd->lex->sql_command != SQLCOM_CREATE_VIEW && + thd->lex->sql_command != SQLCOM_SHOW_CREATE) + { + Field *field=((Item_field*) (args[0]->real_item()))->field; + if (field->can_be_compared_as_longlong()) + { + /* + The following can't be recoded with || as convert_constant_item + changes the argument + */ + if (convert_constant_item(thd, field,&args[1])) + cmp_type=INT_RESULT; // Works for all types. + if (convert_constant_item(thd, field,&args[2])) + cmp_type=INT_RESULT; // Works for all types. + } + } } From 593afb6a7389639aef111f198cff5f1d5192fad7 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 6 Jun 2007 18:29:15 +0500 Subject: [PATCH 02/20] Bug#28553 mysqld crash in "purge master log before(select time from information_schema)" forbid the use of subselect in PURGE LOGS BEFORE command mysql-test/r/subselect.result: test result mysql-test/t/subselect.test: test case sql/sql_yacc.yy: forbid the use of subselect in PURGE LOGS BEFORE command --- mysql-test/r/subselect.result | 2 ++ mysql-test/t/subselect.test | 7 ++++--- sql/sql_yacc.yy | 8 +++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 5bb79a53771..ff120912902 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2834,6 +2834,8 @@ a 4 DROP TABLE t1,t2,t3; purge master logs before (select adddate(current_timestamp(), interval -4 day)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select adddate(current_timestamp(), interval -4 day))' at line 1 +purge master logs before adddate(current_timestamp(), interval -4 day); CREATE TABLE t1 (f1 INT); CREATE TABLE t2 (f2 INT); INSERT INTO t1 VALUES (1); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 67a18e7a30f..978c8f26552 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1815,11 +1815,12 @@ SELECT * FROM t1 DROP TABLE t1,t2,t3; # -# BUG #10308: purge log with subselect +# BUG#10308: purge log with subselect +# Bug#28553: mysqld crash in "purge master log before(select time from information_schema)" # - +--error 1064 purge master logs before (select adddate(current_timestamp(), interval -4 day)); - +purge master logs before adddate(current_timestamp(), interval -4 day); # # Bug#18503: Queries with a quantified subquery returning empty set may diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b72caac46a0..d53dba6bf1b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3567,7 +3567,8 @@ select_derived2: LEX *lex= Lex; lex->derived_tables= 1; if (lex->sql_command == (int)SQLCOM_HA_READ || - lex->sql_command == (int)SQLCOM_KILL) + lex->sql_command == (int)SQLCOM_KILL || + lex->sql_command == (int)SQLCOM_PURGE) { yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; @@ -4748,6 +4749,7 @@ purge: { LEX *lex=Lex; lex->type=0; + lex->sql_command = SQLCOM_PURGE; } purge_options {} ; @@ -4759,7 +4761,6 @@ purge_options: purge_option: TO_SYM TEXT_STRING_sys { - Lex->sql_command = SQLCOM_PURGE; Lex->to_log = $2.str; } | BEFORE_SYM expr @@ -6212,7 +6213,8 @@ subselect_start: { LEX *lex=Lex; if (lex->sql_command == (int)SQLCOM_HA_READ || - lex->sql_command == (int)SQLCOM_KILL) + lex->sql_command == (int)SQLCOM_KILL || + lex->sql_command == (int)SQLCOM_PURGE) { yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; From 64c6a91d40cd3885926a7706549cbfc7c3fe565c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 6 Jun 2007 18:55:21 +0500 Subject: [PATCH 03/20] after merge fix --- mysql-test/r/subselect.result | 3 --- mysql-test/r/subselect_notembedded.result | 2 ++ mysql-test/t/subselect.test | 8 -------- mysql-test/t/subselect_notembedded.test | 7 ++++--- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index aa970e2b171..38f6e2d10e3 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2853,9 +2853,6 @@ a 3 4 DROP TABLE t1,t2,t3; -purge master logs before (select adddate(current_timestamp(), interval -4 day)); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select adddate(current_timestamp(), interval -4 day))' at line 1 -purge master logs before adddate(current_timestamp(), interval -4 day); CREATE TABLE t1 (f1 INT); CREATE TABLE t2 (f2 INT); INSERT INTO t1 VALUES (1); diff --git a/mysql-test/r/subselect_notembedded.result b/mysql-test/r/subselect_notembedded.result index dd4b0701c32..44ae055425e 100644 --- a/mysql-test/r/subselect_notembedded.result +++ b/mysql-test/r/subselect_notembedded.result @@ -1 +1,3 @@ purge master logs before (select adddate(current_timestamp(), interval -4 day)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select adddate(current_timestamp(), interval -4 day))' at line 1 +purge master logs before adddate(current_timestamp(), interval -4 day); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 2ae48a0303f..33e58fe0c32 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1821,14 +1821,6 @@ SELECT * FROM t1 DROP TABLE t1,t2,t3; -# -# BUG#10308: purge log with subselect -# Bug#28553: mysqld crash in "purge master log before(select time from information_schema)" -# ---error 1064 -purge master logs before (select adddate(current_timestamp(), interval -4 day)); -purge master logs before adddate(current_timestamp(), interval -4 day); - # # Bug#18503: Queries with a quantified subquery returning empty set may # return a wrong result. diff --git a/mysql-test/t/subselect_notembedded.test b/mysql-test/t/subselect_notembedded.test index c5b23f6dac8..c112272e8ad 100644 --- a/mysql-test/t/subselect_notembedded.test +++ b/mysql-test/t/subselect_notembedded.test @@ -1,8 +1,9 @@ -- source include/not_embedded.inc # -# BUG #10308: purge log with subselect +# BUG#10308: purge log with subselect +# Bug#28553: mysqld crash in "purge master log before(select time from information_schema)" # - +--error 1064 purge master logs before (select adddate(current_timestamp(), interval -4 day)); - +purge master logs before adddate(current_timestamp(), interval -4 day); From 8d0d27b5a45b8d6224e9d94f77baef7a334e5959 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Jun 2007 00:30:00 +0400 Subject: [PATCH 04/20] Bug#28505: mysql_affected_rows() may return wrong result if CLIENT_FOUND_ROWS flag is set. When the CLIENT_FOUND_ROWS flag is set then the server should return found number of rows independently whether they were updated or not. But this wasn't the case for the INSERT statement which always returned number of rows that were actually changed thus providing wrong info to the user. Now the select_insert::send_eof method and the mysql_insert function are sending the number of touched rows if the CLIENT_FOUND_ROWS flag is set. tests/mysql_client_test.c: Added a test case for the bug#28505: mysql_affected_rows() may return wrong result if CLIENT_FOUND_ROWS flag is set. sql/sql_insert.cc: Bug#28505: mysql_affected_rows() may return wrong result if CLIENT_FOUND_ROWS flag is set. Now the select_insert::send_eof method and the mysql_insert function are sending the number of touched rows if the CLIENT_FOUND_ROWS flag is set. --- sql/sql_insert.cc | 14 ++++++--- tests/mysql_client_test.c | 64 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index bf37a3d6d69..f3ed3ebab24 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -947,20 +947,24 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (values_list.elements == 1 && (!(thd->options & OPTION_WARNINGS) || !thd->cuted_fields)) { - thd->row_count_func= info.copied+info.deleted+info.updated; + thd->row_count_func= info.copied + info.deleted + + ((thd->client_capabilities & CLIENT_FOUND_ROWS) ? + info.touched : info.updated); send_ok(thd, (ulong) thd->row_count_func, id); } else { char buff[160]; + ha_rows updated=((thd->client_capabilities & CLIENT_FOUND_ROWS) ? + info.touched : info.updated); if (ignore) sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, (lock_type == TL_WRITE_DELAYED) ? (ulong) 0 : (ulong) (info.records - info.copied), (ulong) thd->cuted_fields); else sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, - (ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields); - thd->row_count_func= info.copied+info.deleted+info.updated; + (ulong) (info.deleted + updated), (ulong) thd->cuted_fields); + thd->row_count_func= info.copied + info.deleted + updated; ::send_ok(thd, (ulong) thd->row_count_func, id, buff); } thd->abort_on_warning= 0; @@ -2973,7 +2977,9 @@ bool select_insert::send_eof() else sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, (ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields); - thd->row_count_func= info.copied+info.deleted+info.updated; + thd->row_count_func= info.copied + info.deleted + + ((thd->client_capabilities & CLIENT_FOUND_ROWS) ? + info.touched : info.updated); ::send_ok(thd, (ulong) thd->row_count_func, last_insert_id, buff); DBUG_RETURN(0); } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index e56dd693287..54d29dbd683 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15623,6 +15623,69 @@ static void test_bug27876() } +/* + Bug#28505: mysql_affected_rows() returns wrong value if CLIENT_FOUND_ROWS + flag is set. +*/ +static void test_bug28505() +{ + MYSQL *l_mysql; + my_bool error= 0; + my_ulonglong res; + + if (!(l_mysql= mysql_init(NULL))) + { + myerror("mysql_init() failed"); + DIE_UNLESS(1); + } + if (!(mysql_real_connect(l_mysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_FOUND_ROWS))) + { + myerror("connection failed"); + error= 1; + goto end; + } + l_mysql->reconnect= 1; + if (mysql_query(l_mysql, "drop table if exists t1")) + { + myerror(NULL); + error= 1; + goto end; + } + if (mysql_query(l_mysql, "create table t1(f1 int primary key)")) + { + myerror(NULL); + error= 1; + goto end; + } + if (mysql_query(l_mysql, "insert into t1 values(1)")) + { + myerror(NULL); + error= 1; + goto end; + } + if (mysql_query(l_mysql, + "insert into t1 values(1) on duplicate key update f1=1")) + { + myerror(NULL); + error= 1; + goto end; + } + res= mysql_affected_rows(l_mysql); + if (!res) + error= 1; + if (mysql_query(l_mysql, "drop table t1")) + { + myerror(NULL); + error= 1; + } +end: + mysql_close(l_mysql); + DIE_UNLESS(error == 0); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -15904,6 +15967,7 @@ static struct my_tests_st my_tests[]= { { "test_bug21635", test_bug21635 }, { "test_bug24179", test_bug24179 }, { "test_bug27876", test_bug27876 }, + { "test_bug28505", test_bug28505 }, { 0, 0 } }; From 970b26e67958f54eb5bed8bea00e9b5949612e7e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Jun 2007 10:08:44 +0300 Subject: [PATCH 05/20] Bug#28878: InnoDB tables with UTF8 character set and indexes cause wrong result for DML When making key reference buffers over CHAR fields whitespace (0x20) must be used to fill in the remaining space in the field's buffer. This is what Field_string::store() does. Fixed Field_string::get_key_image() to do the same. mysql-test/r/innodb_mysql.result: Bug#28878: test case mysql-test/t/innodb_mysql.test: Bug#28878: test case sql/field.cc: Bug#28878: Fill with space instead of binary zeros. --- mysql-test/r/innodb_mysql.result | 36 ++++++++++++++++++++++++++++++++ mysql-test/t/innodb_mysql.test | 31 +++++++++++++++++++++++++++ sql/field.cc | 3 ++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 45cb116f08b..6aab2372706 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -617,4 +617,40 @@ EXPLAIN SELECT COUNT(*) FROM t2 WHERE stat_id IN (1,3) AND acct_id=785; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range idx1,idx2 idx1 9 NULL 2 Using where; Using index DROP TABLE t1,t2; +CREATE TABLE t1 (a CHAR(2), KEY (a)) ENGINE = InnoDB DEFAULT CHARSET=UTF8; +INSERT INTO t1 VALUES ('uk'),('bg'); +SELECT * FROM t1 WHERE a = 'uk'; +a +uk +DELETE FROM t1 WHERE a = 'uk'; +SELECT * FROM t1 WHERE a = 'uk'; +a +UPDATE t1 SET a = 'us' WHERE a = 'uk'; +SELECT * FROM t1 WHERE a = 'uk'; +a +CREATE TABLE t2 (a CHAR(2), KEY (a)) ENGINE = InnoDB; +INSERT INTO t2 VALUES ('uk'),('bg'); +SELECT * FROM t2 WHERE a = 'uk'; +a +uk +DELETE FROM t2 WHERE a = 'uk'; +SELECT * FROM t2 WHERE a = 'uk'; +a +INSERT INTO t2 VALUES ('uk'); +UPDATE t2 SET a = 'us' WHERE a = 'uk'; +SELECT * FROM t2 WHERE a = 'uk'; +a +CREATE TABLE t3 (a CHAR(2), KEY (a)) ENGINE = MyISAM; +INSERT INTO t3 VALUES ('uk'),('bg'); +SELECT * FROM t3 WHERE a = 'uk'; +a +uk +DELETE FROM t3 WHERE a = 'uk'; +SELECT * FROM t3 WHERE a = 'uk'; +a +INSERT INTO t3 VALUES ('uk'); +UPDATE t3 SET a = 'us' WHERE a = 'uk'; +SELECT * FROM t3 WHERE a = 'uk'; +a +DROP TABLE t1,t2,t3; End of 5.0 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index d9e50add8bf..fbb114f9ce6 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -597,4 +597,35 @@ EXPLAIN SELECT COUNT(*) FROM t2 WHERE stat_id IN (1,3) AND acct_id=785; DROP TABLE t1,t2; +# +# Bug #25866: Getting "#HY000 Can't find record in..." on and INSERT +# +CREATE TABLE t1 (a CHAR(2), KEY (a)) ENGINE = InnoDB DEFAULT CHARSET=UTF8; +INSERT INTO t1 VALUES ('uk'),('bg'); +SELECT * FROM t1 WHERE a = 'uk'; +DELETE FROM t1 WHERE a = 'uk'; +SELECT * FROM t1 WHERE a = 'uk'; +UPDATE t1 SET a = 'us' WHERE a = 'uk'; +SELECT * FROM t1 WHERE a = 'uk'; + +CREATE TABLE t2 (a CHAR(2), KEY (a)) ENGINE = InnoDB; +INSERT INTO t2 VALUES ('uk'),('bg'); +SELECT * FROM t2 WHERE a = 'uk'; +DELETE FROM t2 WHERE a = 'uk'; +SELECT * FROM t2 WHERE a = 'uk'; +INSERT INTO t2 VALUES ('uk'); +UPDATE t2 SET a = 'us' WHERE a = 'uk'; +SELECT * FROM t2 WHERE a = 'uk'; + +CREATE TABLE t3 (a CHAR(2), KEY (a)) ENGINE = MyISAM; +INSERT INTO t3 VALUES ('uk'),('bg'); +SELECT * FROM t3 WHERE a = 'uk'; +DELETE FROM t3 WHERE a = 'uk'; +SELECT * FROM t3 WHERE a = 'uk'; +INSERT INTO t3 VALUES ('uk'); +UPDATE t3 SET a = 'us' WHERE a = 'uk'; +SELECT * FROM t3 WHERE a = 'uk'; + +DROP TABLE t1,t2,t3; + --echo End of 5.0 tests diff --git a/sql/field.cc b/sql/field.cc index 8ff615ee798..5ac8358acaa 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6249,7 +6249,8 @@ uint Field_string::get_key_image(char *buff, uint length, imagetype type_arg) length / field_charset->mbmaxlen); memcpy(buff, ptr, bytes); if (bytes < length) - bzero(buff + bytes, length - bytes); + field_charset->cset->fill(field_charset, buff + bytes, length - bytes, + field_charset->pad_char); return bytes; } From 89d96dd48e3c9a52d8fdeed3cb31d7ffa4a83c36 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Jun 2007 00:59:08 -0700 Subject: [PATCH 06/20] Fixed bug #28449: a crash may happen at some rare conditions when a temporary table has grown out of heap memory reserved for it and the remaining disk space is not big enough to store the table as a MyISAM table. The crash happens because the function create_myisam_from_heap does not handle safely the mem_root structure associated with the converted table in the case when an error has occurred. sql/sql_select.cc: Fixed bug #28449: a crash may happen at some rare conditions when a temporary table has grown out of heap memory reserved for it and the remaining disk space is not big enough to store the table as a MyISAM table. The crash happens because the function create_myisam_from_heap does not handle safely the mem_root structure associated with the converted table in the case when an error has occurred. As it's hard to create a sitiation that would throw an error a special code has been added that raises an error for a newly created test called error_simulation. mysql-test/r/error_simulation.result: New BitKeeper file ``mysql-test/r/error_simulation.result'' Added a test case for bug #28449. mysql-test/t/error_simulation-master.opt: New BitKeeper file ``mysql-test/t/error_simulation-master.opt'' mysql-test/t/error_simulation.test: New BitKeeper file ``mysql-test/t/error_simulation.test'' Added a test case for bug #28449. --- mysql-test/r/error_simulation.result | 19 ++++++++++++++++ mysql-test/t/error_simulation-master.opt | 1 + mysql-test/t/error_simulation.test | 29 ++++++++++++++++++++++++ sql/sql_select.cc | 7 ++++-- 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 mysql-test/r/error_simulation.result create mode 100644 mysql-test/t/error_simulation-master.opt create mode 100644 mysql-test/t/error_simulation.test diff --git a/mysql-test/r/error_simulation.result b/mysql-test/r/error_simulation.result new file mode 100644 index 00000000000..805e8fabbd8 --- /dev/null +++ b/mysql-test/r/error_simulation.result @@ -0,0 +1,19 @@ +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 ( +a varchar(32) character set utf8 collate utf8_bin NOT NULL, +b varchar(32) character set utf8 collate utf8_bin NOT NULL ) +ENGINE=MyISAM DEFAULT CHARSET=utf8; +INSERT INTO t1 VALUES +('AAAAAAAAAA','AAAAAAAAAA'), ('AAAAAAAAAB','AAAAAAAAAB '), +('AAAAAAAAAB','AAAAAAAAAB'), ('AAAAAAAAAC','AAAAAAAAAC'), +('AAAAAAAAAD','AAAAAAAAAD'), ('AAAAAAAAAE','AAAAAAAAAE'), +('AAAAAAAAAF','AAAAAAAAAF'), ('AAAAAAAAAG','AAAAAAAAAG'), +('AAAAAAAAAH','AAAAAAAAAH'), ('AAAAAAAAAI','AAAAAAAAAI'), +('AAAAAAAAAJ','AAAAAAAAAJ'), ('AAAAAAAAAK','AAAAAAAAAK'); +set tmp_table_size=1024; +SELECT MAX(a) FROM t1 GROUP BY a,b; +ERROR 23000: Can't write; duplicate key in table '' +set tmp_table_size=default; +DROP TABLE t1; diff --git a/mysql-test/t/error_simulation-master.opt b/mysql-test/t/error_simulation-master.opt new file mode 100644 index 00000000000..edb77cfa85e --- /dev/null +++ b/mysql-test/t/error_simulation-master.opt @@ -0,0 +1 @@ +--loose-debug=d,raise_error diff --git a/mysql-test/t/error_simulation.test b/mysql-test/t/error_simulation.test new file mode 100644 index 00000000000..8c044224b8a --- /dev/null +++ b/mysql-test/t/error_simulation.test @@ -0,0 +1,29 @@ +-- source include/have_debug.inc + +# +# Bug #28499: crash for grouping query when tmp_table_size is too small +# + +DROP TABLE IF EXISTS t1; + +CREATE TABLE t1 ( + a varchar(32) character set utf8 collate utf8_bin NOT NULL, + b varchar(32) character set utf8 collate utf8_bin NOT NULL ) +ENGINE=MyISAM DEFAULT CHARSET=utf8; + +INSERT INTO t1 VALUES + ('AAAAAAAAAA','AAAAAAAAAA'), ('AAAAAAAAAB','AAAAAAAAAB '), + ('AAAAAAAAAB','AAAAAAAAAB'), ('AAAAAAAAAC','AAAAAAAAAC'), + ('AAAAAAAAAD','AAAAAAAAAD'), ('AAAAAAAAAE','AAAAAAAAAE'), + ('AAAAAAAAAF','AAAAAAAAAF'), ('AAAAAAAAAG','AAAAAAAAAG'), + ('AAAAAAAAAH','AAAAAAAAAH'), ('AAAAAAAAAI','AAAAAAAAAI'), + ('AAAAAAAAAJ','AAAAAAAAAJ'), ('AAAAAAAAAK','AAAAAAAAAK'); + +set tmp_table_size=1024; + +--error ER_DUP_KEY +SELECT MAX(a) FROM t1 GROUP BY a,b; + +set tmp_table_size=default; + +DROP TABLE t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 41688794721..ece37708370 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10147,7 +10147,9 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, /* copy all old rows */ while (!table->file->rnd_next(new_table.record[1])) { - if ((write_err=new_table.file->write_row(new_table.record[1]))) + write_err=new_table.file->write_row(new_table.record[1]); + DBUG_EXECUTE_IF("raise_error", write_err= HA_ERR_FOUND_DUPP_KEY ;); + if (write_err) goto err; } /* copy row that filled HEAP table */ @@ -10174,7 +10176,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, err: DBUG_PRINT("error",("Got error: %d",write_err)); - table->file->print_error(error,MYF(0)); // Give table is full error + table->file->print_error(write_err, MYF(0)); // Give table is full error (void) table->file->ha_rnd_end(); (void) new_table.file->close(); err1: @@ -10182,6 +10184,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, delete new_table.file; err2: thd->proc_info=save_proc_info; + table->mem_root= new_table.mem_root; DBUG_RETURN(1); } From 18310fabf48626767c9aeb632be1be69d3756ed0 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Jun 2007 00:33:03 +0400 Subject: [PATCH 07/20] Bug#28763: Selecting geometry fields in UNION caused server crash. This bug was introduced by the fix for the bug#27300. In this fix a section of code was added to the Item::tmp_table_field_from_field_type method. This section intended to create Field_geom fields for the Item_geometry_func class and its descendants. In order to get the geometry type of the current item it casted "this" to the Item_geometry_func* type. But the Item::tmp_table_field_from_field_type method is also used for creation of fields for UNION and in this case this method is called for an object of the Item_type_holder class and the cast to the Item_geometry_func* type causes a server crash. Now the Item::tmp_table_field_from_field_type method correctly works when it's called for both the Item_type_holder and the Item_geometry_func classes. The new geometry_type variable is added to the Item_type_holder class. The new method called get_geometry_type is added to the Item_field and the Field classes. It returns geometry type from the field for the Item_field and the Field_geom classes and fails an assert for other Field descendants. sql/field.h: Bug#28763: Selecting geometry fields in UNION caused server crash. The new method called get_geometry_type is added to the Field class. It returns geometry type of the field for the Field_geom class and fails an assert for other Field descendants. sql/item.cc: Bug#28763: Selecting geometry fields in UNION caused server crash. Now the Item::tmp_table_field_from_field_type method correctly works when it's called for both the Item_type_holder and the Item_geometry_func classes. mysql-test/r/gis.result: Added a test case for the bug#28763: Selecting geometry fields in UNION caused server crash. mysql-test/t/gis.test: Added a test case for the bug#28763: Selecting geometry fields in UNION caused server crash. sql/item.h: Bug#28763: Selecting geometry fields in UNION caused server crash. The new method called get_geometry_type is added to the Item_field class. It returns geometry type from the field. The new geometry_type variable is added to the Item_type_holder class. --- mysql-test/r/gis.result | 21 +++++++++++++++++++++ mysql-test/t/gis.test | 13 +++++++++++++ sql/field.h | 7 ++++++- sql/item.cc | 8 +++++++- sql/item.h | 7 +++++++ 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 73e5b054f80..d1f292cda0c 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -864,4 +864,25 @@ SELECT Overlaps(@horiz1, @point2) FROM DUAL; Overlaps(@horiz1, @point2) 0 DROP TABLE t1; +create table t1(f1 geometry, f2 point, f3 linestring); +select f1 from t1 union select f1 from t1; +f1 +insert into t1 (f2,f3) values (GeomFromText('POINT(1 1)'), +GeomFromText('LINESTRING(0 0,1 1,2 2)')); +select AsText(f2),AsText(f3) from t1; +AsText(f2) AsText(f3) +POINT(1 1) LINESTRING(0 0,1 1,2 2) +select AsText(a) from (select f2 as a from t1 union select f3 from t1) t; +AsText(a) +POINT(1 1) +LINESTRING(0 0,1 1,2 2) +create table t2 as select f2 as a from t1 union select f3 from t1; +desc t2; +Field Type Null Key Default Extra +a point YES NULL +select AsText(a) from t2; +AsText(a) +POINT(1 1) +LINESTRING(0 0,1 1,2 2) +drop table t1, t2; End of 5.0 tests diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index ccc38db8dea..95ccc6272e2 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -557,4 +557,17 @@ SELECT Overlaps(@horiz1, @point2) FROM DUAL; DROP TABLE t1; +# +# Bug#28763: Selecting geometry fields in UNION caused server crash. +# +create table t1(f1 geometry, f2 point, f3 linestring); +select f1 from t1 union select f1 from t1; +insert into t1 (f2,f3) values (GeomFromText('POINT(1 1)'), + GeomFromText('LINESTRING(0 0,1 1,2 2)')); +select AsText(f2),AsText(f3) from t1; +select AsText(a) from (select f2 as a from t1 union select f3 from t1) t; +create table t2 as select f2 as a from t1 union select f3 from t1; +desc t2; +select AsText(a) from t2; +drop table t1, t2; --echo End of 5.0 tests diff --git a/sql/field.h b/sql/field.h index 37ce6b88453..39378addd4c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -360,7 +360,11 @@ public: { return field_length / charset()->mbmaxlen; } - + virtual geometry_type get_geometry_type() + { + /* shouldn't get here. */ + DBUG_ASSERT(0); + } friend bool reopen_table(THD *,struct st_table *,bool); friend int cre_myisam(my_string name, register TABLE *form, uint options, ulonglong auto_increment_value); @@ -1325,6 +1329,7 @@ public: uint get_key_image(char *buff,uint length,imagetype type); uint size_of() const { return sizeof(*this); } int reset(void) { return !maybe_null() || Field_blob::reset(); } + geometry_type get_geometry_type() { return geom_type; }; }; #endif /*HAVE_SPATIAL*/ diff --git a/sql/item.cc b/sql/item.cc index 92ea35072f9..59708afdd19 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4317,7 +4317,9 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_GEOMETRY: return new Field_geom(max_length, maybe_null, name, table, (Field::geometry_type) - ((Item_geometry_func *)this)->get_geometry_type()); + ((type() == Item::TYPE_HOLDER) ? + ((Item_type_holder *)this)->get_geometry_type() : + ((Item_geometry_func *)this)->get_geometry_type())); } } @@ -6422,6 +6424,10 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item) if (Field::result_merge_type(fld_type) == INT_RESULT) decimals= 0; prev_decimal_int_part= item->decimal_int_part(); + if (item->field_type() == MYSQL_TYPE_GEOMETRY) + geometry_type= (item->type() == Item::FIELD_ITEM) ? + ((Item_field *)item)->get_geometry_type() : + (Field::geometry_type)((Item_geometry_func *)item)->get_geometry_type(); } diff --git a/sql/item.h b/sql/item.h index 11dce3a7758..96936f0ff88 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1304,6 +1304,11 @@ public: int fix_outer_field(THD *thd, Field **field, Item **reference); virtual Item *update_value_transformer(byte *select_arg); void print(String *str); + Field::geometry_type get_geometry_type() + { + DBUG_ASSERT(field_type() == MYSQL_TYPE_GEOMETRY); + return field->get_geometry_type(); + } friend class Item_default_value; friend class Item_insert_value; friend class st_select_lex_unit; @@ -2563,6 +2568,7 @@ class Item_type_holder: public Item protected: TYPELIB *enum_set_typelib; enum_field_types fld_type; + Field::geometry_type geometry_type; void get_full_info(Item *item); @@ -2582,6 +2588,7 @@ public: Field *make_field_by_type(TABLE *table); static uint32 display_length(Item *item); static enum_field_types get_real_type(Item *); + Field::geometry_type get_geometry_type() { return geometry_type; }; }; From 88d5c0146b78ddee5816fc256e9b2b0635df2445 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Jun 2007 15:04:39 -0700 Subject: [PATCH 08/20] Correction to remove compilee warnings and compiler errors on Windows. --- sql/field.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/field.h b/sql/field.h index 39378addd4c..ccdda7d04ce 100644 --- a/sql/field.h +++ b/sql/field.h @@ -364,6 +364,7 @@ public: { /* shouldn't get here. */ DBUG_ASSERT(0); + return GEOM_GEOMETRY; } friend bool reopen_table(THD *,struct st_table *,bool); friend int cre_myisam(my_string name, register TABLE *form, uint options, From d8e2f2622d29fb3c198d4895a1a06e2e61be476d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Jun 2007 22:35:31 -0700 Subject: [PATCH 09/20] Fixed bug #28811: crash for a query containing a subquery with ORDER BY and LIMIT 1. The bug was introduced by the patch for bug 21727. The patch erroneously skipped initialization of the array of headers for sorted records for non-first evaluations of the subquery. To fix the problem a new parameter has been added to the function make_char_array that performs the initialization. Now this function is called for any invocation of the filesort procedure. Yet it allocates the buffer for sorted records only if this parameter is NULL. mysql-test/r/subselect.result: Added a test case for bug #28811. mysql-test/t/subselect.test: Added a test case for bug #28811. --- mysql-test/r/subselect.result | 26 ++++++++++++++++++++++++++ mysql-test/t/subselect.test | 32 ++++++++++++++++++++++++++++++++ sql/filesort.cc | 19 +++++++++++-------- 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 38f6e2d10e3..efd6a5ab572 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4080,4 +4080,30 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1003 select `res`.`count(*)` AS `count(*)` from (select count(0) AS `count(*)` from `test`.`t1` group by `test`.`t1`.`a`) `res` DROP TABLE t1; +CREATE TABLE t1 ( +a varchar(255) default NULL, +b timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, +INDEX idx(a,b) +); +CREATE TABLE t2 ( +a varchar(255) default NULL +); +INSERT INTO t1 VALUES ('abcdefghijk','2007-05-07 06:00:24'); +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO `t1` VALUES ('asdf','2007-02-08 01:11:26'); +INSERT INTO `t2` VALUES ('abcdefghijk'); +INSERT INTO `t2` VALUES ('asdf'); +SET session sort_buffer_size=8192; +SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.a ORDER BY t1.b LIMIT 1) AS d1 FROM t2; +d1 +1 +1 +DROP TABLE t1,t2; End of 5.0 tests. diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 33e58fe0c32..12688fa4cf4 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2913,4 +2913,36 @@ SELECT * FROM (SELECT count(*) FROM t1 GROUP BY a) as res; DROP TABLE t1; +# +# Bug #28811: crash for query containing subquery with ORDER BY and LIMIT 1 +# + +CREATE TABLE t1 ( + a varchar(255) default NULL, + b timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + INDEX idx(a,b) +); +CREATE TABLE t2 ( + a varchar(255) default NULL +); + +INSERT INTO t1 VALUES ('abcdefghijk','2007-05-07 06:00:24'); +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO `t1` VALUES ('asdf','2007-02-08 01:11:26'); +INSERT INTO `t2` VALUES ('abcdefghijk'); +INSERT INTO `t2` VALUES ('asdf'); + +SET session sort_buffer_size=8192; + +SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.a ORDER BY t1.b LIMIT 1) AS d1 FROM t2; + +DROP TABLE t1,t2; + --echo End of 5.0 tests. diff --git a/sql/filesort.cc b/sql/filesort.cc index a4bf04a6786..d518ddbb117 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -35,7 +35,8 @@ if (my_b_write((file),(byte*) (from),param->ref_length)) \ /* functions defined in this file */ -static char **make_char_array(register uint fields, uint length, myf my_flag); +static char **make_char_array(char **old_pos, register uint fields, + uint length, myf my_flag); static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffer_file, uint count); static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select, uchar * *sort_keys, IO_CACHE *buffer_file, @@ -202,9 +203,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, ulong old_memavl; ulong keys= memavl/(param.rec_length+sizeof(char*)); param.keys=(uint) min(records+1, keys); - if (table_sort.sort_keys || - (table_sort.sort_keys= (uchar **) make_char_array(param.keys, param.rec_length, - MYF(0)))) + if ((table_sort.sort_keys= + (uchar **) make_char_array((char **) table_sort.sort_keys, + param.keys, param.rec_length, MYF(0)))) break; old_memavl=memavl; if ((memavl=memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory) @@ -346,14 +347,16 @@ void filesort_free_buffers(TABLE *table, bool full) /* Make a array of string pointers */ -static char **make_char_array(register uint fields, uint length, myf my_flag) +static char **make_char_array(char **old_pos, register uint fields, + uint length, myf my_flag) { register char **pos; - char **old_pos,*char_pos; + char *char_pos; DBUG_ENTER("make_char_array"); - if ((old_pos= (char**) my_malloc((uint) fields*(length+sizeof(char*)), - my_flag))) + if (old_pos || + (old_pos= (char**) my_malloc((uint) fields*(length+sizeof(char*)), + my_flag))) { pos=old_pos; char_pos=((char*) (pos+fields)) -length; while (fields--) *(pos++) = (char_pos+= length); From 5031a418e59ece8855ddf2bf34a457bc1df2ab5d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Jun 2007 14:42:08 +0500 Subject: [PATCH 10/20] Bug#18660 Can't grant any privileges on single table in database with underscore char In case of database level grant the database name may be a pattern, in case of table|column level grant the database name can not be a pattern. We use 'dont_check_global_grants' as a flag to determine if it's database level grant command (see SQLCOM_GRANT case, mysql_execute_command() function) and set db_is_pattern according to 'dont_check_global_grants' value. mysql-test/r/grant2.result: test result mysql-test/t/grant2.test: test case sql/sql_parse.cc: In case of database level grant the database name may be a pattern, in case of table|column level grant the database name can not be a pattern. We use 'dont_check_global_grants' as a flag to determine if it's database level grant command (see SQLCOM_GRANT case, mysql_execute_command() function) and set db_is_pattern according to 'dont_check_global_grants' value. --- mysql-test/r/grant2.result | 18 ++++++++++++++++++ mysql-test/t/grant2.test | 30 ++++++++++++++++++++++++++++++ sql/sql_parse.cc | 12 +++++++++++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index 93098e68070..6de9a83aeed 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -403,4 +403,22 @@ use test; drop database mysqltest_1; drop database mysqltest_2; drop user mysqltest_u1@localhost; +grant all on `mysqltest\_%`.* to mysqltest_1@localhost with grant option; +grant usage on *.* to mysqltest_2@localhost; +create database mysqltest_1; +use mysqltest_1; +create table t1 (f1 int); +grant create on `mysqltest\_1`.* to mysqltest_2@localhost; +grant select on mysqltest_1.t1 to mysqltest_2@localhost; +create database mysqltest_3; +ERROR 42000: Access denied for user 'mysqltest_2'@'localhost' to database 'mysqltest_3' +use mysqltest_1; +create table t2(f1 int); +select * from t1; +f1 +drop database mysqltest_1; +revoke all privileges, grant option from mysqltest_1@localhost; +revoke all privileges, grant option from mysqltest_2@localhost; +drop user mysqltest_1@localhost; +drop user mysqltest_2@localhost; End of 5.0 tests diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index 4a3324b1833..a3a8e2d5d53 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -555,5 +555,35 @@ drop database mysqltest_1; drop database mysqltest_2; drop user mysqltest_u1@localhost; +# +# Bug#18660 Can't grant any privileges on single table in database +# with underscore char +# +grant all on `mysqltest\_%`.* to mysqltest_1@localhost with grant option; +grant usage on *.* to mysqltest_2@localhost; +connect (con18600_1,localhost,mysqltest_1,,); + +create database mysqltest_1; +use mysqltest_1; +create table t1 (f1 int); + +grant create on `mysqltest\_1`.* to mysqltest_2@localhost; +grant select on mysqltest_1.t1 to mysqltest_2@localhost; +connect (con3,localhost,mysqltest_2,,); +connection con3; +--error 1044 +create database mysqltest_3; +use mysqltest_1; +create table t2(f1 int); +select * from t1; +connection default; +drop database mysqltest_1; + +revoke all privileges, grant option from mysqltest_1@localhost; +revoke all privileges, grant option from mysqltest_2@localhost; +drop user mysqltest_1@localhost; +drop user mysqltest_2@localhost; + + --echo End of 5.0 tests diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6277a6c0c10..77525b49fdf 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5252,7 +5252,17 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, Security_context *sctx= thd->security_ctx; #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; - bool db_is_pattern= test(want_access & GRANT_ACL); + /* + GRANT command: + In case of database level grant the database name may be a pattern, + in case of table|column level grant the database name can not be a pattern. + We use 'dont_check_global_grants' as a flag to determine + if it's database level grant command + (see SQLCOM_GRANT case, mysql_execute_command() function) and + set db_is_pattern according to 'dont_check_global_grants' value. + */ + bool db_is_pattern= (test(want_access & GRANT_ACL) && + dont_check_global_grants); #endif ulong dummy; DBUG_ENTER("check_access"); From 2b274a60d55fb76c4b903350352de29efc25dc6d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Jun 2007 13:42:10 +0300 Subject: [PATCH 11/20] Bug #28754: RPM builds differ from tar.gz in "ALTER ... RENAME" on views When constructing the path to the original .frm file ALTER .. RENAME was unnecessary (and incorrectly) lowercasing the whole path when not on a case-insensitive filesystem. This path should not be modified because of lower_case_table_names as it is already in the correct case according to that setting. Fixed by removing the lowercasing. Unfortunately testing this would require running the tests on a case sensitive filesystem in a directory that has uppercase letters. This cannot be guaranteed in all setups so no test case added. sql/sql_table.cc: Bug #28754: don't downcase the .frm path --- sql/sql_table.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 29ecf43a531..a44b087202b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3101,8 +3101,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, alter_info->tablespace_op)); sprintf(new_name_buff,"%s/%s/%s%s",mysql_data_home, db, table_name, reg_ext); unpack_filename(new_name_buff, new_name_buff); - if (lower_case_table_names != 2) - my_casedn_str(files_charset_info, new_name_buff); frm_type= mysql_frm_type(thd, new_name_buff, &table_type); /* Rename a view */ if (frm_type == FRMTYPE_VIEW && !(alter_info->flags & ~ALTER_RENAME)) From 99b4321ac5e577b965adf3fa0db6f5ae92450fe1 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 9 Jun 2007 00:39:23 +0500 Subject: [PATCH 12/20] Bug #28333 Test "flush" tries to create a new thread - on only one platform on PPC/Debian Linux default stack size for a thread is too big. As we use default thread settings in mysqltest, the thread creation fails if we create lots of threads (as it happens in flush.test). So now stack size is explicitly specified for the mysqltest client/mysqltest.c: Bug #28333 Test "flush" tries to create a new thread - on only one platform specify appropriate stack size for the 'query' thread --- client/mysqltest.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 5640d0c24ba..77cdb93dfe5 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -496,6 +496,10 @@ void handle_error(struct st_command*, void handle_no_error(struct st_command*); #ifdef EMBEDDED_LIBRARY + +/* attributes of the query thread */ +pthread_attr_t cn_thd_attrib; + /* send_one_query executes query in separate thread what is necessary in embedded library to run 'send' in proper way. @@ -534,7 +538,7 @@ static int do_send_query(struct st_connection *cn, const char *q, int q_len, cn->cur_query= q; cn->cur_query_len= q_len; cn->query_done= 0; - if (pthread_create(&tid, NULL, send_one_query, (void*)cn)) + if (pthread_create(&tid, &cn_thd_attrib, send_one_query, (void*)cn)) die("Cannot start new thread for query"); return 0; @@ -5999,6 +6003,12 @@ int main(int argc, char **argv) next_con= connections + 1; cur_con= connections; +#ifdef EMBEDDED_LIBRARY + /* set appropriate stack for the 'query' threads */ + (void) pthread_attr_init(&cn_thd_attrib); + pthread_attr_setstacksize(&cn_thd_attrib, DEFAULT_THREAD_STACK); +#endif /*EMBEDDED_LIBRARY*/ + /* Init file stack */ memset(file_stack, 0, sizeof(file_stack)); file_stack_end= From ce4e9f7580c02d1e7c5587bccb3a2a2ed7b0cc69 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 9 Jun 2007 16:52:37 +0500 Subject: [PATCH 13/20] Bug#28266 IS_UPDATABLE field on VIEWS table in I_S database is wrong IS_UPDATABLE flag is set to 'yes' when the view has at least one updatable column and the algorithm is not 'temporary'. mysql-test/r/information_schema.result: test result mysql-test/r/view.result: test result mysql-test/t/information_schema.test: test case mysql-test/t/view.test: test case sql/sql_show.cc: IS_UPDATABLE flag is set to 'yes' when the view has at least one updatable column and the algorithm is not 'temporary'. --- mysql-test/r/information_schema.result | 11 ++++++++++ mysql-test/r/view.result | 13 +++++++++++ mysql-test/t/information_schema.test | 15 +++++++++++++ mysql-test/t/view.test | 4 ++++ sql/sql_show.cc | 30 +++++++++++++++++++++++++- 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index db703df1f52..4947fd7aecc 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1315,3 +1315,14 @@ TABLE_PRIVILEGES information_schema.TABLE_PRIVILEGES 1 TRIGGERS information_schema.TRIGGERS 1 USER_PRIVILEGES information_schema.USER_PRIVILEGES 1 VIEWS information_schema.VIEWS 1 +create table t1(f1 int); +create view v1 as select f1+1 as a from t1; +create table t2 (f1 int, f2 int); +create view v2 as select f1+1 as a, f2 as b from t2; +select table_name, is_updatable from information_schema.views; +table_name is_updatable +v1 NO +v2 YES +delete from v1; +drop view v1,v2; +drop table t1,t2; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 43e147724c8..3757c5fd451 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -23,6 +23,9 @@ c 5 6 11 +select is_updatable from information_schema.views where table_name='v1'; +is_updatable +NO create temporary table t1 (a int, b int); select * from t1; a b @@ -322,6 +325,12 @@ create table t1 (a int, b int, primary key(a)); insert into t1 values (10,2), (20,3), (30,4), (40,5), (50,10); create view v1 (a,c) as select a, b+1 from t1; create algorithm=temptable view v2 (a,c) as select a, b+1 from t1; +select is_updatable from information_schema.views where table_name='v2'; +is_updatable +NO +select is_updatable from information_schema.views where table_name='v1'; +is_updatable +YES update v1 set c=a+c; ERROR HY000: Column 'c' is not updatable update v2 set a=a+c; @@ -604,6 +613,10 @@ insert into t1 values(5,'Hello, world of views'); create view v1 as select * from t1; create view v2 as select * from v1; update v2 set col2='Hello, view world'; +select is_updatable from information_schema.views; +is_updatable +YES +YES select * from t1; col1 col2 5 Hello, view world diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index f8922317eb3..1d368ac6075 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1023,4 +1023,19 @@ where t.table_schema = 'information_schema' and group by c2.column_type order by num limit 1) group by t.table_name order by num1, t.table_name; +# +# Bug#28266 IS_UPDATABLE field on VIEWS table in I_S database is wrong +# +create table t1(f1 int); +create view v1 as select f1+1 as a from t1; +create table t2 (f1 int, f2 int); +create view v2 as select f1+1 as a, f2 as b from t2; +select table_name, is_updatable from information_schema.views; +# +# Note: we can perform 'delete' for non updatable view. +# +delete from v1; +drop view v1,v2; +drop table t1,t2; + # End of 5.0 tests. diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index f574451af08..3c370da4139 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -32,6 +32,7 @@ create view v1 (c,d) as select a,b from t1 # simple view create view v1 (c) as select b+1 from t1; select c from v1; +select is_updatable from information_schema.views where table_name='v1'; # temporary table should not hide table of view create temporary table t1 (a int, b int); @@ -228,6 +229,8 @@ create table t1 (a int, b int, primary key(a)); insert into t1 values (10,2), (20,3), (30,4), (40,5), (50,10); create view v1 (a,c) as select a, b+1 from t1; create algorithm=temptable view v2 (a,c) as select a, b+1 from t1; +select is_updatable from information_schema.views where table_name='v2'; +select is_updatable from information_schema.views where table_name='v1'; # try to update expression -- error 1348 update v1 set c=a+c; @@ -497,6 +500,7 @@ insert into t1 values(5,'Hello, world of views'); create view v1 as select * from t1; create view v2 as select * from v1; update v2 set col2='Hello, view world'; +select is_updatable from information_schema.views; select * from t1; drop view v2, v1; drop table t1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 16ed20cd479..a0db458be78 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3158,6 +3158,7 @@ static int get_schema_views_record(THD *thd, struct st_table_list *tables, DBUG_ENTER("get_schema_views_record"); char definer[USER_HOST_BUFF_SIZE]; uint definer_len; + bool updatable_view; if (tables->view) { @@ -3195,7 +3196,34 @@ static int get_schema_views_record(THD *thd, struct st_table_list *tables, else table->field[4]->store(STRING_WITH_LEN("NONE"), cs); - if (tables->updatable_view) + updatable_view= 0; + if (tables->algorithm != VIEW_ALGORITHM_TMPTABLE) + { + /* + We should use tables->view->select_lex.item_list here and + can not use Field_iterator_view because the view always uses + temporary algorithm during opening for I_S and + TABLE_LIST fields 'field_translation' & 'field_translation_end' + are uninitialized is this case. + */ + List *fields= &tables->view->select_lex.item_list; + List_iterator it(*fields); + Item *item; + Item_field *field; + /* + chech that at least one coulmn in view is updatable + */ + while ((item= it++)) + { + if ((field= item->filed_for_view_update()) && field->field && + !field->field->table->pos_in_table_list->schema_table) + { + updatable_view= 1; + break; + } + } + } + if (updatable_view) table->field[5]->store(STRING_WITH_LEN("YES"), cs); else table->field[5]->store(STRING_WITH_LEN("NO"), cs); From 71aa571d09a0823dcf0b1528f6f0103a7adfcf72 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 9 Jun 2007 17:46:09 +0500 Subject: [PATCH 14/20] Bug#28149 overflow in some "SHOW STATUS"-variables changed bytes_received, bytes_sent status variables to longlong sql/mysqld.cc: changed bytes_received, bytes_sent status variables to longlong sql/sql_class.h: changed bytes_received, bytes_sent status variables to longlong sql/sql_show.cc: changed bytes_received, bytes_sent status variables to longlong sql/structs.h: changed bytes_received, bytes_sent status variables to longlong --- sql/mysqld.cc | 4 ++-- sql/sql_class.h | 4 ++-- sql/sql_show.cc | 2 ++ sql/structs.h | 3 ++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5dfb191c142..ca6bcff3b45 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6190,8 +6190,8 @@ struct show_var_st status_vars[]= { {"Aborted_connects", (char*) &aborted_connects, SHOW_LONG}, {"Binlog_cache_disk_use", (char*) &binlog_cache_disk_use, SHOW_LONG}, {"Binlog_cache_use", (char*) &binlog_cache_use, SHOW_LONG}, - {"Bytes_received", (char*) offsetof(STATUS_VAR, bytes_received), SHOW_LONG_STATUS}, - {"Bytes_sent", (char*) offsetof(STATUS_VAR, bytes_sent), SHOW_LONG_STATUS}, + {"Bytes_received", (char*) offsetof(STATUS_VAR, bytes_received), SHOW_LONGLONG_STATUS}, + {"Bytes_sent", (char*) offsetof(STATUS_VAR, bytes_sent), SHOW_LONGLONG_STATUS}, {"Com_admin_commands", (char*) offsetof(STATUS_VAR, com_other), SHOW_LONG_STATUS}, {"Com_alter_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_DB]), SHOW_LONG_STATUS}, {"Com_alter_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_TABLE]), SHOW_LONG_STATUS}, diff --git a/sql/sql_class.h b/sql/sql_class.h index 2ff5448f3e4..50c45d461e0 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -606,8 +606,8 @@ struct system_variables typedef struct system_status_var { - ulong bytes_received; - ulong bytes_sent; + ulonglong bytes_received; + ulonglong bytes_sent; ulong com_other; ulong com_stat[(uint) SQLCOM_END]; ulong created_tmp_disk_tables; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a0db458be78..902b298e423 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1463,6 +1463,8 @@ static bool show_status_array(THD *thd, const char *wild, case SHOW_LONG_CONST: end= int10_to_str(*(long*) value, buff, 10); break; + case SHOW_LONGLONG_STATUS: + value= ((char *) status_var + (ulonglong) value); case SHOW_LONGLONG: end= longlong10_to_str(*(longlong*) value, buff, 10); break; diff --git a/sql/structs.h b/sql/structs.h index de4cc25db9f..28bdd8c1519 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -190,7 +190,8 @@ enum SHOW_TYPE SHOW_NET_COMPRESSION, SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING, SHOW_SLAVE_RETRIED_TRANS, SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG, SHOW_KEY_CACHE_LONGLONG, - SHOW_LONG_STATUS, SHOW_LONG_CONST_STATUS, SHOW_SLAVE_SKIP_ERRORS + SHOW_LONG_STATUS, SHOW_LONG_CONST_STATUS, SHOW_SLAVE_SKIP_ERRORS, + SHOW_LONGLONG_STATUS }; enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED}; From 59d139eb293e1bcf72cf544e2b8dbe9216ee7acb Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 9 Jun 2007 18:18:34 +0500 Subject: [PATCH 15/20] compiler warning fix --- sql/item_strfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index f9a0f715985..33e9b8de823 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3334,7 +3334,7 @@ String *Item_func_uuid::val_str(String *str) *--s=_dig_vec_lower[mac[i] >> 4]; } randominit(&uuid_rand, tmp + (ulong) server_start_time, - tmp + thd->status_var.bytes_sent); + tmp + (ulong) thd->status_var.bytes_sent); set_clock_seq_str(); } From ccf393b67a9bcf52db91806f49c940ccd08545cc Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Jun 2007 01:41:23 +0400 Subject: [PATCH 16/20] Bug#28904: INSERT .. ON DUPLICATE was silently updating rows when it shouldn't. When the INSERT .. ON DUPLICATE KEY UPDATE has to update a matched row but the new data is the same as in the record then it returns as if no rows were inserted or updated. Nevertheless the row is silently updated. This leads to a situation when zero updated rows are reported in the case when data has actually been changed. Now the write_record function updates a row only if new data differs from that in the record. sql/sql_insert.cc: Bug#28904: INSERT .. ON DUPLICATE was silently updating rows when it shouldn't. Now the write_record function updates a row only if new data differs from that in the record. mysql-test/r/insert_update.result: Added a test case for the bug#28904: INSERT .. ON DUPLICATE was silently updating rows when it shouldn't. mysql-test/t/insert_update.test: Added a test case for the bug#28904: INSERT .. ON DUPLICATE was silently updating rows when it shouldn't. --- mysql-test/r/insert_update.result | 14 ++++++++++++++ mysql-test/t/insert_update.test | 16 ++++++++++++++++ sql/sql_insert.cc | 28 ++++++++++++++-------------- 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index b3bca7517f3..20cde86101e 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -393,3 +393,17 @@ id c1 cnt 1 0 3 2 2 1 DROP TABLE t1; +create table t1(f1 int primary key, +f2 timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP); +insert into t1(f1) values(1); +select @stamp1:=f2 from t1; +@stamp1:=f2 +# +insert into t1(f1) values(1) on duplicate key update f1=1; +select @stamp2:=f2 from t1; +@stamp2:=f2 +# +select if( @stamp1 = @stamp2, "correct", "wrong"); +if( @stamp1 = @stamp2, "correct", "wrong") +correct +drop table t1; diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 725fbdb25d7..67108744ec6 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -290,3 +290,19 @@ INSERT IGNORE INTO t1 (id,c1) SELECT * FROM t2 SELECT * FROM t1; DROP TABLE t1; + +# +# Bug#28904: INSERT .. ON DUPLICATE was silently updating rows when it +# shouldn't. +# +create table t1(f1 int primary key, + f2 timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP); +insert into t1(f1) values(1); +--replace_column 1 # +select @stamp1:=f2 from t1; +--sleep 2 +insert into t1(f1) values(1) on duplicate key update f1=1; +--replace_column 1 # +select @stamp2:=f2 from t1; +select if( @stamp1 = @stamp2, "correct", "wrong"); +drop table t1; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f3ed3ebab24..228fc8860ae 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1404,23 +1404,18 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) goto before_trg_err; table->file->restore_auto_increment(); - if ((error=table->file->update_row(table->record[1],table->record[0]))) - { - if ((error == HA_ERR_FOUND_DUPP_KEY) && info->ignore) - { - goto ok_or_after_trg_err; - } - goto err; - } - - if (table->next_number_field) - table->file->adjust_next_insert_id_after_explicit_value( - table->next_number_field->val_int()); - info->touched++; - if ((table->file->table_flags() & HA_PARTIAL_COLUMN_READ) || compare_record(table, thd->query_id)) { + if ((error=table->file->update_row(table->record[1],table->record[0]))) + { + if ((error == HA_ERR_FOUND_DUPP_KEY) && info->ignore) + { + goto ok_or_after_trg_err; + } + goto err; + } + info->updated++; trg_error= (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, @@ -1429,6 +1424,11 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) info->copied++; } + if (table->next_number_field) + table->file->adjust_next_insert_id_after_explicit_value( + table->next_number_field->val_int()); + info->touched++; + goto ok_or_after_trg_err; } else /* DUP_REPLACE */ From e164c08eafb005aa42da3fda2c97e374ee205c9b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Jun 2007 11:02:34 +0300 Subject: [PATCH 17/20] Bug #28934: server crash when receiving malformed com_execute packets Sometimes a parameter slot may not get a value because of the protocol data being plain wrong. Such cases should be detected and handled by returning an error. Fixed by checking data stream constraints where possible (like maximum length) and reacting to the case where a value cannot be constructed. sql/sql_prepare.cc: Bug #28934: - check for a parameter slot not being set because of wrong data - check if the length read from the stream is not greater than the maximum length of the field tests/mysql_client_test.c: Bug #28934: test case --- sql/sql_prepare.cc | 10 +++++ tests/mysql_client_test.c | 83 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 42655608196..1453a377600 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -562,6 +562,8 @@ void set_param_date(Item_param *param, uchar **pos, ulong len) static void set_param_str(Item_param *param, uchar **pos, ulong len) { ulong length= get_param_length(pos, len); + if (length > len) + length= len; param->set_str((const char *)*pos, length); *pos+= length; } @@ -731,6 +733,8 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, if (read_pos >= data_end) DBUG_RETURN(1); param->set_param_func(param, &read_pos, data_end - read_pos); + if (param->state == Item_param::NO_VALUE) + DBUG_RETURN(1); } } res= param->query_val_str(&str); @@ -767,6 +771,8 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array, if (read_pos >= data_end) DBUG_RETURN(1); param->set_param_func(param, &read_pos, data_end - read_pos); + if (param->state == Item_param::NO_VALUE) + DBUG_RETURN(1); } } if (param->convert_str_value(stmt->thd)) @@ -849,6 +855,8 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query) client_param->length ? *client_param->length : client_param->buffer_length); + if (param->state == Item_param::NO_VALUE) + DBUG_RETURN(1); } } if (param->convert_str_value(thd)) @@ -890,6 +898,8 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) client_param->length ? *client_param->length : client_param->buffer_length); + if (param->state == Item_param::NO_VALUE) + DBUG_RETURN(1); } } res= param->query_val_str(&str); diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 54d29dbd683..7fc45b89b82 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15686,6 +15686,88 @@ end: } +/* + Bug#28934: server crash when receiving malformed com_execute packets +*/ + +static void test_bug28934() +{ + MYSQL *l_mysql; + my_bool error= 0; + my_ulonglong res; + MYSQL_BIND bind[5]; + MYSQL_STMT *stmt; + int cnt; + + if (!(l_mysql= mysql_init(NULL))) + { + myerror("mysql_init() failed"); + DIE_UNLESS(1); + } + if (!(mysql_real_connect(l_mysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_FOUND_ROWS))) + { + myerror("connection failed"); + error= 1; + goto end; + } + l_mysql->reconnect= 1; + if (mysql_query(l_mysql, "drop table if exists t1")) + { + myerror(NULL); + error= 1; + goto end; + } + if (mysql_query(l_mysql, "create table t1(id int)")) + { + myerror(NULL); + error= 1; + goto end; + } + if (mysql_query(l_mysql, "insert into t1 values(1),(2),(3),(4),(5)")) + { + myerror(NULL); + error= 1; + goto end; + } + if (!(stmt= mysql_simple_prepare(l_mysql, + "select * from t1 where id in(?,?,?,?,?)"))) + { + myerror(NULL); + error= 1; + goto end; + } + + memset (&bind, 0, sizeof (bind)); + for (cnt= 0; cnt < 5; cnt++) + { + bind[cnt].buffer_type= MYSQL_TYPE_LONG; + bind[cnt].buffer= (char*)&cnt; + bind[cnt].buffer_length= 0; + } + if(mysql_stmt_bind_param(stmt, bind)) + { + myerror(NULL); + error= 1; + goto end; + } + stmt->param_count=2; + error= mysql_stmt_execute(stmt); + DIE_UNLESS (error != 0); + myerror(NULL); + error= 0; + if (mysql_query(l_mysql, "drop table t1")) + { + myerror(NULL); + error= 1; + } +end: + mysql_close(l_mysql); + DIE_UNLESS(error == 0); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -15968,6 +16050,7 @@ static struct my_tests_st my_tests[]= { { "test_bug24179", test_bug24179 }, { "test_bug27876", test_bug27876 }, { "test_bug28505", test_bug28505 }, + { "test_bug28934", test_bug28934 }, { 0, 0 } }; From 030bb02b69944448b5fb5515d4f1cea26c57fa54 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Jun 2007 14:35:36 +0300 Subject: [PATCH 18/20] Bug #28992: trigger fails in pushbuild - fixed wrong test case for bug 20903 - closed the dangling connections in trigger.test - GET_LOCK() and RELEASE_LOCK() now produce more detailed log - fixed an omission in GET_LOCK() : assign the thread_id when acquiring the lock. mysql-test/r/trigger.result: Bug #28992: test case updated mysql-test/t/trigger.test: Bug #28992: test case updated. dangling connections closed. sql/item_func.cc: Bug #28992: - GET_LOCK() and RELEASE_LOCK() now produce more detailed log - fixed an omission in GET_LOCK() : assign the thread_id when acquiring the lock. --- mysql-test/r/trigger.result | 15 ++++++++------ mysql-test/t/trigger.test | 21 ++++++++++++++----- sql/item_func.cc | 41 +++++++++++++++++++++++++------------ 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index fd9b15ab8ed..5405a632aa4 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -1454,19 +1454,22 @@ CREATE TABLE t2 (id INTEGER); INSERT INTO t2 VALUES (1),(2); CREATE TRIGGER t1_test AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (new.id); -SELECT GET_LOCK('B26162',20); -GET_LOCK('B26162',20) +SELECT GET_LOCK('B26162',120); +GET_LOCK('B26162',120) 1 -SELECT 'rl_acquirer', GET_LOCK('B26162',5), id FROM t2 WHERE id = 1; +SELECT 'rl_acquirer', GET_LOCK('B26162',120), id FROM t2 WHERE id = 1; SET SESSION LOW_PRIORITY_UPDATES=1; SET GLOBAL LOW_PRIORITY_UPDATES=1; INSERT INTO t1 VALUES (5); SELECT 'rl_contender', id FROM t2 WHERE id > 1; SELECT RELEASE_LOCK('B26162'); RELEASE_LOCK('B26162') -0 -rl_acquirer GET_LOCK('B26162',5) id -rl_acquirer 0 1 +1 +rl_acquirer GET_LOCK('B26162',120) id +rl_acquirer 1 1 +SELECT RELEASE_LOCK('B26162'); +RELEASE_LOCK('B26162') +1 rl_contender id rl_contender 2 DROP TRIGGER t1_test; diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 363df94eeb3..7158d02956e 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -1763,6 +1763,9 @@ select * from t1; select * from t3; drop table t1, t2, t3; +disconnect addconroot1; +disconnect addconroot2; +disconnect addconwithoutdb; # # Bug #26162: Trigger DML ignores low_priority_updates setting # @@ -1776,19 +1779,23 @@ INSERT INTO t2 VALUES (1),(2); CREATE TRIGGER t1_test AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (new.id); +CONNECT (rl_holder, localhost, root,,); CONNECT (rl_acquirer, localhost, root,,); CONNECT (wl_acquirer, localhost, root,,); CONNECT (rl_contender, localhost, root,,); -SELECT GET_LOCK('B26162',20); +CONNECTION rl_holder; +SELECT GET_LOCK('B26162',120); CONNECTION rl_acquirer; --send -SELECT 'rl_acquirer', GET_LOCK('B26162',5), id FROM t2 WHERE id = 1; +SELECT 'rl_acquirer', GET_LOCK('B26162',120), id FROM t2 WHERE id = 1; CONNECTION wl_acquirer; SET SESSION LOW_PRIORITY_UPDATES=1; SET GLOBAL LOW_PRIORITY_UPDATES=1; +#need to wait for rl_acquirer to lock on the B26162 lock +sleep 2; --send INSERT INTO t1 VALUES (5); @@ -1798,13 +1805,16 @@ CONNECTION rl_contender; --send SELECT 'rl_contender', id FROM t2 WHERE id > 1; -CONNECTION default; +CONNECTION rl_holder; +#need to wait for wl_acquirer and rl_contender to lock on t2 +sleep 2; SELECT RELEASE_LOCK('B26162'); -CONNECTION wl_acquirer; ---reap CONNECTION rl_acquirer; --reap +SELECT RELEASE_LOCK('B26162'); +CONNECTION wl_acquirer; +--reap CONNECTION rl_contender; --reap @@ -1812,6 +1822,7 @@ CONNECTION default; DISCONNECT rl_acquirer; DISCONNECT wl_acquirer; DISCONNECT rl_contender; +DISCONNECT rl_holder; DROP TRIGGER t1_test; DROP TABLE t1,t2; diff --git a/sql/item_func.cc b/sql/item_func.cc index 580d19fbd4e..cc8830c6d6f 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3449,6 +3449,7 @@ longlong Item_func_get_lock::val_int() THD *thd=current_thd; User_level_lock *ull; int error; + DBUG_ENTER("Item_func_get_lock::val_int"); /* In slave thread no need to get locks, everything is serialized. Anyway @@ -3458,7 +3459,7 @@ longlong Item_func_get_lock::val_int() it's not guaranteed to be same as on master. */ if (thd->slave_thread) - return 1; + DBUG_RETURN(1); pthread_mutex_lock(&LOCK_user_locks); @@ -3466,8 +3467,10 @@ longlong Item_func_get_lock::val_int() { pthread_mutex_unlock(&LOCK_user_locks); null_value=1; - return 0; + DBUG_RETURN(0); } + DBUG_PRINT("info", ("lock %.*s, thd=%ld", res->length(), res->ptr(), + (long) thd->real_id)); null_value=0; if (thd->ull) @@ -3486,14 +3489,17 @@ longlong Item_func_get_lock::val_int() delete ull; pthread_mutex_unlock(&LOCK_user_locks); null_value=1; // Probably out of memory - return 0; + DBUG_RETURN(0); } ull->thread=thd->real_id; + ull->thread_id=thd->thread_id; thd->ull=ull; pthread_mutex_unlock(&LOCK_user_locks); - return 1; // Got new lock + DBUG_PRINT("info", ("made new lock")); + DBUG_RETURN(1); // Got new lock } ull->count++; + DBUG_PRINT("info", ("ull->count=%d", ull->count)); /* Structure is now initialized. Try to get the lock. @@ -3507,9 +3513,13 @@ longlong Item_func_get_lock::val_int() error= 0; while (ull->locked && !thd->killed) { + DBUG_PRINT("info", ("waiting on lock")); error= pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime); if (error == ETIMEDOUT || error == ETIME) + { + DBUG_PRINT("info", ("lock wait timeout")); break; + } error= 0; } @@ -3533,6 +3543,7 @@ longlong Item_func_get_lock::val_int() ull->thread_id= thd->thread_id; thd->ull=ull; error=0; + DBUG_PRINT("info", ("got the lock")); } pthread_mutex_unlock(&LOCK_user_locks); @@ -3542,7 +3553,7 @@ longlong Item_func_get_lock::val_int() thd->mysys_var->current_cond= 0; pthread_mutex_unlock(&thd->mysys_var->mutex); - return !error ? 1 : 0; + DBUG_RETURN(!error ? 1 : 0); } @@ -3560,11 +3571,14 @@ longlong Item_func_release_lock::val_int() String *res=args[0]->val_str(&value); User_level_lock *ull; longlong result; + THD *thd=current_thd; + DBUG_ENTER("Item_func_release_lock::val_int"); if (!res || !res->length()) { null_value=1; - return 0; + DBUG_RETURN(0); } + DBUG_PRINT("info", ("lock %.*s", res->length(), res->ptr())); null_value=0; result=0; @@ -3577,19 +3591,20 @@ longlong Item_func_release_lock::val_int() } else { -#ifdef EMBEDDED_LIBRARY - if (ull->locked && pthread_equal(current_thd->real_id,ull->thread)) -#else - if (ull->locked && pthread_equal(pthread_self(),ull->thread)) -#endif + DBUG_PRINT("info", ("ull->locked=%d ull->thread=%ld thd=%ld", + (int) ull->locked, + (long)ull->thread, + (long)thd->real_id)); + if (ull->locked && pthread_equal(thd->real_id,ull->thread)) { + DBUG_PRINT("info", ("release lock")); result=1; // Release is ok item_user_lock_release(ull); - current_thd->ull=0; + thd->ull=0; } } pthread_mutex_unlock(&LOCK_user_locks); - return result; + DBUG_RETURN(result); } From 119412f8d0cc364678e8e3b3c36c42e6fea69e3d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Jun 2007 14:45:30 +0300 Subject: [PATCH 19/20] removed compilation warning --- tests/mysql_client_test.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 7fc45b89b82..ed1f2d58278 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15694,7 +15694,6 @@ static void test_bug28934() { MYSQL *l_mysql; my_bool error= 0; - my_ulonglong res; MYSQL_BIND bind[5]; MYSQL_STMT *stmt; int cnt; From c0ebdff9c76c2b3e09bf5e44c22e68a35ef1affc Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 13 Jun 2007 09:32:36 -0700 Subject: [PATCH 20/20] Fixed bug #28980: the result of ROUND(,) was erroneously converted to double, while the result of ROUND(, ) was preserved as decimal. As a result of such a conversion the value of ROUND(D,A) could differ from the value of ROUND(D,val(A)) if D was a decimal expression. Now the result of the ROUND function is never converted to double if the first argument is decimal. mysql-test/r/type_decimal.result: Added a test case for bug #28980. mysql-test/t/type_decimal.test: Added a test case for bug #28980. --- mysql-test/r/type_decimal.result | 9 +++++++++ mysql-test/t/type_decimal.test | 14 ++++++++++++++ sql/item_func.cc | 8 +++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index c9c42d18d68..3cf24529421 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -790,3 +790,12 @@ Warning 1292 Truncated incorrect datetime value: '0000-00-00' Warning 1292 Truncated incorrect datetime value: '0000-00-00' Warning 1292 Truncated incorrect datetime value: '0000-00-00' drop table t1; +CREATE TABLE t1 ( +qty decimal(16,6) default NULL, +dps tinyint(3) unsigned default NULL +); +INSERT INTO t1 VALUES (1.1325,3); +SELECT ROUND(qty,3), dps, ROUND(qty,dps) FROM t1; +ROUND(qty,3) dps ROUND(qty,dps) +1.133 3 1.133 +DROP TABLE t1; diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 4fdb0c8458f..5538f19f5f9 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -394,3 +394,17 @@ create table t1 as from (select 1 as s,'t' as t union select null, null ) as sub1; select group_concat(t) from t1 group by week(date)/10; drop table t1; + +# +# Bug#28980: ROUND(, ) returned double values +# + +CREATE TABLE t1 ( + qty decimal(16,6) default NULL, + dps tinyint(3) unsigned default NULL +); +INSERT INTO t1 VALUES (1.1325,3); + +SELECT ROUND(qty,3), dps, ROUND(qty,dps) FROM t1; + +DROP TABLE t1; diff --git a/sql/item_func.cc b/sql/item_func.cc index cc8830c6d6f..ab4a9c50332 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1957,7 +1957,13 @@ void Item_func_round::fix_length_and_dec() { max_length= args[0]->max_length; decimals= args[0]->decimals; - hybrid_type= REAL_RESULT; + if (args[0]->result_type() == DECIMAL_RESULT) + { + max_length++; + hybrid_type= DECIMAL_RESULT; + } + else + hybrid_type= REAL_RESULT; return; }