diff --git a/client/mysqltest.c b/client/mysqltest.c index ce1a64ec653..0d97eb38c30 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1443,38 +1443,40 @@ int do_system(struct st_query *q) /* Print the content between echo and to result file. - If content is a variable, the variable value will be retrieved + Evaluate all variables in the string before printing, allow + for variable names to be escaped using \ SYNOPSIS do_echo() q called command DESCRIPTION - Usage 1: echo text Print the text after echo until end of command to result file - Usage 2: echo $ Print the content of the variable to result file + echo Some text $ + Print "Some text" plus the content of the variable to + result file + + echo Some text \$ + Print "Some text" plus $ to result file */ -int do_echo(struct st_query *q) +int do_echo(struct st_query *command) { - char *p= q->first_argument; - DYNAMIC_STRING *ds; - VAR v; - var_init(&v,0,0,0,0); + DYNAMIC_STRING *ds, ds_echo; ds= &ds_res; - eval_expr(&v, p, 0); /* NULL terminated */ - if (v.str_val_len) - dynstr_append_mem(ds, v.str_val, v.str_val_len); + init_dynamic_string(&ds_echo, "", 256, 256); + do_eval(&ds_echo, command->first_argument); + dynstr_append_mem(ds, ds_echo.str, ds_echo.length); dynstr_append_mem(ds, "\n", 1); - var_free(&v); - q->last_argument= q->end; + dynstr_free(&ds_echo); + command->last_argument= command->end; return 0; } @@ -3733,7 +3735,7 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s", - mysql_stmt_error(stmt), mysql_stmt_errno(stmt)); + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); free_replace_column(); @@ -4199,7 +4201,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, if (mysql_stmt_prepare(stmt, query, query_len)) { handle_error(query, command, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); goto end; } @@ -4215,29 +4217,34 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, parameter markers. */ -#ifdef BUG14013_FIXED - /* - Use cursor when retrieving result - */ if (cursor_protocol_enabled) { + /* + Use cursor when retrieving result + */ ulong type= CURSOR_TYPE_READ_ONLY; if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type)) die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s", - mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); } -#endif /* Execute the query - */ + */ if (mysql_stmt_execute(stmt)) { handle_error(query, command, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); goto end; } + /* + When running in cursor_protocol get the warnings from execute here + and keep them in a separate string for later. + */ + if (cursor_protocol_enabled && !disable_warnings) + append_warnings(&ds_execute_warnings, mysql); + /* We instruct that we want to update the "max_length" field in mysql_stmt_store_result(), this is our only way to know how much @@ -4247,7 +4254,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, my_bool one= 1; if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one)) die("mysql_stmt_attr_set(STMT_ATTR_UPDATE_MAX_LENGTH) failed': %d %s", - mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); } /* @@ -4257,7 +4264,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, if (mysql_stmt_store_result(stmt)) { handle_error(query, command, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); goto end; } @@ -4278,10 +4285,10 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, uint num_fields= mysql_num_fields(res); if (display_metadata) - append_metadata(ds, fields, num_fields); + append_metadata(ds, fields, num_fields); if (!display_result_vertically) - append_table_headings(ds, fields, num_fields); + append_table_headings(ds, fields, num_fields); append_stmt_result(ds, stmt, fields, num_fields); @@ -4303,10 +4310,11 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, /* Append warnings to ds - if there are any */ if (append_warnings(&ds_execute_warnings, mysql) || - ds_prepare_warnings.length || - ds_warnings->length) + ds_execute_warnings.length || + ds_prepare_warnings.length || + ds_warnings->length) { - dynstr_append_mem(ds, "Warnings:\n", 10); + dynstr_append_mem(ds, "Warnings:\n", 10); if (ds_warnings->length) dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 0bf3b76bf45..4b7aace549a 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -4752,12 +4752,39 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) if (!stmt->field_count) DBUG_RETURN(0); - if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE || - mysql->status != MYSQL_STATUS_GET_RESULT) + + if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE) { set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); DBUG_RETURN(1); } + + if (mysql->status == MYSQL_STATUS_READY && + stmt->server_status & SERVER_STATUS_CURSOR_EXISTS) + { + /* + Server side cursor exist, tell server to start sending the rows + */ + NET *net= &mysql->net; + char buff[4 /* statement id */ + + 4 /* number of rows to fetch */]; + + /* Send row request to the server */ + 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)) + { + set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); + DBUG_RETURN(1); + } + } + else if (mysql->status != MYSQL_STATUS_GET_RESULT) + { + set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); + DBUG_RETURN(1); + } + if (result->data) { free_root(&result->alloc, MYF(MY_KEEP_PREALLOC)); @@ -4798,6 +4825,10 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) DBUG_RETURN(1); } + /* Assert that if there was a cursor, all rows have been fetched */ + DBUG_ASSERT(mysql->status != MYSQL_STATUS_READY || + (mysql->server_status & SERVER_STATUS_LAST_ROW_SENT)); + if (stmt->update_max_length) { MYSQL_ROWS *cur= result->data; diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 2ef005f4ceb..03acd7a2ce2 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -201,8 +201,14 @@ source database - world''s most -- popular open # source database -'$message' -"$message" +'# MySQL: The +- world''s most +-- popular open +# source database' +"# MySQL: The +- world''s most +-- popular open +# source database" hej hej hej @@ -221,6 +227,15 @@ mysqltest: At line 1: Missing arguments to let mysqltest: At line 1: Missing variable name in let mysqltest: At line 1: Missing variable name in let mysqltest: At line 1: Missing assignment operator in let +# Execute: --echo # success: $success +# success: 1 +# Execute: echo # success: $success ; +# success: 1 +# The next two variants work fine and expand the content of $success +# Execute: --echo $success +1 +# Execute: echo $success ; +1 mysqltest: At line 1: Missing file name in source mysqltest: At line 1: Could not open file ./non_existingFile mysqltest: In included file "MYSQLTEST_VARDIR/tmp/recursive.sql": At line 1: Source directives are nesting too deep diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 916e63bc7cb..62e667f6b6e 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -20,7 +20,6 @@ ndb_autodiscover2 : Needs to be fixed w.r.t binlog ndb_binlog_basic : Results are not deterministic, Tomas will fix ndb_binlog_ddl_multi : Bug#17038 [PATCH PENDING] ndb_gis : garbled msgs from corrupt THD* -ndb_load : Bug#17233 partition_03ndb : Bug#16385 ps_7ndb : dbug assert in RBR mode when executing test suite rpl_bit_npk : Bug#13418 diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 271d6fb783e..5bdad986b12 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -538,6 +538,19 @@ echo $novar1; --error 1 --exec echo "let hi;" | $MYSQL_TEST 2>&1 +# More advanced test for bug#17280 +let $success= 1; +--echo # Execute: --echo # success: \$success +--echo # success: $success +--echo # Execute: echo # success: \$success ; +echo # success: $success ; + +--echo # The next two variants work fine and expand the content of \$success +--echo # Execute: --echo \$success +--echo $success +--echo # Execute: echo \$success ; +echo $success ; + # ---------------------------------------------------------------------------- # Test to assign let from query # let $=``; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 32302732f14..7db643574c5 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -1049,7 +1049,10 @@ void stmt_fetch_close(Stmt_fetch *fetch) reading from the rest. */ -my_bool fetch_n(const char **query_list, unsigned query_count) +enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 }; + +my_bool fetch_n(const char **query_list, unsigned query_count, + enum fetch_type fetch_type) { unsigned open_statements= query_count; int rc, error_count= 0; @@ -1065,6 +1068,15 @@ my_bool fetch_n(const char **query_list, unsigned query_count) query_list[fetch - fetch_array]); } + if (fetch_type == USE_STORE_RESULT) + { + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + rc= mysql_stmt_store_result(fetch->handle); + check_execute(fetch->handle, rc); + } + } + while (open_statements) { for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) @@ -11867,7 +11879,8 @@ static void test_basic_cursors() fill_tables(basic_tables, sizeof(basic_tables)/sizeof(*basic_tables)); - fetch_n(queries, sizeof(queries)/sizeof(*queries)); + fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH); + fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT); DBUG_VOID_RETURN; } @@ -11880,7 +11893,8 @@ static void test_cursors_with_union() "SELECT t1.id FROM t1 WHERE t1.id < 5" }; myheader("test_cursors_with_union"); - fetch_n(queries, sizeof(queries)/sizeof(*queries)); + fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH); + fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT); } /*