From e40e8052e89ada24a79c827cf38271beed756759 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 16 Nov 2006 13:21:38 +0300 Subject: [PATCH 1/9] BUG#17047: CHAR() and IN() can return NULL without signaling NULL result The problem was that some functions (namely IN() starting with 4.1, and CHAR() starting with 5.0) were returning NULL in certain conditions, while they didn't set their maybe_null flag. Because of that there could be some problems with 'IS NULL' check, and statements that depend on the function value domain, like CREATE TABLE t1 SELECT 1 IN (2, NULL);. The fix is to set maybe_null correctly. mysql-test/r/func_in.result: Add result for bug#17047: CHAR() and IN() can return NULL without signaling NULL result. mysql-test/t/func_in.test: Add test case for bug#17047: CHAR() and IN() can return NULL without signaling NULL result. sql/item_cmpfunc.cc: Remove assignment to maybe_null, as it was already set in fix_fields() based on all arguments, not only on the first. --- mysql-test/r/func_in.result | 8 ++++++++ mysql-test/t/func_in.test | 22 +++++++++++++++++++++- sql/item_cmpfunc.cc | 1 - 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index 3cf2afc83d1..f74c63f7260 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -202,3 +202,11 @@ select count(*) from t1 where id not in (1,2); count(*) 1 drop table t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 SELECT 1 IN (2, NULL); +SELECT should return NULL. +SELECT * FROM t1; +1 IN (2, NULL) +NULL +DROP TABLE t1; +End of 4.1 tests diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index 2ffe5a2d5f7..ffed2aac2a0 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -109,4 +109,24 @@ select count(*) from t1 where id not in (1); select count(*) from t1 where id not in (1,2); drop table t1; -# End of 4.1 tests + +# +# BUG#17047: CHAR() and IN() can return NULL without signaling NULL +# result +# +# The problem was in the IN() function that ignored maybe_null flags +# of all arguments except the first (the one _before_ the IN +# keyword, '1' in the test case below). +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 SELECT 1 IN (2, NULL); +--echo SELECT should return NULL. +SELECT * FROM t1; + +DROP TABLE t1; + + +--echo End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6b6996160a1..859b4e0ecc1 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1998,7 +1998,6 @@ void Item_func_in::fix_length_and_dec() if (cmp_type == STRING_RESULT) in_item->cmp_charset= cmp_collation.collation; } - maybe_null= args[0]->maybe_null; max_length= 1; } From 2d04b1914de45129569d08dceb74f647f3004563 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 17 Nov 2006 12:21:32 +0300 Subject: [PATCH 2/9] BUG#23383: mysql_affected_rows() returns different values than mysql_stmt_affected_rows() The problem was that affected_rows for prepared statement wasn't updated in the client library on the error. The solution is to always update affected_rows, which will be equal to -1 on the error. libmysql/libmysql.c: Update status variables even in the case of an error. Some variables have a defined value on the error (like affected_rows is -1), others are undefined, so updating them won't harm. libmysqld/lib_sql.cc: Update status variables even in the case of an error. Some variables have a defined value on the error (like affected_rows is -1), others are undefined, so updating them won't harm. tests/mysql_client_test.c: Add test for bug#23383: mysql_affected_rows() returns different values than mysql_stmt_affected_rows(). --- libmysql/libmysql.c | 14 ++++--- libmysqld/lib_sql.cc | 14 ++++--- tests/mysql_client_test.c | 78 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 10 deletions(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 91c0b6b8864..a4dc382bc37 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2496,6 +2496,8 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length) NET *net= &mysql->net; char buff[4 /* size of stmt id */ + 5 /* execution flags */]; + my_bool res; + DBUG_ENTER("execute"); DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length)); @@ -2503,15 +2505,17 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length) int4store(buff, stmt->stmt_id); /* Send stmt id to server */ buff[4]= (char) 0; /* no flags */ int4store(buff+5, 1); /* iteration count */ - if (cli_advanced_command(mysql, COM_EXECUTE, buff, sizeof(buff), - packet, length, 1, NULL) || - (*mysql->methods->read_query_result)(mysql)) + + res= test(cli_advanced_command(mysql, COM_EXECUTE, buff, sizeof(buff), + packet, length, 1, NULL) || + (*mysql->methods->read_query_result)(mysql)); + stmt->affected_rows= mysql->affected_rows; + stmt->insert_id= mysql->insert_id; + if (res) { set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); DBUG_RETURN(1); } - stmt->affected_rows= mysql->affected_rows; - stmt->insert_id= mysql->insert_id; DBUG_RETURN(0); } diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 1a3e10f08a8..93d47595010 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -224,20 +224,24 @@ static int emb_stmt_execute(MYSQL_STMT *stmt) { DBUG_ENTER("emb_stmt_execute"); char header[4]; + my_bool res; + int4store(header, stmt->stmt_id); THD *thd= (THD*)stmt->mysql->thd; thd->client_param_count= stmt->param_count; thd->client_params= stmt->params; - if (emb_advanced_command(stmt->mysql, COM_EXECUTE,0,0, - header, sizeof(header), 1, stmt) || - emb_mysql_read_query_result(stmt->mysql)) + + res= test(emb_advanced_command(stmt->mysql, COM_EXECUTE,0,0, + header, sizeof(header), 1, stmt) || + emb_mysql_read_query_result(stmt->mysql)); + stmt->affected_rows= stmt->mysql->affected_rows; + stmt->insert_id= stmt->mysql->insert_id; + if (res) { NET *net= &stmt->mysql->net; set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); DBUG_RETURN(1); } - stmt->affected_rows= stmt->mysql->affected_rows; - stmt->insert_id= stmt->mysql->insert_id; DBUG_RETURN(0); } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index b1ee144e517..e123b2e42ae 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -11949,6 +11949,83 @@ static void test_bug21726() } +/* + BUG#23383: mysql_affected_rows() returns different values than + mysql_stmt_affected_rows() + + Test that both mysql_affected_rows() and mysql_stmt_affected_rows() + return -1 on error, 0 when no rows were affected, and (positive) row + count when some rows were affected. +*/ +static void test_bug23383() +{ + const char *insert_query= "INSERT INTO t1 VALUES (1), (2)"; + const char *update_query= "UPDATE t1 SET i= 4 WHERE i = 3"; + MYSQL_STMT *stmt; + my_ulonglong row_count; + int rc; + + DBUG_ENTER("test_bug23383"); + myheader("test_bug23383"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (i INT UNIQUE)"); + myquery(rc); + + rc= mysql_query(mysql, insert_query); + myquery(rc); + row_count= mysql_affected_rows(mysql); + DIE_UNLESS(row_count == 2); + + rc= mysql_query(mysql, insert_query); + DIE_UNLESS(rc != 0); + row_count= mysql_affected_rows(mysql); + DIE_UNLESS(row_count == (my_ulonglong)-1); + + rc= mysql_query(mysql, update_query); + myquery(rc); + row_count= mysql_affected_rows(mysql); + DIE_UNLESS(row_count == 0); + + rc= mysql_query(mysql, "DELETE FROM t1"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + DIE_UNLESS(stmt != 0); + + rc= mysql_stmt_prepare(stmt, insert_query, strlen(insert_query)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + row_count= mysql_stmt_affected_rows(stmt); + DIE_UNLESS(row_count == 2); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc != 0); + row_count= mysql_stmt_affected_rows(stmt); + DIE_UNLESS(row_count == (my_ulonglong)-1); + + rc= mysql_stmt_prepare(stmt, update_query, strlen(update_query)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + row_count= mysql_stmt_affected_rows(stmt); + DIE_UNLESS(row_count == 0); + + rc= mysql_stmt_close(stmt); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -12176,6 +12253,7 @@ static struct my_tests_st my_tests[]= { { "test_bug15613", test_bug15613 }, { "test_bug20152", test_bug20152 }, { "test_bug21726", test_bug21726 }, + { "test_bug23383", test_bug23383 }, { 0, 0 } }; From 7a45fb546fab6fe3fb2a26820ac39a8ee5cd45db Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Nov 2006 16:49:18 +0300 Subject: [PATCH 3/9] BUG#23159: prepared_stmt_count should be status variable Make Prepared_stmt_count a global status variable, accessible via SHOW STATUS LIKE 'Prepared_stmt_count';. Documentation should be updated. mysql-test/r/ps.result: Update result for bug#16365: Prepared Statements: DoS with too many open statements, according to bug#23159: prepared_stmt_count should be status variable. mysql-test/t/ps.test: Update test case for bug#16365: Prepared Statements: DoS with too many open statements, according to bug#23159: prepared_stmt_count should be status variable. sql/mysqld.cc: Add Prepared_stmt_count as global status variable. sql/set_var.cc: Remove prepared_stmt_count as system variable. --- mysql-test/r/ps.result | 101 +++++++++++++++++++++-------------------- mysql-test/t/ps.test | 57 ++++++++++------------- sql/mysqld.cc | 2 + sql/set_var.cc | 14 ------ 4 files changed, 79 insertions(+), 95 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 2bb5df6e6cf..94c51fdc18b 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -775,12 +775,12 @@ set @old_max_prepared_stmt_count= @@max_prepared_stmt_count; show variables like 'max_prepared_stmt_count'; Variable_name Value max_prepared_stmt_count 16382 -show variables like 'prepared_stmt_count'; +show status like 'prepared_stmt_count'; Variable_name Value -prepared_stmt_count 0 -select @@max_prepared_stmt_count, @@prepared_stmt_count; -@@max_prepared_stmt_count @@prepared_stmt_count -16382 0 +Prepared_stmt_count 0 +select @@max_prepared_stmt_count; +@@max_prepared_stmt_count +16382 set global max_prepared_stmt_count=-1; select @@max_prepared_stmt_count; @@max_prepared_stmt_count @@ -799,67 +799,70 @@ set max_prepared_stmt_count=1; ERROR HY000: Variable 'max_prepared_stmt_count' is a GLOBAL variable and should be set with SET GLOBAL set local max_prepared_stmt_count=1; ERROR HY000: Variable 'max_prepared_stmt_count' is a GLOBAL variable and should be set with SET GLOBAL -set local prepared_stmt_count=0; -ERROR HY000: Variable 'prepared_stmt_count' is a GLOBAL variable and should be set with SET GLOBAL -set @@prepared_stmt_count=0; -ERROR HY000: Variable 'prepared_stmt_count' is a GLOBAL variable and should be set with SET GLOBAL -set global prepared_stmt_count=1; -ERROR 42000: Incorrect argument type to variable 'prepared_stmt_count' set global max_prepared_stmt_count=1; select @@max_prepared_stmt_count; @@max_prepared_stmt_count 1 set global max_prepared_stmt_count=0; -select @@max_prepared_stmt_count, @@prepared_stmt_count; -@@max_prepared_stmt_count @@prepared_stmt_count -0 0 +select @@max_prepared_stmt_count; +@@max_prepared_stmt_count +0 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 0 prepare stmt from "select 1"; ERROR HY000: Unknown error -select @@prepared_stmt_count; -@@prepared_stmt_count -0 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 0 set global max_prepared_stmt_count=1; prepare stmt from "select 1"; -select @@prepared_stmt_count; -@@prepared_stmt_count -1 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 1 prepare stmt1 from "select 1"; ERROR HY000: Unknown error -select @@prepared_stmt_count; -@@prepared_stmt_count -1 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 1 deallocate prepare stmt; -select @@prepared_stmt_count; -@@prepared_stmt_count -0 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 0 prepare stmt from "select 1"; -select @@prepared_stmt_count; -@@prepared_stmt_count -1 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 1 prepare stmt from "select 2"; -select @@prepared_stmt_count; -@@prepared_stmt_count +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 1 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 1 +select @@max_prepared_stmt_count; +@@max_prepared_stmt_count 1 -select @@prepared_stmt_count, @@max_prepared_stmt_count; -@@prepared_stmt_count @@max_prepared_stmt_count -1 1 set global max_prepared_stmt_count=0; prepare stmt from "select 1"; ERROR HY000: Unknown error execute stmt; ERROR HY000: Unknown prepared statement handler (stmt) given to EXECUTE -select @@prepared_stmt_count; -@@prepared_stmt_count -0 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 0 prepare stmt from "select 1"; ERROR HY000: Unknown error -select @@prepared_stmt_count; -@@prepared_stmt_count -0 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 0 set global max_prepared_stmt_count=3; -select @@max_prepared_stmt_count, @@prepared_stmt_count; -@@max_prepared_stmt_count @@prepared_stmt_count -3 0 +select @@max_prepared_stmt_count; +@@max_prepared_stmt_count +3 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 0 prepare stmt from "select 1"; prepare stmt from "select 2"; prepare stmt1 from "select 3"; @@ -867,13 +870,13 @@ prepare stmt2 from "select 4"; ERROR HY000: Unknown error prepare stmt2 from "select 4"; ERROR HY000: Unknown error -select @@max_prepared_stmt_count, @@prepared_stmt_count; -@@max_prepared_stmt_count @@prepared_stmt_count -3 3 +select @@max_prepared_stmt_count; +@@max_prepared_stmt_count +3 +show status like 'prepared_stmt_count'; +Variable_name Value +Prepared_stmt_count 3 deallocate prepare stmt; -select @@max_prepared_stmt_count, @@prepared_stmt_count; -@@max_prepared_stmt_count @@prepared_stmt_count -3 0 set global max_prepared_stmt_count= @old_max_prepared_stmt_count; drop table if exists t1; create temporary table if not exists t1 (a1 int); diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 5b488ae4393..fbeaaa494e0 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -811,6 +811,9 @@ drop table t1; # Bug#16365 Prepared Statements: DoS with too many open statements # Check that the limit @@max_prpeared_stmt_count works. # +# This is also the test for bug#23159 prepared_stmt_count should be +# status variable. +# # Save the old value set @old_max_prepared_stmt_count= @@max_prepared_stmt_count; # @@ -820,17 +823,17 @@ set @old_max_prepared_stmt_count= @@max_prepared_stmt_count; # --disable_ps_protocol # -# A. Check that the new variables are present in SHOW VARIABLES list. +# A. Check that the new variables are present in SHOW VARIABLES and +# SHOW STATUS lists. # show variables like 'max_prepared_stmt_count'; -show variables like 'prepared_stmt_count'; +show status like 'prepared_stmt_count'; # -# B. Check that the new variables are selectable. +# B. Check that the new system variable is selectable. # -select @@max_prepared_stmt_count, @@prepared_stmt_count; +select @@max_prepared_stmt_count; # -# C. Check that max_prepared_stmt_count is settable (global only), -# whereas prepared_stmt_count is readonly. +# C. Check that max_prepared_stmt_count is settable (global only). # set global max_prepared_stmt_count=-1; select @@max_prepared_stmt_count; @@ -844,12 +847,6 @@ set @@max_prepared_stmt_count=1; set max_prepared_stmt_count=1; --error 1229 # ER_GLOBAL_VARIABLE set local max_prepared_stmt_count=1; ---error 1229 # ER_GLOBAL_VARIABLE -set local prepared_stmt_count=0; ---error 1229 # ER_GLOBAL_VARIABLE -set @@prepared_stmt_count=0; ---error 1232 # ER_WRONG_TYPE_FOR_VAR -set global prepared_stmt_count=1; # set to a reasonable limit works set global max_prepared_stmt_count=1; select @@max_prepared_stmt_count; @@ -857,47 +854,50 @@ select @@max_prepared_stmt_count; # D. Check that the variables actually work. # set global max_prepared_stmt_count=0; -select @@max_prepared_stmt_count, @@prepared_stmt_count; +select @@max_prepared_stmt_count; +show status like 'prepared_stmt_count'; --error 1105 # ER_UNKNOWN_ERROR prepare stmt from "select 1"; -select @@prepared_stmt_count; +show status like 'prepared_stmt_count'; set global max_prepared_stmt_count=1; prepare stmt from "select 1"; -select @@prepared_stmt_count; +show status like 'prepared_stmt_count'; --error 1105 # ER_UNKNOWN_ERROR prepare stmt1 from "select 1"; -select @@prepared_stmt_count; +show status like 'prepared_stmt_count'; deallocate prepare stmt; -select @@prepared_stmt_count; +show status like 'prepared_stmt_count'; # # E. Check that we can prepare a statement with the same name # successfully, without hitting the limit. # prepare stmt from "select 1"; -select @@prepared_stmt_count; +show status like 'prepared_stmt_count'; prepare stmt from "select 2"; -select @@prepared_stmt_count; +show status like 'prepared_stmt_count'; # # F. We can set the max below the current count. In this case no new # statements should be allowed to prepare. # -select @@prepared_stmt_count, @@max_prepared_stmt_count; +show status like 'prepared_stmt_count'; +select @@max_prepared_stmt_count; set global max_prepared_stmt_count=0; --error 1105 # ER_UNKNOWN_ERROR prepare stmt from "select 1"; # Result: the old statement is deallocated, the new is not created. --error 1243 # ER_UNKNOWN_STMT_HANDLER execute stmt; -select @@prepared_stmt_count; +show status like 'prepared_stmt_count'; --error 1105 # ER_UNKNOWN_ERROR prepare stmt from "select 1"; -select @@prepared_stmt_count; +show status like 'prepared_stmt_count'; # # G. Show that the variables are up to date even after a connection with all # statements in it was terminated. # set global max_prepared_stmt_count=3; -select @@max_prepared_stmt_count, @@prepared_stmt_count; +select @@max_prepared_stmt_count; +show status like 'prepared_stmt_count'; prepare stmt from "select 1"; connect (con1,localhost,root,,); connection con1; @@ -908,18 +908,11 @@ prepare stmt2 from "select 4"; connection default; --error 1105 # ER_UNKNOWN_ERROR prepare stmt2 from "select 4"; -select @@max_prepared_stmt_count, @@prepared_stmt_count; +select @@max_prepared_stmt_count; +show status like 'prepared_stmt_count'; disconnect con1; connection default; -# Wait for the connection to die: deal with a possible race deallocate prepare stmt; -let $count= `select @@prepared_stmt_count`; -if ($count) -{ ---sleep 2 - let $count= `select @@prepared_stmt_count`; -} -select @@max_prepared_stmt_count, @@prepared_stmt_count; # # Restore the old value. # diff --git a/sql/mysqld.cc b/sql/mysqld.cc index dbb1838c3d7..3327224be46 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5722,6 +5722,7 @@ struct show_var_st status_vars[]= { {"Open_streams", (char*) &my_stream_opened, SHOW_LONG_CONST}, {"Open_tables", (char*) 0, SHOW_OPENTABLES}, {"Opened_tables", (char*) &opened_tables, SHOW_LONG}, + {"Prepared_stmt_count", (char*) &prepared_stmt_count, SHOW_LONG_CONST}, #ifdef HAVE_QUERY_CACHE {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks, SHOW_LONG_CONST}, @@ -5892,6 +5893,7 @@ static void mysql_init_variables(void) binlog_cache_use= binlog_cache_disk_use= 0; max_used_connections= slow_launch_threads = 0; mysqld_user= mysqld_chroot= opt_init_file= opt_bin_logname = 0; + prepared_stmt_count= 0; errmesg= 0; mysqld_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS; bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list)); diff --git a/sql/set_var.cc b/sql/set_var.cc index 4433b6bf7d8..71ca382f9d9 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -119,7 +119,6 @@ static KEY_CACHE *create_key_cache(const char *name, uint length); void fix_sql_mode_var(THD *thd, enum_var_type type); static byte *get_error_count(THD *thd); static byte *get_warning_count(THD *thd); -static byte *get_prepared_stmt_count(THD *thd); static byte *get_have_innodb(THD *thd); /* @@ -482,9 +481,6 @@ static sys_var_readonly sys_warning_count("warning_count", OPT_SESSION, SHOW_LONG, get_warning_count); -static sys_var_readonly sys_prepared_stmt_count("prepared_stmt_count", - OPT_GLOBAL, SHOW_LONG, - get_prepared_stmt_count); /* alias for last_insert_id() to be compatible with Sybase */ #ifdef HAVE_REPLICATION @@ -604,7 +600,6 @@ sys_var *sys_variables[]= &sys_new_mode, &sys_old_passwords, &sys_preload_buff_size, - &sys_prepared_stmt_count, &sys_pseudo_thread_id, &sys_query_alloc_block_size, &sys_query_cache_size, @@ -860,7 +855,6 @@ struct show_var_st init_vars[]= { {"pid_file", (char*) pidfile_name, SHOW_CHAR}, {"port", (char*) &mysqld_port, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, - {sys_prepared_stmt_count.name, (char*) &sys_prepared_stmt_count, SHOW_SYS}, {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size, SHOW_SYS}, @@ -2715,14 +2709,6 @@ static byte *get_have_innodb(THD *thd) } -static byte *get_prepared_stmt_count(THD *thd) -{ - pthread_mutex_lock(&LOCK_prepared_stmt_count); - thd->sys_var_tmp.ulong_value= prepared_stmt_count; - pthread_mutex_unlock(&LOCK_prepared_stmt_count); - return (byte*) &thd->sys_var_tmp.ulong_value; -} - /**************************************************************************** Main handling of variables: - Initialisation From 18770d2fe4956e9be33a73cfc790129c19c6305a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Nov 2006 13:58:00 +0300 Subject: [PATCH 4/9] BUG#21635: MYSQL_FIELD struct's member strings seem to misbehave for expression cols. The problem was that MYSQL_FIELD::org_name was set for MIN() and MAX() functions (COUNT() is also mentioned in the bug report but was already fixed). After this patch for expressions MYSQL_FIELD::name is set to either expression itself or its alias, and other data origin fields of MYSQL_FILED (db, org_table, table, org_name) are empty strings. sql/item_sum.cc: For expressions only col_name should be non-empty string. tests/mysql_client_test.c: Add test case for bug#21635: MYSQL_FIELD struct's member strings seem to misbehave for expression cols. --- sql/item_sum.cc | 10 ++++-- tests/mysql_client_test.c | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 5fd65fecbfc..87c768e9383 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -71,9 +71,13 @@ void Item_sum::make_field(Send_field *tmp_field) if (args[0]->type() == Item::FIELD_ITEM && keep_field_type()) { ((Item_field*) args[0])->field->make_field(tmp_field); - tmp_field->db_name=(char*)""; - tmp_field->org_table_name=tmp_field->table_name=(char*)""; - tmp_field->org_col_name=tmp_field->col_name=name; + /* For expressions only col_name should be non-empty string. */ + char *empty_string= (char*)""; + tmp_field->db_name= empty_string; + tmp_field->org_table_name= empty_string; + tmp_field->table_name= empty_string; + tmp_field->org_col_name= empty_string; + tmp_field->col_name= name; if (maybe_null) tmp_field->flags&= ~NOT_NULL_FLAG; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 6ae9dcb9476..eb9559499bf 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -11945,6 +11945,73 @@ static void test_bug21726() } +/* + BUG#21635: MYSQL_FIELD struct's member strings seem to misbehave for + expression cols + + Check that for MIN(), MAX(), COUNT() only MYSQL_FIELD::name is set + to either expression or its alias, and db, org_table, table, + org_name fields are empty strings. +*/ +static void test_bug21635() +{ + const char *expr[]= + { + "MIN(i)", "MIN(i)", + "MIN(i) AS A1", "A1", + "MAX(i)", "MAX(i)", + "MAX(i) AS A2", "A2", + "COUNT(i)", "COUNT(i)", + "COUNT(i) AS A3", "A3", + }; + const char *query_end; + MYSQL_RES *result; + MYSQL_FIELD *field; + unsigned int field_count, i; + int rc; + + DBUG_ENTER("test_bug21635"); + myheader("test_bug21635"); + + query_end= strxmov(query, "SELECT ", NullS); + for (i= 0; i < sizeof(expr) / sizeof(*expr) / 2; ++i) + query_end= strxmov(query_end, expr[i * 2], ", ", NullS); + query_end= strxmov(query_end - 2, " FROM t1 GROUP BY i", NullS); + DIE_UNLESS(query_end - query < MAX_TEST_QUERY_LENGTH); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1 (i INT)"); + myquery(rc); + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)"); + myquery(rc); + + rc= mysql_real_query(mysql, query, query_end - query); + myquery(rc); + + result= mysql_use_result(mysql); + DIE_UNLESS(result); + + field_count= mysql_field_count(mysql); + for (i= 0; i < field_count; ++i) + { + field= mysql_fetch_field_direct(result, i); + printf("%s -> %s ... ", expr[i * 2], field->name); + fflush(stdout); + DIE_UNLESS(field->db[0] == 0 && field->org_table[0] == 0 && + field->table[0] == 0 && field->org_name[0] == 0); + DIE_UNLESS(strcmp(field->name, expr[i * 2 + 1]) == 0); + puts("OK"); + } + + mysql_free_result(result); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -12172,6 +12239,7 @@ static struct my_tests_st my_tests[]= { { "test_bug15613", test_bug15613 }, { "test_bug20152", test_bug20152 }, { "test_bug21726", test_bug21726 }, + { "test_bug21635", test_bug21635 }, { 0, 0 } }; From a7aecabc85664e822741da2288af29439a78e644 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Nov 2006 16:47:12 +0300 Subject: [PATCH 5/9] Cleanup: remove const. --- tests/mysql_client_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 4bc1fd5f9d4..98d7182d46f 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -12045,7 +12045,7 @@ static void test_bug21635() "COUNT(i)", "COUNT(i)", "COUNT(i) AS A3", "A3", }; - const char *query_end; + char *query_end; MYSQL_RES *result; MYSQL_FIELD *field; unsigned int field_count, i; From af6185240ad6120cc6b74b331fce571353552621 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 29 Nov 2006 09:23:54 +0400 Subject: [PATCH 6/9] fixed compilation failure on hpux the problem is that client tools are compiled with UNDEF_THREADS_HACK flag, and my thread-related additions to the mysqltest.c can't be compiled. Easy solution is to disable these in not-embedded case completely. client/mysqltest.c: it's used in embedded server only --- client/mysqltest.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/mysqltest.c b/client/mysqltest.c index b73ee831cf3..9fe427000d4 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -223,11 +223,13 @@ struct st_connection char *name; MYSQL_STMT* stmt; +#ifdef EMBEDDED_LIBRARY const char *cur_query; int cur_query_len; pthread_mutex_t mutex; pthread_cond_t cond; int query_done; +#endif /*EMBEDDED_LIBRARY*/ }; struct st_connection connections[128]; struct st_connection* cur_con, *next_con, *connections_end; From 3344298d197042b9636265c18ed54935e973de00 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 29 Nov 2006 10:21:59 +0100 Subject: [PATCH 7/9] minor fix mysql-test/mysql-test-run.pl: remove dependency on Data::Dumper, it's not used anywhere --- mysql-test/mysql-test-run.pl | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index f3981dc7c70..a734408e049 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -63,7 +63,6 @@ use Getopt::Long; use Sys::Hostname; use IO::Socket; use IO::Socket::INET; -use Data::Dumper; use strict; use warnings; use diagnostics; From 3b1abddb25b722d12b5dbf224ca36e83df404e44 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 29 Nov 2006 20:22:58 +0100 Subject: [PATCH 8/9] Makefile.am: Remove soft links before creating source TAR, to avoid file copies (bug#11865) Makefile.am: Remove soft links before creating source TAR, to avoid file copies (bug#11865) --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 12a867c1ad7..38e6a28b1b5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -91,6 +91,7 @@ bin-dist: all # Remove BK's "SCCS" subdirectories from source distribution dist-hook: rm -rf `find $(distdir) -type d -name SCCS -print` + rm -f `find $(distdir) -type l -print` tags: support-files/build-tags From 5af42c1b25c72ca16bf1d8181007235640b46c73 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 30 Nov 2006 13:16:12 +0100 Subject: [PATCH 9/9] minor fix to mtr_process.pl mysql-test/lib/mtr_process.pl: print extra message _once_ every 60 seconds --- mysql-test/lib/mtr_process.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 9d0c1f601ba..eef2f1b9dd5 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -1053,7 +1053,7 @@ sub sleep_until_file_created ($$$) { # Print extra message every 60 seconds my $seconds= ($loop * $sleeptime) / 1000; - if ( $seconds > 1 and int($seconds) % 60 == 0 ) + if ( $seconds > 1 and int($seconds * 10) % 600 == 0 ) { my $left= $timeout - $seconds; mtr_warning("Waited $seconds seconds for $pidfile to be created, " .