mysql.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:93k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000-2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* mysql command tool
  14.  * Commands compatible with mSQL by David J. Hughes
  15.  *
  16.  * Written by:
  17.  *   Michael 'Monty' Widenius
  18.  *   Andi Gutmans  <andi@zend.com>
  19.  *   Zeev Suraski  <zeev@zend.com>
  20.  *   Jani Tolonen  <jani@mysql.com>
  21.  *   Matt Wagner   <matt@mysql.com>
  22.  *   Jeremy Cole   <jcole@mysql.com>
  23.  *   Tonu Samuel   <tonu@mysql.com>
  24.  *   Harrison Fisk <harrison@mysql.com>
  25.  *
  26.  **/
  27. #include "client_priv.h"
  28. #include <m_ctype.h>
  29. #include <stdarg.h>
  30. #include <my_dir.h>
  31. #ifndef __GNU_LIBRARY__
  32. #define __GNU_LIBRARY__       // Skip warnings in getopt.h
  33. #endif
  34. #include "my_readline.h"
  35. #include <signal.h>
  36. #include <violite.h>
  37. #if defined(USE_LIBEDIT_INTERFACE) && defined(HAVE_LOCALE_H)
  38. #include <locale.h>
  39. #endif
  40. const char *VER= "14.7";
  41. /* Don't try to make a nice table if the data is too big */
  42. #define MAX_COLUMN_LENGTH      1024
  43. gptr sql_alloc(unsigned size);      // Don't use mysqld alloc for these
  44. void sql_element_free(void *ptr);
  45. #include "sql_string.h"
  46. extern "C" {
  47. #if defined(HAVE_CURSES_H) && defined(HAVE_TERM_H)
  48. #include <curses.h>
  49. #include <term.h>
  50. #else
  51. #if defined(HAVE_TERMIOS_H)
  52. #include <termios.h>
  53. #include <unistd.h>
  54. #elif defined(HAVE_TERMBITS_H)
  55. #include <termbits.h>
  56. #elif defined(HAVE_ASM_TERMBITS_H) && (!defined __GLIBC__ || !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ > 0))
  57. #include <asm/termbits.h> // Standard linux
  58. #endif
  59. #undef VOID
  60. #if defined(HAVE_TERMCAP_H)
  61. #include <termcap.h>
  62. #else
  63. #ifdef HAVE_CURSES_H
  64. #include <curses.h>
  65. #endif
  66. #undef SYSV // hack to avoid syntax error
  67. #ifdef HAVE_TERM_H
  68. #include <term.h>
  69. #endif
  70. #endif
  71. #endif
  72. #undef bcmp // Fix problem with new readline
  73. #if defined( __WIN__) || defined(OS2)
  74. #include <conio.h>
  75. #elif !defined(__NETWARE__)
  76. #include <readline/readline.h>
  77. #define HAVE_READLINE
  78. #endif
  79.   //int vidattr(long unsigned int attrs); // Was missing in sun curses
  80. }
  81. #if !defined(HAVE_VIDATTR)
  82. #undef vidattr
  83. #define vidattr(A) {} // Can't get this to work
  84. #endif
  85. #ifdef FN_NO_CASE_SENCE
  86. #define cmp_database(cs,A,B) my_strcasecmp((cs), (A), (B))
  87. #else
  88. #define cmp_database(cs,A,B) strcmp((A),(B))
  89. #endif
  90. #if !defined( __WIN__) && !defined( OS2) && !defined(__NETWARE__) && (!defined(HAVE_mit_thread) || !defined(THREAD))
  91. #define USE_POPEN
  92. #endif
  93. #include "completion_hash.h"
  94. #define PROMPT_CHAR '\'
  95. #define DEFAULT_DELIMITER ";"
  96. typedef struct st_status
  97. {
  98.   int exit_status;
  99.   ulong query_start_line;
  100.   char *file_name;
  101.   LINE_BUFFER *line_buff;
  102.   bool batch,add_to_history;
  103. } STATUS;
  104. static HashTable ht;
  105. static char **defaults_argv;
  106. enum enum_info_type { INFO_INFO,INFO_ERROR,INFO_RESULT};
  107. typedef enum enum_info_type INFO_TYPE;
  108. static MYSQL mysql; /* The connection */
  109. static my_bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0,
  110.                connected=0,opt_raw_data=0,unbuffered=0,output_tables=0,
  111.        rehash=1,skip_updates=0,safe_updates=0,one_database=0,
  112.        opt_compress=0, using_opt_local_infile=0,
  113.        vertical=0, line_numbers=1, column_names=1,opt_html=0,
  114.                opt_xml=0,opt_nopager=1, opt_outfile=0, named_cmds= 0,
  115.        tty_password= 0, opt_nobeep=0, opt_reconnect=1,
  116.        default_charset_used= 0, opt_secure_auth= 0,
  117.                default_pager_set= 0, opt_sigint_ignore= 0;
  118. static ulong opt_max_allowed_packet, opt_net_buffer_length;
  119. static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
  120. static my_string opt_mysql_unix_port=0;
  121. static int connect_flag=CLIENT_INTERACTIVE;
  122. static char *current_host,*current_db,*current_user=0,*opt_password=0,
  123.             *current_prompt=0, *delimiter_str= 0,
  124.             *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
  125. static char *histfile;
  126. static String glob_buffer,old_buffer;
  127. static String processed_prompt;
  128. static char *full_username=0,*part_username=0,*default_prompt=0;
  129. static int wait_time = 5;
  130. static STATUS status;
  131. static ulong select_limit,max_join_size,opt_connect_timeout=0;
  132. static char mysql_charsets_dir[FN_REFLEN+1];
  133. static const char *xmlmeta[] = {
  134.   "&", "&amp;",
  135.   "<", "&lt;",
  136.   0, 0
  137. };
  138. static const char *day_names[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  139. static const char *month_names[]={"Jan","Feb","Mar","Apr","May","Jun","Jul",
  140.     "Aug","Sep","Oct","Nov","Dec"};
  141. static char default_pager[FN_REFLEN];
  142. static char pager[FN_REFLEN], outfile[FN_REFLEN];
  143. static FILE *PAGER, *OUTFILE;
  144. static MEM_ROOT hash_mem_root;
  145. static uint prompt_counter;
  146. static char delimiter[16]= DEFAULT_DELIMITER;
  147. static uint delimiter_length= 1;
  148. #ifdef HAVE_SMEM
  149. static char *shared_memory_base_name=0;
  150. #endif
  151. static uint opt_protocol=0;
  152. static CHARSET_INFO *charset_info= &my_charset_latin1;
  153. #include "sslopt-vars.h"
  154. const char *default_dbug_option="d:t:o,/tmp/mysql.trace";
  155. void tee_fprintf(FILE *file, const char *fmt, ...);
  156. void tee_fputs(const char *s, FILE *file);
  157. void tee_puts(const char *s, FILE *file);
  158. void tee_putc(int c, FILE *file);
  159. /* The names of functions that actually do the manipulation. */
  160. static int get_options(int argc,char **argv);
  161. static int com_quit(String *str,char*),
  162.    com_go(String *str,char*), com_ego(String *str,char*),
  163.    com_print(String *str,char*),
  164.    com_help(String *str,char*), com_clear(String *str,char*),
  165.    com_connect(String *str,char*), com_status(String *str,char*),
  166.    com_use(String *str,char*), com_source(String *str, char*),
  167.    com_rehash(String *str, char*), com_tee(String *str, char*),
  168.            com_notee(String *str, char*),
  169.            com_prompt(String *str, char*), com_delimiter(String *str, char*);
  170. #ifdef USE_POPEN
  171. static int com_nopager(String *str, char*), com_pager(String *str, char*),
  172.            com_edit(String *str,char*), com_shell(String *str, char *);
  173. #endif
  174. static int read_lines(bool execute_commands);
  175. static int sql_connect(char *host,char *database,char *user,char *password,
  176.        uint silent);
  177. static int put_info(const char *str,INFO_TYPE info,uint error=0,
  178.     const char *sql_state=0);
  179. static int put_error(MYSQL *mysql);
  180. static void safe_put_field(const char *pos,ulong length);
  181. static void xmlencode_print(const char *src, uint length);
  182. static void init_pager();
  183. static void end_pager();
  184. static void init_tee(const char *);
  185. static void end_tee();
  186. static const char* construct_prompt();
  187. static char *get_arg(char *line, my_bool get_next_arg);
  188. static void init_username();
  189. static void add_int_to_prompt(int toadd);
  190. /* A structure which contains information on the commands this program
  191.    can understand. */
  192. typedef struct {
  193.   const char *name; /* User printable name of the function. */
  194.   char cmd_char; /* msql command character */
  195.   int (*func)(String *str,char *); /* Function to call to do the job. */
  196.   bool takes_params; /* Max parameters for command */
  197.   const char *doc; /* Documentation for this function.  */
  198. } COMMANDS;
  199. static COMMANDS commands[] = {
  200.   { "?",      '?', com_help,   1, "Synonym for `help'." },
  201.   { "clear",  'c', com_clear,  0, "Clear command."},
  202.   { "connect",'r', com_connect,1,
  203.     "Reconnect to the server. Optional arguments are db and host." },
  204.   { "delimiter", 'd', com_delimiter,    1,
  205.     "Set query delimiter. " },
  206. #ifdef USE_POPEN
  207.   { "edit",   'e', com_edit,   0, "Edit command with $EDITOR."},
  208. #endif
  209.   { "ego",    'G', com_ego,    0,
  210.     "Send command to mysql server, display result vertically."},
  211.   { "exit",   'q', com_quit,   0, "Exit mysql. Same as quit."},
  212.   { "go",     'g', com_go,     0, "Send command to mysql server." },
  213.   { "help",   'h', com_help,   1, "Display this help." },
  214. #ifdef USE_POPEN
  215.   { "nopager",'n', com_nopager,0, "Disable pager, print to stdout." },
  216. #endif
  217.   { "notee",  't', com_notee,  0, "Don't write into outfile." },
  218. #ifdef USE_POPEN
  219.   { "pager",  'P', com_pager,  1, 
  220.     "Set PAGER [to_pager]. Print the query results via PAGER." },
  221. #endif
  222.   { "print",  'p', com_print,  0, "Print current command." },
  223.   { "prompt", 'R', com_prompt, 1, "Change your mysql prompt."},
  224.   { "quit",   'q', com_quit,   0, "Quit mysql." },
  225.   { "rehash", '#', com_rehash, 0, "Rebuild completion hash." },
  226.   { "source", '.', com_source, 1,
  227.     "Execute a SQL script file. Takes a file name as an argument."},
  228.   { "status", 's', com_status, 0, "Get status information from the server."},
  229. #ifdef USE_POPEN
  230.   { "system", '!', com_shell,  1, "Execute a system shell command."},
  231. #endif
  232.   { "tee",    'T', com_tee,    1, 
  233.     "Set outfile [to_outfile]. Append everything into given outfile." },
  234.   { "use",    'u', com_use,    1,
  235.     "Use another database. Takes database name as argument." },
  236.   /* Get bash-like expansion for some commands */
  237.   { "create table",     0, 0, 0, ""},
  238.   { "create database",  0, 0, 0, ""},
  239.   { "drop",             0, 0, 0, ""},
  240.   { "select",           0, 0, 0, ""},
  241.   { "insert",           0, 0, 0, ""},
  242.   { "replace",          0, 0, 0, ""},
  243.   { "update",           0, 0, 0, ""},
  244.   { "delete",           0, 0, 0, ""},
  245.   { "explain",          0, 0, 0, ""},
  246.   { "show databases",   0, 0, 0, ""},
  247.   { "show fields from", 0, 0, 0, ""},
  248.   { "show keys from",   0, 0, 0, ""},
  249.   { "show tables",      0, 0, 0, ""},
  250.   { "load data from",   0, 0, 0, ""},
  251.   { "alter table",      0, 0, 0, ""},
  252.   { "set option",       0, 0, 0, ""},
  253.   { "lock tables",      0, 0, 0, ""},
  254.   { "unlock tables",    0, 0, 0, ""},
  255.   { (char *)NULL,       0, 0, 0, ""}
  256. };
  257. static const char *load_default_groups[]= { "mysql","client",0 };
  258. static const char *server_default_groups[]=
  259. { "server", "embedded", "mysql_SERVER", 0 };
  260. #ifdef HAVE_READLINE
  261. /*
  262.  HIST_ENTRY is defined for libedit, but not for the real readline
  263.  Need to redefine it for real readline to find it
  264. */
  265. #if !defined(HAVE_HIST_ENTRY)
  266. typedef struct _hist_entry {
  267.   const char      *line;
  268.   const char      *data;
  269. } HIST_ENTRY; 
  270. #endif
  271. extern "C" int add_history(const char *command); /* From readline directory */
  272. extern "C" int read_history(const char *command);
  273. extern "C" int write_history(const char *command);
  274. extern "C" HIST_ENTRY *history_get(int num);
  275. extern "C" int history_length;
  276. static int not_in_history(const char *line);
  277. static void initialize_readline (char *name);
  278. static void fix_history(String *final_command);
  279. #endif
  280. static COMMANDS *find_command (char *name,char cmd_name);
  281. static bool add_line(String &buffer,char *line,char *in_string,
  282.                      bool *ml_comment);
  283. static void remove_cntrl(String &buffer);
  284. static void print_table_data(MYSQL_RES *result);
  285. static void print_table_data_html(MYSQL_RES *result);
  286. static void print_table_data_xml(MYSQL_RES *result);
  287. static void print_tab_data(MYSQL_RES *result);
  288. static void print_table_data_vertically(MYSQL_RES *result);
  289. static ulong start_timer(void);
  290. static void end_timer(ulong start_time,char *buff);
  291. static void mysql_end_timer(ulong start_time,char *buff);
  292. static void nice_time(double sec,char *buff,bool part_second);
  293. static sig_handler mysql_end(int sig);
  294. int main(int argc,char *argv[])
  295. {
  296.   char buff[80];
  297.   char *defaults, *extra_defaults;
  298.   char *emb_argv[3];
  299.   int emb_argc= 1;
  300.   emb_argv[0]= argv[0];
  301.   get_defaults_files(argc, argv, &defaults, &extra_defaults);
  302.   if (defaults)
  303.     emb_argv[emb_argc++]= defaults;
  304.   if (extra_defaults)
  305.     emb_argv[emb_argc++]= extra_defaults;
  306.   MY_INIT(argv[0]);
  307.   DBUG_ENTER("main");
  308.   DBUG_PROCESS(argv[0]);
  309.   
  310.   delimiter_str= delimiter;
  311.   default_prompt = my_strdup(getenv("MYSQL_PS1") ? 
  312.      getenv("MYSQL_PS1") : 
  313.      "mysql> ",MYF(MY_WME));
  314.   current_prompt = my_strdup(default_prompt,MYF(MY_WME));
  315.   prompt_counter=0;
  316.   outfile[0]=0; // no (default) outfile
  317.   strmov(pager, "stdout"); // the default, if --pager wasn't given
  318.   {
  319.     char *tmp=getenv("PAGER");
  320.     if (tmp && strlen(tmp))
  321.     {
  322.       default_pager_set= 1;
  323.       strmov(default_pager, tmp);
  324.     }
  325.   }
  326.   if (!isatty(0) || !isatty(1))
  327.   {
  328.     status.batch=1; opt_silent=1;
  329.     ignore_errors=0;
  330.   }
  331.   else
  332.     status.add_to_history=1;
  333.   status.exit_status=1;
  334.   load_defaults("my",load_default_groups,&argc,&argv);
  335.   defaults_argv=argv;
  336.   if (get_options(argc, (char **) argv))
  337.   {
  338.     free_defaults(defaults_argv);
  339.     my_end(0);
  340.     exit(1);
  341.   }
  342.   if (status.batch && !status.line_buff &&
  343.       !(status.line_buff=batch_readline_init(opt_max_allowed_packet+512,stdin)))
  344.   {
  345.     free_defaults(defaults_argv);
  346.     my_end(0);
  347.     exit(1);
  348.   }
  349.   if (mysql_server_init(emb_argc, emb_argv, (char**) server_default_groups))
  350.   {
  351.     free_defaults(defaults_argv);
  352.     my_end(0);
  353.     exit(1);
  354.   }
  355.   glob_buffer.realloc(512);
  356.   completion_hash_init(&ht, 128);
  357.   init_alloc_root(&hash_mem_root, 16384, 0);
  358.   bzero((char*) &mysql, sizeof(mysql));
  359.   if (sql_connect(current_host,current_db,current_user,opt_password,
  360.   opt_silent))
  361.   {
  362.     quick=1; // Avoid history
  363.     status.exit_status=1;
  364.     mysql_end(-1);
  365.   }
  366.   if (!status.batch)
  367.     ignore_errors=1; // Don't abort monitor
  368.   if (opt_sigint_ignore)
  369.     signal(SIGINT, SIG_IGN);
  370.   else
  371.     signal(SIGINT, mysql_end); // Catch SIGINT to clean up
  372.   signal(SIGQUIT, mysql_end); // Catch SIGQUIT to clean up
  373.   /*
  374.     Run in interactive mode like the ingres/postgres monitor
  375.   */
  376.   put_info("Welcome to the MySQL monitor.  Commands end with ; or \g.",
  377.    INFO_INFO);
  378.   sprintf((char*) glob_buffer.ptr(),
  379.   "Your MySQL connection id is %lu to server version: %sn",
  380.   mysql_thread_id(&mysql),mysql_get_server_info(&mysql));
  381.   put_info((char*) glob_buffer.ptr(),INFO_INFO);
  382. #ifdef HAVE_READLINE
  383.   initialize_readline(my_progname);
  384.   if (!status.batch && !quick && !opt_html && !opt_xml)
  385.   {
  386.     /* read-history from file, default ~/.mysql_history*/
  387.     if (getenv("MYSQL_HISTFILE"))
  388.       histfile=my_strdup(getenv("MYSQL_HISTFILE"),MYF(MY_WME));
  389.     else if (getenv("HOME"))
  390.     {
  391.       histfile=(char*) my_malloc((uint) strlen(getenv("HOME"))
  392.  + (uint) strlen("/.mysql_history")+2,
  393.  MYF(MY_WME));
  394.       if (histfile)
  395. sprintf(histfile,"%s/.mysql_history",getenv("HOME"));
  396.     }
  397.     if (histfile)
  398.     {
  399.       if (verbose)
  400. tee_fprintf(stdout, "Reading history-file %sn",histfile);
  401.       read_history(histfile);
  402.     }
  403.   }
  404. #endif
  405.   sprintf(buff, "%s",
  406. #ifndef NOT_YET
  407.   "Type 'help;' or '\h' for help. Type '\c' to clear the buffer.n");
  408. #else
  409.   "Type 'help [[%]function name[%]]' to get help on usage of function.n");
  410. #endif
  411.   put_info(buff,INFO_INFO);
  412.   status.exit_status=read_lines(1); // read lines and execute them
  413.   if (opt_outfile)
  414.     end_tee();
  415.   mysql_end(0);
  416. #ifndef _lint
  417.   DBUG_RETURN(0); // Keep compiler happy
  418. #endif
  419. }
  420. sig_handler mysql_end(int sig)
  421. {
  422.   mysql_close(&mysql);
  423. #ifdef HAVE_READLINE
  424.   if (!status.batch && !quick && !opt_html && !opt_xml)
  425.   {
  426.     /* write-history */
  427.     if (verbose)
  428.       tee_fprintf(stdout, "Writing history-file %sn",histfile);
  429.     write_history(histfile);
  430.   }
  431.   batch_readline_end(status.line_buff);
  432.   completion_hash_free(&ht);
  433.   free_root(&hash_mem_root,MYF(0));
  434. #endif
  435.   if (sig >= 0)
  436.     put_info(sig ? "Aborted" : "Bye", INFO_RESULT);
  437.   glob_buffer.free();
  438.   old_buffer.free();
  439.   processed_prompt.free();
  440.   my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
  441.   my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
  442.   my_free(histfile,MYF(MY_ALLOW_ZERO_PTR));
  443.   my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
  444.   my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
  445.   my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
  446.   my_free(full_username,MYF(MY_ALLOW_ZERO_PTR));
  447.   my_free(part_username,MYF(MY_ALLOW_ZERO_PTR));
  448.   my_free(default_prompt,MYF(MY_ALLOW_ZERO_PTR));
  449. #ifdef HAVE_SMEM
  450.   my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
  451. #endif
  452.   my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR));
  453.   mysql_server_end();
  454.   free_defaults(defaults_argv);
  455.   my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
  456.   exit(status.exit_status);
  457. }
  458. static struct my_option my_long_options[] =
  459. {
  460.   {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
  461.    0, 0, 0, 0, 0},
  462.   {"help", 'I', "Synonym for -?", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
  463.    0, 0, 0, 0, 0},
  464. #ifdef __NETWARE__
  465.   {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
  466.    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  467. #endif
  468.   {"auto-rehash", OPT_AUTO_REHASH,
  469.    "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.",
  470.    (gptr*) &rehash, (gptr*) &rehash, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
  471.   {"no-auto-rehash", 'A',
  472.    "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.",
  473.    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  474.   {"batch", 'B',
  475.    "Don't use history file. Disable interactive behavior. (Enables --silent)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  476.   {"character-sets-dir", OPT_CHARSETS_DIR,
  477.    "Directory where character sets are.", (gptr*) &charsets_dir,
  478.    (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  479.   {"default-character-set", OPT_DEFAULT_CHARSET,
  480.    "Set the default character set.", (gptr*) &default_charset,
  481.    (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  482.   {"compress", 'C', "Use compression in server/client protocol.",
  483.    (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
  484.    0, 0, 0},
  485. #ifdef DBUG_OFF
  486.   {"debug", '#', "This is a non-debug version. Catch this and exit",
  487.    0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
  488. #else
  489.   {"debug", '#', "Output debug log", (gptr*) &default_dbug_option,
  490.    (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
  491. #endif
  492.   {"database", 'D', "Database to use.", (gptr*) &current_db,
  493.    (gptr*) &current_db, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  494.   {"delimiter", OPT_DELIMITER, "Delimiter to be used.", (gptr*) &delimiter_str,
  495.    (gptr*) &delimiter_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  496.   {"execute", 'e', "Execute command and quit. (Disables --force and history file)", 0,
  497.    0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  498.   {"vertical", 'E', "Print the output of a query (rows) vertically.",
  499.    (gptr*) &vertical, (gptr*) &vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
  500.    0},
  501.   {"force", 'f', "Continue even if we get an sql error.",
  502.    (gptr*) &ignore_errors, (gptr*) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
  503.    0, 0, 0, 0},
  504.   {"no-named-commands", 'g',
  505.    "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.",
  506.    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  507.   {"named-commands", 'G',
  508.    "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.",
  509.    (gptr*) &named_cmds, (gptr*) &named_cmds, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
  510.    0, 0},
  511.   {"ignore-spaces", 'i', "Ignore space after function names.", 0, 0, 0,
  512.    GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  513.   {"local-infile", OPT_LOCAL_INFILE, "Enable/disable LOAD DATA LOCAL INFILE.",
  514.    (gptr*) &opt_local_infile,
  515.    (gptr*) &opt_local_infile, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
  516.   {"no-beep", 'b', "Turn off beep on error.", (gptr*) &opt_nobeep,
  517.    (gptr*) &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 
  518.   {"host", 'h', "Connect to host.", (gptr*) &current_host,
  519.    (gptr*) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  520.   {"html", 'H', "Produce HTML output.", (gptr*) &opt_html, (gptr*) &opt_html,
  521.    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  522.   {"xml", 'X', "Produce XML output", (gptr*) &opt_xml, (gptr*) &opt_xml, 0,
  523.    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  524.   {"line-numbers", OPT_LINE_NUMBERS, "Write line numbers for errors.",
  525.    (gptr*) &line_numbers, (gptr*) &line_numbers, 0, GET_BOOL,
  526.    NO_ARG, 1, 0, 0, 0, 0, 0},  
  527.   {"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,
  528.    NO_ARG, 0, 0, 0, 0, 0, 0},
  529. #ifdef USE_POPEN
  530.   {"no-pager", OPT_NOPAGER,
  531.    "Disable pager and print to stdout. See interactive help (\h) also. WARNING: option deprecated; use --disable-pager instead.",
  532.    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  533. #endif
  534.   {"no-tee", OPT_NOTEE, "Disable outfile. See interactive help (\h) also. WARNING: option deprecated; use --disable-tee instead", 0, 0, 0, GET_NO_ARG,
  535.    NO_ARG, 0, 0, 0, 0, 0, 0},
  536.   {"unbuffered", 'n', "Flush buffer after each query.", (gptr*) &unbuffered,
  537.    (gptr*) &unbuffered, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  538.   {"column-names", OPT_COLUMN_NAMES, "Write column names in results.",
  539.    (gptr*) &column_names, (gptr*) &column_names, 0, GET_BOOL,
  540.    NO_ARG, 1, 0, 0, 0, 0, 0},
  541.   {"skip-column-names", 'N',
  542.    "Don't write column names in results. WARNING: -N is deprecated, use long version of this options instead.",
  543.    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  544.   {"set-variable", 'O',
  545.    "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
  546.    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  547.   {"sigint-ignore", OPT_SIGINT_IGNORE, "Ignore SIGINT (CTRL-C)",
  548.    (gptr*) &opt_sigint_ignore,  (gptr*) &opt_sigint_ignore, 0, GET_BOOL,
  549.    NO_ARG, 0, 0, 0, 0, 0, 0},
  550.   {"one-database", 'o',
  551.    "Only update the default database. This is useful for skipping updates to other database in the update log.",
  552.    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  553. #ifdef USE_POPEN
  554.   {"pager", OPT_PAGER,
  555.    "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.",
  556.    0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
  557. #endif
  558.   {"password", 'p',
  559.    "Password to use when connecting to server. If password is not given it's asked from the tty.",
  560.    0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
  561. #ifdef __WIN__
  562.   {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
  563.    NO_ARG, 0, 0, 0, 0, 0, 0},
  564. #endif
  565.   {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
  566.    (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
  567.    0},
  568.   {"prompt", OPT_PROMPT, "Set the mysql prompt to this value.",
  569.    (gptr*) &current_prompt, (gptr*) &current_prompt, 0, GET_STR_ALLOC,
  570.    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  571.   {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
  572.    0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  573.   {"quick", 'q',
  574.    "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.",
  575.    (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  576.   {"raw", 'r', "Write fields without conversion. Used with --batch.",
  577.    (gptr*) &opt_raw_data, (gptr*) &opt_raw_data, 0, GET_BOOL, NO_ARG, 0, 0, 0,
  578.    0, 0, 0},
  579.   {"reconnect", OPT_RECONNECT, "Reconnect if the connection is lost. Disable with --disable-reconnect. This option is enabled by default.", 
  580.    (gptr*) &opt_reconnect, (gptr*) &opt_reconnect, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
  581.   {"silent", 's', "Be more silent. Print results with a tab as separator, each row on new line.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0,
  582.    0, 0},
  583. #ifdef HAVE_SMEM
  584.   {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
  585.    "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, 
  586.    0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  587. #endif
  588.   {"socket", 'S', "Socket file to use for connection.",
  589.    (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR_ALLOC,
  590.    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  591. #include "sslopt-longopts.h"
  592.   {"table", 't', "Output in table format.", (gptr*) &output_tables,
  593.    (gptr*) &output_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  594.   {"debug-info", 'T', "Print some debug info at exit.", (gptr*) &info_flag,
  595.    (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  596.   {"tee", OPT_TEE,
  597.    "Append everything into outfile. See interactive help (\h) also. Does not work in batch mode.",
  598.    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  599. #ifndef DONT_ALLOW_USER_CHANGE
  600.   {"user", 'u', "User for login if not current user.", (gptr*) &current_user,
  601.    (gptr*) &current_user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  602. #endif
  603.   {"safe-updates", 'U', "Only allow UPDATE and DELETE that uses keys.",
  604.    (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0,
  605.    0, 0, 0, 0},
  606.   {"i-am-a-dummy", 'U', "Synonym for option --safe-updates, -U.",
  607.    (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0,
  608.    0, 0, 0, 0},
  609.   {"verbose", 'v', "Write more. (-v -v -v gives the table output format).", 0,
  610.    0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  611.   {"version", 'V', "Output version information and exit.", 0, 0, 0,
  612.    GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  613.   {"wait", 'w', "Wait and retry if connection is down.", 0, 0, 0, GET_NO_ARG,
  614.    NO_ARG, 0, 0, 0, 0, 0, 0},
  615.   {"connect_timeout", OPT_CONNECT_TIMEOUT,
  616.    "Number of seconds before connection timeout.",
  617.    (gptr*) &opt_connect_timeout,
  618.    (gptr*) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3600*12, 0,
  619.    0, 1},
  620.   {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET,
  621.    "Max packet length to send to, or receive from server",
  622.    (gptr*) &opt_max_allowed_packet, (gptr*) &opt_max_allowed_packet, 0, GET_ULONG,
  623.    REQUIRED_ARG, 16 *1024L*1024L, 4096, (longlong) 2*1024L*1024L*1024L,
  624.    MALLOC_OVERHEAD, 1024, 0},
  625.   {"net_buffer_length", OPT_NET_BUFFER_LENGTH,
  626.    "Buffer for TCP/IP and socket communication",
  627.    (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0, GET_ULONG,
  628.    REQUIRED_ARG, 16384, 1024, 512*1024*1024L, MALLOC_OVERHEAD, 1024, 0},
  629.   {"select_limit", OPT_SELECT_LIMIT,
  630.    "Automatic limit for SELECT when using --safe-updates",
  631.    (gptr*) &select_limit,
  632.    (gptr*) &select_limit, 0, GET_ULONG, REQUIRED_ARG, 1000L, 1, ~0L, 0, 1, 0},
  633.   {"max_join_size", OPT_MAX_JOIN_SIZE,
  634.    "Automatic limit for rows in a join when using --safe-updates",
  635.    (gptr*) &max_join_size,
  636.    (gptr*) &max_join_size, 0, GET_ULONG, REQUIRED_ARG, 1000000L, 1, ~0L, 0, 1,
  637.    0},
  638.   {"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it"
  639.     " uses old (pre-4.1.1) protocol", (gptr*) &opt_secure_auth,
  640.     (gptr*) &opt_secure_auth, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  641.   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
  642. };
  643. static void usage(int version)
  644. {
  645.   /* Divert all help information on NetWare to logger screen. */
  646. #ifdef __NETWARE__
  647. #define printf consoleprintf
  648. #endif
  649. #if defined(USE_LIBEDIT_INTERFACE)
  650.   const char* readline= "";
  651. #else
  652.   const char* readline= "readline";
  653. #endif
  654. #ifdef HAVE_READLINE
  655.   printf("%s  Ver %s Distrib %s, for %s (%s) using %s %sn",
  656.  my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,
  657.          readline, rl_library_version);
  658. #else
  659.   printf("%s  Ver %s Distrib %s, for %s (%s)", my_progname, VER,
  660. MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
  661. #endif
  662.   if (version)
  663.     return;
  664.   printf("
  665. Copyright (C) 2002 MySQL ABn
  666. This software comes with ABSOLUTELY NO WARRANTY. This is free software,n
  667. and you are welcome to modify and redistribute it under the GPL licensen");
  668.   printf("Usage: %s [OPTIONS] [database]n", my_progname);
  669.   my_print_help(my_long_options);
  670.   print_defaults("my", load_default_groups);
  671.   my_print_variables(my_long_options);
  672.   NETWARE_SET_SCREEN_MODE(1);
  673. #ifdef __NETWARE__
  674. #undef printf
  675. #endif
  676. }
  677. static my_bool
  678. get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
  679.        char *argument)
  680. {
  681.   switch(optid) {
  682. #ifdef __NETWARE__
  683.   case OPT_AUTO_CLOSE:
  684.     setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
  685.     break;
  686. #endif
  687.   case OPT_CHARSETS_DIR:
  688.     strmov(mysql_charsets_dir, argument);
  689.     charsets_dir = mysql_charsets_dir;
  690.     break;
  691.   case  OPT_DEFAULT_CHARSET:
  692.     default_charset_used= 1;
  693.     break;
  694.   case OPT_DELIMITER:
  695.     if (argument == disabled_my_option)
  696.       strmov(delimiter, DEFAULT_DELIMITER);
  697.     else
  698.       strmake(delimiter, argument, sizeof(delimiter) - 1);
  699.     delimiter_length= (uint)strlen(delimiter);
  700.     delimiter_str= delimiter;
  701.     break;
  702.   case OPT_LOCAL_INFILE:
  703.     using_opt_local_infile=1;
  704.     break;
  705.   case OPT_TEE:
  706.     if (argument == disabled_my_option)
  707.     {
  708.       if (opt_outfile)
  709. end_tee();
  710.     }
  711.     else
  712.       init_tee(argument);
  713.     break;
  714.   case OPT_NOTEE:
  715.     printf("WARNING: option deprecated; use --disable-tee instead.n");
  716.     if (opt_outfile)
  717.       end_tee();
  718.     break;
  719.   case OPT_PAGER:
  720.     if (argument == disabled_my_option)
  721.       opt_nopager= 1;
  722.     else
  723.     {
  724.       opt_nopager= 0;
  725.       if (argument && strlen(argument))
  726.       {
  727. default_pager_set= 1;
  728. strmov(pager, argument);
  729. strmov(default_pager, pager);
  730.       }
  731.       else if (default_pager_set)
  732. strmov(pager, default_pager);
  733.       else
  734. opt_nopager= 1;
  735.     }
  736.     break;
  737.   case OPT_NOPAGER:
  738.     printf("WARNING: option deprecated; use --disable-pager instead.n");
  739.     opt_nopager= 1;
  740.   case OPT_MYSQL_PROTOCOL:
  741.   {
  742.     if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0)
  743.     {
  744.       fprintf(stderr, "Unknown option to protocol: %sn", argument);
  745.       exit(1);
  746.     }
  747.     break;
  748.   }
  749.   break;
  750.   case 'A':
  751.     rehash= 0;
  752.     break;
  753.   case 'N':
  754.     column_names= 0;
  755.     break;
  756.   case 'e':
  757.     status.batch= 1;
  758.     status.add_to_history= 0;
  759.     if (!status.line_buff)
  760.       ignore_errors= 0;                         // do it for the first -e only
  761.     if (!(status.line_buff= batch_readline_command(status.line_buff, argument)))
  762.       return 1;
  763.     break;
  764.   case 'o':
  765.     if (argument == disabled_my_option)
  766.       one_database= 0;
  767.     else
  768.       one_database= skip_updates= 1;
  769.     break;
  770.   case 'p':
  771.     if (argument == disabled_my_option)
  772.       argument= (char*) ""; // Don't require password
  773.     if (argument)
  774.     {
  775.       char *start= argument;
  776.       my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
  777.       opt_password= my_strdup(argument, MYF(MY_FAE));
  778.       while (*argument) *argument++= 'x'; // Destroy argument
  779.       if (*start)
  780. start[1]=0 ;
  781.       tty_password= 0;
  782.     }
  783.     else
  784.       tty_password= 1;
  785.     break;
  786.   case '#':
  787.     DBUG_PUSH(argument ? argument : default_dbug_option);
  788.     info_flag= 1;
  789.     break;
  790.   case 's':
  791.     if (argument == disabled_my_option)
  792.       opt_silent= 0;
  793.     else
  794.       opt_silent++;
  795.     break;
  796.   case 'v':
  797.     if (argument == disabled_my_option)
  798.       verbose= 0;
  799.     else
  800.       verbose++;
  801.     break;
  802.   case 'B':
  803.     status.batch= 1;
  804.     status.add_to_history= 0;
  805.     set_if_bigger(opt_silent,1);                         // more silent
  806.     break;
  807.   case 'W':
  808. #ifdef __WIN__
  809.     opt_protocol = MYSQL_PROTOCOL_PIPE;
  810. #endif
  811.     break;
  812. #include <sslopt-case.h>
  813.   case 'V':
  814.     usage(1);
  815.     exit(0);
  816.   case 'I':
  817.   case '?':
  818.     usage(0);
  819.     exit(0);
  820.   }
  821.   return 0;
  822. }
  823. static int get_options(int argc, char **argv)
  824. {
  825.   char *tmp, *pagpoint;
  826.   int ho_error;
  827.   MYSQL_PARAMETERS *mysql_params= mysql_get_parameters();
  828.   tmp= (char *) getenv("MYSQL_HOST");
  829.   if (tmp)
  830.     current_host= my_strdup(tmp, MYF(MY_WME));
  831.   pagpoint= getenv("PAGER");
  832.   if (!((char*) (pagpoint)))
  833.   {
  834.     strmov(pager, "stdout");
  835.     opt_nopager= 1;
  836.   }
  837.   else
  838.     strmov(pager, pagpoint);
  839.   strmov(default_pager, pager);
  840.   opt_max_allowed_packet= *mysql_params->p_max_allowed_packet;
  841.   opt_net_buffer_length= *mysql_params->p_net_buffer_length;
  842.   if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
  843.     exit(ho_error);
  844.   *mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
  845.   *mysql_params->p_net_buffer_length= opt_net_buffer_length;
  846.   if (status.batch) /* disable pager and outfile in this case */
  847.   {
  848.     strmov(default_pager, "stdout");
  849.     strmov(pager, "stdout");
  850.     opt_nopager= 1;
  851.     default_pager_set= 0;
  852.     opt_outfile= 0;
  853.     opt_reconnect= 0;
  854.     connect_flag= 0; /* Not in interactive mode */
  855.   }
  856.   
  857.   if (strcmp(default_charset, charset_info->csname) &&
  858.       !(charset_info= get_charset_by_csname(default_charset, 
  859.     MY_CS_PRIMARY, MYF(MY_WME))))
  860.     exit(1);
  861.   if (argc > 1)
  862.   {
  863.     usage(0);
  864.     exit(1);
  865.   }
  866.   if (argc == 1)
  867.   {
  868.     skip_updates= 0;
  869.     my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
  870.     current_db= my_strdup(*argv, MYF(MY_WME));
  871.   }
  872.   if (tty_password)
  873.     opt_password= get_tty_password(NullS);
  874.   return(0);
  875. }
  876. static int read_lines(bool execute_commands)
  877. {
  878. #if defined(OS2) || defined(__NETWARE__)
  879.   char linebuffer[254];
  880.   String buffer;
  881. #endif
  882. #if defined(__WIN__)
  883.   String tmpbuf;
  884.   String buffer;
  885. #endif
  886.   char *line;
  887.   char in_string=0;
  888.   ulong line_number=0;
  889.   bool ml_comment= 0;  
  890.   COMMANDS *com;
  891.   status.exit_status=1;
  892.   
  893.   for (;;)
  894.   {
  895.     if (status.batch || !execute_commands)
  896.     {
  897.       line=batch_readline(status.line_buff);
  898.       line_number++;
  899.       if (!glob_buffer.length())
  900. status.query_start_line=line_number;
  901.     }
  902.     else
  903.     {
  904.       char *prompt= (char*) (ml_comment ? "   /*> " :
  905.                              glob_buffer.is_empty() ?  construct_prompt() :
  906.      !in_string ? "    -> " :
  907.      in_string == ''' ?
  908.      "    '> " : (in_string == '`' ?
  909.      "    `> " :
  910.      "    "> "));
  911.       if (opt_outfile && glob_buffer.is_empty())
  912. fflush(OUTFILE);
  913. #if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
  914.       tee_fputs(prompt, stdout);
  915. #if defined(__NETWARE__)
  916.       line=fgets(linebuffer, sizeof(linebuffer)-1, stdin);
  917.       /* Remove the 'n' */
  918.       if (line)
  919.       {
  920.         char *p = strrchr(line, 'n');
  921.         if (p != NULL)
  922.           *p = '';
  923.       }
  924. #elif defined(__WIN__)
  925.       if (!tmpbuf.is_alloced())
  926.         tmpbuf.alloc(65535);
  927.       buffer.length(0);
  928.       unsigned long clen;
  929.       do
  930.       {
  931.         line= my_cgets((char *) tmpbuf.ptr(), tmpbuf.alloced_length()-1, &clen);
  932.         buffer.append(line, clen);
  933.         /* 
  934.            if we got buffer fully filled than there is a chance that
  935.            something else is still in console input buffer
  936.         */
  937.       } while (tmpbuf.alloced_length() <= clen);
  938.       line= buffer.c_ptr();
  939. #else /* OS2 */
  940.       buffer.length(0);
  941.       /* _cgets() expects the buffer size - 3 as the first byte */
  942.       linebuffer[0]= (char) sizeof(linebuffer) - 3;
  943.       do
  944.       {
  945.         line= _cgets(linebuffer);
  946.         buffer.append(line, (unsigned char)linebuffer[1]);
  947.       /*
  948.         If _cgets() gets an input line that is linebuffer[0] bytes
  949.         long, the next call to _cgets() will return immediately with
  950.         linebuffer[1] == 0, and it does the same thing for input that
  951.         is linebuffer[0]-1 bytes long. So it appears that even though
  952.         _cgets() replaces the newline (which is two bytes on Window) with
  953.         a nil, it still needs the space in the linebuffer for it. This is,
  954.         naturally, undocumented.
  955.        */
  956.       } while ((unsigned char)linebuffer[0] <=
  957.                (unsigned char)linebuffer[1] + 1);
  958.       line= buffer.c_ptr();
  959. #endif /* __NETWARE__ */
  960. #else
  961.       if (opt_outfile)
  962. fputs(prompt, OUTFILE);
  963.       line= readline(prompt);
  964. #endif /* defined( __WIN__) || defined(OS2) || defined(__NETWARE__) */
  965.       /*
  966.         When Ctrl+d or Ctrl+z is pressed, the line may be NULL on some OS
  967.         which may cause coredump.
  968.       */
  969.       if (opt_outfile && line)
  970. fprintf(OUTFILE, "%sn", line);
  971.     }
  972.     if (!line) // End of file
  973.     {
  974.       status.exit_status=0;
  975.       break;
  976.     }
  977.     if (!in_string && (line[0] == '#' ||
  978.        (line[0] == '-' && line[1] == '-') ||
  979.        line[0] == 0))
  980.       continue; // Skip comment lines
  981.     /*
  982.       Check if line is a mysql command line
  983.       (We want to allow help, print and clear anywhere at line start
  984.     */
  985.     if (execute_commands && (named_cmds || glob_buffer.is_empty()) 
  986. && !in_string && (com=find_command(line,0)))
  987.     {
  988.       if ((*com->func)(&glob_buffer,line) > 0)
  989. break;
  990.       if (glob_buffer.is_empty()) // If buffer was emptied
  991. in_string=0;
  992. #ifdef HAVE_READLINE
  993.       if (status.add_to_history && not_in_history(line))
  994. add_history(line);
  995. #endif
  996.       continue;
  997.     }
  998.     if (add_line(glob_buffer,line,&in_string,&ml_comment))
  999.       break;
  1000.   }
  1001.   /* if in batch mode, send last query even if it doesn't end with g or go */
  1002.   if ((status.batch || !execute_commands) && !status.exit_status)
  1003.   {
  1004.     remove_cntrl(glob_buffer);
  1005.     if (!glob_buffer.is_empty())
  1006.     {
  1007.       status.exit_status=1;
  1008.       if (com_go(&glob_buffer,line) <= 0)
  1009. status.exit_status=0;
  1010.     }
  1011.   }
  1012. #if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
  1013.   buffer.free();
  1014. #endif
  1015. #if defined( __WIN__)
  1016.   tmpbuf.free();
  1017. #endif
  1018.   return status.exit_status;
  1019. }
  1020. static COMMANDS *find_command (char *name,char cmd_char)
  1021. {
  1022.   uint len;
  1023.   char *end;
  1024.   if (!name)
  1025.   {
  1026.     len=0;
  1027.     end=0;
  1028.   }
  1029.   else
  1030.   {
  1031.     while (my_isspace(charset_info,*name))
  1032.       name++;
  1033.     if (strstr(name, delimiter) || strstr(name, "\g"))
  1034.       return ((COMMANDS *) 0);
  1035.     if ((end=strcont(name," t")))
  1036.     {
  1037.       len=(uint) (end - name);
  1038.       while (my_isspace(charset_info,*end))
  1039. end++;
  1040.       if (!*end)
  1041. end=0; // no arguments to function
  1042.     }
  1043.     else
  1044.       len=(uint) strlen(name);
  1045.   }
  1046.   for (uint i= 0; commands[i].name; i++)
  1047.   {
  1048.     if (commands[i].func &&
  1049. ((name && 
  1050.   !my_strnncoll(charset_info,(uchar*)name,len,
  1051.      (uchar*)commands[i].name,len) &&
  1052.   !commands[i].name[len] &&
  1053.   (!end || (end && commands[i].takes_params))) ||
  1054.  !name && commands[i].cmd_char == cmd_char))
  1055.       return (&commands[i]);
  1056.   }
  1057.   return ((COMMANDS *) 0);
  1058. }
  1059. static bool add_line(String &buffer,char *line,char *in_string,
  1060.                      bool *ml_comment)
  1061. {
  1062.   uchar inchar;
  1063.   char buff[80], *pos, *out;
  1064.   COMMANDS *com;
  1065.   if (!line[0] && buffer.is_empty())
  1066.     return 0;
  1067. #ifdef HAVE_READLINE
  1068.   if (status.add_to_history && line[0] && not_in_history(line))
  1069.     add_history(line);
  1070. #endif
  1071. #ifdef USE_MB
  1072.   char *strend=line+(uint) strlen(line);
  1073. #endif
  1074.   for (pos=out=line ; (inchar= (uchar) *pos) ; pos++)
  1075.   {
  1076.     if (my_isspace(charset_info,inchar) && out == line && 
  1077.         buffer.is_empty())
  1078.       continue;
  1079. #ifdef USE_MB
  1080.     int l;
  1081.     if (use_mb(charset_info) &&
  1082.         (l= my_ismbchar(charset_info, pos, strend)))
  1083.     {
  1084.       if (!*ml_comment)
  1085.       {
  1086.         while (l--)
  1087.           *out++ = *pos++;
  1088.         pos--;
  1089.       }
  1090.       else
  1091.         pos+= l - 1;
  1092.       continue;
  1093.     }
  1094. #endif
  1095.     if (!*ml_comment && inchar == '\')
  1096.     {
  1097.       // Found possbile one character command like c
  1098.       if (!(inchar = (uchar) *++pos))
  1099. break; // readline adds one ''
  1100.       if (*in_string || inchar == 'N') // N is short for NULL
  1101.       { // Don't allow commands in string
  1102. *out++='\';
  1103. *out++= (char) inchar;
  1104. continue;
  1105.       }
  1106.       if ((com=find_command(NullS,(char) inchar)))
  1107.       {
  1108. const String tmp(line,(uint) (out-line), charset_info);
  1109. buffer.append(tmp);
  1110. if ((*com->func)(&buffer,pos-1) > 0)
  1111.   return 1; // Quit
  1112. if (com->takes_params)
  1113. {
  1114.   for (pos++ ;
  1115.        *pos && (*pos != *delimiter ||
  1116. !is_prefix(pos + 1, delimiter + 1)) ; pos++)
  1117.     ; // Remove parameters
  1118.   if (!*pos)
  1119.     pos--;
  1120.   else 
  1121.     pos+= delimiter_length - 1; // Point at last delim char
  1122. }
  1123. out=line;
  1124.       }
  1125.       else
  1126.       {
  1127. sprintf(buff,"Unknown command '\%c'.",inchar);
  1128. if (put_info(buff,INFO_ERROR) > 0)
  1129.   return 1;
  1130. *out++='\';
  1131. *out++=(char) inchar;
  1132. continue;
  1133.       }
  1134.     }
  1135.     else if (!*ml_comment && (*pos == *delimiter &&
  1136.       is_prefix(pos + 1, delimiter + 1)) &&
  1137.      !*in_string)
  1138.     {
  1139.       uint old_delimiter_length= delimiter_length;
  1140.       if (out != line)
  1141. buffer.append(line, (uint) (out - line)); // Add this line
  1142.       if ((com= find_command(buffer.c_ptr(), 0)))
  1143.       {
  1144. if ((*com->func)(&buffer, buffer.c_ptr()) > 0)
  1145.   return 1; // Quit
  1146.       }
  1147.       else
  1148.       {
  1149. if (com_go(&buffer, 0) > 0)             // < 0 is not fatal
  1150.   return 1;
  1151.       }
  1152.       buffer.length(0);
  1153.       out= line;
  1154.       pos+= old_delimiter_length - 1;
  1155.     }
  1156.     else if (!*ml_comment && (!*in_string && (inchar == '#' ||
  1157.       inchar == '-' && pos[1] == '-' &&
  1158.       my_isspace(charset_info,pos[2]))))
  1159.       break; // comment to end of line
  1160.     else if (!*in_string && inchar == '/' && *(pos+1) == '*' &&
  1161.      *(pos+2) != '!')
  1162.     {
  1163.       pos++;
  1164.       *ml_comment= 1;
  1165.       if (out != line)
  1166.       {
  1167.         buffer.append(line,(uint) (out-line));
  1168.         out=line;
  1169.       }
  1170.     }
  1171.     else if (*ml_comment && inchar == '*' && *(pos + 1) == '/')
  1172.     {
  1173.       pos++;
  1174.       *ml_comment= 0;
  1175.     }      
  1176.     else
  1177.     { // Add found char to buffer
  1178.       if (inchar == *in_string)
  1179. *in_string= 0;
  1180.       else if (!*ml_comment && !*in_string &&
  1181.        (inchar == ''' || inchar == '"' || inchar == '`'))
  1182. *in_string= (char) inchar;
  1183.       if (!*ml_comment)
  1184. *out++= (char) inchar;
  1185.     }
  1186.   }
  1187.   if (out != line || !buffer.is_empty())
  1188.   {
  1189.     *out++='n';
  1190.     uint length=(uint) (out-line);
  1191.     if (buffer.length() + length >= buffer.alloced_length())
  1192.       buffer.realloc(buffer.length()+length+IO_SIZE);
  1193.     if (!(*ml_comment) && buffer.append(line,length))
  1194.       return 1;
  1195.   }
  1196.   return 0;
  1197. }
  1198. /*****************************************************************
  1199.     Interface to Readline Completion
  1200. ******************************************************************/
  1201. #ifdef HAVE_READLINE
  1202. static char *new_command_generator(const char *text, int);
  1203. static char **new_mysql_completion (const char *text, int start, int end);
  1204. /*
  1205.   Tell the GNU Readline library how to complete.  We want to try to complete
  1206.   on command names if this is the first word in the line, or on filenames
  1207.   if not.
  1208. */
  1209. #if defined(USE_NEW_READLINE_INTERFACE) || defined(USE_LIBEDIT_INTERFACE)
  1210. char *no_completion(const char*,int)
  1211. #else
  1212. int no_completion()
  1213. #endif
  1214. {
  1215.   return 0; /* No filename completion */
  1216. }
  1217. /* glues pieces of history back together if in pieces   */
  1218. static void fix_history(String *final_command) 
  1219. {
  1220.   int total_lines = 1;
  1221.   char *ptr = final_command->c_ptr();
  1222.   String fixed_buffer;  /* Converted buffer */
  1223.   char str_char = '';  /* Character if we are in a string or not */
  1224.   
  1225.   /* find out how many lines we have and remove newlines */
  1226.   while (*ptr != '') 
  1227.   {
  1228.     switch (*ptr) {
  1229.       /* string character */
  1230.     case '"':
  1231.     case ''':
  1232.     case '`':
  1233.       if (str_char == '') /* open string */
  1234. str_char = *ptr;
  1235.       else if (str_char == *ptr)   /* close string */
  1236. str_char = '';
  1237.       fixed_buffer.append(ptr,1);
  1238.       break;
  1239.     case 'n':
  1240.       /* 
  1241.  not in string, change to space
  1242.  if in string, leave it alone 
  1243.       */
  1244.       fixed_buffer.append(str_char == '' ? " " : "n");
  1245.       total_lines++;
  1246.       break;
  1247.     case '\':
  1248.       fixed_buffer.append('\');
  1249.       /* need to see if the backslash is escaping anything */
  1250.       if (str_char) 
  1251.       {
  1252. ptr++;
  1253. /* special characters that need escaping */
  1254. if (*ptr == ''' || *ptr == '"' || *ptr == '\')
  1255.   fixed_buffer.append(ptr,1);
  1256. else
  1257.   ptr--;
  1258.       }
  1259.       break;
  1260.       
  1261.     default:
  1262.       fixed_buffer.append(ptr,1);
  1263.     }
  1264.     ptr++;
  1265.   }
  1266.   if (total_lines > 1)
  1267.     add_history(fixed_buffer.ptr());
  1268. }
  1269. /*
  1270.   returns 0 if line matches the previous history entry
  1271.   returns 1 if the line doesn't match the previous history entry
  1272. */
  1273. static int not_in_history(const char *line) 
  1274. {
  1275.   HIST_ENTRY *oldhist = history_get(history_length);
  1276.   
  1277.   if (oldhist == 0)
  1278.     return 1;
  1279.   if (strcmp(oldhist->line,line) == 0)
  1280.     return 0;
  1281.   return 1;
  1282. }
  1283. static void initialize_readline (char *name)
  1284. {
  1285.   /* Allow conditional parsing of the ~/.inputrc file. */
  1286.   rl_readline_name = name;
  1287.   /* Tell the completer that we want a crack first. */
  1288. #if defined(USE_NEW_READLINE_INTERFACE)
  1289.   rl_attempted_completion_function= (rl_completion_func_t*)&new_mysql_completion;
  1290.   rl_completion_entry_function= (rl_compentry_func_t*)&no_completion;
  1291. #elif defined(USE_LIBEDIT_INTERFACE)
  1292. #ifdef HAVE_LOCALE_H
  1293.   setlocale(LC_ALL,""); /* so as libedit use isprint */
  1294. #endif
  1295.   rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion;
  1296.   rl_completion_entry_function= (Function*)&no_completion;
  1297. #else
  1298.   rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion;
  1299.   rl_completion_entry_function= (Function*)&no_completion;
  1300. #endif
  1301. }
  1302. /*
  1303.   Attempt to complete on the contents of TEXT.  START and END show the
  1304.   region of TEXT that contains the word to complete.  We can use the
  1305.   entire line in case we want to do some simple parsing.  Return the
  1306.   array of matches, or NULL if there aren't any.
  1307. */
  1308. static char **new_mysql_completion (const char *text,
  1309.     int start __attribute__((unused)),
  1310.     int end __attribute__((unused)))
  1311. {
  1312.   if (!status.batch && !quick)
  1313. #if defined(USE_NEW_READLINE_INTERFACE)
  1314.     return rl_completion_matches(text, new_command_generator);
  1315. #else
  1316.     return completion_matches((char *)text, (CPFunction *)new_command_generator);
  1317. #endif
  1318.   else
  1319.     return (char**) 0;
  1320. }
  1321. static char *new_command_generator(const char *text,int state)
  1322. {
  1323.   static int textlen;
  1324.   char *ptr;
  1325.   static Bucket *b;
  1326.   static entry *e;
  1327.   static uint i;
  1328.   if (!state)
  1329.     textlen=(uint) strlen(text);
  1330.   if (textlen>0)
  1331.   { /* lookup in the hash */
  1332.     if (!state)
  1333.     {
  1334.       uint len;
  1335.       b = find_all_matches(&ht,text,(uint) strlen(text),&len);
  1336.       if (!b)
  1337. return NullS;
  1338.       e = b->pData;
  1339.     }
  1340.     if (e)
  1341.     {
  1342.       ptr= strdup(e->str);
  1343.       e = e->pNext;
  1344.       return ptr;
  1345.     }
  1346.   }
  1347.   else
  1348.   { /* traverse the entire hash, ugly but works */
  1349.     if (!state)
  1350.     {
  1351.       /* find the first used bucket */
  1352.       for (i=0 ; i < ht.nTableSize ; i++)
  1353.       {
  1354. if (ht.arBuckets[i])
  1355. {
  1356.   b = ht.arBuckets[i];
  1357.   e = b->pData;
  1358.   break;
  1359. }
  1360.       }
  1361.     }
  1362.     ptr= NullS;
  1363.     while (e && !ptr)
  1364.     { /* find valid entry in bucket */
  1365.       if ((uint) strlen(e->str) == b->nKeyLength)
  1366. ptr = strdup(e->str);
  1367.       /* find the next used entry */
  1368.       e = e->pNext;
  1369.       if (!e)
  1370.       { /* find the next used bucket */
  1371. b = b->pNext;
  1372. if (!b)
  1373. {
  1374.   for (i++ ; i<ht.nTableSize; i++)
  1375.   {
  1376.     if (ht.arBuckets[i])
  1377.     {
  1378.       b = ht.arBuckets[i];
  1379.       e = b->pData;
  1380.       break;
  1381.     }
  1382.   }
  1383. }
  1384. else
  1385.   e = b->pData;
  1386.       }
  1387.     }
  1388.     if (ptr)
  1389.       return ptr;
  1390.   }
  1391.   return NullS;
  1392. }
  1393. /* Build up the completion hash */
  1394. static void build_completion_hash(bool rehash, bool write_info)
  1395. {
  1396.   COMMANDS *cmd=commands;
  1397.   MYSQL_RES *databases=0,*tables=0;
  1398.   MYSQL_RES *fields;
  1399.   static char ***field_names= 0;
  1400.   MYSQL_ROW database_row,table_row;
  1401.   MYSQL_FIELD *sql_field;
  1402.   char buf[NAME_LEN*2+2];  // table name plus field name plus 2
  1403.   int i,j,num_fields;
  1404.   DBUG_ENTER("build_completion_hash");
  1405.   if (status.batch || quick || !current_db)
  1406.     DBUG_VOID_RETURN; // We don't need completion in batches
  1407.   /* hash SQL commands */
  1408.   while (cmd->name) {
  1409.     add_word(&ht,(char*) cmd->name);
  1410.     cmd++;
  1411.   }
  1412.   if (!rehash)
  1413.     DBUG_VOID_RETURN;
  1414.   /* Free old used memory */
  1415.   if (field_names)
  1416.     field_names=0;
  1417.   completion_hash_clean(&ht);
  1418.   free_root(&hash_mem_root,MYF(0));
  1419.   /* hash MySQL functions (to be implemented) */
  1420.   /* hash all database names */
  1421.   if (mysql_query(&mysql,"show databases") == 0)
  1422.   {
  1423.     if (!(databases = mysql_store_result(&mysql)))
  1424.       put_info(mysql_error(&mysql),INFO_INFO);
  1425.     else
  1426.     {
  1427.       while ((database_row=mysql_fetch_row(databases)))
  1428.       {
  1429. char *str=strdup_root(&hash_mem_root, (char*) database_row[0]);
  1430. if (str)
  1431.   add_word(&ht,(char*) str);
  1432.       }
  1433.       mysql_free_result(databases);
  1434.     }
  1435.   }
  1436.   /* hash all table names */
  1437.   if (mysql_query(&mysql,"show tables")==0)
  1438.   {
  1439.     if (!(tables = mysql_store_result(&mysql)))
  1440.       put_info(mysql_error(&mysql),INFO_INFO);
  1441.     else
  1442.     {
  1443.       if (mysql_num_rows(tables) > 0 && !opt_silent && write_info)
  1444.       {
  1445. tee_fprintf(stdout, "
  1446. Reading table information for completion of table and column namesn
  1447. You can turn off this feature to get a quicker startup with -Ann");
  1448.       }
  1449.       while ((table_row=mysql_fetch_row(tables)))
  1450.       {
  1451. char *str=strdup_root(&hash_mem_root, (char*) table_row[0]);
  1452. if (str &&
  1453.     !completion_hash_exists(&ht,(char*) str, (uint) strlen(str)))
  1454.   add_word(&ht,str);
  1455.       }
  1456.     }
  1457.   }
  1458.   /* hash all field names, both with the table prefix and without it */
  1459.   if (!tables) /* no tables */
  1460.   {
  1461.     DBUG_VOID_RETURN;
  1462.   }
  1463.   mysql_data_seek(tables,0);
  1464.   if (!(field_names= (char ***) alloc_root(&hash_mem_root,sizeof(char **) *
  1465.    (uint) (mysql_num_rows(tables)+1))))
  1466.   {
  1467.     mysql_free_result(tables);
  1468.     DBUG_VOID_RETURN;
  1469.   }
  1470.   i=0;
  1471.   while ((table_row=mysql_fetch_row(tables)))
  1472.   {
  1473.     if ((fields=mysql_list_fields(&mysql,(const char*) table_row[0],NullS)))
  1474.     {
  1475.       num_fields=mysql_num_fields(fields);
  1476.       if (!(field_names[i] = (char **) alloc_root(&hash_mem_root,
  1477.   sizeof(char *) *
  1478.   (num_fields*2+1))))
  1479.       {
  1480.         mysql_free_result(fields);
  1481.         break;
  1482.       }
  1483.       field_names[i][num_fields*2]= '';
  1484.       j=0;
  1485.       while ((sql_field=mysql_fetch_field(fields)))
  1486.       {
  1487. sprintf(buf,"%.64s.%.64s",table_row[0],sql_field->name);
  1488. field_names[i][j] = strdup_root(&hash_mem_root,buf);
  1489. add_word(&ht,field_names[i][j]);
  1490. field_names[i][num_fields+j] = strdup_root(&hash_mem_root,
  1491.    sql_field->name);
  1492. if (!completion_hash_exists(&ht,field_names[i][num_fields+j],
  1493.     (uint) strlen(field_names[i][num_fields+j])))
  1494.   add_word(&ht,field_names[i][num_fields+j]);
  1495. j++;
  1496.       }
  1497.       mysql_free_result(fields);
  1498.     }
  1499.     else
  1500.       field_names[i]= 0;
  1501.     i++;
  1502.   }
  1503.   mysql_free_result(tables);
  1504.   field_names[i]=0; // End pointer
  1505.   DBUG_VOID_RETURN;
  1506. }
  1507. /* for gnu readline */
  1508. #ifndef HAVE_INDEX
  1509. extern "C" {
  1510. extern char *index(const char *,int c),*rindex(const char *,int);
  1511. char *index(const char *s,int c)
  1512. {
  1513.   for (;;)
  1514.   {
  1515.      if (*s == (char) c) return (char*) s;
  1516.      if (!*s++) return NullS;
  1517.   }
  1518. }
  1519. char *rindex(const char *s,int c)
  1520. {
  1521.   reg3 char *t;
  1522.   t = NullS;
  1523.   do if (*s == (char) c) t = (char*) s; while (*s++);
  1524.   return (char*) t;
  1525. }
  1526. }
  1527. #endif
  1528. #endif /* HAVE_READLINE */
  1529. static int reconnect(void)
  1530. {
  1531.   if (opt_reconnect)
  1532.   {
  1533.     put_info("No connection. Trying to reconnect...",INFO_INFO);
  1534.     (void) com_connect((String *) 0, 0);
  1535.     if (rehash)
  1536.       com_rehash(NULL, NULL);
  1537.   }
  1538.   if (!connected)
  1539.     return put_info("Can't connect to the servern",INFO_ERROR);
  1540.   return 0;
  1541. }
  1542. static void get_current_db()
  1543. {
  1544.   MYSQL_RES *res;
  1545.   my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
  1546.   current_db= NULL;
  1547.   /* In case of error below current_db will be NULL */
  1548.   if (!mysql_query(&mysql, "SELECT DATABASE()") &&
  1549.       (res= mysql_use_result(&mysql)))
  1550.   {
  1551.     MYSQL_ROW row= mysql_fetch_row(res);
  1552.     if (row[0])
  1553.       current_db= my_strdup(row[0], MYF(MY_WME));
  1554.     mysql_free_result(res);
  1555.   }
  1556. }
  1557. /***************************************************************************
  1558.  The different commands
  1559. ***************************************************************************/
  1560. int mysql_real_query_for_lazy(const char *buf, int length)
  1561. {
  1562.   for (uint retry=0;; retry++)
  1563.   {
  1564.     if (!mysql_real_query(&mysql,buf,length))
  1565.       return 0;
  1566.     int error= put_error(&mysql);
  1567.     if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 ||
  1568.       !opt_reconnect)
  1569.       return error;
  1570.     if (reconnect())
  1571.       return error;
  1572.   }
  1573. }
  1574. int mysql_store_result_for_lazy(MYSQL_RES **result)
  1575. {
  1576.   if ((*result=mysql_store_result(&mysql)))
  1577.     return 0;
  1578.   if (mysql_error(&mysql)[0])
  1579.     return put_error(&mysql);
  1580.   return 0;
  1581. }
  1582. static void print_help_item(MYSQL_ROW *cur, int num_name, int num_cat, char *last_char)
  1583. {
  1584.   char ccat= (*cur)[num_cat][0];
  1585.   if (*last_char != ccat)
  1586.   {
  1587.     put_info(ccat == 'Y' ? "categories:" : "topics:", INFO_INFO);
  1588.     *last_char= ccat;
  1589.   }
  1590.   tee_fprintf(PAGER, "   %sn", (*cur)[num_name]);
  1591. }
  1592. static int com_server_help(String *buffer __attribute__((unused)),
  1593.    char *line __attribute__((unused)), char *help_arg)
  1594. {
  1595.   MYSQL_ROW cur;
  1596.   const char *server_cmd= buffer->ptr();
  1597.   char cmd_buf[100];
  1598.   MYSQL_RES *result;
  1599.   int error;
  1600.   
  1601.   if (help_arg[0] != ''')
  1602.   {
  1603.     (void) strxnmov(cmd_buf, sizeof(cmd_buf), "help '", help_arg, "'", NullS);
  1604.     server_cmd= cmd_buf;
  1605.   }
  1606.   
  1607.   if (!status.batch)
  1608.   {
  1609.     old_buffer= *buffer;
  1610.     old_buffer.copy();
  1611.   }
  1612.   if (!connected && reconnect())
  1613.     return 1;
  1614.   if ((error= mysql_real_query_for_lazy(server_cmd,(int)strlen(server_cmd))) ||
  1615.       (error= mysql_store_result_for_lazy(&result)))
  1616.     return error;
  1617.   if (result)
  1618.   {
  1619.     unsigned int num_fields= mysql_num_fields(result);
  1620.     my_ulonglong num_rows= mysql_num_rows(result);
  1621.     mysql_fetch_fields(result);
  1622.     if (num_fields==3 && num_rows==1)
  1623.     {
  1624.       if (!(cur= mysql_fetch_row(result)))
  1625.       {
  1626. error= -1;
  1627. goto err;
  1628.       }
  1629.       init_pager();
  1630.       tee_fprintf(PAGER,   "Name: '%s'n", cur[0]);
  1631.       tee_fprintf(PAGER,   "Description:n%s", cur[1]);
  1632.       if (cur[2] && *((char*)cur[2]))
  1633. tee_fprintf(PAGER, "Examples:n%s", cur[2]);
  1634.       tee_fprintf(PAGER,   "n");
  1635.       end_pager();
  1636.     }
  1637.     else if (num_fields >= 2 && num_rows)
  1638.     {
  1639.       init_pager();
  1640.       char last_char= 0;
  1641.       int num_name= 0, num_cat= 0;
  1642.       LINT_INIT(num_name);
  1643.       LINT_INIT(num_cat);
  1644.       if (num_fields == 2)
  1645.       {
  1646. put_info("Many help items for your request exist.", INFO_INFO);
  1647. put_info("To make a more specific request, please type 'help <item>',nwhere <item> is one of the following", INFO_INFO);
  1648. num_name= 0;
  1649. num_cat= 1;
  1650.       }
  1651.       else if ((cur= mysql_fetch_row(result)))
  1652.       {
  1653. tee_fprintf(PAGER, "You asked for help about help category: "%s"n", cur[0]);
  1654. put_info("For more information, type 'help <item>', where <item> is one of the following", INFO_INFO);
  1655. num_name= 1;
  1656. num_cat= 2;
  1657. print_help_item(&cur,1,2,&last_char);
  1658.       }
  1659.       while ((cur= mysql_fetch_row(result)))
  1660. print_help_item(&cur,num_name,num_cat,&last_char);
  1661.       tee_fprintf(PAGER, "n");
  1662.       end_pager();
  1663.     }
  1664.     else
  1665.     {
  1666.       put_info("nNothing found", INFO_INFO);
  1667.       put_info("Please try to run 'help contents' for a list of all accessible topicsn", INFO_INFO);
  1668.     }
  1669.   }
  1670. err:
  1671.   mysql_free_result(result);
  1672.   return error;
  1673. }
  1674. static int
  1675. com_help(String *buffer __attribute__((unused)),
  1676.  char *line __attribute__((unused)))
  1677. {
  1678.   reg1 int i, j;
  1679.   char * help_arg= strchr(line,' '), buff[32], *end;
  1680.   if (help_arg)
  1681.     return com_server_help(buffer,line,help_arg+1);
  1682.   put_info("nFor information about MySQL products and services, visit:n"
  1683.            "   http://www.mysql.com/n"
  1684.            "For developer information, including the MySQL Reference Manual, "
  1685.            "visit:n"
  1686.            "   http://dev.mysql.com/n"
  1687.            "To buy MySQL Network Support, training, or other products, visit:n"
  1688.            "   https://shop.mysql.com/n", INFO_INFO);
  1689.   put_info("List of all MySQL commands:", INFO_INFO);
  1690.   if (!named_cmds)
  1691.     put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO);
  1692.   for (i = 0; commands[i].name; i++)
  1693.   {
  1694.     end= strmov(buff, commands[i].name);
  1695.     for (j= (int)strlen(commands[i].name); j < 10; j++)
  1696.       end= strmov(end, " ");
  1697.     if (commands[i].func)
  1698.       tee_fprintf(stdout, "%s(\%c) %sn", buff,
  1699.   commands[i].cmd_char, commands[i].doc);
  1700.   }
  1701.   if (connected && mysql_get_server_version(&mysql) >= 40100)
  1702.     put_info("nFor server side help, type 'help contents'n", INFO_INFO);
  1703.   return 0;
  1704. }
  1705. /* ARGSUSED */
  1706. static int
  1707. com_clear(String *buffer,char *line __attribute__((unused)))
  1708. {
  1709. #ifdef HAVE_READLINE
  1710.   if (status.add_to_history)
  1711.     fix_history(buffer);
  1712. #endif
  1713.   buffer->length(0);
  1714.   return 0;
  1715. }
  1716. /*
  1717.   Execute command
  1718.   Returns: 0  if ok
  1719.           -1 if not fatal error
  1720.   1  if fatal error
  1721. */
  1722. static int
  1723. com_go(String *buffer,char *line __attribute__((unused)))
  1724. {
  1725.   char buff[200], time_buff[32], *pos;
  1726.   MYSQL_RES *result;
  1727.   ulong timer, warnings;
  1728.   uint error= 0;
  1729.   int           err= 0;
  1730.   if (!status.batch)
  1731.   {
  1732.     old_buffer= *buffer; // Save for edit command
  1733.     old_buffer.copy();
  1734.   }
  1735.   /* Remove garbage for nicer messages */
  1736.   LINT_INIT(buff[0]);
  1737.   remove_cntrl(*buffer);
  1738.   if (buffer->is_empty())
  1739.   {
  1740.     if (status.batch) // Ignore empty quries
  1741.       return 0;
  1742.     return put_info("No query specifiedn",INFO_ERROR);
  1743.   }
  1744.   if (!connected && reconnect())
  1745.   {
  1746.     buffer->length(0); // Remove query on error
  1747.     return opt_reconnect ? -1 : 1;          // Fatal error
  1748.   }
  1749.   if (verbose)
  1750.     (void) com_print(buffer,0);
  1751.   if (skip_updates &&
  1752.       (buffer->length() < 4 || my_strnncoll(charset_info,
  1753.     (const uchar*)buffer->ptr(),4,
  1754.     (const uchar*)"SET ",4)))
  1755.   {
  1756.     (void) put_info("Ignoring query to other database",INFO_INFO);
  1757.     return 0;
  1758.   }
  1759.   timer=start_timer();
  1760.   error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length());
  1761. #ifdef HAVE_READLINE
  1762.   if (status.add_to_history) 
  1763.   {  
  1764.     buffer->append(vertical ? "\G" : delimiter);
  1765.     /* Append final command onto history */
  1766.     fix_history(buffer);
  1767.   }
  1768. #endif
  1769.   if (error)
  1770.   {
  1771.     buffer->length(0); // Remove query on error
  1772.     return error;
  1773.   }
  1774.   error=0;
  1775.   buffer->length(0);
  1776.   do
  1777.   {
  1778.     if (quick)
  1779.     {
  1780.       if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
  1781. return put_error(&mysql);
  1782.     }
  1783.     else
  1784.     {
  1785.       error= mysql_store_result_for_lazy(&result);
  1786.       if (error)
  1787. return error;
  1788.     }
  1789.     if (verbose >= 3 || !opt_silent)
  1790.       mysql_end_timer(timer,time_buff);
  1791.     else
  1792.       time_buff[0]=0;
  1793.     if (result)
  1794.     {
  1795.       if (!mysql_num_rows(result) && ! quick)
  1796.       {
  1797. strmov(buff, "Empty set");
  1798.       }
  1799.       else
  1800.       {
  1801. init_pager();
  1802. if (opt_html)
  1803.   print_table_data_html(result);
  1804. else if (opt_xml)
  1805.   print_table_data_xml(result);
  1806. else if (vertical)
  1807.   print_table_data_vertically(result);
  1808. else if (opt_silent && verbose <= 2 && !output_tables)
  1809.   print_tab_data(result);
  1810. else
  1811.   print_table_data(result);
  1812. sprintf(buff,"%ld %s in set",
  1813. (long) mysql_num_rows(result),
  1814. (long) mysql_num_rows(result) == 1 ? "row" : "rows");
  1815. end_pager();
  1816.       }
  1817.     }
  1818.     else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0)
  1819.       strmov(buff,"Query OK");
  1820.     else
  1821.       sprintf(buff,"Query OK, %ld %s affected",
  1822.       (long) mysql_affected_rows(&mysql),
  1823.       (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows");
  1824.     pos=strend(buff);
  1825.     if ((warnings= mysql_warning_count(&mysql)))
  1826.     {
  1827.       *pos++= ',';
  1828.       *pos++= ' ';
  1829.       pos=int10_to_str(warnings, pos, 10);
  1830.       pos=strmov(pos, " warning");
  1831.       if (warnings != 1)
  1832. *pos++= 's';
  1833.     }
  1834.     strmov(pos, time_buff);
  1835.     put_info(buff,INFO_RESULT);
  1836.     if (mysql_info(&mysql))
  1837.       put_info(mysql_info(&mysql),INFO_RESULT);
  1838.     put_info("",INFO_RESULT); // Empty row
  1839.     if (result && !mysql_eof(result)) /* Something wrong when using quick */
  1840.       error= put_error(&mysql);
  1841.     else if (unbuffered)
  1842.       fflush(stdout);
  1843.     mysql_free_result(result);
  1844.   } while (!(err= mysql_next_result(&mysql)));
  1845.   if (err >= 1)
  1846.     error= put_error(&mysql);
  1847.   if (!error && !status.batch && 
  1848.       (mysql.server_status & SERVER_STATUS_DB_DROPPED))
  1849.     get_current_db();
  1850.   return error; /* New command follows */
  1851. }
  1852. static void init_pager()
  1853. {
  1854. #ifdef USE_POPEN
  1855.   if (!opt_nopager)
  1856.   {
  1857.     if (!(PAGER= popen(pager, "w")))
  1858.     {
  1859.       tee_fprintf(stdout, "popen() failed! defaulting PAGER to stdout!n");
  1860.       PAGER= stdout;
  1861.     }
  1862.   }
  1863.   else
  1864. #endif
  1865.     PAGER= stdout;
  1866. }
  1867. static void end_pager()
  1868. {
  1869. #ifdef USE_POPEN
  1870.   if (!opt_nopager)
  1871.     pclose(PAGER);
  1872. #endif
  1873. }
  1874. static void init_tee(const char *file_name)
  1875. {
  1876.   FILE* new_outfile;
  1877.   if (opt_outfile)
  1878.     end_tee();
  1879.   if (!(new_outfile= my_fopen(file_name, O_APPEND | O_WRONLY, MYF(MY_WME))))
  1880.   {
  1881.     tee_fprintf(stdout, "Error logging to file '%s'n", file_name);
  1882.     return;
  1883.   }
  1884.   OUTFILE = new_outfile;
  1885.   strmake(outfile, file_name, FN_REFLEN-1);
  1886.   tee_fprintf(stdout, "Logging to file '%s'n", file_name);
  1887.   opt_outfile= 1;
  1888.   return;
  1889. }
  1890. static void end_tee()
  1891. {
  1892.   my_fclose(OUTFILE, MYF(0));
  1893.   OUTFILE= 0;
  1894.   opt_outfile= 0;
  1895.   return;
  1896. }
  1897. static int
  1898. com_ego(String *buffer,char *line)
  1899. {
  1900.   int result;
  1901.   bool oldvertical=vertical;
  1902.   vertical=1;
  1903.   result=com_go(buffer,line);
  1904.   vertical=oldvertical;
  1905.   return result;
  1906. }
  1907. static void
  1908. print_field_types(MYSQL_RES *result)
  1909. {
  1910.   MYSQL_FIELD *field;  
  1911.   while ((field = mysql_fetch_field(result)))
  1912.   {
  1913.     tee_fprintf(PAGER,"Catalog:    '%s'nDatabase:   '%s'nTable:      '%s'nName:       '%s'nType:       %dnLength:     %ldnMax length: %ldnIs_null:    %dnFlags:      %unDecimals:   %unn",
  1914. field->catalog, field->db, field->table, field->name,
  1915. (int) field->type,
  1916. field->length, field->max_length,
  1917. !IS_NOT_NULL(field->flags),
  1918. field->flags, field->decimals);
  1919.   }
  1920.   tee_puts("", PAGER);
  1921. }
  1922. static void
  1923. print_table_data(MYSQL_RES *result)
  1924. {
  1925.   String separator(256);
  1926.   MYSQL_ROW cur;
  1927.   MYSQL_FIELD *field;
  1928.   bool *num_flag;
  1929.   num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result));
  1930.   if (info_flag)
  1931.   {
  1932.     print_field_types(result);
  1933.     mysql_field_seek(result,0);
  1934.   }
  1935.   separator.copy("+",1,charset_info);
  1936.   while ((field = mysql_fetch_field(result)))
  1937.   {
  1938.     uint length= column_names ? field->name_length : 0;
  1939.     if (quick)
  1940.       length=max(length,field->length);
  1941.     else
  1942.       length=max(length,field->max_length);
  1943.     if (length < 4 && !IS_NOT_NULL(field->flags))
  1944.       length=4; // Room for "NULL"
  1945.     field->max_length=length+1;
  1946.     separator.fill(separator.length()+length+2,'-');
  1947.     separator.append('+');
  1948.   }
  1949.   separator.append('');                       // End marker for 
  1950.   tee_puts((char*) separator.ptr(), PAGER);
  1951.   if (column_names)
  1952.   {
  1953.     mysql_field_seek(result,0);
  1954.     (void) tee_fputs("|", PAGER);
  1955.     for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
  1956.     {
  1957.       tee_fprintf(PAGER, " %-*s|",(int) min(field->max_length,
  1958.                                             MAX_COLUMN_LENGTH),
  1959.   field->name);
  1960.       num_flag[off]= IS_NUM(field->type);
  1961.     }
  1962.     (void) tee_fputs("n", PAGER);
  1963.     tee_puts((char*) separator.ptr(), PAGER);
  1964.   }
  1965.   while ((cur= mysql_fetch_row(result)))
  1966.   {
  1967.     ulong *lengths= mysql_fetch_lengths(result);
  1968.     (void) tee_fputs("|", PAGER);
  1969.     mysql_field_seek(result, 0);
  1970.     for (uint off= 0; off < mysql_num_fields(result); off++)
  1971.     {
  1972.       const char *str= cur[off] ? cur[off] : "NULL";
  1973.       field= mysql_fetch_field(result);
  1974.       uint maxlength= field->max_length;
  1975.       if (maxlength > MAX_COLUMN_LENGTH)
  1976.       {
  1977. tee_fputs(str, PAGER);
  1978. tee_fputs(" |", PAGER);
  1979.       }
  1980.       else
  1981.       {
  1982.         uint currlength= (uint) lengths[off];
  1983.         uint numcells= charset_info->cset->numcells(charset_info, 
  1984.                                                     str, str + currlength);
  1985.         tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|",
  1986.                     maxlength + currlength - numcells, str);
  1987.       }
  1988.     }
  1989.     (void) tee_fputs("n", PAGER);
  1990.   }
  1991.   tee_puts((char*) separator.ptr(), PAGER);
  1992.   my_afree((gptr) num_flag);
  1993. }
  1994. static void
  1995. print_table_data_html(MYSQL_RES *result)
  1996. {
  1997.   MYSQL_ROW cur;
  1998.   MYSQL_FIELD *field;
  1999.   mysql_field_seek(result,0);
  2000.   (void) tee_fputs("<TABLE BORDER=1><TR>", PAGER);
  2001.   if (column_names)
  2002.   {
  2003.     while((field = mysql_fetch_field(result)))
  2004.     {
  2005.       tee_fprintf(PAGER, "<TH>%s</TH>", (field->name ? 
  2006.  (field->name[0] ? field->name : 
  2007.   " &nbsp; ") : "NULL"));
  2008.     }
  2009.     (void) tee_fputs("</TR>", PAGER);
  2010.   }
  2011.   while ((cur = mysql_fetch_row(result)))
  2012.   {
  2013.     ulong *lengths=mysql_fetch_lengths(result);
  2014.     (void) tee_fputs("<TR>", PAGER);
  2015.     for (uint i=0; i < mysql_num_fields(result); i++)
  2016.     {
  2017.       (void) tee_fputs("<TD>", PAGER);
  2018.       safe_put_field(cur[i],lengths[i]);
  2019.       (void) tee_fputs("</TD>", PAGER);
  2020.     }
  2021.     (void) tee_fputs("</TR>", PAGER);
  2022.   }
  2023.   (void) tee_fputs("</TABLE>", PAGER);
  2024. }
  2025. static void
  2026. print_table_data_xml(MYSQL_RES *result)
  2027. {
  2028.   MYSQL_ROW   cur;
  2029.   MYSQL_FIELD *fields;
  2030.   mysql_field_seek(result,0);
  2031.   tee_fputs("<?xml version="1.0"?>nn<resultset statement="", PAGER);
  2032.   xmlencode_print(glob_buffer.ptr(), (int)strlen(glob_buffer.ptr()));
  2033.   tee_fputs("">", PAGER);
  2034.   fields = mysql_fetch_fields(result);
  2035.   while ((cur = mysql_fetch_row(result)))
  2036.   {
  2037.     ulong *lengths=mysql_fetch_lengths(result);
  2038.     (void) tee_fputs("n  <row>n", PAGER);
  2039.     for (uint i=0; i < mysql_num_fields(result); i++)
  2040.     {
  2041.       tee_fprintf(PAGER, "t<%s>", (fields[i].name ?
  2042.   (fields[i].name[0] ? fields[i].name :
  2043.    " &nbsp; ") : "NULL"));
  2044.       xmlencode_print(cur[i], lengths[i]);
  2045.       tee_fprintf(PAGER, "</%s>n", (fields[i].name ?
  2046.      (fields[i].name[0] ? fields[i].name :
  2047.       " &nbsp; ") : "NULL"));
  2048.     }
  2049.     (void) tee_fputs("  </row>n", PAGER);
  2050.   }
  2051.   (void) tee_fputs("</resultset>n", PAGER);
  2052. }
  2053. static void
  2054. print_table_data_vertically(MYSQL_RES *result)
  2055. {
  2056.   MYSQL_ROW cur;
  2057.   uint max_length=0;
  2058.   MYSQL_FIELD *field;
  2059.   while ((field = mysql_fetch_field(result)))
  2060.   {
  2061.     uint length= field->name_length;
  2062.     if (length > max_length)
  2063.       max_length= length;
  2064.     field->max_length=length;
  2065.   }
  2066.   mysql_field_seek(result,0);
  2067.   for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++)
  2068.   {
  2069.     mysql_field_seek(result,0);
  2070.     tee_fprintf(PAGER, 
  2071. "*************************** %d. row ***************************n", row_count);
  2072.     for (uint off=0; off < mysql_num_fields(result); off++)
  2073.     {
  2074.       field= mysql_fetch_field(result);
  2075.       tee_fprintf(PAGER, "%*s: ",(int) max_length,field->name);
  2076.       tee_fprintf(PAGER, "%sn",cur[off] ? (char*) cur[off] : "NULL");
  2077.     }
  2078.   }
  2079. }
  2080. static const char
  2081. *array_value(const char **array, char key)
  2082. {
  2083.   int x;
  2084.   for (x= 0; array[x]; x+= 2)
  2085.     if (*array[x] == key)
  2086.       return array[x + 1];
  2087.   return 0;
  2088. }
  2089. static void
  2090. xmlencode_print(const char *src, uint length)
  2091. {
  2092.   if (!src)
  2093.     tee_fputs("NULL", PAGER);
  2094.   else
  2095.   {
  2096.     for (const char *p = src; *p && length; *p++, length--)
  2097.     {
  2098.       const char *t;
  2099.       if ((t = array_value(xmlmeta, *p)))
  2100. tee_fputs(t, PAGER);
  2101.       else
  2102. tee_putc(*p, PAGER);
  2103.     }
  2104.   }
  2105. }
  2106. static void
  2107. safe_put_field(const char *pos,ulong length)
  2108. {
  2109.   if (!pos)
  2110.     tee_fputs("NULL", PAGER);
  2111.   else
  2112.   {
  2113.     if (opt_raw_data)
  2114.       tee_fputs(pos, PAGER);
  2115.     else for (const char *end=pos+length ; pos != end ; pos++)
  2116.     {
  2117. #ifdef USE_MB
  2118.       int l;
  2119.       if (use_mb(charset_info) &&
  2120.           (l = my_ismbchar(charset_info, pos, end)))
  2121.       {
  2122.   while (l--)
  2123.     tee_putc(*pos++, PAGER);
  2124.   pos--;
  2125.   continue;
  2126.       }
  2127. #endif
  2128.       if (!*pos)
  2129. tee_fputs("\0", PAGER); // This makes everything hard
  2130.       else if (*pos == 't')
  2131. tee_fputs("\t", PAGER); // This would destroy tab format
  2132.       else if (*pos == 'n')
  2133. tee_fputs("\n", PAGER); // This too
  2134.       else if (*pos == '\')
  2135. tee_fputs("\\", PAGER);
  2136. else
  2137. tee_putc(*pos, PAGER);
  2138.     }
  2139.   }
  2140. }
  2141. static void
  2142. print_tab_data(MYSQL_RES *result)
  2143. {
  2144.   MYSQL_ROW cur;
  2145.   MYSQL_FIELD *field;
  2146.   ulong *lengths;
  2147.   if (opt_silent < 2 && column_names)
  2148.   {
  2149.     int first=0;
  2150.     while ((field = mysql_fetch_field(result)))
  2151.     {
  2152.       if (first++)
  2153. (void) tee_fputs("t", PAGER);
  2154.       (void) tee_fputs(field->name, PAGER);
  2155.     }
  2156.     (void) tee_fputs("n", PAGER);
  2157.   }
  2158.   while ((cur = mysql_fetch_row(result)))
  2159.   {
  2160.     lengths=mysql_fetch_lengths(result);
  2161.     safe_put_field(cur[0],lengths[0]);
  2162.     for (uint off=1 ; off < mysql_num_fields(result); off++)
  2163.     {
  2164.       (void) tee_fputs("t", PAGER);
  2165.       safe_put_field(cur[off], lengths[off]);
  2166.     }
  2167.     (void) tee_fputs("n", PAGER);
  2168.   }
  2169. }
  2170. static int
  2171. com_tee(String *buffer, char *line __attribute__((unused)))
  2172. {
  2173.   char file_name[FN_REFLEN], *end, *param;
  2174.   if (status.batch)
  2175.     return 0;
  2176.   while (my_isspace(charset_info,*line))
  2177.     line++;
  2178.   if (!(param = strchr(line, ' '))) // if outfile wasn't given, use the default
  2179.   {
  2180.     if (!strlen(outfile))
  2181.     {
  2182.       printf("No previous outfile available, you must give a filename!n");
  2183.       return 0;
  2184.     }
  2185.     else if (opt_outfile)
  2186.     {
  2187.       tee_fprintf(stdout, "Currently logging to file '%s'n", outfile);
  2188.       return 0;
  2189.     }
  2190.     else
  2191.       param = outfile; //resume using the old outfile
  2192.   }
  2193.   /* eliminate the spaces before the parameters */
  2194.   while (my_isspace(charset_info,*param))
  2195.     param++;
  2196.   end= strmake(file_name, param, sizeof(file_name) - 1);
  2197.   /* remove end space from command line */
  2198.   while (end > file_name && (my_isspace(charset_info,end[-1]) || 
  2199.      my_iscntrl(charset_info,end[-1])))
  2200.     end--;
  2201.   end[0]= 0;
  2202.   if (end == file_name)
  2203.   {
  2204.     printf("No outfile specified!n");
  2205.     return 0;
  2206.   }
  2207.   init_tee(file_name);
  2208.   return 0;
  2209. }
  2210. static int
  2211. com_notee(String *buffer __attribute__((unused)),
  2212.   char *line __attribute__((unused)))
  2213. {
  2214.   if (opt_outfile)
  2215.     end_tee();
  2216.   tee_fprintf(stdout, "Outfile disabled.n");
  2217.   return 0;
  2218. }
  2219. /*
  2220.   Sorry, this command is not available in Windows.
  2221. */
  2222. #ifdef USE_POPEN
  2223. static int
  2224. com_pager(String *buffer, char *line __attribute__((unused)))
  2225. {
  2226.   char pager_name[FN_REFLEN], *end, *param;
  2227.   if (status.batch)
  2228.     return 0;
  2229.   /* Skip spaces in front of the pager command */
  2230.   while (my_isspace(charset_info, *line))
  2231.     line++;
  2232.   /* Skip the pager command */
  2233.   param= strchr(line, ' ');
  2234.   /* Skip the spaces between the command and the argument */
  2235.   while (param && my_isspace(charset_info, *param))
  2236.     param++;
  2237.   if (!param || !strlen(param)) // if pager was not given, use the default
  2238.   {
  2239.     if (!default_pager_set)
  2240.     {
  2241.       tee_fprintf(stdout, "Default pager wasn't set, using stdout.n");
  2242.       opt_nopager=1;
  2243.       strmov(pager, "stdout");
  2244.       PAGER= stdout;
  2245.       return 0;
  2246.     }
  2247.     strmov(pager, default_pager);
  2248.   }
  2249.   else
  2250.   {
  2251.     end= strmake(pager_name, param, sizeof(pager_name)-1);
  2252.     while (end > pager_name && (my_isspace(charset_info,end[-1]) || 
  2253.                                 my_iscntrl(charset_info,end[-1])))
  2254.       end--;
  2255.     end[0]=0;
  2256.     strmov(pager, pager_name);
  2257.     strmov(default_pager, pager_name);
  2258.   }
  2259.   opt_nopager=0;
  2260.   tee_fprintf(stdout, "PAGER set to '%s'n", pager);
  2261.   return 0;
  2262. }
  2263. static int
  2264. com_nopager(String *buffer __attribute__((unused)),
  2265.     char *line __attribute__((unused)))
  2266. {
  2267.   strmov(pager, "stdout");
  2268.   opt_nopager=1;
  2269.   PAGER= stdout;
  2270.   tee_fprintf(stdout, "PAGER set to stdoutn");
  2271.   return 0;
  2272. }
  2273. #endif
  2274. /*
  2275.   Sorry, you can't send the result to an editor in Win32
  2276. */
  2277. #ifdef USE_POPEN
  2278. static int
  2279. com_edit(String *buffer,char *line __attribute__((unused)))
  2280. {
  2281.   char filename[FN_REFLEN],buff[160];
  2282.   int fd,tmp;
  2283.   const char *editor;
  2284.   if ((fd=create_temp_file(filename,NullS,"sql", O_CREAT | O_WRONLY,
  2285.    MYF(MY_WME))) < 0)
  2286.     goto err;
  2287.   if (buffer->is_empty() && !old_buffer.is_empty())
  2288.     (void) my_write(fd,(byte*) old_buffer.ptr(),old_buffer.length(),
  2289.     MYF(MY_WME));
  2290.   else
  2291.     (void) my_write(fd,(byte*) buffer->ptr(),buffer->length(),MYF(MY_WME));
  2292.   (void) my_close(fd,MYF(0));
  2293.   if (!(editor = (char *)getenv("EDITOR")) &&
  2294.       !(editor = (char *)getenv("VISUAL")))
  2295.     editor = "vi";
  2296.   strxmov(buff,editor," ",filename,NullS);
  2297.   (void) system(buff);
  2298.   MY_STAT stat_arg;
  2299.   if (!my_stat(filename,&stat_arg,MYF(MY_WME)))
  2300.     goto err;
  2301.   if ((fd = my_open(filename,O_RDONLY, MYF(MY_WME))) < 0)
  2302.     goto err;
  2303.   (void) buffer->alloc((uint) stat_arg.st_size);
  2304.   if ((tmp=read(fd,(char*) buffer->ptr(),buffer->alloced_length())) >= 0L)
  2305.     buffer->length((uint) tmp);
  2306.   else
  2307.     buffer->length(0);
  2308.   (void) my_close(fd,MYF(0));
  2309.   (void) my_delete(filename,MYF(MY_WME));
  2310. err:
  2311.   return 0;
  2312. }
  2313. #endif
  2314. /* If arg is given, exit without errors. This happens on command 'quit' */
  2315. static int
  2316. com_quit(String *buffer __attribute__((unused)),
  2317.  char *line __attribute__((unused)))
  2318. {
  2319.   /* let the screen auto close on a normal shutdown */
  2320.   NETWARE_SET_SCREEN_MODE(SCR_AUTOCLOSE_ON_EXIT);
  2321.   status.exit_status=0;
  2322.   return 1;
  2323. }
  2324. static int
  2325. com_rehash(String *buffer __attribute__((unused)),
  2326.  char *line __attribute__((unused)))
  2327. {
  2328. #ifdef HAVE_READLINE
  2329.   build_completion_hash(1, 0);
  2330. #endif
  2331.   return 0;
  2332. }
  2333. #ifdef USE_POPEN
  2334. static int
  2335. com_shell(String *buffer, char *line __attribute__((unused)))
  2336. {
  2337.   char *shell_cmd;
  2338.   /* Skip space from line begin */
  2339.   while (my_isspace(charset_info, *line))
  2340.     line++;
  2341.   if (!(shell_cmd = strchr(line, ' ')))
  2342.   {
  2343.     put_info("Usage: \! shell-command", INFO_ERROR);
  2344.     return -1;
  2345.   }
  2346.   /*
  2347.     The output of the shell command does not
  2348.     get directed to the pager or the outfile
  2349.   */
  2350.   if (system(shell_cmd) == -1)
  2351.   {
  2352.     put_info(strerror(errno), INFO_ERROR, errno);
  2353.     return -1;
  2354.   }
  2355.   return 0;
  2356. }
  2357. #endif
  2358. static int
  2359. com_print(String *buffer,char *line __attribute__((unused)))
  2360. {
  2361.   tee_puts("--------------", stdout);
  2362.   (void) tee_fputs(buffer->c_ptr(), stdout);
  2363.   if (!buffer->length() || (*buffer)[buffer->length()-1] != 'n')
  2364.     tee_putc('n', stdout);
  2365.   tee_puts("--------------n", stdout);
  2366.   return 0; /* If empty buffer */
  2367. }
  2368. /* ARGSUSED */
  2369. static int
  2370. com_connect(String *buffer, char *line)
  2371. {
  2372.   char *tmp, buff[256];
  2373.   bool save_rehash= rehash;
  2374.   int error;
  2375.   bzero(buff, sizeof(buff));
  2376.   if (buffer)
  2377.   {
  2378.     strmov(buff, line);
  2379.     tmp= get_arg(buff, 0);
  2380.     if (tmp && *tmp)
  2381.     {
  2382.       my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
  2383.       current_db= my_strdup(tmp, MYF(MY_WME));
  2384.       tmp= get_arg(buff, 1);
  2385.       if (tmp)
  2386.       {
  2387. my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
  2388. current_host=my_strdup(tmp,MYF(MY_WME));
  2389.       }
  2390.     }
  2391.     else
  2392.       rehash= 0; // Quick re-connect
  2393.     buffer->length(0); // command used
  2394.   }
  2395.   else
  2396.     rehash= 0;
  2397.   error=sql_connect(current_host,current_db,current_user,opt_password,0);
  2398.   rehash= save_rehash;
  2399.   if (connected)
  2400.   {
  2401.     sprintf(buff,"Connection id:    %lu",mysql_thread_id(&mysql));
  2402.     put_info(buff,INFO_INFO);
  2403.     sprintf(buff,"Current database: %.128sn",
  2404.     current_db ? current_db : "*** NONE ***");
  2405.     put_info(buff,INFO_INFO);
  2406.   }
  2407.   return error;
  2408. }
  2409. static int com_source(String *buffer, char *line)
  2410. {
  2411.   char source_name[FN_REFLEN], *end, *param;
  2412.   LINE_BUFFER *line_buff;
  2413.   int error;
  2414.   STATUS old_status;
  2415.   FILE *sql_file;
  2416.   /* Skip space from file name */
  2417.   while (my_isspace(charset_info,*line))
  2418.     line++;
  2419.   if (!(param = strchr(line, ' '))) // Skip command name
  2420.     return put_info("Usage: \. <filename> | source <filename>", 
  2421.     INFO_ERROR, 0);
  2422.   while (my_isspace(charset_info,*param))
  2423.     param++;
  2424.   end=strmake(source_name,param,sizeof(source_name)-1);
  2425.   while (end > source_name && (my_isspace(charset_info,end[-1]) || 
  2426.                                my_iscntrl(charset_info,end[-1])))
  2427.     end--;
  2428.   end[0]=0;
  2429.   unpack_filename(source_name,source_name);
  2430.   /* open file name */
  2431.   if (!(sql_file = my_fopen(source_name, O_RDONLY | O_BINARY,MYF(0))))
  2432.   {
  2433.     char buff[FN_REFLEN+60];
  2434.     sprintf(buff,"Failed to open file '%s', error: %d", source_name,errno);
  2435.     return put_info(buff, INFO_ERROR, 0);
  2436.   }
  2437.   if (!(line_buff=batch_readline_init(opt_max_allowed_packet+512,sql_file)))
  2438.   {
  2439.     my_fclose(sql_file,MYF(0));
  2440.     return put_info("Can't initialize batch_readline", INFO_ERROR, 0);
  2441.   }
  2442.   /* Save old status */
  2443.   old_status=status;
  2444.   bfill((char*) &status,sizeof(status),(char) 0);
  2445.   status.batch=old_status.batch; // Run in batch mode
  2446.   status.line_buff=line_buff;
  2447.   status.file_name=source_name;
  2448.   glob_buffer.length(0); // Empty command buffer
  2449.   error=read_lines(0); // Read lines from file
  2450.   status=old_status; // Continue as before
  2451.   my_fclose(sql_file,MYF(0));
  2452.   batch_readline_end(line_buff);
  2453.   return error;
  2454. }
  2455. /* ARGSUSED */
  2456. static int
  2457. com_delimiter(String *buffer __attribute__((unused)), char *line)
  2458. {
  2459.   char buff[256], *tmp;
  2460.   strmake(buff, line, sizeof(buff) - 1);
  2461.   tmp= get_arg(buff, 0);
  2462.   if (!tmp || !*tmp)
  2463.   {
  2464.     put_info("DELIMITER must be followed by a 'delimiter' character or string",
  2465.      INFO_ERROR);
  2466.     return 0;
  2467.   }
  2468.   strmake(delimiter, tmp, sizeof(delimiter) - 1);
  2469.   delimiter_length= (int)strlen(delimiter);
  2470.   delimiter_str= delimiter;
  2471.   return 0;
  2472. }
  2473. /* ARGSUSED */
  2474. static int
  2475. com_use(String *buffer __attribute__((unused)), char *line)
  2476. {
  2477.   char *tmp, buff[FN_REFLEN + 1];
  2478.   bzero(buff, sizeof(buff));
  2479.   strmov(buff, line);
  2480.   tmp= get_arg(buff, 0);
  2481.   if (!tmp || !*tmp)
  2482.   {
  2483.     put_info("USE must be followed by a database name", INFO_ERROR);
  2484.     return 0;
  2485.   }
  2486.   /*
  2487.     We need to recheck the current database, because it may change
  2488.     under our feet, for example if DROP DATABASE or RENAME DATABASE
  2489.     (latter one not yet available by the time the comment was written)
  2490.   */
  2491.   get_current_db();
  2492.   if (!current_db || cmp_database(charset_info, current_db,tmp))
  2493.   {
  2494.     if (one_database)
  2495.       skip_updates= 1;
  2496.     else
  2497.     {
  2498.       /*
  2499. reconnect once if connection is down or if connection was found to
  2500. be down during query
  2501.       */
  2502.       if (!connected && reconnect())
  2503.       return opt_reconnect ? -1 : 1;                        // Fatal error
  2504.       if (mysql_select_db(&mysql,tmp))
  2505.       {
  2506. if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR)
  2507.   return put_error(&mysql);
  2508. if (reconnect())
  2509.         return opt_reconnect ? -1 : 1;                      // Fatal error
  2510. if (mysql_select_db(&mysql,tmp))
  2511.   return put_error(&mysql);
  2512.       }
  2513.       my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
  2514.       current_db=my_strdup(tmp,MYF(MY_WME));
  2515. #ifdef HAVE_READLINE
  2516.       build_completion_hash(rehash, 1);
  2517. #endif
  2518.     }
  2519.   }
  2520.   else
  2521.     skip_updates= 0;
  2522.   put_info("Database changed",INFO_INFO);
  2523.   return 0;
  2524. }
  2525. /*
  2526.   Gets argument from a command on the command line. If get_next_arg is
  2527.   not defined, skips the command and returns the first argument. The
  2528.   line is modified by adding zero to the end of the argument. If
  2529.   get_next_arg is defined, then the function searches for end of string
  2530.   first, after found, returns the next argument and adds zero to the
  2531.   end. If you ever wish to use this feature, remember to initialize all
  2532.   items in the array to zero first.
  2533. */
  2534. char *get_arg(char *line, my_bool get_next_arg)
  2535. {
  2536.   char *ptr, *start;
  2537.   my_bool quoted= 0, valid_arg= 0;
  2538.   char qtype= 0;
  2539.   ptr= line;
  2540.   if (get_next_arg)
  2541.   {
  2542.     for (; *ptr; ptr++) ;
  2543.     if (*(ptr + 1))
  2544.       ptr++;
  2545.   }
  2546.   else
  2547.   {
  2548.     /* skip leading white spaces */
  2549.     while (my_isspace(charset_info, *ptr))
  2550.       ptr++;
  2551.     if (*ptr == '\') // short command was used
  2552.       ptr+= 2;
  2553.     else
  2554.       while (*ptr &&!my_isspace(charset_info, *ptr)) // skip command
  2555.         ptr++;
  2556.   }
  2557.   if (!*ptr)
  2558.     return NullS;
  2559.   while (my_isspace(charset_info, *ptr))
  2560.     ptr++;
  2561.   if (*ptr == ''' || *ptr == '"' || *ptr == '`')
  2562.   {
  2563.     qtype= *ptr;
  2564.     quoted= 1;
  2565.     ptr++;
  2566.   }
  2567.   for (start=ptr ; *ptr; ptr++)
  2568.   {
  2569.     if (*ptr == '\' && ptr[1]) // escaped character
  2570.     {
  2571.       // Remove the backslash
  2572.       strmov(ptr, ptr+1);
  2573.     }
  2574.     else if ((!quoted && *ptr == ' ') || (quoted && *ptr == qtype))
  2575.     {
  2576.       *ptr= 0;
  2577.       break;
  2578.     }
  2579.   }
  2580.   valid_arg= ptr != start;
  2581.   return valid_arg ? start : NullS;
  2582. }
  2583. static int
  2584. sql_real_connect(char *host,char *database,char *user,char *password,
  2585.  uint silent)
  2586. {
  2587.   if (connected)
  2588.   {
  2589.     connected= 0;
  2590.     mysql_close(&mysql);
  2591.   }
  2592.   mysql_init(&mysql);
  2593.   if (opt_connect_timeout)
  2594.   {
  2595.     uint timeout=opt_connect_timeout;
  2596.     mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT,
  2597.   (char*) &timeout);
  2598.   }
  2599.   if (opt_compress)
  2600.     mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
  2601.   if (opt_secure_auth)
  2602.     mysql_options(&mysql, MYSQL_SECURE_AUTH, (char *) &opt_secure_auth);
  2603.   if (using_opt_local_infile)
  2604.     mysql_options(&mysql,MYSQL_OPT_LOCAL_INFILE, (char*) &opt_local_infile);
  2605. #ifdef HAVE_OPENSSL
  2606.   if (opt_use_ssl)
  2607.     mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
  2608.   opt_ssl_capath, opt_ssl_cipher);
  2609. #endif
  2610.   if (opt_protocol)
  2611.     mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
  2612. #ifdef HAVE_SMEM
  2613.   if (shared_memory_base_name)
  2614.     mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
  2615. #endif
  2616.   if (safe_updates)
  2617.   {
  2618.     char init_command[100];
  2619.     sprintf(init_command,
  2620.     "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,SQL_MAX_JOIN_SIZE=%lu",
  2621.     select_limit,max_join_size);
  2622.     mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command);
  2623.   }
  2624.   if (default_charset_used)
  2625.     mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
  2626.   if (!mysql_real_connect(&mysql, host, user, password,
  2627.   database, opt_mysql_port, opt_mysql_unix_port,
  2628.   connect_flag | CLIENT_MULTI_STATEMENTS))
  2629.   {
  2630.     if (!silent ||
  2631. (mysql_errno(&mysql) != CR_CONN_HOST_ERROR &&
  2632.  mysql_errno(&mysql) != CR_CONNECTION_ERROR))
  2633.     {
  2634.       (void) put_error(&mysql);
  2635.       (void) fflush(stdout);
  2636.       return ignore_errors ? -1 : 1; // Abort
  2637.     }
  2638.     return -1; // Retryable
  2639.   }
  2640.   connected=1;
  2641. #ifndef EMBEDDED_LIBRARY
  2642.   mysql.reconnect=info_flag ? 1 : 0; // We want to know if this happens
  2643. #endif
  2644. #ifdef HAVE_READLINE
  2645.   build_completion_hash(rehash, 1);
  2646. #endif
  2647.   return 0;
  2648. }
  2649. static int
  2650. sql_connect(char *host,char *database,char *user,char *password,uint silent)
  2651. {
  2652.   bool message=0;
  2653.   uint count=0;
  2654.   int error;
  2655.   for (;;)
  2656.   {
  2657.     if ((error=sql_real_connect(host,database,user,password,wait_flag)) >= 0)
  2658.     {
  2659.       if (count)
  2660.       {
  2661. tee_fputs("n", stderr);
  2662. (void) fflush(stderr);
  2663.       }
  2664.       return error;
  2665.     }
  2666.     if (!wait_flag)
  2667.       return ignore_errors ? -1 : 1;
  2668.     if (!message && !silent)
  2669.     {
  2670.       message=1;
  2671.       tee_fputs("Waiting",stderr); (void) fflush(stderr);
  2672.     }
  2673.     (void) sleep(wait_time);
  2674.     if (!silent)
  2675.     {
  2676.       putc('.',stderr); (void) fflush(stderr);
  2677.       count++;
  2678.     }
  2679.   }
  2680. }
  2681. static int
  2682. com_status(String *buffer __attribute__((unused)),
  2683.    char *line __attribute__((unused)))
  2684. {
  2685.   const char *status;
  2686.   char buff[22];
  2687.   ulonglong id;
  2688.   MYSQL_RES *result;
  2689.   LINT_INIT(result);
  2690.   tee_puts("--------------", stdout);
  2691.   usage(1); /* Print version */
  2692.   if (connected)
  2693.   {
  2694.     tee_fprintf(stdout, "nConnection id:tt%lun",mysql_thread_id(&mysql));
  2695.     /* 
  2696.       Don't remove "limit 1", 
  2697.       it is protection againts SQL_SELECT_LIMIT=0
  2698.     */
  2699.     if (!mysql_query(&mysql,"select DATABASE(), USER() limit 1") &&
  2700. (result=mysql_use_result(&mysql)))
  2701.     {
  2702.       MYSQL_ROW cur=mysql_fetch_row(result);
  2703.       if (cur)
  2704.       {
  2705.         tee_fprintf(stdout, "Current database:t%sn", cur[0] ? cur[0] : "");
  2706.         tee_fprintf(stdout, "Current user:tt%sn", cur[1]);
  2707.       }
  2708.       mysql_free_result(result);
  2709.     } 
  2710. #ifdef HAVE_OPENSSL
  2711.     if (mysql.net.vio && mysql.net.vio->ssl_arg &&
  2712. SSL_get_cipher((SSL*) mysql.net.vio->ssl_arg))
  2713.       tee_fprintf(stdout, "SSL:tttCipher in use is %sn",
  2714.   SSL_get_cipher((SSL*) mysql.net.vio->ssl_arg));
  2715.     else
  2716. #endif /* HAVE_OPENSSL */
  2717.       tee_puts("SSL:tttNot in use", stdout);
  2718.   }
  2719.   else
  2720.   {
  2721.     vidattr(A_BOLD);
  2722.     tee_fprintf(stdout, "nNo connectionn");
  2723.     vidattr(A_NORMAL);
  2724.     return 0;
  2725.   }
  2726.   if (skip_updates)
  2727.   {
  2728.     vidattr(A_BOLD);
  2729.     tee_fprintf(stdout, "nAll updates ignored to this databasen");
  2730.     vidattr(A_NORMAL);
  2731.   }
  2732. #ifdef USE_POPEN
  2733.   tee_fprintf(stdout, "Current pager:tt%sn", pager);
  2734.   tee_fprintf(stdout, "Using outfile:tt'%s'n", opt_outfile ? outfile : "");
  2735. #endif
  2736.   tee_fprintf(stdout, "Using delimiter:t%sn", delimiter);
  2737.   tee_fprintf(stdout, "Server version:tt%sn", mysql_get_server_info(&mysql));
  2738.   tee_fprintf(stdout, "Protocol version:t%dn", mysql_get_proto_info(&mysql));
  2739.   tee_fprintf(stdout, "Connection:tt%sn", mysql_get_host_info(&mysql));
  2740.   if ((id= mysql_insert_id(&mysql)))
  2741.     tee_fprintf(stdout, "Insert id:tt%sn", llstr(id, buff));
  2742.   /* 
  2743.     Don't remove "limit 1", 
  2744.     it is protection againts SQL_SELECT_LIMIT=0
  2745.   */
  2746.   if (!mysql_query(&mysql,"select @@character_set_client, @@character_set_connection, @@character_set_server, @@character_set_database limit 1") &&
  2747.       (result=mysql_use_result(&mysql)))
  2748.   {
  2749.     MYSQL_ROW cur=mysql_fetch_row(result);
  2750.     if (cur)
  2751.     {
  2752.       tee_fprintf(stdout, "Server characterset:t%sn", cur[2] ? cur[2] : "");
  2753.       tee_fprintf(stdout, "Db     characterset:t%sn", cur[3] ? cur[3] : "");
  2754.       tee_fprintf(stdout, "Client characterset:t%sn", cur[0] ? cur[0] : "");
  2755.       tee_fprintf(stdout, "Conn.  characterset:t%sn", cur[1] ? cur[1] : "");
  2756.     }
  2757.     mysql_free_result(result);
  2758.   }
  2759.   else
  2760.   {
  2761.     /* Probably pre-4.1 server */
  2762.     tee_fprintf(stdout, "Client characterset:t%sn", charset_info->csname);
  2763.     tee_fprintf(stdout, "Server characterset:t%sn", mysql.charset->csname);
  2764.   }
  2765. #ifndef EMBEDDED_LIBRARY
  2766.   if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! mysql.unix_socket)
  2767.     tee_fprintf(stdout, "TCP port:tt%dn", mysql.port);
  2768.   else
  2769.     tee_fprintf(stdout, "UNIX socket:tt%sn", mysql.unix_socket);
  2770.   if (mysql.net.compress)
  2771.     tee_fprintf(stdout, "Protocol:ttCompressedn");
  2772. #endif
  2773.   if ((status=mysql_stat(&mysql)) && !mysql_error(&mysql)[0])
  2774.   {
  2775.     ulong sec;
  2776.     char buff[40];
  2777.     const char *pos= strchr(status,' ');
  2778.     /* print label */
  2779.     tee_fprintf(stdout, "%.*sttt", (int) (pos-status), status);
  2780.     if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec)))
  2781.     {
  2782.       nice_time((double) sec,buff,0);
  2783.       tee_puts(buff, stdout); /* print nice time */
  2784.       while (*status == ' ') status++; /* to next info */
  2785.     }
  2786.     if (status)
  2787.     {
  2788.       tee_putc('n', stdout);
  2789.       tee_puts(status, stdout);
  2790.     }
  2791.   }
  2792.   if (safe_updates)
  2793.   {
  2794.     vidattr(A_BOLD);
  2795.     tee_fprintf(stdout, "nNote that you are running in safe_update_mode:n");
  2796.     vidattr(A_NORMAL);
  2797.     tee_fprintf(stdout, "
  2798. UPDATEs and DELETEs that don't use a key in the WHERE clause are not allowed.n
  2799. (One can force an UPDATE/DELETE by adding LIMIT # at the end of the command.)n
  2800. SELECT has an automatic 'LIMIT %lu' if LIMIT is not used.n
  2801. Max number of examined row combination in a join is set to: %lunn",
  2802. select_limit, max_join_size);
  2803.   }
  2804.   tee_puts("--------------n", stdout);
  2805.   return 0;
  2806. }
  2807. static int
  2808. put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate)
  2809. {
  2810.   FILE *file= (info_type == INFO_ERROR ? stderr : stdout);
  2811.   static int inited=0;
  2812.   if (status.batch)
  2813.   {
  2814.     if (info_type == INFO_ERROR)
  2815.     {
  2816.       (void) fflush(file);
  2817.       fprintf(file,"ERROR");
  2818.       if (error)
  2819.       {
  2820. if (sqlstate)
  2821.   (void) fprintf(file," %d (%s)",error, sqlstate);
  2822.         else
  2823.   (void) fprintf(file," %d",error);
  2824.       }
  2825.       if (status.query_start_line && line_numbers)
  2826.       {
  2827. (void) fprintf(file," at line %lu",status.query_start_line);
  2828. if (status.file_name)
  2829.   (void) fprintf(file," in file: '%s'", status.file_name);
  2830.       }
  2831.       (void) fprintf(file,": %sn",str);
  2832.       (void) fflush(file);
  2833.       if (!ignore_errors)
  2834. return 1;
  2835.     }
  2836.     else if (info_type == INFO_RESULT && verbose > 1)
  2837.       tee_puts(str, file);
  2838.     if (unbuffered)
  2839.       fflush(file);
  2840.     return info_type == INFO_ERROR ? -1 : 0;
  2841.   }
  2842.   if (!opt_silent || info_type == INFO_ERROR)
  2843.   {
  2844.     if (!inited)
  2845.     {
  2846.       inited=1;
  2847. #ifdef HAVE_SETUPTERM
  2848.       (void) setupterm((char *)0, 1, (int *) 0);
  2849. #endif
  2850.     }
  2851.     if (info_type == INFO_ERROR)
  2852.     {
  2853.       if (!opt_nobeep)
  2854. putchar('07');        /* This should make a bell */
  2855.       vidattr(A_STANDOUT);
  2856.       if (error)
  2857.       {
  2858. if (sqlstate)
  2859.           (void) tee_fprintf(file, "ERROR %d (%s): ", error, sqlstate);
  2860.         else
  2861.           (void) tee_fprintf(file, "ERROR %d: ", error);
  2862.       }
  2863.       else
  2864.         tee_puts("ERROR: ", file);
  2865.     }
  2866.     else
  2867.       vidattr(A_BOLD);
  2868.     (void) tee_puts(str, file);
  2869.     vidattr(A_NORMAL);
  2870.   }
  2871.   if (unbuffered)
  2872.     fflush(file);
  2873.   return info_type == INFO_ERROR ? -1 : 0;
  2874. }
  2875. static int
  2876. put_error(MYSQL *mysql)
  2877. {
  2878.   return put_info(mysql_error(mysql), INFO_ERROR, mysql_errno(mysql),
  2879.   mysql_sqlstate(mysql));
  2880. }  
  2881. static void remove_cntrl(String &buffer)
  2882. {
  2883.   char *start,*end;
  2884.   end=(start=(char*) buffer.ptr())+buffer.length();
  2885.   while (start < end && !my_isgraph(charset_info,end[-1]))
  2886.     end--;
  2887.   buffer.length((uint) (end-start));
  2888. }
  2889. void tee_fprintf(FILE *file, const char *fmt, ...)
  2890. {
  2891.   va_list args;
  2892.   NETWARE_YIELD;
  2893.   va_start(args, fmt);
  2894.   (void) vfprintf(file, fmt, args);
  2895. #ifdef OS2
  2896.   fflush( file);
  2897. #endif
  2898.   va_end(args);
  2899.   if (opt_outfile)
  2900.   {
  2901.     va_start(args, fmt);
  2902.     (void) vfprintf(OUTFILE, fmt, args);
  2903.     va_end(args);
  2904.   }
  2905. }
  2906. void tee_fputs(const char *s, FILE *file)
  2907. {
  2908.   NETWARE_YIELD;
  2909.   fputs(s, file);
  2910. #ifdef OS2
  2911.   fflush( file);
  2912. #endif
  2913.   if (opt_outfile)
  2914.     fputs(s, OUTFILE);
  2915. }
  2916. void tee_puts(const char *s, FILE *file)
  2917. {
  2918.   NETWARE_YIELD;
  2919.   fputs(s, file);
  2920.   fputs("n", file);
  2921. #ifdef OS2
  2922.   fflush( file);
  2923. #endif
  2924.   if (opt_outfile)
  2925.   {
  2926.     fputs(s, OUTFILE);
  2927.     fputs("n", OUTFILE);
  2928.   }
  2929. }
  2930. void tee_putc(int c, FILE *file)
  2931. {
  2932.   putc(c, file);
  2933. #ifdef OS2
  2934.   fflush( file);
  2935. #endif
  2936.   if (opt_outfile)
  2937.     putc(c, OUTFILE);
  2938. }
  2939. #if defined( __WIN__) || defined( OS2) || defined(__NETWARE__)
  2940. #include <time.h>
  2941. #else
  2942. #include <sys/times.h>
  2943. #ifdef _SC_CLK_TCK // For mit-pthreads
  2944. #undef CLOCKS_PER_SEC
  2945. #define CLOCKS_PER_SEC (sysconf(_SC_CLK_TCK))
  2946. #endif
  2947. #endif
  2948. static ulong start_timer(void)
  2949. {
  2950. #if defined( __WIN__) || defined( OS2) || defined(__NETWARE__)
  2951.  return clock();
  2952. #else
  2953.   struct tms tms_tmp;
  2954.   return times(&tms_tmp);
  2955. #endif
  2956. }
  2957. static void nice_time(double sec,char *buff,bool part_second)
  2958. {
  2959.   ulong tmp;
  2960.   if (sec >= 3600.0*24)
  2961.   {
  2962.     tmp=(ulong) floor(sec/(3600.0*24));
  2963.     sec-=3600.0*24*tmp;
  2964.     buff=int10_to_str((long) tmp, buff, 10);
  2965.     buff=strmov(buff,tmp > 1 ? " days " : " day ");
  2966.   }
  2967.   if (sec >= 3600.0)
  2968.   {
  2969.     tmp=(ulong) floor(sec/3600.0);
  2970.     sec-=3600.0*tmp;
  2971.     buff=int10_to_str((long) tmp, buff, 10);
  2972.     buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
  2973.   }
  2974.   if (sec >= 60.0)
  2975.   {
  2976.     tmp=(ulong) floor(sec/60.0);
  2977.     sec-=60.0*tmp;
  2978.     buff=int10_to_str((long) tmp, buff, 10);
  2979.     buff=strmov(buff," min ");
  2980.   }
  2981.   if (part_second)
  2982.     sprintf(buff,"%.2f sec",sec);
  2983.   else
  2984.     sprintf(buff,"%d sec",(int) sec);
  2985. }
  2986. static void end_timer(ulong start_time,char *buff)
  2987. {
  2988.   nice_time((double) (start_timer() - start_time) /
  2989.     CLOCKS_PER_SEC,buff,1);
  2990. }
  2991. static void mysql_end_timer(ulong start_time,char *buff)
  2992. {
  2993.   buff[0]=' ';
  2994.   buff[1]='(';
  2995.   end_timer(start_time,buff+2);
  2996.   strmov(strend(buff),")");
  2997. }
  2998. static const char* construct_prompt()
  2999. {
  3000.   processed_prompt.free(); // Erase the old prompt
  3001.   time_t  lclock = time(NULL); // Get the date struct
  3002.   struct tm *t = localtime(&lclock);
  3003.   /* parse thru the settings for the prompt */
  3004.   for (char *c = current_prompt; *c ; *c++)
  3005.   {
  3006.     if (*c != PROMPT_CHAR)
  3007. processed_prompt.append(*c);
  3008.     else
  3009.     {
  3010.       switch (*++c) {
  3011.       case '':
  3012. c--; // stop it from going beyond if ends with %
  3013. break;
  3014.       case 'c':
  3015. add_int_to_prompt(++prompt_counter);
  3016. break;
  3017.       case 'v':
  3018. if (connected)
  3019.   processed_prompt.append(mysql_get_server_info(&mysql));
  3020. else
  3021.   processed_prompt.append("not_connected");
  3022. break;
  3023.       case 'd':
  3024. processed_prompt.append(current_db ? current_db : "(none)");
  3025. break;
  3026.       case 'h':
  3027.       {
  3028. const char *prompt;
  3029. prompt= connected ? mysql_get_host_info(&mysql) : "not_connected";
  3030. if (strstr(prompt, "Localhost"))
  3031.   processed_prompt.append("localhost");
  3032. else
  3033. {
  3034.   const char *end=strcend(prompt,' ');
  3035.   processed_prompt.append(prompt, (uint) (end-prompt));
  3036. }
  3037. break;
  3038.       }
  3039.       case 'p':
  3040.       {
  3041. #ifndef EMBEDDED_LIBRARY
  3042. if (!connected)
  3043. {
  3044.   processed_prompt.append("not_connected");
  3045.   break;
  3046. }
  3047. const char *host_info = mysql_get_host_info(&mysql);
  3048. if (strstr(host_info, "memory")) 
  3049. {
  3050. processed_prompt.append( mysql.host );
  3051. }
  3052. else if (strstr(host_info,"TCP/IP") ||
  3053.     !mysql.unix_socket)
  3054.   add_int_to_prompt(mysql.port);
  3055. else
  3056. {
  3057.   char *pos=strrchr(mysql.unix_socket,'/');
  3058.     processed_prompt.append(pos ? pos+1 : mysql.unix_socket);
  3059. }
  3060. #endif
  3061.       }
  3062. break;
  3063.       case 'U':
  3064. if (!full_username)
  3065.   init_username();
  3066. processed_prompt.append(full_username);
  3067. break;
  3068.       case 'u':
  3069. if (!full_username)
  3070.   init_username();
  3071. processed_prompt.append(part_username);
  3072. break;
  3073.       case PROMPT_CHAR:
  3074. processed_prompt.append(PROMPT_CHAR);
  3075. break;
  3076.       case 'n':
  3077. processed_prompt.append('n');
  3078. break;
  3079.       case ' ':
  3080.       case '_':
  3081. processed_prompt.append(' ');
  3082. break;
  3083.       case 'R':
  3084. if (t->tm_hour < 10)
  3085.   processed_prompt.append('0');
  3086. add_int_to_prompt(t->tm_hour);
  3087. break;
  3088.       case 'r':
  3089. int getHour;
  3090. getHour = t->tm_hour % 12;
  3091. if (getHour == 0)
  3092.   getHour=12;
  3093. if (getHour < 10)
  3094.   processed_prompt.append('0');
  3095. add_int_to_prompt(getHour);
  3096. break;
  3097.       case 'm':
  3098. if (t->tm_min < 10)
  3099.   processed_prompt.append('0');
  3100. add_int_to_prompt(t->tm_min);
  3101. break;
  3102.       case 'y':
  3103. int getYear;
  3104. getYear = t->tm_year % 100;
  3105. if (getYear < 10)
  3106.   processed_prompt.append('0');
  3107. add_int_to_prompt(getYear);
  3108. break;
  3109.       case 'Y':
  3110. add_int_to_prompt(t->tm_year+1900);
  3111. break;
  3112.       case 'D':
  3113. char* dateTime;
  3114. time_t lclock;
  3115. lclock = time(NULL);
  3116. dateTime = ctime(&lclock);
  3117. processed_prompt.append(strtok(dateTime,"n"));
  3118. break;
  3119.       case 's':
  3120. if (t->tm_sec < 10)
  3121.   processed_prompt.append('0');
  3122. add_int_to_prompt(t->tm_sec);
  3123. break;
  3124.       case 'w':
  3125. processed_prompt.append(day_names[t->tm_wday]);
  3126. break;
  3127.       case 'P':
  3128. processed_prompt.append(t->tm_hour < 12 ? "am" : "pm");
  3129. break;
  3130.       case 'o':
  3131. add_int_to_prompt(t->tm_mon+1);
  3132. break;
  3133.       case 'O':
  3134. processed_prompt.append(month_names[t->tm_mon]);
  3135. break;
  3136.       case ''':
  3137. processed_prompt.append("'");
  3138. break;
  3139.       case '"':
  3140. processed_prompt.append('"');
  3141. break;
  3142.       case 'S':
  3143. processed_prompt.append(';');
  3144. break;
  3145.       case 't':
  3146. processed_prompt.append('t');
  3147. break;
  3148.       default:
  3149. processed_prompt.append(c);
  3150.       }
  3151.     }
  3152.   }
  3153.   processed_prompt.append('');
  3154.   return processed_prompt.ptr();
  3155. }
  3156. static void add_int_to_prompt(int toadd)
  3157. {
  3158.   char buffer[16];
  3159.   int10_to_str(toadd,buffer,10);
  3160.   processed_prompt.append(buffer);
  3161. }
  3162. static void init_username()
  3163. {
  3164.   my_free(full_username,MYF(MY_ALLOW_ZERO_PTR));
  3165.   my_free(part_username,MYF(MY_ALLOW_ZERO_PTR));
  3166.   MYSQL_RES *result;
  3167.   LINT_INIT(result);
  3168.   if (!mysql_query(&mysql,"select USER()") &&
  3169.       (result=mysql_use_result(&mysql)))
  3170.   {
  3171.     MYSQL_ROW cur=mysql_fetch_row(result);
  3172.     full_username=my_strdup(cur[0],MYF(MY_WME));
  3173.     part_username=my_strdup(strtok(cur[0],"@"),MYF(MY_WME));
  3174.     (void) mysql_fetch_row(result); // Read eof
  3175.   }
  3176. }
  3177. static int com_prompt(String *buffer, char *line)
  3178. {
  3179.   char *ptr=strchr(line, ' ');
  3180.   prompt_counter = 0;
  3181.   my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR));
  3182.   current_prompt=my_strdup(ptr ? ptr+1 : default_prompt,MYF(MY_WME));
  3183.   if (!ptr)
  3184.     tee_fprintf(stdout, "Returning to default PROMPT of %sn", default_prompt);
  3185.   else
  3186.     tee_fprintf(stdout, "PROMPT set to '%s'n", current_prompt);
  3187.   return 0;
  3188. }
  3189. #ifndef EMBEDDED_LIBRARY
  3190. /* Keep sql_string library happy */
  3191. gptr sql_alloc(unsigned int Size)
  3192. {
  3193.   return my_malloc(Size,MYF(MY_WME));
  3194. }
  3195. void sql_element_free(void *ptr)
  3196. {
  3197.   my_free((gptr) ptr,MYF(0));
  3198. }
  3199. #endif /* EMBEDDED_LIBRARY */