diff options
Diffstat (limited to 'client/mysql.cc')
-rw-r--r-- | client/mysql.cc | 1471 |
1 files changed, 902 insertions, 569 deletions
diff --git a/client/mysql.cc b/client/mysql.cc index 32547a4d138..da52fb54e7d 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1,15 +1,15 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - +/* Copyright (C) 2000-2003 MySQL AB + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -20,21 +20,27 @@ * Written by: * Michael 'Monty' Widenius * Andi Gutmans <andi@zend.com> - * Zeev Suraski <zeev@zend.com> - * Jani Tolonen <jani@mysql.com> + * Zeev Suraski <zeev@zend.com> + * Jani Tolonen <jani@mysql.com> + * Matt Wagner <matt@mysql.com> + * Jeremy Cole <jcole@mysql.com> + * Tonu Samuel <tonu@mysql.com> + * Harrison Fisk <hcfisk@buffalo.edu> * **/ #include "client_priv.h" #include <m_ctype.h> +#include <stdarg.h> #include <my_dir.h> #ifndef __GNU_LIBRARY__ #define __GNU_LIBRARY__ // Skip warnings in getopt.h #endif #include "my_readline.h" #include <signal.h> +#include <violite.h> -const char *VER="11.18"; +const char *VER= "12.18"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -71,10 +77,9 @@ extern "C" { #endif #undef bcmp // Fix problem with new readline -#undef bzero #if defined( __WIN__) || defined(OS2) #include <conio.h> -#else +#elif !defined(__NETWARE__) #include <readline/readline.h> #define HAVE_READLINE #endif @@ -86,14 +91,20 @@ extern "C" { #define vidattr(A) {} // Can't get this to work #endif -#ifdef __WIN__ +#ifdef FN_NO_CASE_SENCE #define cmp_database(A,B) my_strcasecmp((A),(B)) #else #define cmp_database(A,B) strcmp((A),(B)) #endif +#if !defined( __WIN__) && !defined( OS2) && !defined(__NETWARE__) && (!defined(HAVE_mit_thread) || !defined(THREAD)) +#define USE_POPEN +#endif + #include "completion_hash.h" +#define PROMPT_CHAR '\\' + typedef struct st_status { int exit_status; @@ -105,30 +116,45 @@ typedef struct st_status static HashTable ht; +static char **defaults_argv; enum enum_info_type { INFO_INFO,INFO_ERROR,INFO_RESULT}; typedef enum enum_info_type INFO_TYPE; static MYSQL mysql; /* The connection */ -static bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0, - connected=0,opt_raw_data=0,unbuffered=0,output_tables=0, - no_rehash=0,skip_updates=0,safe_updates=0,one_database=0, - opt_compress=0, using_opt_local_infile=0, - vertical=0,skip_line_numbers=0,skip_column_names=0,opt_html=0, - opt_nopager=1, opt_outfile=0, no_named_cmds=1; +static my_bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0, + connected=0,opt_raw_data=0,unbuffered=0,output_tables=0, + rehash=1,skip_updates=0,safe_updates=0,one_database=0, + opt_compress=0, using_opt_local_infile=0, + vertical=0, line_numbers=1, column_names=1,opt_html=0, + opt_xml=0,opt_nopager=1, opt_outfile=0, named_cmds= 0, + tty_password= 0, opt_nobeep=0; static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0; static my_string opt_mysql_unix_port=0; static int connect_flag=CLIENT_INTERACTIVE; static char *current_host,*current_db,*current_user=0,*opt_password=0, - *default_charset; + *current_prompt=0, *default_charset; static char *histfile; static String glob_buffer,old_buffer; +static String processed_prompt; +static char *full_username=0,*part_username=0,*default_prompt=0; static int wait_time = 5; static STATUS status; static ulong select_limit,max_join_size,opt_connect_timeout=0; +static char mysql_charsets_dir[FN_REFLEN+1]; +static const char *xmlmeta[] = { + "&", "&", + "<", "<", + 0, 0 +}; +static const char *day_names[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; +static const char *month_names[]={"Jan","Feb","Mar","Apr","May","Jun","Jul", + "Aug","Sep","Oct","Nov","Dec"}; static char default_pager[FN_REFLEN]; -char pager[FN_REFLEN], outfile[FN_REFLEN]; -FILE *PAGER, *OUTFILE; +static char pager[FN_REFLEN], outfile[FN_REFLEN]; +static FILE *PAGER, *OUTFILE; +static MEM_ROOT hash_mem_root; +static uint prompt_counter; #include "sslopt-vars.h" @@ -149,11 +175,12 @@ static int com_quit(String *str,char*), com_connect(String *str,char*), com_status(String *str,char*), com_use(String *str,char*), com_source(String *str, char*), com_rehash(String *str, char*), com_tee(String *str, char*), - com_notee(String *str, char*); + com_notee(String *str, char*), + com_prompt(String *str, char*); -#ifndef __WIN__ +#ifdef USE_POPEN static int com_nopager(String *str, char*), com_pager(String *str, char*), - com_edit(String *str,char*); + com_edit(String *str,char*), com_shell(String *str, char *); #endif static int read_lines(bool execute_commands); @@ -161,10 +188,14 @@ static int sql_connect(char *host,char *database,char *user,char *password, uint silent); static int put_info(const char *str,INFO_TYPE info,uint error=0); static void safe_put_field(const char *pos,ulong length); +static void xmlencode_print(const char *src, uint length); static void init_pager(); static void end_pager(); -static void init_tee(); +static void init_tee(const char *); static void end_tee(); +static const char* construct_prompt(); +static void init_username(); +static void add_int_to_prompt(int toadd); /* A structure which contains information on the commands this program can understand. */ @@ -183,27 +214,31 @@ static COMMANDS commands[] = { { "clear", 'c', com_clear, 0, "Clear command."}, { "connect",'r', com_connect,1, "Reconnect to the server. Optional arguments are db and host." }, -#ifndef __WIN__ +#ifdef USE_POPEN { "edit", 'e', com_edit, 0, "Edit command with $EDITOR."}, #endif { "ego", 'G', com_ego, 0, "Send command to mysql server, display result vertically."}, { "exit", 'q', com_quit, 0, "Exit mysql. Same as quit."}, { "go", 'g', com_go, 0, "Send command to mysql server." }, -#ifndef __WIN__ +#ifdef USE_POPEN { "nopager",'n', com_nopager,0, "Disable pager, print to stdout." }, #endif { "notee", 't', com_notee, 0, "Don't write into outfile." }, -#ifndef __WIN__ +#ifdef USE_POPEN { "pager", 'P', com_pager, 1, "Set PAGER [to_pager]. Print the query results via PAGER." }, #endif { "print", 'p', com_print, 0, "Print current command." }, + { "prompt", 'R', com_prompt, 1, "Change your mysql prompt."}, { "quit", 'q', com_quit, 0, "Quit mysql." }, { "rehash", '#', com_rehash, 0, "Rebuild completion hash." }, { "source", '.', com_source, 1, "Execute a SQL script file. Takes a file name as an argument."}, { "status", 's', com_status, 0, "Get status information from the server."}, +#ifdef USE_POPEN + { "system", '!', com_shell, 1, "Execute a system shell command."}, +#endif { "tee", 'T', com_tee, 1, "Set outfile [to_outfile]. Append everything into given outfile." }, { "use", 'u', com_use, 1, @@ -232,6 +267,8 @@ static COMMANDS commands[] = { }; static const char *load_default_groups[]= { "mysql","client",0 }; +static const char *server_default_groups[]= +{ "server", "embedded", "mysql_SERVER", 0 }; #ifdef HAVE_READLINE extern "C" void add_history(char *command); /* From readline directory */ @@ -245,6 +282,7 @@ static bool add_line(String &buffer,char *line,char *in_string); static void remove_cntrl(String &buffer); static void print_table_data(MYSQL_RES *result); static void print_table_data_html(MYSQL_RES *result); +static void print_table_data_xml(MYSQL_RES *result); static void print_tab_data(MYSQL_RES *result); static void print_table_data_vertically(MYSQL_RES *result); static ulong start_timer(void); @@ -262,8 +300,14 @@ int main(int argc,char *argv[]) DBUG_ENTER("main"); DBUG_PROCESS(argv[0]); - strmov(outfile, "\0"); // no (default) outfile, unless given at least once - strmov(pager, "stdout"); // the default, if --pager wasn't given + default_prompt = my_strdup(getenv("MYSQL_PS1") ? + getenv("MYSQL_PS1") : + "mysql> ",MYF(MY_WME)); + current_prompt = my_strdup(default_prompt,MYF(MY_WME)); + prompt_counter=0; + + outfile[0]=0; // no (default) outfile + strmov(pager, "stdout"); // the default, if --pager wasn't given { char *tmp=getenv("PAGER"); if (tmp) @@ -278,17 +322,24 @@ int main(int argc,char *argv[]) status.add_to_history=1; status.exit_status=1; load_defaults("my",load_default_groups,&argc,&argv); - if (get_options(argc,(char **) argv)) + defaults_argv=argv; + if (get_options(argc, (char **) argv)) { + free_defaults(defaults_argv); my_end(0); exit(1); } - free_defaults(argv); if (status.batch && !status.line_buff && !(status.line_buff=batch_readline_init(max_allowed_packet+512,stdin))) + { + free_defaults(defaults_argv); exit(1); + } glob_buffer.realloc(512); - completion_hash_init(&ht,50); + mysql_server_init(0, NULL, (char**) server_default_groups); + completion_hash_init(&ht, 128); + init_alloc_root(&hash_mem_root, 16384, 0); + bzero((char*) &mysql, sizeof(mysql)); if (sql_connect(current_host,current_db,current_user,opt_password, opt_silent)) { @@ -301,7 +352,7 @@ int main(int argc,char *argv[]) signal(SIGINT, mysql_end); // Catch SIGINT to clean up /* - ** Run in interactive mode like the ingres/postgres monitor + Run in interactive mode like the ingres/postgres monitor */ put_info("Welcome to the MySQL monitor. Commands end with ; or \\g.", @@ -313,9 +364,9 @@ int main(int argc,char *argv[]) #ifdef HAVE_READLINE initialize_readline(my_progname); - if (!status.batch && !quick && !opt_html) + if (!status.batch && !quick && !opt_html && !opt_xml) { - /*read-history from file, default ~/.mysql_history*/ + /* read-history from file, default ~/.mysql_history*/ if (getenv("MYSQL_HISTFILE")) histfile=my_strdup(getenv("MYSQL_HISTFILE"),MYF(MY_WME)); else if (getenv("HOME")) @@ -348,10 +399,9 @@ int main(int argc,char *argv[]) sig_handler mysql_end(int sig) { - if (connected) - mysql_close(&mysql); + mysql_close(&mysql); #ifdef HAVE_READLINE - if (!status.batch && !quick && ! opt_html) + if (!status.batch && !quick && !opt_html && !opt_xml) { /* write-history */ if (verbose) @@ -360,88 +410,181 @@ sig_handler mysql_end(int sig) } batch_readline_end(status.line_buff); completion_hash_free(&ht); + free_root(&hash_mem_root,MYF(0)); + #endif if (sig >= 0) put_info(sig ? "Aborted" : "Bye", INFO_RESULT); glob_buffer.free(); old_buffer.free(); + processed_prompt.free(); my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR)); my_free(histfile,MYF(MY_ALLOW_ZERO_PTR)); my_free(current_db,MYF(MY_ALLOW_ZERO_PTR)); my_free(current_host,MYF(MY_ALLOW_ZERO_PTR)); my_free(current_user,MYF(MY_ALLOW_ZERO_PTR)); + my_free(full_username,MYF(MY_ALLOW_ZERO_PTR)); + my_free(part_username,MYF(MY_ALLOW_ZERO_PTR)); + my_free(default_prompt,MYF(MY_ALLOW_ZERO_PTR)); + my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR)); + mysql_server_end(); + free_defaults(defaults_argv); my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); exit(status.exit_status); } -static struct option long_options[] = + +static struct my_option my_long_options[] = { - {"i-am-a-dummy", optional_argument, 0, 'U'}, - {"batch", no_argument, 0, 'B'}, - {"character-sets-dir",required_argument, 0, OPT_CHARSETS_DIR}, - {"compress", no_argument, 0, 'C'}, + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, + 0, 0, 0, 0, 0}, + {"auto-rehash", OPT_AUTO_REHASH, + "Enable automatic rehashing. One doesn't need to use 'rehash' to get table and field completion, but startup and reconnecting may take a longer time. Disable with --disable-auto-rehash.", + (gptr*) &rehash, (gptr*) &rehash, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"no-auto-rehash", 'A', + "No automatic rehashing. One has to use 'rehash' to get table and field completion. This gives a quicker start of mysql and disables rehashing on reconnect. WARNING: options deprecated; use --disable-auto-rehash instead.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"batch", 'B', + "Print results with a tab as separator, each row on new line. Doesn't use history file.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"character-sets-dir", OPT_CHARSETS_DIR, + "Directory where character sets are.", (gptr*) &charsets_dir, + (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"default-character-set", OPT_DEFAULT_CHARSET, + "Set the default character set.", (gptr*) &default_charset, + (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"compress", 'C', "Use compression in server/client protocol.", + (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, + 0, 0, 0}, #ifndef DBUG_OFF - {"debug", optional_argument, 0, '#'}, + {"debug", '#', "Output debug log.", (gptr*) &default_dbug_option, + (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"database", required_argument, 0, 'D'}, - {"debug-info", no_argument, 0, 'T'}, - {"default-character-set", required_argument,0, OPT_DEFAULT_CHARSET}, - {"enable-named-commands", no_argument, 0, 'G'}, - {"execute", required_argument, 0, 'e'}, - {"force", no_argument, 0, 'f'}, - {"help", no_argument, 0, '?'}, - {"html", no_argument, 0, 'H'}, - {"host", required_argument, 0, 'h'}, - {"ignore-spaces", no_argument, 0, 'i'}, - {"local-infile", optional_argument, 0, OPT_LOCAL_INFILE}, - {"no-auto-rehash",no_argument, 0, 'A'}, - {"no-named-commands", no_argument, 0, 'g'}, -#ifndef __WIN__ - {"no-pager", no_argument, 0, OPT_NOPAGER}, - {"nopager", no_argument, 0, OPT_NOPAGER}, /* we are kind */ - {"pager", optional_argument, 0, OPT_PAGER}, + {"database", 'D', "Database to use.", (gptr*) ¤t_db, + (gptr*) ¤t_db, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"execute", 'e', "Execute command and quit. (Output like with --batch).", 0, + 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"vertical", 'E', "Print the output of a query (rows) vertically.", + (gptr*) &vertical, (gptr*) &vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + 0}, + {"force", 'f', "Continue even if we get an sql error.", + (gptr*) &ignore_errors, (gptr*) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, + 0, 0, 0, 0}, + {"no-named-commands", 'g', + "Named commands are disabled. Use \\* form only, or use named commands only in the beginning of a line ending with a semicolon (;) Since version 10.9 the client now starts with this option ENABLED by default! Disable with '-G'. Long format commands still work from the first line. WARNING: option deprecated; use --disable-named-commands instead.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"named-commands", 'G', + "Enable named commands. Named commands mean this program's internal commands; see mysql> help . When enabled, the named commands can be used from any line of the query, otherwise only from the first line, before an enter. Disable with --disable-named-commands. This option is disabled by default.", + (gptr*) &named_cmds, (gptr*) &named_cmds, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, + {"ignore-spaces", 'i', "Ignore space after function names.", 0, 0, 0, + GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"local-infile", OPT_LOCAL_INFILE, "Enable/disable LOAD DATA LOCAL INFILE.", + (gptr*) &opt_local_infile, + (gptr*) &opt_local_infile, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"no-beep", 'b', "Turn off beep on error.", (gptr*) &opt_nobeep, + (gptr*) &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host.", (gptr*) ¤t_host, + (gptr*) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"html", 'H', "Produce HTML output.", (gptr*) &opt_html, (gptr*) &opt_html, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"xml", 'X', "Produce XML output", (gptr*) &opt_xml, (gptr*) &opt_xml, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"line-numbers", OPT_LINE_NUMBERS, "Write line numbers for errors.", + (gptr*) &line_numbers, (gptr*) &line_numbers, 0, GET_BOOL, + NO_ARG, 1, 0, 0, 0, 0, 0}, + {"skip-line-numbers", 'L', "Don't write line number for errors. WARNING: -L is deprecated, use long version of this option instead.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef USE_POPEN + {"no-pager", OPT_NOPAGER, + "Disable pager and print to stdout. See interactive help (\\h) also. WARNING: option deprecated; use --disable-pager instead.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"no-tee", no_argument, 0, OPT_NOTEE}, - {"notee", no_argument, 0, OPT_NOTEE}, /* we are kind */ - {"tee", required_argument, 0, OPT_TEE}, - {"one-database", no_argument, 0, 'o'}, - {"password", optional_argument, 0, 'p'}, + {"no-tee", OPT_NOTEE, "Disable outfile. See interactive help (\\h) also. WARNING: option deprecated; use --disable-tee instead", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {"unbuffered", 'n', "Flush buffer after each query.", (gptr*) &unbuffered, + (gptr*) &unbuffered, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"column-names", OPT_COLUMN_NAMES, "Write column names in results.", + (gptr*) &column_names, (gptr*) &column_names, 0, GET_BOOL, + NO_ARG, 1, 0, 0, 0, 0, 0}, + {"skip-column-names", 'N', + "Don't write column names in results. WARNING: -N is deprecated, use long version of this options instead.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"set-variable", 'O', + "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"one-database", 'o', + "Only update the default database. This is useful for skipping updates to other database in the update log.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef USE_POPEN + {"pager", OPT_PAGER, + "Pager to use to display results. If you don't supply an option the default pager is taken from your ENV variable PAGER. Valid pagers are less, more, cat [> filename], etc. See interactive help (\\h) also. This option does not work in batch mode.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"password", 'p', + "Password to use when connecting to server. If password is not given it's asked from the tty.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __WIN__ - {"pipe", no_argument, 0, 'W'}, + {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"port", required_argument, 0, 'P'}, - {"quick", no_argument, 0, 'q'}, - {"set-variable", required_argument, 0, 'O'}, - {"raw", no_argument, 0, 'r'}, - {"safe-updates", optional_argument, 0, 'U'}, - {"silent", no_argument, 0, 's'}, - {"skip-column-names",no_argument, 0, 'N'}, - {"skip-line-numbers",no_argument, 0, 'L'}, - {"socket", required_argument, 0, 'S'}, + {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, + (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, + 0}, + {"prompt", OPT_PROMPT, "Set the mysql prompt to this value.", + (gptr*) ¤t_prompt, (gptr*) ¤t_prompt, 0, GET_STR_ALLOC, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"quick", 'q', + "Don't cache result, print it row by row. This may slow down the server if the output is suspended. Doesn't use history file. ", + (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"raw", 'r', "Write fields without conversion. Used with --batch", + (gptr*) &opt_raw_data, (gptr*) &opt_raw_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, + 0, 0, 0}, + {"silent", 's', "Be more silent.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, + 0, 0}, + {"socket", 'S', "Socket file to use for connection.", + (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR_ALLOC, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #include "sslopt-longopts.h" - {"table", no_argument, 0, 't'}, + {"table", 't', "Output in table format.", (gptr*) &output_tables, + (gptr*) &output_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", 'T', "Print some debug info at exit.", (gptr*) &info_flag, + (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"tee", OPT_TEE, + "Append everything into outfile. See interactive help (\\h) also. Does not work in batch mode.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DONT_ALLOW_USER_CHANGE - {"user", required_argument, 0, 'u'}, + {"user", 'u', "User for login if not current user.", (gptr*) ¤t_user, + (gptr*) ¤t_user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"unbuffered", no_argument, 0, 'n'}, - {"verbose", no_argument, 0, 'v'}, - {"version", no_argument, 0, 'V'}, - {"vertical", no_argument, 0, 'E'}, - {"wait", optional_argument, 0, 'w'}, - {0, 0, 0, 0} -}; - - -CHANGEABLE_VAR changeable_vars[] = { - { "connect_timeout", (long*) &opt_connect_timeout, 0, 0, 3600*12, 0, 1}, - { "max_allowed_packet", (long*) &max_allowed_packet,16*1024L*1024L,4096, - 24*1024L*1024L, MALLOC_OVERHEAD,1024}, - { "net_buffer_length",(long*) &net_buffer_length,16384,1024,16*1024*1024L, - MALLOC_OVERHEAD,1024}, - { "select_limit", (long*) &select_limit, 1000L, 1, ~0L, 0, 1}, - { "max_join_size", (long*) &max_join_size, 1000000L, 1, ~0L, 0, 1}, - { 0, 0, 0, 0, 0, 0, 0} + {"safe-updates", 'U', "Only allow UPDATE and DELETE that uses keys.", + (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, OPT_ARG, 0, 0, + 0, 0, 0, 0}, + {"i-am-a-dummy", 'U', "Synonym for option --safe-updates, -U.", + (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, OPT_ARG, 0, 0, + 0, 0, 0, 0}, + {"verbose", 'v', "Write more. (-v -v -v gives the table output format)", 0, + 0, 0, GET_NO_ARG, NO_ARG, 0, 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}, + {"wait", 'w', "Wait and retry if connection is down.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {"connect_timeout", OPT_CONNECT_TIMEOUT, "", (gptr*) &opt_connect_timeout, + (gptr*) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3600*12, 0, + 0, 1}, + {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "", + (gptr*) &max_allowed_packet, (gptr*) &max_allowed_packet, 0, GET_ULONG, + REQUIRED_ARG, 16 *1024L*1024L, 4096, 512*1024L*1024L, MALLOC_OVERHEAD, + 1024, 0}, + {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "", + (gptr*) &net_buffer_length, (gptr*) &net_buffer_length, 0, GET_ULONG, + REQUIRED_ARG, 16384, 1024, 512*1024*1024L, MALLOC_OVERHEAD, 1024, 0}, + {"select_limit", OPT_SELECT_LIMIT, "", (gptr*) &select_limit, + (gptr*) &select_limit, 0, GET_ULONG, REQUIRED_ARG, 1000L, 1, ~0L, 0, 1, 0}, + {"max_join_size", OPT_MAX_JOIN_SIZE, "", (gptr*) &max_join_size, + (gptr*) &max_join_size, 0, GET_ULONG, REQUIRED_ARG, 1000000L, 1, ~0L, 0, 1, + 0}, + { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -451,298 +594,171 @@ static void usage(int version) my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); if (version) return; - puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB"); - puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n"); - printf("Usage: %s [OPTIONS] [database]\n", my_progname); - printf("\n\ - -?, --help Display this help and exit.\n\ - -A, --no-auto-rehash No automatic rehashing. One has to use 'rehash' to\n\ - get table and field completion. This gives a quicker\n\ - start of mysql and disables rehashing on reconnect.\n\ - -B, --batch Print results with a tab as separator, each row on\n\ - a new line. Doesn't use history file.\n\ - --character-sets-dir=...\n\ - Directory where character sets are located.\n\ - -C, --compress Use compression in server/client protocol.\n"); -#ifndef DBUG_OFF - printf("\ - -#, --debug[=...] Debug log. Default is '%s'.\n",default_dbug_option); -#endif - printf("\ - -D, --database=.. Database to use.\n\ - --default-character-set=...\n\ - Set the default character set.\n\ - -e, --execute=... Execute command and quit. (Output like with --batch)\n\ - -E, --vertical Print the output of a query (rows) vertically.\n\ - -f, --force Continue even if we get an sql error.\n\ - -g, --no-named-commands\n\ - Named commands are disabled. Use \\* form only, or\n\ - use named commands only in the beginning of a line\n\ - ending with a semicolon (;) Since version 10.9 the\n\ - client now starts with this option ENABLED by\n\ - default! Disable with '-G'. Long format commands\n\ - still work from the first line.\n\ - -G, --enable-named-commands\n\ - Named commands are enabled. Opposite to -g.\n\ - -i, --ignore-spaces Ignore spaces after function names.\n\ - -h, --host=... Connect to host.\n\ - -H, --html Produce HTML output.\n\ - --local-infile=[1|0] Enable/disable LOAD DATA LOCAL INFILE\n\ - -L, --skip-line-numbers\n\ - Don't write line number for errors.\n"); -#ifndef __WIN__ - printf("\ - --no-pager Disable pager and print to stdout. See interactive\n\ - help (\\h) also.\n"); -#endif - printf("\ - --no-tee Disable outfile. See interactive help (\\h) also.\n\ - -n, --unbuffered Flush buffer after each query.\n\ - -N, --skip-column-names\n\ - Don't write column names in results.\n\ - -O, --set-variable var=option\n\ - Give a variable an value. --help lists variables.\n\ - -o, --one-database Only update the default database. This is useful\n\ - for skipping updates to other database in the update\n\ - log.\n"); -#ifndef __WIN__ - printf("\ - --pager[=...] Pager to use to display results. If you don't supply\n\ - an option the default pager is taken from your ENV\n\ - variable PAGER (%s).\n\ - Valid pagers are less, more, cat [> filename], etc.\n\ - See interactive help (\\h) also. This option does\n\ - not work in batch mode.\n", getenv("PAGER") ? getenv("PAGER") : ""); -#endif - printf("\ - -p[password], --password[=...]\n\ - Password to use when connecting to server\n\ - If password is not given it's asked from the tty.\n"); -#ifdef __WIN__ - puts(" -W, --pipe Use named pipes to connect to server"); -#endif - printf("\n\ - -P, --port=... Port number to use for connection.\n\ - -q, --quick Don't cache result, print it row by row. This may\n\ - slow down the server if the output is suspended.\n\ - Doesn't use history file.\n\ - -r, --raw Write fields without conversion. Used with --batch\n\ - -s, --silent Be more silent.\n\ - -S --socket=... Socket file to use for connection.\n"); -#include "sslopt-usage.h" - printf("\ - -t, --table Output in table format.\n\ - -T, --debug-info Print some debug info at exit.\n\ - --tee=... Append everything into outfile. See interactive help\n\ - (\\h) also. Does not work in batch mode.\n"); -#ifndef DONT_ALLOW_USER_CHANGE - printf("\ - -u, --user=# User for login if not current user.\n"); -#endif printf("\ - -U, --safe-updates[=#], --i-am-a-dummy[=#]\n\ - Only allow UPDATE and DELETE that uses keys.\n\ - -v, --verbose Write more. (-v -v -v gives the table output format)\n\ - -V, --version Output version information and exit.\n\ - -w, --wait Wait and retry if connection is down.\n"); - print_defaults("my",load_default_groups); - - printf("\nPossible variables for option --set-variable (-O) are:\n"); - for (uint i=0 ; changeable_vars[i].name ; i++) - printf("%-20s current value: %lu\n", - changeable_vars[i].name, - (ulong) *changeable_vars[i].varptr); +Copyright (C) 2002 MySQL AB\n\ +This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ +and you are welcome to modify and redistribute it under the GPL license\n"); + printf("Usage: %s [OPTIONS] [database]\n", my_progname); + my_print_help(my_long_options); + print_defaults("my", load_default_groups); + my_print_variables(my_long_options); } - -static int get_options(int argc, char **argv) +static my_bool +get_one_option(int optid, const struct my_option *opt __attribute__((unused)), + char *argument) { - int c,option_index=0; - bool tty_password=0; - - set_all_changeable_vars(changeable_vars); - while ((c=getopt_long(argc,argv, - (char*) "?ABCD:LfgGHinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::", - long_options, &option_index)) != EOF) - { - switch(c) { - case OPT_DEFAULT_CHARSET: - default_charset= optarg; - break; - case OPT_CHARSETS_DIR: - charsets_dir= optarg; - break; - case OPT_TEE: - if (!opt_outfile && strlen(optarg)) - { - strmov(outfile, optarg); - opt_outfile=1; - init_tee(); - } - break; - case OPT_NOTEE: + switch(optid) { + case OPT_CHARSETS_DIR: + strmov(mysql_charsets_dir, argument); + charsets_dir = mysql_charsets_dir; + break; + case OPT_LOCAL_INFILE: + using_opt_local_infile=1; + break; + case OPT_TEE: + if (argument == disabled_my_option) + { if (opt_outfile) end_tee(); - opt_outfile=0; - break; - case OPT_PAGER: - opt_nopager=0; - if (optarg) - strmov(pager, optarg); + } + else + init_tee(argument); + break; + case OPT_NOTEE: + printf("WARNING: option deprecated; use --disable-tee instead.\n"); + if (opt_outfile) + end_tee(); + break; + case OPT_PAGER: + if (argument == disabled_my_option) + opt_nopager= 1; + else + { + opt_nopager= 0; + if (argument) + strmov(pager, argument); else - { - char *pagpoint = getenv("PAGER"); - if (!((char*) (pagpoint))) - { - strmov(pager, "stdout"); - opt_nopager=1; - } - else - strmov(pager, pagpoint); - } + strmov(pager, default_pager); strmov(default_pager, pager); - break; - case OPT_NOPAGER: - opt_nopager=1; - break; - case 'D': - my_free(current_db,MYF(MY_ALLOW_ZERO_PTR)); - current_db=my_strdup(optarg,MYF(MY_WME)); - break; - case 'e': - status.batch=1; - status.add_to_history=0; - batch_readline_end(status.line_buff); // If multiple -e - if (!(status.line_buff=batch_readline_command(optarg))) - return 1; - ignore_errors=0; - break; - case 'f': - ignore_errors=1; - break; - case 'h': - my_free(current_host,MYF(MY_ALLOW_ZERO_PTR)); - current_host=my_strdup(optarg,MYF(MY_WME)); - break; -#ifndef DONT_ALLOW_USER_CHANGE - case 'u': - my_free(current_user,MYF(MY_ALLOW_ZERO_PTR)); - current_user= my_strdup(optarg,MYF(MY_WME)); - break; -#endif - case 'U': - if (!optarg) - safe_updates=1; - else - safe_updates=atoi(optarg) != 0; - break; - case 'o': - one_database=skip_updates=1; - break; - case 'O': - if (set_changeable_var(optarg, changeable_vars)) - { - usage(0); - return(1); - } - break; - case 'p': - if (optarg) - { - char *start=optarg; - my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); - opt_password=my_strdup(optarg,MYF(MY_FAE)); - while (*optarg) *optarg++= 'x'; // Destroy argument - if (*start) - start[1]=0; - } - else - tty_password=1; - break; - case 't': - output_tables=1; - break; - case 'r': - opt_raw_data=1; - break; - case '#': - DBUG_PUSH(optarg ? optarg : default_dbug_option); - info_flag=1; - break; - case 'q': quick=1; break; - case 's': opt_silent++; break; - case 'T': info_flag=1; break; - case 'n': unbuffered=1; break; - case 'v': verbose++; break; - case 'E': vertical=1; break; - case 'w': - wait_flag=1; - if(optarg) wait_time = atoi(optarg) ; - break; - case 'A': no_rehash=1; break; - case 'G': no_named_cmds=0; break; - case 'g': no_named_cmds=1; break; - case 'H': opt_html=1; break; - case 'i': connect_flag|= CLIENT_IGNORE_SPACE; break; - case 'B': - if (!status.batch) - { - status.batch=1; - status.add_to_history=0; - opt_silent++; // more silent - } - break; - case 'C': - opt_compress=1; - break; - case OPT_LOCAL_INFILE: - using_opt_local_infile=1; - opt_local_infile= test(!optarg || atoi(optarg)>0); - break; - case 'L': - skip_line_numbers=1; - break; - case 'N': - skip_column_names=1; - break; - case 'P': - opt_mysql_port= (unsigned int) atoi(optarg); - break; - case 'S': - my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR)); - opt_mysql_unix_port= my_strdup(optarg,MYF(0)); - break; - case 'W': + } + break; + case OPT_NOPAGER: + printf("WARNING: option deprecated; use --disable-pager instead.\n"); + opt_nopager= 1; + break; + case 'A': + rehash= 0; + break; + case 'N': + column_names= 0; + break; + case 'e': + status.batch= 1; + status.add_to_history= 0; + batch_readline_end(status.line_buff); // If multiple -e + if (!(status.line_buff= batch_readline_command(argument))) + return 1; + ignore_errors= 0; + break; + case 'o': + if (argument == disabled_my_option) + one_database= 0; + else + one_database= skip_updates= 1; + break; + case 'p': + if (argument == disabled_my_option) + argument= (char*) ""; // Don't require password + if (argument) + { + char *start= argument; + my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + opt_password= my_strdup(argument, MYF(MY_FAE)); + while (*argument) *argument++= 'x'; // Destroy argument + if (*start) + start[1]=0 ; + } + else + tty_password= 1; + break; + case '#': + DBUG_PUSH(argument ? argument : default_dbug_option); + info_flag= 1; + break; + case 's': + if (argument == disabled_my_option) + opt_silent= 0; + else + opt_silent++; + break; + case 'v': + if (argument == disabled_my_option) + verbose= 0; + else + verbose++; + break; + case 'B': + if (!status.batch) + { + status.batch= 1; + status.add_to_history= 0; + opt_silent++; // more silent + } + break; + case 'W': #ifdef __WIN__ - opt_mysql_unix_port=my_strdup(MYSQL_NAMEDPIPE,MYF(0)); + opt_mysql_unix_port= my_strdup(MYSQL_NAMEDPIPE, MYF(0)); #endif - break; - case 'V': usage(1); exit(0); - case 'I': - case '?': - usage(0); - exit(0); -#include "sslopt-case.h" - default: - tee_fprintf(stderr,"illegal option: -%c\n",opterr); - usage(0); - exit(1); - } + break; +#include <sslopt-case.h> + case 'V': + usage(1); + exit(0); + case 'I': + case '?': + usage(0); + exit(0); + } + return 0; +} + + +static int get_options(int argc, char **argv) +{ + char *tmp, *pagpoint; + int ho_error; + + tmp= (char *) getenv("MYSQL_HOST"); + if (tmp) + current_host= my_strdup(tmp, MYF(MY_WME)); + + pagpoint= getenv("PAGER"); + if (!((char*) (pagpoint))) + { + strmov(pager, "stdout"); + opt_nopager= 1; } + else + strmov(pager, pagpoint); + strmov(default_pager, pager); + + if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) + exit(ho_error); + if (status.batch) /* disable pager and outfile in this case */ { strmov(default_pager, "stdout"); strmov(pager, "stdout"); - opt_nopager=1; - opt_outfile=0; + opt_nopager= 1; + opt_outfile= 0; + connect_flag= 0; /* Not in interactive mode */ } if (default_charset) { if (set_default_charset_by_name(default_charset, MYF(MY_WME))) exit(1); } - argc-=optind; - argv+=optind; if (argc > 1) { usage(0); @@ -750,23 +766,17 @@ static int get_options(int argc, char **argv) } if (argc == 1) { - my_free(current_db,MYF(MY_ALLOW_ZERO_PTR)); - current_db= my_strdup(*argv,MYF(MY_WME)); - } - if (!current_host) - { /* If we don't have a hostname have a look at MYSQL_HOST */ - char *tmp=(char *) getenv("MYSQL_HOST"); - if (tmp) - current_host = my_strdup(tmp,MYF(MY_WME)); + my_free(current_db, MYF(MY_ALLOW_ZERO_PTR)); + current_db= my_strdup(*argv, MYF(MY_WME)); } if (tty_password) - opt_password=get_tty_password(NullS); + opt_password= get_tty_password(NullS); return(0); } static int read_lines(bool execute_commands) { -#if defined( __WIN__) || defined(OS2) +#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) char linebuffer[254]; #endif char *line; @@ -786,30 +796,33 @@ static int read_lines(bool execute_commands) } else { -#if defined( __WIN__) || defined(OS2) + char *prompt= (char*) (glob_buffer.is_empty() ? construct_prompt() : + !in_string ? " -> " : + in_string == '\'' ? + " '> " : " \"> "); if (opt_outfile && glob_buffer.is_empty()) fflush(OUTFILE); - tee_fputs(glob_buffer.is_empty() ? "mysql> " : - !in_string ? " -> " : - in_string == '\'' ? - " '> " : " \"> ",stdout); - linebuffer[0]=(char) sizeof(linebuffer); - line=_cgets(linebuffer); -#else - if (opt_outfile) + +#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) + tee_fputs(prompt, stdout); +#ifdef __NETWARE__ + line=fgets(linebuffer, sizeof(linebuffer)-1, stdin); + /* Remove the '\n' */ { - if (glob_buffer.is_empty()) - fflush(OUTFILE); - fputs(glob_buffer.is_empty() ? "mysql> " : - !in_string ? " -> " : - in_string == '\'' ? - " '> " : " \"> ", OUTFILE); + char *p = strrchr(line, '\n'); + if (p != NULL) + *p = '\0'; } - line=readline((char*) (glob_buffer.is_empty() ? "mysql> " : - !in_string ? " -> " : - in_string == '\'' ? - " '> " : " \"> ")); -#endif +#else + linebuffer[0]= (char) sizeof(linebuffer); + line= _cgets(linebuffer); +#endif /* __NETWARE__ */ +#else + if (opt_outfile) + fputs(prompt, OUTFILE); + line= readline(prompt); +#endif /* defined( __WIN__) || defined(OS2) || defined(__NETWARE__) */ + if (opt_outfile) fprintf(OUTFILE, "%s\n", line); } @@ -823,9 +836,11 @@ static int read_lines(bool execute_commands) line[0] == 0)) continue; // Skip comment lines - /* Check if line is a mysql command line */ - /* (We want to allow help, print and clear anywhere at line start */ - if (execute_commands && (!no_named_cmds || glob_buffer.is_empty()) + /* + Check if line is a mysql command line + (We want to allow help, print and clear anywhere at line start + */ + if (execute_commands && (named_cmds || glob_buffer.is_empty()) && !in_string && (com=find_command(line,0))) { if ((*com->func)(&glob_buffer,line) > 0) @@ -1007,20 +1022,20 @@ static bool add_line(String &buffer,char *line,char *in_string) return 0; } -/* **************************************************************** */ -/* */ -/* Interface to Readline Completion */ -/* */ -/* **************************************************************** */ +/***************************************************************** + Interface to Readline Completion +******************************************************************/ #ifdef HAVE_READLINE static char *new_command_generator(char *text, int); static char **new_mysql_completion (char *text, int start, int end); -/* Tell the GNU Readline library how to complete. We want to try to complete - on command names if this is the first word in the line, or on filenames - if not. */ +/* + Tell the GNU Readline library how to complete. We want to try to complete + on command names if this is the first word in the line, or on filenames + if not. +*/ char **no_completion (char *text __attribute__ ((unused)), char *word __attribute__ ((unused))) @@ -1039,11 +1054,12 @@ static void initialize_readline (char *name) rl_completion_entry_function=(Function *) no_completion; } -/* Attempt to complete on the contents of TEXT. START and END show the - region of TEXT that contains the word to complete. We can use the - entire line in case we want to do some simple parsing. Return the - array of matches, or NULL if there aren't any. */ - +/* + Attempt to complete on the contents of TEXT. START and END show the + region of TEXT that contains the word to complete. We can use the + entire line in case we want to do some simple parsing. Return the + array of matches, or NULL if there aren't any. +*/ static char **new_mysql_completion (char *text, int start __attribute__((unused)), @@ -1063,67 +1079,72 @@ static char *new_command_generator(char *text,int state) static entry *e; static uint i; - if (!state) { + if (!state) textlen=(uint) strlen(text); - } - if (textlen>0) { /* lookup in the hash */ - if (!state) { + if (textlen>0) + { /* lookup in the hash */ + if (!state) + { uint len; b = find_all_matches(&ht,text,(uint) strlen(text),&len); - if (!b) { + if (!b) return NullS; - } e = b->pData; } - while (e) { + if (e) + { ptr= strdup(e->str); e = e->pNext; return ptr; } - } else { /* traverse the entire hash, ugly but works */ + } + else + { /* traverse the entire hash, ugly but works */ - if (!state) { - i=0; + if (!state) + { /* find the first used bucket */ - while (i<ht.nTableSize) { - if (ht.arBuckets[i]) { + for (i=0 ; i < ht.nTableSize ; i++) + { + if (ht.arBuckets[i]) + { b = ht.arBuckets[i]; e = b->pData; break; } - i++; } } ptr= NullS; - while (e && !ptr) { /* find valid entry in bucket */ - if ((uint) strlen(e->str)==b->nKeyLength) { + while (e && !ptr) + { /* find valid entry in bucket */ + if ((uint) strlen(e->str) == b->nKeyLength) ptr = strdup(e->str); - } /* find the next used entry */ e = e->pNext; - if (!e) { /* find the next used bucket */ + if (!e) + { /* find the next used bucket */ b = b->pNext; - if (!b) { - i++; - while (i<ht.nTableSize) { - if (ht.arBuckets[i]) { + if (!b) + { + for (i++ ; i<ht.nTableSize; i++) + { + if (ht.arBuckets[i]) + { b = ht.arBuckets[i]; e = b->pData; break; } - i++; } - } else { - e = b->pData; } + else + e = b->pData; } } - if (ptr) { + if (ptr) return ptr; - } } return NullS; } @@ -1131,10 +1152,11 @@ static char *new_command_generator(char *text,int state) /* Build up the completion hash */ -static void build_completion_hash(bool skip_rehash,bool write_info) +static void build_completion_hash(bool rehash, bool write_info) { COMMANDS *cmd=commands; - static MYSQL_RES *databases=0,*tables=0,*fields; + MYSQL_RES *databases=0,*tables=0; + MYSQL_RES *fields; static char ***field_names= 0; MYSQL_ROW database_row,table_row; MYSQL_FIELD *sql_field; @@ -1145,35 +1167,42 @@ static void build_completion_hash(bool skip_rehash,bool write_info) if (status.batch || quick || !current_db) DBUG_VOID_RETURN; // We don't need completion in batches - completion_hash_clean(&ht); if (tables) { mysql_free_result(tables); tables=0; } - if (databases) { - mysql_free_result(databases); - databases=0; - } /* hash SQL commands */ while (cmd->name) { add_word(&ht,(char*) cmd->name); cmd++; } - if (skip_rehash) + if (!rehash) DBUG_VOID_RETURN; + /* Free old used memory */ + if (field_names) + field_names=0; + completion_hash_clean(&ht); + free_root(&hash_mem_root,MYF(0)); + /* hash MySQL functions (to be implemented) */ /* hash all database names */ - if (mysql_query(&mysql,"show databases")==0) { + if (mysql_query(&mysql,"show databases") == 0) + { if (!(databases = mysql_store_result(&mysql))) put_info(mysql_error(&mysql),INFO_INFO); else { while ((database_row=mysql_fetch_row(databases))) - add_word(&ht,(char*) database_row[0]); + { + char *str=strdup_root(&hash_mem_root, (char*) database_row[0]); + if (str) + add_word(&ht,(char*) str); + } + mysql_free_result(databases); } } /* hash all table names */ @@ -1191,22 +1220,13 @@ You can turn off this feature to get a quicker startup with -A\n\n"); } while ((table_row=mysql_fetch_row(tables))) { - if (!completion_hash_exists(&ht,(char*) table_row[0], - (uint) strlen((const char*) table_row[0]))) - add_word(&ht,table_row[0]); + char *str=strdup_root(&hash_mem_root, (char*) table_row[0]); + if (str && + !completion_hash_exists(&ht,(char*) str, (uint) strlen(str))) + add_word(&ht,str); } } } - if (field_names) { - for (i=0; field_names[i]; i++) { - for (j=0; field_names[i][j]; j++) { - my_free(field_names[i][j],MYF(0)); - } - my_free((gptr) field_names[i],MYF(0)); - } - my_free((gptr) field_names,MYF(0)); - } - field_names=0; /* hash all field names, both with the table prefix and without it */ if (!tables) /* no tables */ @@ -1214,36 +1234,37 @@ You can turn off this feature to get a quicker startup with -A\n\n"); DBUG_VOID_RETURN; } mysql_data_seek(tables,0); - field_names = (char ***) my_malloc(sizeof(char **) * - (uint) (mysql_num_rows(tables)+1), - MYF(MY_WME)); - if (!field_names) + if (!(field_names= (char ***) alloc_root(&hash_mem_root,sizeof(char **) * + (uint) (mysql_num_rows(tables)+1)))) + { + mysql_free_result(tables); DBUG_VOID_RETURN; + } i=0; while ((table_row=mysql_fetch_row(tables))) { if ((fields=mysql_list_fields(&mysql,(const char*) table_row[0],NullS))) { num_fields=mysql_num_fields(fields); - field_names[i] = (char **) my_malloc(sizeof(char *)*(num_fields*2+1), - MYF(0)); - if (!field_names[i]) - { - continue; - } + if (!(field_names[i] = (char **) alloc_root(&hash_mem_root, + sizeof(char *) * + (num_fields*2+1)))) + break; field_names[i][num_fields*2]='\0'; j=0; while ((sql_field=mysql_fetch_field(fields))) { sprintf(buf,"%s.%s",table_row[0],sql_field->name); - field_names[i][j] = my_strdup(buf,MYF(0)); + field_names[i][j] = strdup_root(&hash_mem_root,buf); add_word(&ht,field_names[i][j]); - field_names[i][num_fields+j] = my_strdup(sql_field->name,MYF(0)); + field_names[i][num_fields+j] = strdup_root(&hash_mem_root, + sql_field->name); if (!completion_hash_exists(&ht,field_names[i][num_fields+j], (uint) strlen(field_names[i][num_fields+j]))) add_word(&ht,field_names[i][num_fields+j]); j++; } + mysql_free_result(fields); } else { @@ -1253,20 +1274,18 @@ You can turn off this feature to get a quicker startup with -A\n\n"); } i++; } + mysql_free_result(tables); field_names[i]=0; // End pointer DBUG_VOID_RETURN; } - /* for gnu readline */ #ifndef HAVE_INDEX -#ifdef __cplusplus extern "C" { -#endif -extern char *index(const char *,pchar c),*rindex(const char *,pchar); +extern char *index(const char *,int c),*rindex(const char *,int); -char *index(const char *s,pchar c) +char *index(const char *s,int c) { for (;;) { @@ -1275,7 +1294,7 @@ char *index(const char *s,pchar c) } } -char *rindex(const char *s,pchar c) +char *rindex(const char *s,int c) { reg3 char *t; @@ -1283,19 +1302,19 @@ char *rindex(const char *s,pchar c) do if (*s == (char) c) t = (char*) s; while (*s++); return (char*) t; } -#ifdef __cplusplus } #endif -#endif #endif /* HAVE_READLINE */ + static int reconnect(void) { if (!status.batch) { put_info("No connection. Trying to reconnect...",INFO_INFO); (void) com_connect((String *) 0, 0); - if(!no_rehash) com_rehash(NULL, NULL); + if (rehash) + com_rehash(NULL, NULL); } if (!connected) return put_info("Can't connect to the server\n",INFO_ERROR); @@ -1313,9 +1332,13 @@ com_help (String *buffer __attribute__((unused)), { reg1 int i; - put_info("\nMySQL commands:",INFO_INFO); - if (no_named_cmds) - put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO); + put_info("\nFor the complete MySQL Manual online visit:\n http://www.mysql.com/documentation\n", INFO_INFO); + put_info("For info on technical support from MySQL developers visit:\n http://www.mysql.com/support\n", INFO_INFO); + put_info("For info on MySQL books, utilities, consultants, etc. visit:\n http://www.mysql.com/portal\n", INFO_INFO); + put_info("List of all MySQL commands:", INFO_INFO); + if (!named_cmds) + put_info(" (Commands must appear first on line and end with ';')\n", + INFO_INFO); for (i = 0; commands[i].name; i++) { if (commands[i].func) @@ -1342,10 +1365,10 @@ com_clear(String *buffer,char *line __attribute__((unused))) /* -** Execute command -** Returns: 0 if ok -** -1 if not fatal error -** 1 if fatal error + Execute command + Returns: 0 if ok + -1 if not fatal error + 1 if fatal error */ @@ -1363,7 +1386,7 @@ com_go(String *buffer,char *line __attribute__((unused))) old_buffer.copy(); } - /* Remove garbage for nicer messages */ + /* Remove garbage for nicer messages */ LINT_INIT(buff[0]); remove_cntrl(*buffer); @@ -1443,6 +1466,8 @@ com_go(String *buffer,char *line __attribute__((unused))) init_pager(); if (opt_html) print_table_data_html(result); + else if (opt_xml) + print_table_data_xml(result); else if (vertical) print_table_data_vertically(result); else if (opt_silent && verbose <= 2 && !output_tables) @@ -1479,7 +1504,7 @@ com_go(String *buffer,char *line __attribute__((unused))) static void init_pager() { -#if !defined( __WIN__) && !defined( OS2) +#ifdef USE_POPEN if (!opt_nopager) { if (!(PAGER= popen(pager, "w"))) @@ -1495,25 +1520,36 @@ static void init_pager() static void end_pager() { -#if !defined( __WIN__) && !defined( OS2) +#ifdef USE_POPEN if (!opt_nopager) pclose(PAGER); #endif } -static void init_tee() + +static void init_tee(const char *file_name) { - if (!(OUTFILE= my_fopen(outfile, O_APPEND | O_WRONLY, MYF(MY_WME)))) + FILE* new_outfile; + if (opt_outfile) + end_tee(); + if (!(new_outfile= my_fopen(file_name, O_APPEND | O_WRONLY, MYF(MY_WME)))) { - opt_outfile=0; - init_pager(); + tee_fprintf(stdout, "Error logging to file '%s'\n", file_name); return; } + OUTFILE = new_outfile; + strmake(outfile, file_name, FN_REFLEN-1); + tee_fprintf(stdout, "Logging to file '%s'\n", file_name); + opt_outfile= 1; + return; } + static void end_tee() { my_fclose(OUTFILE, MYF(0)); + OUTFILE= 0; + opt_outfile= 0; return; } @@ -1552,6 +1588,9 @@ print_table_data(MYSQL_RES *result) MYSQL_ROW cur; MYSQL_FIELD *field; bool *num_flag; +#ifdef __NETWARE__ + uint lines= 0; +#endif num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result)); if (info_flag) @@ -1562,7 +1601,7 @@ print_table_data(MYSQL_RES *result) separator.copy("+",1); while ((field = mysql_fetch_field(result))) { - uint length=skip_column_names ? 0 : (uint) strlen(field->name); + uint length= column_names ? (uint) strlen(field->name) : 0; if (quick) length=max(length,field->length); else @@ -1574,7 +1613,7 @@ print_table_data(MYSQL_RES *result) separator.append('+'); } tee_puts(separator.c_ptr(), PAGER); - if (!skip_column_names) + if (column_names) { mysql_field_seek(result,0); (void) tee_fputs("|", PAGER); @@ -1588,38 +1627,47 @@ print_table_data(MYSQL_RES *result) tee_puts(separator.c_ptr(), PAGER); } - while ((cur = mysql_fetch_row(result))) + while ((cur= mysql_fetch_row(result))) { (void) tee_fputs("|", PAGER); - mysql_field_seek(result,0); - for (uint off=0 ; off < mysql_num_fields(result); off++) + mysql_field_seek(result, 0); + for (uint off= 0; off < mysql_num_fields(result); off++) { - const char *str=cur[off] ? cur[off] : "NULL"; - field = mysql_fetch_field(result); - uint length=field->max_length; + const char *str= cur[off] ? cur[off] : "NULL"; + field= mysql_fetch_field(result); + uint length= field->max_length; if (length > MAX_COLUMN_LENGTH) { - tee_fputs(str,PAGER); tee_fputs(" |",PAGER); + tee_fputs(str, PAGER); + tee_fputs(" |", PAGER); } else tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|", length, str); } (void) tee_fputs("\n", PAGER); +#ifdef __NETWARE__ + // on a long result the screen could hog the cpu + if ((lines++ & 1023) == 0) pthread_yield(); +#endif } tee_puts(separator.c_ptr(), PAGER); my_afree((gptr) num_flag); } + static void print_table_data_html(MYSQL_RES *result) { - MYSQL_ROW cur; - MYSQL_FIELD *field; + MYSQL_ROW cur; + MYSQL_FIELD *field; +#ifdef __NETWARE__ + uint lines= 0; +#endif mysql_field_seek(result,0); (void) tee_fputs("<TABLE BORDER=1><TR>", PAGER); - if (!skip_column_names) + if (column_names) { while((field = mysql_fetch_field(result))) { @@ -1640,11 +1688,54 @@ print_table_data_html(MYSQL_RES *result) (void) tee_fputs("</TD>", PAGER); } (void) tee_fputs("</TR>", PAGER); +#ifdef __NETWARE__ + // on a long result the screen could hog the cpu + if ((lines++ & 1023) == 0) pthread_yield(); +#endif } (void) tee_fputs("</TABLE>", PAGER); } +static void +print_table_data_xml(MYSQL_RES *result) +{ + MYSQL_ROW cur; + MYSQL_FIELD *fields; +#ifdef __NETWARE__ + uint lines= 0; +#endif + + mysql_field_seek(result,0); + + tee_fputs("<?xml version=\"1.0\"?>\n\n<resultset statement=\"", PAGER); + xmlencode_print(glob_buffer.ptr(), strlen(glob_buffer.ptr())); + tee_fputs("\">", PAGER); + + fields = mysql_fetch_fields(result); + while ((cur = mysql_fetch_row(result))) + { + (void) tee_fputs("\n <row>\n", PAGER); + for (uint i=0; i < mysql_num_fields(result); i++) + { + ulong *lengths=mysql_fetch_lengths(result); + tee_fprintf(PAGER, "\t<%s>", (fields[i].name ? + (fields[i].name[0] ? fields[i].name : + " ") : "NULL")); + xmlencode_print(cur[i], lengths[i]); + tee_fprintf(PAGER, "</%s>\n", (fields[i].name ? + (fields[i].name[0] ? fields[i].name : + " ") : "NULL")); + } + (void) tee_fputs(" </row>\n", PAGER); +#ifdef __NETWARE__ + // on a long result the screen could hog the cpu + if ((lines++ & 1023) == 0) pthread_yield(); +#endif + } + (void) tee_fputs("</resultset>\n", PAGER); +} + static void print_table_data_vertically(MYSQL_RES *result) @@ -1673,6 +1764,40 @@ print_table_data_vertically(MYSQL_RES *result) tee_fprintf(PAGER, "%*s: ",(int) max_length,field->name); tee_fprintf(PAGER, "%s\n",cur[off] ? (char*) cur[off] : "NULL"); } +#ifdef __NETWARE__ + // on a long result the screen could hog the cpu + if ((row_count & 1023) == 0) pthread_yield(); +#endif + } +} + + +static const char +*array_value(const char **array, char key) +{ + int x; + for (x= 0; array[x]; x+= 2) + if (*array[x] == key) + return array[x + 1]; + return 0; +} + + +static void +xmlencode_print(const char *src, uint length) +{ + if (!src) + tee_fputs("NULL", PAGER); + else + { + for (const char *p = src; *p && length; *p++, length--) + { + const char *t; + if ((t = array_value(xmlmeta, *p))) + tee_fputs(t, PAGER); + else + tee_putc(*p, PAGER); + } } } @@ -1706,7 +1831,7 @@ safe_put_field(const char *pos,ulong length) tee_fputs("\\n", PAGER); // This too else if (*pos == '\\') tee_fputs("\\\\", PAGER); - else + else tee_putc(*pos, PAGER); } } @@ -1720,7 +1845,7 @@ print_tab_data(MYSQL_RES *result) MYSQL_FIELD *field; ulong *lengths; - if (opt_silent < 2 && !skip_column_names) + if (opt_silent < 2 && column_names) { int first=0; while ((field = mysql_fetch_field(result))) @@ -1738,7 +1863,7 @@ print_tab_data(MYSQL_RES *result) for (uint off=1 ; off < mysql_num_fields(result); off++) { (void) tee_fputs("\t", PAGER); - safe_put_field(cur[off],lengths[off]); + safe_put_field(cur[off], lengths[off]); } (void) tee_fputs("\n", PAGER); } @@ -1757,57 +1882,51 @@ com_tee(String *buffer, char *line __attribute__((unused))) { if (!strlen(outfile)) { - printf("No previous outfile available, you must give the filename!\n"); - opt_outfile=0; + printf("No previous outfile available, you must give a filename!\n"); return 0; } - } - else - { - while (isspace(*param)) - param++; - end= strend(param); - while (end > file_name && (isspace(end[-1]) || iscntrl(end[-1]))) - end--; - end[0]= 0; - if ((*(end - 1) == '"' && *param == '"') || - (*(end - 1) == '\'' && *param == '\'')) + else if (opt_outfile) { - *--end= 0; - param++; + tee_fprintf(stdout, "Currently logging to file '%s'\n", outfile); + return 0; } - strmake(file_name, param, sizeof(file_name) - 1); - strmov(outfile, file_name); + else + param = outfile; //resume using the old outfile } - if (!strlen(outfile)) + + /* eliminate the spaces before the parameters */ + while (isspace(*param)) + param++; + end= strmake(file_name, param, sizeof(file_name) - 1); + /* remove end space from command line */ + while (end > file_name && (isspace(end[-1]) || iscntrl(end[-1]))) + end--; + end[0]= 0; + if (end == file_name) { printf("No outfile specified!\n"); return 0; } - if (opt_outfile) - end_tee(); - init_tee(); - opt_outfile= 1; - tee_fprintf(stdout, "Logging to file '%s'\n", outfile); + init_tee(file_name); return 0; } + static int com_notee(String *buffer __attribute__((unused)), char *line __attribute__((unused))) { if (opt_outfile) end_tee(); - opt_outfile=0; tee_fprintf(stdout, "Outfile disabled.\n"); return 0; } /* -** Sorry, this command is not available in Windows. + Sorry, this command is not available in Windows. */ -#ifndef __WIN__ +#ifdef USE_POPEN static int com_pager(String *buffer, char *line __attribute__((unused))) { @@ -1818,9 +1937,9 @@ com_pager(String *buffer, char *line __attribute__((unused))) /* Skip space from file name */ while (isspace(*line)) line++; - if (!(param = strchr(line, ' '))) // if pager was not given, use the default + if (!(param= strchr(line, ' '))) // if pager was not given, use the default { - if (!strlen(default_pager)) + if (!default_pager[0]) { tee_fprintf(stdout, "Default pager wasn't set, using stdout.\n"); opt_nopager=1; @@ -1860,10 +1979,10 @@ com_nopager(String *buffer __attribute__((unused)), /* -** Sorry, you can't send the result to an editor in Win32 + Sorry, you can't send the result to an editor in Win32 */ -#ifndef __WIN__ +#ifdef USE_POPEN static int com_edit(String *buffer,char *line __attribute__((unused))) { @@ -1911,6 +2030,10 @@ static int com_quit(String *buffer __attribute__((unused)), char *line __attribute__((unused))) { +#ifdef __NETWARE__ + // let the screen auto close on a normal shutdown + setscreenmode(SCR_AUTOCLOSE_ON_EXIT); +#endif status.exit_status=0; return 1; } @@ -1920,11 +2043,36 @@ com_rehash(String *buffer __attribute__((unused)), char *line __attribute__((unused))) { #ifdef HAVE_READLINE - build_completion_hash(0,0); + build_completion_hash(1, 0); #endif return 0; } + +#ifdef USE_POPEN +static int +com_shell(String *buffer, char *line __attribute__((unused))) +{ + char *shell_cmd; + if (!(shell_cmd = strchr(line, ' '))) + { + put_info("Usage: \\! shell-command", INFO_ERROR); + return -1; + } + /* + The output of the shell command does not + get directed to the pager or the outfile + */ + if (system(shell_cmd) == -1) + { + put_info(strerror(errno), INFO_ERROR, errno); + return -1; + } + return 0; +} +#endif + + static int com_print(String *buffer,char *line __attribute__((unused))) { @@ -1941,7 +2089,7 @@ static int com_connect(String *buffer, char *line) { char *tmp,buff[256]; - bool save_rehash=no_rehash; + bool save_rehash= rehash; int error; if (buffer) @@ -1963,13 +2111,13 @@ com_connect(String *buffer, char *line) } } else - no_rehash=1; // Quick re-connect + rehash= 0; // Quick re-connect buffer->length(0); // command used } else - no_rehash=1; + rehash= 0; error=sql_connect(current_host,current_db,current_user,opt_password,0); - no_rehash=save_rehash; + rehash= save_rehash; if (connected) { @@ -2055,7 +2203,7 @@ com_use(String *buffer __attribute__((unused)), char *line) if (!current_db || cmp_database(current_db,tmp)) { if (one_database) - skip_updates=1; + skip_updates= 1; else { /* @@ -2077,12 +2225,12 @@ com_use(String *buffer __attribute__((unused)), char *line) my_free(current_db,MYF(MY_ALLOW_ZERO_PTR)); current_db=my_strdup(tmp,MYF(MY_WME)); #ifdef HAVE_READLINE - build_completion_hash(no_rehash,1); + build_completion_hash(rehash, 1); #endif } } else - skip_updates=0; + skip_updates= 0; put_info("Database changed",INFO_INFO); return 0; } @@ -2092,11 +2240,8 @@ static int sql_real_connect(char *host,char *database,char *user,char *password, uint silent) { - if (connected) - { /* if old is open, close it first */ - mysql_close(&mysql); - connected= 0; - } + mysql_close(&mysql); + connected= 0; mysql_init(&mysql); if (opt_connect_timeout) { @@ -2111,7 +2256,7 @@ sql_real_connect(char *host,char *database,char *user,char *password, #ifdef HAVE_OPENSSL if (opt_use_ssl) mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath); + opt_ssl_capath, opt_ssl_cipher); #endif if (safe_updates) { @@ -2121,8 +2266,8 @@ sql_real_connect(char *host,char *database,char *user,char *password, select_limit,max_join_size); mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command); } - if (!mysql_real_connect(&mysql,host,user,password, - database,opt_mysql_port,opt_mysql_unix_port, + if (!mysql_real_connect(&mysql, host, user, password, + database, opt_mysql_port, opt_mysql_unix_port, connect_flag)) { if (!silent || @@ -2138,7 +2283,7 @@ sql_real_connect(char *host,char *database,char *user,char *password, connected=1; mysql.reconnect=info_flag ? 1 : 0; // We want to know if this happens #ifdef HAVE_READLINE - build_completion_hash(no_rehash,1); + build_completion_hash(rehash, 1); #endif return 0; } @@ -2183,7 +2328,7 @@ static int com_status(String *buffer __attribute__((unused)), char *line __attribute__((unused))) { - char *status; + const char *status; tee_puts("--------------", stdout); usage(1); /* Print version */ if (connected) @@ -2199,6 +2344,13 @@ com_status(String *buffer __attribute__((unused)), tee_fprintf(stdout, "Current user:\t\t%s\n",cur[1]); (void) mysql_fetch_row(result); // Read eof } +#ifdef HAVE_OPENSSL + if (mysql.net.vio->ssl_ && SSL_get_cipher(mysql.net.vio->ssl_)) + tee_fprintf(stdout, "SSL:\t\t\tCipher in use is %s\n", + SSL_get_cipher(mysql.net.vio->ssl_)); + else +#endif /* HAVE_OPENSSL */ + tee_puts("SSL:\t\t\tNot in use", stdout); } else { @@ -2213,7 +2365,7 @@ com_status(String *buffer __attribute__((unused)), tee_fprintf(stdout, "\nAll updates ignored to this database\n"); vidattr(A_NORMAL); } -#ifndef __WIN__ +#ifdef USE_POPEN tee_fprintf(stdout, "Current pager:\t\t%s\n", pager); tee_fprintf(stdout, "Using outfile:\t\t'%s'\n", opt_outfile ? outfile : ""); #endif @@ -2232,11 +2384,11 @@ com_status(String *buffer __attribute__((unused)), if ((status=mysql_stat(&mysql)) && !mysql_error(&mysql)[0]) { - char *pos,buff[40]; ulong sec; - pos=strchr(status,' '); - *pos++=0; - tee_fprintf(stdout, "%s\t\t\t", status); /* print label */ + char buff[40]; + const char *pos= strchr(status,' '); + /* print label */ + tee_fprintf(stdout, "%.*s\t\t\t", (int) (pos-status), status); if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec))) { nice_time((double) sec,buff,0); @@ -2270,7 +2422,7 @@ static int put_info(const char *str,INFO_TYPE info_type,uint error) { static int inited=0; - + if (status.batch) { if (info_type == INFO_ERROR) @@ -2279,7 +2431,7 @@ put_info(const char *str,INFO_TYPE info_type,uint error) fprintf(stderr,"ERROR"); if (error) (void) fprintf(stderr," %d",error); - if (status.query_start_line && ! skip_line_numbers) + if (status.query_start_line && line_numbers) { (void) fprintf(stderr," at line %lu",status.query_start_line); if (status.file_name) @@ -2307,7 +2459,8 @@ put_info(const char *str,INFO_TYPE info_type,uint error) } if (info_type == INFO_ERROR) { - putchar('\007'); /* This should make a bell */ + if (!opt_nobeep) + putchar('\007'); /* This should make a bell */ vidattr(A_STANDOUT); if (error) (void) tee_fprintf(stderr, "ERROR %d: ", error); @@ -2385,17 +2538,19 @@ void tee_putc(int c, FILE *file) putc(c, OUTFILE); } -#if defined( __WIN__) || defined( OS2) +#if defined( __WIN__) || defined( OS2) || defined(__NETWARE__) #include <time.h> #else #include <sys/times.h> +#ifdef _SC_CLK_TCK // For mit-pthreads #undef CLOCKS_PER_SEC #define CLOCKS_PER_SEC (sysconf(_SC_CLK_TCK)) #endif +#endif static ulong start_timer(void) { -#if defined( __WIN__) || defined( OS2) +#if defined( __WIN__) || defined( OS2) || defined(__NETWARE__) return clock(); #else struct tms tms_tmp; @@ -2450,6 +2605,183 @@ static void mysql_end_timer(ulong start_time,char *buff) strmov(strend(buff),")"); } +static const char* construct_prompt() +{ + //erase the old prompt + processed_prompt.free(); + //get the date struct + time_t lclock = time(NULL); + struct tm *t = localtime(&lclock); + //parse thru the settings for the prompt + for (char *c = current_prompt; *c ; *c++) + { + if (*c != PROMPT_CHAR) + processed_prompt.append(*c); + else + { + switch (*++c) { + case '\0': + //stop it from going beyond if ends with % + c--; + break; + case 'c': + add_int_to_prompt(++prompt_counter); + break; + case 'v': + processed_prompt.append(mysql_get_server_info(&mysql)); + break; + case 'd': + processed_prompt.append(current_db ? current_db : "(none)"); + break; + case 'h': + { + const char *prompt=mysql_get_host_info(&mysql); + if (strstr(prompt, "Localhost")) + processed_prompt.append("localhost"); + else + { + const char *end=strcend(prompt,' '); + processed_prompt.append(prompt, (uint) (end-prompt)); + } + break; + } + case 'p': + if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || + ! mysql.unix_socket) + add_int_to_prompt(mysql.port); + else + { + char *pos=strrchr(mysql.unix_socket,'/'); + processed_prompt.append(pos ? pos+1 : mysql.unix_socket); + } + break; + case 'U': + if (!full_username) + init_username(); + processed_prompt.append(full_username); + break; + case 'u': + if (!full_username) + init_username(); + processed_prompt.append(part_username); + break; + case PROMPT_CHAR: + processed_prompt.append(PROMPT_CHAR); + break; + case 'n': + processed_prompt.append('\n'); + break; + case ' ': + case '_': + processed_prompt.append(' '); + break; + case 'R': + add_int_to_prompt(t->tm_hour); + break; + case 'r': + int getHour; + getHour = t->tm_hour % 12; + if (getHour == 0) + getHour=12; + add_int_to_prompt(getHour); + break; + case 'm': + if (t->tm_min < 10) + processed_prompt.append('0'); + add_int_to_prompt(t->tm_min); + break; + case 'y': + int getYear; + getYear = t->tm_year % 100; + if (getYear < 10) + processed_prompt.append('0'); + add_int_to_prompt(getYear); + break; + case 'Y': + add_int_to_prompt(t->tm_year+1900); + break; + case 'D': + char* dateTime; + time_t lclock; + lclock = time(NULL); + dateTime = ctime(&lclock); + processed_prompt.append(strtok(dateTime,"\n")); + break; + case 's': + add_int_to_prompt(t->tm_sec); + break; + case 'w': + processed_prompt.append(day_names[t->tm_wday]); + break; + case 'P': + processed_prompt.append(t->tm_hour < 12 ? "am" : "pm"); + break; + case 'o': + add_int_to_prompt(t->tm_mon+1); + break; + case 'O': + processed_prompt.append(month_names[t->tm_mon]); + break; + case '\'': + processed_prompt.append("'"); + break; + case '"': + processed_prompt.append('"'); + break; + case 'S': + processed_prompt.append(';'); + break; + case 't': + processed_prompt.append('\t'); + break; + default: + processed_prompt.append(c); + } + } + } + processed_prompt.append('\0'); + return processed_prompt.ptr(); +} + + +static void add_int_to_prompt(int toadd) +{ + char buffer[16]; + int10_to_str(toadd,buffer,10); + processed_prompt.append(buffer); +} + +static void init_username() +{ + my_free(full_username,MYF(MY_ALLOW_ZERO_PTR)); + my_free(part_username,MYF(MY_ALLOW_ZERO_PTR)); + + MYSQL_RES *result; + LINT_INIT(result); + if (!mysql_query(&mysql,"select USER()") && + (result=mysql_use_result(&mysql))) + { + MYSQL_ROW cur=mysql_fetch_row(result); + full_username=my_strdup(cur[0],MYF(MY_WME)); + part_username=my_strdup(strtok(cur[0],"@"),MYF(MY_WME)); + (void) mysql_fetch_row(result); // Read eof + } +} + +static int com_prompt(String *buffer, char *line) +{ + char *ptr=strchr(line, ' '); + prompt_counter = 0; + my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR)); + current_prompt=my_strdup(ptr ? ptr+1 : default_prompt,MYF(MY_WME)); + if (!ptr) + tee_fprintf(stdout, "Returning to default PROMPT of %s\n", default_prompt); + else + tee_fprintf(stdout, "PROMPT set to '%s'\n", current_prompt); + return 0; +} + +#ifndef EMBEDDED_LIBRARY /* Keep sql_string library happy */ gptr sql_alloc(unsigned int Size) @@ -2461,3 +2793,4 @@ void sql_element_free(void *ptr) { my_free((gptr) ptr,MYF(0)); } +#endif /* EMBEDDED_LIBRARY */ |