From 86fbb58c3ac0865482819c10a3e81f2eea001c36 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 15:39:13 +0200 Subject: Merging upstream version 1:10.11.7. Signed-off-by: Daniel Baumann --- client/mysql.cc | 139 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 108 insertions(+), 31 deletions(-) (limited to 'client/mysql.cc') 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 -- cgit v1.2.3