summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/CMakeLists.txt2
-rw-r--r--client/mysql.cc139
-rw-r--r--client/mysql_upgrade.c9
-rw-r--r--client/mysqladmin.cc32
-rw-r--r--client/mysqltest.cc419
5 files changed, 419 insertions, 182 deletions
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index 55fd02b2..4dfce247 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -16,7 +16,7 @@
INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/include
- ${PCRE_INCLUDES}
+ ${PCRE_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/mysys_ssl
${ZLIB_INCLUDE_DIR}
${SSL_INCLUDE_DIRS}
diff --git a/client/mysql.cc b/client/mysql.cc
index 1c842dae..ab4c3cd7 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -261,6 +261,9 @@ static int connect_flag=CLIENT_INTERACTIVE;
static my_bool opt_binary_mode= FALSE;
static my_bool opt_connect_expired_password= FALSE;
static int interrupted_query= 0;
+#ifdef USE_LIBEDIT_INTERFACE
+static int sigint_received= 0;
+#endif
static char *current_host,*current_db,*current_user=0,*opt_password=0,
*current_prompt=0, *delimiter_str= 0,
*default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME,
@@ -1162,6 +1165,8 @@ extern "C" sig_handler handle_sigint(int sig);
static sig_handler window_resize(int sig);
#endif
+static void end_in_sig_handler(int sig);
+static bool kill_query(const char *reason);
const char DELIMITER_NAME[]= "delimiter";
const uint DELIMITER_NAME_LEN= sizeof(DELIMITER_NAME) - 1;
@@ -1301,8 +1306,8 @@ int main(int argc,char *argv[])
if (opt_sigint_ignore)
signal(SIGINT, SIG_IGN);
else
- signal(SIGINT, handle_sigint); // Catch SIGINT to clean up
- signal(SIGQUIT, mysql_end); // Catch SIGQUIT to clean up
+ signal(SIGINT, handle_sigint); // Catch SIGINT to clean up
+ signal(SIGQUIT, mysql_end); // Catch SIGQUIT to clean up
#if defined(HAVE_TERMIOS_H) && defined(GWINSZ_IN_SYS_IOCTL)
/* Readline will call this if it installs a handler */
@@ -1512,30 +1517,35 @@ static bool do_connect(MYSQL *mysql, const char *host, const char *user,
}
-/*
- This function handles sigint calls
- If query is in process, kill query
- If 'source' is executed, abort source command
- no query in process, terminate like previous behavior
- */
+void end_in_sig_handler(int sig)
+{
+#ifdef _WIN32
+ /*
+ When SIGINT is raised on Windows, the OS creates a new thread to handle the
+ interrupt. Once that thread completes, the main thread continues running
+ only to find that it's resources have already been free'd when the sigint
+ handler called mysql_end().
+ */
+ mysql_thread_end();
+#else
+ mysql_end(sig);
+#endif
+}
-sig_handler handle_sigint(int sig)
+
+/*
+ Kill a running query. Returns true if we were unable to connect to the server.
+*/
+bool kill_query(const char *reason)
{
char kill_buffer[40];
MYSQL *kill_mysql= NULL;
- /* terminate if no query being executed, or we already tried interrupting */
- if (!executing_query || (interrupted_query == 2))
- {
- tee_fprintf(stdout, "Ctrl-C -- exit!\n");
- goto err;
- }
-
kill_mysql= mysql_init(kill_mysql);
if (!do_connect(kill_mysql,current_host, current_user, opt_password, "", 0))
{
- tee_fprintf(stdout, "Ctrl-C -- sorry, cannot connect to server to kill query, giving up ...\n");
- goto err;
+ tee_fprintf(stdout, "%s -- sorry, cannot connect to server to kill query, giving up ...\n", reason);
+ return true;
}
/* First time try to kill the query, second time the connection */
@@ -1550,27 +1560,62 @@ sig_handler handle_sigint(int sig)
(interrupted_query == 1) ? "QUERY " : "",
mysql_thread_id(&mysql));
if (verbose)
- tee_fprintf(stdout, "Ctrl-C -- sending \"%s\" to server ...\n",
+ tee_fprintf(stdout, "%s -- sending \"%s\" to server ...\n", reason,
kill_buffer);
mysql_real_query(kill_mysql, kill_buffer, (uint) strlen(kill_buffer));
mysql_close(kill_mysql);
- tee_fprintf(stdout, "Ctrl-C -- query killed. Continuing normally.\n");
+ if (interrupted_query == 1)
+ tee_fprintf(stdout, "%s -- query killed.\n", reason);
+ else
+ tee_fprintf(stdout, "%s -- connection killed.\n", reason);
+
if (in_com_source)
aborted= 1; // Abort source command
- return;
+ return false;
+}
-err:
-#ifdef _WIN32
+/*
+ This function handles sigint calls
+ If query is in process, kill query
+ If 'source' is executed, abort source command
+ no query in process, regenerate prompt.
+*/
+sig_handler handle_sigint(int sig)
+{
/*
- When SIGINT is raised on Windows, the OS creates a new thread to handle the
- interrupt. Once that thread completes, the main thread continues running
- only to find that it's resources have already been free'd when the sigint
- handler called mysql_end().
+ On Unix only, if no query is being executed just clear the prompt,
+ don't exit. On Windows we exit.
*/
- mysql_thread_end();
+ if (!executing_query)
+ {
+#ifndef _WIN32
+ tee_fprintf(stdout, "^C\n");
+#ifdef USE_LIBEDIT_INTERFACE
+ /* Libedit will regenerate it outside of the signal handler. */
+ sigint_received= 1;
#else
- mysql_end(sig);
-#endif
+ rl_on_new_line(); // Regenerate the prompt on a newline
+ rl_replace_line("", 0); // Clear the previous text
+ rl_redisplay();
+#endif
+#else // WIN32
+ tee_fprintf(stdout, "Ctrl-C -- exit!\n");
+ end_in_sig_handler(sig);
+#endif
+ return;
+ }
+
+ /*
+ When executing a query, this newline makes the prompt look like so:
+ ^C
+ Ctrl-C -- query killed.
+ */
+ tee_fprintf(stdout, "\n");
+ if (kill_query("Ctrl-C"))
+ {
+ aborted= 1;
+ end_in_sig_handler(sig);
+ }
}
@@ -2137,6 +2182,15 @@ static int get_options(int argc, char **argv)
return(0);
}
+
+#if !defined(_WIN32) && defined(USE_LIBEDIT_INTERFACE)
+static inline void reset_prompt(char *in_string, bool *ml_comment) {
+ glob_buffer.length(0);
+ *ml_comment = false;
+ *in_string = 0;
+}
+#endif
+
static int read_and_execute(bool interactive)
{
char *line= NULL;
@@ -2228,7 +2282,30 @@ static int read_and_execute(bool interactive)
if (line)
free(line);
line= readline(prompt);
-#endif /* defined(_WIN32) */
+#ifdef USE_LIBEDIT_INTERFACE
+ /*
+ libedit handles interrupts different than libreadline.
+ libreadline has its own signal handlers, thus a sigint during readline
+ doesn't force readline to return null string.
+
+ However libedit returns null if the interrupt signal is raised.
+ We can also get an empty string when ctrl+d is pressed (EoF).
+
+ We need this sigint_received flag, to differentiate between the two
+ cases. This flag is only set during our handle_sigint function when
+ LIBEDIT_INTERFACE is used.
+ */
+ if (!line && sigint_received)
+ {
+ // User asked to clear the input.
+ sigint_received= 0;
+ reset_prompt(&in_string, &ml_comment);
+ continue;
+ }
+ // For safety, we always mark this as cleared.
+ sigint_received= 0;
+#endif
+#endif /* defined(__WIN__) */
/*
When Ctrl+d or Ctrl+z is pressed, the line may be NULL on some OS
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c
index a6d497b2..7bac797f 100644
--- a/client/mysql_upgrade.c
+++ b/client/mysql_upgrade.c
@@ -1159,6 +1159,8 @@ static int install_used_plugin_data_types(void)
DYNAMIC_STRING ds_result;
const char *query = "SELECT table_comment FROM information_schema.tables"
" WHERE table_comment LIKE 'Unknown data type: %'";
+ if (opt_systables_only)
+ return 0;
if (init_dynamic_string(&ds_result, "", 512, 512))
die("Out of memory");
run_query(query, &ds_result, TRUE);
@@ -1475,7 +1477,12 @@ int main(int argc, char **argv)
open_mysql_upgrade_file();
if (opt_check_upgrade)
- exit(upgrade_already_done(0) == 0);
+ {
+ int upgrade_needed = upgrade_already_done(0);
+ free_used_memory();
+ my_end(my_end_arg);
+ exit(upgrade_needed == 0);
+ }
/* Find mysqlcheck */
find_tool(mysqlcheck_path, IF_WIN("mariadb-check.exe", "mariadb-check"), self_name);
diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc
index 022ba2ae..69bd3cd7 100644
--- a/client/mysqladmin.cc
+++ b/client/mysqladmin.cc
@@ -28,7 +28,7 @@
#include <password.h>
#include <my_sys.h>
-#define ADMIN_VERSION "9.1"
+#define ADMIN_VERSION "10.0"
#define MAX_MYSQL_VAR 512
#define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */
#define MAX_TRUNC_LENGTH 3
@@ -40,12 +40,12 @@ char ex_var_names[MAX_MYSQL_VAR+100][FN_REFLEN];
ulonglong last_values[MAX_MYSQL_VAR+100];
static int interval=0;
static my_bool option_force=0,interrupted=0,new_line=0,
- opt_compress= 0, opt_local= 0, opt_relative= 0, opt_verbose= 0,
+ opt_compress= 0, opt_local= 0, opt_relative= 0,
opt_vertical= 0, tty_password= 0, opt_nobeep,
- opt_shutdown_wait_for_slaves= 0;
+ opt_shutdown_wait_for_slaves= 0, opt_not_used;
static my_bool debug_info_flag= 0, debug_check_flag= 0;
static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations;
-static uint opt_count_iterations= 0, my_end_arg;
+static uint opt_count_iterations= 0, my_end_arg, opt_verbose= 0;
static ulong opt_connect_timeout, opt_shutdown_timeout;
static char * unix_port=0;
static char *opt_plugin_dir= 0, *opt_default_auth= 0;
@@ -204,8 +204,10 @@ static struct my_option my_long_options[] =
{"user", 'u', "User for login if not current user.", &user,
&user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
- {"verbose", 'v', "Write more information.", &opt_verbose,
- &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"verbose", 'v', "Write more information."
+ "Using it will print more information for 'processlist."
+ "Using it 2 times will print even more information for 'processlist'.",
+ &opt_not_used, &opt_not_used, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"vertical", 'E',
@@ -298,6 +300,11 @@ get_one_option(const struct my_option *opt, const char *argument,
case 'I': /* Info */
usage();
exit(0);
+ case 'v': /* --verbose */
+ opt_verbose++;
+ if (argument == disabled_my_option)
+ opt_verbose= 0;
+ break;
case OPT_CHARSETS_DIR:
#if MYSQL_VERSION_ID > 32300
charsets_dir = argument;
@@ -828,10 +835,17 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
{
MYSQL_RES *result;
MYSQL_ROW row;
+ const char *query;
+
+ if (!opt_verbose)
+ query= "show processlist";
+ else if (opt_verbose == 1)
+ query= "show full processlist";
+ else
+ query= "select * from information_schema.processlist where id != connection_id()";
- if (mysql_query(mysql, (opt_verbose ? "show full processlist" :
- "show processlist")) ||
- !(result = mysql_store_result(mysql)))
+ if (mysql_query(mysql, query) ||
+ !(result = mysql_store_result(mysql)))
{
my_printf_error(0, "process list failed; error: '%s'", error_flags,
mysql_error(mysql));
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index 87c5a62a..a49895c9 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -80,6 +80,9 @@ static my_bool non_blocking_api_enabled= 0;
#define DIE_BUFF_SIZE 256*1024
+#define RESULT_STRING_INIT_MEM 2048
+#define RESULT_STRING_INCREMENT_MEM 2048
+
/* Flags controlling send and reap */
#define QUERY_SEND_FLAG 1
#define QUERY_REAP_FLAG 2
@@ -88,6 +91,8 @@ static my_bool non_blocking_api_enabled= 0;
#define CLOSED_CONNECTION "-closed_connection-"
+#define dynstr_append DO_NO_USE
+
#ifndef HAVE_SETENV
static int setenv(const char *name, const char *value, int overwrite);
#endif
@@ -1729,7 +1734,7 @@ void log_msg(const char *fmt, ...)
va_end(args);
dynstr_append_mem(&ds_res, buff, len);
- dynstr_append(&ds_res, "\n");
+ dynstr_append_mem(&ds_res, STRING_WITH_LEN("\n"));
DBUG_VOID_RETURN;
}
@@ -1865,7 +1870,7 @@ static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...)
die("Out of memory");
dynstr_append_os_quoted(&ds_cmdline, tool_path, NullS);
- dynstr_append(&ds_cmdline, " ");
+ dynstr_append_mem(&ds_cmdline, STRING_WITH_LEN(" "));
va_start(args, ds_res);
@@ -1875,14 +1880,14 @@ static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...)
if (strncmp(arg, "--", 2) == 0)
dynstr_append_os_quoted(&ds_cmdline, arg, NullS);
else
- dynstr_append(&ds_cmdline, arg);
- dynstr_append(&ds_cmdline, " ");
+ dynstr_append_mem(&ds_cmdline, arg, strlen(arg));
+ dynstr_append_mem(&ds_cmdline, STRING_WITH_LEN(" "));
}
va_end(args);
#ifdef _WIN32
- dynstr_append(&ds_cmdline, "\"");
+ dynstr_append_mem(&ds_cmdline, STRING_WITH_LEN("\""));
#endif
DBUG_PRINT("info", ("Running: %s", ds_cmdline.str));
@@ -2017,8 +2022,8 @@ void show_diff(DYNAMIC_STRING* ds,
Fallback to dump both files to result file and inform
about installing "diff"
*/
- dynstr_append(&ds_tmp, "\n");
- dynstr_append(&ds_tmp,
+ char message[]=
+"\n"
"\n"
"The two files differ but it was not possible to execute 'diff' in\n"
"order to show only the difference. Instead the whole content of the\n"
@@ -2028,17 +2033,18 @@ void show_diff(DYNAMIC_STRING* ds,
#ifdef _WIN32
"or http://gnuwin32.sourceforge.net/packages/diffutils.htm\n"
#endif
-"\n");
+"\n";
+ dynstr_append_mem(&ds_tmp, message, sizeof(message));
- dynstr_append(&ds_tmp, " --- ");
- dynstr_append(&ds_tmp, filename1);
- dynstr_append(&ds_tmp, " >>>\n");
+ dynstr_append_mem(&ds_tmp, STRING_WITH_LEN(" --- "));
+ dynstr_append_mem(&ds_tmp, filename1, strlen(filename1));
+ dynstr_append_mem(&ds_tmp, STRING_WITH_LEN(" >>>\n"));
cat_file(&ds_tmp, filename1);
- dynstr_append(&ds_tmp, "<<<\n --- ");
- dynstr_append(&ds_tmp, filename1);
- dynstr_append(&ds_tmp, " >>>\n");
+ dynstr_append_mem(&ds_tmp, STRING_WITH_LEN("<<<\n --- "));
+ dynstr_append_mem(&ds_tmp, filename1, strlen(filename1));
+ dynstr_append_mem(&ds_tmp, STRING_WITH_LEN(" >>>\n"));
cat_file(&ds_tmp, filename2);
- dynstr_append(&ds_tmp, "<<<<\n");
+ dynstr_append_mem(&ds_tmp, STRING_WITH_LEN("<<<<\n"));
}
if (ds)
@@ -2818,9 +2824,9 @@ do_result_format_version(struct st_command *command)
set_result_format_version(version);
- dynstr_append(&ds_res, "result_format: ");
+ dynstr_append_mem(&ds_res, STRING_WITH_LEN("result_format: "));
dynstr_append_mem(&ds_res, ds_version.str, ds_version.length);
- dynstr_append(&ds_res, "\n");
+ dynstr_append_mem(&ds_res, STRING_WITH_LEN("\n"));
dynstr_free(&ds_version);
}
@@ -3291,13 +3297,15 @@ static int replace(DYNAMIC_STRING *ds_str,
{
DYNAMIC_STRING ds_tmp;
const char *start= strstr(ds_str->str, search_str);
+ size_t prefixlen= start - ds_str->str;
if (!start)
return 1;
init_dynamic_string(&ds_tmp, "",
ds_str->length + replace_len, 256);
- dynstr_append_mem(&ds_tmp, ds_str->str, start - ds_str->str);
+ dynstr_append_mem(&ds_tmp, ds_str->str, prefixlen);
dynstr_append_mem(&ds_tmp, replace_str, replace_len);
- dynstr_append(&ds_tmp, start + search_len);
+ dynstr_append_mem(&ds_tmp, start + search_len,
+ ds_str->length - prefixlen - search_len);
dynstr_set(ds_str, ds_tmp.str);
dynstr_free(&ds_tmp);
return 0;
@@ -3412,7 +3420,7 @@ void do_exec(struct st_command *command)
if (disable_result_log)
{
/* Collect stderr output as well, for the case app. crashes or returns error.*/
- dynstr_append(&ds_cmd, " 2>&1");
+ dynstr_append_mem(&ds_cmd, STRING_WITH_LEN(" 2>&1"));
}
DBUG_PRINT("info", ("Executing '%s' as '%s'",
@@ -3624,9 +3632,9 @@ void do_system(struct st_command *command)
else
{
/* If ! abort_on_error, log message and continue */
- dynstr_append(&ds_res, "system command '");
+ dynstr_append_mem(&ds_res, STRING_WITH_LEN("system command '"));
replace_dynstr_append(&ds_res, command->first_argument);
- dynstr_append(&ds_res, "' failed\n");
+ dynstr_append_mem(&ds_res, STRING_WITH_LEN("' failed\n"));
}
}
@@ -3802,7 +3810,7 @@ void do_remove_files_wildcard(struct st_command *command)
wild_compare(file->name, ds_wild.str, 0))
continue;
ds_file_to_remove.length= directory_length;
- dynstr_append(&ds_file_to_remove, file->name);
+ dynstr_append_mem(&ds_file_to_remove, file->name, strlen(file->name));
DBUG_PRINT("info", ("removing file: %s", ds_file_to_remove.str));
if ((error= (my_delete(ds_file_to_remove.str, MYF(MY_WME)) != 0)))
sys_errno= my_errno;
@@ -4092,7 +4100,7 @@ static int get_list_files(DYNAMIC_STRING *ds, const DYNAMIC_STRING *ds_dirname,
wild_compare(file->name, ds_wild->str, 0))
continue;
replace_dynstr_append(ds, file->name);
- dynstr_append(ds, "\n");
+ dynstr_append_mem(ds, STRING_WITH_LEN("\n"));
}
set_wild_chars(0);
my_dirend(dir_info);
@@ -4690,15 +4698,11 @@ void do_perl(struct st_command *command)
/* Check for error code that indicates perl could not be started */
int exstat= WEXITSTATUS(error);
-#ifdef _WIN32
- if (exstat == 1)
- /* Text must begin 'perl not found' as mtr looks for it */
- abort_not_supported_test("perl not found in path or did not start");
-#else
+#ifndef _WIN32
if (exstat == 127)
abort_not_supported_test("perl not found in path");
-#endif
else
+#endif
handle_command_error(command, exstat, my_errno);
}
dynstr_free(&ds_delimiter);
@@ -7681,7 +7685,7 @@ void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field,
}
else
{
- dynstr_append(ds, field->name);
+ dynstr_append_mem(ds, field->name, strlen(field->name));
dynstr_append_mem(ds, "\t", 1);
replace_dynstr_append_mem(ds, val, len);
dynstr_append_mem(ds, "\n", 1);
@@ -7792,9 +7796,10 @@ void append_metadata(DYNAMIC_STRING *ds,
uint num_fields)
{
MYSQL_FIELD *field_end;
- dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
- "Column_alias\tType\tLength\tMax length\tIs_null\t"
- "Flags\tDecimals\tCharsetnr\n");
+ dynstr_append_mem(ds, STRING_WITH_LEN(
+ "Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
+ "Column_alias\tType\tLength\tMax length\tIs_null\t"
+ "Flags\tDecimals\tCharsetnr\n"));
for (field_end= field+num_fields ;
field < field_end ;
@@ -7853,13 +7858,13 @@ void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows,
const char *info)
{
char buf[40], buff2[21];
- sprintf(buf,"affected rows: %s\n", llstr(affected_rows, buff2));
- dynstr_append(ds, buf);
+ size_t len= sprintf(buf,"affected rows: %s\n", llstr(affected_rows, buff2));
+ dynstr_append_mem(ds, buf, len);
if (info)
{
- dynstr_append(ds, "info: ");
- dynstr_append(ds, info);
- dynstr_append_mem(ds, "\n", 1);
+ dynstr_append_mem(ds, STRING_WITH_LEN("info: "));
+ dynstr_append_mem(ds, info, strlen(info));
+ dynstr_append_mem(ds, STRING_WITH_LEN("\n"));
}
}
@@ -7905,18 +7910,19 @@ static void append_session_track_info(DYNAMIC_STRING *ds, MYSQL *mysql)
(enum_session_state_type) type,
&data, &data_length))
{
- dynstr_append(ds, "-- ");
+ dynstr_append_mem(ds, STRING_WITH_LEN("-- "));
if (type <= SESSION_TRACK_END)
{
- dynstr_append(ds, trking_info_desc[type]);
+ dynstr_append_mem(ds, trking_info_desc[type],
+ strlen(trking_info_desc[type]));
}
else
{
DBUG_ASSERT(0);
- dynstr_append(ds, "Tracker???\n");
+ dynstr_append_mem(ds, STRING_WITH_LEN("Tracker???\n"));
}
- dynstr_append(ds, "-- ");
+ dynstr_append_mem(ds, STRING_WITH_LEN("-- "));
dynstr_append_mem(ds, data, data_length);
}
else
@@ -7925,16 +7931,16 @@ static void append_session_track_info(DYNAMIC_STRING *ds, MYSQL *mysql)
(enum_session_state_type) type,
&data, &data_length))
{
- dynstr_append(ds, "\n-- ");
+ dynstr_append_mem(ds, STRING_WITH_LEN("\n-- "));
if (data == NULL)
{
DBUG_ASSERT(data_length == 0);
- dynstr_append_mem(ds, "<NULL>", sizeof("<NULL>") - 1);
+ dynstr_append_mem(ds, STRING_WITH_LEN("<NULL>"));
}
else
dynstr_append_mem(ds, data, data_length);
}
- dynstr_append(ds, "\n\n");
+ dynstr_append_mem(ds, STRING_WITH_LEN("\n\n"));
}
#endif /* EMBEDDED_LIBRARY */
}
@@ -8334,7 +8340,8 @@ void handle_error(struct st_command *command,
else if (command->expected_errors.err[0].type == ERR_SQLSTATE ||
(command->expected_errors.err[0].type == ERR_ERRNO &&
command->expected_errors.err[0].code.errnum != 0))
- dynstr_append(ds,"Got one of the listed errors\n");
+ dynstr_append_mem(ds, STRING_WITH_LEN("Got one of the listed "
+ "errors\n"));
}
/* OK */
revert_properties();
@@ -8414,6 +8421,85 @@ void handle_no_error(struct st_command *command)
/*
+ Read result set after prepare statement execution
+
+ SYNOPSIS
+ read_stmt_results
+ stmt - prepare statemet
+ mysql - mysql handle
+ command - current command pointer
+ ds - output buffer where to store result form query
+
+ RETURN VALUE
+ 1 - if there is an error in result set
+*/
+
+int read_stmt_results(MYSQL_STMT* stmt,
+ DYNAMIC_STRING* ds,
+ struct st_command *command)
+{
+ MYSQL_RES *res= NULL;
+
+ /*
+ 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
+ buffer to allocate for result data
+ */
+ {
+ 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));
+ }
+
+ /*
+ If we got here the statement succeeded and was expected to do so,
+ get data. Note that this can still give errors found during execution!
+ Store the result of the query if if will return any fields
+ */
+ if (mysql_stmt_field_count(stmt) && mysql_stmt_store_result(stmt))
+ {
+ handle_error(command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
+ return 1;
+ }
+
+ if (!disable_result_log)
+ {
+ /*
+ Not all statements creates a result set. If there is one we can
+ now create another normal result set that contains the meta
+ data. This set can be handled almost like any other non prepared
+ statement result set.
+ */
+ if ((res= mysql_stmt_result_metadata(stmt)) != NULL)
+ {
+ /* Take the column count from meta info */
+ MYSQL_FIELD *fields= mysql_fetch_fields(res);
+ uint num_fields= mysql_num_fields(res);
+
+ if (display_metadata)
+ append_metadata(ds, fields, num_fields);
+
+ if (!display_result_vertically)
+ append_table_headings(ds, fields, num_fields);
+
+ append_stmt_result(ds, stmt, fields, num_fields);
+
+ mysql_free_result(res); /* Free normal result set with meta data */
+
+ }
+ else
+ {
+ /*
+ This is a query without resultset
+ */
+ }
+ }
+ return 0;
+}
+
+/*
Run query using prepared statement C API
SYNOPSIS
@@ -8433,11 +8519,17 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
DYNAMIC_STRING *ds_warnings)
{
my_bool ignore_second_execution= 0;
- MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */
MYSQL *mysql= cn->mysql;
MYSQL_STMT *stmt;
DYNAMIC_STRING ds_prepare_warnings;
DYNAMIC_STRING ds_execute_warnings;
+ DYNAMIC_STRING ds_res_1st_execution;
+ DYNAMIC_STRING ds_res_2_execution_unsorted;
+ DYNAMIC_STRING *ds_res_2_output;
+ my_bool ds_res_1st_execution_init = FALSE;
+ my_bool compare_2nd_execution = TRUE;
+ int query_match_ps2_re;
+
DBUG_ENTER("run_query_stmt");
DBUG_PRINT("query", ("'%-.60s'", query));
DBUG_PRINT("info",
@@ -8453,7 +8545,7 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
/*
Init a new stmt if it's not already one created for this connection
*/
- if(!(stmt= cn->stmt))
+ if (!(stmt= cn->stmt))
{
if (!(stmt= mysql_stmt_init(mysql)))
die("unable to init stmt structure");
@@ -8467,6 +8559,12 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
init_dynamic_string(&ds_execute_warnings, NULL, 0, 256);
}
+ /* Check and remove potential trash */
+ if (strlen(ds->str) != 0)
+ {
+ dynstr_trunc(ds, 0);
+ }
+
/*
Prepare the query
*/
@@ -8502,10 +8600,12 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
}
#endif
+ query_match_ps2_re = match_re(&ps2_re, query);
+
/*
Execute the query first time if second execution enable
*/
- if(ps2_protocol_enabled && match_re(&ps2_re, query))
+ if (ps2_protocol_enabled && query_match_ps2_re)
{
if (do_stmt_execute(cn))
{
@@ -8513,12 +8613,32 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
goto end;
}
+
/*
We cannot run query twice if we get prepare warnings as these will otherwise be
disabled
*/
ignore_second_execution= (prepare_warnings_enabled &&
mysql_warning_count(mysql) != 0);
+
+ if (ignore_second_execution)
+ compare_2nd_execution = 0;
+ else
+ {
+ init_dynamic_string(&ds_res_1st_execution, "",
+ RESULT_STRING_INIT_MEM, RESULT_STRING_INCREMENT_MEM);
+ ds_res_1st_execution_init = TRUE;
+ if (read_stmt_results(stmt, &ds_res_1st_execution, command))
+ {
+ /*
+ There was an error during execution
+ and there is no result set to compare
+ */
+ compare_2nd_execution = 0;
+ }
+ else
+ handle_no_error(command);
+ }
}
/*
@@ -8531,6 +8651,8 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
goto end;
}
+ DBUG_ASSERT(ds->length == 0);
+
int err;
do
{
@@ -8541,75 +8663,82 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
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
- buffer to allocate for result data
- */
+ if (!disable_result_log &&
+ compare_2nd_execution &&
+ ps2_protocol_enabled &&
+ query_match_ps2_re &&
+ display_result_sorted)
{
- 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));
+ init_dynamic_string(&ds_res_2_execution_unsorted, "",
+ RESULT_STRING_INIT_MEM,
+ RESULT_STRING_INCREMENT_MEM);
+ ds_res_2_output= &ds_res_2_execution_unsorted;
}
+ else
+ ds_res_2_output= ds;
- /*
- If we got here the statement succeeded and was expected to do so,
- get data. Note that this can still give errors found during execution!
- Store the result of the query if if will return any fields
- */
- if (mysql_stmt_field_count(stmt) && mysql_stmt_store_result(stmt))
+ if (read_stmt_results(stmt, ds_res_2_output, command))
{
- handle_error(command, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
- goto end;
+ if (ds_res_2_output != ds)
+ {
+ dynstr_append_mem(ds, ds_res_2_output->str, ds_res_2_output->length);
+ dynstr_free(ds_res_2_output);
+ }
+ goto end;
}
if (!disable_result_log)
{
/*
- Not all statements creates a result set. If there is one we can
- now create another normal result set that contains the meta
- data. This set can be handled almost like any other non prepared
- statement result set.
+ The results of the first and second execution are compared
+ only if result logging is enabled
*/
- if ((res= mysql_stmt_result_metadata(stmt)) != NULL)
+ if (compare_2nd_execution && ps2_protocol_enabled && query_match_ps2_re)
{
- /* Take the column count from meta info */
- MYSQL_FIELD *fields= mysql_fetch_fields(res);
- uint num_fields= mysql_num_fields(res);
-
- if (display_metadata)
- append_metadata(ds, fields, num_fields);
-
- if (!display_result_vertically)
- append_table_headings(ds, fields, num_fields);
-
- append_stmt_result(ds, stmt, fields, num_fields);
-
- mysql_free_result(res); /* Free normal result set with meta data */
-
- /*
- Normally, if there is a result set, we do not show warnings from the
- prepare phase. This is because some warnings are generated both during
- prepare and execute; this would generate different warning output
- between normal and ps-protocol test runs.
-
- The --enable_prepare_warnings command can be used to change this so
- that warnings from both the prepare and execute phase are shown.
- */
- if (!disable_warnings && !prepare_warnings_enabled)
+ DYNAMIC_STRING *ds_res_1_execution_compare;
+ DYNAMIC_STRING ds_res_1_execution_sorted;
+ if (display_result_sorted)
{
- DBUG_PRINT("info", ("warnings disabled"));
- dynstr_set(&ds_prepare_warnings, NULL);
+ init_dynamic_string(&ds_res_1_execution_sorted, "",
+ RESULT_STRING_INIT_MEM,
+ RESULT_STRING_INCREMENT_MEM);
+ dynstr_append_sorted(&ds_res_1_execution_sorted,
+ &ds_res_1st_execution, 1);
+ dynstr_append_sorted(ds, &ds_res_2_execution_unsorted, 1);
+ ds_res_1_execution_compare= &ds_res_1_execution_sorted;
+ }
+ else
+ {
+ ds_res_1_execution_compare= &ds_res_1st_execution;
+ }
+ if (ds->length != ds_res_1_execution_compare->length ||
+ !(memcmp(ds_res_1_execution_compare->str, ds->str, ds->length) == 0))
+ {
+ die("The result of the 1st execution does not match with \n"
+ "the result of the 2nd execution of ps-protocol:\n 1st:\n"
+ "%s\n 2nd:\n %s",
+ ds_res_1_execution_compare->str,
+ ds->str);
+ }
+ if (display_result_sorted)
+ {
+ dynstr_free(&ds_res_1_execution_sorted);
+ dynstr_free(&ds_res_2_execution_unsorted);
}
}
- else
- {
- /*
- This is a query without resultset
- */
- }
+
+ /*
+ Normally, if there is a result set, we do not show warnings from the
+ prepare phase. This is because some warnings are generated both during
+ prepare and execute; this would generate different warning output
+ between normal and ps-protocol test runs.
+ The --enable_prepare_warnings command can be used to change this so
+ that warnings from both the prepare and execute phase are shown.
+ */
+ if ((mysql_stmt_result_metadata(stmt) != NULL) &&
+ !disable_warnings &&
+ !prepare_warnings_enabled)
+ dynstr_set(&ds_prepare_warnings, NULL);
/*
Fetch info before fetching warnings, since it will be reset
@@ -8621,7 +8750,6 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
if (display_session_track_info)
append_session_track_info(ds, mysql);
-
if (!disable_warnings && !mysql_more_results(stmt->mysql))
{
/* Get the warnings from execute */
@@ -8653,7 +8781,15 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
mysql_sqlstate(mysql), ds);
else
handle_no_error(command);
+
end:
+
+ if (ds_res_1st_execution_init)
+ {
+ dynstr_free(&ds_res_1st_execution);
+ ds_res_1st_execution_init= FALSE;
+ }
+
if (!disable_warnings)
{
dynstr_free(&ds_prepare_warnings);
@@ -9164,11 +9300,14 @@ int util_query(MYSQL* org_mysql, const char* query){
void run_query(struct st_connection *cn, struct st_command *command, int flags)
{
MYSQL *mysql= cn->mysql;
- DYNAMIC_STRING *ds;
- DYNAMIC_STRING *save_ds= NULL;
- DYNAMIC_STRING ds_result;
- DYNAMIC_STRING ds_sorted;
- DYNAMIC_STRING ds_warnings;
+ DYNAMIC_STRING *rs_output; /* where to put results */
+ DYNAMIC_STRING rs_cmp_result; /* here we put results to compare with
+ pre-recrded file */
+ DYNAMIC_STRING rs_unsorted; /* if we need sorted results, here we store
+ results before sorting them */
+ DYNAMIC_STRING *rs_sorted_save= NULL; /* here we store where to put sorted
+ result if needed */
+ DYNAMIC_STRING rs_warnings;
char *query;
size_t query_len;
my_bool view_created= 0, sp_created= 0;
@@ -9181,10 +9320,10 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
if (!(flags & QUERY_SEND_FLAG) && !cn->pending)
die("Cannot reap on a connection without pending send");
-
- init_dynamic_string(&ds_warnings, NULL, 0, 256);
- ds_warn= &ds_warnings;
-
+
+ init_dynamic_string(&rs_warnings, NULL, 0, 256);
+ ds_warn= &rs_warnings;
+
/*
Evaluate query if this is an eval command
*/
@@ -9214,11 +9353,11 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
*/
if (command->require_file)
{
- init_dynamic_string(&ds_result, "", 1024, 1024);
- ds= &ds_result;
+ init_dynamic_string(&rs_cmp_result, "", 1024, 1024);
+ rs_output= &rs_cmp_result;
}
else
- ds= &ds_res;
+ rs_output= &ds_res; // will be shown to colsole
/*
Log the query into the output buffer
@@ -9232,9 +9371,9 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
print_query= command->query;
print_len= (int)(command->end - command->query);
}
- replace_dynstr_append_mem(ds, print_query, print_len);
- dynstr_append_mem(ds, delimiter, delimiter_length);
- dynstr_append_mem(ds, "\n", 1);
+ replace_dynstr_append_mem(rs_output, print_query, print_len);
+ dynstr_append_mem(rs_output, delimiter, delimiter_length);
+ dynstr_append_mem(rs_output, "\n", 1);
}
/* We're done with this flag */
@@ -9289,7 +9428,7 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
Collect warnings from create of the view that should otherwise
have been produced when the SELECT was executed
*/
- append_warnings(&ds_warnings,
+ append_warnings(&rs_warnings,
service_connection_enabled ?
cur_con->util_mysql :
mysql);
@@ -9345,9 +9484,9 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
that can be sorted before it's added to the
global result string
*/
- init_dynamic_string(&ds_sorted, "", 1024, 1024);
- save_ds= ds; /* Remember original ds */
- ds= &ds_sorted;
+ init_dynamic_string(&rs_unsorted, "", 1024, 1024);
+ rs_sorted_save= rs_output; /* Remember original ds */
+ rs_output= &rs_unsorted;
}
/*
@@ -9368,20 +9507,20 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
All other statements can be run using prepared statement C API.
*/
!match_re(&ps_re, query))
- run_query_stmt(cn, command, query, query_len, ds, &ds_warnings);
+ run_query_stmt(cn, command, query, query_len, rs_output, &rs_warnings);
else
run_query_normal(cn, command, flags, query, query_len,
- ds, &ds_warnings);
+ rs_output, &rs_warnings);
- dynstr_free(&ds_warnings);
+ dynstr_free(&rs_warnings);
ds_warn= 0;
if (display_result_sorted)
{
/* Sort the result set and append it to result */
- dynstr_append_sorted(save_ds, &ds_sorted, 1);
- ds= save_ds;
- dynstr_free(&ds_sorted);
+ dynstr_append_sorted(rs_sorted_save, &rs_unsorted, 1);
+ rs_output= rs_sorted_save;
+ dynstr_free(&rs_unsorted);
}
if (sp_created)
@@ -9404,11 +9543,11 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
and the output should be checked against an already
existing file which has been specified using --require or --result
*/
- check_require(ds, command->require_file);
+ check_require(rs_output, command->require_file);
}
- if (ds == &ds_result)
- dynstr_free(&ds_result);
+ if (rs_output == &rs_cmp_result)
+ dynstr_free(&rs_cmp_result);
DBUG_VOID_RETURN;
}
@@ -9667,7 +9806,7 @@ void mark_progress(struct st_command* command __attribute__((unused)),
dynstr_append_mem(&ds_progress, "\t", 1);
/* Filename */
- dynstr_append(&ds_progress, cur_file->file_name);
+ dynstr_append_mem(&ds_progress, cur_file->file_name, strlen(cur_file->file_name));
dynstr_append_mem(&ds_progress, ":", 1);
/* Line in file */
@@ -9865,7 +10004,7 @@ int main(int argc, char **argv)
read_command_buf= (char*)my_malloc(PSI_NOT_INSTRUMENTED, read_command_buflen= 65536, MYF(MY_FAE));
- init_dynamic_string(&ds_res, "", 2048, 2048);
+ init_dynamic_string(&ds_res, "", RESULT_STRING_INIT_MEM, RESULT_STRING_INCREMENT_MEM);
init_alloc_root(PSI_NOT_INSTRUMENTED, &require_file_root, 1024, 1024, MYF(0));
parse_args(argc, argv);
@@ -10292,7 +10431,7 @@ int main(int argc, char **argv)
if (p && *p == '#' && *(p+1) == '#')
{
dynstr_append_mem(&ds_res, command->query, command->query_len);
- dynstr_append(&ds_res, "\n");
+ dynstr_append_mem(&ds_res, STRING_WITH_LEN("\n"));
}
break;
}
@@ -10305,7 +10444,7 @@ int main(int argc, char **argv)
if (disable_query_log)
break;
- dynstr_append(&ds_res, "\n");
+ dynstr_append_mem(&ds_res, STRING_WITH_LEN("\n"));
break;
case Q_PING:
handle_command_error(command, mysql_ping(cur_con->mysql), -1);
@@ -11967,8 +12106,8 @@ void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING *ds_input,
for (i= 0; i < lines.elements ; i++)
{
const char **line= dynamic_element(&lines, i, const char**);
- dynstr_append(ds, *line);
- dynstr_append(ds, "\n");
+ dynstr_append_mem(ds, *line, strlen(*line));
+ dynstr_append_mem(ds, STRING_WITH_LEN("\n"));
}
delete_dynamic(&lines);