From 3f25e323c583cfb411c521ad58d3b59fca70fa91 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2006 12:11:16 +0100 Subject: [PATCH 1/4] Bug#17280 mysqltest, --echo sometimes does not expand $variables - Evaluate all variables in the text before printing it to result file client/mysqltest.c: Update echo command to vvaluate all variables in the string before printing, allow for variable names to be escaped using \ mysql-test/r/mysqltest.result: Update results for echo mysql-test/t/mysqltest.test: Add more advanced tests for echo of strings with several variables and/or text plus variables. Also test that variables can be escaped --- client/mysqltest.c | 28 +++++++++++++++------------- mysql-test/r/mysqltest.result | 19 +++++++++++++++++-- mysql-test/t/mysqltest.test | 13 +++++++++++++ 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 6a2a7b072de..8c712541fb5 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1384,38 +1384,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; } diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 067054510c2..53141a8d266 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 @@ -222,6 +228,15 @@ mysqltest: At line 1: Missing arguments to let mysqltest: At line 1: Missing variable name in let mysqltest: At line 1: Variable name in =hi does not start with '$' 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 "./var/tmp/recursive.sql": At line 1: Source directives are nesting too deep diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 5cf49185c30..caedbfab4a6 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -539,6 +539,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 $=``; From 101e618f7f46fb0012a4166aea7213730a0b4281 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2006 14:50:29 +0100 Subject: [PATCH 2/4] Bug#14013 mysql_stmt_store_result() bombs if a cursor is open - Add code to 'mysql_stmt_store_result' to allow it to be called on a prepared statement with open server side cursor. - Add tests to mysql_client_test that uses 'mysql_stmt_store_result' client/mysqltest.c: Enable cursor protocol(remove the ifdef BUG14013_FIXED) When running in cursor mode, the warnings from execute needs to be extracted after mysql_stmt_execute, put them in a dynamic string for later use. Untabify some tabs. libmysql/libmysql.c: Allow 'mysql_stmt_store_result' to be called on a statement with an open server side cursor. Detect that a server side cursor is open and send a "fetch" to ask for all rows to be sent to the client. Read all binary rows as normal store. Check that server said last row was sent after all binary rows has been sent. tests/mysql_client_test.c: Update 'fetch_n' function to take parameter indicating if 'mysql_stmt_store_result' should be used on the statement. Call fetch_n with parameter set to use 'mysql_stmt_store_result' --- client/mysqltest.c | 40 ++++++++++++++++++++++----------------- libmysql/libmysql.c | 35 ++++++++++++++++++++++++++++++++-- tests/mysql_client_test.c | 20 +++++++++++++++++--- 3 files changed, 73 insertions(+), 22 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 24be5de8021..3851a922e13 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3167,7 +3167,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(); @@ -3632,7 +3632,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; } @@ -3648,29 +3648,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 @@ -3680,7 +3685,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)); } /* @@ -3690,7 +3695,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; } @@ -3711,10 +3716,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); @@ -3736,10 +3741,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 11ee7284cbf..30eecf809c5 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -4757,12 +4757,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)); @@ -4803,6 +4830,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/tests/mysql_client_test.c b/tests/mysql_client_test.c index 216961b3a80..25729e9f47c 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); } /* From 1a9c96c58c555245a8e44824795a8ac5d46581fe Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2006 17:15:24 +0100 Subject: [PATCH 3/4] Change from std_data to std_data_ln --- mysql-test/r/ndb_load.result | 4 ++-- mysql-test/t/ndb_load.test | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/ndb_load.result b/mysql-test/r/ndb_load.result index 76da5b2a215..416a350066b 100644 --- a/mysql-test/r/ndb_load.result +++ b/mysql-test/r/ndb_load.result @@ -1,10 +1,10 @@ DROP TABLE IF EXISTS t1; CREATE TABLE t1 (word CHAR(20) NOT NULL PRIMARY KEY) ENGINE=NDB; -LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1 ; +LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t1 ; ERROR 23000: Can't write; duplicate key in table 't1' DROP TABLE t1; CREATE TABLE t1 (word CHAR(20) NOT NULL) ENGINE=NDB; -LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1 ; +LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t1 ; SELECT * FROM t1 ORDER BY word; word Aarhus diff --git a/mysql-test/t/ndb_load.test b/mysql-test/t/ndb_load.test index 72a5b53eaad..af2df70b74e 100644 --- a/mysql-test/t/ndb_load.test +++ b/mysql-test/t/ndb_load.test @@ -12,12 +12,12 @@ DROP TABLE IF EXISTS t1; # should give duplicate key CREATE TABLE t1 (word CHAR(20) NOT NULL PRIMARY KEY) ENGINE=NDB; --error 1022 -LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1 ; +LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t1 ; DROP TABLE t1; # now without a primary key we should be ok CREATE TABLE t1 (word CHAR(20) NOT NULL) ENGINE=NDB; -LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1 ; +LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t1 ; SELECT * FROM t1 ORDER BY word; DROP TABLE t1; From 4b114615cfbab3c54e8dc236ae7cccffa5c9c9a3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2006 17:21:18 +0100 Subject: [PATCH 4/4] Enable ndb_load test case mysql-test/t/disabled.def: Enable test case --- mysql-test/t/disabled.def | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 09a11578096..46f15983dc3 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -12,4 +12,3 @@ sp-goto : GOTO is currently is disabled - will be fixed in the future subselect : Bug#15706 -ndb_load : Bug #17233