diff options
author | Vladislav Vaintroub <vvaintroub@mysql.com> | 2009-09-23 22:15:22 +0200 |
---|---|---|
committer | Vladislav Vaintroub <vvaintroub@mysql.com> | 2009-09-23 22:15:22 +0200 |
commit | 7ddb103b8ebf1ae6a2e14a96bf6712a7d209e1a4 (patch) | |
tree | 82532894c9a2009297e7f9605c2786f7931f0297 /client | |
parent | fc8db5e9ea231da4e8f5af3b38a12688d1590d53 (diff) | |
parent | 4e83ce7ce7dcb172e7de6beeaf665f0d0845c8de (diff) | |
download | mariadb-git-7ddb103b8ebf1ae6a2e14a96bf6712a7d209e1a4.tar.gz |
merge
Diffstat (limited to 'client')
-rw-r--r-- | client/mysql.cc | 21 | ||||
-rw-r--r-- | client/mysql_upgrade.c | 3 | ||||
-rw-r--r-- | client/mysqladmin.cc | 138 | ||||
-rw-r--r-- | client/mysqldump.c | 6 | ||||
-rw-r--r-- | client/mysqltest.cc | 111 |
5 files changed, 204 insertions, 75 deletions
diff --git a/client/mysql.cc b/client/mysql.cc index dc7022a0ffa..bafd173343e 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -86,7 +86,7 @@ extern "C" { #endif #undef bcmp // Fix problem with new readline -#if defined( __WIN__) +#if defined(__WIN__) #include <conio.h> #elif !defined(__NETWARE__) #include <readline/readline.h> @@ -106,7 +106,7 @@ extern "C" { #define cmp_database(cs,A,B) strcmp((A),(B)) #endif -#if !defined( __WIN__) && !defined(__NETWARE__) && !defined(THREAD) +#if !defined(__WIN__) && !defined(__NETWARE__) && !defined(THREAD) #define USE_POPEN #endif @@ -1862,7 +1862,7 @@ static int read_and_execute(bool interactive) if (opt_outfile && glob_buffer.is_empty()) fflush(OUTFILE); -#if defined( __WIN__) || defined(__NETWARE__) +#if defined(__WIN__) || defined(__NETWARE__) tee_fputs(prompt, stdout); #if defined(__NETWARE__) line=fgets(linebuffer, sizeof(linebuffer)-1, stdin); @@ -1873,7 +1873,7 @@ static int read_and_execute(bool interactive) if (p != NULL) *p = '\0'; } -#else defined(__WIN__) +#else if (!tmpbuf.is_alloced()) tmpbuf.alloc(65535); tmpbuf.length(0); @@ -1899,7 +1899,7 @@ static int read_and_execute(bool interactive) if (opt_outfile) fputs(prompt, OUTFILE); line= readline(prompt); -#endif /* defined( __WIN__) || defined(__NETWARE__) */ +#endif /* defined(__WIN__) || defined(__NETWARE__) */ /* When Ctrl+d or Ctrl+z is pressed, the line may be NULL on some OS @@ -1947,10 +1947,10 @@ static int read_and_execute(bool interactive) } } -#if defined( __WIN__) || defined(__NETWARE__) +#if defined(__WIN__) || defined(__NETWARE__) buffer.free(); #endif -#if defined( __WIN__) +#if defined(__WIN__) tmpbuf.free(); #endif @@ -3819,7 +3819,8 @@ com_edit(String *buffer,char *line __attribute__((unused))) !(editor = (char *)getenv("VISUAL"))) editor = "vi"; strxmov(buff,editor," ",filename,NullS); - (void) system(buff); + if(system(buff) == -1) + goto err; MY_STAT stat_arg; if (!my_stat(filename,&stat_arg,MYF(MY_WME))) @@ -4602,7 +4603,7 @@ void tee_putc(int c, FILE *file) putc(c, OUTFILE); } -#if defined( __WIN__) || defined(__NETWARE__) +#if defined(__WIN__) || defined(__NETWARE__) #include <time.h> #else #include <sys/times.h> @@ -4614,7 +4615,7 @@ void tee_putc(int c, FILE *file) static ulong start_timer(void) { -#if defined( __WIN__) || defined(__NETWARE__) +#if defined(__WIN__) || defined(__NETWARE__) return clock(); #else struct tms tms_tmp; diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 645fb037647..cfd7ed4ea56 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -552,6 +552,7 @@ static int upgrade_already_done(void) FILE *in; char upgrade_info_file[FN_REFLEN]= {0}; char buf[sizeof(MYSQL_SERVER_VERSION)+1]; + char *res; if (get_upgrade_info_file_name(upgrade_info_file)) return 0; /* Could not get filename => not sure */ @@ -564,7 +565,7 @@ static int upgrade_already_done(void) will be detected by the strncmp */ bzero(buf, sizeof(buf)); - fgets(buf, sizeof(buf), in); + res= fgets(buf, sizeof(buf), in); my_fclose(in, MYF(0)); diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index a4e7c5ad0c9..2b93c149523 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -22,6 +22,7 @@ #endif #include <sys/stat.h> #include <mysql.h> +#include <sql_common.h> #define ADMIN_VERSION "8.42" #define MAX_MYSQL_VAR 512 @@ -353,6 +354,11 @@ int main(int argc,char *argv[]) if (sql_connect(&mysql, option_wait)) { + /* + We couldn't get an initial connection and will definitely exit. + The following just determines the exit-code we'll give. + */ + unsigned int err= mysql_errno(&mysql); if (err >= CR_MIN_ERROR && err <= CR_MAX_ERROR) error= 1; @@ -371,41 +377,79 @@ int main(int argc,char *argv[]) } else { - while (!interrupted) + /* + --count=0 aborts right here. Otherwise iff --sleep=t ("interval") + is given a t!=0, we get an endless loop, or n iterations if --count=n + was given an n!=0. If --sleep wasn't given, we get one iteration. + + To wit, --wait loops the connection-attempts, while --sleep loops + the command execution (endlessly if no --count is given). + */ + + while (!interrupted && (!opt_count_iterations || nr_iterations)) { new_line = 0; - if ((error=execute_commands(&mysql,argc,commands))) + + if ((error= execute_commands(&mysql,argc,commands))) { + /* + Unknown/malformed command always aborts and can't be --forced. + If the user got confused about the syntax, proceeding would be + dangerous ... + */ if (error > 0) - break; /* Wrong command error */ - if (!option_force) + break; + + /* + Command was well-formed, but failed on the server. Might succeed + on retry (if conditions on server change etc.), but needs --force + to retry. + */ + if (!option_force) + break; + } /* if((error= ... */ + + if (interval) /* --sleep=interval given */ + { + /* + If connection was dropped (unintentionally, or due to SHUTDOWN), + re-establish it if --wait ("retry-connect") was given and user + didn't signal for us to die. Otherwise, signal failure. + */ + + if (mysql.net.vio == 0) { if (option_wait && !interrupted) { - mysql_close(&mysql); - if (!sql_connect(&mysql, option_wait)) - { - sleep(1); /* Don't retry too rapidly */ - continue; /* Retry */ - } + sleep(1); + sql_connect(&mysql, option_wait); + /* + continue normally and decrease counters so that + "mysqladmin --count=1 --wait=1 shutdown" + cannot loop endlessly. + */ } - error=1; - break; - } - } - if (interval) - { - if (opt_count_iterations && --nr_iterations == 0) - break; + else + { + /* + connexion broke, and we have no order to re-establish it. fail. + */ + if (!option_force) + error= 1; + break; + } + } /* lost connection */ + sleep(interval); if (new_line) puts(""); } else - break; - } - mysql_close(&mysql); - } + break; /* no --sleep, done looping */ + } /* command-loop */ + } /* got connection */ + + mysql_close(&mysql); my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); my_free(user,MYF(MY_ALLOW_ZERO_PTR)); #ifdef HAVE_SMEM @@ -423,6 +467,17 @@ sig_handler endprog(int signal_number __attribute__((unused))) interrupted=1; } +/** + @brief connect to server, optionally waiting for same to come up + + @param mysql connection struct + @param wait wait for server to come up? + (0: no, ~0: forever, n: cycles) + + @return Operation result + @retval 0 success + @retval 1 failure +*/ static my_bool sql_connect(MYSQL *mysql, uint wait) { @@ -431,7 +486,7 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) for (;;) { if (mysql_real_connect(mysql,host,user,opt_password,NullS,tcp_port, - unix_port, 0)) + unix_port, CLIENT_REMEMBER_OPTIONS)) { mysql->reconnect= 1; if (info) @@ -442,9 +497,9 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) return 0; } - if (!wait) + if (!wait) // was or reached 0, fail { - if (!option_silent) + if (!option_silent) // print diagnostics { if (!host) host= (char*) LOCAL_HOST; @@ -468,11 +523,18 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) } return 1; } + if (wait != (uint) ~0) - wait--; /* One less retry */ + wait--; /* count down, one less retry */ + if ((mysql_errno(mysql) != CR_CONN_HOST_ERROR) && (mysql_errno(mysql) != CR_CONNECTION_ERROR)) { + /* + Error is worse than "server doesn't answer (yet?)"; + fail even if we still have "wait-coins" unless --force + was also given. + */ fprintf(stderr,"Got error: %s\n", mysql_error(mysql)); if (!option_force) return 1; @@ -496,11 +558,18 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) } -/* - Execute a command. - Return 0 on ok - -1 on retryable error - 1 on fatal error +/** + @brief Execute all commands + + @details We try to execute all commands we were given, in the order + given, but return with non-zero as soon as we encounter trouble. + By that token, individual commands can be considered a conjunction + with boolean short-cut. + + @return success? + @retval 0 Yes! ALL commands worked! + @retval 1 No, one failed and will never work (malformed): fatal error! + @retval -1 No, one failed on the server, may work next time! */ static int execute_commands(MYSQL *mysql,int argc, char **argv) @@ -570,7 +639,6 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) mysql_error(mysql)); return -1; } - mysql_close(mysql); /* Close connection to avoid error messages */ argc=1; /* force SHUTDOWN to be the last command */ if (got_pidfile) { @@ -1036,14 +1104,16 @@ static void usage(void) static int drop_db(MYSQL *mysql, const char *db) { char name_buff[FN_REFLEN+20], buf[10]; + char *input; + if (!option_force) { puts("Dropping the database is potentially a very bad thing to do."); puts("Any data stored in the database will be destroyed.\n"); printf("Do you really want to drop the '%s' database [y/N] ",db); fflush(stdout); - VOID(fgets(buf,sizeof(buf)-1,stdin)); - if ((*buf != 'y') && (*buf != 'Y')) + input= fgets(buf, sizeof(buf)-1, stdin); + if (!input || ((*input != 'y') && (*input != 'Y'))) { puts("\nOK, aborting database drop!"); return -1; diff --git a/client/mysqldump.c b/client/mysqldump.c index cac27424d6e..e9e3124b9cb 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -5008,7 +5008,7 @@ int main(int argc, char **argv) exit_code= get_options(&argc, &argv); if (exit_code) { - free_resources(0); + free_resources(); exit(exit_code); } @@ -5016,14 +5016,14 @@ int main(int argc, char **argv) { if(!(stderror_file= freopen(log_error_file, "a+", stderr))) { - free_resources(0); + free_resources(); exit(EX_MYSQLERR); } } if (connect_to_db(current_host, current_user, opt_password)) { - free_resources(0); + free_resources(); exit(EX_MYSQLERR); } if (!path) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 265d3b0a8e7..3812a1bb8d1 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -417,6 +417,7 @@ static struct st_expected_errors saved_expected_errors; struct st_command { char *query, *query_buf,*first_argument,*last_argument,*end; + DYNAMIC_STRING content; int first_word_len, query_len; my_bool abort_on_error; struct st_expected_errors expected_errors; @@ -431,10 +432,12 @@ DYNAMIC_STRING ds_res; char builtin_echo[FN_REFLEN]; +static void cleanup_and_exit(int exit_code) __attribute__((noreturn)); + void die(const char *fmt, ...) - ATTRIBUTE_FORMAT(printf, 1, 2); + ATTRIBUTE_FORMAT(printf, 1, 2) __attribute__((noreturn)); void abort_not_supported_test(const char *fmt, ...) - ATTRIBUTE_FORMAT(printf, 1, 2); + ATTRIBUTE_FORMAT(printf, 1, 2) __attribute__((noreturn)); void verbose_msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); void log_msg(const char *fmt, ...) @@ -1138,6 +1141,8 @@ void free_used_memory() { struct st_command **q= dynamic_element(&q_lines, i, struct st_command**); my_free((*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR)); + if ((*q)->content.str) + dynstr_free(&(*q)->content); my_free((*q),MYF(0)); } for (i= 0; i < 10; i++) @@ -1163,6 +1168,7 @@ void free_used_memory() mysql_server_end(); /* Don't use DBUG after mysql_server_end() */ + DBUG_VIOLATION_HELPER_LEAVE; return; } @@ -2485,7 +2491,7 @@ void do_source(struct st_command *command) } dynstr_free(&ds_filename); - return; + DBUG_VOID_RETURN; } @@ -3287,21 +3293,30 @@ void do_write_file_command(struct st_command *command, my_bool append) sizeof(write_file_args)/sizeof(struct command_arg), ' '); - /* If no delimiter was provided, use EOF */ - if (ds_delimiter.length == 0) - dynstr_set(&ds_delimiter, "EOF"); - if (!append && access(ds_filename.str, F_OK) == 0) { /* The file should not be overwritten */ die("File already exist: '%s'", ds_filename.str); } - init_dynamic_string(&ds_content, "", 1024, 1024); - read_until_delimiter(&ds_content, &ds_delimiter); - DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str)); - str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append); - dynstr_free(&ds_content); + ds_content= command->content; + /* If it hasn't been done already by a loop iteration, fill it in */ + if (! ds_content.str) + { + /* If no delimiter was provided, use EOF */ + if (ds_delimiter.length == 0) + dynstr_set(&ds_delimiter, "EOF"); + + init_dynamic_string(&ds_content, "", 1024, 1024); + read_until_delimiter(&ds_content, &ds_delimiter); + command->content= ds_content; + } + /* This function could be called even if "false", so check before printing */ + if (cur_block->ok) + { + DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str)); + str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append); + } dynstr_free(&ds_filename); dynstr_free(&ds_delimiter); DBUG_VOID_RETURN; @@ -3444,12 +3459,17 @@ void do_diff_files(struct st_command *command) die("command \"diff_files\" failed, file '%s' does not exist", ds_filename2.str); - if ((error= compare_files(ds_filename.str, ds_filename2.str))) + if ((error= compare_files(ds_filename.str, ds_filename2.str)) && + match_expected_error(command, error, NULL) < 0) { /* Compare of the two files failed, append them to output - so the failure can be analyzed + so the failure can be analyzed, but only if it was not + expected to fail. */ show_diff(&ds_res, ds_filename.str, ds_filename2.str); + log_file.write(&ds_res); + log_file.flush(); + dynstr_set(&ds_res, 0); } dynstr_free(&ds_filename); @@ -3705,10 +3725,9 @@ void do_wait_for_slave_to_stop(struct st_command *c __attribute__((unused))) MYSQL* mysql = &cur_con->mysql; for (;;) { - MYSQL_RES *res; + MYSQL_RES *UNINIT_VAR(res); MYSQL_ROW row; int done; - LINT_INIT(res); if (mysql_query(mysql,"show status like 'Slave_running'") || !(res=mysql_store_result(mysql))) @@ -5240,13 +5259,12 @@ my_bool end_of_query(int c) int read_line(char *buf, int size) { - char c, last_quote; + char c, UNINIT_VAR(last_quote); char *p= buf, *buf_end= buf + size - 1; int skip_char= 0; enum {R_NORMAL, R_Q, R_SLASH_IN_Q, R_COMMENT, R_LINE_START} state= R_LINE_START; DBUG_ENTER("read_line"); - LINT_INIT(last_quote); start_lineno= cur_file->lineno; DBUG_PRINT("info", ("Starting to read at lineno: %d", start_lineno)); @@ -6478,8 +6496,7 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, if (!disable_result_log) { - ulonglong affected_rows; /* Ok to be undef if 'disable_info' is set */ - LINT_INIT(affected_rows); + ulonglong UNINIT_VAR(affected_rows); /* Ok to be undef if 'disable_info' is set */ if (res) { @@ -7165,6 +7182,10 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) run_query_normal(cn, command, flags, query, query_len, ds, &ds_warnings); + dynstr_free(&ds_warnings); + if (command->type == Q_EVAL) + dynstr_free(&eval_query); + if (display_result_sorted) { /* Sort the result set and append it to result */ @@ -7195,11 +7216,8 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) check_require(ds, command->require_file); } - dynstr_free(&ds_warnings); if (ds == &ds_result) dynstr_free(&ds_result); - if (command->type == Q_EVAL) - dynstr_free(&eval_query); DBUG_VOID_RETURN; } @@ -7508,6 +7526,8 @@ static void init_signal_handling(void) #endif sigaction(SIGILL, &sa, NULL); sigaction(SIGFPE, &sa, NULL); + + DBUG_VOID_RETURN; } #endif /* !__WIN__ */ @@ -7682,7 +7702,31 @@ int main(int argc, char **argv) command->type= Q_COMMENT; } - if (cur_block->ok) + my_bool ok_to_do= cur_block->ok; + /* + Some commands need to be "done" the first time if they may get + re-iterated over in a true context. This can only happen if there's + a while loop at some level above the current block. + */ + if (!ok_to_do) + { + if (command->type == Q_SOURCE || + command->type == Q_WRITE_FILE || + command->type == Q_APPEND_FILE || + command->type == Q_PERL) + { + for (struct st_block *stb= cur_block-1; stb >= block_stack; stb--) + { + if (stb->cmd == cmd_while) + { + ok_to_do= 1; + break; + } + } + } + } + + if (ok_to_do) { command->last_argument= command->first_argument; processed = 1; @@ -7991,6 +8035,8 @@ int main(int argc, char **argv) if (parsing_disabled) die("Test ended with parsing disabled"); + my_bool empty_result= FALSE; + /* The whole test has been executed _sucessfully_. Time to compare result or save it to record file. @@ -8031,11 +8077,20 @@ int main(int argc, char **argv) } else { - die("The test didn't produce any output"); + /* Empty output is an error *unless* we also have an empty result file */ + if (! result_file_name || record || + compare_files (log_file.file_name(), result_file_name)) + { + die("The test didn't produce any output"); + } + else + { + empty_result= TRUE; /* Meaning empty was expected */ + } } - if (!command_executed && result_file_name) - die("No queries executed but result file found!"); + if (!command_executed && result_file_name && !empty_result) + die("No queries executed but non-empty result file found!"); verbose_msg("Test has succeeded!"); timer_output(); @@ -8122,6 +8177,8 @@ void do_get_replace_column(struct st_command *command) } my_free(start, MYF(0)); command->last_argument= command->end; + + DBUG_VOID_RETURN; } |