diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index b19edbd1a00..1e967b668c5 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -587,9 +587,4 @@ SELECT CASE c1 WHEN c1 + 1 THEN 1 END, ABS(AVG(c0)) FROM t1; CASE c1 WHEN c1 + 1 THEN 1 END ABS(AVG(c0)) NULL 1.0000 DROP TABLE t1; -CREATE TABLE t1(a TEXT); -INSERT INTO t1 VALUES('iynfj'); -SELECT SUM( DISTINCT a ) FROM t1 GROUP BY a HAVING a IN ( AVG( 1 ), 1 + a ); -SUM( DISTINCT a ) -DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/suite/binlog/r/binlog_stm_ps.result b/mysql-test/suite/binlog/r/binlog_stm_ps.result index ea7cc6f16df..3af525e297c 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_ps.result +++ b/mysql-test/suite/binlog/r/binlog_stm_ps.result @@ -11,7 +11,7 @@ prepare s from "insert into t1 select 100 limit ?"; set @a=100; execute s using @a; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # use `test`; create table t1 (a int) diff --git a/mysql-test/suite/binlog/r/binlog_unsafe.result b/mysql-test/suite/binlog/r/binlog_unsafe.result index 675c327e9e7..4c2c32ad8f1 100644 --- a/mysql-test/suite/binlog/r/binlog_unsafe.result +++ b/mysql-test/suite/binlog/r/binlog_unsafe.result @@ -10,25 +10,25 @@ INSERT DELAYED INTO t1 VALUES (5); ---- Insert directly ---- INSERT INTO t1 VALUES (@@global.sync_binlog); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. INSERT INTO t1 VALUES (@@session.insert_id); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. INSERT INTO t1 VALUES (@@global.auto_increment_increment); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. INSERT INTO t2 SELECT UUID(); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. INSERT INTO t2 VALUES (@@session.sql_mode); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. INSERT INTO t2 VALUES (@@global.init_slave); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. INSERT INTO t2 VALUES (@@hostname); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. ---- Insert from stored procedure ---- CREATE PROCEDURE proc() BEGIN @@ -42,13 +42,13 @@ INSERT INTO t2 VALUES (@@hostname); END| CALL proc(); Warnings: -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. ---- Insert from stored function ---- CREATE FUNCTION func() RETURNS INT @@ -66,13 +66,13 @@ SELECT func(); func() 0 Warnings: -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. ---- Insert from trigger ---- CREATE TRIGGER trig BEFORE INSERT ON trigger_table @@ -88,14 +88,14 @@ INSERT INTO t2 VALUES (@@hostname); END| INSERT INTO trigger_table VALUES ('bye.'); Warnings: -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. ---- Insert from prepared statement ---- PREPARE p1 FROM 'INSERT INTO t1 VALUES (@@global.sync_binlog)'; PREPARE p2 FROM 'INSERT INTO t1 VALUES (@@session.insert_id)'; @@ -106,25 +106,25 @@ PREPARE p6 FROM 'INSERT INTO t2 VALUES (@@global.init_slave)'; PREPARE p7 FROM 'INSERT INTO t2 VALUES (@@hostname)'; EXECUTE p1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. EXECUTE p2; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. EXECUTE p3; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. EXECUTE p4; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. EXECUTE p5; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. EXECUTE p6; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. EXECUTE p7; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. ---- Insert from nested call of triggers / functions / procedures ---- CREATE PROCEDURE proc1() INSERT INTO trigger_table VALUES ('ha!')| @@ -154,13 +154,13 @@ EXECUTE prep6; func5() 0 Warnings: -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. ==== Variables that should *not* be unsafe ==== INSERT INTO t1 VALUES (@@session.pseudo_thread_id); INSERT INTO t1 VALUES (@@session.pseudo_thread_id); @@ -195,16 +195,16 @@ DROP TABLE t1, t2, t3, trigger_table, trigger_table2; CREATE TABLE t1(a INT, b INT, KEY(a), PRIMARY KEY(b)); INSERT INTO t1 SELECT * FROM t1 LIMIT 1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. REPLACE INTO t1 SELECT * FROM t1 LIMIT 1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. UPDATE t1 SET a=1 LIMIT 1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. DELETE FROM t1 LIMIT 1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. CREATE PROCEDURE p1() BEGIN INSERT INTO t1 SELECT * FROM t1 LIMIT 1; @@ -214,10 +214,10 @@ DELETE FROM t1 LIMIT 1; END| CALL p1(); Warnings: -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. DROP PROCEDURE p1; DROP TABLE t1; DROP TABLE IF EXISTS t1; @@ -225,16 +225,16 @@ CREATE TABLE t1 (a VARCHAR(100), b VARCHAR(100)); INSERT INTO t1 VALUES ('a','b'); UPDATE t1 SET b = '%s%s%s%s%s%s%s%s%s%s%s%s%s%s' WHERE a = 'a' LIMIT 1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. DROP TABLE t1; DROP TABLE IF EXISTS t1, t2; CREATE TABLE t1(i INT PRIMARY KEY); CREATE TABLE t2(i INT PRIMARY KEY); CREATE TABLE t3(i INT, ch CHAR(50)); -"Should issue message Statement is not safe to log in statement format." +"Should issue message Statement may not be safe to log in statement format." INSERT INTO t1 SELECT * FROM t2 LIMIT 1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. CREATE FUNCTION func6() RETURNS INT BEGIN @@ -243,10 +243,10 @@ INSERT INTO t1 VALUES (11); INSERT INTO t1 VALUES (12); RETURN 0; END| -"Should issue message Statement is not safe to log in statement format only once" +"Should issue message Statement may not be safe to log in statement format only once" INSERT INTO t3 VALUES(func6(), UUID()); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. "Check whether SET @@SQL_LOG_BIN = 0/1 doesn't work in substatements" CREATE FUNCTION fun_check_log_bin() RETURNS INT BEGIN @@ -259,7 +259,7 @@ SELECT fun_check_log_bin(); fun_check_log_bin() 100 Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. "SQL_LOG_BIN should be ON still" SHOW VARIABLES LIKE "SQL_LOG_BIN"; Variable_name Value @@ -315,16 +315,16 @@ CREATE TABLE t1(i INT PRIMARY KEY); CREATE TABLE t2(i INT PRIMARY KEY); INSERT INTO t1 SELECT * FROM t2 LIMIT 1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. INSERT INTO t1 VALUES(@@global.sync_binlog); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. UPDATE t1 SET i = 999 LIMIT 1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. DELETE FROM t1 LIMIT 1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. DROP TABLE t1, t2; SET @@SESSION.SQL_MODE = @save_sql_mode; "End of tests" diff --git a/mysql-test/suite/binlog/t/binlog_unsafe.test b/mysql-test/suite/binlog/t/binlog_unsafe.test index 1b0f0a6c30a..c4e1f31cbce 100644 --- a/mysql-test/suite/binlog/t/binlog_unsafe.test +++ b/mysql-test/suite/binlog/t/binlog_unsafe.test @@ -289,7 +289,7 @@ CREATE TABLE t1(i INT PRIMARY KEY); CREATE TABLE t2(i INT PRIMARY KEY); CREATE TABLE t3(i INT, ch CHAR(50)); ---echo "Should issue message Statement is not safe to log in statement format." +--echo "Should issue message Statement may not be safe to log in statement format." INSERT INTO t1 SELECT * FROM t2 LIMIT 1; DELIMITER |; @@ -302,7 +302,7 @@ BEGIN RETURN 0; END| DELIMITER ;| ---echo "Should issue message Statement is not safe to log in statement format only once" +--echo "Should issue message Statement may not be safe to log in statement format only once" INSERT INTO t3 VALUES(func6(), UUID()); --echo "Check whether SET @@SQL_LOG_BIN = 0/1 doesn't work in substatements" diff --git a/mysql-test/suite/rpl/r/rpl_stm_loadfile.result b/mysql-test/suite/rpl/r/rpl_stm_loadfile.result index 72f58268d5f..ca76695f4d4 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_loadfile.result +++ b/mysql-test/suite/rpl/r/rpl_stm_loadfile.result @@ -10,7 +10,7 @@ CREATE TABLE test.t1 (a INT, blob_column LONGBLOB, PRIMARY KEY(a)); INSERT INTO test.t1 VALUES(1,'test'); UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=1; Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. create procedure test.p1() begin INSERT INTO test.t1 VALUES(2,'test'); @@ -18,7 +18,7 @@ UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=2; end| CALL test.p1(); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. SELECT * FROM test.t1 ORDER BY blob_column; a blob_column 1 abase diff --git a/mysql-test/suite/rpl/r/rpl_udf.result b/mysql-test/suite/rpl/r/rpl_udf.result index 56df5b30d93..ccf16271d01 100644 --- a/mysql-test/suite/rpl/r/rpl_udf.result +++ b/mysql-test/suite/rpl/r/rpl_udf.result @@ -182,19 +182,19 @@ CREATE TABLE t1(sum INT, price FLOAT(24)) ENGINE=MyISAM; affected rows: 0 INSERT INTO t1 VALUES(myfunc_int(100), myfunc_double(50.00)); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. affected rows: 1 INSERT INTO t1 VALUES(myfunc_int(10), myfunc_double(5.00)); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. affected rows: 1 INSERT INTO t1 VALUES(myfunc_int(200), myfunc_double(25.00)); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. affected rows: 1 INSERT INTO t1 VALUES(myfunc_int(1), myfunc_double(500.00)); Warnings: -Note 1592 Statement is not safe to log in statement format. +Note 1592 Statement may not be safe to log in statement format. affected rows: 1 SELECT * FROM t1 ORDER BY sum; sum price diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index 795a92180db..3fc1697f146 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -439,14 +439,4 @@ SELECT CASE c1 WHEN c1 + 1 THEN 1 END, ABS(AVG(c0)) FROM t1; DROP TABLE t1; -# -# Bug #44399: crash with statement using TEXT columns, aggregates, GROUP BY, -# and HAVING -# - -CREATE TABLE t1(a TEXT); -INSERT INTO t1 VALUES('iynfj'); -SELECT SUM( DISTINCT a ) FROM t1 GROUP BY a HAVING a IN ( AVG( 1 ), 1 + a ); -DROP TABLE t1; - --echo End of 5.1 tests diff --git a/sql-common/client.c b/sql-common/client.c index d2c7e02551d..a6a2be1086f 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -120,6 +120,7 @@ const char *def_shared_memory_base_name= default_shared_memory_base_name; static void mysql_close_free_options(MYSQL *mysql); static void mysql_close_free(MYSQL *mysql); +static void mysql_prune_stmt_list(MYSQL *mysql); #if !(defined(__WIN__) || defined(__NETWARE__)) static int wait_for_data(my_socket fd, uint timeout); @@ -924,6 +925,7 @@ void end_server(MYSQL *mysql) vio_delete(mysql->net.vio); reset_sigpipe(mysql); mysql->net.vio= 0; /* Marker */ + mysql_prune_stmt_list(mysql); } net_end(&mysql->net); free_old_query(mysql); @@ -2526,30 +2528,9 @@ my_bool mysql_reconnect(MYSQL *mysql) tmp_mysql.reconnect= 1; tmp_mysql.free_me= mysql->free_me; - /* - For each stmt in mysql->stmts, move it to tmp_mysql if it is - in state MYSQL_STMT_INIT_DONE, otherwise close it. - */ - { - LIST *element= mysql->stmts; - for (; element; element= element->next) - { - MYSQL_STMT *stmt= (MYSQL_STMT *) element->data; - 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 - { - tmp_mysql.stmts= list_add(tmp_mysql.stmts, &stmt->list); - } - /* No need to call list_delete for statement here */ - } - mysql->stmts= NULL; - } + /* Move prepared statements (if any) over to the new mysql object */ + tmp_mysql.stmts= mysql->stmts; + mysql->stmts= 0; /* Don't free options as these are now used in tmp_mysql */ bzero((char*) &mysql->options,sizeof(mysql->options)); @@ -2639,6 +2620,46 @@ static void mysql_close_free(MYSQL *mysql) } +/** + For use when the connection to the server has been lost (in which case + the server has discarded all information about prepared statements + associated with the connection). + + Mark all statements in mysql->stmts by setting stmt->mysql= 0 if the + statement has transitioned beyond the MYSQL_STMT_INIT_DONE state, and + unlink the statement from the mysql->stmts list. + + The remaining pruned list of statements (if any) is kept in mysql->stmts. + + @param mysql pointer to the MYSQL object + + @return none +*/ +static void mysql_prune_stmt_list(MYSQL *mysql) +{ + LIST *element= mysql->stmts; + LIST *pruned_list= 0; + + for (; element; element= element->next) + { + MYSQL_STMT *stmt= (MYSQL_STMT *) element->data; + 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 + { + pruned_list= list_add(pruned_list, element); + } + } + + mysql->stmts= pruned_list; +} + + /* Clear connection pointer of every statement: this is necessary to give error on attempt to use a prepared statement of closed diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 5017464f968..a9bfea1b806 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -189,7 +189,6 @@ enum_field_types agg_field_type(Item **items, uint nitems) collect_cmp_types() items Array of items to collect types from nitems Number of items in the array - with_sum_func a sum function is referenced DESCRIPTION This function collects different result types for comparison of the first @@ -200,7 +199,7 @@ enum_field_types agg_field_type(Item **items, uint nitems) Bitmap of collected types - otherwise */ -static uint collect_cmp_types(Item **items, uint nitems, my_bool with_sum_func) +static uint collect_cmp_types(Item **items, uint nitems) { uint i; uint found_types; @@ -216,16 +215,6 @@ static uint collect_cmp_types(Item **items, uint nitems, my_bool with_sum_func) found_types|= 1<< (uint)item_cmp_type(left_result, items[i]->result_type()); } - if (with_sum_func || current_thd->lex->current_select->group_list.elements) - { - /* - See TODO commentary in the setup_copy_fields function: - item in a group may be wrapped with an Item_copy_string item. - That item has a STRING_RESULT result type, so we need - to take this type into account. - */ - found_types |= (1 << item_cmp_type(left_result, STRING_RESULT)); - } return found_types; } @@ -2733,8 +2722,19 @@ void Item_func_case::fix_length_and_dec() for (nagg= 0; nagg < ncases/2 ; nagg++) agg[nagg+1]= args[nagg*2]; nagg++; - if (!(found_types= collect_cmp_types(agg, nagg, with_sum_func))) + if (!(found_types= collect_cmp_types(agg, nagg))) return; + if (with_sum_func || current_thd->lex->current_select->group_list.elements) + { + /* + See TODO commentary in the setup_copy_fields function: + item in a group may be wrapped with an Item_copy_string item. + That item has a STRING_RESULT result type, so we need + to take this type into account. + */ + found_types |= (1 << item_cmp_type(left_result_type, STRING_RESULT)); + } + for (i= 0; i <= (uint)DECIMAL_RESULT; i++) { if (found_types & (1 << i) && !cmp_items[i]) @@ -3525,7 +3525,7 @@ void Item_func_in::fix_length_and_dec() uint type_cnt= 0, i; Item_result cmp_type= STRING_RESULT; left_result_type= args[0]->result_type(); - if (!(found_types= collect_cmp_types(args, arg_count, with_sum_func))) + if (!(found_types= collect_cmp_types(args, arg_count))) return; for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index cd11b6d4c24..cc7ea75dbbf 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2461,6 +2461,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end); + /* Close connection socket; for use with client testing (Bug#43560). */ + DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio);); + DBUG_VOID_RETURN; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 1183256eb1a..e56d1e9f506 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -103,7 +103,7 @@ if (!opt_silent) \ static void print_error(const char *msg); static void print_st_error(MYSQL_STMT *stmt, const char *msg); -static void client_disconnect(void); +static void client_disconnect(MYSQL* mysql, my_bool drop_db); /* @@ -271,10 +271,20 @@ mysql_simple_prepare(MYSQL *mysql_arg, const char *query) } -/* Connect to the server */ +/** + Connect to the server with options given by arguments to this application, + stored in global variables opt_host, opt_user, opt_password, opt_db, + opt_port and opt_unix_socket. -static void client_connect(ulong flag) + @param flag[in] client_flag passed on to mysql_real_connect + @param protocol[in] MYSQL_PROTOCOL_* to use for this connection + @param auto_reconnect[in] set to 1 for auto reconnect + + @return pointer to initialized and connected MYSQL object +*/ +static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect) { + MYSQL* mysql; int rc; static char query[MAX_TEST_QUERY_LENGTH]; myheader_r("client_connect"); @@ -291,6 +301,7 @@ static void client_connect(ulong flag) } /* enable local infile, in non-binary builds often disabled by default */ mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0); + mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol); if (!(mysql_real_connect(mysql, opt_host, opt_user, opt_password, opt_db ? opt_db:"test", opt_port, @@ -302,7 +313,7 @@ static void client_connect(ulong flag) fprintf(stdout, "\n Check the connection options using --help or -?\n"); exit(1); } - mysql->reconnect= 1; + mysql->reconnect= auto_reconnect; if (!opt_silent) fprintf(stdout, "OK"); @@ -329,12 +340,14 @@ static void client_connect(ulong flag) if (!opt_silent) fprintf(stdout, "OK"); + + return mysql; } /* Close the connection */ -static void client_disconnect() +static void client_disconnect(MYSQL* mysql, my_bool drop_db) { static char query[MAX_TEST_QUERY_LENGTH]; @@ -342,13 +355,16 @@ static void client_disconnect() if (mysql) { - if (!opt_silent) - fprintf(stdout, "\n dropping the test database '%s' ...", current_db); - strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS); + if (drop_db) + { + if (!opt_silent) + fprintf(stdout, "\n dropping the test database '%s' ...", current_db); + strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS); - mysql_query(mysql, query); - if (!opt_silent) - fprintf(stdout, "OK"); + mysql_query(mysql, query); + if (!opt_silent) + fprintf(stdout, "OK"); + } if (!opt_silent) fprintf(stdout, "\n closing the connection ..."); @@ -17712,6 +17728,100 @@ static void test_bug40365(void) } +/** + Subtest for Bug#43560. Verifies that a loss of connection on the server side + is handled well by the mysql_stmt_execute() call, i.e., no SIGSEGV due to + a vio socket that is cleared upon closed connection. + + Assumes the presence of the close_conn_after_stmt_execute debug feature in + the server. Verifies that it is connected to a debug server before proceeding + with the test. + */ +static void test_bug43560(void) +{ + MYSQL* conn; + uint rc; + MYSQL_STMT *stmt= 0; + MYSQL_BIND bind; + my_bool is_null= 0; + const uint BUFSIZE= 256; + char buffer[BUFSIZE]; + const char* values[] = {"eins", "zwei", "drei", "viele", NULL}; + const char insert_str[] = "INSERT INTO t1 (c2) VALUES (?)"; + unsigned long length; + + DBUG_ENTER("test_bug43560"); + myheader("test_bug43560"); + + /* Make sure we only run against a debug server. */ + if (!strstr(mysql->server_version, "debug")) + { + fprintf(stdout, "Skipping test_bug43560: server not DEBUG version\n"); + DBUG_VOID_RETURN; + } + + /* + Set up a separate connection for this test to avoid messing up the + general MYSQL object used in other subtests. Use TCP protocol to avoid + problems with the buffer semantics of AF_UNIX, and turn off auto reconnect. + */ + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + + rc= mysql_query(conn, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(conn, + "CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 CHAR(10))"); + myquery(rc); + + stmt= mysql_stmt_init(conn); + check_stmt(stmt); + rc= mysql_stmt_prepare(stmt, insert_str, strlen(insert_str)); + check_execute(stmt, rc); + + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer_length= BUFSIZE; + bind.buffer= buffer; + bind.is_null= &is_null; + bind.length= &length; + rc= mysql_stmt_bind_param(stmt, &bind); + check_execute(stmt, rc); + + /* First execute; should succeed. */ + strncpy(buffer, values[0], BUFSIZE); + length= strlen(buffer); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* + Set up the server to close this session's server-side socket after + next execution of prep statement. + */ + rc= mysql_query(conn,"SET SESSION debug='+d,close_conn_after_stmt_execute'"); + myquery(rc); + + /* Second execute; should fail due to socket closed during execution. */ + strncpy(buffer, values[1], BUFSIZE); + length= strlen(buffer); + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc && mysql_stmt_errno(stmt) == CR_SERVER_LOST); + + /* + Third execute; should fail (connection already closed), or SIGSEGV in + case of a Bug#43560 type regression in which case the whole test fails. + */ + strncpy(buffer, values[2], BUFSIZE); + length= strlen(buffer); + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc && mysql_stmt_errno(stmt) == CR_SERVER_LOST); + + client_disconnect(conn, 0); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + /** Bug#36326: nested transaction and select */ @@ -18140,6 +18250,7 @@ static struct my_tests_st my_tests[]= { { "test_wl4166_2", test_wl4166_2 }, { "test_bug38486", test_bug38486 }, { "test_bug40365", test_bug40365 }, + { "test_bug43560", test_bug43560 }, #ifdef HAVE_QUERY_CACHE { "test_bug36326", test_bug36326 }, #endif @@ -18268,7 +18379,8 @@ int main(int argc, char **argv) (char**) embedded_server_groups)) DIE("Can't initialize MySQL server"); - client_connect(0); /* connect to server */ + /* connect to server with no flags, default protocol, auto reconnect true */ + mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1); total_time= 0; for (iter_count= 1; iter_count <= opt_count; iter_count++) @@ -18298,7 +18410,7 @@ int main(int argc, char **argv) fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv); fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n", my_progname); - client_disconnect(); + client_disconnect(mysql, 1); free_defaults(defaults_argv); exit(1); } @@ -18311,7 +18423,7 @@ int main(int argc, char **argv) /* End of tests */ } - client_disconnect(); /* disconnect from server */ + client_disconnect(mysql, 1); /* disconnect from server */ free_defaults(defaults_argv); print_test_output();