From 0fa2ee981be78dd30073313a9fbeb48edce6e96b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Mar 2008 10:17:49 -0300 Subject: Bug#35009 Results of mysql_client_test are discarded upon failure It's impossible to determine which test inside mysql_client_test failed if the log file is overwritten by mysqltest when dumping the test case results. Redirect mysql_client_test output to a separate file. mysql-test/t/mysql_client_test.test: Redirect mysql_client_test output to a separate log file so it doesn't get overwritten by mysqltest. --- mysql-test/t/mysql_client_test.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test index 66a27abd61a..b46a127785a 100644 --- a/mysql-test/t/mysql_client_test.test +++ b/mysql-test/t/mysql_client_test.test @@ -8,8 +8,8 @@ # server or run mysql-test-run --debug mysql_client_test and check # var/log/mysql_client_test.trace ---exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.log 2>&1 ---exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.log 2>&1 +--exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.out 2>&1 +--exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.out 2>&1 # End of 4.1 tests echo ok; -- cgit v1.2.1 From 0769fe559036512506736768fb31ddb0482ac2e6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Mar 2008 10:32:30 -0300 Subject: Use the same name for mysql_client_test output file in all branches. mysql-test/t/mysql_client_test.test: Rename mysql_client_test output file to mysql_client_test.out.log --- mysql-test/t/mysql_client_test.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test index b46a127785a..7667522feaf 100644 --- a/mysql-test/t/mysql_client_test.test +++ b/mysql-test/t/mysql_client_test.test @@ -8,8 +8,8 @@ # server or run mysql-test-run --debug mysql_client_test and check # var/log/mysql_client_test.trace ---exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.out 2>&1 ---exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.out 2>&1 +--exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1 +--exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1 # End of 4.1 tests echo ok; -- cgit v1.2.1 From eea48abc777b98bc06699fa4593aff2a71751e79 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 5 Mar 2008 14:57:13 +0100 Subject: Fix for Bug #34786 Compiling ndb on Mac OS X 10.5.2 (Intel) fails storage/ndb/src/kernel/blocks/tsman.cpp: Fix build on Tiger and Leopard, incl. 10.5.2 This is already in vm/ndb_malloc_impl.cpp --- storage/ndb/src/kernel/blocks/tsman.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/storage/ndb/src/kernel/blocks/tsman.cpp b/storage/ndb/src/kernel/blocks/tsman.cpp index 8e68e118f98..ce5797cf209 100644 --- a/storage/ndb/src/kernel/blocks/tsman.cpp +++ b/storage/ndb/src/kernel/blocks/tsman.cpp @@ -181,7 +181,6 @@ struct TsmanChunk Vector bitmask; }; template class Vector; -template class Vector; #endif void -- cgit v1.2.1 From c184cd6320ac3b5cbd1ab953d94ea1ef8c4d200e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Mar 2008 12:40:46 +0100 Subject: Bug#25132 disabled query cache: Qcache_free_blocks = 1 The initial value of free memory blocks in 0. When the query cache is enabled a new memory block gets allocated and is assigned number 1. The free memory block is later split each time query cache memory is allocated for new blocks. This means that the free memory block counter won't be reduced to zero when the number of allocated blocks are zero, but rather one. To avoid confusion this patch changes this behavior so that the free memory block counter is reset to zero when the query cache is disabled. Note that when the query cache is enabled and resized the free memory block counter was still calculated correctly. mysql-test/r/query_cache.result: test case mysql-test/t/query_cache.test: test case sql/sql_cache.cc: Restore the memory block count to 0 for consistency. --- mysql-test/r/query_cache.result | 10 ++++++++++ mysql-test/t/query_cache.test | 9 +++++++++ sql/sql_cache.cc | 1 + 3 files changed, 20 insertions(+) diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 68f18d1b0b2..b47c91b0406 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1650,6 +1650,16 @@ Variable_name Value Qcache_queries_in_cache 1 DROP DATABASE bug30269; DROP USER 'bug30269'@'localhost'; +# +# Bug#25132 disabled query cache: Qcache_free_blocks = 1 +# +set global query_cache_size=100000; +set global query_cache_size=0; +set global query_cache_type=0; +show status like 'Qcache_free_blocks'; +Variable_name Value +Qcache_free_blocks 0 +Restore default values. set GLOBAL query_cache_type=default; set GLOBAL query_cache_limit=default; set GLOBAL query_cache_min_res_unit=default; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 44b63df9739..e0042ab6311 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -1251,6 +1251,15 @@ DROP DATABASE bug30269; disconnect bug30269; DROP USER 'bug30269'@'localhost'; +--echo # +--echo # Bug#25132 disabled query cache: Qcache_free_blocks = 1 +--echo # +set global query_cache_size=100000; +set global query_cache_size=0; +set global query_cache_type=0; +show status like 'Qcache_free_blocks'; + +--echo Restore default values. set GLOBAL query_cache_type=default; set GLOBAL query_cache_limit=default; set GLOBAL query_cache_min_res_unit=default; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 8c868971911..2bf00e7e51f 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1794,6 +1794,7 @@ void Query_cache::make_disabled() query_cache_size= 0; queries_blocks= 0; free_memory= 0; + free_memory_blocks= 0; bins= 0; steps= 0; cache= 0; -- cgit v1.2.1 From aafb492d594776ead1014163461d30cbf9ca5772 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Mar 2008 09:16:53 -0300 Subject: Bug#35103 mysql_client_test::test_bug29948 causes sporadic failures Disable test case for bug 29948, which is causing sporadically failures in other tests inside mysql_client_test. tests/mysql_client_test.c: Disable test case. --- tests/mysql_client_test.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 260e7b1e7a7..0deb37d25c3 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15942,6 +15942,7 @@ static void test_bug27592() DBUG_VOID_RETURN; } +#if 0 static void test_bug29948() { @@ -16017,6 +16018,8 @@ static void test_bug29948() mysql_close(dbc); } +#endif + /** Bug#29306 Truncated data in MS Access with decimal (3,1) columns in a VIEW */ @@ -16543,7 +16546,7 @@ static struct my_tests_st my_tests[]= { { "test_bug28505", test_bug28505 }, { "test_bug28934", test_bug28934 }, { "test_bug27592", test_bug27592 }, - { "test_bug29948", test_bug29948 }, + /* { "test_bug29948", test_bug29948 }, Bug#35103 */ { "test_bug29306", test_bug29306 }, { "test_bug31669", test_bug31669 }, { "test_bug32265", test_bug32265 }, -- cgit v1.2.1 From 326c4e90589dd87792eacfa6e8746bc486a10ba0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Mar 2008 16:13:33 +0300 Subject: A fix for Bug#34643: TRUNCATE crash if trigger and foreign key. In cases when TRUNCATE was executed by invoking mysql_delete() rather than by table recreation (for example, when TRUNCATE was issued on InnoDB table with is referenced by foreign key) triggers were invoked. In debug builds this also led to crash because of an assertion, which assumes that some preliminary actions take place before trigger invocation, which doesn't happen in case of TRUNCATE. The fix is not to execute triggers in mysql_delete() when this function is used by TRUNCATE. mysql-test/r/trigger-trans.result: Update result file. mysql-test/t/trigger-trans.test: A test case for Bug#34643: TRUNCATE crash if trigger and foreign key. sql/sql_delete.cc: Do not process triggers in TRUNCATE. --- mysql-test/r/trigger-trans.result | 19 +++++++++++++++++++ mysql-test/t/trigger-trans.test | 32 ++++++++++++++++++++++++++++++++ sql/sql_delete.cc | 15 ++++++++++----- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/trigger-trans.result b/mysql-test/r/trigger-trans.result index cd5f629564f..dccaa27c5fd 100644 --- a/mysql-test/r/trigger-trans.result +++ b/mysql-test/r/trigger-trans.result @@ -140,4 +140,23 @@ select * from t3; c 1 drop table t1, t2, t3; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=innodb; +CREATE TABLE t2(b INT, FOREIGN KEY(b) REFERENCES t1(a)) ENGINE=innodb; +INSERT INTO t1 VALUES (1); +CREATE TRIGGER t1_bd BEFORE DELETE ON t1 FOR EACH ROW SET @a = 1; +CREATE TRIGGER t1_ad AFTER DELETE ON t1 FOR EACH ROW SET @b = 1; +SET @a = 0; +SET @b = 0; +TRUNCATE t1; +SELECT @a, @b; +@a @b +0 0 +INSERT INTO t1 VALUES (1); +DELETE FROM t1; +SELECT @a, @b; +@a @b +1 1 +DROP TABLE t2, t1; End of 5.0 tests diff --git a/mysql-test/t/trigger-trans.test b/mysql-test/t/trigger-trans.test index 8103a1ba0b1..5db5b982773 100644 --- a/mysql-test/t/trigger-trans.test +++ b/mysql-test/t/trigger-trans.test @@ -128,5 +128,37 @@ drop table t1, t2, t3; disconnect connection_update; disconnect connection_aux; +# +# Bug#34643: TRUNCATE crash if trigger and foreign key. +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings + +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=innodb; +CREATE TABLE t2(b INT, FOREIGN KEY(b) REFERENCES t1(a)) ENGINE=innodb; + +INSERT INTO t1 VALUES (1); + +CREATE TRIGGER t1_bd BEFORE DELETE ON t1 FOR EACH ROW SET @a = 1; +CREATE TRIGGER t1_ad AFTER DELETE ON t1 FOR EACH ROW SET @b = 1; + +SET @a = 0; +SET @b = 0; + +TRUNCATE t1; + +SELECT @a, @b; + +INSERT INTO t1 VALUES (1); + +DELETE FROM t1; + +SELECT @a, @b; + +DROP TABLE t2, t1; + --echo End of 5.0 tests diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index a28a39a769d..3019b68d6f1 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -35,6 +35,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, READ_RECORD info; bool using_limit=limit != HA_POS_ERROR; bool transactional_table, safe_update, const_cond; + bool triggers_applicable; ha_rows deleted; uint usable_index= MAX_KEY; SELECT_LEX *select_lex= &thd->lex->select_lex; @@ -93,6 +94,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, select_lex->no_error= thd->lex->ignore; + /* NOTE: TRUNCATE must not invoke triggers. */ + + triggers_applicable= table->triggers && + thd->lex->sql_command != SQLCOM_TRUNCATE; + /* Test if the user wants to delete all rows and deletion doesn't have any side-effects (because of triggers), so we can use optimized @@ -102,8 +108,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ if (!using_limit && const_cond && (!conds || conds->val_int()) && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && - (thd->lex->sql_command == SQLCOM_TRUNCATE || - !(table->triggers && table->triggers->has_delete_triggers())) + !(triggers_applicable && table->triggers->has_delete_triggers()) ) { deleted= table->file->records; @@ -217,7 +222,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, init_ftfuncs(thd, select_lex, 1); thd->proc_info="updating"; - if (table->triggers) + if (triggers_applicable) { table->triggers->mark_fields_used(thd, TRG_EVENT_DELETE); if (table->triggers->has_triggers(TRG_EVENT_DELETE, @@ -239,7 +244,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (!(select && select->skip_record())&& !thd->net.report_error ) { - if (table->triggers && + if (triggers_applicable && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)) { @@ -250,7 +255,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (!(error=table->file->delete_row(table->record[0]))) { deleted++; - if (table->triggers && + if (triggers_applicable && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE)) { -- cgit v1.2.1 From d80e7ce4e5e8aaae3473c617baaed5454bb520ed Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Mar 2008 16:50:24 +0300 Subject: Fix manual merge. --- sql/sql_delete.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 24eb109e6d9..7c3a046cb20 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -129,9 +129,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ if (!using_limit && const_cond_result && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && - !triggers_applicable && - !thd->current_stmt_binlog_row_based && - !table->triggers->has_delete_triggers()) + !(triggers_applicable && + thd->current_stmt_binlog_row_based && + table->triggers->has_delete_triggers())) { /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); -- cgit v1.2.1 From b279be388e1d8208396ada701d3015b9d7cbbc4c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Mar 2008 17:44:40 +0300 Subject: Fix for Bug#33507: Event scheduler creates more threads than max_connections -- which results in user lockout. The problem was that the variable thread_count that contains the number of active threads was interpreted as a number of active connections. The fix is to introduce a new counter for active connections. mysql-test/r/connect.result: A test case for Bug#33507: Event scheduler creates more threads than max_connections -- which results in user lockout. mysql-test/t/connect.test: A test case for Bug#33507: Event scheduler creates more threads than max_connections -- which results in user lockout. sql/mysql_priv.h: 1. Polishing: login_connection() and end_connection() need not to be public. 2. Introduce connection_count -- a variable to contain the number of active connections. It is protected by LOCK_connection_count. sql/mysqld.cc: Use connection_count to count active connections. sql/sql_connect.cc: 1. Use connection_count to count active connections. 2. Make login_connection(), end_connection() private for the module as they had to be. --- mysql-test/r/connect.result | 58 ++++++++++++++++++++ mysql-test/t/connect.test | 127 +++++++++++++++++++++++++++++++++++++++++++- sql/mysql_priv.h | 5 +- sql/mysqld.cc | 42 +++++++++++++-- sql/sql_connect.cc | 13 ++--- 5 files changed, 231 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index 25cf4f90e6d..de4eb28c500 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -115,3 +115,61 @@ create temporary table t2(id integer not null auto_increment primary key); set @id := 1; delete from t1 where id like @id; drop table t1; +# ------------------------------------------------------------------ +# -- End of 4.1 tests +# ------------------------------------------------------------------ + +# -- Bug#33507: Event scheduler creates more threads than max_connections +# -- which results in user lockout. + +GRANT USAGE ON *.* TO mysqltest_u1@localhost; + +SET GLOBAL max_connections = 3; +SET GLOBAL event_scheduler = ON; + +# -- Waiting for old connections to close... + + +# -- Disconnecting default connection... + +# -- Check that we allow exactly three user connections, no matter how +# -- many threads are running. + +# -- Connecting (1)... + +# -- Waiting for root connection to close... + +# -- Connecting (2)... +# -- Connecting (3)... +# -- Connecting (4)... +ERROR 08004: Too many connections + +# -- Waiting for the last connection to close... + +# -- Check that we allow one extra SUPER-user connection. + +# -- Connecting super (1)... +# -- Connecting super (2)... +ERROR 00000: Too many connections + +SELECT user FROM information_schema.processlist ORDER BY id; +user +event_scheduler +mysqltest_u1 +mysqltest_u1 +mysqltest_u1 +root + +# -- Resetting variables... +SET GLOBAL max_connections = 151; +SET GLOBAL event_scheduler = OFF; + +# -- That's it. Closing connections... + +# -- Restoring default connection... + +# -- End of Bug#33507. + +# ------------------------------------------------------------------ +# -- End of 5.1 tests +# ------------------------------------------------------------------ diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index 2e66c24d877..9e8f0d9b115 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -102,4 +102,129 @@ disconnect con7; connection default; drop table t1; -# End of 4.1 tests +--disconnect con1 +--disconnect con2 +--disconnect con3 +--disconnect con4 +--disconnect con5 +--disconnect con6 +--disconnect con10 + +--echo # ------------------------------------------------------------------ +--echo # -- End of 4.1 tests +--echo # ------------------------------------------------------------------ + +--echo +--echo # -- Bug#33507: Event scheduler creates more threads than max_connections +--echo # -- which results in user lockout. +--echo + +GRANT USAGE ON *.* TO mysqltest_u1@localhost; + +# NOTE: if the test case fails sporadically due to spurious connections, +# consider disabling all users. + +--echo + +let $saved_max_connections = `SELECT @@global.max_connections`; + +SET GLOBAL max_connections = 3; +SET GLOBAL event_scheduler = ON; + +--echo +--echo # -- Waiting for old connections to close... +let $wait_condition = + SELECT COUNT(*) = 1 + FROM information_schema.processlist + WHERE db = 'test'; +--source include/wait_condition.inc + +--echo +let $wait_condition = + SELECT COUNT(*) = 1 + FROM information_schema.processlist + WHERE user = 'event_scheduler'; +--source include/wait_condition.inc +--echo + +--echo # -- Disconnecting default connection... +--disconnect default + +--echo +--echo # -- Check that we allow exactly three user connections, no matter how +--echo # -- many threads are running. +--echo + +--echo # -- Connecting (1)... +--connect (con_1,localhost,mysqltest_u1) + +--echo +--echo # -- Waiting for root connection to close... +let $wait_condition = + SELECT COUNT(*) = 1 + FROM information_schema.processlist + WHERE db = 'test'; +--source include/wait_condition.inc +--echo + +--echo # -- Connecting (2)... +--connect (con_2,localhost,mysqltest_u1) + +--echo # -- Connecting (3)... +--connect (con_3,localhost,mysqltest_u1) + +--echo # -- Connecting (4)... +--disable_query_log +--error ER_CON_COUNT_ERROR +--connect (con_4,localhost,mysqltest_u1) +--enable_query_log + +--echo +--echo # -- Waiting for the last connection to close... +let $wait_condition = + SELECT COUNT(*) = 3 + FROM information_schema.processlist + WHERE db = 'test'; +--source include/wait_condition.inc + +--echo +--echo # -- Check that we allow one extra SUPER-user connection. +--echo + +--echo # -- Connecting super (1)... +--connect (con_super_1,localhost,root) + +--echo # -- Connecting super (2)... +--disable_query_log +--error ER_CON_COUNT_ERROR +--connect (con_super_2,localhost,root) +--enable_query_log + +--echo +# Ensure that we have Event Scheduler thread, 3 ordinary user connections and +# one extra super-user connection. +SELECT user FROM information_schema.processlist ORDER BY id; + +--echo +--echo # -- Resetting variables... + +--eval SET GLOBAL max_connections = $saved_max_connections +SET GLOBAL event_scheduler = OFF; + +--echo +--echo # -- That's it. Closing connections... +--disconnect con_1 +--disconnect con_2 +--disconnect con_super_1 + +--echo +--echo # -- Restoring default connection... +--connect (default,localhost,root,,test) + +--echo +--echo # -- End of Bug#33507. +--echo + +--echo # ------------------------------------------------------------------ +--echo # -- End of 5.1 tests +--echo # ------------------------------------------------------------------ diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b52e5aa745c..de40004fc6d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -974,8 +974,6 @@ void time_out_user_resource_limits(THD *thd, USER_CONN *uc); void decrease_user_connections(USER_CONN *uc); void thd_init_client_charset(THD *thd, uint cs_number); bool setup_connection_thread_globals(THD *thd); -bool login_connection(THD *thd); -void end_connection(THD *thd); bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create); @@ -1895,6 +1893,7 @@ extern bool opt_disable_networking, opt_skip_show_db; extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress; extern uint volatile thread_count, thread_running, global_read_lock; +extern uint connection_count; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; extern my_bool opt_slave_compressed_protocol, use_temp_pool; @@ -1933,7 +1932,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_lock_db, LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock, LOCK_global_system_variables, LOCK_user_conn, LOCK_prepared_stmt_count, - LOCK_bytes_sent, LOCK_bytes_received; + LOCK_bytes_sent, LOCK_bytes_received, LOCK_connection_count; #ifdef HAVE_OPENSSL extern pthread_mutex_t LOCK_des_key_file; #endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index cdd08be6573..fd9ce9e1cea 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -584,7 +584,8 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, LOCK_global_system_variables, - LOCK_user_conn, LOCK_slave_list, LOCK_active_mi; + LOCK_user_conn, LOCK_slave_list, LOCK_active_mi, + LOCK_connection_count; /** The below lock protects access to two global server variables: max_prepared_stmt_count and prepared_stmt_count. These variables @@ -720,6 +721,11 @@ char *des_key_file; struct st_VioSSLFd *ssl_acceptor_fd; #endif /* HAVE_OPENSSL */ +/** + Number of currently active user connections. The variable is protected by + LOCK_connection_count. +*/ +uint connection_count= 0; /* Function declarations */ @@ -1341,6 +1347,7 @@ static void clean_up_mutexes() (void) pthread_mutex_destroy(&LOCK_bytes_sent); (void) pthread_mutex_destroy(&LOCK_bytes_received); (void) pthread_mutex_destroy(&LOCK_user_conn); + (void) pthread_mutex_destroy(&LOCK_connection_count); Events::destroy_mutexes(); #ifdef HAVE_OPENSSL (void) pthread_mutex_destroy(&LOCK_des_key_file); @@ -1783,6 +1790,11 @@ void unlink_thd(THD *thd) DBUG_ENTER("unlink_thd"); DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); thd->cleanup(); + + pthread_mutex_lock(&LOCK_connection_count); + --connection_count; + pthread_mutex_unlock(&LOCK_connection_count); + (void) pthread_mutex_lock(&LOCK_thread_count); thread_count--; delete thd; @@ -3453,6 +3465,7 @@ static int init_thread_environment() (void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_prepared_stmt_count, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_connection_count, MY_MUTEX_INIT_FAST); #ifdef HAVE_OPENSSL (void) pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST); #ifndef HAVE_YASSL @@ -4700,6 +4713,11 @@ void create_thread_to_handle_connection(THD *thd) thread_count--; thd->killed= THD::KILL_CONNECTION; // Safety (void) pthread_mutex_unlock(&LOCK_thread_count); + + pthread_mutex_lock(&LOCK_connection_count); + --connection_count; + pthread_mutex_unlock(&LOCK_connection_count); + statistic_increment(aborted_connects,&LOCK_status); /* Can't use my_error() since store_globals has not been called. */ my_snprintf(error_message_buff, sizeof(error_message_buff), @@ -4739,15 +4757,31 @@ static void create_new_thread(THD *thd) if (protocol_version > 9) net->return_errno=1; - /* don't allow too many connections */ - if (thread_count - delayed_insert_threads >= max_connections+1 || abort_loop) + /* + Don't allow too many connections. We roughly check here that we allow + only (max_connections + 1) connections. + */ + + pthread_mutex_lock(&LOCK_connection_count); + + if (connection_count >= max_connections + 1 || abort_loop) { + pthread_mutex_unlock(&LOCK_connection_count); + DBUG_PRINT("error",("Too many connections")); close_connection(thd, ER_CON_COUNT_ERROR, 1); delete thd; DBUG_VOID_RETURN; } + + ++connection_count; + + pthread_mutex_unlock(&LOCK_connection_count); + + /* Start a new thread to handle connection. */ + pthread_mutex_lock(&LOCK_thread_count); + /* The initialization of thread_id is done in create_embedded_thd() for the embedded library. @@ -4755,13 +4789,13 @@ static void create_new_thread(THD *thd) */ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; - /* Start a new thread to handle connection */ thread_count++; if (thread_count - delayed_insert_threads > max_used_connections) max_used_connections= thread_count - delayed_insert_threads; thread_scheduler.add_connection(thd); + DBUG_VOID_RETURN; } #endif /* EMBEDDED_LIBRARY */ diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index b22a33e3e92..6f8cd6494cd 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -402,10 +402,11 @@ check_user(THD *thd, enum enum_server_command command, if (check_count) { - VOID(pthread_mutex_lock(&LOCK_thread_count)); - bool count_ok= thread_count <= max_connections + delayed_insert_threads - || (thd->main_security_ctx.master_access & SUPER_ACL); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + pthread_mutex_lock(&LOCK_connection_count); + bool count_ok= connection_count <= max_connections || + (thd->main_security_ctx.master_access & SUPER_ACL); + VOID(pthread_mutex_unlock(&LOCK_connection_count)); + if (!count_ok) { // too many connections my_error(ER_CON_COUNT_ERROR, MYF(0)); @@ -930,7 +931,7 @@ bool setup_connection_thread_globals(THD *thd) */ -bool login_connection(THD *thd) +static bool login_connection(THD *thd) { NET *net= &thd->net; int error; @@ -968,7 +969,7 @@ bool login_connection(THD *thd) This mainly updates status variables */ -void end_connection(THD *thd) +static void end_connection(THD *thd) { NET *net= &thd->net; plugin_thdvar_cleanup(thd); -- cgit v1.2.1 From 054341a6d07110dac1d05f023abd98bf7eaad39e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Mar 2008 23:07:10 +0300 Subject: Fix manual merge. --- sql/sql_delete.cc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7c3a046cb20..b9a7cd12662 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -103,10 +103,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, /* Error evaluating val_int(). */ DBUG_RETURN(TRUE); } - /* NOTE: TRUNCATE must not invoke triggers. */ - - triggers_applicable= table->triggers && - thd->lex->sql_command != SQLCOM_TRUNCATE; /* Test if the user wants to delete all rows and deletion doesn't have @@ -129,9 +125,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ if (!using_limit && const_cond_result && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && - !(triggers_applicable && - thd->current_stmt_binlog_row_based && - table->triggers->has_delete_triggers())) + (thd->lex->sql_command == SQLCOM_TRUNCATE || + (!thd->current_stmt_binlog_row_based && + !(table->triggers && table->triggers->has_delete_triggers())))) { /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -255,6 +251,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, init_ftfuncs(thd, select_lex, 1); thd_proc_info(thd, "updating"); + + /* NOTE: TRUNCATE must not invoke triggers. */ + + triggers_applicable= table->triggers && + thd->lex->sql_command != SQLCOM_TRUNCATE; + if (triggers_applicable && table->triggers->has_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER)) -- cgit v1.2.1 From c167501bfb10d21a72bdf61ff59dc155280bc45e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Mar 2008 12:02:12 +0300 Subject: Fix for Bug#35074: max_used_connections is not correct. The problem was that number of threads was used to calculate max_used_connections. The fix is to use number of active connections. mysql-test/r/connect.result: Update result file. mysql-test/t/connect.test: - Add a test case for Bug#35074: max_used_connections is not correct; - Make a test case for Bug#33507 more stable. sql/mysqld.cc: Use number of connections insetad of threads to calculate max_used_connections. --- mysql-test/r/connect.result | 34 ++++++++++++++++++++ mysql-test/t/connect.test | 75 +++++++++++++++++++++++++++++++++++++++++++++ sql/mysqld.cc | 6 ++-- 3 files changed, 112 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index de4eb28c500..c323bdf5998 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -162,14 +162,48 @@ root # -- Resetting variables... SET GLOBAL max_connections = 151; + +# -- Stopping Event Scheduler... SET GLOBAL event_scheduler = OFF; +# -- Waiting for Event Scheduler to stop... # -- That's it. Closing connections... # -- Restoring default connection... +# -- Waiting for connections to close... + +DROP USER mysqltest_u1@localhost; + # -- End of Bug#33507. +# -- Bug#35074: max_used_connections is not correct. + +FLUSH STATUS; + +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 1 + +# -- Starting Event Scheduler... +SET GLOBAL event_scheduler = ON; +# -- Waiting for Event Scheduler to start... + +# -- Opening a new connection to check max_used_connections... + +# -- Check that max_used_connections hasn't changed. +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 2 + +# -- Closing new connection... + +# -- Stopping Event Scheduler... +SET GLOBAL event_scheduler = OFF; +# -- Waiting for Event Scheduler to stop... + +# -- End of Bug#35074. + # ------------------------------------------------------------------ # -- End of 5.1 tests # ------------------------------------------------------------------ diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index 9e8f0d9b115..c8b69a050ba 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -209,22 +209,97 @@ SELECT user FROM information_schema.processlist ORDER BY id; --echo # -- Resetting variables... --eval SET GLOBAL max_connections = $saved_max_connections + +--echo +--echo # -- Stopping Event Scheduler... SET GLOBAL event_scheduler = OFF; +--echo # -- Waiting for Event Scheduler to stop... +let $wait_condition = + SELECT COUNT(*) = 0 + FROM information_schema.processlist + WHERE user = 'event_scheduler'; +--source include/wait_condition.inc + --echo --echo # -- That's it. Closing connections... --disconnect con_1 --disconnect con_2 +--disconnect con_3 --disconnect con_super_1 --echo --echo # -- Restoring default connection... --connect (default,localhost,root,,test) +--echo +--echo # -- Waiting for connections to close... +let $wait_condition = + SELECT COUNT(*) = 1 + FROM information_schema.processlist + WHERE db = 'test'; +--source include/wait_condition.inc + +--echo +DROP USER mysqltest_u1@localhost; + --echo --echo # -- End of Bug#33507. --echo +########################################################################### + +--echo # -- Bug#35074: max_used_connections is not correct. +--echo + +FLUSH STATUS; + +--echo +SHOW STATUS LIKE 'max_used_connections'; + +--echo +--echo # -- Starting Event Scheduler... +SET GLOBAL event_scheduler = ON; + +--echo # -- Waiting for Event Scheduler to start... +let $wait_condition = + SELECT COUNT(*) = 1 + FROM information_schema.processlist + WHERE user = 'event_scheduler'; +--source include/wait_condition.inc + +# NOTE: We should use a new connection here instead of reconnect in order to +# avoid races (we can not for sure when the connection being disconnected is +# actually disconnected on the server). + +--echo +--echo # -- Opening a new connection to check max_used_connections... +--connect (con_1,localhost,root) + +--echo +--echo # -- Check that max_used_connections hasn't changed. +SHOW STATUS LIKE 'max_used_connections'; + +--echo +--echo # -- Closing new connection... +--disconnect con_1 +--connection default + +--echo +--echo # -- Stopping Event Scheduler... +SET GLOBAL event_scheduler = OFF; + +--echo # -- Waiting for Event Scheduler to stop... +let $wait_condition = + SELECT COUNT(*) = 0 + FROM information_schema.processlist + WHERE user = 'event_scheduler'; +--source include/wait_condition.inc + +--echo +--echo # -- End of Bug#35074. +--echo + --echo # ------------------------------------------------------------------ --echo # -- End of 5.1 tests --echo # ------------------------------------------------------------------ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index fd9ce9e1cea..05f616dcd44 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4776,6 +4776,9 @@ static void create_new_thread(THD *thd) ++connection_count; + if (connection_count > max_used_connections) + max_used_connections= connection_count; + pthread_mutex_unlock(&LOCK_connection_count); /* Start a new thread to handle connection. */ @@ -4791,9 +4794,6 @@ static void create_new_thread(THD *thd) thread_count++; - if (thread_count - delayed_insert_threads > max_used_connections) - max_used_connections= thread_count - delayed_insert_threads; - thread_scheduler.add_connection(thd); DBUG_VOID_RETURN; -- cgit v1.2.1 From 416ab8532e6ee39de48c75aca49aa665cc8d2a2a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Mar 2008 14:54:29 -0300 Subject: Bug#34891 sp_notembedded.test fails sporadically The problem is that since MyISAM's concurrent_insert is on by default some concurrent SELECT statements might not see changes made by INSERT statements in other connections, even if the INSERT statement has returned. The solution is to disable concurrent_insert so that INSERT statements returns after the data is actually visible to other statements. mysql-test/r/flush_read_lock_kill.result: Restore old value of @@global.concurrent_insert mysql-test/r/kill.result: Restore old value of @@global.concurrent_insert mysql-test/r/sp_notembedded.result: Update test case result mysql-test/t/flush_read_lock_kill.test: Restore old value of @@global.concurrent_insert so it doesn't affect other tests. mysql-test/t/kill.test: Restore old value of @@global.concurrent_insert so it doesn't affect other tests. mysql-test/t/sp_notembedded.test: Disable and restore concurrent_insert value at the end of the test case. The test case for Bug 29936 requires that the inserted rows need to be visible before a SELECT statement is queued in another connection. Remove sleep at the start of the test, it's not necessary to log the result of the processlist command, showing the warnings has the same end result. --- mysql-test/r/flush_read_lock_kill.result | 2 + mysql-test/r/kill.result | 2 + mysql-test/r/sp_notembedded.result | 36 ++++++-- mysql-test/t/flush_read_lock_kill.test | 5 ++ mysql-test/t/kill.test | 7 ++ mysql-test/t/sp_notembedded.test | 141 ++++++++++++++++--------------- 6 files changed, 122 insertions(+), 71 deletions(-) diff --git a/mysql-test/r/flush_read_lock_kill.result b/mysql-test/r/flush_read_lock_kill.result index f69656806da..0b599f343f7 100644 --- a/mysql-test/r/flush_read_lock_kill.result +++ b/mysql-test/r/flush_read_lock_kill.result @@ -1,3 +1,4 @@ +set @old_concurrent_insert= @@global.concurrent_insert; set @@global.concurrent_insert= 0; drop table if exists t1; create table t1 (kill_id int); @@ -8,3 +9,4 @@ select ((@id := kill_id) - kill_id) from t1; 0 kill connection @id; drop table t1; +set @@global.concurrent_insert= @old_concurrent_insert; diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result index a522d18f36b..8b6830d4798 100644 --- a/mysql-test/r/kill.result +++ b/mysql-test/r/kill.result @@ -1,3 +1,4 @@ +set @old_concurrent_insert= @@global.concurrent_insert; set @@global.concurrent_insert= 0; drop table if exists t1, t2, t3; create table t1 (kill_id int); @@ -137,3 +138,4 @@ KILL CONNECTION_ID(); # of close of the connection socket SELECT 1; Got one of the listed errors +set @@global.concurrent_insert= @old_concurrent_insert; diff --git a/mysql-test/r/sp_notembedded.result b/mysql-test/r/sp_notembedded.result index 0b1fa565d28..3efb01fdb94 100644 --- a/mysql-test/r/sp_notembedded.result +++ b/mysql-test/r/sp_notembedded.result @@ -1,3 +1,5 @@ +set @old_concurrent_insert= @@global.concurrent_insert; +set @@global.concurrent_insert= 0; drop table if exists t1,t3; drop procedure if exists bug4902| create procedure bug4902() @@ -17,11 +19,11 @@ begin show processlist; end| call bug4902_2()| -Id User Host db Command Time State Info -# root localhost test Query # NULL show processlist +show warnings| +Level Code Message call bug4902_2()| -Id User Host db Command Time State Info -# root localhost test Query # NULL show processlist +show warnings| +Level Code Message drop procedure bug4902_2| drop table if exists t1| create table t1 ( @@ -68,7 +70,7 @@ c 2 show status like 'Qcache_hits'| Variable_name Value -Qcache_hits 2 +Qcache_hits 0 set global query_cache_size = @x| flush status| flush query cache| @@ -208,3 +210,27 @@ GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION drop user mysqltest_1@localhost; drop procedure 15298_1; drop procedure 15298_2; +drop table if exists t1; +drop procedure if exists p1; +create table t1 (value varchar(15)); +create procedure p1() update t1 set value='updated' where value='old'; +call p1(); +insert into t1 (value) values ("old"); +select get_lock('b26162',120); +get_lock('b26162',120) +1 +select 'rl_acquirer', value from t1 where get_lock('b26162',120);; +set session low_priority_updates=on; +call p1();; +select 'rl_contender', value from t1; +rl_contender value +rl_contender old +select release_lock('b26162'); +release_lock('b26162') +1 +rl_acquirer value +rl_acquirer old +drop procedure p1; +drop table t1; +set session low_priority_updates=default; +set @@global.concurrent_insert= @old_concurrent_insert; diff --git a/mysql-test/t/flush_read_lock_kill.test b/mysql-test/t/flush_read_lock_kill.test index c3926d09205..c03f3be2534 100644 --- a/mysql-test/t/flush_read_lock_kill.test +++ b/mysql-test/t/flush_read_lock_kill.test @@ -14,6 +14,7 @@ # Disable concurrent inserts to avoid test failures when reading the # connection id which was inserted into a table by another thread. +set @old_concurrent_insert= @@global.concurrent_insert; set @@global.concurrent_insert= 0; connect (con1,localhost,root,,); @@ -58,3 +59,7 @@ reap; connection con2; drop table t1; +connection default; + +# Restore global concurrent_insert value +set @@global.concurrent_insert= @old_concurrent_insert; diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index b7e1e82fe5d..8ef668f542b 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -8,6 +8,7 @@ # Disable concurrent inserts to avoid test failures when reading the # connection id which was inserted into a table by another thread. +set @old_concurrent_insert= @@global.concurrent_insert; set @@global.concurrent_insert= 0; connect (con1, localhost, root,,); @@ -326,3 +327,9 @@ KILL CONNECTION_ID(); --echo # of close of the connection socket --error 2013, 2006 SELECT 1; +--connection default + +########################################################################### + +# Restore global concurrent_insert value. Keep in the end of the test file. +set @@global.concurrent_insert= @old_concurrent_insert; diff --git a/mysql-test/t/sp_notembedded.test b/mysql-test/t/sp_notembedded.test index 4e298b2076a..16ebb710f25 100644 --- a/mysql-test/t/sp_notembedded.test +++ b/mysql-test/t/sp_notembedded.test @@ -1,7 +1,9 @@ # Can't test with embedded server -- source include/not_embedded.inc +# Disable concurrent inserts to avoid test failures +set @old_concurrent_insert= @@global.concurrent_insert; +set @@global.concurrent_insert= 0; ---sleep 2 --disable_warnings drop table if exists t1,t3; --enable_warnings @@ -39,10 +41,14 @@ create procedure bug4902_2() begin show processlist; end| ---replace_column 1 # 6 # 3 localhost +--disable_result_log call bug4902_2()| ---replace_column 1 # 6 # 3 localhost +--enable_result_log +show warnings| +--disable_result_log call bug4902_2()| +--enable_result_log +show warnings| drop procedure bug4902_2| # @@ -268,69 +274,72 @@ drop procedure 15298_1; drop procedure 15298_2; # -# Test case disabled due to Bug#34891: sp_notembedded.test fails sporadically. +# Bug#29936 Stored Procedure DML ignores low_priority_updates setting # -# # -# # Bug#29936 Stored Procedure DML ignores low_priority_updates setting -# # -# -# --disable_warnings -# drop table if exists t1; -# drop procedure if exists p1; -# --enable_warnings -# -# create table t1 (value varchar(15)); -# create procedure p1() update t1 set value='updated' where value='old'; -# -# # load the procedure into sp cache and execute once -# call p1(); -# -# insert into t1 (value) values ("old"); -# -# connect (rl_holder, localhost, root,,); -# connect (rl_acquirer, localhost, root,,); -# connect (rl_contender, localhost, root,,); -# connect (rl_wait, localhost, root,,); -# -# connection rl_holder; -# select get_lock('b26162',120); -# -# connection rl_acquirer; -# --send select 'rl_acquirer', value from t1 where get_lock('b26162',120); -# -# # we must wait till this select opens and locks the tables -# connection rl_wait; -# let $wait_condition= -# select count(*) = 1 from information_schema.processlist -# where state = "User lock" and -# info = "select 'rl_acquirer', value from t1 where get_lock('b26162',120)"; -# --source include/wait_condition.inc -# -# connection default; -# set session low_priority_updates=on; -# --send call p1(); -# -# connection rl_wait; -# let $wait_condition= -# select count(*) = 1 from information_schema.processlist -# where state = "Locked" and -# info = "update t1 set value='updated' where value='old'"; -# --source include/wait_condition.inc -# -# connection rl_contender; -# select 'rl_contender', value from t1; -# -# connection rl_holder; -# select release_lock('b26162'); + +--disable_warnings +drop table if exists t1; +drop procedure if exists p1; +--enable_warnings + +create table t1 (value varchar(15)); +create procedure p1() update t1 set value='updated' where value='old'; + +# load the procedure into sp cache and execute once +call p1(); + +insert into t1 (value) values ("old"); + +connect (rl_holder, localhost, root,,); +connect (rl_acquirer, localhost, root,,); +connect (rl_contender, localhost, root,,); +connect (rl_wait, localhost, root,,); + +connection rl_holder; +select get_lock('b26162',120); + +connection rl_acquirer; +--send select 'rl_acquirer', value from t1 where get_lock('b26162',120); + +# we must wait till this select opens and locks the tables +connection rl_wait; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "User lock" and + info = "select 'rl_acquirer', value from t1 where get_lock('b26162',120)"; +--source include/wait_condition.inc + +connection default; +set session low_priority_updates=on; +--send call p1(); + +connection rl_wait; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Locked" and + info = "update t1 set value='updated' where value='old'"; +--source include/wait_condition.inc + +connection rl_contender; +select 'rl_contender', value from t1; + +connection rl_holder; +select release_lock('b26162'); + +connection rl_acquirer; +--reap +connection default; +--reap + +disconnect rl_holder; +disconnect rl_acquirer; +disconnect rl_wait; +drop procedure p1; +drop table t1; +set session low_priority_updates=default; + # -# connection rl_acquirer; -# --reap -# connection default; -# --reap +# Restore global concurrent_insert value. Keep in the end of the test file. # -# disconnect rl_holder; -# disconnect rl_acquirer; -# disconnect rl_wait; -# drop procedure p1; -# drop table t1; -# set session low_priority_updates=default; + +set @@global.concurrent_insert= @old_concurrent_insert; -- cgit v1.2.1 From 2ebee313b5c4aed3a667b07bc93147eb9087f227 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Mar 2008 15:58:27 +0300 Subject: A fix for Bug#35289: Too many connections -- wrong SQL state in some case. ER_CON_COUNT_ERROR is defined with SQL state 08004. However, this SQL state is not always returned. This error can be thrown in two cases: 1. when an ordinary user (a user w/o SUPER privilege) is connecting, and the number of active user connections is equal or greater than max_connections. 2. when a user is connecting and the number of active user connections is already (max_connections + 1) -- that means that no more connections will be accepted regardless of the user credentials. In the 1-st case, SQL state is correct. The bug happens in the 2-nd case -- on UNIX the client gets 00000 SQL state, which is absolutely wrong (00000 means "not error SQL state); on Windows the client accidentally gets HY000 (which means "unknown SQL state). The cause of the problem is that the server rejects extra connection prior to read a packet with client capabilities. Thus, the server does not know if the client supports SQL states or not (if the client supports 4.1 protocol or not). So, the server supposes the worst and does not send SQL state at all. The difference in behavior on UNIX and Windows occurs because on Windows CLI_MYSQL_REAL_CONNECT() invokes create_shared_memory(), which returns an error (in default configuration, where shared memory is not configured). Then, the client does not reset this error, so when the connection is rejected, SQL state is HY000 (from the error from create_shared_memory()). The bug appeared after test case for Bug#33507 -- before that, this behavior just had not been tested. The fix is to 1) reset the error after create_shared_memory(); 2) set SQL state to 'unknown error' if it was not received from the server. A separate test case is not required, since the behavior is already tested in connect.test. Note for doc-team: the manual should be updated to say that under some circumstances, 'Too many connections' has HY000 SQL state. mysql-test/r/connect.result: Update result file. sql-common/client.c: 1. Reset an error from create_shared_memory(); 2. Set SQL state to 'unknown error' if it was not received from the server. --- mysql-test/r/connect.result | 2 +- sql-common/client.c | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index c323bdf5998..f2bacf92cc8 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -150,7 +150,7 @@ ERROR 08004: Too many connections # -- Connecting super (1)... # -- Connecting super (2)... -ERROR 00000: Too many connections +ERROR HY000: Too many connections SELECT user FROM information_schema.processlist ORDER BY id; user diff --git a/sql-common/client.c b/sql-common/client.c index b1728f0f74f..e7cf30c1a35 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -684,6 +684,16 @@ cli_safe_read(MYSQL *mysql) strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH); pos+= SQLSTATE_LENGTH+1; } + else + { + /* + The SQL state hasn't been received -- it should be reset to HY000 + (unknown error sql state). + */ + + strmov(net->sqlstate, unknown_sqlstate); + } + (void) strmake(net->last_error,(char*) pos, min((uint) len,(uint) sizeof(net->last_error)-1)); } @@ -1897,7 +1907,13 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, (int) have_tcpip)); if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) goto error; - /* Try also with PIPE or TCP/IP */ + + /* + Try also with PIPE or TCP/IP. Clear the error from + create_shared_memory(). + */ + + net_clear_error(net); } else { -- cgit v1.2.1 From 063b50477296f20b22e5cc5c1f50b8302ef55c19 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Mar 2008 17:40:12 -0300 Subject: Bug#35103 mysql_client_test::test_bug29948 causes sporadic failures The problem was that the COM_STMT_SEND_LONG_DATA was sending a response packet if the prepared statement wasn't found in the server (due to reconnection). The commands COM_STMT_SEND_LONG_DATA and COM_STMT_CLOSE should not send any packets, even error packets should not be sent since they are not expected by the client API. The solution is to clear generated during the execution of the aforementioned commands and to skip resend of prepared statement commands. Another fix is that if the connection breaks during the send of prepared statement command, the command is not sent again since the prepared statement is no longer in the server. libmysql/libmysql.c: The mysql handle might be reset after a reconnection. Pass the now used stmt argument to cli_advanced_command. sql-common/client.c: Don't resend command if the connection broke and it's a prepared statement command. If the session is broken, prepared statements on the server are gone, set the error accordanly. sql/sql_prepare.cc: Clear any error set during the execution of the request command. tests/mysql_client_test.c: Fix memory leak by freeing result associated with statement. Remove test case for Bug 29948 because it's not reliable in 5.0 (fixed in 5.1) due to KILL queries sending two packets for a thread that kills itself. --- libmysql/libmysql.c | 17 +++++++--- sql-common/client.c | 10 ++++-- sql/sql_prepare.cc | 16 ++++++---- tests/mysql_client_test.c | 79 +---------------------------------------------- 4 files changed, 30 insertions(+), 92 deletions(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 4afc3ec5925..b4fc40bc78a 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2456,7 +2456,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length) int4store(buff+5, 1); /* iteration count */ res= test(cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff), - packet, length, 1, NULL) || + packet, length, 1, stmt) || (*mysql->methods->read_query_result)(mysql)); stmt->affected_rows= mysql->affected_rows; stmt->server_status= mysql->server_status; @@ -2673,7 +2673,7 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row) int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */ if ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH, buff, sizeof(buff), NullS, 0, - 1, NULL)) + 1, stmt)) { set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); return 1; @@ -3340,7 +3340,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, */ if ((*mysql->methods->advanced_command)(mysql, COM_STMT_SEND_LONG_DATA, buff, sizeof(buff), data, - length, 1, NULL)) + length, 1, stmt)) { set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, mysql->net.sqlstate); @@ -4737,6 +4737,13 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) MYSQL_DATA *result= &stmt->result; DBUG_ENTER("mysql_stmt_store_result"); + if (!mysql) + { + /* mysql can be reset in mysql_close called from mysql_reconnect */ + set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate); + DBUG_RETURN(1); + } + mysql= mysql->last_used_con; if (!stmt->field_count) @@ -4762,7 +4769,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) int4store(buff, stmt->stmt_id); int4store(buff + 4, (int)~0); /* number of rows to fetch */ if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff), - NullS, 0, 1, NULL)) + NullS, 0, 1, stmt)) { set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); DBUG_RETURN(1); @@ -4949,7 +4956,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) char buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */ int4store(buff, stmt->stmt_id); if ((*mysql->methods->advanced_command)(mysql, COM_STMT_RESET, buff, - sizeof(buff), 0, 0, 0, NULL)) + sizeof(buff), 0, 0, 0, stmt)) { set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, mysql->net.sqlstate); diff --git a/sql-common/client.c b/sql-common/client.c index 1fc73549520..8b619b5452d 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -665,11 +665,12 @@ my_bool cli_advanced_command(MYSQL *mysql, enum enum_server_command command, const char *header, ulong header_length, const char *arg, ulong arg_length, my_bool skip_check, - MYSQL_STMT *stmt __attribute__((unused))) + MYSQL_STMT *stmt) { NET *net= &mysql->net; my_bool result= 1; init_sigpipe_variables + my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE; DBUG_ENTER("cli_advanced_command"); /* Don't give sigpipe errors if the client doesn't want them */ @@ -677,7 +678,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command, if (mysql->net.vio == 0) { /* Do reconnect if possible */ - if (mysql_reconnect(mysql)) + if (mysql_reconnect(mysql) || stmt_skip) DBUG_RETURN(1); } if (mysql->status != MYSQL_STATUS_READY || @@ -708,7 +709,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command, goto end; } end_server(mysql); - if (mysql_reconnect(mysql)) + if (mysql_reconnect(mysql) || stmt_skip) goto end; if (net_write_command(net,(uchar) command, header, header_length, arg, arg_length)) @@ -2503,6 +2504,9 @@ my_bool mysql_reconnect(MYSQL *mysql) if (stmt->state != MYSQL_STMT_INIT_DONE) { stmt->mysql= 0; + stmt->last_errno= CR_SERVER_LOST; + strmov(stmt->last_error, ER(CR_SERVER_LOST)); + strmov(stmt->sqlstate, unknown_sqlstate); } else { diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 18cfd8d7dfc..207183f567c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2516,7 +2516,7 @@ void mysql_stmt_close(THD *thd, char *packet) DBUG_ENTER("mysql_stmt_close"); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close"))) - DBUG_VOID_RETURN; + goto out; /* The only way currently a statement can be deallocated when it's @@ -2525,6 +2525,9 @@ void mysql_stmt_close(THD *thd, char *packet) DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE)); (void) stmt->deallocate(); +out: + /* clear errors, response packet is not expected */ + thd->clear_error(); DBUG_VOID_RETURN; } @@ -2591,10 +2594,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) #ifndef EMBEDDED_LIBRARY /* Minimal size of long data packet is 6 bytes */ if (packet_length <= MYSQL_LONG_DATA_HEADER) - { - my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data"); - DBUG_VOID_RETURN; - } + goto out; #endif stmt_id= uint4korr(packet); @@ -2614,7 +2614,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) stmt->last_errno= ER_WRONG_ARGUMENTS; sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "mysql_stmt_send_long_data"); - DBUG_VOID_RETURN; + goto out; } #endif @@ -2630,6 +2630,10 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) stmt->last_errno= ER_OUTOFMEMORY; sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0); } + +out: + /* clear errors, response packet is not expected */ + thd->clear_error(); DBUG_VOID_RETURN; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 0deb37d25c3..142fd741443 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -11746,6 +11746,7 @@ static void test_bug5194() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); + mysql_stmt_reset(stmt); } mysql_stmt_close(stmt); @@ -15942,83 +15943,6 @@ static void test_bug27592() DBUG_VOID_RETURN; } -#if 0 - -static void test_bug29948() -{ - MYSQL *dbc=NULL; - MYSQL_STMT *stmt=NULL; - MYSQL_BIND bind; - - int res=0; - my_bool auto_reconnect=1, error=0, is_null=0; - char kill_buf[20]; - const char *query; - int buf; - unsigned long length, cursor_type; - - dbc = mysql_init(NULL); - DIE_UNLESS(dbc); - - mysql_options(dbc, MYSQL_OPT_RECONNECT, (char*)&auto_reconnect); - if (!mysql_real_connect(dbc, opt_host, opt_user, - opt_password, current_db, opt_port, - opt_unix_socket, - (CLIENT_FOUND_ROWS | CLIENT_MULTI_STATEMENTS | - CLIENT_MULTI_RESULTS))) - { - printf("connection failed: %s (%d)", mysql_error(dbc), - mysql_errno(dbc)); - exit(1); - } - - bzero(&bind, sizeof(bind)); - bind.buffer_type= MYSQL_TYPE_LONG; - bind.buffer= (char *)&buf; - bind.is_null= &is_null; - bind.error= &error; - bind.length= &length; - - res= mysql_query(dbc, "DROP TABLE IF EXISTS t1"); - myquery(res); - res= mysql_query(dbc, "CREATE TABLE t1 (a INT)"); - myquery(res); - res= mysql_query(dbc, "INSERT INTO t1 VALUES(1)"); - myquery(res); - - stmt= mysql_stmt_init(dbc); - check_stmt(stmt); - - cursor_type= CURSOR_TYPE_READ_ONLY; - res= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void *)&cursor_type); - myquery(res); - - query= "SELECT * from t1 where a=?"; - res= mysql_stmt_prepare(stmt, query, strlen(query)); - myquery(res); - - res= mysql_stmt_bind_param(stmt, &bind); - myquery(res); - - res= mysql_stmt_execute(stmt); - check_execute(stmt, res); - - res= mysql_stmt_bind_result(stmt,&bind); - check_execute(stmt, res); - - sprintf(kill_buf, "kill %ld", dbc->thread_id); - mysql_query(dbc, kill_buf); - - res= mysql_stmt_store_result(stmt); - DIE_UNLESS(res); - - mysql_stmt_free_result(stmt); - mysql_stmt_close(stmt); - mysql_query(dbc, "DROP TABLE t1"); - mysql_close(dbc); -} - -#endif /** Bug#29306 Truncated data in MS Access with decimal (3,1) columns in a VIEW @@ -16546,7 +16470,6 @@ static struct my_tests_st my_tests[]= { { "test_bug28505", test_bug28505 }, { "test_bug28934", test_bug28934 }, { "test_bug27592", test_bug27592 }, - /* { "test_bug29948", test_bug29948 }, Bug#35103 */ { "test_bug29306", test_bug29306 }, { "test_bug31669", test_bug31669 }, { "test_bug32265", test_bug32265 }, -- cgit v1.2.1 From 30d644f859ee65748f12e3861abaf1fbb2c3b2c7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Mar 2008 13:39:56 +0300 Subject: A patch for Bug#35329: connect does not set mysql_errno variable. The problem was that 'connect' command didn't set mysql_errno variable, thus the script was unable to determine whether connection was opened or not. The fix is to set this variable. Test cases will be added in the scope of Bug33507 into connect.test file. client/mysqltest.c: Set 'mysql_errno' variable. --- client/mysqltest.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/mysqltest.c b/client/mysqltest.c index 52e02789579..7ef184ae7e8 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -4221,11 +4221,13 @@ int connect_n_handle_errors(struct st_command *command, if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0, CLIENT_MULTI_STATEMENTS)) { + var_set_errno(mysql_errno(con)); handle_error(command, mysql_errno(con), mysql_error(con), mysql_sqlstate(con), ds); return 0; /* Not connected */ } + var_set_errno(0); handle_no_error(command); return 1; /* Connected */ } -- cgit v1.2.1 From c1e69a77a6f6563214b5f5e8813db423c4f3a04c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Mar 2008 14:26:00 +0300 Subject: Avoid races in connect.test. The problem was in a test case for Bug33507: - when the number of active connections reaches the limit, the server accepts only root connections. That's achieved by accepting a connection, negotiating with the client and checking user credentials. If it is not SUPER, the connection is dropped. - when the server accepts connection, it increases the counter; - when the server drops connection, it decreases the counter; - the race was in between of decreasing the counter and accepting new connection: - max_user_connections = 2; - 2 oridinary user connections accepted; - extra user connection is establishing; - server checked user credentials, and sent 'Too many connections' error; - the client receives the error and establishes extra SUPER user connection; - the server however didn't decrease the counter (the extra user connection still is "alive" in the server) -- so, the new SUPER-user connection, will be dropped, because it exceeds (max_user_connections + 1). The fix is to implement "safe connect", which makes several attempts to connect and use it in the test script. mysql-test/r/connect.result: Update test file. mysql-test/t/connect.test: Avoid races in connect.test. mysql-test/include/connect2.inc: Auxiliary routine to establish a connection reliably. --- mysql-test/include/connect2.inc | 56 +++++++++++++++++++++++++++++ mysql-test/r/connect.result | 29 ++++++++++----- mysql-test/t/connect.test | 80 ++++++++++++++++++----------------------- 3 files changed, 110 insertions(+), 55 deletions(-) create mode 100644 mysql-test/include/connect2.inc diff --git a/mysql-test/include/connect2.inc b/mysql-test/include/connect2.inc new file mode 100644 index 00000000000..6b830a909ed --- /dev/null +++ b/mysql-test/include/connect2.inc @@ -0,0 +1,56 @@ +# include/connect2.inc +# +# SUMMARY +# +# Make several attempts to connect. +# +# USAGE +# +# EXAMPLE +# +# connect.test +# + +--disable_query_log + +let $wait_counter= 300; +if ($wait_timeout) +{ + let $wait_counter= `SELECT $wait_timeout * 10`; +} +# Reset $wait_timeout so that its value won't be used on subsequent +# calls, and default will be used instead. +let $wait_timeout= 0; + +--echo # -- Establishing connection '$con_name' (user: $con_user_name)... + +while ($wait_counter) +{ + --disable_abort_on_error + --disable_result_log + --connect ($con_name,localhost,$con_user_name) + --enable_result_log + --enable_abort_on_error + + let $error = $mysql_errno; + + if (!$error) + { + let $wait_counter= 0; + } + if ($error) + { + real_sleep 0.1; + dec $wait_counter; + } +} +if ($error) +{ + --echo # -- Error: can not establish connection '$con_name'. +} +if (!$error) +{ + --echo # -- Connection '$con_name' has been established. +} + +--enable_query_log diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index f2bacf92cc8..727433d3032 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -127,8 +127,7 @@ GRANT USAGE ON *.* TO mysqltest_u1@localhost; SET GLOBAL max_connections = 3; SET GLOBAL event_scheduler = ON; -# -- Waiting for old connections to close... - +# -- Waiting for Event Scheduler to start... # -- Disconnecting default connection... @@ -136,22 +135,33 @@ SET GLOBAL event_scheduler = ON; # -- many threads are running. # -- Connecting (1)... - -# -- Waiting for root connection to close... +# -- Establishing connection 'con_1' (user: mysqltest_u1)... +# -- Connection 'con_1' has been established. # -- Connecting (2)... +# -- Establishing connection 'con_2' (user: mysqltest_u1)... +# -- Connection 'con_2' has been established. + # -- Connecting (3)... -# -- Connecting (4)... -ERROR 08004: Too many connections +# -- Establishing connection 'con_3' (user: mysqltest_u1)... +# -- Connection 'con_3' has been established. -# -- Waiting for the last connection to close... +# -- Connecting (4) [should fail]... +# -- Establishing connection 'con_4' (user: mysqltest_u1)... +# -- Error: can not establish connection 'con_4'. # -- Check that we allow one extra SUPER-user connection. # -- Connecting super (1)... -# -- Connecting super (2)... -ERROR HY000: Too many connections +# -- Establishing connection 'con_super_1' (user: root)... +# -- Connection 'con_super_1' has been established. + +# -- Connecting super (2) [should fail]... +# -- Establishing connection 'con_super_2' (user: root)... +# -- Error: can not establish connection 'con_super_2'. +# -- Ensure that we have Event Scheduler thread, 3 ordinary user +# -- connections and one extra super-user connection. SELECT user FROM information_schema.processlist ORDER BY id; user event_scheduler @@ -165,6 +175,7 @@ SET GLOBAL max_connections = 151; # -- Stopping Event Scheduler... SET GLOBAL event_scheduler = OFF; + # -- Waiting for Event Scheduler to stop... # -- That's it. Closing connections... diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index c8b69a050ba..0893bf9ad18 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -114,106 +114,94 @@ drop table t1; --echo # -- End of 4.1 tests --echo # ------------------------------------------------------------------ +########################################################################### + --echo --echo # -- Bug#33507: Event scheduler creates more threads than max_connections --echo # -- which results in user lockout. ---echo +--echo GRANT USAGE ON *.* TO mysqltest_u1@localhost; # NOTE: if the test case fails sporadically due to spurious connections, # consider disabling all users. --echo - let $saved_max_connections = `SELECT @@global.max_connections`; - SET GLOBAL max_connections = 3; SET GLOBAL event_scheduler = ON; --echo ---echo # -- Waiting for old connections to close... -let $wait_condition = - SELECT COUNT(*) = 1 - FROM information_schema.processlist - WHERE db = 'test'; ---source include/wait_condition.inc - ---echo +--echo # -- Waiting for Event Scheduler to start... let $wait_condition = SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE user = 'event_scheduler'; --source include/wait_condition.inc ---echo +--echo --echo # -- Disconnecting default connection... --disconnect default --echo --echo # -- Check that we allow exactly three user connections, no matter how --echo # -- many threads are running. ---echo +--echo --echo # -- Connecting (1)... ---connect (con_1,localhost,mysqltest_u1) +let $con_name = con_1; +let $con_user_name = mysqltest_u1; +--source include/connect2.inc --echo ---echo # -- Waiting for root connection to close... -let $wait_condition = - SELECT COUNT(*) = 1 - FROM information_schema.processlist - WHERE db = 'test'; ---source include/wait_condition.inc ---echo - --echo # -- Connecting (2)... ---connect (con_2,localhost,mysqltest_u1) +let $con_name = con_2; +let $con_user_name = mysqltest_u1; +--source include/connect2.inc +--echo --echo # -- Connecting (3)... ---connect (con_3,localhost,mysqltest_u1) - ---echo # -- Connecting (4)... ---disable_query_log ---error ER_CON_COUNT_ERROR ---connect (con_4,localhost,mysqltest_u1) ---enable_query_log +let $con_name = con_3; +let $con_user_name = mysqltest_u1; +--source include/connect2.inc --echo ---echo # -- Waiting for the last connection to close... -let $wait_condition = - SELECT COUNT(*) = 3 - FROM information_schema.processlist - WHERE db = 'test'; ---source include/wait_condition.inc +--echo # -- Connecting (4) [should fail]... +let $con_name = con_4; +let $con_user_name = mysqltest_u1; +let $wait_timeout = 5; +--source include/connect2.inc --echo --echo # -- Check that we allow one extra SUPER-user connection. ---echo +--echo --echo # -- Connecting super (1)... ---connect (con_super_1,localhost,root) +let $con_name = con_super_1; +let $con_user_name = root; +--source include/connect2.inc ---echo # -- Connecting super (2)... ---disable_query_log ---error ER_CON_COUNT_ERROR ---connect (con_super_2,localhost,root) ---enable_query_log +--echo +--echo # -- Connecting super (2) [should fail]... +let $con_name = con_super_2; +let $con_user_name = root; +let $wait_timeout = 5; +--source include/connect2.inc --echo -# Ensure that we have Event Scheduler thread, 3 ordinary user connections and -# one extra super-user connection. +--echo # -- Ensure that we have Event Scheduler thread, 3 ordinary user +--echo # -- connections and one extra super-user connection. SELECT user FROM information_schema.processlist ORDER BY id; --echo --echo # -- Resetting variables... - --eval SET GLOBAL max_connections = $saved_max_connections --echo --echo # -- Stopping Event Scheduler... SET GLOBAL event_scheduler = OFF; +--echo --echo # -- Waiting for Event Scheduler to stop... let $wait_condition = SELECT COUNT(*) = 0 -- cgit v1.2.1 From 23d567aa7cb01811294a24ecda100d2a90fe8acf Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Mar 2008 11:16:37 -0300 Subject: Post-merge fix for Bug 35103. sql/sql_prepare.cc: Don't send unexpected error to the client. --- sql/sql_prepare.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 207183f567c..b00606aba4a 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2602,7 +2602,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) if (!(stmt=find_prepared_statement(thd, stmt_id, "mysql_stmt_send_long_data"))) - DBUG_VOID_RETURN; + goto out; param_number= uint2korr(packet); packet+= 2; -- cgit v1.2.1 From 809522598a9a8946a5e1fa4a981717c38466a379 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Mar 2008 16:39:09 -0300 Subject: Post-merge fixes for Bug 35103 libmysql/libmysql.c: Manual merge sql/sql_class.cc: Don't send anything back to the client if disabled. sql/sql_prepare.cc: Don't send any packet back for statement close. tests/mysql_client_test.c: Manual merge --- libmysql/libmysql.c | 2 +- sql/sql_class.cc | 22 ++++++++++++++++++---- sql/sql_prepare.cc | 4 ++-- tests/mysql_client_test.c | 28 +++++++++++++++++++--------- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 423068a6ba2..99bd393a907 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -4751,7 +4751,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) if (!mysql) { /* mysql can be reset in mysql_close called from mysql_reconnect */ - set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate); + set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); DBUG_RETURN(1); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 376102c8bf9..594577dd89c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -395,8 +395,11 @@ Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg, { DBUG_ASSERT(! is_set()); #ifdef DBUG_OFF - /* In production, refuse to overwrite an error with an OK packet. */ - if (is_error()) + /* + In production, refuse to overwrite an error or a custom response + with an OK packet. + */ + if (is_error() || is_disabled()) return; #endif /** Only allowed to report success if has not yet reported an error */ @@ -424,8 +427,11 @@ Diagnostics_area::set_eof_status(THD *thd) DBUG_ASSERT(! is_set()); #ifdef DBUG_OFF - /* In production, refuse to overwrite an error with an EOF packet. */ - if (is_error()) + /* + In production, refuse to overwrite an error or a custom response + with an EOF packet. + */ + if (is_error() || is_disabled()) return; #endif @@ -454,6 +460,14 @@ Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg, an error can happen during the flush. */ DBUG_ASSERT(! is_set() || can_overwrite_status); +#ifdef DBUG_OFF + /* + In production, refuse to overwrite a custom response with an + ERROR packet. + */ + if (is_disabled()) + return; +#endif m_sql_errno= sql_errno_arg; strmake(m_message, message_arg, sizeof(m_message) - 1); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index a027ffe9daa..c922b21af90 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2555,6 +2555,8 @@ void mysql_stmt_close(THD *thd, char *packet) Prepared_statement *stmt; DBUG_ENTER("mysql_stmt_close"); + thd->main_da.disable_status(); + if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close"))) DBUG_VOID_RETURN; @@ -2566,8 +2568,6 @@ void mysql_stmt_close(THD *thd, char *packet) (void) stmt->deallocate(); general_log_print(thd, thd->command, NullS); - thd->main_da.disable_status(); - DBUG_VOID_RETURN; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 482ae37d15b..085b14a65e9 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -12016,6 +12016,7 @@ static void test_bug5194() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); + mysql_stmt_reset(stmt); } mysql_stmt_close(stmt); @@ -16600,7 +16601,10 @@ static void test_bug27592() DBUG_VOID_RETURN; } -#if 0 + +/** + Bug#29948 autoreconnect + prepared statements + kill seems unstable +*/ static void test_bug29948() { @@ -16614,7 +16618,10 @@ static void test_bug29948() const char *query; int buf; unsigned long length, cursor_type; - + + DBUG_ENTER("test_bug29948"); + myheader("test_bug29948"); + dbc = mysql_init(NULL); DIE_UNLESS(dbc); @@ -16650,7 +16657,7 @@ static void test_bug29948() res= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void *)&cursor_type); myquery(res); - query= "SELECT * from t1 where a=?"; + query= "SELECT * FROM t1 WHERE a=?"; res= mysql_stmt_prepare(stmt, query, strlen(query)); myquery(res); @@ -16662,20 +16669,23 @@ static void test_bug29948() res= mysql_stmt_bind_result(stmt,&bind); check_execute(stmt, res); - - sprintf(kill_buf, "kill %ld", dbc->thread_id); - mysql_query(dbc, kill_buf); + + my_snprintf(kill_buf, sizeof(kill_buf), "KILL %ld", dbc->thread_id); + res= mysql_query(dbc, kill_buf); + myquery(res); res= mysql_stmt_store_result(stmt); DIE_UNLESS(res); mysql_stmt_free_result(stmt); mysql_stmt_close(stmt); - mysql_query(dbc, "DROP TABLE t1"); + + res= mysql_query(dbc, "DROP TABLE t1"); + myquery(res); + mysql_close(dbc); } -#endif /* Bug#29687 mysql_stmt_store_result memory leak in libmysqld @@ -17715,7 +17725,7 @@ static struct my_tests_st my_tests[]= { { "test_bug28505", test_bug28505 }, { "test_bug28934", test_bug28934 }, { "test_bug27592", test_bug27592 }, - /* { "test_bug29948", test_bug29948 }, */ + { "test_bug29948", test_bug29948 }, { "test_bug29687", test_bug29687 }, { "test_bug29692", test_bug29692 }, { "test_bug29306", test_bug29306 }, -- cgit v1.2.1