mysql.cc
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:63k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16. /* mysql command tool
  17.  * Commands compatible with mSQL by David J. Hughes
  18.  *
  19.  * Written by:
  20.  *   Michael 'Monty' Widenius
  21.  *   Andi Gutmans  <andi@zend.com>
  22.  *   Zeev Suraski <zeev@zend.com>
  23.  *   Jani Tolonen <jani@mysql.com>
  24.  *
  25.  **/
  26. #include <global.h>
  27. #include <my_sys.h> 
  28. #include <m_string.h>
  29. #include <m_ctype.h>
  30. #include "mysql.h"
  31. #include "errmsg.h"
  32. #include <my_dir.h>
  33. #ifndef __GNU_LIBRARY__
  34. #define __GNU_LIBRARY__       // Skip warnings in getopt.h
  35. #endif
  36. #include <getopt.h>
  37. #include "my_readline.h"
  38. #include <signal.h>
  39. const char *VER="11.13";
  40. /* Don't try to make a nice table if the data is too big */
  41. #define MAX_COLUMN_LENGTH      1024
  42. gptr sql_alloc(unsigned size);      // Don't use mysqld alloc for these
  43. void sql_element_free(void *ptr);
  44. #include "sql_string.h"
  45. extern "C" {
  46. #if defined(HAVE_CURSES_H) && defined(HAVE_TERM_H)
  47. #include <curses.h>
  48. #include <term.h>
  49. #else
  50. #if defined(HAVE_TERMIOS_H)
  51. #include <termios.h>
  52. #include <unistd.h>
  53. #elif defined(HAVE_TERMBITS_H)
  54. #include <termbits.h>
  55. #elif defined(HAVE_ASM_TERMBITS_H) && (!defined __GLIBC__ || !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ > 0))
  56. #include <asm/termbits.h> // Standard linux
  57. #endif
  58. #undef VOID
  59. #if defined(HAVE_TERMCAP_H)
  60. #include <termcap.h>
  61. #else
  62. #ifdef HAVE_CURSES_H
  63. #include <curses.h>
  64. #endif
  65. #undef SYSV // hack to avoid syntax error
  66. #ifdef HAVE_TERM_H
  67. #include <term.h>
  68. #endif
  69. #endif
  70. #endif
  71. #undef bcmp // Fix problem with new readline
  72. #undef bzero
  73. #ifdef __WIN__
  74. #include <conio.h>
  75. #else
  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 __WIN__
  86. #define cmp_database(A,B) my_strcasecmp((A),(B))
  87. #else
  88. #define cmp_database(A,B) strcmp((A),(B))
  89. #endif
  90. #include "completion_hash.h"
  91. typedef struct st_status
  92. {
  93.   int exit_status;
  94.   ulong query_start_line;
  95.   char *file_name;
  96.   LINE_BUFFER *line_buff;
  97.   bool batch,add_to_history;
  98. } STATUS;
  99. static HashTable ht;
  100. enum enum_info_type { INFO_INFO,INFO_ERROR,INFO_RESULT};
  101. typedef enum enum_info_type INFO_TYPE;
  102. static MYSQL mysql; /* The connection */
  103. static bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0,
  104.     connected=0,opt_raw_data=0,unbuffered=0,output_tables=0,
  105.     no_rehash=0,skip_updates=0,safe_updates=0,one_database=0,
  106.     opt_compress=0,
  107.     vertical=0,skip_line_numbers=0,skip_column_names=0,opt_html=0,
  108.     opt_nopager=1, opt_outfile=0, no_named_cmds=1;
  109. static uint verbose=0,opt_silent=0,opt_mysql_port=0;
  110. static my_string opt_mysql_unix_port=0;
  111. static int connect_flag=CLIENT_INTERACTIVE;
  112. static char *current_host,*current_db,*current_user=0,*opt_password=0,
  113.             *default_charset;
  114. static char *histfile;
  115. static String glob_buffer,old_buffer;
  116. static int wait_time = 5;
  117. static STATUS status;
  118. static ulong select_limit,max_join_size,opt_connect_timeout=0;
  119. static char default_pager[FN_REFLEN];
  120. char pager[FN_REFLEN], outfile[FN_REFLEN];
  121. FILE *PAGER, *OUTFILE;
  122. #include "sslopt-vars.h"
  123. #ifndef DBUG_OFF
  124. const char *default_dbug_option="d:t:o,/tmp/mysql.trace";
  125. #endif
  126. void tee_fprintf(FILE *file, const char *fmt, ...);
  127. void tee_fputs(const char *s, FILE *file);
  128. void tee_puts(const char *s, FILE *file);
  129. void tee_putc(int c, FILE *file);
  130. /* The names of functions that actually do the manipulation. */
  131. static int get_options(int argc,char **argv);
  132. static int com_quit(String *str,char*),
  133.    com_go(String *str,char*), com_ego(String *str,char*),
  134.    com_print(String *str,char*),
  135.    com_help(String *str,char*), com_clear(String *str,char*),
  136.    com_connect(String *str,char*), com_status(String *str,char*),
  137.    com_use(String *str,char*), com_source(String *str, char*),
  138.    com_rehash(String *str, char*), com_tee(String *str, char*),
  139.            com_notee(String *str, char*);
  140. #ifndef __WIN__
  141. static int com_nopager(String *str, char*), com_pager(String *str, char*),
  142.    com_edit(String *str,char*);
  143. #endif
  144. static int read_lines(bool execute_commands);
  145. static int sql_connect(char *host,char *database,char *user,char *password,
  146.        uint silent);
  147. static int put_info(const char *str,INFO_TYPE info,uint error=0);
  148. static void safe_put_field(const char *pos,ulong length);
  149. static void init_pager();
  150. static void end_pager();
  151. static void init_tee();
  152. static void end_tee();
  153. /* A structure which contains information on the commands this program
  154.    can understand. */
  155. typedef struct {
  156.   const char *name; /* User printable name of the function. */
  157.   char cmd_char; /* msql command character */
  158.   int (*func)(String *str,char *); /* Function to call to do the job. */
  159.   bool takes_params; /* Max parameters for command */
  160.   const char *doc; /* Documentation for this function.  */
  161. } COMMANDS;
  162. static COMMANDS commands[] = {
  163.   { "help",   'h', com_help,   0, "Display this help." },
  164.   { "?",      '?', com_help,   0, "Synonym for `help'." },
  165.   { "clear",  'c', com_clear,  0, "Clear command."},
  166.   { "connect",'r', com_connect,1,
  167.     "Reconnect to the server. Optional arguments are db and host." },
  168. #ifndef __WIN__
  169.   { "edit",   'e', com_edit,   0, "Edit command with $EDITOR."},
  170. #endif
  171.   { "ego",    'G', com_ego,    0,
  172.     "Send command to mysql server, display result vertically."},
  173.   { "exit",   'q', com_quit,   0, "Exit mysql. Same as quit."},
  174.   { "go",     'g', com_go,     0, "Send command to mysql server." },
  175. #ifndef __WIN__
  176.   { "nopager",'n', com_nopager,0, "Disable pager, print to stdout." },
  177. #endif
  178.   { "notee",  't', com_notee,  0, "Don't write into outfile." },
  179. #ifndef __WIN__
  180.   { "pager",  'P', com_pager,  1, 
  181.     "Set PAGER [to_pager]. Print the query results via PAGER." },
  182. #endif
  183.   { "print",  'p', com_print,  0, "Print current command." },
  184.   { "quit",   'q', com_quit,   0, "Quit mysql." },
  185.   { "rehash", '#', com_rehash, 0, "Rebuild completion hash." },
  186.   { "source", '.', com_source, 1,
  187.     "Execute a SQL script file. Takes a file name as an argument."},
  188.   { "status", 's', com_status, 0, "Get status information from the server."},
  189.   { "tee",    'T', com_tee,    1, 
  190.     "Set outfile [to_outfile]. Append everything into given outfile." },
  191.   { "use",    'u', com_use,    1,
  192.     "Use another database. Takes database name as argument." },
  193.   /* Get bash-like expansion for some commands */
  194.   { "create table",     0, 0, 0, ""},
  195.   { "create database",  0, 0, 0, ""},
  196.   { "drop",             0, 0, 0, ""},
  197.   { "select",           0, 0, 0, ""},
  198.   { "insert",           0, 0, 0, ""},
  199.   { "replace",          0, 0, 0, ""},
  200.   { "update",           0, 0, 0, ""},
  201.   { "delete",           0, 0, 0, ""},
  202.   { "explain",          0, 0, 0, ""},
  203.   { "show databases",   0, 0, 0, ""},
  204.   { "show fields from", 0, 0, 0, ""},
  205.   { "show keys from",   0, 0, 0, ""},
  206.   { "show tables",      0, 0, 0, ""},
  207.   { "load data from",   0, 0, 0, ""},
  208.   { "alter table",      0, 0, 0, ""},
  209.   { "set option",       0, 0, 0, ""},
  210.   { "lock tables",      0, 0, 0, ""},
  211.   { "unlock tables",    0, 0, 0, ""},
  212.   { (char *)NULL,       0, 0, 0, ""}
  213. };
  214. static const char *load_default_groups[]= { "mysql","client",0 };
  215. #ifdef HAVE_READLINE
  216. extern "C" void add_history(char *command); /* From readline directory */
  217. extern "C" int read_history(char *command);
  218. extern "C" int write_history(char *command);
  219. static void initialize_readline (char *name);
  220. #endif
  221. static COMMANDS *find_command (char *name,char cmd_name);
  222. static bool add_line(String &buffer,char *line,char *in_string);
  223. static void remove_cntrl(String &buffer);
  224. static void print_table_data(MYSQL_RES *result);
  225. static void print_table_data_html(MYSQL_RES *result);
  226. static void print_tab_data(MYSQL_RES *result);
  227. static void print_table_data_vertically(MYSQL_RES *result);
  228. static ulong start_timer(void);
  229. static void end_timer(ulong start_time,char *buff);
  230. static void mysql_end_timer(ulong start_time,char *buff);
  231. static void nice_time(double sec,char *buff,bool part_second);
  232. static sig_handler mysql_end(int sig);
  233. int main(int argc,char *argv[])
  234. {
  235.   char buff[80];
  236.   MY_INIT(argv[0]);
  237.   DBUG_ENTER("main");
  238.   DBUG_PROCESS(argv[0]);
  239.   strmov(outfile, "");   // no (default) outfile, unless given at least once
  240.   strmov(pager, "stdout"); // the default, if --pager wasn't given
  241.   if (!isatty(0) || !isatty(1))
  242.   {
  243.     status.batch=1; opt_silent=1;
  244.     ignore_errors=0;
  245.   }
  246.   else
  247.     status.add_to_history=1;
  248.   status.exit_status=1;
  249.   load_defaults("my",load_default_groups,&argc,&argv);
  250.   if (get_options(argc,(char **) argv))
  251.   {
  252.     my_end(0);
  253.     exit(1);
  254.   }
  255.   free_defaults(argv);
  256.   if (status.batch && !status.line_buff &&
  257.       !(status.line_buff=batch_readline_init(max_allowed_packet+512,stdin)))
  258.     exit(1);
  259.   glob_buffer.realloc(512);
  260.   completion_hash_init(&ht,50);
  261.   if (sql_connect(current_host,current_db,current_user,opt_password,
  262.   opt_silent))
  263.   {
  264.     quick=1; // Avoid history
  265.     status.exit_status=1;
  266.     mysql_end(-1);
  267.   }
  268.   if (!status.batch)
  269.     ignore_errors=1; // Don't abort monitor
  270.   signal(SIGINT, mysql_end); // Catch SIGINT to clean up
  271.   /*
  272.   **  Run in interactive mode like the ingres/postgres monitor
  273.   */
  274.   put_info("Welcome to the MySQL monitor.  Commands end with ; or \g.",
  275.    INFO_INFO);
  276.   sprintf((char*) glob_buffer.ptr(),
  277.   "Your MySQL connection id is %ld to server version: %sn",
  278.   mysql_thread_id(&mysql),mysql_get_server_info(&mysql));
  279.   put_info((char*) glob_buffer.ptr(),INFO_INFO);
  280. #ifdef HAVE_READLINE
  281.   initialize_readline(my_progname);
  282.   if (!status.batch && !quick && !opt_html)
  283.   {
  284.     /*read-history from file, default ~/.mysql_history*/
  285.     if (getenv("MYSQL_HISTFILE"))
  286.       histfile=my_strdup(getenv("MYSQL_HISTFILE"),MYF(MY_WME));
  287.     else if (getenv("HOME"))
  288.     {
  289.       histfile=(char*) my_malloc((uint) strlen(getenv("HOME"))
  290.  + (uint) strlen("/.mysql_history")+2,
  291.  MYF(MY_WME));
  292.       if (histfile)
  293. sprintf(histfile,"%s/.mysql_history",getenv("HOME"));
  294.     }
  295.     if (histfile)
  296.     {
  297.       if (verbose)
  298. tee_fprintf(stdout, "Reading history-file %sn",histfile);
  299.       read_history(histfile);
  300.     }
  301.   }
  302. #endif
  303.   sprintf(buff, 
  304.   "Type 'help;' or '\h' for help. Type '\c' to clear the buffern");
  305.   put_info(buff,INFO_INFO);
  306.   status.exit_status=read_lines(1); // read lines and execute them
  307.   if (opt_outfile)
  308.     end_tee();
  309.   mysql_end(0);
  310. #ifndef _lint
  311.   DBUG_RETURN(0); // Keep compiler happy
  312. #endif
  313. }
  314. sig_handler mysql_end(int sig)
  315. {
  316.   if (connected)
  317.     mysql_close(&mysql);
  318. #ifdef HAVE_READLINE
  319.   if (!status.batch && !quick && ! opt_html)
  320.   {
  321.     /* write-history */
  322.     if (verbose)
  323.       tee_fprintf(stdout, "Writing history-file %sn",histfile);
  324.     write_history(histfile);
  325.   }
  326.   batch_readline_end(status.line_buff);
  327.   completion_hash_free(&ht);
  328. #endif
  329.   if (sig >= 0)
  330.     put_info(sig ? "Aborted" : "Bye", INFO_RESULT);
  331.   glob_buffer.free();
  332.   old_buffer.free();
  333.   my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
  334.   my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
  335.   my_free(histfile,MYF(MY_ALLOW_ZERO_PTR));
  336.   my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
  337.   my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
  338.   my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
  339.   my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
  340.   exit(status.exit_status);
  341. }
  342. enum options {OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET,
  343.       OPT_PAGER, OPT_NOPAGER, OPT_TEE, OPT_NOTEE} ;
  344. static struct option long_options[] =
  345. {
  346.   {"i-am-a-dummy",  optional_argument,    0, 'U'},
  347.   {"batch",     no_argument,    0, 'B'},
  348.   {"character-sets-dir",required_argument, 0, OPT_CHARSETS_DIR},
  349.   {"compress",     no_argument,    0, 'C'},
  350. #ifndef DBUG_OFF
  351.   {"debug",     optional_argument,    0, '#'},
  352. #endif
  353.   {"database",     required_argument,     0, 'D'},
  354.   {"debug-info",    no_argument,    0, 'T'},
  355.   {"default-character-set", required_argument,0, OPT_DEFAULT_CHARSET},
  356.   {"enable-named-commands", no_argument,   0, 'G'},
  357.   {"execute",     required_argument,    0, 'e'},
  358.   {"force",     no_argument,    0, 'f'},
  359.   {"help",     no_argument,    0, '?'},
  360.   {"html",     no_argument,    0, 'H'},
  361.   {"host",     required_argument,    0, 'h'},
  362.   {"ignore-spaces", no_argument,    0, 'i'},
  363.   {"no-auto-rehash",no_argument,    0, 'A'},
  364.   {"no-named-commands", no_argument,       0, 'g'},
  365.   {"no-tee",        no_argument,           0, OPT_NOTEE},
  366. #ifndef __WIN__
  367.   {"no-pager",      no_argument,           0, OPT_NOPAGER},
  368.   {"nopager",       no_argument,           0, OPT_NOPAGER},  /* we are kind */
  369.   {"pager",         optional_argument,     0, OPT_PAGER},
  370. #endif
  371.   {"notee",         no_argument,           0, OPT_NOTEE},    /* we are kind */
  372.   {"tee",           required_argument,     0, OPT_TEE},
  373.   {"one-database",  no_argument,    0, 'o'},
  374.   {"password",     optional_argument,    0, 'p'},
  375. #ifdef __WIN__
  376.   {"pipe",     no_argument,    0, 'W'},
  377. #endif
  378.   {"port",     required_argument,    0, 'P'},
  379.   {"quick",     no_argument,    0, 'q'},
  380.   {"set-variable",  required_argument,    0, 'O'},
  381.   {"raw",     no_argument,    0, 'r'},
  382.   {"safe-updates",  optional_argument,    0, 'U'},
  383.   {"silent",     no_argument,    0, 's'},
  384.   {"skip-column-names",no_argument,    0, 'N'},
  385.   {"skip-line-numbers",no_argument,    0, 'L'},
  386.   {"socket",     required_argument,    0, 'S'},
  387. #include "sslopt-longopts.h"
  388.   {"table",     no_argument,    0, 't'},
  389. #ifndef DONT_ALLOW_USER_CHANGE
  390.   {"user",     required_argument,    0, 'u'},
  391. #endif
  392.   {"unbuffered",    no_argument,    0, 'n'},
  393.   {"verbose",     no_argument,    0, 'v'},
  394.   {"version",     no_argument,    0, 'V'},
  395.   {"vertical",     no_argument,    0, 'E'},
  396.   {"wait",     optional_argument,    0, 'w'},
  397.   {0, 0, 0, 0}
  398. };
  399. CHANGEABLE_VAR changeable_vars[] = {
  400.   { "connect_timeout", (long*) &opt_connect_timeout, 0, 0, 3600*12, 0, 1},
  401.   { "max_allowed_packet", (long*) &max_allowed_packet,16*1024L*1024L,4096,
  402.     24*1024L*1024L, MALLOC_OVERHEAD,1024},
  403.   { "net_buffer_length",(long*) &net_buffer_length,16384,1024,24*1024*1024L,
  404.     MALLOC_OVERHEAD,1024},
  405.   { "select_limit", (long*) &select_limit, 1000L, 1, ~0L, 0, 1},
  406.   { "max_join_size", (long*) &max_join_size, 1000000L, 1, ~0L, 0, 1},
  407.   { 0, 0, 0, 0, 0, 0, 0}
  408. };
  409. static void usage(int version)
  410. {
  411.   printf("%s  Ver %s Distrib %s, for %s (%s)n",
  412.  my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
  413.   if (version)
  414.     return;
  415.   puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
  416.   puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,nand you are welcome to modify and redistribute it under the GPL licensen");
  417.   printf("Usage: %s [OPTIONS] [database]n", my_progname);
  418.   printf("n
  419.   -?, --help Display this help and exit.n
  420.   -A, --no-auto-rehash  No automatic rehashing. One has to use 'rehash' ton
  421. get table and field completion. This gives a quickern
  422. start of mysql and disables rehashing on reconnect.n
  423.   -B, --batch Print results with a tab as separator, each row onn
  424. a new line. Doesn't use history file.n
  425.   --character-sets-dir=...n
  426.                         Directory where character sets are located.n
  427.   -C, --compress Use compression in server/client protocol.n");
  428. #ifndef DBUG_OFF
  429.   printf("
  430.   -#, --debug[=...]     Debug log. Default is '%s'.n",default_dbug_option);
  431. #endif
  432.   printf("
  433.   -D, --database=.. Database to use.n
  434.   --default-character-set=...n
  435.                         Set the default character set.n
  436.   -e, --execute=...     Execute command and quit. (Output like with --batch)n
  437.   -E, --vertical        Print the output of a query (rows) vertically.n
  438.   -f, --force           Continue even if we get an sql error.n
  439.   -g, --no-named-commandsn
  440. Named commands are disabled. Use \* form only, orn
  441.                         use named commands only in the beginning of a linen
  442.                         ending with a semicolon (;) Since version 10.9 then
  443.                         client now starts with this option ENABLED byn
  444.                         default! Disable with '-G'. Long format commandsn
  445.                         still work from the first line.n
  446.   -G, --enable-named-commandsn
  447.                         Named commands are enabled. Opposite to -g.n
  448.   -i, --ignore-space Ignore space after function names.n
  449.   -h, --host=... Connect to host.n
  450.   -H, --html Produce HTML output.n
  451.   -L, --skip-line-numbersn
  452.                         Don't write line number for errors.n");
  453. #ifndef __WIN__
  454.   printf("
  455.   --no-pager            Disable pager and print to stdout. See interactiven
  456.                         help (\h) also.n");
  457. #endif
  458.   printf("
  459.   --no-tee              Disable outfile. See interactive help (\h) also.n
  460.   -n, --unbuffered Flush buffer after each query.n
  461.   -N, --skip-column-namesn
  462.                         Don't write column names in results.n
  463.   -O, --set-variable var=optionn
  464. Give a variable an value. --help lists variables.n
  465.   -o, --one-database Only update the default database. This is usefuln
  466. for skipping updates to other database in the updaten
  467. log.n");
  468. #ifndef __WIN__
  469.   printf("
  470.   --pager[=...]         Pager to use to display results. If you don't supplyn
  471.                         an option the default pager is taken from your ENVn
  472.                         variable PAGER (%s).n
  473.                         Valid pagers are less, more, cat [> filename], etc.n
  474.                         See interactive help (\h) also. This option doesn
  475.                         not work in batch mode.n", getenv("PAGER") ? getenv("PAGER") : "");
  476. #endif
  477.   printf("
  478.   -p[password], --password[=...]n
  479. Password to use when connecting to servern
  480. If password is not given it's asked from the tty.n");
  481. #ifdef __WIN__
  482.   puts("  -W, --pipe Use named pipes to connect to server");
  483. #endif
  484.   printf("n
  485.   -P, --port=... Port number to use for connection.n
  486.   -q, --quick Don't cache result, print it row by row. This mayn
  487. slow down the server if the output is suspended.n
  488. Doesn't use history file.n
  489.   -r, --raw Write fields without conversion. Used with --batchn
  490.   -s, --silent Be more silent.n
  491.   -S  --socket=... Socket file to use for connection.n");
  492. #include "sslopt-usage.h"
  493.   printf("
  494.   -t, --table Output in table format.n
  495.   -T, --debug-info Print some debug info at exit.n
  496.   --tee=...             Append everything into outfile. See interactive helpn
  497.                         (\h) also. Does not work in batch mode.n");
  498. #ifndef DONT_ALLOW_USER_CHANGE
  499.   printf("
  500.   -u, --user=# User for login if not current user.n");
  501. #endif
  502.   printf("
  503.   -U, --safe-updates[=#], --i-am-a-dummy[=#]n
  504.         Only allow UPDATE and DELETE that uses keys.n
  505.   -v, --verbose Write more. (-v -v -v gives the table output format)n
  506.   -V, --version Output version information and exit.n
  507.   -w, --wait Wait and retry if connection is down.n");
  508.   print_defaults("my",load_default_groups);
  509.   printf("nPossible variables for option --set-variable (-O) are:n");
  510.   for (uint i=0 ; changeable_vars[i].name ; i++)
  511.     printf("%-20s  current value: %lun",
  512.    changeable_vars[i].name,
  513.    (ulong) *changeable_vars[i].varptr);
  514. }
  515. static int get_options(int argc, char **argv)
  516. {
  517.   int c,option_index=0;
  518.   bool tty_password=0;
  519.   set_all_changeable_vars(changeable_vars);
  520.   while ((c=getopt_long(argc,argv,
  521. "?ABCD:LfgGHinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::",
  522. long_options, &option_index)) != EOF)
  523.   {
  524.     switch(c) {
  525.     case OPT_DEFAULT_CHARSET:
  526.       default_charset= optarg;
  527.       break;
  528.     case OPT_CHARSETS_DIR:
  529.       charsets_dir= optarg;
  530.       break;
  531.     case OPT_TEE:
  532.       if (!opt_outfile && strlen(optarg))
  533.       {
  534. strmov(outfile, optarg);
  535. opt_outfile=1;
  536. init_tee();
  537.       }
  538.       break;
  539.     case OPT_NOTEE:
  540.       if (opt_outfile)
  541. end_tee();
  542.       opt_outfile=0;
  543.       break;
  544.     case OPT_PAGER:
  545.       opt_nopager=0;
  546.       if (optarg)
  547. strmov(pager, optarg);
  548.       else
  549. strmov(pager, (char*) getenv("PAGER"));
  550.       strmov(default_pager, pager);
  551.       break;
  552.     case OPT_NOPAGER:
  553.       opt_nopager=1;
  554.       break;
  555.     case 'D':
  556.       my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));      
  557.       current_db=my_strdup(optarg,MYF(MY_WME));
  558.       break;
  559.     case 'e':
  560.       status.batch=1;
  561.       status.add_to_history=0;
  562.       batch_readline_end(status.line_buff); // If multiple -e
  563.       if (!(status.line_buff=batch_readline_command(optarg)))
  564. return 1;
  565.       ignore_errors=0;
  566.       break;
  567.     case 'f':
  568.       ignore_errors=1;
  569.       break;
  570.     case 'h':
  571.       my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
  572.       current_host=my_strdup(optarg,MYF(MY_WME));
  573.       break;
  574. #ifndef DONT_ALLOW_USER_CHANGE
  575.     case 'u':
  576.       my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
  577.       current_user= my_strdup(optarg,MYF(MY_WME));
  578.       break;
  579. #endif
  580.     case 'U':
  581.       if (!optarg)
  582. safe_updates=1;
  583.       else
  584. safe_updates=atoi(optarg) != 0;
  585.       break;
  586.     case 'o':
  587.       one_database=skip_updates=1;
  588.       break;
  589.     case 'O':
  590.       if (set_changeable_var(optarg, changeable_vars))
  591.       {
  592. usage(0);
  593. return(1);
  594.       }
  595.       break;
  596.     case 'p':
  597.       if (optarg)
  598.       {
  599. char *start=optarg;
  600. my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
  601. opt_password=my_strdup(optarg,MYF(MY_FAE));
  602. while (*optarg) *optarg++= 'x'; // Destroy argument
  603. if (*start)
  604.   start[1]=0;
  605.       }
  606.       else
  607. tty_password=1;
  608.       break;
  609.     case 't':
  610.       output_tables=1;
  611.       break;
  612.     case 'r':
  613.       opt_raw_data=1;
  614.       break;
  615.     case '#':
  616.       DBUG_PUSH(optarg ? optarg : default_dbug_option);
  617.       info_flag=1;
  618.       break;
  619.     case 'q': quick=1; break;
  620.     case 's': opt_silent++; break;
  621.     case 'T': info_flag=1; break;
  622.     case 'n': unbuffered=1; break;
  623.     case 'v': verbose++; break;
  624.     case 'E': vertical=1; break;
  625.     case 'w':
  626.       wait_flag=1;
  627.       if(optarg) wait_time = atoi(optarg) ;
  628.       break;
  629.     case 'A': no_rehash=1; break;
  630.     case 'G': no_named_cmds=0; break;
  631.     case 'g': no_named_cmds=1; break;
  632.     case 'H': opt_html=1; break;
  633.     case 'i': connect_flag|= CLIENT_IGNORE_SPACE; break;
  634.     case 'B':
  635.       if (!status.batch)
  636.       {
  637. status.batch=1;
  638. status.add_to_history=0;
  639. opt_silent++; // more silent
  640.       }
  641.       break;
  642.     case 'C':
  643.       opt_compress=1;
  644.       break;
  645.     case 'L':
  646.       skip_line_numbers=1;
  647.       break;
  648.     case 'N':
  649.       skip_column_names=1;
  650.       break;
  651.     case 'P':
  652.       opt_mysql_port= (unsigned int) atoi(optarg);
  653.       break;
  654.     case 'S':
  655.       my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
  656.       opt_mysql_unix_port= my_strdup(optarg,MYF(0));
  657.       break;
  658.     case 'W':
  659. #ifdef __WIN__
  660.       opt_mysql_unix_port=my_strdup(MYSQL_NAMEDPIPE,MYF(0));
  661. #endif
  662.       break;
  663.     case 'V': usage(1); exit(0);
  664.     case 'I':
  665.     case '?':
  666.       usage(0);
  667.       exit(0);
  668. #include "sslopt-case.h"
  669.     default:
  670.       tee_fprintf(stderr,"illegal option: -%cn",opterr);
  671.       usage(0);
  672.       exit(1);
  673.     }
  674.   }
  675.   if (status.batch) /* disable pager and outfile in this case */
  676.   {
  677.     strmov(default_pager, "stdout");
  678.     strmov(pager, "stdout");
  679.     opt_nopager=1;
  680.     opt_outfile=0;
  681.   }
  682.   if (default_charset)
  683.   {
  684.     if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
  685.       exit(1);
  686.   }
  687.   argc-=optind;
  688.   argv+=optind;
  689.   if (argc > 1)
  690.   {
  691.     usage(0);
  692.     exit(1);
  693.   }
  694.   if (argc == 1)
  695.   {
  696.     my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
  697.     current_db= my_strdup(*argv,MYF(MY_WME));
  698.   }
  699.   if (!current_host)
  700.   { /* If we don't have a hostname have a look at MYSQL_HOST */
  701.     char *tmp=(char *) getenv("MYSQL_HOST");
  702.     if (tmp)
  703.       current_host = my_strdup(tmp,MYF(MY_WME));
  704.   }
  705.   if (tty_password)
  706.     opt_password=get_tty_password(NullS);
  707.   return(0);
  708. }
  709. static int read_lines(bool execute_commands)
  710. {
  711. #ifdef __WIN__
  712.   char linebuffer[254];
  713. #endif
  714.   char *line;
  715.   char in_string=0;
  716.   ulong line_number=0;
  717.   COMMANDS *com;
  718.   status.exit_status=1;
  719.   for (;;)
  720.   {
  721.     if (status.batch || !execute_commands)
  722.     {
  723.       line=batch_readline(status.line_buff);
  724.       line_number++;
  725.       if (!glob_buffer.length())
  726. status.query_start_line=line_number;
  727.     }
  728.     else
  729.     {
  730. #ifdef __WIN__
  731.       if (opt_outfile && glob_buffer.is_empty())
  732. fflush(OUTFILE);
  733.       tee_fputs(glob_buffer.is_empty() ? "mysql> " :
  734. !in_string ? "    -> " :
  735. in_string == ''' ?
  736. "    '> " : "    "> ",stdout);
  737.       linebuffer[0]=(char) sizeof(linebuffer);
  738.       line=_cgets(linebuffer);
  739. #else
  740.       if (opt_outfile)
  741.       {
  742. if (glob_buffer.is_empty())
  743.   fflush(OUTFILE);
  744. fputs(glob_buffer.is_empty() ? "mysql> " :
  745.       !in_string ? "    -> " :
  746.       in_string == ''' ?
  747.       "    '> " : "    "> ", OUTFILE);
  748.       }
  749.       line=readline((char*) (glob_buffer.is_empty() ? "mysql> " :
  750.      !in_string ? "    -> " :
  751.      in_string == ''' ?
  752.      "    '> " : "    "> "));
  753. #endif
  754.       if (opt_outfile)
  755. fprintf(OUTFILE, "%sn", line);
  756.     }
  757.     if (!line) // End of file
  758.     {
  759.       status.exit_status=0;
  760.       break;
  761.     }
  762.     if (!in_string && (line[0] == '#' ||
  763.        (line[0] == '-' && line[1] == '-') ||
  764.        line[0] == 0))
  765.       continue; // Skip comment lines
  766.     /* Check if line is a mysql command line */
  767.     /* (We want to allow help, print and clear anywhere at line start */
  768.     if (execute_commands && (!no_named_cmds || glob_buffer.is_empty()) 
  769. && !in_string && (com=find_command(line,0)))
  770.     {
  771.       if ((*com->func)(&glob_buffer,line) > 0)
  772. break;
  773.       if (glob_buffer.is_empty()) // If buffer was emptied
  774. in_string=0;
  775. #ifdef HAVE_READLINE
  776.       if (status.add_to_history)
  777. add_history(line);
  778. #endif
  779.       continue;
  780.     }
  781.     if (add_line(glob_buffer,line,&in_string))
  782.       break;
  783.   }
  784.   /* if in batch mode, send last query even if it doesn't end with g or go */
  785.   if ((status.batch || !execute_commands) && !status.exit_status)
  786.   {
  787.     remove_cntrl(glob_buffer);
  788.     if (!glob_buffer.is_empty())
  789.     {
  790.       status.exit_status=1;
  791.       if (com_go(&glob_buffer,line) <= 0)
  792. status.exit_status=0;
  793.     }
  794.   }
  795.   return status.exit_status;
  796. }
  797. static COMMANDS *find_command (char *name,char cmd_char)
  798. {
  799.   uint len;
  800.   char *end;
  801.   if (!name)
  802.   {
  803.     len=0;
  804.     end=0;
  805.   }
  806.   else
  807.   {
  808.     while (isspace(*name))
  809.       name++;
  810.     if (strchr(name,';') || strstr(name,"\g"))
  811.       return ((COMMANDS *) 0);
  812.     if ((end=strcont(name," t")))
  813.     {
  814.       len=(uint) (end - name);
  815.       while (isspace(*end))
  816. end++;
  817.       if (!*end)
  818. end=0; // no arguments to function
  819.     }
  820.     else
  821.       len=(uint) strlen(name);
  822.   }
  823.   for (uint i= 0; commands[i].name; i++)
  824.   {
  825.     if (commands[i].func &&
  826. ((name && !my_casecmp(name,commands[i].name,len) &&
  827.   !commands[i].name[len] &&
  828.   (!end || (end && commands[i].takes_params))) ||
  829.  !name && commands[i].cmd_char == cmd_char))
  830.       return (&commands[i]);
  831.   }
  832.   return ((COMMANDS *) 0);
  833. }
  834. static bool add_line(String &buffer,char *line,char *in_string)
  835. {
  836.   uchar inchar;
  837.   char buff[80],*pos,*out;
  838.   COMMANDS *com;
  839.   if (!line[0] && buffer.is_empty())
  840.     return 0;
  841. #ifdef HAVE_READLINE
  842.   if (status.add_to_history && line[0])
  843.     add_history(line);
  844. #endif
  845. #ifdef USE_MB
  846.   char *strend=line+(uint) strlen(line);
  847. #endif
  848.   for (pos=out=line ; (inchar= (uchar) *pos) ; pos++)
  849.   {
  850.     if (isspace(inchar) && out == line && buffer.is_empty())
  851.       continue;
  852. #ifdef USE_MB
  853.     int l;
  854.     if (use_mb(default_charset_info) &&
  855.         (l = my_ismbchar(default_charset_info, pos, strend))) {
  856. while (l--)
  857.     *out++ = *pos++;
  858. pos--;
  859. continue;
  860.     }
  861. #endif
  862.     if (inchar == '\')
  863.     { // mSQL or postgreSQL style command ?
  864.       if (!(inchar = (uchar) *++pos))
  865. break; // readline adds one ''
  866.       if (*in_string || inchar == 'N')
  867.       { // Don't allow commands in string
  868. *out++='\';
  869. *out++= (char) inchar;
  870. continue;
  871.       }
  872.       if ((com=find_command(NullS,(char) inchar)))
  873.       {
  874. const String tmp(line,(uint) (out-line));
  875. buffer.append(tmp);
  876. if ((*com->func)(&buffer,pos-1) > 0)
  877.   return 1; // Quit
  878. if (com->takes_params)
  879. {
  880.   for (pos++ ; *pos && *pos != ';' ; pos++) ; // Remove parameters
  881.   if (!*pos)
  882.     pos--;
  883. }
  884. out=line;
  885.       }
  886.       else
  887.       {
  888. sprintf(buff,"Unknown command '\%c'.",inchar);
  889. if (put_info(buff,INFO_ERROR) > 0)
  890.   return 1;
  891. *out++='\';
  892. *out++=(char) inchar;
  893. continue;
  894.       }
  895.     }
  896.     else if (inchar == ';' && !*in_string)
  897.     { // ';' is end of command
  898.       if (out != line)
  899. buffer.append(line,(uint) (out-line)); // Add this line
  900.       if ((com=find_command(buffer.c_ptr(),0)))
  901.       {
  902. if ((*com->func)(&buffer,buffer.c_ptr()) > 0)
  903.   return 1; // Quit
  904.       }
  905.       else
  906.       {
  907. int error=com_go(&buffer,0);
  908. if (error)
  909. {
  910.   return error < 0 ? 0 : 1; // < 0 is not fatal
  911. }
  912.       }
  913.       buffer.length(0);
  914.       out=line;
  915.     }
  916.     else if (!*in_string && (inchar == '#' ||
  917.      inchar == '-' && pos[1] == '-' &&
  918.      isspace(pos[2])))
  919.       break; // comment to end of line
  920.     else
  921.     { // Add found char to buffer
  922.       if (inchar == *in_string)
  923. *in_string=0;
  924.       else if (!*in_string && (inchar == ''' || inchar == '"'))
  925. *in_string=(char) inchar;
  926.       *out++ = (char) inchar;
  927.     }
  928.   }
  929.   if (out != line || !buffer.is_empty())
  930.   {
  931.     *out++='n';
  932.     uint length=(uint) (out-line);
  933.     if (buffer.length() + length >= buffer.alloced_length())
  934.       buffer.realloc(buffer.length()+length+IO_SIZE);
  935.     if (buffer.append(line,length))
  936.       return 1;
  937.   }
  938.   return 0;
  939. }
  940. /* **************************************************************** */
  941. /*     */
  942. /*     Interface to Readline Completion     */
  943. /*     */
  944. /* **************************************************************** */
  945. #ifdef HAVE_READLINE
  946. static char *new_command_generator(char *text, int);
  947. static char **new_mysql_completion (char *text, int start, int end);
  948. /* Tell the GNU Readline library how to complete.  We want to try to complete
  949.    on command names if this is the first word in the line, or on filenames
  950.    if not. */
  951. char **no_completion (char *text __attribute__ ((unused)),
  952.       char *word __attribute__ ((unused)))
  953. {
  954.   return 0; /* No filename completion */
  955. }
  956. static void initialize_readline (char *name)
  957. {
  958.   /* Allow conditional parsing of the ~/.inputrc file. */
  959.   rl_readline_name = name;
  960.   /* Tell the completer that we want a crack first. */
  961.   /* rl_attempted_completion_function = (CPPFunction *)mysql_completion;*/
  962.   rl_attempted_completion_function = (CPPFunction *) new_mysql_completion;
  963.   rl_completion_entry_function=(Function *) no_completion;
  964. }
  965. /* Attempt to complete on the contents of TEXT.  START and END show the
  966.    region of TEXT that contains the word to complete.  We can use the
  967.    entire line in case we want to do some simple parsing.  Return the
  968.    array of matches, or NULL if there aren't any. */
  969. static char **new_mysql_completion (char *text,
  970.     int start __attribute__((unused)),
  971.     int end __attribute__((unused)))
  972. {
  973.   if (!status.batch && !quick)
  974.     return completion_matches(text, (CPFunction*) new_command_generator);
  975.   else
  976.     return (char**) 0;
  977. }
  978. static char *new_command_generator(char *text,int state)
  979. {
  980.   static int textlen;
  981.   char *ptr;
  982.   static Bucket *b;
  983.   static entry *e;
  984.   static uint i;
  985.   if (!state) {
  986.     textlen=(uint) strlen(text);
  987.   }
  988.   if (textlen>0) { /* lookup in the hash */
  989.     if (!state) {
  990.       uint len;
  991.       b = find_all_matches(&ht,text,(uint) strlen(text),&len);
  992.       if (!b) {
  993. return NullS;
  994.       }
  995.       e = b->pData;
  996.     }
  997.     while (e) {
  998.       ptr= strdup(e->str);
  999.       e = e->pNext;
  1000.       return ptr;
  1001.     }
  1002.   } else { /* traverse the entire hash, ugly but works */
  1003.     if (!state) {
  1004.       i=0;
  1005.       /* find the first used bucket */
  1006.       while (i<ht.nTableSize) {
  1007. if (ht.arBuckets[i]) {
  1008.   b = ht.arBuckets[i];
  1009.   e = b->pData;
  1010.   break;
  1011. }
  1012. i++;
  1013.       }
  1014.     }
  1015.     ptr= NullS;
  1016.     while (e && !ptr) { /* find valid entry in bucket */
  1017.       if ((uint) strlen(e->str)==b->nKeyLength) {
  1018. ptr = strdup(e->str);
  1019.       }
  1020.       /* find the next used entry */
  1021.       e = e->pNext;
  1022.       if (!e) { /* find the next used bucket */
  1023. b = b->pNext;
  1024. if (!b) {
  1025.   i++;
  1026.   while (i<ht.nTableSize) {
  1027.     if (ht.arBuckets[i]) {
  1028.       b = ht.arBuckets[i];
  1029.       e = b->pData;
  1030.       break;
  1031.     }
  1032.     i++;
  1033.   }
  1034. } else {
  1035.   e = b->pData;
  1036. }
  1037.       }
  1038.     }
  1039.     if (ptr) {
  1040.       return ptr;
  1041.     }
  1042.   }
  1043.   return NullS;
  1044. }
  1045. /* Build up the completion hash */
  1046. static void build_completion_hash(bool skip_rehash,bool write_info)
  1047. {
  1048.   COMMANDS *cmd=commands;
  1049.   static MYSQL_RES *databases=0,*tables=0,*fields;
  1050.   static char ***field_names= 0;
  1051.   MYSQL_ROW database_row,table_row;
  1052.   MYSQL_FIELD *sql_field;
  1053.   char buf[NAME_LEN*2+2];  // table name plus field name plus 2
  1054.   int i,j,num_fields;
  1055.   DBUG_ENTER("build_completion_hash");
  1056.   if (status.batch || quick || !current_db)
  1057.     DBUG_VOID_RETURN; // We don't need completion in batches
  1058.   completion_hash_clean(&ht);
  1059.   if (tables)
  1060.   {
  1061.     mysql_free_result(tables);
  1062.     tables=0;
  1063.   }
  1064.   if (databases) {
  1065.     mysql_free_result(databases);
  1066.     databases=0;
  1067.   }
  1068.   /* hash SQL commands */
  1069.   while (cmd->name) {
  1070.     add_word(&ht,(char*) cmd->name);
  1071.     cmd++;
  1072.   }
  1073.   if (skip_rehash)
  1074.     DBUG_VOID_RETURN;
  1075.   /* hash MySQL functions (to be implemented) */
  1076.   /* hash all database names */
  1077.   if (mysql_query(&mysql,"show databases")==0) {
  1078.     if (!(databases = mysql_store_result(&mysql)))
  1079.       put_info(mysql_error(&mysql),INFO_INFO);
  1080.     else
  1081.     {
  1082.       while ((database_row=mysql_fetch_row(databases)))
  1083. add_word(&ht,(char*) database_row[0]);
  1084.     }
  1085.   }
  1086.   /* hash all table names */
  1087.   if (mysql_query(&mysql,"show tables")==0)
  1088.   {
  1089.     if (!(tables = mysql_store_result(&mysql)))
  1090.       put_info(mysql_error(&mysql),INFO_INFO);
  1091.     else
  1092.     {
  1093.       if (mysql_num_rows(tables) > 0 && !opt_silent && write_info)
  1094.       {
  1095. tee_fprintf(stdout, "
  1096. Reading table information for completion of table and column namesn
  1097. You can turn off this feature to get a quicker startup with -Ann");
  1098.       }
  1099.       while ((table_row=mysql_fetch_row(tables)))
  1100.       {
  1101. if (!completion_hash_exists(&ht,(char*) table_row[0],
  1102.     (uint) strlen((const char*) table_row[0])))
  1103.   add_word(&ht,table_row[0]);
  1104.       }
  1105.     }
  1106.   }
  1107.   if (field_names) {
  1108.     for (i=0; field_names[i]; i++) {
  1109.       for (j=0; field_names[i][j]; j++) {
  1110. my_free(field_names[i][j],MYF(0));
  1111.       }
  1112.       my_free((gptr) field_names[i],MYF(0));
  1113.     }
  1114.     my_free((gptr) field_names,MYF(0));
  1115.   }
  1116.   field_names=0;
  1117.   /* hash all field names, both with the table prefix and without it */
  1118.   if (!tables) /* no tables */
  1119.   {
  1120.     DBUG_VOID_RETURN;
  1121.   }
  1122.   mysql_data_seek(tables,0);
  1123.   field_names = (char ***) my_malloc(sizeof(char **) *
  1124.      (uint) (mysql_num_rows(tables)+1),
  1125.      MYF(MY_WME));
  1126.   if (!field_names)
  1127.     DBUG_VOID_RETURN;
  1128.   i=0;
  1129.   while ((table_row=mysql_fetch_row(tables)))
  1130.   {
  1131.     if ((fields=mysql_list_fields(&mysql,(const char*) table_row[0],NullS)))
  1132.     {
  1133.       num_fields=mysql_num_fields(fields);
  1134.       field_names[i] = (char **) my_malloc(sizeof(char *)*(num_fields*2+1),
  1135.    MYF(0));
  1136.       if (!field_names[i])
  1137.       {
  1138. continue;
  1139.       }
  1140.       field_names[i][num_fields*2]='';
  1141.       j=0;
  1142.       while ((sql_field=mysql_fetch_field(fields)))
  1143.       {
  1144. sprintf(buf,"%s.%s",table_row[0],sql_field->name);
  1145. field_names[i][j] = my_strdup(buf,MYF(0));
  1146. add_word(&ht,field_names[i][j]);
  1147. field_names[i][num_fields+j] = my_strdup(sql_field->name,MYF(0));
  1148. if (!completion_hash_exists(&ht,field_names[i][num_fields+j],
  1149.     (uint) strlen(field_names[i][num_fields+j])))
  1150.   add_word(&ht,field_names[i][num_fields+j]);
  1151. j++;
  1152.       }
  1153.     }
  1154.     else
  1155.     {
  1156.       tee_fprintf(stdout,
  1157.   "Didn't find any fields in table '%s'n",table_row[0]);
  1158.       field_names[i]=0;
  1159.     }
  1160.     i++;
  1161.   }
  1162.   field_names[i]=0; // End pointer
  1163.   DBUG_VOID_RETURN;
  1164. }
  1165. /* for gnu readline */
  1166. #ifndef HAVE_INDEX
  1167. #ifdef __cplusplus
  1168. extern "C" {
  1169. #endif
  1170. extern char *index(const char *,pchar c),*rindex(const char *,pchar);
  1171. char *index(const char *s,pchar c)
  1172. {
  1173.   for (;;)
  1174.   {
  1175.      if (*s == (char) c) return (char*) s;
  1176.      if (!*s++) return NullS;
  1177.   }
  1178. }
  1179. char *rindex(const char *s,pchar c)
  1180. {
  1181.   reg3 char *t;
  1182.   t = NullS;
  1183.   do if (*s == (char) c) t = (char*) s; while (*s++);
  1184.   return (char*) t;
  1185. }
  1186. #ifdef __cplusplus
  1187. }
  1188. #endif
  1189. #endif
  1190. #endif /* HAVE_READLINE */
  1191. static int reconnect(void)
  1192. {
  1193.   if (!status.batch)
  1194.   {
  1195.     put_info("No connection. Trying to reconnect...",INFO_INFO);
  1196.     (void) com_connect((String *) 0, 0);
  1197.     if(!no_rehash) com_rehash(NULL, NULL);
  1198.   }
  1199.   if (!connected)
  1200.     return put_info("Can't connect to the servern",INFO_ERROR);
  1201.   return 0;
  1202. }
  1203. /***************************************************************************
  1204.  The different commands
  1205. ***************************************************************************/
  1206. static int
  1207. com_help (String *buffer __attribute__((unused)),
  1208.   char *line __attribute__((unused)))
  1209. {
  1210.   reg1 int i;
  1211.   put_info("nMySQL commands:",INFO_INFO);
  1212.   if (no_named_cmds)
  1213.     put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO);
  1214.   for (i = 0; commands[i].name; i++)
  1215.   {
  1216.     if (commands[i].func)
  1217.       tee_fprintf(stdout, "%st(\%c)t%sn", commands[i].name,
  1218.   commands[i].cmd_char, commands[i].doc);
  1219.   }
  1220.   if (connected)
  1221.     tee_fprintf(stdout,
  1222. "nConnection id: %ld  (Can be used with mysqladmin kill)nn",
  1223. mysql_thread_id(&mysql));
  1224.   else
  1225.     tee_fprintf(stdout, "Not connected!  Reconnect with 'connect'!nn");
  1226.   return 0;
  1227. }
  1228. /* ARGSUSED */
  1229. static int
  1230. com_clear(String *buffer,char *line __attribute__((unused)))
  1231. {
  1232.   buffer->length(0);
  1233.   return 0;
  1234. }
  1235. /*
  1236. ** Execute command
  1237. ** Returns: 0  if ok
  1238. **     -1 if not fatal error
  1239. **     1  if fatal error
  1240. */
  1241. static int
  1242. com_go(String *buffer,char *line __attribute__((unused)))
  1243. {
  1244.   char buff[160],time_buff[32];
  1245.   MYSQL_RES *result;
  1246.   ulong timer;
  1247.   uint error=0;
  1248.   if (!status.batch)
  1249.   {
  1250.     old_buffer= *buffer; // Save for edit command
  1251.     old_buffer.copy();
  1252.   }
  1253. /* Remove garbage for nicer messages */
  1254.   LINT_INIT(buff[0]);
  1255.   remove_cntrl(*buffer);
  1256.   if (buffer->is_empty())
  1257.   {
  1258.     if (status.batch) // Ignore empty quries
  1259.       return 0;
  1260.     return put_info("No query specifiedn",INFO_ERROR);
  1261.   }
  1262.   if (!connected && reconnect())
  1263.   {
  1264.     buffer->length(0); // Remove query on error
  1265.     return status.batch ? 1 : -1; // Fatal error
  1266.   }
  1267.   if (verbose)
  1268.     (void) com_print(buffer,0);
  1269.   if (skip_updates &&
  1270.       (buffer->length() < 4 || my_sortcmp(buffer->ptr(),"SET ",4)))
  1271.   {
  1272.     (void) put_info("Ignoring query to other database",INFO_INFO);
  1273.     return 0;
  1274.   }
  1275.   timer=start_timer();
  1276.   for (uint retry=0;; retry++)
  1277.   {
  1278.     if (!mysql_real_query(&mysql,buffer->ptr(),buffer->length()))
  1279.       break;
  1280.     error=put_info(mysql_error(&mysql),INFO_ERROR, mysql_errno(&mysql));
  1281.     if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 
  1282. || status.batch)
  1283.     {
  1284.       buffer->length(0); // Remove query on error
  1285.       return error;
  1286.     }
  1287.     if (reconnect())
  1288.     {
  1289.       buffer->length(0); // Remove query on error
  1290.       return error;
  1291.     }
  1292.   }
  1293.   error=0;
  1294.   buffer->length(0);
  1295.   if (quick)
  1296.   {
  1297.     if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
  1298.     {
  1299.       return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
  1300.     }
  1301.   }
  1302.   else
  1303.   {
  1304.     if (!(result=mysql_store_result(&mysql)))
  1305.     {
  1306.       if (mysql_error(&mysql)[0])
  1307.       {
  1308. return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
  1309.       }
  1310.     }
  1311.   }
  1312.   if (verbose >= 3 || !opt_silent)
  1313.     mysql_end_timer(timer,time_buff);
  1314.   else
  1315.     time_buff[0]=0;
  1316.   if (result)
  1317.   {
  1318.     if (!mysql_num_rows(result) && ! quick)
  1319.     {
  1320.       sprintf(buff,"Empty set%s",time_buff);
  1321.     }
  1322.     else
  1323.     {
  1324.       init_pager();
  1325.       if (opt_html)
  1326. print_table_data_html(result);
  1327.       else if (vertical)
  1328. print_table_data_vertically(result);
  1329.       else if (opt_silent && verbose <= 2 && !output_tables)
  1330. print_tab_data(result);
  1331.       else
  1332. print_table_data(result);
  1333.       sprintf(buff,"%ld %s in set%s",
  1334.       (long) mysql_num_rows(result),
  1335.       (long) mysql_num_rows(result) == 1 ? "row" : "rows",
  1336.       time_buff);
  1337.       end_pager();
  1338.     }
  1339.   }
  1340.   else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0)
  1341.     sprintf(buff,"Query OK%s",time_buff);
  1342.   else
  1343.     sprintf(buff,"Query OK, %ld %s affected%s",
  1344.     (long) mysql_affected_rows(&mysql),
  1345.     (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows",
  1346.     time_buff);
  1347.   put_info(buff,INFO_RESULT);
  1348.   if (mysql_info(&mysql))
  1349.     put_info(mysql_info(&mysql),INFO_RESULT);
  1350.   put_info("",INFO_RESULT); // Empty row
  1351.   if (result && !mysql_eof(result)) /* Something wrong when using quick */
  1352.     error=put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
  1353.   else if (unbuffered)
  1354.     fflush(stdout);
  1355.   mysql_free_result(result);
  1356.   return error; /* New command follows */
  1357. }
  1358. static void init_pager()
  1359. {
  1360. #ifndef __WIN__
  1361.   if (!opt_nopager)
  1362.   {
  1363.     if (!(PAGER= popen(pager, "w")))
  1364.     {
  1365.       tee_fprintf(stdout, "popen() failed! defaulting PAGER to stdout!n");
  1366.       PAGER= stdout;
  1367.     }
  1368.   }
  1369.   else
  1370. #endif
  1371.     PAGER= stdout;
  1372. }
  1373. static void end_pager()
  1374. {
  1375. #ifndef __WIN__
  1376.   if (!opt_nopager)
  1377.     pclose(PAGER);
  1378. #endif
  1379. }
  1380. static void init_tee()
  1381. {
  1382.   if (!(OUTFILE= my_fopen(outfile, O_APPEND | O_WRONLY, MYF(MY_WME))))
  1383.   {
  1384.     opt_outfile=0;
  1385.     init_pager();
  1386.     return;
  1387.   }
  1388. }
  1389. static void end_tee()
  1390. {
  1391.   my_fclose(OUTFILE, MYF(0));
  1392.   return;
  1393. }
  1394. static int
  1395. com_ego(String *buffer,char *line)
  1396. {
  1397.   int result;
  1398.   bool oldvertical=vertical;
  1399.   vertical=1;
  1400.   result=com_go(buffer,line);
  1401.   vertical=oldvertical;
  1402.   return result;
  1403. }
  1404. static void
  1405. print_field_types(MYSQL_RES *result)
  1406. {
  1407.   MYSQL_FIELD *field;  
  1408.   while ((field = mysql_fetch_field(result)))
  1409.   {
  1410.     tee_fprintf(PAGER,"%s '%s' %d %d %d %d %dn",
  1411. field->name,
  1412. field->table ? "" : field->table,
  1413. (int) field->type,
  1414. field->length, field->max_length, 
  1415. field->flags, field->decimals);
  1416.   }
  1417.   tee_puts("", PAGER);
  1418. }
  1419. static void
  1420. print_table_data(MYSQL_RES *result)
  1421. {
  1422.   String separator(256);
  1423.   MYSQL_ROW cur;
  1424.   MYSQL_FIELD *field;
  1425.   bool *num_flag;
  1426.   num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result));
  1427.   if (info_flag)
  1428.   {
  1429.     print_field_types(result);
  1430.     mysql_field_seek(result,0);
  1431.   }
  1432.   separator.copy("+",1);
  1433.   while ((field = mysql_fetch_field(result)))
  1434.   {
  1435.     uint length=skip_column_names ? 0 : (uint) strlen(field->name);
  1436.     if (quick)
  1437.       length=max(length,field->length);
  1438.     else
  1439.       length=max(length,field->max_length);
  1440.     if (length < 4 && !IS_NOT_NULL(field->flags))
  1441.       length=4; // Room for "NULL"
  1442.     field->max_length=length+1;
  1443.     separator.fill(separator.length()+length+2,'-');
  1444.     separator.append('+');
  1445.   }
  1446.   tee_puts(separator.c_ptr(), PAGER);
  1447.   if (!skip_column_names)
  1448.   {
  1449.     mysql_field_seek(result,0);
  1450.     (void) tee_fputs("|", PAGER);
  1451.     for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
  1452.     {
  1453.       tee_fprintf(PAGER, " %-*s|",min(field->max_length,MAX_COLUMN_LENGTH),
  1454.   field->name);
  1455.       num_flag[off]= IS_NUM(field->type);
  1456.     }
  1457.     (void) tee_fputs("n", PAGER);
  1458.     tee_puts(separator.c_ptr(), PAGER);
  1459.   }
  1460.   while ((cur = mysql_fetch_row(result)))
  1461.   {
  1462.     (void) tee_fputs("|", PAGER);
  1463.     mysql_field_seek(result,0);
  1464.     for (uint off=0 ; off < mysql_num_fields(result); off++)
  1465.     {
  1466.       const char *str=cur[off] ? cur[off] : "NULL";
  1467.       field = mysql_fetch_field(result);
  1468.       uint length=field->max_length;
  1469.       if (length > MAX_COLUMN_LENGTH)
  1470.       {
  1471. tee_fputs(str,PAGER); tee_fputs(" |",PAGER);
  1472.       }
  1473.       else
  1474.       tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|",
  1475.   length, str);
  1476.     }
  1477.     (void) tee_fputs("n", PAGER);
  1478.   }
  1479.   tee_puts(separator.c_ptr(), PAGER);
  1480.   my_afree((gptr) num_flag);
  1481. }
  1482. static void
  1483. print_table_data_html(MYSQL_RES *result)
  1484. {
  1485.   MYSQL_ROW   cur;
  1486.   MYSQL_FIELD *field;
  1487.   mysql_field_seek(result,0);
  1488.   (void) tee_fputs("<TABLE BORDER=1><TR>", PAGER);
  1489.   if (!skip_column_names)
  1490.   {
  1491.     while((field = mysql_fetch_field(result)))
  1492.     {
  1493.       tee_fprintf(PAGER, "<TH>%s</TH>", (field->name ? 
  1494.  (field->name[0] ? field->name : 
  1495.   " &nbsp; ") : "NULL"));
  1496.     }
  1497.     (void) tee_fputs("</TR>", PAGER);
  1498.   }
  1499.   while ((cur = mysql_fetch_row(result)))
  1500.   {
  1501.     (void) tee_fputs("<TR>", PAGER);
  1502.     for (uint i=0; i < mysql_num_fields(result); i++)
  1503.     {
  1504.       ulong *lengths=mysql_fetch_lengths(result);
  1505.       (void) tee_fputs("<TD>", PAGER);
  1506.       safe_put_field(cur[i],lengths[i]);
  1507.       (void) tee_fputs("</TD>", PAGER);
  1508.     }
  1509.     (void) tee_fputs("</TR>", PAGER);
  1510.   }
  1511.   (void) tee_fputs("</TABLE>", PAGER);
  1512. }
  1513. static void
  1514. print_table_data_vertically(MYSQL_RES *result)
  1515. {
  1516.   MYSQL_ROW cur;
  1517.   uint max_length=0;
  1518.   MYSQL_FIELD *field;
  1519.   while ((field = mysql_fetch_field(result)))
  1520.   {
  1521.     uint length=(uint) strlen(field->name);
  1522.     if (length > max_length)
  1523.       max_length= length;
  1524.     field->max_length=length;
  1525.   }
  1526.   mysql_field_seek(result,0);
  1527.   for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++)
  1528.   {
  1529.     mysql_field_seek(result,0);
  1530.     tee_fprintf(PAGER, 
  1531. "*************************** %d. row ***************************n", row_count);
  1532.     for (uint off=0; off < mysql_num_fields(result); off++)
  1533.     {
  1534.       field= mysql_fetch_field(result);
  1535.       tee_fprintf(PAGER, "%*s: ",(int) max_length,field->name);
  1536.       tee_fprintf(PAGER, "%sn",cur[off] ? (char*) cur[off] : "NULL");
  1537.     }
  1538.   }
  1539. }
  1540. static void
  1541. safe_put_field(const char *pos,ulong length)
  1542. {
  1543.   if (!pos)
  1544.     tee_fputs("NULL", PAGER);
  1545.   else
  1546.   {
  1547.     if (opt_raw_data)
  1548.       tee_fputs(pos, PAGER);
  1549.     else for (const char *end=pos+length ; pos != end ; pos++)
  1550.     {
  1551. #ifdef USE_MB
  1552.       int l;
  1553.       if (use_mb(default_charset_info) &&
  1554.           (l = my_ismbchar(default_charset_info, pos, end))) {
  1555.   while (l--)
  1556.     tee_putc(*pos++, PAGER);
  1557.   pos--;
  1558.   continue;
  1559.       }
  1560. #endif
  1561.       if (!*pos)
  1562. tee_fputs("\0", PAGER); // This makes everything hard
  1563.       else if (*pos == 't')
  1564. tee_fputs("\t", PAGER); // This would destroy tab format
  1565.       else if (*pos == 'n')
  1566. tee_fputs("\n", PAGER); // This too
  1567.       else if (*pos == '\')
  1568. tee_fputs("\\", PAGER);
  1569.       else
  1570. tee_putc(*pos, PAGER);
  1571.     }
  1572.   }
  1573. }
  1574. static void
  1575. print_tab_data(MYSQL_RES *result)
  1576. {
  1577.   MYSQL_ROW cur;
  1578.   MYSQL_FIELD *field;
  1579.   ulong *lengths;
  1580.   if (opt_silent < 2 && !skip_column_names)
  1581.   {
  1582.     int first=0;
  1583.     while ((field = mysql_fetch_field(result)))
  1584.     {
  1585.       if (first++)
  1586. (void) tee_fputs("t", PAGER);
  1587.       (void) tee_fputs(field->name, PAGER);
  1588.     }
  1589.     (void) tee_fputs("n", PAGER);
  1590.   }
  1591.   while ((cur = mysql_fetch_row(result)))
  1592.   {
  1593.     lengths=mysql_fetch_lengths(result);
  1594.     safe_put_field(cur[0],lengths[0]);
  1595.     for (uint off=1 ; off < mysql_num_fields(result); off++)
  1596.     {
  1597.       (void) tee_fputs("t", PAGER);
  1598.       safe_put_field(cur[off],lengths[off]);
  1599.     }
  1600.     (void) tee_fputs("n", PAGER);
  1601.   }
  1602. }
  1603. static int
  1604. com_tee(String *buffer, char *line __attribute__((unused)))
  1605. {
  1606.   char file_name[FN_REFLEN], *end, *param;
  1607.   if (status.batch)
  1608.     return 0;
  1609.   while (isspace(*line))
  1610.     line++;
  1611.   if (!(param = strchr(line, ' '))) // if outfile wasn't given, use the default
  1612.   {
  1613.     if (!strlen(outfile))
  1614.     {
  1615.       printf("No previous outfile available, you must give the filename!n");
  1616.       opt_outfile=0;
  1617.       return 0;
  1618.     }
  1619.   }
  1620.   else
  1621.   {
  1622.     while (isspace(*param))
  1623.       param++;
  1624.     end=strmake(file_name, param, sizeof(file_name)-1);
  1625.     while (end > file_name && (isspace(end[-1]) || iscntrl(end[-1])))
  1626.       end--;
  1627.     end[0]=0;
  1628.     strmov(outfile, file_name);
  1629.   }
  1630.   if (!strlen(outfile))
  1631.   {
  1632.     printf("No outfile specified!n");
  1633.     return 0;
  1634.   }
  1635.   if (!opt_outfile)
  1636.   {
  1637.     init_tee();
  1638.     opt_outfile=1;
  1639.   }
  1640.   tee_fprintf(stdout, "Logging to file '%s'n", outfile);
  1641.   return 0;
  1642. }
  1643. static int
  1644. com_notee(String *buffer __attribute__((unused)),
  1645.   char *line __attribute__((unused)))
  1646. {
  1647.   if (opt_outfile)
  1648.     end_tee();
  1649.   opt_outfile=0;
  1650.   tee_fprintf(stdout, "Outfile disabled.n");
  1651.   return 0;
  1652. }
  1653. /*
  1654. ** Sorry, this command is not available in Windows.
  1655. */
  1656. #ifndef __WIN__
  1657. static int
  1658. com_pager(String *buffer, char *line __attribute__((unused)))
  1659. {
  1660.   char pager_name[FN_REFLEN], *end, *param;
  1661.   if (status.batch)
  1662.     return 0;
  1663.   /* Skip space from file name */
  1664.   while (isspace(*line))
  1665.     line++;
  1666.   if (!(param = strchr(line, ' '))) // if pager was not given, use the default
  1667.   {
  1668.     if (!strlen(default_pager))
  1669.     {
  1670.       tee_fprintf(stdout, "Default pager wasn't set, using stdout.n");
  1671.       opt_nopager=1;
  1672.       strmov(pager, "stdout");
  1673.       PAGER= stdout;
  1674.       return 0;
  1675.     }
  1676.     strmov(pager, default_pager);
  1677.   }
  1678.   else
  1679.   {
  1680.     while (isspace(*param))
  1681.       param++;
  1682.     end=strmake(pager_name, param, sizeof(pager_name)-1);
  1683.     while (end > pager_name && (isspace(end[-1]) || iscntrl(end[-1])))
  1684.       end--;
  1685.     end[0]=0;
  1686.     strmov(pager, pager_name);
  1687.   }
  1688.   opt_nopager=0;
  1689.   tee_fprintf(stdout, "PAGER set to %sn", pager);
  1690.   return 0;
  1691. }
  1692. static int
  1693. com_nopager(String *buffer __attribute__((unused)),
  1694.     char *line __attribute__((unused)))
  1695. {
  1696.   strmov(pager, "stdout");
  1697.   opt_nopager=1;
  1698.   tee_fprintf(stdout, "PAGER set to stdoutn");
  1699.   return 0;
  1700. }
  1701. #endif
  1702. /*
  1703. ** Sorry, you can't send the result to an editor in Win32
  1704. */
  1705. #ifndef __WIN__
  1706. static int
  1707. com_edit(String *buffer,char *line __attribute__((unused)))
  1708. {
  1709.   char filename[FN_REFLEN],buff[160];
  1710.   int fd,tmp;
  1711.   const char *editor;
  1712.   if ((fd=create_temp_file(filename,NullS,"sql", O_CREAT | O_WRONLY,
  1713.    MYF(MY_WME))) < 0)
  1714.     goto err;
  1715.   if (buffer->is_empty() && !old_buffer.is_empty())
  1716.     (void) my_write(fd,(byte*) old_buffer.ptr(),old_buffer.length(),
  1717.     MYF(MY_WME));
  1718.   else
  1719.     (void) my_write(fd,(byte*) buffer->ptr(),buffer->length(),MYF(MY_WME));
  1720.   (void) my_close(fd,MYF(0));
  1721.   if (!(editor = (char *)getenv("EDITOR")) &&
  1722.       !(editor = (char *)getenv("VISUAL")))
  1723.     editor = "vi";
  1724.   strxmov(buff,editor," ",filename,NullS);
  1725.   (void) system(buff);
  1726.   MY_STAT stat_arg;
  1727.   if (!my_stat(filename,&stat_arg,MYF(MY_WME)))
  1728.     goto err;
  1729.   if ((fd = my_open(filename,O_RDONLY, MYF(MY_WME))) < 0)
  1730.     goto err;
  1731.   (void) buffer->alloc((uint) stat_arg.st_size);
  1732.   if ((tmp=read(fd,(char*) buffer->ptr(),buffer->alloced_length())) >= 0L)
  1733.     buffer->length((uint) tmp);
  1734.   else
  1735.     buffer->length(0);
  1736.   (void) my_close(fd,MYF(0));
  1737.   (void) my_delete(filename,MYF(MY_WME));
  1738. err:
  1739.   return 0;
  1740. }
  1741. #endif
  1742. /* If arg is given, exit without errors. This happens on command 'quit' */
  1743. static int
  1744. com_quit(String *buffer __attribute__((unused)),
  1745.  char *line __attribute__((unused)))
  1746. {
  1747.   status.exit_status=0;
  1748.   return 1;
  1749. }
  1750. static int
  1751. com_rehash(String *buffer __attribute__((unused)),
  1752.  char *line __attribute__((unused)))
  1753. {
  1754. #ifdef HAVE_READLINE
  1755.   build_completion_hash(0,0);
  1756. #endif
  1757.   return 0;
  1758. }
  1759. static int
  1760. com_print(String *buffer,char *line __attribute__((unused)))
  1761. {
  1762.   tee_puts("--------------", stdout);
  1763.   (void) tee_fputs(buffer->c_ptr(), stdout);
  1764.   if (!buffer->length() || (*buffer)[buffer->length()-1] != 'n')
  1765.     tee_putc('n', stdout);
  1766.   tee_puts("--------------n", stdout);
  1767.   return 0; /* If empty buffer */
  1768. }
  1769. /* ARGSUSED */
  1770. static int
  1771. com_connect(String *buffer, char *line)
  1772. {
  1773.   char *tmp,buff[256];
  1774.   bool save_rehash=no_rehash;
  1775.   int error;
  1776.   if (buffer)
  1777.   {
  1778.     while (isspace(*line))
  1779.       line++;
  1780.     strnmov(buff,line,sizeof(buff)-1); // Don't destroy history
  1781.     if (buff[0] == '\') // Short command
  1782.       buff[1]=' ';
  1783.     tmp=(char *) strtok(buff," t"); // Skip connect command
  1784.     if (tmp && (tmp=(char *) strtok(NullS," t;")))
  1785.     {
  1786.       my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
  1787.       current_db=my_strdup(tmp,MYF(MY_WME));
  1788.       if ((tmp=(char *) strtok(NullS," t;")))
  1789.       {
  1790. my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
  1791. current_host=my_strdup(tmp,MYF(MY_WME));
  1792.       }
  1793.     }
  1794.     else
  1795.       no_rehash=1; // Quick re-connect
  1796.     buffer->length(0); // command used
  1797.   }
  1798.   else
  1799.     no_rehash=1;
  1800.   error=sql_connect(current_host,current_db,current_user,opt_password,0);
  1801.   no_rehash=save_rehash;
  1802.   if (connected)
  1803.   {
  1804.     sprintf(buff,"Connection id:    %ld",mysql_thread_id(&mysql));
  1805.     put_info(buff,INFO_INFO);
  1806.     sprintf(buff,"Current database: %sn",
  1807.     current_db ? current_db : "*** NONE ***");
  1808.     put_info(buff,INFO_INFO);
  1809.   }
  1810.   return error;
  1811. }
  1812. static int com_source(String *buffer, char *line)
  1813. {
  1814.   char source_name[FN_REFLEN], *end, *param;
  1815.   LINE_BUFFER *line_buff;
  1816.   int error;
  1817.   STATUS old_status;
  1818.   FILE *sql_file;
  1819.   /* Skip space from file name */
  1820.   while (isspace(*line))
  1821.     line++;
  1822.   if (!(param = strchr(line, ' '))) // Skip command name
  1823.     return put_info("Usage: \. <filename> | source <filename>", 
  1824.     INFO_ERROR, 0);
  1825.   while (isspace(*param))
  1826.     param++;
  1827.   end=strmake(source_name,param,sizeof(source_name)-1);
  1828.   while (end > source_name && (isspace(end[-1]) || iscntrl(end[-1])))
  1829.     end--;
  1830.   end[0]=0;
  1831.   unpack_filename(source_name,source_name);
  1832.   /* open file name */
  1833.   if (!(sql_file = my_fopen(source_name, O_RDONLY | O_BINARY,MYF(0))))
  1834.   {
  1835.     char buff[FN_REFLEN+60];
  1836.     sprintf(buff,"Failed to open file '%s', error: %d", source_name,errno);
  1837.     return put_info(buff, INFO_ERROR, 0);
  1838.   }
  1839.   if (!(line_buff=batch_readline_init(max_allowed_packet+512,sql_file)))
  1840.   {
  1841.     my_fclose(sql_file,MYF(0));
  1842.     return put_info("Can't initialize batch_readline", INFO_ERROR, 0);
  1843.   }
  1844.   /* Save old status */
  1845.   old_status=status;
  1846.   bfill((char*) &status,sizeof(status),(char) 0);
  1847.   status.batch=old_status.batch; // Run in batch mode
  1848.   status.line_buff=line_buff;
  1849.   status.file_name=source_name;
  1850.   glob_buffer.length(0); // Empty command buffer
  1851.   error=read_lines(0); // Read lines from file
  1852.   status=old_status; // Continue as before
  1853.   my_fclose(sql_file,MYF(0));
  1854.   batch_readline_end(line_buff);
  1855.   return error;
  1856. }
  1857. /* ARGSUSED */
  1858. static int
  1859. com_use(String *buffer __attribute__((unused)), char *line)
  1860. {
  1861.   char *tmp;
  1862.   char buff[256];
  1863.   while (isspace(*line))
  1864.     line++;
  1865.   strnmov(buff,line,sizeof(buff)-1); // Don't destroy history
  1866.   if (buff[0] == '\') // Short command
  1867.     buff[1]=' ';
  1868.   tmp=(char *) strtok(buff," t;"); // Skip connect command
  1869.   if (!tmp || !(tmp=(char *) strtok(NullS," t;")))
  1870.   {
  1871.     put_info("USE must be followed by a database name",INFO_ERROR);
  1872.     return 0;
  1873.   }
  1874.   if (!current_db || cmp_database(current_db,tmp))
  1875.   {
  1876.     if (one_database)
  1877.       skip_updates=1;
  1878.     else
  1879.     {
  1880.       /*
  1881. reconnect once if connection is down or if connection was found to
  1882. be down during query
  1883.       */
  1884.       if (!connected && reconnect())
  1885. return status.batch ? 1 : -1; // Fatal error
  1886.       if (mysql_select_db(&mysql,tmp))
  1887.       {
  1888. if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR)
  1889.   return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
  1890. if (reconnect())
  1891.   return status.batch ? 1 : -1; // Fatal error
  1892. if (mysql_select_db(&mysql,tmp))
  1893.   return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
  1894.       }
  1895.       my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
  1896.       current_db=my_strdup(tmp,MYF(MY_WME));
  1897. #ifdef HAVE_READLINE
  1898.       build_completion_hash(no_rehash,1);
  1899. #endif
  1900.     }
  1901.   }
  1902.   else
  1903.     skip_updates=0;
  1904.   put_info("Database changed",INFO_INFO);
  1905.   return 0;
  1906. }
  1907. static int
  1908. sql_real_connect(char *host,char *database,char *user,char *password,
  1909.  uint silent)
  1910. {
  1911.   if (connected)
  1912.   { /* if old is open, close it first */
  1913.     mysql_close(&mysql);
  1914.     connected= 0;
  1915.   }
  1916.   mysql_init(&mysql);
  1917.   if (opt_connect_timeout)
  1918.   {
  1919.     uint timeout=opt_connect_timeout;
  1920.     mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT,
  1921.   (char*) &timeout);
  1922.   }
  1923.   if (opt_compress)
  1924.     mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
  1925. #ifdef HAVE_OPENSSL
  1926.   if (opt_use_ssl)
  1927.     mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
  1928.   opt_ssl_capath);
  1929. #endif
  1930.   if (safe_updates)
  1931.   {
  1932.     char init_command[100];
  1933.     sprintf(init_command,
  1934.     "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,SQL_MAX_JOIN_SIZE=%lu",
  1935.     select_limit,max_join_size);
  1936.     mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command);
  1937.   }
  1938.   if (!mysql_real_connect(&mysql,host,user,password,
  1939.   database,opt_mysql_port,opt_mysql_unix_port,
  1940.   connect_flag))
  1941.   {
  1942.     if (!silent ||
  1943. (mysql_errno(&mysql) != CR_CONN_HOST_ERROR &&
  1944.  mysql_errno(&mysql) != CR_CONNECTION_ERROR))
  1945.     {
  1946.       put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
  1947.       (void) fflush(stdout);
  1948.       return ignore_errors ? -1 : 1; // Abort
  1949.     }
  1950.     return -1; // Retryable
  1951.   }
  1952.   connected=1;
  1953.   mysql.reconnect=info_flag ? 1 : 0; // We want to know if this happens
  1954. #ifdef HAVE_READLINE
  1955.   build_completion_hash(no_rehash,1);
  1956. #endif
  1957.   return 0;
  1958. }
  1959. static int
  1960. sql_connect(char *host,char *database,char *user,char *password,uint silent)
  1961. {
  1962.   bool message=0;
  1963.   uint count=0;
  1964.   int error;
  1965.   for (;;)
  1966.   {
  1967.     if ((error=sql_real_connect(host,database,user,password,wait_flag)) >= 0)
  1968.     {
  1969.       if (count)
  1970.       {
  1971. tee_fputs("n", stderr);
  1972. (void) fflush(stderr);
  1973.       }
  1974.       return error;
  1975.     }
  1976.     if (!wait_flag)
  1977.       return ignore_errors ? -1 : 1;
  1978.     if (!message && !silent)
  1979.     {
  1980.       message=1;
  1981.       tee_fputs("Waiting",stderr); (void) fflush(stderr);
  1982.     }
  1983.     (void) sleep(wait_time);
  1984.     if (!silent)
  1985.     {
  1986.       putc('.',stderr); (void) fflush(stderr);
  1987.       count++;
  1988.     }
  1989.   }
  1990. }
  1991. static int
  1992. com_status(String *buffer __attribute__((unused)),
  1993.    char *line __attribute__((unused)))
  1994. {
  1995.   char *status;
  1996.   tee_puts("--------------", stdout);
  1997.   usage(1); /* Print version */
  1998.   if (connected)
  1999.   {
  2000.     MYSQL_RES *result;
  2001.     LINT_INIT(result);
  2002.     tee_fprintf(stdout, "nConnection id:tt%ldn",mysql_thread_id(&mysql));
  2003.     if (!mysql_query(&mysql,"select DATABASE(),USER()") &&
  2004. (result=mysql_use_result(&mysql)))
  2005.     {
  2006.       MYSQL_ROW cur=mysql_fetch_row(result);
  2007.       tee_fprintf(stdout, "Current database:t%sn",cur[0]);
  2008.       tee_fprintf(stdout, "Current user:tt%sn",cur[1]);
  2009.       (void) mysql_fetch_row(result); // Read eof
  2010.     }
  2011.   }
  2012.   else
  2013.   {
  2014.     vidattr(A_BOLD);
  2015.     tee_fprintf(stdout, "nNo connectionn");
  2016.     vidattr(A_NORMAL);
  2017.     return 0;
  2018.   }
  2019.   if (skip_updates)
  2020.   {
  2021.     vidattr(A_BOLD);
  2022.     tee_fprintf(stdout, "nAll updates ignored to this databasen");
  2023.     vidattr(A_NORMAL);
  2024.   }
  2025. #ifndef __WIN__
  2026.   tee_fprintf(stdout, "Current pager:tt%sn", pager);
  2027.   tee_fprintf(stdout, "Using outfile:tt'%s'n", opt_outfile ? outfile : "");
  2028. #endif
  2029.   tee_fprintf(stdout, "Server version:tt%sn", mysql_get_server_info(&mysql));
  2030.   tee_fprintf(stdout, "Protocol version:t%dn", mysql_get_proto_info(&mysql));
  2031.   tee_fprintf(stdout, "Connection:tt%sn", mysql_get_host_info(&mysql));
  2032.   tee_fprintf(stdout, "Client characterset:t%sn",
  2033.       default_charset_info->name);
  2034.   tee_fprintf(stdout, "Server characterset:t%sn", mysql.charset->name);
  2035.   if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! mysql.unix_socket)
  2036.     tee_fprintf(stdout, "TCP port:tt%dn", mysql.port);
  2037.   else
  2038.     tee_fprintf(stdout, "UNIX socket:tt%sn", mysql.unix_socket);
  2039.   if (mysql.net.compress)
  2040.     tee_fprintf(stdout, "Protocol:ttCompressedn");
  2041.   if ((status=mysql_stat(&mysql)) && !mysql_error(&mysql)[0])
  2042.   {
  2043.     char *pos,buff[40];
  2044.     ulong sec;
  2045.     pos=strchr(status,' ');
  2046.     *pos++=0;
  2047.     tee_fprintf(stdout, "%sttt", status); /* print label */
  2048.     if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec)))
  2049.     {
  2050.       nice_time((double) sec,buff,0);
  2051.       tee_puts(buff, stdout); /* print nice time */
  2052.       while (*status == ' ') status++; /* to next info */
  2053.     }
  2054.     if (status)
  2055.     {
  2056.       tee_putc('n', stdout);
  2057.       tee_puts(status, stdout);
  2058.     }
  2059.   }
  2060.   if (safe_updates)
  2061.   {
  2062.     vidattr(A_BOLD);
  2063.     tee_fprintf(stdout, "nNote that you are running in safe_update_mode:n");
  2064.     vidattr(A_NORMAL);
  2065.     tee_fprintf(stdout, "
  2066. UPDATEs and DELETEs that don't use a key in the WHERE clause are not allowed.n
  2067. (One can force an UPDATE/DELETE by adding LIMIT # at the end of the command.)n
  2068. SELECT has an automatic 'LIMIT %lu' if LIMIT is not used.n
  2069. Max number of examined row combination in a join is set to: %lunn",
  2070. select_limit, max_join_size);
  2071.   }
  2072.   tee_puts("--------------n", stdout);
  2073.   return 0;
  2074. }
  2075. static int
  2076. put_info(const char *str,INFO_TYPE info_type,uint error)
  2077. {
  2078.   static int inited=0;
  2079.   
  2080.   if (status.batch)
  2081.   {
  2082.     if (info_type == INFO_ERROR)
  2083.     {
  2084.       (void) fflush(stdout);
  2085.       fprintf(stderr,"ERROR");
  2086.       if (error)
  2087. (void) fprintf(stderr," %d",error);
  2088.       if (status.query_start_line && ! skip_line_numbers)
  2089.       {
  2090. (void) fprintf(stderr," at line %lu",status.query_start_line);
  2091. if (status.file_name)
  2092.   (void) fprintf(stderr," in file: '%s'", status.file_name);
  2093.       }
  2094.       (void) fprintf(stderr,": %sn",str);
  2095.       (void) fflush(stderr);
  2096.       if (!ignore_errors)
  2097. return 1;
  2098.     }
  2099.     else if (info_type == INFO_RESULT && verbose > 1)
  2100.       tee_puts(str, stdout);
  2101.     if (unbuffered)
  2102.       fflush(stdout);
  2103.     return info_type == INFO_ERROR ? -1 : 0;
  2104.   }
  2105.   if (!opt_silent || info_type == INFO_ERROR)
  2106.   {
  2107.     if (!inited)
  2108.     {
  2109.       inited=1;
  2110. #ifdef HAVE_SETUPTERM
  2111.       (void) setupterm((char *)0, 1, (int *) 0);
  2112. #endif
  2113.     }
  2114.     if (info_type == INFO_ERROR)
  2115.     {
  2116.       putchar('07'); /* This should make a bell */
  2117.       vidattr(A_STANDOUT);
  2118.       if (error)
  2119.         (void) tee_fprintf(stderr, "ERROR %d: ", error);
  2120.       else
  2121.         tee_puts("ERROR: ", stdout);
  2122.     }
  2123.     else
  2124.       vidattr(A_BOLD);
  2125.     (void) tee_puts(str, stdout);
  2126.     vidattr(A_NORMAL);
  2127.   }
  2128.   if (unbuffered)
  2129.     fflush(stdout);
  2130.   return info_type == INFO_ERROR ? -1 : 0;
  2131. }
  2132. static void remove_cntrl(String &buffer)
  2133. {
  2134.   char *start,*end;
  2135.   end=(start=(char*) buffer.ptr())+buffer.length();
  2136.   while (start < end && !isgraph(end[-1]))
  2137.     end--;
  2138.   buffer.length((uint) (end-start));
  2139. }
  2140. void tee_fprintf(FILE *file, const char *fmt, ...)
  2141. {
  2142.   va_list args;
  2143.   va_start(args, fmt);
  2144.   (void) vfprintf(file, fmt, args);
  2145.   if (opt_outfile)
  2146.     (void) vfprintf(OUTFILE, fmt, args);
  2147.   va_end(args);
  2148. }
  2149. void tee_fputs(const char *s, FILE *file)
  2150. {
  2151.   fputs(s, file);
  2152.   if (opt_outfile)
  2153.     fputs(s, OUTFILE);
  2154. }
  2155. void tee_puts(const char *s, FILE *file)
  2156. {
  2157.   fputs(s, file);
  2158.   fputs("n", file);
  2159.   if (opt_outfile)
  2160.   {
  2161.     fputs(s, OUTFILE);
  2162.     fputs("n", OUTFILE);
  2163.   }
  2164. }
  2165. void tee_putc(int c, FILE *file)
  2166. {
  2167.   putc(c, file);
  2168.   if (opt_outfile)
  2169.     putc(c, OUTFILE);
  2170. }
  2171. #ifdef __WIN__
  2172. #include <time.h>
  2173. #else
  2174. #include <sys/times.h>
  2175. #undef CLOCKS_PER_SEC
  2176. #define CLOCKS_PER_SEC (sysconf(_SC_CLK_TCK))
  2177. #endif
  2178. static ulong start_timer(void)
  2179. {
  2180. #ifdef __WIN__
  2181.  return clock();
  2182. #else
  2183.   struct tms tms_tmp;
  2184.   return times(&tms_tmp);
  2185. #endif
  2186. }
  2187. static void nice_time(double sec,char *buff,bool part_second)
  2188. {
  2189.   ulong tmp;
  2190.   if (sec >= 3600.0*24)
  2191.   {
  2192.     tmp=(ulong) floor(sec/(3600.0*24));
  2193.     sec-=3600.0*24*tmp;
  2194.     buff=int2str((long) tmp,buff,10);
  2195.     buff=strmov(buff,tmp > 1 ? " days " : " day ");
  2196.   }
  2197.   if (sec >= 3600.0)
  2198.   {
  2199.     tmp=(ulong) floor(sec/3600.0);
  2200.     sec-=3600.0*tmp;
  2201.     buff=int2str((long) tmp,buff,10);
  2202.     buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
  2203.   }
  2204.   if (sec >= 60.0)
  2205.   {
  2206.     tmp=(ulong) floor(sec/60.0);
  2207.     sec-=60.0*tmp;
  2208.     buff=int2str((long) tmp,buff,10);
  2209.     buff=strmov(buff," min ");
  2210.   }
  2211.   if (part_second)
  2212.     sprintf(buff,"%.2f sec",sec);
  2213.   else
  2214.     sprintf(buff,"%d sec",(int) sec);
  2215. }
  2216. static void end_timer(ulong start_time,char *buff)
  2217. {
  2218.   nice_time((double) (start_timer() - start_time) /
  2219.     CLOCKS_PER_SEC,buff,1);
  2220. }
  2221. static void mysql_end_timer(ulong start_time,char *buff)
  2222. {
  2223.   buff[0]=' ';
  2224.   buff[1]='(';
  2225.   end_timer(start_time,buff+2);
  2226.   strmov(strend(buff),")");
  2227. }
  2228. /* Keep sql_string library happy */
  2229. gptr sql_alloc(unsigned int Size)
  2230. {
  2231.   return my_malloc(Size,MYF(MY_WME));
  2232. }
  2233. void sql_element_free(void *ptr)
  2234. {
  2235.   my_free((gptr) ptr,MYF(0));
  2236. }